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.c56
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)
421static int 421static int
422ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) 422ipip6_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 }