aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>2009-09-22 19:43:14 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-07 04:07:37 -0400
commitfa857afcf77da669eb6b7031ec07ad14b912c307 (patch)
tree3dcc3899a968e2e21f912442ebfb4cac46f93a0c /net/ipv6/sit.c
parentee5e81f00051b5c373c8de16e3604fd6d3be699e (diff)
ipv6 sit: 6rd (IPv6 Rapid Deployment) Support.
IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly deploy IPv6 unicast service to IPv4 sites to which it provides customer premise equipment. Like 6to4, it utilizes stateless IPv6 in IPv4 encapsulation in order to transit IPv4-only network infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6 prefix of its own in place of the fixed 6to4 prefix. With this option enabled, the SIT driver offers 6rd functionality by providing additional ioctl API to configure the IPv6 Prefix for in stead of static 2002::/16 for 6to4. Original patch was done by Alexandre Cassen <acassen@freebox.fr> based on old Internet-Draft. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c124
1 files changed, 116 insertions, 8 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 99da272951dc..6955654262a5 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -161,6 +161,21 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
161 write_unlock_bh(&ipip6_lock); 161 write_unlock_bh(&ipip6_lock);
162} 162}
163 163
164static void ipip6_tunnel_clone_6rd(struct ip_tunnel *t, struct sit_net *sitn)
165{
166#ifdef CONFIG_IPV6_SIT_6RD
167 if (t->dev == sitn->fb_tunnel_dev) {
168 ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
169 t->ip6rd.relay_prefix = 0;
170 t->ip6rd.prefixlen = 16;
171 t->ip6rd.relay_prefixlen = 0;
172 } else {
173 struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
174 memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
175 }
176#endif
177}
178
164static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, 179static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
165 struct ip_tunnel_parm *parms, int create) 180 struct ip_tunnel_parm *parms, int create)
166{ 181{
@@ -213,6 +228,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
213 228
214 dev_hold(dev); 229 dev_hold(dev);
215 230
231 ipip6_tunnel_clone_6rd(t, sitn);
232
216 ipip6_tunnel_link(sitn, nt); 233 ipip6_tunnel_link(sitn, nt);
217 return nt; 234 return nt;
218 235
@@ -532,17 +549,41 @@ out:
532 return 0; 549 return 0;
533} 550}
534 551
535/* Returns the embedded IPv4 address if the IPv6 address 552/*
536 comes from 6to4 (RFC 3056) addr space */ 553 * Returns the embedded IPv4 address if the IPv6 address
537 554 * comes from 6rd / 6to4 (RFC 3056) addr space.
538static inline __be32 try_6to4(struct in6_addr *v6dst) 555 */
556static inline
557__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
539{ 558{
540 __be32 dst = 0; 559 __be32 dst = 0;
541 560
561#ifdef CONFIG_IPV6_SIT_6RD
562 if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
563 tunnel->ip6rd.prefixlen)) {
564 unsigned pbw0, pbi0;
565 int pbi1;
566 u32 d;
567
568 pbw0 = tunnel->ip6rd.prefixlen >> 5;
569 pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
570
571 d = (ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0]) << pbi0) >>
572 tunnel->ip6rd.relay_prefixlen;
573
574 pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
575 if (pbi1 > 0)
576 d |= ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0 + 1]) >>
577 (32 - pbi1);
578
579 dst = tunnel->ip6rd.relay_prefix | htonl(d);
580 }
581#else
542 if (v6dst->s6_addr16[0] == htons(0x2002)) { 582 if (v6dst->s6_addr16[0] == htons(0x2002)) {
543 /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ 583 /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
544 memcpy(&dst, &v6dst->s6_addr16[1], 4); 584 memcpy(&dst, &v6dst->s6_addr16[1], 4);
545 } 585 }
586#endif
546 return dst; 587 return dst;
547} 588}
548 589
@@ -596,7 +637,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
596 } 637 }
597 638
598 if (!dst) 639 if (!dst)
599 dst = try_6to4(&iph6->daddr); 640 dst = try_6rd(&iph6->daddr, tunnel);
600 641
601 if (!dst) { 642 if (!dst) {
602 struct neighbour *neigh = NULL; 643 struct neighbour *neigh = NULL;
@@ -786,9 +827,15 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
786 struct ip_tunnel *t; 827 struct ip_tunnel *t;
787 struct net *net = dev_net(dev); 828 struct net *net = dev_net(dev);
788 struct sit_net *sitn = net_generic(net, sit_net_id); 829 struct sit_net *sitn = net_generic(net, sit_net_id);
830#ifdef CONFIG_IPV6_SIT_6RD
831 struct ip_tunnel_6rd ip6rd;
832#endif
789 833
790 switch (cmd) { 834 switch (cmd) {
791 case SIOCGETTUNNEL: 835 case SIOCGETTUNNEL:
836#ifdef CONFIG_IPV6_SIT_6RD
837 case SIOCGET6RD:
838#endif
792 t = NULL; 839 t = NULL;
793 if (dev == sitn->fb_tunnel_dev) { 840 if (dev == sitn->fb_tunnel_dev) {
794 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { 841 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
@@ -799,9 +846,25 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
799 } 846 }
800 if (t == NULL) 847 if (t == NULL)
801 t = netdev_priv(dev); 848 t = netdev_priv(dev);
802 memcpy(&p, &t->parms, sizeof(p)); 849
803 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 850 err = -EFAULT;
804 err = -EFAULT; 851 if (cmd == SIOCGETTUNNEL) {
852 memcpy(&p, &t->parms, sizeof(p));
853 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
854 sizeof(p)))
855 goto done;
856#ifdef CONFIG_IPV6_SIT_6RD
857 } else {
858 ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix);
859 ip6rd.relay_prefix = t->ip6rd.relay_prefix;
860 ip6rd.prefixlen = t->ip6rd.prefixlen;
861 ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
862 if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
863 sizeof(ip6rd)))
864 goto done;
865#endif
866 }
867 err = 0;
805 break; 868 break;
806 869
807 case SIOCADDTUNNEL: 870 case SIOCADDTUNNEL:
@@ -922,6 +985,51 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
922 netdev_state_change(dev); 985 netdev_state_change(dev);
923 break; 986 break;
924 987
988#ifdef CONFIG_IPV6_SIT_6RD
989 case SIOCADD6RD:
990 case SIOCCHG6RD:
991 case SIOCDEL6RD:
992 err = -EPERM;
993 if (!capable(CAP_NET_ADMIN))
994 goto done;
995
996 err = -EFAULT;
997 if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
998 sizeof(ip6rd)))
999 goto done;
1000
1001 t = netdev_priv(dev);
1002
1003 if (cmd != SIOCDEL6RD) {
1004 struct in6_addr prefix;
1005 __be32 relay_prefix;
1006
1007 err = -EINVAL;
1008 if (ip6rd.relay_prefixlen > 32 ||
1009 ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
1010 goto done;
1011
1012 ipv6_addr_prefix(&prefix, &ip6rd.prefix,
1013 ip6rd.prefixlen);
1014 if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
1015 goto done;
1016 relay_prefix = ip6rd.relay_prefix &
1017 htonl(0xffffffffUL <<
1018 (32 - ip6rd.relay_prefixlen));
1019 if (relay_prefix != ip6rd.relay_prefix)
1020 goto done;
1021
1022 ipv6_addr_copy(&t->ip6rd.prefix, &prefix);
1023 t->ip6rd.relay_prefix = relay_prefix;
1024 t->ip6rd.prefixlen = ip6rd.prefixlen;
1025 t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
1026 } else
1027 ipip6_tunnel_clone_6rd(t, sitn);
1028
1029 err = 0;
1030 break;
1031#endif
1032
925 default: 1033 default:
926 err = -EINVAL; 1034 err = -EINVAL;
927 } 1035 }