aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/ip6_tunnel.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 9409887fb664..8c97cd1048c2 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -477,6 +477,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
477 int rel_msg = 0; 477 int rel_msg = 0;
478 u8 rel_type = ICMPV6_DEST_UNREACH; 478 u8 rel_type = ICMPV6_DEST_UNREACH;
479 u8 rel_code = ICMPV6_ADDR_UNREACH; 479 u8 rel_code = ICMPV6_ADDR_UNREACH;
480 u8 tproto;
480 __u32 rel_info = 0; 481 __u32 rel_info = 0;
481 __u16 len; 482 __u16 len;
482 int err = -ENOENT; 483 int err = -ENOENT;
@@ -490,7 +491,8 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
490 &ipv6h->saddr)) == NULL) 491 &ipv6h->saddr)) == NULL)
491 goto out; 492 goto out;
492 493
493 if (t->parms.proto != ipproto && t->parms.proto != 0) 494 tproto = ACCESS_ONCE(t->parms.proto);
495 if (tproto != ipproto && tproto != 0)
494 goto out; 496 goto out;
495 497
496 err = 0; 498 err = 0;
@@ -791,6 +793,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
791{ 793{
792 struct ip6_tnl *t; 794 struct ip6_tnl *t;
793 const struct ipv6hdr *ipv6h = ipv6_hdr(skb); 795 const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
796 u8 tproto;
794 int err; 797 int err;
795 798
796 rcu_read_lock(); 799 rcu_read_lock();
@@ -799,7 +802,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
799 &ipv6h->daddr)) != NULL) { 802 &ipv6h->daddr)) != NULL) {
800 struct pcpu_sw_netstats *tstats; 803 struct pcpu_sw_netstats *tstats;
801 804
802 if (t->parms.proto != ipproto && t->parms.proto != 0) { 805 tproto = ACCESS_ONCE(t->parms.proto);
806 if (tproto != ipproto && tproto != 0) {
803 rcu_read_unlock(); 807 rcu_read_unlock();
804 goto discard; 808 goto discard;
805 } 809 }
@@ -1078,9 +1082,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
1078 struct flowi6 fl6; 1082 struct flowi6 fl6;
1079 __u8 dsfield; 1083 __u8 dsfield;
1080 __u32 mtu; 1084 __u32 mtu;
1085 u8 tproto;
1081 int err; 1086 int err;
1082 1087
1083 if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) || 1088 tproto = ACCESS_ONCE(t->parms.proto);
1089 if ((tproto != IPPROTO_IPIP && tproto != 0) ||
1084 !ip6_tnl_xmit_ctl(t)) 1090 !ip6_tnl_xmit_ctl(t))
1085 return -1; 1091 return -1;
1086 1092
@@ -1120,9 +1126,11 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
1120 struct flowi6 fl6; 1126 struct flowi6 fl6;
1121 __u8 dsfield; 1127 __u8 dsfield;
1122 __u32 mtu; 1128 __u32 mtu;
1129 u8 tproto;
1123 int err; 1130 int err;
1124 1131
1125 if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || 1132 tproto = ACCESS_ONCE(t->parms.proto);
1133 if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
1126 !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) 1134 !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
1127 return -1; 1135 return -1;
1128 1136
@@ -1285,6 +1293,14 @@ static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
1285 return err; 1293 return err;
1286} 1294}
1287 1295
1296static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
1297{
1298 /* for default tnl0 device allow to change only the proto */
1299 t->parms.proto = p->proto;
1300 netdev_state_change(t->dev);
1301 return 0;
1302}
1303
1288static void 1304static void
1289ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) 1305ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
1290{ 1306{
@@ -1384,7 +1400,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1384 break; 1400 break;
1385 ip6_tnl_parm_from_user(&p1, &p); 1401 ip6_tnl_parm_from_user(&p1, &p);
1386 t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL); 1402 t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
1387 if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { 1403 if (cmd == SIOCCHGTUNNEL) {
1388 if (t != NULL) { 1404 if (t != NULL) {
1389 if (t->dev != dev) { 1405 if (t->dev != dev) {
1390 err = -EEXIST; 1406 err = -EEXIST;
@@ -1392,8 +1408,10 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1392 } 1408 }
1393 } else 1409 } else
1394 t = netdev_priv(dev); 1410 t = netdev_priv(dev);
1395 1411 if (dev == ip6n->fb_tnl_dev)
1396 err = ip6_tnl_update(t, &p1); 1412 err = ip6_tnl0_update(t, &p1);
1413 else
1414 err = ip6_tnl_update(t, &p1);
1397 } 1415 }
1398 if (t) { 1416 if (t) {
1399 err = 0; 1417 err = 0;