diff options
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d2c16e10f650..43b33373adb2 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -412,7 +412,7 @@ static void prl_list_destroy_rcu(struct rcu_head *head) | |||
412 | 412 | ||
413 | p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); | 413 | p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); |
414 | do { | 414 | do { |
415 | n = p->next; | 415 | n = rcu_dereference_protected(p->next, 1); |
416 | kfree(p); | 416 | kfree(p); |
417 | p = n; | 417 | p = n; |
418 | } while (p); | 418 | } while (p); |
@@ -421,15 +421,17 @@ static void prl_list_destroy_rcu(struct rcu_head *head) | |||
421 | static int | 421 | static int |
422 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 422 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) |
423 | { | 423 | { |
424 | struct ip_tunnel_prl_entry *x, **p; | 424 | struct ip_tunnel_prl_entry *x; |
425 | struct ip_tunnel_prl_entry __rcu **p; | ||
425 | int err = 0; | 426 | int err = 0; |
426 | 427 | ||
427 | ASSERT_RTNL(); | 428 | ASSERT_RTNL(); |
428 | 429 | ||
429 | if (a && a->addr != htonl(INADDR_ANY)) { | 430 | if (a && a->addr != htonl(INADDR_ANY)) { |
430 | for (p = &t->prl; *p; p = &(*p)->next) { | 431 | for (p = &t->prl; |
431 | if ((*p)->addr == a->addr) { | 432 | (x = rtnl_dereference(*p)) != NULL; |
432 | x = *p; | 433 | p = &x->next) { |
434 | if (x->addr == a->addr) { | ||
433 | *p = x->next; | 435 | *p = x->next; |
434 | call_rcu(&x->rcu_head, prl_entry_destroy_rcu); | 436 | call_rcu(&x->rcu_head, prl_entry_destroy_rcu); |
435 | t->prl_count--; | 437 | t->prl_count--; |
@@ -438,9 +440,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
438 | } | 440 | } |
439 | err = -ENXIO; | 441 | err = -ENXIO; |
440 | } else { | 442 | } else { |
441 | if (t->prl) { | 443 | x = rtnl_dereference(t->prl); |
444 | if (x) { | ||
442 | t->prl_count = 0; | 445 | t->prl_count = 0; |
443 | x = t->prl; | ||
444 | call_rcu(&x->rcu_head, prl_list_destroy_rcu); | 446 | call_rcu(&x->rcu_head, prl_list_destroy_rcu); |
445 | t->prl = NULL; | 447 | t->prl = NULL; |
446 | } | 448 | } |
@@ -730,16 +732,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
730 | dst = addr6->s6_addr32[3]; | 732 | dst = addr6->s6_addr32[3]; |
731 | } | 733 | } |
732 | 734 | ||
733 | { | 735 | rt = ip_route_output_ports(dev_net(dev), NULL, |
734 | struct flowi fl = { .fl4_dst = dst, | 736 | dst, tiph->saddr, |
735 | .fl4_src = tiph->saddr, | 737 | 0, 0, |
736 | .fl4_tos = RT_TOS(tos), | 738 | IPPROTO_IPV6, RT_TOS(tos), |
737 | .oif = tunnel->parms.link, | 739 | tunnel->parms.link); |
738 | .proto = IPPROTO_IPV6 }; | 740 | if (IS_ERR(rt)) { |
739 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 741 | dev->stats.tx_carrier_errors++; |
740 | dev->stats.tx_carrier_errors++; | 742 | goto tx_error_icmp; |
741 | goto tx_error_icmp; | ||
742 | } | ||
743 | } | 743 | } |
744 | if (rt->rt_type != RTN_UNICAST) { | 744 | if (rt->rt_type != RTN_UNICAST) { |
745 | ip_rt_put(rt); | 745 | ip_rt_put(rt); |
@@ -855,13 +855,14 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
855 | iph = &tunnel->parms.iph; | 855 | iph = &tunnel->parms.iph; |
856 | 856 | ||
857 | if (iph->daddr) { | 857 | if (iph->daddr) { |
858 | struct flowi fl = { .fl4_dst = iph->daddr, | 858 | struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL, |
859 | .fl4_src = iph->saddr, | 859 | iph->daddr, iph->saddr, |
860 | .fl4_tos = RT_TOS(iph->tos), | 860 | 0, 0, |
861 | .oif = tunnel->parms.link, | 861 | IPPROTO_IPV6, |
862 | .proto = IPPROTO_IPV6 }; | 862 | RT_TOS(iph->tos), |
863 | struct rtable *rt; | 863 | tunnel->parms.link); |
864 | if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 864 | |
865 | if (!IS_ERR(rt)) { | ||
865 | tdev = rt->dst.dev; | 866 | tdev = rt->dst.dev; |
866 | ip_rt_put(rt); | 867 | ip_rt_put(rt); |
867 | } | 868 | } |
@@ -1179,7 +1180,7 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
1179 | if (!dev->tstats) | 1180 | if (!dev->tstats) |
1180 | return -ENOMEM; | 1181 | return -ENOMEM; |
1181 | dev_hold(dev); | 1182 | dev_hold(dev); |
1182 | sitn->tunnels_wc[0] = tunnel; | 1183 | rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); |
1183 | return 0; | 1184 | return 0; |
1184 | } | 1185 | } |
1185 | 1186 | ||
@@ -1196,11 +1197,12 @@ static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_hea | |||
1196 | for (prio = 1; prio < 4; prio++) { | 1197 | for (prio = 1; prio < 4; prio++) { |
1197 | int h; | 1198 | int h; |
1198 | for (h = 0; h < HASH_SIZE; h++) { | 1199 | for (h = 0; h < HASH_SIZE; h++) { |
1199 | struct ip_tunnel *t = sitn->tunnels[prio][h]; | 1200 | struct ip_tunnel *t; |
1200 | 1201 | ||
1202 | t = rtnl_dereference(sitn->tunnels[prio][h]); | ||
1201 | while (t != NULL) { | 1203 | while (t != NULL) { |
1202 | unregister_netdevice_queue(t->dev, head); | 1204 | unregister_netdevice_queue(t->dev, head); |
1203 | t = t->next; | 1205 | t = rtnl_dereference(t->next); |
1204 | } | 1206 | } |
1205 | } | 1207 | } |
1206 | } | 1208 | } |