diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2014-03-14 02:28:07 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2014-03-14 02:28:07 -0400 |
commit | 2f32b51b609faea1e40bb8c5bd305f1351740936 (patch) | |
tree | a114ff4244c4c10c7aeedd64886a0ece4ff45b8f | |
parent | 870a2df4ca026817eb87bb2f9daaa60a93fd051a (diff) |
xfrm: Introduce xfrm_input_afinfo to access the the callbacks properly
IPv6 can be build as a module, so we need mechanism to access
the address family dependent callback functions properly.
Therefore we introduce xfrm_input_afinfo, similar to that
what we have for the address family dependent part of
policies and states.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r-- | include/net/xfrm.h | 23 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 1 | ||||
-rw-r--r-- | net/ipv4/xfrm4_protocol.c | 13 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 75 |
4 files changed, 99 insertions, 13 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ce3d96f752fd..af13599b60a0 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -349,6 +349,16 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); | |||
349 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | 349 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); |
350 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 350 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
351 | 351 | ||
352 | struct xfrm_input_afinfo { | ||
353 | unsigned int family; | ||
354 | struct module *owner; | ||
355 | int (*callback)(struct sk_buff *skb, u8 protocol, | ||
356 | int err); | ||
357 | }; | ||
358 | |||
359 | int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo); | ||
360 | int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo); | ||
361 | |||
352 | void xfrm_state_delete_tunnel(struct xfrm_state *x); | 362 | void xfrm_state_delete_tunnel(struct xfrm_state *x); |
353 | 363 | ||
354 | struct xfrm_type { | 364 | struct xfrm_type { |
@@ -1392,6 +1402,7 @@ void xfrm4_init(void); | |||
1392 | int xfrm_state_init(struct net *net); | 1402 | int xfrm_state_init(struct net *net); |
1393 | void xfrm_state_fini(struct net *net); | 1403 | void xfrm_state_fini(struct net *net); |
1394 | void xfrm4_state_init(void); | 1404 | void xfrm4_state_init(void); |
1405 | void xfrm4_protocol_init(void); | ||
1395 | #ifdef CONFIG_XFRM | 1406 | #ifdef CONFIG_XFRM |
1396 | int xfrm6_init(void); | 1407 | int xfrm6_init(void); |
1397 | void xfrm6_fini(void); | 1408 | void xfrm6_fini(void); |
@@ -1773,18 +1784,6 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m) | |||
1773 | return ret; | 1784 | return ret; |
1774 | } | 1785 | } |
1775 | 1786 | ||
1776 | static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, | ||
1777 | u8 protocol, int err) | ||
1778 | { | ||
1779 | switch(family) { | ||
1780 | #ifdef CONFIG_INET | ||
1781 | case AF_INET: | ||
1782 | return xfrm4_rcv_cb(skb, protocol, err); | ||
1783 | #endif | ||
1784 | } | ||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, | 1787 | static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, |
1789 | unsigned int family) | 1788 | unsigned int family) |
1790 | { | 1789 | { |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index e1a63930a967..6156f68a1e90 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -325,6 +325,7 @@ void __init xfrm4_init(void) | |||
325 | 325 | ||
326 | xfrm4_state_init(); | 326 | xfrm4_state_init(); |
327 | xfrm4_policy_init(); | 327 | xfrm4_policy_init(); |
328 | xfrm4_protocol_init(); | ||
328 | #ifdef CONFIG_SYSCTL | 329 | #ifdef CONFIG_SYSCTL |
329 | register_pernet_subsys(&xfrm4_net_ops); | 330 | register_pernet_subsys(&xfrm4_net_ops); |
330 | #endif | 331 | #endif |
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c index cdc09efca442..7f7b243e8139 100644 --- a/net/ipv4/xfrm4_protocol.c +++ b/net/ipv4/xfrm4_protocol.c | |||
@@ -179,6 +179,12 @@ static const struct net_protocol ipcomp4_protocol = { | |||
179 | .netns_ok = 1, | 179 | .netns_ok = 1, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static struct xfrm_input_afinfo xfrm4_input_afinfo = { | ||
183 | .family = AF_INET, | ||
184 | .owner = THIS_MODULE, | ||
185 | .callback = xfrm4_rcv_cb, | ||
186 | }; | ||
187 | |||
182 | static inline const struct net_protocol *netproto(unsigned char protocol) | 188 | static inline const struct net_protocol *netproto(unsigned char protocol) |
183 | { | 189 | { |
184 | switch (protocol) { | 190 | switch (protocol) { |
@@ -199,7 +205,6 @@ int xfrm4_protocol_register(struct xfrm4_protocol *handler, | |||
199 | struct xfrm4_protocol __rcu **pprev; | 205 | struct xfrm4_protocol __rcu **pprev; |
200 | struct xfrm4_protocol *t; | 206 | struct xfrm4_protocol *t; |
201 | bool add_netproto = false; | 207 | bool add_netproto = false; |
202 | |||
203 | int ret = -EEXIST; | 208 | int ret = -EEXIST; |
204 | int priority = handler->priority; | 209 | int priority = handler->priority; |
205 | 210 | ||
@@ -273,3 +278,9 @@ int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, | |||
273 | return ret; | 278 | return ret; |
274 | } | 279 | } |
275 | EXPORT_SYMBOL(xfrm4_protocol_deregister); | 280 | EXPORT_SYMBOL(xfrm4_protocol_deregister); |
281 | |||
282 | void __init xfrm4_protocol_init(void) | ||
283 | { | ||
284 | xfrm_input_register_afinfo(&xfrm4_input_afinfo); | ||
285 | } | ||
286 | EXPORT_SYMBOL(xfrm4_protocol_init); | ||
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4218164f4f5e..85d1d4764612 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -16,6 +16,81 @@ | |||
16 | 16 | ||
17 | static struct kmem_cache *secpath_cachep __read_mostly; | 17 | static struct kmem_cache *secpath_cachep __read_mostly; |
18 | 18 | ||
19 | static DEFINE_SPINLOCK(xfrm_input_afinfo_lock); | ||
20 | static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO]; | ||
21 | |||
22 | int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo) | ||
23 | { | ||
24 | int err = 0; | ||
25 | |||
26 | if (unlikely(afinfo == NULL)) | ||
27 | return -EINVAL; | ||
28 | if (unlikely(afinfo->family >= NPROTO)) | ||
29 | return -EAFNOSUPPORT; | ||
30 | spin_lock_bh(&xfrm_input_afinfo_lock); | ||
31 | if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL)) | ||
32 | err = -ENOBUFS; | ||
33 | else | ||
34 | rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo); | ||
35 | spin_unlock_bh(&xfrm_input_afinfo_lock); | ||
36 | return err; | ||
37 | } | ||
38 | EXPORT_SYMBOL(xfrm_input_register_afinfo); | ||
39 | |||
40 | int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo) | ||
41 | { | ||
42 | int err = 0; | ||
43 | |||
44 | if (unlikely(afinfo == NULL)) | ||
45 | return -EINVAL; | ||
46 | if (unlikely(afinfo->family >= NPROTO)) | ||
47 | return -EAFNOSUPPORT; | ||
48 | spin_lock_bh(&xfrm_input_afinfo_lock); | ||
49 | if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) { | ||
50 | if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo)) | ||
51 | err = -EINVAL; | ||
52 | else | ||
53 | RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL); | ||
54 | } | ||
55 | spin_unlock_bh(&xfrm_input_afinfo_lock); | ||
56 | synchronize_rcu(); | ||
57 | return err; | ||
58 | } | ||
59 | EXPORT_SYMBOL(xfrm_input_unregister_afinfo); | ||
60 | |||
61 | static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family) | ||
62 | { | ||
63 | struct xfrm_input_afinfo *afinfo; | ||
64 | |||
65 | if (unlikely(family >= NPROTO)) | ||
66 | return NULL; | ||
67 | rcu_read_lock(); | ||
68 | afinfo = rcu_dereference(xfrm_input_afinfo[family]); | ||
69 | if (unlikely(!afinfo)) | ||
70 | rcu_read_unlock(); | ||
71 | return afinfo; | ||
72 | } | ||
73 | |||
74 | static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo) | ||
75 | { | ||
76 | rcu_read_unlock(); | ||
77 | } | ||
78 | |||
79 | static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, | ||
80 | int err) | ||
81 | { | ||
82 | int ret; | ||
83 | struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family); | ||
84 | |||
85 | if (!afinfo) | ||
86 | return -EAFNOSUPPORT; | ||
87 | |||
88 | ret = afinfo->callback(skb, protocol, err); | ||
89 | xfrm_input_put_afinfo(afinfo); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
19 | void __secpath_destroy(struct sec_path *sp) | 94 | void __secpath_destroy(struct sec_path *sp) |
20 | { | 95 | { |
21 | int i; | 96 | int i; |