diff options
Diffstat (limited to 'net/ipv6/tunnel6.c')
-rw-r--r-- | net/ipv6/tunnel6.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 918d07dd1219..23e2809878ae 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -30,9 +30,10 @@ | |||
30 | #include <net/xfrm.h> | 30 | #include <net/xfrm.h> |
31 | 31 | ||
32 | static struct xfrm6_tunnel *tunnel6_handlers; | 32 | static struct xfrm6_tunnel *tunnel6_handlers; |
33 | static struct xfrm6_tunnel *tunnel46_handlers; | ||
33 | static DEFINE_MUTEX(tunnel6_mutex); | 34 | static DEFINE_MUTEX(tunnel6_mutex); |
34 | 35 | ||
35 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | 36 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) |
36 | { | 37 | { |
37 | struct xfrm6_tunnel **pprev; | 38 | struct xfrm6_tunnel **pprev; |
38 | int ret = -EEXIST; | 39 | int ret = -EEXIST; |
@@ -40,7 +41,8 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | |||
40 | 41 | ||
41 | mutex_lock(&tunnel6_mutex); | 42 | mutex_lock(&tunnel6_mutex); |
42 | 43 | ||
43 | for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { | 44 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
45 | *pprev; pprev = &(*pprev)->next) { | ||
44 | if ((*pprev)->priority > priority) | 46 | if ((*pprev)->priority > priority) |
45 | break; | 47 | break; |
46 | if ((*pprev)->priority == priority) | 48 | if ((*pprev)->priority == priority) |
@@ -60,14 +62,15 @@ err: | |||
60 | 62 | ||
61 | EXPORT_SYMBOL(xfrm6_tunnel_register); | 63 | EXPORT_SYMBOL(xfrm6_tunnel_register); |
62 | 64 | ||
63 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) | 65 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) |
64 | { | 66 | { |
65 | struct xfrm6_tunnel **pprev; | 67 | struct xfrm6_tunnel **pprev; |
66 | int ret = -ENOENT; | 68 | int ret = -ENOENT; |
67 | 69 | ||
68 | mutex_lock(&tunnel6_mutex); | 70 | mutex_lock(&tunnel6_mutex); |
69 | 71 | ||
70 | for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { | 72 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
73 | *pprev; pprev = &(*pprev)->next) { | ||
71 | if (*pprev == handler) { | 74 | if (*pprev == handler) { |
72 | *pprev = handler->next; | 75 | *pprev = handler->next; |
73 | ret = 0; | 76 | ret = 0; |
@@ -103,6 +106,25 @@ drop: | |||
103 | return 0; | 106 | return 0; |
104 | } | 107 | } |
105 | 108 | ||
109 | static int tunnel46_rcv(struct sk_buff **pskb) | ||
110 | { | ||
111 | struct sk_buff *skb = *pskb; | ||
112 | struct xfrm6_tunnel *handler; | ||
113 | |||
114 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
115 | goto drop; | ||
116 | |||
117 | for (handler = tunnel46_handlers; handler; handler = handler->next) | ||
118 | if (!handler->handler(skb)) | ||
119 | return 0; | ||
120 | |||
121 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | ||
122 | |||
123 | drop: | ||
124 | kfree_skb(skb); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
106 | static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 128 | static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
107 | int type, int code, int offset, __be32 info) | 129 | int type, int code, int offset, __be32 info) |
108 | { | 130 | { |
@@ -119,17 +141,30 @@ static struct inet6_protocol tunnel6_protocol = { | |||
119 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 141 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
120 | }; | 142 | }; |
121 | 143 | ||
144 | static struct inet6_protocol tunnel46_protocol = { | ||
145 | .handler = tunnel46_rcv, | ||
146 | .err_handler = tunnel6_err, | ||
147 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | ||
148 | }; | ||
149 | |||
122 | static int __init tunnel6_init(void) | 150 | static int __init tunnel6_init(void) |
123 | { | 151 | { |
124 | if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { | 152 | if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { |
125 | printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); | 153 | printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); |
126 | return -EAGAIN; | 154 | return -EAGAIN; |
127 | } | 155 | } |
156 | if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) { | ||
157 | printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); | ||
158 | inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); | ||
159 | return -EAGAIN; | ||
160 | } | ||
128 | return 0; | 161 | return 0; |
129 | } | 162 | } |
130 | 163 | ||
131 | static void __exit tunnel6_fini(void) | 164 | static void __exit tunnel6_fini(void) |
132 | { | 165 | { |
166 | if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP)) | ||
167 | printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); | ||
133 | if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) | 168 | if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) |
134 | printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); | 169 | printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); |
135 | } | 170 | } |