diff options
| -rw-r--r-- | include/net/xfrm.h | 16 | ||||
| -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 | ||||
| -rw-r--r-- | net/ipv6/Kconfig | 19 | ||||
| -rw-r--r-- | net/ipv6/Makefile | 3 | ||||
| -rw-r--r-- | net/ipv6/ip6_tunnel.c | 45 | ||||
| -rw-r--r-- | net/ipv6/tunnel6.c | 131 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_input.c | 5 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 81 |
12 files changed, 344 insertions, 247 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 61b7504fc2ba..e100291e43f4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -864,13 +864,19 @@ struct xfrm_algo_desc { | |||
| 864 | /* XFRM tunnel handlers. */ | 864 | /* XFRM tunnel handlers. */ |
| 865 | struct xfrm_tunnel { | 865 | struct xfrm_tunnel { |
| 866 | int (*handler)(struct sk_buff *skb); | 866 | int (*handler)(struct sk_buff *skb); |
| 867 | void (*err_handler)(struct sk_buff *skb, __u32 info); | 867 | int (*err_handler)(struct sk_buff *skb, __u32 info); |
| 868 | |||
| 869 | struct xfrm_tunnel *next; | ||
| 870 | int priority; | ||
| 868 | }; | 871 | }; |
| 869 | 872 | ||
| 870 | struct xfrm6_tunnel { | 873 | struct xfrm6_tunnel { |
| 871 | int (*handler)(struct sk_buff **pskb); | 874 | int (*handler)(struct sk_buff *skb); |
| 872 | void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, | 875 | int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 873 | int type, int code, int offset, __u32 info); | 876 | int type, int code, int offset, __u32 info); |
| 877 | |||
| 878 | struct xfrm6_tunnel *next; | ||
| 879 | int priority; | ||
| 874 | }; | 880 | }; |
| 875 | 881 | ||
| 876 | extern void xfrm_init(void); | 882 | extern void xfrm_init(void); |
| @@ -906,7 +912,7 @@ extern int xfrm4_rcv(struct sk_buff *skb); | |||
| 906 | extern int xfrm4_output(struct sk_buff *skb); | 912 | extern int xfrm4_output(struct sk_buff *skb); |
| 907 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); | 913 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); |
| 908 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); | 914 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); |
| 909 | extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi); | 915 | extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); |
| 910 | extern int xfrm6_rcv(struct sk_buff **pskb); | 916 | extern int xfrm6_rcv(struct sk_buff **pskb); |
| 911 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); | 917 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); |
| 912 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); | 918 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); |
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 | } |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index e6f83b6a2b76..f8a107ab5592 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -88,7 +88,7 @@ config INET6_IPCOMP | |||
| 88 | tristate "IPv6: IPComp transformation" | 88 | tristate "IPv6: IPComp transformation" |
| 89 | depends on IPV6 | 89 | depends on IPV6 |
| 90 | select XFRM | 90 | select XFRM |
| 91 | select INET6_TUNNEL | 91 | select INET6_XFRM_TUNNEL |
| 92 | select CRYPTO | 92 | select CRYPTO |
| 93 | select CRYPTO_DEFLATE | 93 | select CRYPTO_DEFLATE |
| 94 | ---help--- | 94 | ---help--- |
| @@ -97,19 +97,18 @@ config INET6_IPCOMP | |||
| 97 | 97 | ||
| 98 | If unsure, say Y. | 98 | If unsure, say Y. |
| 99 | 99 | ||
| 100 | config INET6_XFRM_TUNNEL | ||
| 101 | tristate | ||
| 102 | select INET6_TUNNEL | ||
| 103 | default n | ||
| 104 | |||
| 100 | config INET6_TUNNEL | 105 | config INET6_TUNNEL |
| 101 | tristate "IPv6: tunnel transformation" | 106 | tristate |
| 102 | depends on IPV6 | 107 | default n |
| 103 | select XFRM | ||
| 104 | ---help--- | ||
| 105 | Support for generic IPv6-in-IPv6 tunnel transformation, which is | ||
| 106 | required by the IPv6-in-IPv6 tunneling module as well as tunnel mode | ||
| 107 | IPComp. | ||
| 108 | |||
| 109 | If unsure, say Y. | ||
| 110 | 108 | ||
| 111 | config IPV6_TUNNEL | 109 | config IPV6_TUNNEL |
| 112 | tristate "IPv6: IPv6-in-IPv6 tunnel" | 110 | tristate "IPv6: IPv6-in-IPv6 tunnel" |
| 111 | select INET6_TUNNEL | ||
| 113 | depends on IPV6 | 112 | depends on IPV6 |
| 114 | ---help--- | 113 | ---help--- |
| 115 | Support for IPv6-in-IPv6 tunnels described in RFC 2473. | 114 | Support for IPv6-in-IPv6 tunnels described in RFC 2473. |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 41877abd22e6..a760b0988fbb 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -18,7 +18,8 @@ ipv6-objs += $(ipv6-y) | |||
| 18 | obj-$(CONFIG_INET6_AH) += ah6.o | 18 | obj-$(CONFIG_INET6_AH) += ah6.o |
| 19 | obj-$(CONFIG_INET6_ESP) += esp6.o | 19 | obj-$(CONFIG_INET6_ESP) += esp6.o |
| 20 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o | 20 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o |
| 21 | obj-$(CONFIG_INET6_TUNNEL) += xfrm6_tunnel.o | 21 | obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o |
| 22 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | ||
| 22 | obj-$(CONFIG_NETFILTER) += netfilter/ | 23 | obj-$(CONFIG_NETFILTER) += netfilter/ |
| 23 | 24 | ||
| 24 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 25 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 48597538db3f..ff9040c92556 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
| @@ -44,7 +44,6 @@ | |||
| 44 | 44 | ||
| 45 | #include <net/ip.h> | 45 | #include <net/ip.h> |
| 46 | #include <net/ipv6.h> | 46 | #include <net/ipv6.h> |
| 47 | #include <net/protocol.h> | ||
| 48 | #include <net/ip6_route.h> | 47 | #include <net/ip6_route.h> |
| 49 | #include <net/addrconf.h> | 48 | #include <net/addrconf.h> |
| 50 | #include <net/ip6_tunnel.h> | 49 | #include <net/ip6_tunnel.h> |
| @@ -391,7 +390,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | |||
| 391 | * to the specifications in RFC 2473. | 390 | * to the specifications in RFC 2473. |
| 392 | **/ | 391 | **/ |
| 393 | 392 | ||
| 394 | static void | 393 | static int |
| 395 | ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 394 | ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 396 | int type, int code, int offset, __u32 info) | 395 | int type, int code, int offset, __u32 info) |
| 397 | { | 396 | { |
| @@ -402,6 +401,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 402 | int rel_code = ICMPV6_ADDR_UNREACH; | 401 | int rel_code = ICMPV6_ADDR_UNREACH; |
| 403 | __u32 rel_info = 0; | 402 | __u32 rel_info = 0; |
| 404 | __u16 len; | 403 | __u16 len; |
| 404 | int err = -ENOENT; | ||
| 405 | 405 | ||
| 406 | /* If the packet doesn't contain the original IPv6 header we are | 406 | /* If the packet doesn't contain the original IPv6 header we are |
| 407 | in trouble since we might need the source address for further | 407 | in trouble since we might need the source address for further |
| @@ -411,6 +411,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 411 | if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL) | 411 | if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL) |
| 412 | goto out; | 412 | goto out; |
| 413 | 413 | ||
| 414 | err = 0; | ||
| 415 | |||
| 414 | switch (type) { | 416 | switch (type) { |
| 415 | __u32 teli; | 417 | __u32 teli; |
| 416 | struct ipv6_tlv_tnl_enc_lim *tel; | 418 | struct ipv6_tlv_tnl_enc_lim *tel; |
| @@ -492,6 +494,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 492 | } | 494 | } |
| 493 | out: | 495 | out: |
| 494 | read_unlock(&ip6ip6_lock); | 496 | read_unlock(&ip6ip6_lock); |
| 497 | return err; | ||
| 495 | } | 498 | } |
| 496 | 499 | ||
| 497 | static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, | 500 | static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, |
| @@ -511,9 +514,8 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, | |||
| 511 | **/ | 514 | **/ |
| 512 | 515 | ||
| 513 | static int | 516 | static int |
| 514 | ip6ip6_rcv(struct sk_buff **pskb) | 517 | ip6ip6_rcv(struct sk_buff *skb) |
| 515 | { | 518 | { |
| 516 | struct sk_buff *skb = *pskb; | ||
| 517 | struct ipv6hdr *ipv6h; | 519 | struct ipv6hdr *ipv6h; |
| 518 | struct ip6_tnl *t; | 520 | struct ip6_tnl *t; |
| 519 | 521 | ||
| @@ -1112,39 +1114,12 @@ ip6ip6_fb_tnl_dev_init(struct net_device *dev) | |||
| 1112 | return 0; | 1114 | return 0; |
| 1113 | } | 1115 | } |
| 1114 | 1116 | ||
| 1115 | #ifdef CONFIG_INET6_TUNNEL | ||
| 1116 | static struct xfrm6_tunnel ip6ip6_handler = { | 1117 | static struct xfrm6_tunnel ip6ip6_handler = { |
| 1117 | .handler = ip6ip6_rcv, | 1118 | .handler = ip6ip6_rcv, |
| 1118 | .err_handler = ip6ip6_err, | 1119 | .err_handler = ip6ip6_err, |
| 1120 | .priority = 1, | ||
| 1119 | }; | 1121 | }; |
| 1120 | 1122 | ||
| 1121 | static inline int ip6ip6_register(void) | ||
| 1122 | { | ||
| 1123 | return xfrm6_tunnel_register(&ip6ip6_handler); | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | static inline int ip6ip6_unregister(void) | ||
| 1127 | { | ||
| 1128 | return xfrm6_tunnel_deregister(&ip6ip6_handler); | ||
| 1129 | } | ||
| 1130 | #else | ||
| 1131 | static struct inet6_protocol xfrm6_tunnel_protocol = { | ||
| 1132 | .handler = ip6ip6_rcv, | ||
| 1133 | .err_handler = ip6ip6_err, | ||
| 1134 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | ||
| 1135 | }; | ||
| 1136 | |||
| 1137 | static inline int ip6ip6_register(void) | ||
| 1138 | { | ||
| 1139 | return inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | static inline int ip6ip6_unregister(void) | ||
| 1143 | { | ||
| 1144 | return inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6); | ||
| 1145 | } | ||
| 1146 | #endif | ||
| 1147 | |||
| 1148 | /** | 1123 | /** |
| 1149 | * ip6_tunnel_init - register protocol and reserve needed resources | 1124 | * ip6_tunnel_init - register protocol and reserve needed resources |
| 1150 | * | 1125 | * |
| @@ -1155,7 +1130,7 @@ static int __init ip6_tunnel_init(void) | |||
| 1155 | { | 1130 | { |
| 1156 | int err; | 1131 | int err; |
| 1157 | 1132 | ||
| 1158 | if (ip6ip6_register() < 0) { | 1133 | if (xfrm6_tunnel_register(&ip6ip6_handler)) { |
| 1159 | printk(KERN_ERR "ip6ip6 init: can't register tunnel\n"); | 1134 | printk(KERN_ERR "ip6ip6 init: can't register tunnel\n"); |
| 1160 | return -EAGAIN; | 1135 | return -EAGAIN; |
| 1161 | } | 1136 | } |
| @@ -1174,7 +1149,7 @@ static int __init ip6_tunnel_init(void) | |||
| 1174 | } | 1149 | } |
| 1175 | return 0; | 1150 | return 0; |
| 1176 | fail: | 1151 | fail: |
| 1177 | ip6ip6_unregister(); | 1152 | xfrm6_tunnel_deregister(&ip6ip6_handler); |
| 1178 | return err; | 1153 | return err; |
| 1179 | } | 1154 | } |
| 1180 | 1155 | ||
| @@ -1184,7 +1159,7 @@ fail: | |||
| 1184 | 1159 | ||
| 1185 | static void __exit ip6_tunnel_cleanup(void) | 1160 | static void __exit ip6_tunnel_cleanup(void) |
| 1186 | { | 1161 | { |
| 1187 | if (ip6ip6_unregister() < 0) | 1162 | if (xfrm6_tunnel_deregister(&ip6ip6_handler)) |
| 1188 | printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n"); | 1163 | printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n"); |
| 1189 | 1164 | ||
| 1190 | unregister_netdev(ip6ip6_fb_tnl_dev); | 1165 | unregister_netdev(ip6ip6_fb_tnl_dev); |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c new file mode 100644 index 000000000000..5659b52284bd --- /dev/null +++ b/net/ipv6/tunnel6.c | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C)2003,2004 USAGI/WIDE Project | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | ||
| 18 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> | ||
| 19 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/mutex.h> | ||
| 25 | #include <linux/netdevice.h> | ||
| 26 | #include <linux/skbuff.h> | ||
| 27 | #include <net/protocol.h> | ||
| 28 | #include <net/xfrm.h> | ||
| 29 | |||
| 30 | static struct xfrm6_tunnel *tunnel6_handlers; | ||
| 31 | static DEFINE_MUTEX(tunnel6_mutex); | ||
| 32 | |||
| 33 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | ||
| 34 | { | ||
| 35 | struct xfrm6_tunnel **pprev; | ||
| 36 | int ret = -EEXIST; | ||
| 37 | int priority = handler->priority; | ||
| 38 | |||
| 39 | mutex_lock(&tunnel6_mutex); | ||
| 40 | |||
| 41 | for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { | ||
| 42 | if ((*pprev)->priority > priority) | ||
| 43 | break; | ||
| 44 | if ((*pprev)->priority == priority) | ||
| 45 | goto err; | ||
| 46 | } | ||
| 47 | |||
| 48 | handler->next = *pprev; | ||
| 49 | *pprev = handler; | ||
| 50 | |||
| 51 | ret = 0; | ||
| 52 | |||
| 53 | err: | ||
| 54 | mutex_unlock(&tunnel6_mutex); | ||
| 55 | |||
| 56 | return ret; | ||
| 57 | } | ||
| 58 | |||
| 59 | EXPORT_SYMBOL(xfrm6_tunnel_register); | ||
| 60 | |||
| 61 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) | ||
| 62 | { | ||
| 63 | struct xfrm6_tunnel **pprev; | ||
| 64 | int ret = -ENOENT; | ||
| 65 | |||
| 66 | mutex_lock(&tunnel6_mutex); | ||
| 67 | |||
| 68 | for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { | ||
| 69 | if (*pprev == handler) { | ||
| 70 | *pprev = handler->next; | ||
| 71 | ret = 0; | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | mutex_unlock(&tunnel6_mutex); | ||
| 77 | |||
| 78 | synchronize_net(); | ||
| 79 | |||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 83 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | ||
| 84 | |||
| 85 | static int tunnel6_rcv(struct sk_buff **pskb) | ||
| 86 | { | ||
| 87 | struct sk_buff *skb = *pskb; | ||
| 88 | struct xfrm6_tunnel *handler; | ||
| 89 | |||
| 90 | for (handler = tunnel6_handlers; handler; handler = handler->next) | ||
| 91 | if (!handler->handler(skb)) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | kfree_skb(skb); | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
| 99 | int type, int code, int offset, __u32 info) | ||
| 100 | { | ||
| 101 | struct xfrm6_tunnel *handler; | ||
| 102 | |||
| 103 | for (handler = tunnel6_handlers; handler; handler = handler->next) | ||
| 104 | if (!handler->err_handler(skb, opt, type, code, offset, info)) | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct inet6_protocol tunnel6_protocol = { | ||
| 109 | .handler = tunnel6_rcv, | ||
| 110 | .err_handler = tunnel6_err, | ||
| 111 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static int __init tunnel6_init(void) | ||
| 115 | { | ||
| 116 | if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { | ||
| 117 | printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); | ||
| 118 | return -EAGAIN; | ||
| 119 | } | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void __exit tunnel6_fini(void) | ||
| 124 | { | ||
| 125 | if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) | ||
| 126 | printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); | ||
| 127 | } | ||
| 128 | |||
| 129 | module_init(tunnel6_init); | ||
| 130 | module_exit(tunnel6_fini); | ||
| 131 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 1ca2da68ef69..cccf8b76f046 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
| @@ -28,9 +28,8 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | |||
| 28 | IP6_ECN_set_ce(inner_iph); | 28 | IP6_ECN_set_ce(inner_iph); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi) | 31 | int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) |
| 32 | { | 32 | { |
| 33 | struct sk_buff *skb = *pskb; | ||
| 34 | int err; | 33 | int err; |
| 35 | u32 seq; | 34 | u32 seq; |
| 36 | struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; | 35 | struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; |
| @@ -159,5 +158,5 @@ EXPORT_SYMBOL(xfrm6_rcv_spi); | |||
| 159 | 158 | ||
| 160 | int xfrm6_rcv(struct sk_buff **pskb) | 159 | int xfrm6_rcv(struct sk_buff **pskb) |
| 161 | { | 160 | { |
| 162 | return xfrm6_rcv_spi(pskb, 0); | 161 | return xfrm6_rcv_spi(*pskb, 0); |
| 163 | } | 162 | } |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 08f9abbdf1d7..a8f6776c518d 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <net/ip.h> | 28 | #include <net/ip.h> |
| 29 | #include <net/xfrm.h> | 29 | #include <net/xfrm.h> |
| 30 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
| 31 | #include <net/protocol.h> | ||
| 32 | #include <linux/ipv6.h> | 31 | #include <linux/ipv6.h> |
| 33 | #include <linux/icmpv6.h> | 32 | #include <linux/icmpv6.h> |
| 34 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
| @@ -357,71 +356,18 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec | |||
| 357 | return 0; | 356 | return 0; |
| 358 | } | 357 | } |
| 359 | 358 | ||
| 360 | static struct xfrm6_tunnel *xfrm6_tunnel_handler; | 359 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
| 361 | static DEFINE_MUTEX(xfrm6_tunnel_mutex); | ||
| 362 | |||
| 363 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | ||
| 364 | { | 360 | { |
| 365 | int ret; | ||
| 366 | |||
| 367 | mutex_lock(&xfrm6_tunnel_mutex); | ||
| 368 | ret = 0; | ||
| 369 | if (xfrm6_tunnel_handler != NULL) | ||
| 370 | ret = -EINVAL; | ||
| 371 | if (!ret) | ||
| 372 | xfrm6_tunnel_handler = handler; | ||
| 373 | mutex_unlock(&xfrm6_tunnel_mutex); | ||
| 374 | |||
| 375 | return ret; | ||
| 376 | } | ||
| 377 | |||
| 378 | EXPORT_SYMBOL(xfrm6_tunnel_register); | ||
| 379 | |||
| 380 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) | ||
| 381 | { | ||
| 382 | int ret; | ||
| 383 | |||
| 384 | mutex_lock(&xfrm6_tunnel_mutex); | ||
| 385 | ret = 0; | ||
| 386 | if (xfrm6_tunnel_handler != handler) | ||
| 387 | ret = -EINVAL; | ||
| 388 | if (!ret) | ||
| 389 | xfrm6_tunnel_handler = NULL; | ||
| 390 | mutex_unlock(&xfrm6_tunnel_mutex); | ||
| 391 | |||
| 392 | synchronize_net(); | ||
| 393 | |||
| 394 | return ret; | ||
| 395 | } | ||
| 396 | |||
| 397 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | ||
| 398 | |||
| 399 | static int xfrm6_tunnel_rcv(struct sk_buff **pskb) | ||
| 400 | { | ||
| 401 | struct sk_buff *skb = *pskb; | ||
| 402 | struct xfrm6_tunnel *handler = xfrm6_tunnel_handler; | ||
| 403 | struct ipv6hdr *iph = skb->nh.ipv6h; | 361 | struct ipv6hdr *iph = skb->nh.ipv6h; |
| 404 | u32 spi; | 362 | u32 spi; |
| 405 | 363 | ||
| 406 | /* device-like_ip6ip6_handler() */ | ||
| 407 | if (handler && handler->handler(pskb) == 0) | ||
| 408 | return 0; | ||
| 409 | |||
| 410 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 364 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); |
| 411 | return xfrm6_rcv_spi(pskb, spi); | 365 | return xfrm6_rcv_spi(skb, spi); |
| 412 | } | 366 | } |
| 413 | 367 | ||
| 414 | static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 368 | static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
| 415 | int type, int code, int offset, __u32 info) | 369 | int type, int code, int offset, __u32 info) |
| 416 | { | 370 | { |
| 417 | struct xfrm6_tunnel *handler = xfrm6_tunnel_handler; | ||
| 418 | |||
| 419 | /* call here first for device-like ip6ip6 err handling */ | ||
| 420 | if (handler) { | ||
| 421 | handler->err_handler(skb, opt, type, code, offset, info); | ||
| 422 | return; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* xfrm6_tunnel native err handling */ | 371 | /* xfrm6_tunnel native err handling */ |
| 426 | switch (type) { | 372 | switch (type) { |
| 427 | case ICMPV6_DEST_UNREACH: | 373 | case ICMPV6_DEST_UNREACH: |
| @@ -462,7 +408,8 @@ static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 462 | default: | 408 | default: |
| 463 | break; | 409 | break; |
| 464 | } | 410 | } |
| 465 | return; | 411 | |
| 412 | return 0; | ||
| 466 | } | 413 | } |
| 467 | 414 | ||
| 468 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) | 415 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) |
| @@ -493,10 +440,10 @@ static struct xfrm_type xfrm6_tunnel_type = { | |||
| 493 | .output = xfrm6_tunnel_output, | 440 | .output = xfrm6_tunnel_output, |
| 494 | }; | 441 | }; |
| 495 | 442 | ||
| 496 | static struct inet6_protocol xfrm6_tunnel_protocol = { | 443 | static struct xfrm6_tunnel xfrm6_tunnel_handler = { |
| 497 | .handler = xfrm6_tunnel_rcv, | 444 | .handler = xfrm6_tunnel_rcv, |
| 498 | .err_handler = xfrm6_tunnel_err, | 445 | .err_handler = xfrm6_tunnel_err, |
| 499 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 446 | .priority = 2, |
| 500 | }; | 447 | }; |
| 501 | 448 | ||
| 502 | static int __init xfrm6_tunnel_init(void) | 449 | static int __init xfrm6_tunnel_init(void) |
| @@ -508,16 +455,16 @@ static int __init xfrm6_tunnel_init(void) | |||
| 508 | "xfrm6_tunnel init: can't add xfrm type\n"); | 455 | "xfrm6_tunnel init: can't add xfrm type\n"); |
| 509 | return -EAGAIN; | 456 | return -EAGAIN; |
| 510 | } | 457 | } |
| 511 | if (inet6_add_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) { | 458 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { |
| 512 | X6TPRINTK1(KERN_ERR | 459 | X6TPRINTK1(KERN_ERR |
| 513 | "xfrm6_tunnel init(): can't add protocol\n"); | 460 | "xfrm6_tunnel init(): can't add handler\n"); |
| 514 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 461 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 515 | return -EAGAIN; | 462 | return -EAGAIN; |
| 516 | } | 463 | } |
| 517 | if (xfrm6_tunnel_spi_init() < 0) { | 464 | if (xfrm6_tunnel_spi_init() < 0) { |
| 518 | X6TPRINTK1(KERN_ERR | 465 | X6TPRINTK1(KERN_ERR |
| 519 | "xfrm6_tunnel init: failed to initialize spi\n"); | 466 | "xfrm6_tunnel init: failed to initialize spi\n"); |
| 520 | inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6); | 467 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); |
| 521 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 468 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
| 522 | return -EAGAIN; | 469 | return -EAGAIN; |
| 523 | } | 470 | } |
| @@ -529,9 +476,9 @@ static void __exit xfrm6_tunnel_fini(void) | |||
| 529 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); | 476 | X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); |
| 530 | 477 | ||
| 531 | xfrm6_tunnel_spi_fini(); | 478 | xfrm6_tunnel_spi_fini(); |
| 532 | if (inet6_del_protocol(&xfrm6_tunnel_protocol, IPPROTO_IPV6) < 0) | 479 | if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler)) |
| 533 | X6TPRINTK1(KERN_ERR | 480 | X6TPRINTK1(KERN_ERR |
| 534 | "xfrm6_tunnel close: can't remove protocol\n"); | 481 | "xfrm6_tunnel close: can't remove handler\n"); |
| 535 | if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0) | 482 | if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0) |
| 536 | X6TPRINTK1(KERN_ERR | 483 | X6TPRINTK1(KERN_ERR |
| 537 | "xfrm6_tunnel close: can't remove xfrm type\n"); | 484 | "xfrm6_tunnel close: can't remove xfrm type\n"); |
