diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/Kconfig | 17 | ||||
-rw-r--r-- | net/ipv4/Makefile | 3 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 79 | ||||
-rw-r--r-- | net/ipv4/tunnel4.c | 113 | ||||
-rw-r--r-- | net/ipv4/xfrm4_tunnel.c | 79 |
5 files changed, 165 insertions, 126 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 011cca7ae02b..e40f75322377 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -235,6 +235,7 @@ config IP_PNP_RARP | |||
235 | # bool ' IP: ARP support' CONFIG_IP_PNP_ARP | 235 | # bool ' IP: ARP support' CONFIG_IP_PNP_ARP |
236 | config NET_IPIP | 236 | config NET_IPIP |
237 | tristate "IP: tunneling" | 237 | tristate "IP: tunneling" |
238 | select INET_TUNNEL | ||
238 | ---help--- | 239 | ---help--- |
239 | Tunneling means encapsulating data of one protocol type within | 240 | Tunneling means encapsulating data of one protocol type within |
240 | another protocol and sending it over a channel that understands the | 241 | another protocol and sending it over a channel that understands the |
@@ -395,7 +396,7 @@ config INET_ESP | |||
395 | config INET_IPCOMP | 396 | config INET_IPCOMP |
396 | tristate "IP: IPComp transformation" | 397 | tristate "IP: IPComp transformation" |
397 | select XFRM | 398 | select XFRM |
398 | select INET_TUNNEL | 399 | select INET_XFRM_TUNNEL |
399 | select CRYPTO | 400 | select CRYPTO |
400 | select CRYPTO_DEFLATE | 401 | select CRYPTO_DEFLATE |
401 | ---help--- | 402 | ---help--- |
@@ -404,14 +405,14 @@ config INET_IPCOMP | |||
404 | 405 | ||
405 | If unsure, say Y. | 406 | If unsure, say Y. |
406 | 407 | ||
408 | config INET_XFRM_TUNNEL | ||
409 | tristate | ||
410 | select INET_TUNNEL | ||
411 | default n | ||
412 | |||
407 | config INET_TUNNEL | 413 | config INET_TUNNEL |
408 | tristate "IP: tunnel transformation" | 414 | tristate |
409 | select XFRM | 415 | default n |
410 | ---help--- | ||
411 | Support for generic IP tunnel transformation, which is required by | ||
412 | the IP tunneling module as well as tunnel mode IPComp. | ||
413 | |||
414 | If unsure, say Y. | ||
415 | 416 | ||
416 | config INET_DIAG | 417 | config INET_DIAG |
417 | tristate "INET: socket monitoring interface" | 418 | tristate "INET: socket monitoring interface" |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 35e5f5999092..9ef50a0b9d2c 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -22,7 +22,8 @@ obj-$(CONFIG_SYN_COOKIES) += syncookies.o | |||
22 | obj-$(CONFIG_INET_AH) += ah4.o | 22 | obj-$(CONFIG_INET_AH) += ah4.o |
23 | obj-$(CONFIG_INET_ESP) += esp4.o | 23 | obj-$(CONFIG_INET_ESP) += esp4.o |
24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o | 24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o |
25 | obj-$(CONFIG_INET_TUNNEL) += xfrm4_tunnel.o | 25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o |
26 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o | ||
26 | obj-$(CONFIG_IP_PNP) += ipconfig.o | 27 | obj-$(CONFIG_IP_PNP) += ipconfig.o |
27 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o | 28 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o |
28 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o | 29 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 03d13742a4b8..eef07b0916a3 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -114,7 +114,6 @@ | |||
114 | #include <net/sock.h> | 114 | #include <net/sock.h> |
115 | #include <net/ip.h> | 115 | #include <net/ip.h> |
116 | #include <net/icmp.h> | 116 | #include <net/icmp.h> |
117 | #include <net/protocol.h> | ||
118 | #include <net/ipip.h> | 117 | #include <net/ipip.h> |
119 | #include <net/inet_ecn.h> | 118 | #include <net/inet_ecn.h> |
120 | #include <net/xfrm.h> | 119 | #include <net/xfrm.h> |
@@ -274,7 +273,7 @@ static void ipip_tunnel_uninit(struct net_device *dev) | |||
274 | dev_put(dev); | 273 | dev_put(dev); |
275 | } | 274 | } |
276 | 275 | ||
277 | static void ipip_err(struct sk_buff *skb, u32 info) | 276 | static int ipip_err(struct sk_buff *skb, u32 info) |
278 | { | 277 | { |
279 | #ifndef I_WISH_WORLD_WERE_PERFECT | 278 | #ifndef I_WISH_WORLD_WERE_PERFECT |
280 | 279 | ||
@@ -286,21 +285,22 @@ static void ipip_err(struct sk_buff *skb, u32 info) | |||
286 | int type = skb->h.icmph->type; | 285 | int type = skb->h.icmph->type; |
287 | int code = skb->h.icmph->code; | 286 | int code = skb->h.icmph->code; |
288 | struct ip_tunnel *t; | 287 | struct ip_tunnel *t; |
288 | int err; | ||
289 | 289 | ||
290 | switch (type) { | 290 | switch (type) { |
291 | default: | 291 | default: |
292 | case ICMP_PARAMETERPROB: | 292 | case ICMP_PARAMETERPROB: |
293 | return; | 293 | return 0; |
294 | 294 | ||
295 | case ICMP_DEST_UNREACH: | 295 | case ICMP_DEST_UNREACH: |
296 | switch (code) { | 296 | switch (code) { |
297 | case ICMP_SR_FAILED: | 297 | case ICMP_SR_FAILED: |
298 | case ICMP_PORT_UNREACH: | 298 | case ICMP_PORT_UNREACH: |
299 | /* Impossible event. */ | 299 | /* Impossible event. */ |
300 | return; | 300 | return 0; |
301 | case ICMP_FRAG_NEEDED: | 301 | case ICMP_FRAG_NEEDED: |
302 | /* Soft state for pmtu is maintained by IP core. */ | 302 | /* Soft state for pmtu is maintained by IP core. */ |
303 | return; | 303 | return 0; |
304 | default: | 304 | default: |
305 | /* All others are translated to HOST_UNREACH. | 305 | /* All others are translated to HOST_UNREACH. |
306 | rfc2003 contains "deep thoughts" about NET_UNREACH, | 306 | rfc2003 contains "deep thoughts" about NET_UNREACH, |
@@ -311,14 +311,18 @@ static void ipip_err(struct sk_buff *skb, u32 info) | |||
311 | break; | 311 | break; |
312 | case ICMP_TIME_EXCEEDED: | 312 | case ICMP_TIME_EXCEEDED: |
313 | if (code != ICMP_EXC_TTL) | 313 | if (code != ICMP_EXC_TTL) |
314 | return; | 314 | return 0; |
315 | break; | 315 | break; |
316 | } | 316 | } |
317 | 317 | ||
318 | err = -ENOENT; | ||
319 | |||
318 | read_lock(&ipip_lock); | 320 | read_lock(&ipip_lock); |
319 | t = ipip_tunnel_lookup(iph->daddr, iph->saddr); | 321 | t = ipip_tunnel_lookup(iph->daddr, iph->saddr); |
320 | if (t == NULL || t->parms.iph.daddr == 0) | 322 | if (t == NULL || t->parms.iph.daddr == 0) |
321 | goto out; | 323 | goto out; |
324 | |||
325 | err = 0; | ||
322 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) | 326 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) |
323 | goto out; | 327 | goto out; |
324 | 328 | ||
@@ -329,7 +333,7 @@ static void ipip_err(struct sk_buff *skb, u32 info) | |||
329 | t->err_time = jiffies; | 333 | t->err_time = jiffies; |
330 | out: | 334 | out: |
331 | read_unlock(&ipip_lock); | 335 | read_unlock(&ipip_lock); |
332 | return; | 336 | return err; |
333 | #else | 337 | #else |
334 | struct iphdr *iph = (struct iphdr*)dp; | 338 | struct iphdr *iph = (struct iphdr*)dp; |
335 | int hlen = iph->ihl<<2; | 339 | int hlen = iph->ihl<<2; |
@@ -344,15 +348,15 @@ out: | |||
344 | struct rtable *rt; | 348 | struct rtable *rt; |
345 | 349 | ||
346 | if (len < hlen + sizeof(struct iphdr)) | 350 | if (len < hlen + sizeof(struct iphdr)) |
347 | return; | 351 | return 0; |
348 | eiph = (struct iphdr*)(dp + hlen); | 352 | eiph = (struct iphdr*)(dp + hlen); |
349 | 353 | ||
350 | switch (type) { | 354 | switch (type) { |
351 | default: | 355 | default: |
352 | return; | 356 | return 0; |
353 | case ICMP_PARAMETERPROB: | 357 | case ICMP_PARAMETERPROB: |
354 | if (skb->h.icmph->un.gateway < hlen) | 358 | if (skb->h.icmph->un.gateway < hlen) |
355 | return; | 359 | return 0; |
356 | 360 | ||
357 | /* So... This guy found something strange INSIDE encapsulated | 361 | /* So... This guy found something strange INSIDE encapsulated |
358 | packet. Well, he is fool, but what can we do ? | 362 | packet. Well, he is fool, but what can we do ? |
@@ -366,16 +370,16 @@ out: | |||
366 | case ICMP_SR_FAILED: | 370 | case ICMP_SR_FAILED: |
367 | case ICMP_PORT_UNREACH: | 371 | case ICMP_PORT_UNREACH: |
368 | /* Impossible event. */ | 372 | /* Impossible event. */ |
369 | return; | 373 | return 0; |
370 | case ICMP_FRAG_NEEDED: | 374 | case ICMP_FRAG_NEEDED: |
371 | /* And it is the only really necessary thing :-) */ | 375 | /* And it is the only really necessary thing :-) */ |
372 | rel_info = ntohs(skb->h.icmph->un.frag.mtu); | 376 | rel_info = ntohs(skb->h.icmph->un.frag.mtu); |
373 | if (rel_info < hlen+68) | 377 | if (rel_info < hlen+68) |
374 | return; | 378 | return 0; |
375 | rel_info -= hlen; | 379 | rel_info -= hlen; |
376 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ | 380 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ |
377 | if (rel_info > ntohs(eiph->tot_len)) | 381 | if (rel_info > ntohs(eiph->tot_len)) |
378 | return; | 382 | return 0; |
379 | break; | 383 | break; |
380 | default: | 384 | default: |
381 | /* All others are translated to HOST_UNREACH. | 385 | /* All others are translated to HOST_UNREACH. |
@@ -389,14 +393,14 @@ out: | |||
389 | break; | 393 | break; |
390 | case ICMP_TIME_EXCEEDED: | 394 | case ICMP_TIME_EXCEEDED: |
391 | if (code != ICMP_EXC_TTL) | 395 | if (code != ICMP_EXC_TTL) |
392 | return; | 396 | return 0; |
393 | break; | 397 | break; |
394 | } | 398 | } |
395 | 399 | ||
396 | /* Prepare fake skb to feed it to icmp_send */ | 400 | /* Prepare fake skb to feed it to icmp_send */ |
397 | skb2 = skb_clone(skb, GFP_ATOMIC); | 401 | skb2 = skb_clone(skb, GFP_ATOMIC); |
398 | if (skb2 == NULL) | 402 | if (skb2 == NULL) |
399 | return; | 403 | return 0; |
400 | dst_release(skb2->dst); | 404 | dst_release(skb2->dst); |
401 | skb2->dst = NULL; | 405 | skb2->dst = NULL; |
402 | skb_pull(skb2, skb->data - (u8*)eiph); | 406 | skb_pull(skb2, skb->data - (u8*)eiph); |
@@ -409,7 +413,7 @@ out: | |||
409 | fl.proto = IPPROTO_IPIP; | 413 | fl.proto = IPPROTO_IPIP; |
410 | if (ip_route_output_key(&rt, &key)) { | 414 | if (ip_route_output_key(&rt, &key)) { |
411 | kfree_skb(skb2); | 415 | kfree_skb(skb2); |
412 | return; | 416 | return 0; |
413 | } | 417 | } |
414 | skb2->dev = rt->u.dst.dev; | 418 | skb2->dev = rt->u.dst.dev; |
415 | 419 | ||
@@ -424,14 +428,14 @@ out: | |||
424 | rt->u.dst.dev->type != ARPHRD_TUNNEL) { | 428 | rt->u.dst.dev->type != ARPHRD_TUNNEL) { |
425 | ip_rt_put(rt); | 429 | ip_rt_put(rt); |
426 | kfree_skb(skb2); | 430 | kfree_skb(skb2); |
427 | return; | 431 | return 0; |
428 | } | 432 | } |
429 | } else { | 433 | } else { |
430 | ip_rt_put(rt); | 434 | ip_rt_put(rt); |
431 | if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || | 435 | if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || |
432 | skb2->dst->dev->type != ARPHRD_TUNNEL) { | 436 | skb2->dst->dev->type != ARPHRD_TUNNEL) { |
433 | kfree_skb(skb2); | 437 | kfree_skb(skb2); |
434 | return; | 438 | return 0; |
435 | } | 439 | } |
436 | } | 440 | } |
437 | 441 | ||
@@ -439,7 +443,7 @@ out: | |||
439 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | 443 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { |
440 | if (rel_info > dst_mtu(skb2->dst)) { | 444 | if (rel_info > dst_mtu(skb2->dst)) { |
441 | kfree_skb(skb2); | 445 | kfree_skb(skb2); |
442 | return; | 446 | return 0; |
443 | } | 447 | } |
444 | skb2->dst->ops->update_pmtu(skb2->dst, rel_info); | 448 | skb2->dst->ops->update_pmtu(skb2->dst, rel_info); |
445 | rel_info = htonl(rel_info); | 449 | rel_info = htonl(rel_info); |
@@ -453,7 +457,7 @@ out: | |||
453 | 457 | ||
454 | icmp_send(skb2, rel_type, rel_code, rel_info); | 458 | icmp_send(skb2, rel_type, rel_code, rel_info); |
455 | kfree_skb(skb2); | 459 | kfree_skb(skb2); |
456 | return; | 460 | return 0; |
457 | #endif | 461 | #endif |
458 | } | 462 | } |
459 | 463 | ||
@@ -855,39 +859,12 @@ static int __init ipip_fb_tunnel_init(struct net_device *dev) | |||
855 | return 0; | 859 | return 0; |
856 | } | 860 | } |
857 | 861 | ||
858 | #ifdef CONFIG_INET_TUNNEL | ||
859 | static struct xfrm_tunnel ipip_handler = { | 862 | static struct xfrm_tunnel ipip_handler = { |
860 | .handler = ipip_rcv, | 863 | .handler = ipip_rcv, |
861 | .err_handler = ipip_err, | 864 | .err_handler = ipip_err, |
865 | .priority = 1, | ||
862 | }; | 866 | }; |
863 | 867 | ||
864 | static inline int ipip_register(void) | ||
865 | { | ||
866 | return xfrm4_tunnel_register(&ipip_handler); | ||
867 | } | ||
868 | |||
869 | static inline int ipip_unregister(void) | ||
870 | { | ||
871 | return xfrm4_tunnel_deregister(&ipip_handler); | ||
872 | } | ||
873 | #else | ||
874 | static struct net_protocol ipip_protocol = { | ||
875 | .handler = ipip_rcv, | ||
876 | .err_handler = ipip_err, | ||
877 | .no_policy = 1, | ||
878 | }; | ||
879 | |||
880 | static inline int ipip_register(void) | ||
881 | { | ||
882 | return inet_add_protocol(&ipip_protocol, IPPROTO_IPIP); | ||
883 | } | ||
884 | |||
885 | static inline int ipip_unregister(void) | ||
886 | { | ||
887 | return inet_del_protocol(&ipip_protocol, IPPROTO_IPIP); | ||
888 | } | ||
889 | #endif | ||
890 | |||
891 | static char banner[] __initdata = | 868 | static char banner[] __initdata = |
892 | KERN_INFO "IPv4 over IPv4 tunneling driver\n"; | 869 | KERN_INFO "IPv4 over IPv4 tunneling driver\n"; |
893 | 870 | ||
@@ -897,7 +874,7 @@ static int __init ipip_init(void) | |||
897 | 874 | ||
898 | printk(banner); | 875 | printk(banner); |
899 | 876 | ||
900 | if (ipip_register() < 0) { | 877 | if (xfrm4_tunnel_register(&ipip_handler)) { |
901 | printk(KERN_INFO "ipip init: can't register tunnel\n"); | 878 | printk(KERN_INFO "ipip init: can't register tunnel\n"); |
902 | return -EAGAIN; | 879 | return -EAGAIN; |
903 | } | 880 | } |
@@ -919,7 +896,7 @@ static int __init ipip_init(void) | |||
919 | err2: | 896 | err2: |
920 | free_netdev(ipip_fb_tunnel_dev); | 897 | free_netdev(ipip_fb_tunnel_dev); |
921 | err1: | 898 | err1: |
922 | ipip_unregister(); | 899 | xfrm4_tunnel_deregister(&ipip_handler); |
923 | goto out; | 900 | goto out; |
924 | } | 901 | } |
925 | 902 | ||
@@ -939,7 +916,7 @@ static void __exit ipip_destroy_tunnels(void) | |||
939 | 916 | ||
940 | static void __exit ipip_fini(void) | 917 | static void __exit ipip_fini(void) |
941 | { | 918 | { |
942 | if (ipip_unregister() < 0) | 919 | if (xfrm4_tunnel_deregister(&ipip_handler)) |
943 | printk(KERN_INFO "ipip close: can't deregister tunnel\n"); | 920 | printk(KERN_INFO "ipip close: can't deregister tunnel\n"); |
944 | 921 | ||
945 | rtnl_lock(); | 922 | rtnl_lock(); |
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c new file mode 100644 index 000000000000..0d7d386dac22 --- /dev/null +++ b/net/ipv4/tunnel4.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* tunnel4.c: Generic IP tunnel transformer. | ||
2 | * | ||
3 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) | ||
4 | */ | ||
5 | |||
6 | #include <linux/init.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/mutex.h> | ||
9 | #include <linux/netdevice.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <net/protocol.h> | ||
12 | #include <net/xfrm.h> | ||
13 | |||
14 | static struct xfrm_tunnel *tunnel4_handlers; | ||
15 | static DEFINE_MUTEX(tunnel4_mutex); | ||
16 | |||
17 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler) | ||
18 | { | ||
19 | struct xfrm_tunnel **pprev; | ||
20 | int ret = -EEXIST; | ||
21 | int priority = handler->priority; | ||
22 | |||
23 | mutex_lock(&tunnel4_mutex); | ||
24 | |||
25 | for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { | ||
26 | if ((*pprev)->priority > priority) | ||
27 | break; | ||
28 | if ((*pprev)->priority == priority) | ||
29 | goto err; | ||
30 | } | ||
31 | |||
32 | handler->next = *pprev; | ||
33 | *pprev = handler; | ||
34 | |||
35 | ret = 0; | ||
36 | |||
37 | err: | ||
38 | mutex_unlock(&tunnel4_mutex); | ||
39 | |||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | EXPORT_SYMBOL(xfrm4_tunnel_register); | ||
44 | |||
45 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) | ||
46 | { | ||
47 | struct xfrm_tunnel **pprev; | ||
48 | int ret = -ENOENT; | ||
49 | |||
50 | mutex_lock(&tunnel4_mutex); | ||
51 | |||
52 | for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { | ||
53 | if (*pprev == handler) { | ||
54 | *pprev = handler->next; | ||
55 | ret = 0; | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | mutex_unlock(&tunnel4_mutex); | ||
61 | |||
62 | synchronize_net(); | ||
63 | |||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | EXPORT_SYMBOL(xfrm4_tunnel_deregister); | ||
68 | |||
69 | static int tunnel4_rcv(struct sk_buff *skb) | ||
70 | { | ||
71 | struct xfrm_tunnel *handler; | ||
72 | |||
73 | for (handler = tunnel4_handlers; handler; handler = handler->next) | ||
74 | if (!handler->handler(skb)) | ||
75 | return 0; | ||
76 | |||
77 | kfree_skb(skb); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static void tunnel4_err(struct sk_buff *skb, u32 info) | ||
82 | { | ||
83 | struct xfrm_tunnel *handler; | ||
84 | |||
85 | for (handler = tunnel4_handlers; handler; handler = handler->next) | ||
86 | if (!handler->err_handler(skb, info)) | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | static struct net_protocol tunnel4_protocol = { | ||
91 | .handler = tunnel4_rcv, | ||
92 | .err_handler = tunnel4_err, | ||
93 | .no_policy = 1, | ||
94 | }; | ||
95 | |||
96 | static int __init tunnel4_init(void) | ||
97 | { | ||
98 | if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { | ||
99 | printk(KERN_ERR "tunnel4 init: can't add protocol\n"); | ||
100 | return -EAGAIN; | ||
101 | } | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void __exit tunnel4_fini(void) | ||
106 | { | ||
107 | if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) | ||
108 | printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); | ||
109 | } | ||
110 | |||
111 | module_init(tunnel4_init); | ||
112 | module_exit(tunnel4_fini); | ||
113 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index b08d56b117f8..2d670935c2b5 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c | |||
@@ -26,64 +26,6 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s | |||
26 | return 0; | 26 | return 0; |
27 | } | 27 | } |
28 | 28 | ||
29 | static struct xfrm_tunnel *ipip_handler; | ||
30 | static DEFINE_MUTEX(xfrm4_tunnel_mutex); | ||
31 | |||
32 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler) | ||
33 | { | ||
34 | int ret; | ||
35 | |||
36 | mutex_lock(&xfrm4_tunnel_mutex); | ||
37 | ret = 0; | ||
38 | if (ipip_handler != NULL) | ||
39 | ret = -EINVAL; | ||
40 | if (!ret) | ||
41 | ipip_handler = handler; | ||
42 | mutex_unlock(&xfrm4_tunnel_mutex); | ||
43 | |||
44 | return ret; | ||
45 | } | ||
46 | |||
47 | EXPORT_SYMBOL(xfrm4_tunnel_register); | ||
48 | |||
49 | int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) | ||
50 | { | ||
51 | int ret; | ||
52 | |||
53 | mutex_lock(&xfrm4_tunnel_mutex); | ||
54 | ret = 0; | ||
55 | if (ipip_handler != handler) | ||
56 | ret = -EINVAL; | ||
57 | if (!ret) | ||
58 | ipip_handler = NULL; | ||
59 | mutex_unlock(&xfrm4_tunnel_mutex); | ||
60 | |||
61 | synchronize_net(); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | EXPORT_SYMBOL(xfrm4_tunnel_deregister); | ||
67 | |||
68 | static int ipip_rcv(struct sk_buff *skb) | ||
69 | { | ||
70 | struct xfrm_tunnel *handler = ipip_handler; | ||
71 | |||
72 | /* Tunnel devices take precedence. */ | ||
73 | if (handler && handler->handler(skb) == 0) | ||
74 | return 0; | ||
75 | |||
76 | return xfrm4_rcv(skb); | ||
77 | } | ||
78 | |||
79 | static void ipip_err(struct sk_buff *skb, u32 info) | ||
80 | { | ||
81 | struct xfrm_tunnel *handler = ipip_handler; | ||
82 | |||
83 | if (handler) | ||
84 | handler->err_handler(skb, info); | ||
85 | } | ||
86 | |||
87 | static int ipip_init_state(struct xfrm_state *x) | 29 | static int ipip_init_state(struct xfrm_state *x) |
88 | { | 30 | { |
89 | if (!x->props.mode) | 31 | if (!x->props.mode) |
@@ -111,10 +53,15 @@ static struct xfrm_type ipip_type = { | |||
111 | .output = ipip_output | 53 | .output = ipip_output |
112 | }; | 54 | }; |
113 | 55 | ||
114 | static struct net_protocol ipip_protocol = { | 56 | static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) |
115 | .handler = ipip_rcv, | 57 | { |
116 | .err_handler = ipip_err, | 58 | return -ENOENT; |
117 | .no_policy = 1, | 59 | } |
60 | |||
61 | static struct xfrm_tunnel xfrm_tunnel_handler = { | ||
62 | .handler = xfrm4_rcv, | ||
63 | .err_handler = xfrm_tunnel_err, | ||
64 | .priority = 2, | ||
118 | }; | 65 | }; |
119 | 66 | ||
120 | static int __init ipip_init(void) | 67 | static int __init ipip_init(void) |
@@ -123,8 +70,8 @@ static int __init ipip_init(void) | |||
123 | printk(KERN_INFO "ipip init: can't add xfrm type\n"); | 70 | printk(KERN_INFO "ipip init: can't add xfrm type\n"); |
124 | return -EAGAIN; | 71 | return -EAGAIN; |
125 | } | 72 | } |
126 | if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) { | 73 | if (xfrm4_tunnel_register(&xfrm_tunnel_handler)) { |
127 | printk(KERN_INFO "ipip init: can't add protocol\n"); | 74 | printk(KERN_INFO "ipip init: can't add xfrm handler\n"); |
128 | xfrm_unregister_type(&ipip_type, AF_INET); | 75 | xfrm_unregister_type(&ipip_type, AF_INET); |
129 | return -EAGAIN; | 76 | return -EAGAIN; |
130 | } | 77 | } |
@@ -133,8 +80,8 @@ static int __init ipip_init(void) | |||
133 | 80 | ||
134 | static void __exit ipip_fini(void) | 81 | static void __exit ipip_fini(void) |
135 | { | 82 | { |
136 | if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) | 83 | if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler)) |
137 | printk(KERN_INFO "ipip close: can't remove protocol\n"); | 84 | printk(KERN_INFO "ipip close: can't remove xfrm handler\n"); |
138 | if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) | 85 | if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) |
139 | printk(KERN_INFO "ipip close: can't remove xfrm type\n"); | 86 | printk(KERN_INFO "ipip close: can't remove xfrm type\n"); |
140 | } | 87 | } |