aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_tunnel.c
diff options
context:
space:
mode:
authorYasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>2007-02-14 10:43:16 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:40 -0400
commitc4d3efafcc933fd2ffd169d7dc4f980393a13796 (patch)
tree01ecdc7128ae03c29acbd605589a56420bcf95ec /net/ipv6/ip6_tunnel.c
parent61ec2aec28ba8de09f76a558a5d6d3893b1d2e47 (diff)
[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.
Some notes - Protocol number IPPROTO_IPIP is used for IPv4 over IPv6 packets. - If IP6_TNL_F_USE_ORIG_TCLASS is set, TOS in IPv4 header is copied to Traffic Class in outer IPv6 header on xmit. - IP6_TNL_F_USE_ORIG_FLOWLABEL is ignored on xmit of IPv4 packets, because IPv4 header does not have flow label. - Kernel sends ICMP error if IPv4 packet is too big on xmit, even if DF flag is not set. Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r--net/ipv6/ip6_tunnel.c190
1 files changed, 185 insertions, 5 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4546bb923a20..a6541495deab 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1,14 +1,15 @@
1/* 1/*
2 * IPv6 over IPv6 tunnel device 2 * IPv6 tunneling device
3 * Linux INET6 implementation 3 * Linux INET6 implementation
4 * 4 *
5 * Authors: 5 * Authors:
6 * Ville Nuorvala <vnuorval@tcs.hut.fi> 6 * Ville Nuorvala <vnuorval@tcs.hut.fi>
7 * Yasuyuki Kozakai <kozakai@linux-ipv6.org>
7 * 8 *
8 * $Id$ 9 * $Id$
9 * 10 *
10 * Based on: 11 * Based on:
11 * linux/net/ipv6/sit.c 12 * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
12 * 13 *
13 * RFC 2473 14 * RFC 2473
14 * 15 *
@@ -24,6 +25,7 @@
24#include <linux/errno.h> 25#include <linux/errno.h>
25#include <linux/types.h> 26#include <linux/types.h>
26#include <linux/sockios.h> 27#include <linux/sockios.h>
28#include <linux/icmp.h>
27#include <linux/if.h> 29#include <linux/if.h>
28#include <linux/in.h> 30#include <linux/in.h>
29#include <linux/ip.h> 31#include <linux/ip.h>
@@ -41,6 +43,7 @@
41#include <asm/uaccess.h> 43#include <asm/uaccess.h>
42#include <asm/atomic.h> 44#include <asm/atomic.h>
43 45
46#include <net/icmp.h>
44#include <net/ip.h> 47#include <net/ip.h>
45#include <net/ipv6.h> 48#include <net/ipv6.h>
46#include <net/ip6_route.h> 49#include <net/ip6_route.h>
@@ -51,7 +54,7 @@
51#include <net/inet_ecn.h> 54#include <net/inet_ecn.h>
52 55
53MODULE_AUTHOR("Ville Nuorvala"); 56MODULE_AUTHOR("Ville Nuorvala");
54MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel"); 57MODULE_DESCRIPTION("IPv6 tunneling device");
55MODULE_LICENSE("GPL"); 58MODULE_LICENSE("GPL");
56 59
57#define IPV6_TLV_TEL_DST_SIZE 8 60#define IPV6_TLV_TEL_DST_SIZE 8
@@ -63,6 +66,7 @@ MODULE_LICENSE("GPL");
63#endif 66#endif
64 67
65#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) 68#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
69#define IPV6_TCLASS_SHIFT 20
66 70
67#define HASH_SIZE 32 71#define HASH_SIZE 32
68 72
@@ -470,6 +474,104 @@ out:
470} 474}
471 475
472static int 476static int
477ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
478 int type, int code, int offset, __u32 info)
479{
480 int rel_msg = 0;
481 int rel_type = type;
482 int rel_code = code;
483 __u32 rel_info = info;
484 int err;
485 struct sk_buff *skb2;
486 struct iphdr *eiph;
487 struct flowi fl;
488 struct rtable *rt;
489
490 err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info,
491 offset);
492 if (err < 0)
493 return err;
494
495 if (rel_msg == 0)
496 return 0;
497
498 switch (rel_type) {
499 case ICMPV6_DEST_UNREACH:
500 if (rel_code != ICMPV6_ADDR_UNREACH)
501 return 0;
502 rel_type = ICMP_DEST_UNREACH;
503 rel_code = ICMP_HOST_UNREACH;
504 break;
505 case ICMPV6_PKT_TOOBIG:
506 if (rel_code != 0)
507 return 0;
508 rel_type = ICMP_DEST_UNREACH;
509 rel_code = ICMP_FRAG_NEEDED;
510 break;
511 default:
512 return 0;
513 }
514
515 if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
516 return 0;
517
518 skb2 = skb_clone(skb, GFP_ATOMIC);
519 if (!skb2)
520 return 0;
521
522 dst_release(skb2->dst);
523 skb2->dst = NULL;
524 skb_pull(skb2, offset);
525 skb2->nh.raw = skb2->data;
526 eiph = skb2->nh.iph;
527
528 /* Try to guess incoming interface */
529 memset(&fl, 0, sizeof(fl));
530 fl.fl4_dst = eiph->saddr;
531 fl.fl4_tos = RT_TOS(eiph->tos);
532 fl.proto = IPPROTO_IPIP;
533 if (ip_route_output_key(&rt, &fl))
534 goto out;
535
536 skb2->dev = rt->u.dst.dev;
537
538 /* route "incoming" packet */
539 if (rt->rt_flags & RTCF_LOCAL) {
540 ip_rt_put(rt);
541 rt = NULL;
542 fl.fl4_dst = eiph->daddr;
543 fl.fl4_src = eiph->saddr;
544 fl.fl4_tos = eiph->tos;
545 if (ip_route_output_key(&rt, &fl) ||
546 rt->u.dst.dev->type != ARPHRD_TUNNEL) {
547 ip_rt_put(rt);
548 goto out;
549 }
550 } else {
551 ip_rt_put(rt);
552 if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
553 skb2->dev) ||
554 skb2->dst->dev->type != ARPHRD_TUNNEL)
555 goto out;
556 }
557
558 /* change mtu on this route */
559 if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
560 if (rel_info > dst_mtu(skb2->dst))
561 goto out;
562
563 skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
564 rel_info = htonl(rel_info);
565 }
566
567 icmp_send(skb2, rel_type, rel_code, rel_info);
568
569out:
570 kfree_skb(skb2);
571 return 0;
572}
573
574static int
473ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 575ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
474 int type, int code, int offset, __u32 info) 576 int type, int code, int offset, __u32 info)
475{ 577{
@@ -513,6 +615,19 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
513 return 0; 615 return 0;
514} 616}
515 617
618static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
619 struct ipv6hdr *ipv6h,
620 struct sk_buff *skb)
621{
622 __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
623
624 if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
625 ipv4_change_dsfield(skb->nh.iph, INET_ECN_MASK, dsfield);
626
627 if (INET_ECN_is_ce(dsfield))
628 IP_ECN_set_ce(skb->nh.iph);
629}
630
516static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, 631static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
517 struct ipv6hdr *ipv6h, 632 struct ipv6hdr *ipv6h,
518 struct sk_buff *skb) 633 struct sk_buff *skb)
@@ -605,6 +720,11 @@ discard:
605 return 0; 720 return 0;
606} 721}
607 722
723static int ip4ip6_rcv(struct sk_buff *skb)
724{
725 return ip6_tnl_rcv(skb, ETH_P_IP, ip4ip6_dscp_ecn_decapsulate);
726}
727
608static int ip6ip6_rcv(struct sk_buff *skb) 728static int ip6ip6_rcv(struct sk_buff *skb)
609{ 729{
610 return ip6_tnl_rcv(skb, ETH_P_IPV6, ip6ip6_dscp_ecn_decapsulate); 730 return ip6_tnl_rcv(skb, ETH_P_IPV6, ip6ip6_dscp_ecn_decapsulate);
@@ -691,7 +811,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
691 * it. 811 * it.
692 * 812 *
693 * Return: 813 * Return:
694 * 0 814 * 0 on success
695 * -1 fail 815 * -1 fail
696 * %-EMSGSIZE message too big. return mtu in this case. 816 * %-EMSGSIZE message too big. return mtu in this case.
697 **/ 817 **/
@@ -809,6 +929,44 @@ tx_err_dst_release:
809} 929}
810 930
811static inline int 931static inline int
932ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
933{
934 struct ip6_tnl *t = netdev_priv(dev);
935 struct iphdr *iph = skb->nh.iph;
936 int encap_limit = -1;
937 struct flowi fl;
938 __u8 dsfield;
939 __u32 mtu;
940 int err;
941
942 if (!ip6_tnl_xmit_ctl(t))
943 return -1;
944
945 if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
946 encap_limit = t->parms.encap_limit;
947
948 memcpy(&fl, &t->fl, sizeof (fl));
949 fl.proto = IPPROTO_IPIP;
950
951 dsfield = ipv4_get_dsfield(iph);
952
953 if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
954 fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
955 & IPV6_TCLASS_MASK);
956
957 err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
958 if (err != 0) {
959 /* XXX: send ICMP error even if DF is not set. */
960 if (err == -EMSGSIZE)
961 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
962 htonl(mtu));
963 return -1;
964 }
965
966 return 0;
967}
968
969static inline int
812ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) 970ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
813{ 971{
814 struct ip6_tnl *t = netdev_priv(dev); 972 struct ip6_tnl *t = netdev_priv(dev);
@@ -867,6 +1025,9 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
867 } 1025 }
868 1026
869 switch (skb->protocol) { 1027 switch (skb->protocol) {
1028 case __constant_htons(ETH_P_IP):
1029 ret = ip4ip6_tnl_xmit(skb, dev);
1030 break;
870 case __constant_htons(ETH_P_IPV6): 1031 case __constant_htons(ETH_P_IPV6):
871 ret = ip6ip6_tnl_xmit(skb, dev); 1032 ret = ip6ip6_tnl_xmit(skb, dev);
872 break; 1033 break;
@@ -1199,6 +1360,12 @@ ip6ip6_fb_tnl_dev_init(struct net_device *dev)
1199 return 0; 1360 return 0;
1200} 1361}
1201 1362
1363static struct xfrm6_tunnel ip4ip6_handler = {
1364 .handler = ip4ip6_rcv,
1365 .err_handler = ip4ip6_err,
1366 .priority = 1,
1367};
1368
1202static struct xfrm6_tunnel ip6ip6_handler = { 1369static struct xfrm6_tunnel ip6ip6_handler = {
1203 .handler = ip6ip6_rcv, 1370 .handler = ip6ip6_rcv,
1204 .err_handler = ip6ip6_err, 1371 .err_handler = ip6ip6_err,
@@ -1215,9 +1382,16 @@ static int __init ip6_tunnel_init(void)
1215{ 1382{
1216 int err; 1383 int err;
1217 1384
1385 if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) {
1386 printk(KERN_ERR "ip4ip6 init: can't register tunnel\n");
1387 err = -EAGAIN;
1388 goto out;
1389 }
1390
1218 if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { 1391 if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
1219 printk(KERN_ERR "ip6ip6 init: can't register tunnel\n"); 1392 printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
1220 return -EAGAIN; 1393 err = -EAGAIN;
1394 goto unreg_ip4ip6;
1221 } 1395 }
1222 ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", 1396 ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
1223 ip6ip6_tnl_dev_setup); 1397 ip6ip6_tnl_dev_setup);
@@ -1235,6 +1409,9 @@ static int __init ip6_tunnel_init(void)
1235 return 0; 1409 return 0;
1236fail: 1410fail:
1237 xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); 1411 xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
1412unreg_ip4ip6:
1413 xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
1414out:
1238 return err; 1415 return err;
1239} 1416}
1240 1417
@@ -1258,6 +1435,9 @@ static void __exit ip6ip6_destroy_tunnels(void)
1258 1435
1259static void __exit ip6_tunnel_cleanup(void) 1436static void __exit ip6_tunnel_cleanup(void)
1260{ 1437{
1438 if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
1439 printk(KERN_INFO "ip4ip6 close: can't deregister tunnel\n");
1440
1261 if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) 1441 if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
1262 printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n"); 1442 printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
1263 1443