diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2013-08-19 02:07:34 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-10-09 07:16:36 -0400 |
commit | 212e560112598cfa8a3061237dd9db5f2252e48c (patch) | |
tree | 5171ac63bce1a4d57efc0cd82e8f99c58d54ed73 /net/ipv6/xfrm6_mode_tunnel.c | |
parent | f59bbdfa5c6e2a2f74f0e03d1beab6ddb9b3d466 (diff) |
ipv6: Add a receive path hook for vti6 in xfrm6_mode_tunnel.
Add a receive path hook for the IPsec vritual tunnel interface.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv6/xfrm6_mode_tunnel.c')
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 4770d515c2c8..cb04f7a16b5e 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -18,6 +18,65 @@ | |||
18 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
19 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
20 | 20 | ||
21 | /* Informational hook. The decap is still done here. */ | ||
22 | static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly; | ||
23 | static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex); | ||
24 | |||
25 | int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler) | ||
26 | { | ||
27 | struct xfrm_tunnel_notifier __rcu **pprev; | ||
28 | struct xfrm_tunnel_notifier *t; | ||
29 | int ret = -EEXIST; | ||
30 | int priority = handler->priority; | ||
31 | |||
32 | mutex_lock(&xfrm6_mode_tunnel_input_mutex); | ||
33 | |||
34 | for (pprev = &rcv_notify_handlers; | ||
35 | (t = rcu_dereference_protected(*pprev, | ||
36 | lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; | ||
37 | pprev = &t->next) { | ||
38 | if (t->priority > priority) | ||
39 | break; | ||
40 | if (t->priority == priority) | ||
41 | goto err; | ||
42 | |||
43 | } | ||
44 | |||
45 | handler->next = *pprev; | ||
46 | rcu_assign_pointer(*pprev, handler); | ||
47 | |||
48 | ret = 0; | ||
49 | |||
50 | err: | ||
51 | mutex_unlock(&xfrm6_mode_tunnel_input_mutex); | ||
52 | return ret; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register); | ||
55 | |||
56 | int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler) | ||
57 | { | ||
58 | struct xfrm_tunnel_notifier __rcu **pprev; | ||
59 | struct xfrm_tunnel_notifier *t; | ||
60 | int ret = -ENOENT; | ||
61 | |||
62 | mutex_lock(&xfrm6_mode_tunnel_input_mutex); | ||
63 | for (pprev = &rcv_notify_handlers; | ||
64 | (t = rcu_dereference_protected(*pprev, | ||
65 | lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; | ||
66 | pprev = &t->next) { | ||
67 | if (t == handler) { | ||
68 | *pprev = handler->next; | ||
69 | ret = 0; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | mutex_unlock(&xfrm6_mode_tunnel_input_mutex); | ||
74 | synchronize_net(); | ||
75 | |||
76 | return ret; | ||
77 | } | ||
78 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister); | ||
79 | |||
21 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | 80 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) |
22 | { | 81 | { |
23 | const struct ipv6hdr *outer_iph = ipv6_hdr(skb); | 82 | const struct ipv6hdr *outer_iph = ipv6_hdr(skb); |
@@ -63,8 +122,15 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
63 | return 0; | 122 | return 0; |
64 | } | 123 | } |
65 | 124 | ||
125 | #define for_each_input_rcu(head, handler) \ | ||
126 | for (handler = rcu_dereference(head); \ | ||
127 | handler != NULL; \ | ||
128 | handler = rcu_dereference(handler->next)) | ||
129 | |||
130 | |||
66 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | 131 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) |
67 | { | 132 | { |
133 | struct xfrm_tunnel_notifier *handler; | ||
68 | int err = -EINVAL; | 134 | int err = -EINVAL; |
69 | 135 | ||
70 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | 136 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) |
@@ -72,6 +138,9 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
72 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 138 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
73 | goto out; | 139 | goto out; |
74 | 140 | ||
141 | for_each_input_rcu(rcv_notify_handlers, handler) | ||
142 | handler->handler(skb); | ||
143 | |||
75 | err = skb_unclone(skb, GFP_ATOMIC); | 144 | err = skb_unclone(skb, GFP_ATOMIC); |
76 | if (err) | 145 | if (err) |
77 | goto out; | 146 | goto out; |