aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/esp6_offload.c8
-rw-r--r--net/ipv6/ip6_fib.c4
-rw-r--r--net/ipv6/ip6_flowlabel.c22
-rw-r--r--net/ipv6/route.c70
-rw-r--r--net/ipv6/xfrm6_tunnel.c6
5 files changed, 62 insertions, 48 deletions
diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c
index bff83279d76f..d453cf417b03 100644
--- a/net/ipv6/esp6_offload.c
+++ b/net/ipv6/esp6_offload.c
@@ -74,13 +74,13 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
74 goto out; 74 goto out;
75 75
76 if (sp->len == XFRM_MAX_DEPTH) 76 if (sp->len == XFRM_MAX_DEPTH)
77 goto out; 77 goto out_reset;
78 78
79 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, 79 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
80 (xfrm_address_t *)&ipv6_hdr(skb)->daddr, 80 (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
81 spi, IPPROTO_ESP, AF_INET6); 81 spi, IPPROTO_ESP, AF_INET6);
82 if (!x) 82 if (!x)
83 goto out; 83 goto out_reset;
84 84
85 sp->xvec[sp->len++] = x; 85 sp->xvec[sp->len++] = x;
86 sp->olen++; 86 sp->olen++;
@@ -88,7 +88,7 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
88 xo = xfrm_offload(skb); 88 xo = xfrm_offload(skb);
89 if (!xo) { 89 if (!xo) {
90 xfrm_state_put(x); 90 xfrm_state_put(x);
91 goto out; 91 goto out_reset;
92 } 92 }
93 } 93 }
94 94
@@ -109,6 +109,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
109 xfrm_input(skb, IPPROTO_ESP, spi, -2); 109 xfrm_input(skb, IPPROTO_ESP, spi, -2);
110 110
111 return ERR_PTR(-EINPROGRESS); 111 return ERR_PTR(-EINPROGRESS);
112out_reset:
113 secpath_reset(skb);
112out: 114out:
113 skb_push(skb, offset); 115 skb_push(skb, offset);
114 NAPI_GRO_CB(skb)->same_flow = 0; 116 NAPI_GRO_CB(skb)->same_flow = 0;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index a8919c217cc2..08e0390e001c 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -916,9 +916,7 @@ static void fib6_drop_pcpu_from(struct fib6_info *f6i,
916 if (pcpu_rt) { 916 if (pcpu_rt) {
917 struct fib6_info *from; 917 struct fib6_info *from;
918 918
919 from = rcu_dereference_protected(pcpu_rt->from, 919 from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL);
920 lockdep_is_held(&table->tb6_lock));
921 rcu_assign_pointer(pcpu_rt->from, NULL);
922 fib6_info_release(from); 920 fib6_info_release(from);
923 } 921 }
924 } 922 }
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index cb54a8a3c273..be5f3d7ceb96 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -94,15 +94,21 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
94 return fl; 94 return fl;
95} 95}
96 96
97static void fl_free_rcu(struct rcu_head *head)
98{
99 struct ip6_flowlabel *fl = container_of(head, struct ip6_flowlabel, rcu);
100
101 if (fl->share == IPV6_FL_S_PROCESS)
102 put_pid(fl->owner.pid);
103 kfree(fl->opt);
104 kfree(fl);
105}
106
97 107
98static void fl_free(struct ip6_flowlabel *fl) 108static void fl_free(struct ip6_flowlabel *fl)
99{ 109{
100 if (fl) { 110 if (fl)
101 if (fl->share == IPV6_FL_S_PROCESS) 111 call_rcu(&fl->rcu, fl_free_rcu);
102 put_pid(fl->owner.pid);
103 kfree(fl->opt);
104 kfree_rcu(fl, rcu);
105 }
106} 112}
107 113
108static void fl_release(struct ip6_flowlabel *fl) 114static void fl_release(struct ip6_flowlabel *fl)
@@ -633,9 +639,9 @@ recheck:
633 if (fl1->share == IPV6_FL_S_EXCL || 639 if (fl1->share == IPV6_FL_S_EXCL ||
634 fl1->share != fl->share || 640 fl1->share != fl->share ||
635 ((fl1->share == IPV6_FL_S_PROCESS) && 641 ((fl1->share == IPV6_FL_S_PROCESS) &&
636 (fl1->owner.pid == fl->owner.pid)) || 642 (fl1->owner.pid != fl->owner.pid)) ||
637 ((fl1->share == IPV6_FL_S_USER) && 643 ((fl1->share == IPV6_FL_S_USER) &&
638 uid_eq(fl1->owner.uid, fl->owner.uid))) 644 !uid_eq(fl1->owner.uid, fl->owner.uid)))
639 goto release; 645 goto release;
640 646
641 err = -ENOMEM; 647 err = -ENOMEM;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b18e85cd7587..23a20d62daac 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -380,11 +380,8 @@ static void ip6_dst_destroy(struct dst_entry *dst)
380 in6_dev_put(idev); 380 in6_dev_put(idev);
381 } 381 }
382 382
383 rcu_read_lock(); 383 from = xchg((__force struct fib6_info **)&rt->from, NULL);
384 from = rcu_dereference(rt->from);
385 rcu_assign_pointer(rt->from, NULL);
386 fib6_info_release(from); 384 fib6_info_release(from);
387 rcu_read_unlock();
388} 385}
389 386
390static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 387static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
@@ -1323,9 +1320,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1323 /* purge completely the exception to allow releasing the held resources: 1320 /* purge completely the exception to allow releasing the held resources:
1324 * some [sk] cache may keep the dst around for unlimited time 1321 * some [sk] cache may keep the dst around for unlimited time
1325 */ 1322 */
1326 from = rcu_dereference_protected(rt6_ex->rt6i->from, 1323 from = xchg((__force struct fib6_info **)&rt6_ex->rt6i->from, NULL);
1327 lockdep_is_held(&rt6_exception_lock));
1328 rcu_assign_pointer(rt6_ex->rt6i->from, NULL);
1329 fib6_info_release(from); 1324 fib6_info_release(from);
1330 dst_dev_put(&rt6_ex->rt6i->dst); 1325 dst_dev_put(&rt6_ex->rt6i->dst);
1331 1326
@@ -3495,11 +3490,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3495 3490
3496 rcu_read_lock(); 3491 rcu_read_lock();
3497 res.f6i = rcu_dereference(rt->from); 3492 res.f6i = rcu_dereference(rt->from);
3498 /* This fib6_info_hold() is safe here because we hold reference to rt 3493 if (!res.f6i)
3499 * and rt already holds reference to fib6_info. 3494 goto out;
3500 */
3501 fib6_info_hold(res.f6i);
3502 rcu_read_unlock();
3503 3495
3504 res.nh = &res.f6i->fib6_nh; 3496 res.nh = &res.f6i->fib6_nh;
3505 res.fib6_flags = res.f6i->fib6_flags; 3497 res.fib6_flags = res.f6i->fib6_flags;
@@ -3514,10 +3506,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3514 3506
3515 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; 3507 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
3516 3508
3517 /* No need to remove rt from the exception table if rt is 3509 /* rt6_insert_exception() will take care of duplicated exceptions */
3518 * a cached route because rt6_insert_exception() will
3519 * takes care of it
3520 */
3521 if (rt6_insert_exception(nrt, &res)) { 3510 if (rt6_insert_exception(nrt, &res)) {
3522 dst_release_immediate(&nrt->dst); 3511 dst_release_immediate(&nrt->dst);
3523 goto out; 3512 goto out;
@@ -3530,7 +3519,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3530 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); 3519 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3531 3520
3532out: 3521out:
3533 fib6_info_release(res.f6i); 3522 rcu_read_unlock();
3534 neigh_release(neigh); 3523 neigh_release(neigh);
3535} 3524}
3536 3525
@@ -3772,23 +3761,34 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
3772 3761
3773static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) 3762static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
3774{ 3763{
3775 int type;
3776 struct dst_entry *dst = skb_dst(skb); 3764 struct dst_entry *dst = skb_dst(skb);
3765 struct net *net = dev_net(dst->dev);
3766 struct inet6_dev *idev;
3767 int type;
3768
3769 if (netif_is_l3_master(skb->dev) &&
3770 dst->dev == net->loopback_dev)
3771 idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
3772 else
3773 idev = ip6_dst_idev(dst);
3774
3777 switch (ipstats_mib_noroutes) { 3775 switch (ipstats_mib_noroutes) {
3778 case IPSTATS_MIB_INNOROUTES: 3776 case IPSTATS_MIB_INNOROUTES:
3779 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); 3777 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
3780 if (type == IPV6_ADDR_ANY) { 3778 if (type == IPV6_ADDR_ANY) {
3781 IP6_INC_STATS(dev_net(dst->dev), 3779 IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
3782 __in6_dev_get_safely(skb->dev),
3783 IPSTATS_MIB_INADDRERRORS);
3784 break; 3780 break;
3785 } 3781 }
3786 /* FALLTHROUGH */ 3782 /* FALLTHROUGH */
3787 case IPSTATS_MIB_OUTNOROUTES: 3783 case IPSTATS_MIB_OUTNOROUTES:
3788 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), 3784 IP6_INC_STATS(net, idev, ipstats_mib_noroutes);
3789 ipstats_mib_noroutes);
3790 break; 3785 break;
3791 } 3786 }
3787
3788 /* Start over by dropping the dst for l3mdev case */
3789 if (netif_is_l3_master(skb->dev))
3790 skb_dst_drop(skb);
3791
3792 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); 3792 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
3793 kfree_skb(skb); 3793 kfree_skb(skb);
3794 return 0; 3794 return 0;
@@ -5056,16 +5056,20 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
5056 5056
5057 rcu_read_lock(); 5057 rcu_read_lock();
5058 from = rcu_dereference(rt->from); 5058 from = rcu_dereference(rt->from);
5059 5059 if (from) {
5060 if (fibmatch) 5060 if (fibmatch)
5061 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif, 5061 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL,
5062 RTM_NEWROUTE, NETLINK_CB(in_skb).portid, 5062 iif, RTM_NEWROUTE,
5063 nlh->nlmsg_seq, 0); 5063 NETLINK_CB(in_skb).portid,
5064 else 5064 nlh->nlmsg_seq, 0);
5065 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr, 5065 else
5066 &fl6.saddr, iif, RTM_NEWROUTE, 5066 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5067 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 5067 &fl6.saddr, iif, RTM_NEWROUTE,
5068 0); 5068 NETLINK_CB(in_skb).portid,
5069 nlh->nlmsg_seq, 0);
5070 } else {
5071 err = -ENETUNREACH;
5072 }
5069 rcu_read_unlock(); 5073 rcu_read_unlock();
5070 5074
5071 if (err < 0) { 5075 if (err < 0) {
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index bc65db782bfb..d9e5f6808811 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -345,7 +345,7 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
345 unsigned int i; 345 unsigned int i;
346 346
347 xfrm_flush_gc(); 347 xfrm_flush_gc();
348 xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); 348 xfrm_state_flush(net, 0, false, true);
349 349
350 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) 350 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
351 WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); 351 WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i]));
@@ -402,6 +402,10 @@ static void __exit xfrm6_tunnel_fini(void)
402 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); 402 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
403 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); 403 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
404 unregister_pernet_subsys(&xfrm6_tunnel_net_ops); 404 unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
405 /* Someone maybe has gotten the xfrm6_tunnel_spi.
406 * So need to wait it.
407 */
408 rcu_barrier();
405 kmem_cache_destroy(xfrm6_tunnel_spi_kmem); 409 kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
406} 410}
407 411