aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_mode_tunnel.c
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2013-08-19 02:07:34 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2013-10-09 07:16:36 -0400
commit212e560112598cfa8a3061237dd9db5f2252e48c (patch)
tree5171ac63bce1a4d57efc0cd82e8f99c58d54ed73 /net/ipv6/xfrm6_mode_tunnel.c
parentf59bbdfa5c6e2a2f74f0e03d1beab6ddb9b3d466 (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.c69
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. */
22static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly;
23static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex);
24
25int 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
50err:
51 mutex_unlock(&xfrm6_mode_tunnel_input_mutex);
52 return ret;
53}
54EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register);
55
56int 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}
78EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister);
79
21static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) 80static 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
66static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 131static 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;