aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
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 }