diff options
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 32 |
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 | ||
1296 | static 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 | |||
1288 | static void | 1304 | static void |
1289 | ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) | 1305 | ip6_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; |