diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 5 | ||||
-rw-r--r-- | net/ipv6/addrlabel.c | 5 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 6 | ||||
-rw-r--r-- | net/ipv6/exthdrs_core.c | 4 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 6 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 67 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 4 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 26 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 14 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 2 | ||||
-rw-r--r-- | net/ipv6/protocol.c | 32 | ||||
-rw-r--r-- | net/ipv6/raw.c | 12 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 2 | ||||
-rw-r--r-- | net/ipv6/route.c | 14 | ||||
-rw-r--r-- | net/ipv6/sit.c | 71 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 | ||||
-rw-r--r-- | net/ipv6/tunnel6.c | 17 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 2 | ||||
-rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 4 |
19 files changed, 145 insertions, 150 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 324fac3b6c16..8c88340278f5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -243,7 +243,7 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
243 | /* Check if a route is valid prefix route */ | 243 | /* Check if a route is valid prefix route */ |
244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | 244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) |
245 | { | 245 | { |
246 | return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0); | 246 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; |
247 | } | 247 | } |
248 | 248 | ||
249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -2964,7 +2964,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2964 | start sending router solicitations. | 2964 | start sending router solicitations. |
2965 | */ | 2965 | */ |
2966 | 2966 | ||
2967 | if (ifp->idev->cnf.forwarding == 0 && | 2967 | if ((ifp->idev->cnf.forwarding == 0 || |
2968 | ifp->idev->cnf.forwarding == 2) && | ||
2968 | ifp->idev->cnf.rtr_solicits > 0 && | 2969 | ifp->idev->cnf.rtr_solicits > 0 && |
2969 | (dev->flags&IFF_LOOPBACK) == 0 && | 2970 | (dev->flags&IFF_LOOPBACK) == 0 && |
2970 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 2971 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 8175f802651b..c8993e5a337c 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -518,10 +518,9 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
518 | 518 | ||
519 | static inline int ip6addrlbl_msgsize(void) | 519 | static inline int ip6addrlbl_msgsize(void) |
520 | { | 520 | { |
521 | return (NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) | 521 | return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) |
522 | + nla_total_size(16) /* IFAL_ADDRESS */ | 522 | + nla_total_size(16) /* IFAL_ADDRESS */ |
523 | + nla_total_size(4) /* IFAL_LABEL */ | 523 | + nla_total_size(4); /* IFAL_LABEL */ |
524 | ); | ||
525 | } | 524 | } |
526 | 525 | ||
527 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, | 526 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 56b9bf2516f4..60220985bb80 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -467,7 +467,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
467 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 467 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
468 | sin->sin6_scope_id = sk->sk_bound_dev_if; | 468 | sin->sin6_scope_id = sk->sk_bound_dev_if; |
469 | *uaddr_len = sizeof(*sin); | 469 | *uaddr_len = sizeof(*sin); |
470 | return(0); | 470 | return 0; |
471 | } | 471 | } |
472 | 472 | ||
473 | EXPORT_SYMBOL(inet6_getname); | 473 | EXPORT_SYMBOL(inet6_getname); |
@@ -488,7 +488,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
488 | case SIOCADDRT: | 488 | case SIOCADDRT: |
489 | case SIOCDELRT: | 489 | case SIOCDELRT: |
490 | 490 | ||
491 | return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); | 491 | return ipv6_route_ioctl(net, cmd, (void __user *)arg); |
492 | 492 | ||
493 | case SIOCSIFADDR: | 493 | case SIOCSIFADDR: |
494 | return addrconf_add_ifaddr(net, (void __user *) arg); | 494 | return addrconf_add_ifaddr(net, (void __user *) arg); |
@@ -502,7 +502,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
502 | return sk->sk_prot->ioctl(sk, cmd, arg); | 502 | return sk->sk_prot->ioctl(sk, cmd, arg); |
503 | } | 503 | } |
504 | /*NOTREACHED*/ | 504 | /*NOTREACHED*/ |
505 | return(0); | 505 | return 0; |
506 | } | 506 | } |
507 | 507 | ||
508 | EXPORT_SYMBOL(inet6_ioctl); | 508 | EXPORT_SYMBOL(inet6_ioctl); |
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index e1caa5d526c2..14ed0a955b56 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
@@ -13,12 +13,12 @@ int ipv6_ext_hdr(u8 nexthdr) | |||
13 | /* | 13 | /* |
14 | * find out if nexthdr is an extension header or a protocol | 14 | * find out if nexthdr is an extension header or a protocol |
15 | */ | 15 | */ |
16 | return ( (nexthdr == NEXTHDR_HOP) || | 16 | return (nexthdr == NEXTHDR_HOP) || |
17 | (nexthdr == NEXTHDR_ROUTING) || | 17 | (nexthdr == NEXTHDR_ROUTING) || |
18 | (nexthdr == NEXTHDR_FRAGMENT) || | 18 | (nexthdr == NEXTHDR_FRAGMENT) || |
19 | (nexthdr == NEXTHDR_AUTH) || | 19 | (nexthdr == NEXTHDR_AUTH) || |
20 | (nexthdr == NEXTHDR_NONE) || | 20 | (nexthdr == NEXTHDR_NONE) || |
21 | (nexthdr == NEXTHDR_DEST) ); | 21 | (nexthdr == NEXTHDR_DEST); |
22 | } | 22 | } |
23 | 23 | ||
24 | /* | 24 | /* |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 980912ed7a38..99157b4cd56e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -637,7 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
637 | } | 637 | } |
638 | mtu -= hlen + sizeof(struct frag_hdr); | 638 | mtu -= hlen + sizeof(struct frag_hdr); |
639 | 639 | ||
640 | if (skb_has_frags(skb)) { | 640 | if (skb_has_frag_list(skb)) { |
641 | int first_len = skb_pagelen(skb); | 641 | int first_len = skb_pagelen(skb); |
642 | struct sk_buff *frag2; | 642 | struct sk_buff *frag2; |
643 | 643 | ||
@@ -878,8 +878,8 @@ static inline int ip6_rt_check(struct rt6key *rt_key, | |||
878 | struct in6_addr *fl_addr, | 878 | struct in6_addr *fl_addr, |
879 | struct in6_addr *addr_cache) | 879 | struct in6_addr *addr_cache) |
880 | { | 880 | { |
881 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | 881 | return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && |
882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | 882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); |
883 | } | 883 | } |
884 | 884 | ||
885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 0fd027f3f47e..f6d9f683543e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -83,15 +83,14 @@ struct ip6_tnl_net { | |||
83 | /* the IPv6 tunnel fallback device */ | 83 | /* the IPv6 tunnel fallback device */ |
84 | struct net_device *fb_tnl_dev; | 84 | struct net_device *fb_tnl_dev; |
85 | /* lists for storing tunnels in use */ | 85 | /* lists for storing tunnels in use */ |
86 | struct ip6_tnl *tnls_r_l[HASH_SIZE]; | 86 | struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; |
87 | struct ip6_tnl *tnls_wc[1]; | 87 | struct ip6_tnl __rcu *tnls_wc[1]; |
88 | struct ip6_tnl **tnls[2]; | 88 | struct ip6_tnl __rcu **tnls[2]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * Locking : hash tables are protected by RCU and a spinlock | 92 | * Locking : hash tables are protected by RCU and RTNL |
93 | */ | 93 | */ |
94 | static DEFINE_SPINLOCK(ip6_tnl_lock); | ||
95 | 94 | ||
96 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 95 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
97 | { | 96 | { |
@@ -138,8 +137,8 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | |||
138 | static struct ip6_tnl * | 137 | static struct ip6_tnl * |
139 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | 138 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) |
140 | { | 139 | { |
141 | unsigned h0 = HASH(remote); | 140 | unsigned int h0 = HASH(remote); |
142 | unsigned h1 = HASH(local); | 141 | unsigned int h1 = HASH(local); |
143 | struct ip6_tnl *t; | 142 | struct ip6_tnl *t; |
144 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 143 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
145 | 144 | ||
@@ -167,7 +166,7 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
167 | * Return: head of IPv6 tunnel list | 166 | * Return: head of IPv6 tunnel list |
168 | **/ | 167 | **/ |
169 | 168 | ||
170 | static struct ip6_tnl ** | 169 | static struct ip6_tnl __rcu ** |
171 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | 170 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) |
172 | { | 171 | { |
173 | struct in6_addr *remote = &p->raddr; | 172 | struct in6_addr *remote = &p->raddr; |
@@ -190,12 +189,10 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | |||
190 | static void | 189 | static void |
191 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 190 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
192 | { | 191 | { |
193 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); | 192 | struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms); |
194 | 193 | ||
195 | spin_lock_bh(&ip6_tnl_lock); | 194 | rcu_assign_pointer(t->next , rtnl_dereference(*tp)); |
196 | t->next = *tp; | ||
197 | rcu_assign_pointer(*tp, t); | 195 | rcu_assign_pointer(*tp, t); |
198 | spin_unlock_bh(&ip6_tnl_lock); | ||
199 | } | 196 | } |
200 | 197 | ||
201 | /** | 198 | /** |
@@ -206,13 +203,14 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
206 | static void | 203 | static void |
207 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 204 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
208 | { | 205 | { |
209 | struct ip6_tnl **tp; | 206 | struct ip6_tnl __rcu **tp; |
210 | 207 | struct ip6_tnl *iter; | |
211 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { | 208 | |
212 | if (t == *tp) { | 209 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); |
213 | spin_lock_bh(&ip6_tnl_lock); | 210 | (iter = rtnl_dereference(*tp)) != NULL; |
214 | *tp = t->next; | 211 | tp = &iter->next) { |
215 | spin_unlock_bh(&ip6_tnl_lock); | 212 | if (t == iter) { |
213 | rcu_assign_pointer(*tp, t->next); | ||
216 | break; | 214 | break; |
217 | } | 215 | } |
218 | } | 216 | } |
@@ -290,10 +288,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net, | |||
290 | { | 288 | { |
291 | struct in6_addr *remote = &p->raddr; | 289 | struct in6_addr *remote = &p->raddr; |
292 | struct in6_addr *local = &p->laddr; | 290 | struct in6_addr *local = &p->laddr; |
291 | struct ip6_tnl __rcu **tp; | ||
293 | struct ip6_tnl *t; | 292 | struct ip6_tnl *t; |
294 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 293 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
295 | 294 | ||
296 | for (t = *ip6_tnl_bucket(ip6n, p); t; t = t->next) { | 295 | for (tp = ip6_tnl_bucket(ip6n, p); |
296 | (t = rtnl_dereference(*tp)) != NULL; | ||
297 | tp = &t->next) { | ||
297 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 298 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
298 | ipv6_addr_equal(remote, &t->parms.raddr)) | 299 | ipv6_addr_equal(remote, &t->parms.raddr)) |
299 | return t; | 300 | return t; |
@@ -318,13 +319,10 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
318 | struct net *net = dev_net(dev); | 319 | struct net *net = dev_net(dev); |
319 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 320 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
320 | 321 | ||
321 | if (dev == ip6n->fb_tnl_dev) { | 322 | if (dev == ip6n->fb_tnl_dev) |
322 | spin_lock_bh(&ip6_tnl_lock); | 323 | rcu_assign_pointer(ip6n->tnls_wc[0], NULL); |
323 | ip6n->tnls_wc[0] = NULL; | 324 | else |
324 | spin_unlock_bh(&ip6_tnl_lock); | ||
325 | } else { | ||
326 | ip6_tnl_unlink(ip6n, t); | 325 | ip6_tnl_unlink(ip6n, t); |
327 | } | ||
328 | ip6_tnl_dst_reset(t); | 326 | ip6_tnl_dst_reset(t); |
329 | dev_put(dev); | 327 | dev_put(dev); |
330 | } | 328 | } |
@@ -727,7 +725,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
727 | skb_tunnel_rx(skb, t->dev); | 725 | skb_tunnel_rx(skb, t->dev); |
728 | 726 | ||
729 | dscp_ecn_decapsulate(t, ipv6h, skb); | 727 | dscp_ecn_decapsulate(t, ipv6h, skb); |
730 | netif_rx(skb); | 728 | |
729 | if (netif_rx(skb) == NET_RX_DROP) | ||
730 | t->dev->stats.rx_dropped++; | ||
731 | |||
731 | rcu_read_unlock(); | 732 | rcu_read_unlock(); |
732 | return 0; | 733 | return 0; |
733 | } | 734 | } |
@@ -1369,16 +1370,16 @@ static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) | |||
1369 | ip6_tnl_dev_init_gen(dev); | 1370 | ip6_tnl_dev_init_gen(dev); |
1370 | t->parms.proto = IPPROTO_IPV6; | 1371 | t->parms.proto = IPPROTO_IPV6; |
1371 | dev_hold(dev); | 1372 | dev_hold(dev); |
1372 | ip6n->tnls_wc[0] = t; | 1373 | rcu_assign_pointer(ip6n->tnls_wc[0], t); |
1373 | } | 1374 | } |
1374 | 1375 | ||
1375 | static struct xfrm6_tunnel ip4ip6_handler = { | 1376 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { |
1376 | .handler = ip4ip6_rcv, | 1377 | .handler = ip4ip6_rcv, |
1377 | .err_handler = ip4ip6_err, | 1378 | .err_handler = ip4ip6_err, |
1378 | .priority = 1, | 1379 | .priority = 1, |
1379 | }; | 1380 | }; |
1380 | 1381 | ||
1381 | static struct xfrm6_tunnel ip6ip6_handler = { | 1382 | static struct xfrm6_tunnel ip6ip6_handler __read_mostly = { |
1382 | .handler = ip6ip6_rcv, | 1383 | .handler = ip6ip6_rcv, |
1383 | .err_handler = ip6ip6_err, | 1384 | .err_handler = ip6ip6_err, |
1384 | .priority = 1, | 1385 | .priority = 1, |
@@ -1391,14 +1392,14 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | |||
1391 | LIST_HEAD(list); | 1392 | LIST_HEAD(list); |
1392 | 1393 | ||
1393 | for (h = 0; h < HASH_SIZE; h++) { | 1394 | for (h = 0; h < HASH_SIZE; h++) { |
1394 | t = ip6n->tnls_r_l[h]; | 1395 | t = rtnl_dereference(ip6n->tnls_r_l[h]); |
1395 | while (t != NULL) { | 1396 | while (t != NULL) { |
1396 | unregister_netdevice_queue(t->dev, &list); | 1397 | unregister_netdevice_queue(t->dev, &list); |
1397 | t = t->next; | 1398 | t = rtnl_dereference(t->next); |
1398 | } | 1399 | } |
1399 | } | 1400 | } |
1400 | 1401 | ||
1401 | t = ip6n->tnls_wc[0]; | 1402 | t = rtnl_dereference(ip6n->tnls_wc[0]); |
1402 | unregister_netdevice_queue(t->dev, &list); | 1403 | unregister_netdevice_queue(t->dev, &list); |
1403 | unregister_netdevice_many(&list); | 1404 | unregister_netdevice_many(&list); |
1404 | } | 1405 | } |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 66078dad7fe8..2640c9be589d 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -666,7 +666,9 @@ static int pim6_rcv(struct sk_buff *skb) | |||
666 | 666 | ||
667 | skb_tunnel_rx(skb, reg_dev); | 667 | skb_tunnel_rx(skb, reg_dev); |
668 | 668 | ||
669 | netif_rx(skb); | 669 | if (netif_rx(skb) == NET_RX_DROP) |
670 | reg_dev->stats.rx_dropped++; | ||
671 | |||
670 | dev_put(reg_dev); | 672 | dev_put(reg_dev); |
671 | return 0; | 673 | return 0; |
672 | drop: | 674 | drop: |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 58841c4ae947..b3dd844cd34f 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -228,12 +228,12 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | |||
228 | do { | 228 | do { |
229 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 229 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
230 | } while(cur < end && cur->nd_opt_type != type); | 230 | } while(cur < end && cur->nd_opt_type != type); |
231 | return (cur <= end && cur->nd_opt_type == type ? cur : NULL); | 231 | return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
232 | } | 232 | } |
233 | 233 | ||
234 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) | 234 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) |
235 | { | 235 | { |
236 | return (opt->nd_opt_type == ND_OPT_RDNSS); | 236 | return opt->nd_opt_type == ND_OPT_RDNSS; |
237 | } | 237 | } |
238 | 238 | ||
239 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | 239 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, |
@@ -244,7 +244,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | |||
244 | do { | 244 | do { |
245 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 245 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
246 | } while(cur < end && !ndisc_is_useropt(cur)); | 246 | } while(cur < end && !ndisc_is_useropt(cur)); |
247 | return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL); | 247 | return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; |
248 | } | 248 | } |
249 | 249 | ||
250 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | 250 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, |
@@ -319,7 +319,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | |||
319 | int prepad = ndisc_addr_option_pad(dev->type); | 319 | int prepad = ndisc_addr_option_pad(dev->type); |
320 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) | 320 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) |
321 | return NULL; | 321 | return NULL; |
322 | return (lladdr + prepad); | 322 | return lladdr + prepad; |
323 | } | 323 | } |
324 | 324 | ||
325 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) | 325 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
@@ -1105,6 +1105,18 @@ errout: | |||
1105 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); | 1105 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static inline int accept_ra(struct inet6_dev *in6_dev) | ||
1109 | { | ||
1110 | /* | ||
1111 | * If forwarding is enabled, RA are not accepted unless the special | ||
1112 | * hybrid mode (accept_ra=2) is enabled. | ||
1113 | */ | ||
1114 | if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) | ||
1115 | return 0; | ||
1116 | |||
1117 | return in6_dev->cnf.accept_ra; | ||
1118 | } | ||
1119 | |||
1108 | static void ndisc_router_discovery(struct sk_buff *skb) | 1120 | static void ndisc_router_discovery(struct sk_buff *skb) |
1109 | { | 1121 | { |
1110 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); | 1122 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
@@ -1158,8 +1170,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1158 | return; | 1170 | return; |
1159 | } | 1171 | } |
1160 | 1172 | ||
1161 | /* skip route and link configuration on routers */ | 1173 | if (!accept_ra(in6_dev)) |
1162 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1163 | goto skip_linkparms; | 1174 | goto skip_linkparms; |
1164 | 1175 | ||
1165 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1176 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
@@ -1309,8 +1320,7 @@ skip_linkparms: | |||
1309 | NEIGH_UPDATE_F_ISROUTER); | 1320 | NEIGH_UPDATE_F_ISROUTER); |
1310 | } | 1321 | } |
1311 | 1322 | ||
1312 | /* skip route and link configuration on routers */ | 1323 | if (!accept_ra(in6_dev)) |
1313 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1314 | goto out; | 1324 | goto out; |
1315 | 1325 | ||
1316 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1326 | #ifdef CONFIG_IPV6_ROUTE_INFO |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 8e754be92c24..6b331e9b5706 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -82,13 +82,13 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); | |||
82 | int | 82 | int |
83 | ip6t_ext_hdr(u8 nexthdr) | 83 | ip6t_ext_hdr(u8 nexthdr) |
84 | { | 84 | { |
85 | return ( (nexthdr == IPPROTO_HOPOPTS) || | 85 | return (nexthdr == IPPROTO_HOPOPTS) || |
86 | (nexthdr == IPPROTO_ROUTING) || | 86 | (nexthdr == IPPROTO_ROUTING) || |
87 | (nexthdr == IPPROTO_FRAGMENT) || | 87 | (nexthdr == IPPROTO_FRAGMENT) || |
88 | (nexthdr == IPPROTO_ESP) || | 88 | (nexthdr == IPPROTO_ESP) || |
89 | (nexthdr == IPPROTO_AH) || | 89 | (nexthdr == IPPROTO_AH) || |
90 | (nexthdr == IPPROTO_NONE) || | 90 | (nexthdr == IPPROTO_NONE) || |
91 | (nexthdr == IPPROTO_DSTOPTS) ); | 91 | (nexthdr == IPPROTO_DSTOPTS); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Returns whether matches rule or not. */ | 94 | /* Returns whether matches rule or not. */ |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 578f3c1a16db..138a8b362706 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -363,7 +363,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
363 | /* If the first fragment is fragmented itself, we split | 363 | /* If the first fragment is fragmented itself, we split |
364 | * it to two chunks: the first with data and paged part | 364 | * it to two chunks: the first with data and paged part |
365 | * and the second, holding only fragments. */ | 365 | * and the second, holding only fragments. */ |
366 | if (skb_has_frags(head)) { | 366 | if (skb_has_frag_list(head)) { |
367 | struct sk_buff *clone; | 367 | struct sk_buff *clone; |
368 | int i, plen = 0; | 368 | int i, plen = 0; |
369 | 369 | ||
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 1fa3468f0f32..9bb936ae2452 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -25,28 +25,14 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
27 | 27 | ||
28 | const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; | 28 | const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] __read_mostly; |
29 | static DEFINE_SPINLOCK(inet6_proto_lock); | ||
30 | |||
31 | 29 | ||
32 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
33 | { | 31 | { |
34 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 32 | int hash = protocol & (MAX_INET_PROTOS - 1); |
35 | |||
36 | spin_lock_bh(&inet6_proto_lock); | ||
37 | |||
38 | if (inet6_protos[hash]) { | ||
39 | ret = -1; | ||
40 | } else { | ||
41 | inet6_protos[hash] = prot; | ||
42 | ret = 0; | ||
43 | } | ||
44 | |||
45 | spin_unlock_bh(&inet6_proto_lock); | ||
46 | 33 | ||
47 | return ret; | 34 | return !cmpxchg(&inet6_protos[hash], NULL, prot) ? 0 : -1; |
48 | } | 35 | } |
49 | |||
50 | EXPORT_SYMBOL(inet6_add_protocol); | 36 | EXPORT_SYMBOL(inet6_add_protocol); |
51 | 37 | ||
52 | /* | 38 | /* |
@@ -57,20 +43,10 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
57 | { | 43 | { |
58 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 44 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); |
59 | 45 | ||
60 | spin_lock_bh(&inet6_proto_lock); | 46 | ret = (cmpxchg(&inet6_protos[hash], prot, NULL) == prot) ? 0 : -1; |
61 | |||
62 | if (inet6_protos[hash] != prot) { | ||
63 | ret = -1; | ||
64 | } else { | ||
65 | inet6_protos[hash] = NULL; | ||
66 | ret = 0; | ||
67 | } | ||
68 | |||
69 | spin_unlock_bh(&inet6_proto_lock); | ||
70 | 47 | ||
71 | synchronize_net(); | 48 | synchronize_net(); |
72 | 49 | ||
73 | return ret; | 50 | return ret; |
74 | } | 51 | } |
75 | |||
76 | EXPORT_SYMBOL(inet6_del_protocol); | 52 | EXPORT_SYMBOL(inet6_del_protocol); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e677937a07fc..45e6efb7f171 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -764,7 +764,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
764 | return -EINVAL; | 764 | return -EINVAL; |
765 | 765 | ||
766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) | 766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) |
767 | return(-EAFNOSUPPORT); | 767 | return -EAFNOSUPPORT; |
768 | 768 | ||
769 | /* port is the proto value [0..255] carried in nexthdr */ | 769 | /* port is the proto value [0..255] carried in nexthdr */ |
770 | proto = ntohs(sin6->sin6_port); | 770 | proto = ntohs(sin6->sin6_port); |
@@ -772,10 +772,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
772 | if (!proto) | 772 | if (!proto) |
773 | proto = inet->inet_num; | 773 | proto = inet->inet_num; |
774 | else if (proto != inet->inet_num) | 774 | else if (proto != inet->inet_num) |
775 | return(-EINVAL); | 775 | return -EINVAL; |
776 | 776 | ||
777 | if (proto > 255) | 777 | if (proto > 255) |
778 | return(-EINVAL); | 778 | return -EINVAL; |
779 | 779 | ||
780 | daddr = &sin6->sin6_addr; | 780 | daddr = &sin6->sin6_addr; |
781 | if (np->sndflow) { | 781 | if (np->sndflow) { |
@@ -985,7 +985,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
985 | /* You may get strange result with a positive odd offset; | 985 | /* You may get strange result with a positive odd offset; |
986 | RFC2292bis agrees with me. */ | 986 | RFC2292bis agrees with me. */ |
987 | if (val > 0 && (val&1)) | 987 | if (val > 0 && (val&1)) |
988 | return(-EINVAL); | 988 | return -EINVAL; |
989 | if (val < 0) { | 989 | if (val < 0) { |
990 | rp->checksum = 0; | 990 | rp->checksum = 0; |
991 | } else { | 991 | } else { |
@@ -997,7 +997,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
997 | break; | 997 | break; |
998 | 998 | ||
999 | default: | 999 | default: |
1000 | return(-ENOPROTOOPT); | 1000 | return -ENOPROTOOPT; |
1001 | } | 1001 | } |
1002 | } | 1002 | } |
1003 | 1003 | ||
@@ -1190,7 +1190,7 @@ static int rawv6_init_sk(struct sock *sk) | |||
1190 | default: | 1190 | default: |
1191 | break; | 1191 | break; |
1192 | } | 1192 | } |
1193 | return(0); | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | struct proto rawv6_prot = { | 1196 | struct proto rawv6_prot = { |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 64cfef1b0a4c..c7ba3149633f 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -458,7 +458,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
458 | /* If the first fragment is fragmented itself, we split | 458 | /* If the first fragment is fragmented itself, we split |
459 | * it to two chunks: the first with data and paged part | 459 | * it to two chunks: the first with data and paged part |
460 | * and the second, holding only fragments. */ | 460 | * and the second, holding only fragments. */ |
461 | if (skb_has_frags(head)) { | 461 | if (skb_has_frag_list(head)) { |
462 | struct sk_buff *clone; | 462 | struct sk_buff *clone; |
463 | int i, plen = 0; | 463 | int i, plen = 0; |
464 | 464 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d126365ac046..25b0beda4331 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -217,14 +217,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
217 | 217 | ||
218 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) | 218 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) |
219 | { | 219 | { |
220 | return (rt->rt6i_flags & RTF_EXPIRES && | 220 | return (rt->rt6i_flags & RTF_EXPIRES) && |
221 | time_after(jiffies, rt->rt6i_expires)); | 221 | time_after(jiffies, rt->rt6i_expires); |
222 | } | 222 | } |
223 | 223 | ||
224 | static inline int rt6_need_strict(struct in6_addr *daddr) | 224 | static inline int rt6_need_strict(struct in6_addr *daddr) |
225 | { | 225 | { |
226 | return (ipv6_addr_type(daddr) & | 226 | return ipv6_addr_type(daddr) & |
227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); | 227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
228 | } | 228 | } |
229 | 229 | ||
230 | /* | 230 | /* |
@@ -440,7 +440,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | |||
440 | __func__, match); | 440 | __func__, match); |
441 | 441 | ||
442 | net = dev_net(rt0->rt6i_dev); | 442 | net = dev_net(rt0->rt6i_dev); |
443 | return (match ? match : net->ipv6.ip6_null_entry); | 443 | return match ? match : net->ipv6.ip6_null_entry; |
444 | } | 444 | } |
445 | 445 | ||
446 | #ifdef CONFIG_IPV6_ROUTE_INFO | 446 | #ifdef CONFIG_IPV6_ROUTE_INFO |
@@ -859,7 +859,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
859 | 859 | ||
860 | dst_release(*dstp); | 860 | dst_release(*dstp); |
861 | *dstp = new; | 861 | *dstp = new; |
862 | return (new ? 0 : -ENOMEM); | 862 | return new ? 0 : -ENOMEM; |
863 | } | 863 | } |
864 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | 864 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); |
865 | 865 | ||
@@ -1070,7 +1070,7 @@ static int ip6_dst_gc(struct dst_ops *ops) | |||
1070 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; | 1070 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; |
1071 | out: | 1071 | out: |
1072 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; | 1072 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; |
1073 | return (atomic_read(&ops->entries) > rt_max_size); | 1073 | return atomic_read(&ops->entries) > rt_max_size; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | /* Clean host part of a prefix. Not necessary in radix tree, | 1076 | /* Clean host part of a prefix. Not necessary in radix tree, |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4699cd3c3118..8a0399822230 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -68,19 +68,18 @@ static void ipip6_tunnel_setup(struct net_device *dev); | |||
68 | 68 | ||
69 | static int sit_net_id __read_mostly; | 69 | static int sit_net_id __read_mostly; |
70 | struct sit_net { | 70 | struct sit_net { |
71 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | 71 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; |
72 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | 72 | struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; |
73 | struct ip_tunnel *tunnels_l[HASH_SIZE]; | 73 | struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; |
74 | struct ip_tunnel *tunnels_wc[1]; | 74 | struct ip_tunnel __rcu *tunnels_wc[1]; |
75 | struct ip_tunnel **tunnels[4]; | 75 | struct ip_tunnel __rcu **tunnels[4]; |
76 | 76 | ||
77 | struct net_device *fb_tunnel_dev; | 77 | struct net_device *fb_tunnel_dev; |
78 | }; | 78 | }; |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * Locking : hash tables are protected by RCU and a spinlock | 81 | * Locking : hash tables are protected by RCU and RTNL |
82 | */ | 82 | */ |
83 | static DEFINE_SPINLOCK(ipip6_lock); | ||
84 | 83 | ||
85 | #define for_each_ip_tunnel_rcu(start) \ | 84 | #define for_each_ip_tunnel_rcu(start) \ |
86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | 85 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) |
@@ -91,8 +90,8 @@ static DEFINE_SPINLOCK(ipip6_lock); | |||
91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 90 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
92 | struct net_device *dev, __be32 remote, __be32 local) | 91 | struct net_device *dev, __be32 remote, __be32 local) |
93 | { | 92 | { |
94 | unsigned h0 = HASH(remote); | 93 | unsigned int h0 = HASH(remote); |
95 | unsigned h1 = HASH(local); | 94 | unsigned int h1 = HASH(local); |
96 | struct ip_tunnel *t; | 95 | struct ip_tunnel *t; |
97 | struct sit_net *sitn = net_generic(net, sit_net_id); | 96 | struct sit_net *sitn = net_generic(net, sit_net_id); |
98 | 97 | ||
@@ -121,12 +120,12 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
121 | return NULL; | 120 | return NULL; |
122 | } | 121 | } |
123 | 122 | ||
124 | static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | 123 | static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, |
125 | struct ip_tunnel_parm *parms) | 124 | struct ip_tunnel_parm *parms) |
126 | { | 125 | { |
127 | __be32 remote = parms->iph.daddr; | 126 | __be32 remote = parms->iph.daddr; |
128 | __be32 local = parms->iph.saddr; | 127 | __be32 local = parms->iph.saddr; |
129 | unsigned h = 0; | 128 | unsigned int h = 0; |
130 | int prio = 0; | 129 | int prio = 0; |
131 | 130 | ||
132 | if (remote) { | 131 | if (remote) { |
@@ -140,7 +139,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | |||
140 | return &sitn->tunnels[prio][h]; | 139 | return &sitn->tunnels[prio][h]; |
141 | } | 140 | } |
142 | 141 | ||
143 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | 142 | static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, |
144 | struct ip_tunnel *t) | 143 | struct ip_tunnel *t) |
145 | { | 144 | { |
146 | return __ipip6_bucket(sitn, &t->parms); | 145 | return __ipip6_bucket(sitn, &t->parms); |
@@ -148,13 +147,14 @@ static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | |||
148 | 147 | ||
149 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | 148 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) |
150 | { | 149 | { |
151 | struct ip_tunnel **tp; | 150 | struct ip_tunnel __rcu **tp; |
152 | 151 | struct ip_tunnel *iter; | |
153 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { | 152 | |
154 | if (t == *tp) { | 153 | for (tp = ipip6_bucket(sitn, t); |
155 | spin_lock_bh(&ipip6_lock); | 154 | (iter = rtnl_dereference(*tp)) != NULL; |
156 | *tp = t->next; | 155 | tp = &iter->next) { |
157 | spin_unlock_bh(&ipip6_lock); | 156 | if (t == iter) { |
157 | rcu_assign_pointer(*tp, t->next); | ||
158 | break; | 158 | break; |
159 | } | 159 | } |
160 | } | 160 | } |
@@ -162,12 +162,10 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | |||
162 | 162 | ||
163 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | 163 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) |
164 | { | 164 | { |
165 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); | 165 | struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); |
166 | 166 | ||
167 | spin_lock_bh(&ipip6_lock); | 167 | rcu_assign_pointer(t->next, rtnl_dereference(*tp)); |
168 | t->next = *tp; | ||
169 | rcu_assign_pointer(*tp, t); | 168 | rcu_assign_pointer(*tp, t); |
170 | spin_unlock_bh(&ipip6_lock); | ||
171 | } | 169 | } |
172 | 170 | ||
173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | 171 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) |
@@ -187,17 +185,20 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | |||
187 | #endif | 185 | #endif |
188 | } | 186 | } |
189 | 187 | ||
190 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | 188 | static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, |
191 | struct ip_tunnel_parm *parms, int create) | 189 | struct ip_tunnel_parm *parms, int create) |
192 | { | 190 | { |
193 | __be32 remote = parms->iph.daddr; | 191 | __be32 remote = parms->iph.daddr; |
194 | __be32 local = parms->iph.saddr; | 192 | __be32 local = parms->iph.saddr; |
195 | struct ip_tunnel *t, **tp, *nt; | 193 | struct ip_tunnel *t, *nt; |
194 | struct ip_tunnel __rcu **tp; | ||
196 | struct net_device *dev; | 195 | struct net_device *dev; |
197 | char name[IFNAMSIZ]; | 196 | char name[IFNAMSIZ]; |
198 | struct sit_net *sitn = net_generic(net, sit_net_id); | 197 | struct sit_net *sitn = net_generic(net, sit_net_id); |
199 | 198 | ||
200 | for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { | 199 | for (tp = __ipip6_bucket(sitn, parms); |
200 | (t = rtnl_dereference(*tp)) != NULL; | ||
201 | tp = &t->next) { | ||
201 | if (local == t->parms.iph.saddr && | 202 | if (local == t->parms.iph.saddr && |
202 | remote == t->parms.iph.daddr && | 203 | remote == t->parms.iph.daddr && |
203 | parms->link == t->parms.link) { | 204 | parms->link == t->parms.link) { |
@@ -340,7 +341,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
340 | 341 | ||
341 | ASSERT_RTNL(); | 342 | ASSERT_RTNL(); |
342 | 343 | ||
343 | for (p = t->prl; p; p = p->next) { | 344 | for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { |
344 | if (p->addr == a->addr) { | 345 | if (p->addr == a->addr) { |
345 | if (chg) { | 346 | if (chg) { |
346 | p->flags = a->flags; | 347 | p->flags = a->flags; |
@@ -451,15 +452,12 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
451 | struct sit_net *sitn = net_generic(net, sit_net_id); | 452 | struct sit_net *sitn = net_generic(net, sit_net_id); |
452 | 453 | ||
453 | if (dev == sitn->fb_tunnel_dev) { | 454 | if (dev == sitn->fb_tunnel_dev) { |
454 | spin_lock_bh(&ipip6_lock); | 455 | rcu_assign_pointer(sitn->tunnels_wc[0], NULL); |
455 | sitn->tunnels_wc[0] = NULL; | ||
456 | spin_unlock_bh(&ipip6_lock); | ||
457 | dev_put(dev); | ||
458 | } else { | 456 | } else { |
459 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); | 457 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); |
460 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); | 458 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); |
461 | dev_put(dev); | ||
462 | } | 459 | } |
460 | dev_put(dev); | ||
463 | } | 461 | } |
464 | 462 | ||
465 | 463 | ||
@@ -566,7 +564,10 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
566 | skb_tunnel_rx(skb, tunnel->dev); | 564 | skb_tunnel_rx(skb, tunnel->dev); |
567 | 565 | ||
568 | ipip6_ecn_decapsulate(iph, skb); | 566 | ipip6_ecn_decapsulate(iph, skb); |
569 | netif_rx(skb); | 567 | |
568 | if (netif_rx(skb) == NET_RX_DROP) | ||
569 | tunnel->dev->stats.rx_dropped++; | ||
570 | |||
570 | rcu_read_unlock(); | 571 | rcu_read_unlock(); |
571 | return 0; | 572 | return 0; |
572 | } | 573 | } |
@@ -590,7 +591,7 @@ __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) | |||
590 | #ifdef CONFIG_IPV6_SIT_6RD | 591 | #ifdef CONFIG_IPV6_SIT_6RD |
591 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 592 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
592 | tunnel->ip6rd.prefixlen)) { | 593 | tunnel->ip6rd.prefixlen)) { |
593 | unsigned pbw0, pbi0; | 594 | unsigned int pbw0, pbi0; |
594 | int pbi1; | 595 | int pbi1; |
595 | u32 d; | 596 | u32 d; |
596 | 597 | ||
@@ -1132,7 +1133,7 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
1132 | sitn->tunnels_wc[0] = tunnel; | 1133 | sitn->tunnels_wc[0] = tunnel; |
1133 | } | 1134 | } |
1134 | 1135 | ||
1135 | static struct xfrm_tunnel sit_handler = { | 1136 | static struct xfrm_tunnel sit_handler __read_mostly = { |
1136 | .handler = ipip6_rcv, | 1137 | .handler = ipip6_rcv, |
1137 | .err_handler = ipip6_err, | 1138 | .err_handler = ipip6_err, |
1138 | .priority = 1, | 1139 | .priority = 1, |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fe6d40418c0b..8d93f6d81979 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -139,7 +139,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
139 | return -EINVAL; | 139 | return -EINVAL; |
140 | 140 | ||
141 | if (usin->sin6_family != AF_INET6) | 141 | if (usin->sin6_family != AF_INET6) |
142 | return(-EAFNOSUPPORT); | 142 | return -EAFNOSUPPORT; |
143 | 143 | ||
144 | memset(&fl, 0, sizeof(fl)); | 144 | memset(&fl, 0, sizeof(fl)); |
145 | 145 | ||
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index fc3c86a47452..d9864725d0c6 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -30,8 +30,8 @@ | |||
30 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
31 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
32 | 32 | ||
33 | static struct xfrm6_tunnel *tunnel6_handlers; | 33 | static struct xfrm6_tunnel *tunnel6_handlers __read_mostly; |
34 | static struct xfrm6_tunnel *tunnel46_handlers; | 34 | static struct xfrm6_tunnel *tunnel46_handlers __read_mostly; |
35 | static DEFINE_MUTEX(tunnel6_mutex); | 35 | static DEFINE_MUTEX(tunnel6_mutex); |
36 | 36 | ||
37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) | 37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) |
@@ -51,7 +51,7 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) | |||
51 | } | 51 | } |
52 | 52 | ||
53 | handler->next = *pprev; | 53 | handler->next = *pprev; |
54 | *pprev = handler; | 54 | rcu_assign_pointer(*pprev, handler); |
55 | 55 | ||
56 | ret = 0; | 56 | ret = 0; |
57 | 57 | ||
@@ -88,6 +88,11 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | |||
88 | 88 | ||
89 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | 89 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); |
90 | 90 | ||
91 | #define for_each_tunnel_rcu(head, handler) \ | ||
92 | for (handler = rcu_dereference(head); \ | ||
93 | handler != NULL; \ | ||
94 | handler = rcu_dereference(handler->next)) \ | ||
95 | |||
91 | static int tunnel6_rcv(struct sk_buff *skb) | 96 | static int tunnel6_rcv(struct sk_buff *skb) |
92 | { | 97 | { |
93 | struct xfrm6_tunnel *handler; | 98 | struct xfrm6_tunnel *handler; |
@@ -95,7 +100,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
95 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 100 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
96 | goto drop; | 101 | goto drop; |
97 | 102 | ||
98 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 103 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
99 | if (!handler->handler(skb)) | 104 | if (!handler->handler(skb)) |
100 | return 0; | 105 | return 0; |
101 | 106 | ||
@@ -113,7 +118,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
113 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 118 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
114 | goto drop; | 119 | goto drop; |
115 | 120 | ||
116 | for (handler = tunnel46_handlers; handler; handler = handler->next) | 121 | for_each_tunnel_rcu(tunnel46_handlers, handler) |
117 | if (!handler->handler(skb)) | 122 | if (!handler->handler(skb)) |
118 | return 0; | 123 | return 0; |
119 | 124 | ||
@@ -129,7 +134,7 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
129 | { | 134 | { |
130 | struct xfrm6_tunnel *handler; | 135 | struct xfrm6_tunnel *handler; |
131 | 136 | ||
132 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 137 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
133 | if (!handler->err_handler(skb, opt, type, code, offset, info)) | 138 | if (!handler->err_handler(skb, opt, type, code, offset, info)) |
134 | break; | 139 | break; |
135 | } | 140 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6baeabbbca82..39676eac3a37 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -199,7 +199,7 @@ static inline int xfrm6_garbage_collect(struct dst_ops *ops) | |||
199 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); | 199 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); |
200 | 200 | ||
201 | xfrm6_policy_afinfo.garbage_collect(net); | 201 | xfrm6_policy_afinfo.garbage_collect(net); |
202 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | 202 | return atomic_read(&ops->entries) > ops->gc_thresh * 2; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | 205 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 2ce3a8278f26..ac7584b946a5 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -317,13 +317,13 @@ static const struct xfrm_type xfrm6_tunnel_type = { | |||
317 | .output = xfrm6_tunnel_output, | 317 | .output = xfrm6_tunnel_output, |
318 | }; | 318 | }; |
319 | 319 | ||
320 | static struct xfrm6_tunnel xfrm6_tunnel_handler = { | 320 | static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = { |
321 | .handler = xfrm6_tunnel_rcv, | 321 | .handler = xfrm6_tunnel_rcv, |
322 | .err_handler = xfrm6_tunnel_err, | 322 | .err_handler = xfrm6_tunnel_err, |
323 | .priority = 2, | 323 | .priority = 2, |
324 | }; | 324 | }; |
325 | 325 | ||
326 | static struct xfrm6_tunnel xfrm46_tunnel_handler = { | 326 | static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = { |
327 | .handler = xfrm6_tunnel_rcv, | 327 | .handler = xfrm6_tunnel_rcv, |
328 | .err_handler = xfrm6_tunnel_err, | 328 | .err_handler = xfrm6_tunnel_err, |
329 | .priority = 2, | 329 | .priority = 2, |