diff options
Diffstat (limited to 'net/ipv6')
31 files changed, 808 insertions, 657 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 4ea244891b58..309af19a0a0a 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o | |||
40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
42 | 42 | ||
43 | obj-y += addrconf_core.o exthdrs_core.o | 43 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o |
44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) | 44 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) |
45 | 45 | ||
46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1b5d8cb9b123..bd9f9360f769 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -110,10 +110,6 @@ static inline u32 cstamp_delta(unsigned long cstamp) | |||
110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | 110 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; |
111 | } | 111 | } |
112 | 112 | ||
113 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | ||
114 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | ||
115 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | ||
116 | |||
117 | #ifdef CONFIG_SYSCTL | 113 | #ifdef CONFIG_SYSCTL |
118 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 114 | static void addrconf_sysctl_register(struct inet6_dev *idev); |
119 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 115 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); |
@@ -1051,7 +1047,7 @@ retry: | |||
1051 | ipv6_add_addr(idev, &addr, tmp_plen, | 1047 | ipv6_add_addr(idev, &addr, tmp_plen, |
1052 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, | 1048 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, |
1053 | addr_flags) : NULL; | 1049 | addr_flags) : NULL; |
1054 | if (!ift || IS_ERR(ift)) { | 1050 | if (IS_ERR_OR_NULL(ift)) { |
1055 | in6_ifa_put(ifp); | 1051 | in6_ifa_put(ifp); |
1056 | in6_dev_put(idev); | 1052 | in6_dev_put(idev); |
1057 | pr_info("%s: retry temporary address regeneration\n", __func__); | 1053 | pr_info("%s: retry temporary address regeneration\n", __func__); |
@@ -2080,7 +2076,7 @@ ok: | |||
2080 | addr_type&IPV6_ADDR_SCOPE_MASK, | 2076 | addr_type&IPV6_ADDR_SCOPE_MASK, |
2081 | addr_flags); | 2077 | addr_flags); |
2082 | 2078 | ||
2083 | if (!ifp || IS_ERR(ifp)) { | 2079 | if (IS_ERR_OR_NULL(ifp)) { |
2084 | in6_dev_put(in6_dev); | 2080 | in6_dev_put(in6_dev); |
2085 | return; | 2081 | return; |
2086 | } | 2082 | } |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b043c60429bd..6b793bfc0e10 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -811,11 +811,10 @@ static struct pernet_operations inet6_net_ops = { | |||
811 | 811 | ||
812 | static int __init inet6_init(void) | 812 | static int __init inet6_init(void) |
813 | { | 813 | { |
814 | struct sk_buff *dummy_skb; | ||
815 | struct list_head *r; | 814 | struct list_head *r; |
816 | int err = 0; | 815 | int err = 0; |
817 | 816 | ||
818 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); | 817 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > FIELD_SIZEOF(struct sk_buff, cb)); |
819 | 818 | ||
820 | /* Register the socket-side information for inet6_create. */ | 819 | /* Register the socket-side information for inet6_create. */ |
821 | for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) | 820 | for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 757a810d8f15..921b8b398a8c 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -47,7 +47,7 @@ | |||
47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); | 47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); |
48 | 48 | ||
49 | /* Big ac list lock for all the sockets */ | 49 | /* Big ac list lock for all the sockets */ |
50 | static DEFINE_RWLOCK(ipv6_sk_ac_lock); | 50 | static DEFINE_SPINLOCK(ipv6_sk_ac_lock); |
51 | 51 | ||
52 | 52 | ||
53 | /* | 53 | /* |
@@ -128,10 +128,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
128 | 128 | ||
129 | err = ipv6_dev_ac_inc(dev, addr); | 129 | err = ipv6_dev_ac_inc(dev, addr); |
130 | if (!err) { | 130 | if (!err) { |
131 | write_lock_bh(&ipv6_sk_ac_lock); | 131 | spin_lock_bh(&ipv6_sk_ac_lock); |
132 | pac->acl_next = np->ipv6_ac_list; | 132 | pac->acl_next = np->ipv6_ac_list; |
133 | np->ipv6_ac_list = pac; | 133 | np->ipv6_ac_list = pac; |
134 | write_unlock_bh(&ipv6_sk_ac_lock); | 134 | spin_unlock_bh(&ipv6_sk_ac_lock); |
135 | pac = NULL; | 135 | pac = NULL; |
136 | } | 136 | } |
137 | 137 | ||
@@ -152,7 +152,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
152 | struct ipv6_ac_socklist *pac, *prev_pac; | 152 | struct ipv6_ac_socklist *pac, *prev_pac; |
153 | struct net *net = sock_net(sk); | 153 | struct net *net = sock_net(sk); |
154 | 154 | ||
155 | write_lock_bh(&ipv6_sk_ac_lock); | 155 | spin_lock_bh(&ipv6_sk_ac_lock); |
156 | prev_pac = NULL; | 156 | prev_pac = NULL; |
157 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { | 157 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { |
158 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && | 158 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && |
@@ -161,7 +161,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
161 | prev_pac = pac; | 161 | prev_pac = pac; |
162 | } | 162 | } |
163 | if (!pac) { | 163 | if (!pac) { |
164 | write_unlock_bh(&ipv6_sk_ac_lock); | 164 | spin_unlock_bh(&ipv6_sk_ac_lock); |
165 | return -ENOENT; | 165 | return -ENOENT; |
166 | } | 166 | } |
167 | if (prev_pac) | 167 | if (prev_pac) |
@@ -169,7 +169,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
169 | else | 169 | else |
170 | np->ipv6_ac_list = pac->acl_next; | 170 | np->ipv6_ac_list = pac->acl_next; |
171 | 171 | ||
172 | write_unlock_bh(&ipv6_sk_ac_lock); | 172 | spin_unlock_bh(&ipv6_sk_ac_lock); |
173 | 173 | ||
174 | rcu_read_lock(); | 174 | rcu_read_lock(); |
175 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); | 175 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); |
@@ -192,10 +192,10 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
192 | if (!np->ipv6_ac_list) | 192 | if (!np->ipv6_ac_list) |
193 | return; | 193 | return; |
194 | 194 | ||
195 | write_lock_bh(&ipv6_sk_ac_lock); | 195 | spin_lock_bh(&ipv6_sk_ac_lock); |
196 | pac = np->ipv6_ac_list; | 196 | pac = np->ipv6_ac_list; |
197 | np->ipv6_ac_list = NULL; | 197 | np->ipv6_ac_list = NULL; |
198 | write_unlock_bh(&ipv6_sk_ac_lock); | 198 | spin_unlock_bh(&ipv6_sk_ac_lock); |
199 | 199 | ||
200 | prev_index = 0; | 200 | prev_index = 0; |
201 | rcu_read_lock(); | 201 | rcu_read_lock(); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 7a778b9a7b85..f5a54782a340 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/transp_v6.h> | 30 | #include <net/transp_v6.h> |
31 | #include <net/ip6_route.h> | 31 | #include <net/ip6_route.h> |
32 | #include <net/tcp_states.h> | 32 | #include <net/tcp_states.h> |
33 | #include <net/dsfield.h> | ||
33 | 34 | ||
34 | #include <linux/errqueue.h> | 35 | #include <linux/errqueue.h> |
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
@@ -356,12 +357,11 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
356 | sin->sin6_port = serr->port; | 357 | sin->sin6_port = serr->port; |
357 | sin->sin6_scope_id = 0; | 358 | sin->sin6_scope_id = 0; |
358 | if (skb->protocol == htons(ETH_P_IPV6)) { | 359 | if (skb->protocol == htons(ETH_P_IPV6)) { |
359 | sin->sin6_addr = | 360 | const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset), |
360 | *(struct in6_addr *)(nh + serr->addr_offset); | 361 | struct ipv6hdr, daddr); |
362 | sin->sin6_addr = ip6h->daddr; | ||
361 | if (np->sndflow) | 363 | if (np->sndflow) |
362 | sin->sin6_flowinfo = | 364 | sin->sin6_flowinfo = ip6_flowinfo(ip6h); |
363 | (*(__be32 *)(nh + serr->addr_offset - 24) & | ||
364 | IPV6_FLOWINFO_MASK); | ||
365 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 365 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
366 | sin->sin6_scope_id = IP6CB(skb)->iif; | 366 | sin->sin6_scope_id = IP6CB(skb)->iif; |
367 | } else { | 367 | } else { |
@@ -489,13 +489,14 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, | |||
489 | } | 489 | } |
490 | 490 | ||
491 | if (np->rxopt.bits.rxtclass) { | 491 | if (np->rxopt.bits.rxtclass) { |
492 | int tclass = ipv6_tclass(ipv6_hdr(skb)); | 492 | int tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
493 | put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); | 493 | put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); |
494 | } | 494 | } |
495 | 495 | ||
496 | if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) { | 496 | if (np->rxopt.bits.rxflow) { |
497 | __be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK; | 497 | __be32 flowinfo = ip6_flowinfo((struct ipv6hdr *)nh); |
498 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | 498 | if (flowinfo) |
499 | put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); | ||
499 | } | 500 | } |
500 | 501 | ||
501 | /* HbH is allowed only once */ | 502 | /* HbH is allowed only once */ |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 473f628f9f20..07a7d65a7cb6 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -553,7 +553,8 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
553 | const unsigned char *nh = skb_network_header(skb); | 553 | const unsigned char *nh = skb_network_header(skb); |
554 | 554 | ||
555 | if (nh[optoff + 1] == 2) { | 555 | if (nh[optoff + 1] == 2) { |
556 | IP6CB(skb)->ra = optoff; | 556 | IP6CB(skb)->flags |= IP6SKB_ROUTERALERT; |
557 | memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra)); | ||
557 | return true; | 558 | return true; |
558 | } | 559 | } |
559 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", | 560 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 30647857a375..b386a2ce4c6f 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -32,6 +32,9 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
32 | { | 32 | { |
33 | const struct sock *sk2; | 33 | const struct sock *sk2; |
34 | const struct hlist_node *node; | 34 | const struct hlist_node *node; |
35 | int reuse = sk->sk_reuse; | ||
36 | int reuseport = sk->sk_reuseport; | ||
37 | kuid_t uid = sock_i_uid((struct sock *)sk); | ||
35 | 38 | ||
36 | /* We must walk the whole port owner list in this case. -DaveM */ | 39 | /* We must walk the whole port owner list in this case. -DaveM */ |
37 | /* | 40 | /* |
@@ -42,11 +45,17 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
42 | if (sk != sk2 && | 45 | if (sk != sk2 && |
43 | (!sk->sk_bound_dev_if || | 46 | (!sk->sk_bound_dev_if || |
44 | !sk2->sk_bound_dev_if || | 47 | !sk2->sk_bound_dev_if || |
45 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && | 48 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
46 | (!sk->sk_reuse || !sk2->sk_reuse || | 49 | if ((!reuse || !sk2->sk_reuse || |
47 | sk2->sk_state == TCP_LISTEN) && | 50 | sk2->sk_state == TCP_LISTEN) && |
48 | ipv6_rcv_saddr_equal(sk, sk2)) | 51 | (!reuseport || !sk2->sk_reuseport || |
49 | break; | 52 | (sk2->sk_state != TCP_TIME_WAIT && |
53 | !uid_eq(uid, | ||
54 | sock_i_uid((struct sock *)sk2))))) { | ||
55 | if (ipv6_rcv_saddr_equal(sk, sk2)) | ||
56 | break; | ||
57 | } | ||
58 | } | ||
50 | } | 59 | } |
51 | 60 | ||
52 | return node != NULL; | 61 | return node != NULL; |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index dea17fd28e50..32b4a1675d82 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -158,25 +158,38 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
158 | } | 158 | } |
159 | 159 | ||
160 | struct sock *inet6_lookup_listener(struct net *net, | 160 | struct sock *inet6_lookup_listener(struct net *net, |
161 | struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, | 161 | struct inet_hashinfo *hashinfo, const struct in6_addr *saddr, |
162 | const __be16 sport, const struct in6_addr *daddr, | ||
162 | const unsigned short hnum, const int dif) | 163 | const unsigned short hnum, const int dif) |
163 | { | 164 | { |
164 | struct sock *sk; | 165 | struct sock *sk; |
165 | const struct hlist_nulls_node *node; | 166 | const struct hlist_nulls_node *node; |
166 | struct sock *result; | 167 | struct sock *result; |
167 | int score, hiscore; | 168 | int score, hiscore, matches = 0, reuseport = 0; |
169 | u32 phash = 0; | ||
168 | unsigned int hash = inet_lhashfn(net, hnum); | 170 | unsigned int hash = inet_lhashfn(net, hnum); |
169 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; | 171 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; |
170 | 172 | ||
171 | rcu_read_lock(); | 173 | rcu_read_lock(); |
172 | begin: | 174 | begin: |
173 | result = NULL; | 175 | result = NULL; |
174 | hiscore = -1; | 176 | hiscore = 0; |
175 | sk_nulls_for_each(sk, node, &ilb->head) { | 177 | sk_nulls_for_each(sk, node, &ilb->head) { |
176 | score = compute_score(sk, net, hnum, daddr, dif); | 178 | score = compute_score(sk, net, hnum, daddr, dif); |
177 | if (score > hiscore) { | 179 | if (score > hiscore) { |
178 | hiscore = score; | 180 | hiscore = score; |
179 | result = sk; | 181 | result = sk; |
182 | reuseport = sk->sk_reuseport; | ||
183 | if (reuseport) { | ||
184 | phash = inet6_ehashfn(net, daddr, hnum, | ||
185 | saddr, sport); | ||
186 | matches = 1; | ||
187 | } | ||
188 | } else if (score == hiscore && reuseport) { | ||
189 | matches++; | ||
190 | if (((u64)phash * matches) >> 32 == 0) | ||
191 | result = sk; | ||
192 | phash = next_pseudo_random32(phash); | ||
180 | } | 193 | } |
181 | } | 194 | } |
182 | /* | 195 | /* |
diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c new file mode 100644 index 000000000000..72d198b8e4d2 --- /dev/null +++ b/net/ipv6/ip6_checksum.c | |||
@@ -0,0 +1,97 @@ | |||
1 | #include <net/ip.h> | ||
2 | #include <net/udp.h> | ||
3 | #include <net/udplite.h> | ||
4 | #include <asm/checksum.h> | ||
5 | |||
6 | #ifndef _HAVE_ARCH_IPV6_CSUM | ||
7 | __sum16 csum_ipv6_magic(const struct in6_addr *saddr, | ||
8 | const struct in6_addr *daddr, | ||
9 | __u32 len, unsigned short proto, | ||
10 | __wsum csum) | ||
11 | { | ||
12 | |||
13 | int carry; | ||
14 | __u32 ulen; | ||
15 | __u32 uproto; | ||
16 | __u32 sum = (__force u32)csum; | ||
17 | |||
18 | sum += (__force u32)saddr->s6_addr32[0]; | ||
19 | carry = (sum < (__force u32)saddr->s6_addr32[0]); | ||
20 | sum += carry; | ||
21 | |||
22 | sum += (__force u32)saddr->s6_addr32[1]; | ||
23 | carry = (sum < (__force u32)saddr->s6_addr32[1]); | ||
24 | sum += carry; | ||
25 | |||
26 | sum += (__force u32)saddr->s6_addr32[2]; | ||
27 | carry = (sum < (__force u32)saddr->s6_addr32[2]); | ||
28 | sum += carry; | ||
29 | |||
30 | sum += (__force u32)saddr->s6_addr32[3]; | ||
31 | carry = (sum < (__force u32)saddr->s6_addr32[3]); | ||
32 | sum += carry; | ||
33 | |||
34 | sum += (__force u32)daddr->s6_addr32[0]; | ||
35 | carry = (sum < (__force u32)daddr->s6_addr32[0]); | ||
36 | sum += carry; | ||
37 | |||
38 | sum += (__force u32)daddr->s6_addr32[1]; | ||
39 | carry = (sum < (__force u32)daddr->s6_addr32[1]); | ||
40 | sum += carry; | ||
41 | |||
42 | sum += (__force u32)daddr->s6_addr32[2]; | ||
43 | carry = (sum < (__force u32)daddr->s6_addr32[2]); | ||
44 | sum += carry; | ||
45 | |||
46 | sum += (__force u32)daddr->s6_addr32[3]; | ||
47 | carry = (sum < (__force u32)daddr->s6_addr32[3]); | ||
48 | sum += carry; | ||
49 | |||
50 | ulen = (__force u32)htonl((__u32) len); | ||
51 | sum += ulen; | ||
52 | carry = (sum < ulen); | ||
53 | sum += carry; | ||
54 | |||
55 | uproto = (__force u32)htonl(proto); | ||
56 | sum += uproto; | ||
57 | carry = (sum < uproto); | ||
58 | sum += carry; | ||
59 | |||
60 | return csum_fold((__force __wsum)sum); | ||
61 | } | ||
62 | EXPORT_SYMBOL(csum_ipv6_magic); | ||
63 | #endif | ||
64 | |||
65 | int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) | ||
66 | { | ||
67 | int err; | ||
68 | |||
69 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
70 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
71 | |||
72 | if (proto == IPPROTO_UDPLITE) { | ||
73 | err = udplite_checksum_init(skb, uh); | ||
74 | if (err) | ||
75 | return err; | ||
76 | } | ||
77 | |||
78 | if (uh->check == 0) { | ||
79 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
80 | this error. Well, it is reasonable. | ||
81 | */ | ||
82 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
83 | return 1; | ||
84 | } | ||
85 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
86 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
87 | skb->len, proto, skb->csum)) | ||
88 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
89 | |||
90 | if (!skb_csum_unnecessary(skb)) | ||
91 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
92 | &ipv6_hdr(skb)->daddr, | ||
93 | skb->len, proto, 0)); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | EXPORT_SYMBOL(udp6_csum_init); | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index d6de4b447250..ea42bf40a997 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -51,25 +51,38 @@ | |||
51 | #define FL_HASH(l) (ntohl(l)&FL_HASH_MASK) | 51 | #define FL_HASH(l) (ntohl(l)&FL_HASH_MASK) |
52 | 52 | ||
53 | static atomic_t fl_size = ATOMIC_INIT(0); | 53 | static atomic_t fl_size = ATOMIC_INIT(0); |
54 | static struct ip6_flowlabel *fl_ht[FL_HASH_MASK+1]; | 54 | static struct ip6_flowlabel __rcu *fl_ht[FL_HASH_MASK+1]; |
55 | 55 | ||
56 | static void ip6_fl_gc(unsigned long dummy); | 56 | static void ip6_fl_gc(unsigned long dummy); |
57 | static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); | 57 | static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); |
58 | 58 | ||
59 | /* FL hash table lock: it protects only of GC */ | 59 | /* FL hash table lock: it protects only of GC */ |
60 | 60 | ||
61 | static DEFINE_RWLOCK(ip6_fl_lock); | 61 | static DEFINE_SPINLOCK(ip6_fl_lock); |
62 | 62 | ||
63 | /* Big socket sock */ | 63 | /* Big socket sock */ |
64 | 64 | ||
65 | static DEFINE_RWLOCK(ip6_sk_fl_lock); | 65 | static DEFINE_SPINLOCK(ip6_sk_fl_lock); |
66 | 66 | ||
67 | #define for_each_fl_rcu(hash, fl) \ | ||
68 | for (fl = rcu_dereference(fl_ht[(hash)]); \ | ||
69 | fl != NULL; \ | ||
70 | fl = rcu_dereference(fl->next)) | ||
71 | #define for_each_fl_continue_rcu(fl) \ | ||
72 | for (fl = rcu_dereference(fl->next); \ | ||
73 | fl != NULL; \ | ||
74 | fl = rcu_dereference(fl->next)) | ||
75 | |||
76 | #define for_each_sk_fl_rcu(np, sfl) \ | ||
77 | for (sfl = rcu_dereference_bh(np->ipv6_fl_list); \ | ||
78 | sfl != NULL; \ | ||
79 | sfl = rcu_dereference_bh(sfl->next)) | ||
67 | 80 | ||
68 | static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) | 81 | static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) |
69 | { | 82 | { |
70 | struct ip6_flowlabel *fl; | 83 | struct ip6_flowlabel *fl; |
71 | 84 | ||
72 | for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { | 85 | for_each_fl_rcu(FL_HASH(label), fl) { |
73 | if (fl->label == label && net_eq(fl->fl_net, net)) | 86 | if (fl->label == label && net_eq(fl->fl_net, net)) |
74 | return fl; | 87 | return fl; |
75 | } | 88 | } |
@@ -80,11 +93,11 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) | |||
80 | { | 93 | { |
81 | struct ip6_flowlabel *fl; | 94 | struct ip6_flowlabel *fl; |
82 | 95 | ||
83 | read_lock_bh(&ip6_fl_lock); | 96 | rcu_read_lock_bh(); |
84 | fl = __fl_lookup(net, label); | 97 | fl = __fl_lookup(net, label); |
85 | if (fl) | 98 | if (fl && !atomic_inc_not_zero(&fl->users)) |
86 | atomic_inc(&fl->users); | 99 | fl = NULL; |
87 | read_unlock_bh(&ip6_fl_lock); | 100 | rcu_read_unlock_bh(); |
88 | return fl; | 101 | return fl; |
89 | } | 102 | } |
90 | 103 | ||
@@ -96,13 +109,13 @@ static void fl_free(struct ip6_flowlabel *fl) | |||
96 | put_pid(fl->owner.pid); | 109 | put_pid(fl->owner.pid); |
97 | release_net(fl->fl_net); | 110 | release_net(fl->fl_net); |
98 | kfree(fl->opt); | 111 | kfree(fl->opt); |
112 | kfree_rcu(fl, rcu); | ||
99 | } | 113 | } |
100 | kfree(fl); | ||
101 | } | 114 | } |
102 | 115 | ||
103 | static void fl_release(struct ip6_flowlabel *fl) | 116 | static void fl_release(struct ip6_flowlabel *fl) |
104 | { | 117 | { |
105 | write_lock_bh(&ip6_fl_lock); | 118 | spin_lock_bh(&ip6_fl_lock); |
106 | 119 | ||
107 | fl->lastuse = jiffies; | 120 | fl->lastuse = jiffies; |
108 | if (atomic_dec_and_test(&fl->users)) { | 121 | if (atomic_dec_and_test(&fl->users)) { |
@@ -119,7 +132,7 @@ static void fl_release(struct ip6_flowlabel *fl) | |||
119 | time_after(ip6_fl_gc_timer.expires, ttd)) | 132 | time_after(ip6_fl_gc_timer.expires, ttd)) |
120 | mod_timer(&ip6_fl_gc_timer, ttd); | 133 | mod_timer(&ip6_fl_gc_timer, ttd); |
121 | } | 134 | } |
122 | write_unlock_bh(&ip6_fl_lock); | 135 | spin_unlock_bh(&ip6_fl_lock); |
123 | } | 136 | } |
124 | 137 | ||
125 | static void ip6_fl_gc(unsigned long dummy) | 138 | static void ip6_fl_gc(unsigned long dummy) |
@@ -128,12 +141,13 @@ static void ip6_fl_gc(unsigned long dummy) | |||
128 | unsigned long now = jiffies; | 141 | unsigned long now = jiffies; |
129 | unsigned long sched = 0; | 142 | unsigned long sched = 0; |
130 | 143 | ||
131 | write_lock(&ip6_fl_lock); | 144 | spin_lock(&ip6_fl_lock); |
132 | 145 | ||
133 | for (i=0; i<=FL_HASH_MASK; i++) { | 146 | for (i=0; i<=FL_HASH_MASK; i++) { |
134 | struct ip6_flowlabel *fl, **flp; | 147 | struct ip6_flowlabel *fl, **flp; |
135 | flp = &fl_ht[i]; | 148 | flp = &fl_ht[i]; |
136 | while ((fl=*flp) != NULL) { | 149 | while ((fl = rcu_dereference_protected(*flp, |
150 | lockdep_is_held(&ip6_fl_lock))) != NULL) { | ||
137 | if (atomic_read(&fl->users) == 0) { | 151 | if (atomic_read(&fl->users) == 0) { |
138 | unsigned long ttd = fl->lastuse + fl->linger; | 152 | unsigned long ttd = fl->lastuse + fl->linger; |
139 | if (time_after(ttd, fl->expires)) | 153 | if (time_after(ttd, fl->expires)) |
@@ -156,18 +170,19 @@ static void ip6_fl_gc(unsigned long dummy) | |||
156 | if (sched) { | 170 | if (sched) { |
157 | mod_timer(&ip6_fl_gc_timer, sched); | 171 | mod_timer(&ip6_fl_gc_timer, sched); |
158 | } | 172 | } |
159 | write_unlock(&ip6_fl_lock); | 173 | spin_unlock(&ip6_fl_lock); |
160 | } | 174 | } |
161 | 175 | ||
162 | static void __net_exit ip6_fl_purge(struct net *net) | 176 | static void __net_exit ip6_fl_purge(struct net *net) |
163 | { | 177 | { |
164 | int i; | 178 | int i; |
165 | 179 | ||
166 | write_lock(&ip6_fl_lock); | 180 | spin_lock(&ip6_fl_lock); |
167 | for (i = 0; i <= FL_HASH_MASK; i++) { | 181 | for (i = 0; i <= FL_HASH_MASK; i++) { |
168 | struct ip6_flowlabel *fl, **flp; | 182 | struct ip6_flowlabel *fl, **flp; |
169 | flp = &fl_ht[i]; | 183 | flp = &fl_ht[i]; |
170 | while ((fl = *flp) != NULL) { | 184 | while ((fl = rcu_dereference_protected(*flp, |
185 | lockdep_is_held(&ip6_fl_lock))) != NULL) { | ||
171 | if (net_eq(fl->fl_net, net) && | 186 | if (net_eq(fl->fl_net, net) && |
172 | atomic_read(&fl->users) == 0) { | 187 | atomic_read(&fl->users) == 0) { |
173 | *flp = fl->next; | 188 | *flp = fl->next; |
@@ -178,7 +193,7 @@ static void __net_exit ip6_fl_purge(struct net *net) | |||
178 | flp = &fl->next; | 193 | flp = &fl->next; |
179 | } | 194 | } |
180 | } | 195 | } |
181 | write_unlock(&ip6_fl_lock); | 196 | spin_unlock(&ip6_fl_lock); |
182 | } | 197 | } |
183 | 198 | ||
184 | static struct ip6_flowlabel *fl_intern(struct net *net, | 199 | static struct ip6_flowlabel *fl_intern(struct net *net, |
@@ -188,7 +203,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
188 | 203 | ||
189 | fl->label = label & IPV6_FLOWLABEL_MASK; | 204 | fl->label = label & IPV6_FLOWLABEL_MASK; |
190 | 205 | ||
191 | write_lock_bh(&ip6_fl_lock); | 206 | spin_lock_bh(&ip6_fl_lock); |
192 | if (label == 0) { | 207 | if (label == 0) { |
193 | for (;;) { | 208 | for (;;) { |
194 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; | 209 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; |
@@ -210,16 +225,16 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
210 | lfl = __fl_lookup(net, fl->label); | 225 | lfl = __fl_lookup(net, fl->label); |
211 | if (lfl != NULL) { | 226 | if (lfl != NULL) { |
212 | atomic_inc(&lfl->users); | 227 | atomic_inc(&lfl->users); |
213 | write_unlock_bh(&ip6_fl_lock); | 228 | spin_unlock_bh(&ip6_fl_lock); |
214 | return lfl; | 229 | return lfl; |
215 | } | 230 | } |
216 | } | 231 | } |
217 | 232 | ||
218 | fl->lastuse = jiffies; | 233 | fl->lastuse = jiffies; |
219 | fl->next = fl_ht[FL_HASH(fl->label)]; | 234 | fl->next = fl_ht[FL_HASH(fl->label)]; |
220 | fl_ht[FL_HASH(fl->label)] = fl; | 235 | rcu_assign_pointer(fl_ht[FL_HASH(fl->label)], fl); |
221 | atomic_inc(&fl_size); | 236 | atomic_inc(&fl_size); |
222 | write_unlock_bh(&ip6_fl_lock); | 237 | spin_unlock_bh(&ip6_fl_lock); |
223 | return NULL; | 238 | return NULL; |
224 | } | 239 | } |
225 | 240 | ||
@@ -234,17 +249,17 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) | |||
234 | 249 | ||
235 | label &= IPV6_FLOWLABEL_MASK; | 250 | label &= IPV6_FLOWLABEL_MASK; |
236 | 251 | ||
237 | read_lock_bh(&ip6_sk_fl_lock); | 252 | rcu_read_lock_bh(); |
238 | for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) { | 253 | for_each_sk_fl_rcu(np, sfl) { |
239 | struct ip6_flowlabel *fl = sfl->fl; | 254 | struct ip6_flowlabel *fl = sfl->fl; |
240 | if (fl->label == label) { | 255 | if (fl->label == label) { |
241 | fl->lastuse = jiffies; | 256 | fl->lastuse = jiffies; |
242 | atomic_inc(&fl->users); | 257 | atomic_inc(&fl->users); |
243 | read_unlock_bh(&ip6_sk_fl_lock); | 258 | rcu_read_unlock_bh(); |
244 | return fl; | 259 | return fl; |
245 | } | 260 | } |
246 | } | 261 | } |
247 | read_unlock_bh(&ip6_sk_fl_lock); | 262 | rcu_read_unlock_bh(); |
248 | return NULL; | 263 | return NULL; |
249 | } | 264 | } |
250 | 265 | ||
@@ -255,11 +270,21 @@ void fl6_free_socklist(struct sock *sk) | |||
255 | struct ipv6_pinfo *np = inet6_sk(sk); | 270 | struct ipv6_pinfo *np = inet6_sk(sk); |
256 | struct ipv6_fl_socklist *sfl; | 271 | struct ipv6_fl_socklist *sfl; |
257 | 272 | ||
258 | while ((sfl = np->ipv6_fl_list) != NULL) { | 273 | if (!rcu_access_pointer(np->ipv6_fl_list)) |
274 | return; | ||
275 | |||
276 | spin_lock_bh(&ip6_sk_fl_lock); | ||
277 | while ((sfl = rcu_dereference_protected(np->ipv6_fl_list, | ||
278 | lockdep_is_held(&ip6_sk_fl_lock))) != NULL) { | ||
259 | np->ipv6_fl_list = sfl->next; | 279 | np->ipv6_fl_list = sfl->next; |
280 | spin_unlock_bh(&ip6_sk_fl_lock); | ||
281 | |||
260 | fl_release(sfl->fl); | 282 | fl_release(sfl->fl); |
261 | kfree(sfl); | 283 | kfree_rcu(sfl, rcu); |
284 | |||
285 | spin_lock_bh(&ip6_sk_fl_lock); | ||
262 | } | 286 | } |
287 | spin_unlock_bh(&ip6_sk_fl_lock); | ||
263 | } | 288 | } |
264 | 289 | ||
265 | /* Service routines */ | 290 | /* Service routines */ |
@@ -424,7 +449,7 @@ static int mem_check(struct sock *sk) | |||
424 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) | 449 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) |
425 | return 0; | 450 | return 0; |
426 | 451 | ||
427 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) | 452 | for_each_sk_fl_rcu(np, sfl) |
428 | count++; | 453 | count++; |
429 | 454 | ||
430 | if (room <= 0 || | 455 | if (room <= 0 || |
@@ -467,11 +492,11 @@ static bool ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) | |||
467 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | 492 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, |
468 | struct ip6_flowlabel *fl) | 493 | struct ip6_flowlabel *fl) |
469 | { | 494 | { |
470 | write_lock_bh(&ip6_sk_fl_lock); | 495 | spin_lock_bh(&ip6_sk_fl_lock); |
471 | sfl->fl = fl; | 496 | sfl->fl = fl; |
472 | sfl->next = np->ipv6_fl_list; | 497 | sfl->next = np->ipv6_fl_list; |
473 | np->ipv6_fl_list = sfl; | 498 | rcu_assign_pointer(np->ipv6_fl_list, sfl); |
474 | write_unlock_bh(&ip6_sk_fl_lock); | 499 | spin_unlock_bh(&ip6_sk_fl_lock); |
475 | } | 500 | } |
476 | 501 | ||
477 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 502 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) |
@@ -493,31 +518,33 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
493 | 518 | ||
494 | switch (freq.flr_action) { | 519 | switch (freq.flr_action) { |
495 | case IPV6_FL_A_PUT: | 520 | case IPV6_FL_A_PUT: |
496 | write_lock_bh(&ip6_sk_fl_lock); | 521 | spin_lock_bh(&ip6_sk_fl_lock); |
497 | for (sflp = &np->ipv6_fl_list; (sfl=*sflp)!=NULL; sflp = &sfl->next) { | 522 | for (sflp = &np->ipv6_fl_list; |
523 | (sfl = rcu_dereference(*sflp))!=NULL; | ||
524 | sflp = &sfl->next) { | ||
498 | if (sfl->fl->label == freq.flr_label) { | 525 | if (sfl->fl->label == freq.flr_label) { |
499 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) | 526 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) |
500 | np->flow_label &= ~IPV6_FLOWLABEL_MASK; | 527 | np->flow_label &= ~IPV6_FLOWLABEL_MASK; |
501 | *sflp = sfl->next; | 528 | *sflp = rcu_dereference(sfl->next); |
502 | write_unlock_bh(&ip6_sk_fl_lock); | 529 | spin_unlock_bh(&ip6_sk_fl_lock); |
503 | fl_release(sfl->fl); | 530 | fl_release(sfl->fl); |
504 | kfree(sfl); | 531 | kfree_rcu(sfl, rcu); |
505 | return 0; | 532 | return 0; |
506 | } | 533 | } |
507 | } | 534 | } |
508 | write_unlock_bh(&ip6_sk_fl_lock); | 535 | spin_unlock_bh(&ip6_sk_fl_lock); |
509 | return -ESRCH; | 536 | return -ESRCH; |
510 | 537 | ||
511 | case IPV6_FL_A_RENEW: | 538 | case IPV6_FL_A_RENEW: |
512 | read_lock_bh(&ip6_sk_fl_lock); | 539 | rcu_read_lock_bh(); |
513 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { | 540 | for_each_sk_fl_rcu(np, sfl) { |
514 | if (sfl->fl->label == freq.flr_label) { | 541 | if (sfl->fl->label == freq.flr_label) { |
515 | err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); | 542 | err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); |
516 | read_unlock_bh(&ip6_sk_fl_lock); | 543 | rcu_read_unlock_bh(); |
517 | return err; | 544 | return err; |
518 | } | 545 | } |
519 | } | 546 | } |
520 | read_unlock_bh(&ip6_sk_fl_lock); | 547 | rcu_read_unlock_bh(); |
521 | 548 | ||
522 | if (freq.flr_share == IPV6_FL_S_NONE && | 549 | if (freq.flr_share == IPV6_FL_S_NONE && |
523 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { | 550 | ns_capable(net->user_ns, CAP_NET_ADMIN)) { |
@@ -541,11 +568,11 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
541 | 568 | ||
542 | if (freq.flr_label) { | 569 | if (freq.flr_label) { |
543 | err = -EEXIST; | 570 | err = -EEXIST; |
544 | read_lock_bh(&ip6_sk_fl_lock); | 571 | rcu_read_lock_bh(); |
545 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { | 572 | for_each_sk_fl_rcu(np, sfl) { |
546 | if (sfl->fl->label == freq.flr_label) { | 573 | if (sfl->fl->label == freq.flr_label) { |
547 | if (freq.flr_flags&IPV6_FL_F_EXCL) { | 574 | if (freq.flr_flags&IPV6_FL_F_EXCL) { |
548 | read_unlock_bh(&ip6_sk_fl_lock); | 575 | rcu_read_unlock_bh(); |
549 | goto done; | 576 | goto done; |
550 | } | 577 | } |
551 | fl1 = sfl->fl; | 578 | fl1 = sfl->fl; |
@@ -553,7 +580,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
553 | break; | 580 | break; |
554 | } | 581 | } |
555 | } | 582 | } |
556 | read_unlock_bh(&ip6_sk_fl_lock); | 583 | rcu_read_unlock_bh(); |
557 | 584 | ||
558 | if (fl1 == NULL) | 585 | if (fl1 == NULL) |
559 | fl1 = fl_lookup(net, freq.flr_label); | 586 | fl1 = fl_lookup(net, freq.flr_label); |
@@ -641,13 +668,13 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) | |||
641 | struct net *net = seq_file_net(seq); | 668 | struct net *net = seq_file_net(seq); |
642 | 669 | ||
643 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { | 670 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { |
644 | fl = fl_ht[state->bucket]; | 671 | for_each_fl_rcu(state->bucket, fl) { |
645 | 672 | if (net_eq(fl->fl_net, net)) | |
646 | while (fl && !net_eq(fl->fl_net, net)) | 673 | goto out; |
647 | fl = fl->next; | 674 | } |
648 | if (fl) | ||
649 | break; | ||
650 | } | 675 | } |
676 | fl = NULL; | ||
677 | out: | ||
651 | return fl; | 678 | return fl; |
652 | } | 679 | } |
653 | 680 | ||
@@ -656,18 +683,22 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo | |||
656 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | 683 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); |
657 | struct net *net = seq_file_net(seq); | 684 | struct net *net = seq_file_net(seq); |
658 | 685 | ||
659 | fl = fl->next; | 686 | for_each_fl_continue_rcu(fl) { |
687 | if (net_eq(fl->fl_net, net)) | ||
688 | goto out; | ||
689 | } | ||
690 | |||
660 | try_again: | 691 | try_again: |
661 | while (fl && !net_eq(fl->fl_net, net)) | 692 | if (++state->bucket <= FL_HASH_MASK) { |
662 | fl = fl->next; | 693 | for_each_fl_rcu(state->bucket, fl) { |
663 | 694 | if (net_eq(fl->fl_net, net)) | |
664 | while (!fl) { | 695 | goto out; |
665 | if (++state->bucket <= FL_HASH_MASK) { | 696 | } |
666 | fl = fl_ht[state->bucket]; | 697 | goto try_again; |
667 | goto try_again; | ||
668 | } else | ||
669 | break; | ||
670 | } | 698 | } |
699 | fl = NULL; | ||
700 | |||
701 | out: | ||
671 | return fl; | 702 | return fl; |
672 | } | 703 | } |
673 | 704 | ||
@@ -681,9 +712,9 @@ static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos) | |||
681 | } | 712 | } |
682 | 713 | ||
683 | static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) | 714 | static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) |
684 | __acquires(ip6_fl_lock) | 715 | __acquires(RCU) |
685 | { | 716 | { |
686 | read_lock_bh(&ip6_fl_lock); | 717 | rcu_read_lock_bh(); |
687 | return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 718 | return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
688 | } | 719 | } |
689 | 720 | ||
@@ -700,9 +731,9 @@ static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
700 | } | 731 | } |
701 | 732 | ||
702 | static void ip6fl_seq_stop(struct seq_file *seq, void *v) | 733 | static void ip6fl_seq_stop(struct seq_file *seq, void *v) |
703 | __releases(ip6_fl_lock) | 734 | __releases(RCU) |
704 | { | 735 | { |
705 | read_unlock_bh(&ip6_fl_lock); | 736 | rcu_read_unlock_bh(); |
706 | } | 737 | } |
707 | 738 | ||
708 | static int ip6fl_seq_show(struct seq_file *seq, void *v) | 739 | static int ip6fl_seq_show(struct seq_file *seq, void *v) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index c727e4712751..db91fe3466a3 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -772,9 +772,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
772 | * Push down and install the IP header. | 772 | * Push down and install the IP header. |
773 | */ | 773 | */ |
774 | ipv6h = ipv6_hdr(skb); | 774 | ipv6h = ipv6_hdr(skb); |
775 | *(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000); | 775 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); |
776 | dsfield = INET_ECN_encapsulate(0, dsfield); | ||
777 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | ||
778 | ipv6h->hop_limit = tunnel->parms.hop_limit; | 776 | ipv6h->hop_limit = tunnel->parms.hop_limit; |
779 | ipv6h->nexthdr = proto; | 777 | ipv6h->nexthdr = proto; |
780 | ipv6h->saddr = fl6->saddr; | 778 | ipv6h->saddr = fl6->saddr; |
@@ -1240,7 +1238,7 @@ static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, | |||
1240 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); | 1238 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); |
1241 | __be16 *p = (__be16 *)(ipv6h+1); | 1239 | __be16 *p = (__be16 *)(ipv6h+1); |
1242 | 1240 | ||
1243 | *(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000); | 1241 | ip6_flow_hdr(ipv6h, 0, t->fl.u.ip6.flowlabel); |
1244 | ipv6h->hop_limit = t->parms.hop_limit; | 1242 | ipv6h->hop_limit = t->parms.hop_limit; |
1245 | ipv6h->nexthdr = NEXTHDR_GRE; | 1243 | ipv6h->nexthdr = NEXTHDR_GRE; |
1246 | ipv6h->saddr = t->parms.laddr; | 1244 | ipv6h->saddr = t->parms.laddr; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a52d864d562b..4ac5bf30e16a 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -212,7 +212,7 @@ resubmit: | |||
212 | if (ipv6_addr_is_multicast(&hdr->daddr) && | 212 | if (ipv6_addr_is_multicast(&hdr->daddr) && |
213 | !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, | 213 | !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, |
214 | &hdr->saddr) && | 214 | &hdr->saddr) && |
215 | !ipv6_is_mld(skb, nexthdr)) | 215 | !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) |
216 | goto discard; | 216 | goto discard; |
217 | } | 217 | } |
218 | if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && | 218 | if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && |
@@ -280,10 +280,8 @@ int ip6_mc_input(struct sk_buff *skb) | |||
280 | struct inet6_skb_parm *opt = IP6CB(skb); | 280 | struct inet6_skb_parm *opt = IP6CB(skb); |
281 | 281 | ||
282 | /* Check for MLD */ | 282 | /* Check for MLD */ |
283 | if (unlikely(opt->ra)) { | 283 | if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { |
284 | /* Check if this is a mld message */ | 284 | /* Check if this is a mld message */ |
285 | u8 *ptr = skb_network_header(skb) + opt->ra; | ||
286 | struct icmp6hdr *icmp6; | ||
287 | u8 nexthdr = hdr->nexthdr; | 285 | u8 nexthdr = hdr->nexthdr; |
288 | __be16 frag_off; | 286 | __be16 frag_off; |
289 | int offset; | 287 | int offset; |
@@ -291,7 +289,7 @@ int ip6_mc_input(struct sk_buff *skb) | |||
291 | /* Check if the value of Router Alert | 289 | /* Check if the value of Router Alert |
292 | * is for MLD (0x0000). | 290 | * is for MLD (0x0000). |
293 | */ | 291 | */ |
294 | if ((ptr[2] | ptr[3]) == 0) { | 292 | if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { |
295 | deliver = false; | 293 | deliver = false; |
296 | 294 | ||
297 | if (!ipv6_ext_hdr(nexthdr)) { | 295 | if (!ipv6_ext_hdr(nexthdr)) { |
@@ -303,24 +301,10 @@ int ip6_mc_input(struct sk_buff *skb) | |||
303 | if (offset < 0) | 301 | if (offset < 0) |
304 | goto out; | 302 | goto out; |
305 | 303 | ||
306 | if (nexthdr != IPPROTO_ICMPV6) | 304 | if (!ipv6_is_mld(skb, nexthdr, offset)) |
307 | goto out; | 305 | goto out; |
308 | 306 | ||
309 | if (!pskb_may_pull(skb, (skb_network_header(skb) + | 307 | deliver = true; |
310 | offset + 1 - skb->data))) | ||
311 | goto out; | ||
312 | |||
313 | icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); | ||
314 | |||
315 | switch (icmp6->icmp6_type) { | ||
316 | case ICMPV6_MGM_QUERY: | ||
317 | case ICMPV6_MGM_REPORT: | ||
318 | case ICMPV6_MGM_REDUCTION: | ||
319 | case ICMPV6_MLD2_REPORT: | ||
320 | deliver = true; | ||
321 | break; | ||
322 | } | ||
323 | goto out; | ||
324 | } | 308 | } |
325 | /* unknown RA - process it normally */ | 309 | /* unknown RA - process it normally */ |
326 | } | 310 | } |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index f26f0da7f095..d141fc32a2ea 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -100,6 +100,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
100 | SKB_GSO_DODGY | | 100 | SKB_GSO_DODGY | |
101 | SKB_GSO_TCP_ECN | | 101 | SKB_GSO_TCP_ECN | |
102 | SKB_GSO_TCPV6 | | 102 | SKB_GSO_TCPV6 | |
103 | SKB_GSO_SHARED_FRAG | | ||
103 | 0))) | 104 | 0))) |
104 | goto out; | 105 | goto out; |
105 | 106 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0c7c03d50dc0..906b7e6dd7fb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -56,8 +56,6 @@ | |||
56 | #include <net/checksum.h> | 56 | #include <net/checksum.h> |
57 | #include <linux/mroute6.h> | 57 | #include <linux/mroute6.h> |
58 | 58 | ||
59 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | ||
60 | |||
61 | int __ip6_local_out(struct sk_buff *skb) | 59 | int __ip6_local_out(struct sk_buff *skb) |
62 | { | 60 | { |
63 | int len; | 61 | int len; |
@@ -88,7 +86,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
88 | struct dst_entry *dst = skb_dst(skb); | 86 | struct dst_entry *dst = skb_dst(skb); |
89 | struct net_device *dev = dst->dev; | 87 | struct net_device *dev = dst->dev; |
90 | struct neighbour *neigh; | 88 | struct neighbour *neigh; |
91 | struct rt6_info *rt; | 89 | struct in6_addr *nexthop; |
90 | int ret; | ||
92 | 91 | ||
93 | skb->protocol = htons(ETH_P_IPV6); | 92 | skb->protocol = htons(ETH_P_IPV6); |
94 | skb->dev = dev; | 93 | skb->dev = dev; |
@@ -123,10 +122,17 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
123 | skb->len); | 122 | skb->len); |
124 | } | 123 | } |
125 | 124 | ||
126 | rt = (struct rt6_info *) dst; | 125 | rcu_read_lock_bh(); |
127 | neigh = rt->n; | 126 | nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); |
128 | if (neigh) | 127 | neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); |
129 | return dst_neigh_output(dst, neigh, skb); | 128 | if (unlikely(!neigh)) |
129 | neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); | ||
130 | if (!IS_ERR(neigh)) { | ||
131 | ret = dst_neigh_output(dst, neigh, skb); | ||
132 | rcu_read_unlock_bh(); | ||
133 | return ret; | ||
134 | } | ||
135 | rcu_read_unlock_bh(); | ||
130 | 136 | ||
131 | IP6_INC_STATS_BH(dev_net(dst->dev), | 137 | IP6_INC_STATS_BH(dev_net(dst->dev), |
132 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 138 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
@@ -216,7 +222,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
216 | if (hlimit < 0) | 222 | if (hlimit < 0) |
217 | hlimit = ip6_dst_hoplimit(dst); | 223 | hlimit = ip6_dst_hoplimit(dst); |
218 | 224 | ||
219 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; | 225 | ip6_flow_hdr(hdr, tclass, fl6->flowlabel); |
220 | 226 | ||
221 | hdr->payload_len = htons(seg_len); | 227 | hdr->payload_len = htons(seg_len); |
222 | hdr->nexthdr = proto; | 228 | hdr->nexthdr = proto; |
@@ -246,39 +252,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
246 | 252 | ||
247 | EXPORT_SYMBOL(ip6_xmit); | 253 | EXPORT_SYMBOL(ip6_xmit); |
248 | 254 | ||
249 | /* | ||
250 | * To avoid extra problems ND packets are send through this | ||
251 | * routine. It's code duplication but I really want to avoid | ||
252 | * extra checks since ipv6_build_header is used by TCP (which | ||
253 | * is for us performance critical) | ||
254 | */ | ||
255 | |||
256 | int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, | ||
257 | const struct in6_addr *saddr, const struct in6_addr *daddr, | ||
258 | int proto, int len) | ||
259 | { | ||
260 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
261 | struct ipv6hdr *hdr; | ||
262 | |||
263 | skb->protocol = htons(ETH_P_IPV6); | ||
264 | skb->dev = dev; | ||
265 | |||
266 | skb_reset_network_header(skb); | ||
267 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
268 | hdr = ipv6_hdr(skb); | ||
269 | |||
270 | *(__be32*)hdr = htonl(0x60000000); | ||
271 | |||
272 | hdr->payload_len = htons(len); | ||
273 | hdr->nexthdr = proto; | ||
274 | hdr->hop_limit = np->hop_limit; | ||
275 | |||
276 | hdr->saddr = *saddr; | ||
277 | hdr->daddr = *daddr; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | 255 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) |
283 | { | 256 | { |
284 | struct ip6_ra_chain *ra; | 257 | struct ip6_ra_chain *ra; |
@@ -913,8 +886,12 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
913 | * dst entry of the nexthop router | 886 | * dst entry of the nexthop router |
914 | */ | 887 | */ |
915 | rt = (struct rt6_info *) *dst; | 888 | rt = (struct rt6_info *) *dst; |
916 | n = rt->n; | 889 | rcu_read_lock_bh(); |
917 | if (n && !(n->nud_state & NUD_VALID)) { | 890 | n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr)); |
891 | err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; | ||
892 | rcu_read_unlock_bh(); | ||
893 | |||
894 | if (err) { | ||
918 | struct inet6_ifaddr *ifp; | 895 | struct inet6_ifaddr *ifp; |
919 | struct flowi6 fl_gw6; | 896 | struct flowi6 fl_gw6; |
920 | int redirect; | 897 | int redirect; |
@@ -1548,9 +1525,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1548 | skb_reset_network_header(skb); | 1525 | skb_reset_network_header(skb); |
1549 | hdr = ipv6_hdr(skb); | 1526 | hdr = ipv6_hdr(skb); |
1550 | 1527 | ||
1551 | *(__be32*)hdr = fl6->flowlabel | | 1528 | ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); |
1552 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | ||
1553 | |||
1554 | hdr->hop_limit = np->cork.hop_limit; | 1529 | hdr->hop_limit = np->cork.hop_limit; |
1555 | hdr->nexthdr = proto; | 1530 | hdr->nexthdr = proto; |
1556 | hdr->saddr = fl6->saddr; | 1531 | hdr->saddr = fl6->saddr; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a14f28b280f5..fff83cbc197f 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -1030,9 +1030,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
1030 | skb_push(skb, sizeof(struct ipv6hdr)); | 1030 | skb_push(skb, sizeof(struct ipv6hdr)); |
1031 | skb_reset_network_header(skb); | 1031 | skb_reset_network_header(skb); |
1032 | ipv6h = ipv6_hdr(skb); | 1032 | ipv6h = ipv6_hdr(skb); |
1033 | *(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000); | 1033 | ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield), fl6->flowlabel); |
1034 | dsfield = INET_ECN_encapsulate(0, dsfield); | ||
1035 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | ||
1036 | ipv6h->hop_limit = t->parms.hop_limit; | 1034 | ipv6h->hop_limit = t->parms.hop_limit; |
1037 | ipv6h->nexthdr = proto; | 1035 | ipv6h->nexthdr = proto; |
1038 | ipv6h->saddr = fl6->saddr; | 1036 | ipv6h->saddr = fl6->saddr; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8fd154e5f079..351ce98e90d9 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -1017,6 +1017,50 @@ static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, | |||
1017 | return NULL; | 1017 | return NULL; |
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | /* Look for a (*,*,oif) entry */ | ||
1021 | static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt, | ||
1022 | mifi_t mifi) | ||
1023 | { | ||
1024 | int line = MFC6_HASH(&in6addr_any, &in6addr_any); | ||
1025 | struct mfc6_cache *c; | ||
1026 | |||
1027 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) | ||
1028 | if (ipv6_addr_any(&c->mf6c_origin) && | ||
1029 | ipv6_addr_any(&c->mf6c_mcastgrp) && | ||
1030 | (c->mfc_un.res.ttls[mifi] < 255)) | ||
1031 | return c; | ||
1032 | |||
1033 | return NULL; | ||
1034 | } | ||
1035 | |||
1036 | /* Look for a (*,G) entry */ | ||
1037 | static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt, | ||
1038 | struct in6_addr *mcastgrp, | ||
1039 | mifi_t mifi) | ||
1040 | { | ||
1041 | int line = MFC6_HASH(mcastgrp, &in6addr_any); | ||
1042 | struct mfc6_cache *c, *proxy; | ||
1043 | |||
1044 | if (ipv6_addr_any(mcastgrp)) | ||
1045 | goto skip; | ||
1046 | |||
1047 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) | ||
1048 | if (ipv6_addr_any(&c->mf6c_origin) && | ||
1049 | ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) { | ||
1050 | if (c->mfc_un.res.ttls[mifi] < 255) | ||
1051 | return c; | ||
1052 | |||
1053 | /* It's ok if the mifi is part of the static tree */ | ||
1054 | proxy = ip6mr_cache_find_any_parent(mrt, | ||
1055 | c->mf6c_parent); | ||
1056 | if (proxy && proxy->mfc_un.res.ttls[mifi] < 255) | ||
1057 | return c; | ||
1058 | } | ||
1059 | |||
1060 | skip: | ||
1061 | return ip6mr_cache_find_any_parent(mrt, mifi); | ||
1062 | } | ||
1063 | |||
1020 | /* | 1064 | /* |
1021 | * Allocate a multicast cache entry | 1065 | * Allocate a multicast cache entry |
1022 | */ | 1066 | */ |
@@ -1247,7 +1291,8 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb) | |||
1247 | * MFC6 cache manipulation by user space | 1291 | * MFC6 cache manipulation by user space |
1248 | */ | 1292 | */ |
1249 | 1293 | ||
1250 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | 1294 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc, |
1295 | int parent) | ||
1251 | { | 1296 | { |
1252 | int line; | 1297 | int line; |
1253 | struct mfc6_cache *c, *next; | 1298 | struct mfc6_cache *c, *next; |
@@ -1256,7 +1301,9 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | |||
1256 | 1301 | ||
1257 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { | 1302 | list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { |
1258 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1303 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
1259 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { | 1304 | ipv6_addr_equal(&c->mf6c_mcastgrp, |
1305 | &mfc->mf6cc_mcastgrp.sin6_addr) && | ||
1306 | (parent == -1 || parent == c->mf6c_parent)) { | ||
1260 | write_lock_bh(&mrt_lock); | 1307 | write_lock_bh(&mrt_lock); |
1261 | list_del(&c->list); | 1308 | list_del(&c->list); |
1262 | write_unlock_bh(&mrt_lock); | 1309 | write_unlock_bh(&mrt_lock); |
@@ -1391,7 +1438,7 @@ void ip6_mr_cleanup(void) | |||
1391 | } | 1438 | } |
1392 | 1439 | ||
1393 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | 1440 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, |
1394 | struct mf6cctl *mfc, int mrtsock) | 1441 | struct mf6cctl *mfc, int mrtsock, int parent) |
1395 | { | 1442 | { |
1396 | bool found = false; | 1443 | bool found = false; |
1397 | int line; | 1444 | int line; |
@@ -1413,7 +1460,9 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
1413 | 1460 | ||
1414 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { | 1461 | list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { |
1415 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && | 1462 | if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && |
1416 | ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { | 1463 | ipv6_addr_equal(&c->mf6c_mcastgrp, |
1464 | &mfc->mf6cc_mcastgrp.sin6_addr) && | ||
1465 | (parent == -1 || parent == mfc->mf6cc_parent)) { | ||
1417 | found = true; | 1466 | found = true; |
1418 | break; | 1467 | break; |
1419 | } | 1468 | } |
@@ -1430,7 +1479,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | |||
1430 | return 0; | 1479 | return 0; |
1431 | } | 1480 | } |
1432 | 1481 | ||
1433 | if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) | 1482 | if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) && |
1483 | !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) | ||
1434 | return -EINVAL; | 1484 | return -EINVAL; |
1435 | 1485 | ||
1436 | c = ip6mr_cache_alloc(); | 1486 | c = ip6mr_cache_alloc(); |
@@ -1596,7 +1646,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) | |||
1596 | 1646 | ||
1597 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) | 1647 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) |
1598 | { | 1648 | { |
1599 | int ret; | 1649 | int ret, parent = 0; |
1600 | struct mif6ctl vif; | 1650 | struct mif6ctl vif; |
1601 | struct mf6cctl mfc; | 1651 | struct mf6cctl mfc; |
1602 | mifi_t mifi; | 1652 | mifi_t mifi; |
@@ -1653,15 +1703,21 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1653 | */ | 1703 | */ |
1654 | case MRT6_ADD_MFC: | 1704 | case MRT6_ADD_MFC: |
1655 | case MRT6_DEL_MFC: | 1705 | case MRT6_DEL_MFC: |
1706 | parent = -1; | ||
1707 | case MRT6_ADD_MFC_PROXY: | ||
1708 | case MRT6_DEL_MFC_PROXY: | ||
1656 | if (optlen < sizeof(mfc)) | 1709 | if (optlen < sizeof(mfc)) |
1657 | return -EINVAL; | 1710 | return -EINVAL; |
1658 | if (copy_from_user(&mfc, optval, sizeof(mfc))) | 1711 | if (copy_from_user(&mfc, optval, sizeof(mfc))) |
1659 | return -EFAULT; | 1712 | return -EFAULT; |
1713 | if (parent == 0) | ||
1714 | parent = mfc.mf6cc_parent; | ||
1660 | rtnl_lock(); | 1715 | rtnl_lock(); |
1661 | if (optname == MRT6_DEL_MFC) | 1716 | if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY) |
1662 | ret = ip6mr_mfc_delete(mrt, &mfc); | 1717 | ret = ip6mr_mfc_delete(mrt, &mfc, parent); |
1663 | else | 1718 | else |
1664 | ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk); | 1719 | ret = ip6mr_mfc_add(net, mrt, &mfc, |
1720 | sk == mrt->mroute6_sk, parent); | ||
1665 | rtnl_unlock(); | 1721 | rtnl_unlock(); |
1666 | return ret; | 1722 | return ret; |
1667 | 1723 | ||
@@ -2018,19 +2074,29 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2018 | { | 2074 | { |
2019 | int psend = -1; | 2075 | int psend = -1; |
2020 | int vif, ct; | 2076 | int vif, ct; |
2077 | int true_vifi = ip6mr_find_vif(mrt, skb->dev); | ||
2021 | 2078 | ||
2022 | vif = cache->mf6c_parent; | 2079 | vif = cache->mf6c_parent; |
2023 | cache->mfc_un.res.pkt++; | 2080 | cache->mfc_un.res.pkt++; |
2024 | cache->mfc_un.res.bytes += skb->len; | 2081 | cache->mfc_un.res.bytes += skb->len; |
2025 | 2082 | ||
2083 | if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) { | ||
2084 | struct mfc6_cache *cache_proxy; | ||
2085 | |||
2086 | /* For an (*,G) entry, we only check that the incomming | ||
2087 | * interface is part of the static tree. | ||
2088 | */ | ||
2089 | cache_proxy = ip6mr_cache_find_any_parent(mrt, vif); | ||
2090 | if (cache_proxy && | ||
2091 | cache_proxy->mfc_un.res.ttls[true_vifi] < 255) | ||
2092 | goto forward; | ||
2093 | } | ||
2094 | |||
2026 | /* | 2095 | /* |
2027 | * Wrong interface: drop packet and (maybe) send PIM assert. | 2096 | * Wrong interface: drop packet and (maybe) send PIM assert. |
2028 | */ | 2097 | */ |
2029 | if (mrt->vif6_table[vif].dev != skb->dev) { | 2098 | if (mrt->vif6_table[vif].dev != skb->dev) { |
2030 | int true_vifi; | ||
2031 | |||
2032 | cache->mfc_un.res.wrong_if++; | 2099 | cache->mfc_un.res.wrong_if++; |
2033 | true_vifi = ip6mr_find_vif(mrt, skb->dev); | ||
2034 | 2100 | ||
2035 | if (true_vifi >= 0 && mrt->mroute_do_assert && | 2101 | if (true_vifi >= 0 && mrt->mroute_do_assert && |
2036 | /* pimsm uses asserts, when switching from RPT to SPT, | 2102 | /* pimsm uses asserts, when switching from RPT to SPT, |
@@ -2048,14 +2114,32 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2048 | goto dont_forward; | 2114 | goto dont_forward; |
2049 | } | 2115 | } |
2050 | 2116 | ||
2117 | forward: | ||
2051 | mrt->vif6_table[vif].pkt_in++; | 2118 | mrt->vif6_table[vif].pkt_in++; |
2052 | mrt->vif6_table[vif].bytes_in += skb->len; | 2119 | mrt->vif6_table[vif].bytes_in += skb->len; |
2053 | 2120 | ||
2054 | /* | 2121 | /* |
2055 | * Forward the frame | 2122 | * Forward the frame |
2056 | */ | 2123 | */ |
2124 | if (ipv6_addr_any(&cache->mf6c_origin) && | ||
2125 | ipv6_addr_any(&cache->mf6c_mcastgrp)) { | ||
2126 | if (true_vifi >= 0 && | ||
2127 | true_vifi != cache->mf6c_parent && | ||
2128 | ipv6_hdr(skb)->hop_limit > | ||
2129 | cache->mfc_un.res.ttls[cache->mf6c_parent]) { | ||
2130 | /* It's an (*,*) entry and the packet is not coming from | ||
2131 | * the upstream: forward the packet to the upstream | ||
2132 | * only. | ||
2133 | */ | ||
2134 | psend = cache->mf6c_parent; | ||
2135 | goto last_forward; | ||
2136 | } | ||
2137 | goto dont_forward; | ||
2138 | } | ||
2057 | for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { | 2139 | for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { |
2058 | if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { | 2140 | /* For (*,G) entry, don't forward to the incoming interface */ |
2141 | if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) && | ||
2142 | ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { | ||
2059 | if (psend != -1) { | 2143 | if (psend != -1) { |
2060 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | 2144 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); |
2061 | if (skb2) | 2145 | if (skb2) |
@@ -2064,6 +2148,7 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
2064 | psend = ct; | 2148 | psend = ct; |
2065 | } | 2149 | } |
2066 | } | 2150 | } |
2151 | last_forward: | ||
2067 | if (psend != -1) { | 2152 | if (psend != -1) { |
2068 | ip6mr_forward2(net, mrt, skb, cache, psend); | 2153 | ip6mr_forward2(net, mrt, skb, cache, psend); |
2069 | return 0; | 2154 | return 0; |
@@ -2099,6 +2184,14 @@ int ip6_mr_input(struct sk_buff *skb) | |||
2099 | read_lock(&mrt_lock); | 2184 | read_lock(&mrt_lock); |
2100 | cache = ip6mr_cache_find(mrt, | 2185 | cache = ip6mr_cache_find(mrt, |
2101 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); | 2186 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); |
2187 | if (cache == NULL) { | ||
2188 | int vif = ip6mr_find_vif(mrt, skb->dev); | ||
2189 | |||
2190 | if (vif >= 0) | ||
2191 | cache = ip6mr_cache_find_any(mrt, | ||
2192 | &ipv6_hdr(skb)->daddr, | ||
2193 | vif); | ||
2194 | } | ||
2102 | 2195 | ||
2103 | /* | 2196 | /* |
2104 | * No usable cache entry | 2197 | * No usable cache entry |
@@ -2186,6 +2279,13 @@ int ip6mr_get_route(struct net *net, | |||
2186 | 2279 | ||
2187 | read_lock(&mrt_lock); | 2280 | read_lock(&mrt_lock); |
2188 | cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); | 2281 | cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); |
2282 | if (!cache && skb->dev) { | ||
2283 | int vif = ip6mr_find_vif(mrt, skb->dev); | ||
2284 | |||
2285 | if (vif >= 0) | ||
2286 | cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr, | ||
2287 | vif); | ||
2288 | } | ||
2189 | 2289 | ||
2190 | if (!cache) { | 2290 | if (!cache) { |
2191 | struct sk_buff *skb2; | 2291 | struct sk_buff *skb2; |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 28dfa5f3801f..e5de48551864 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -376,8 +376,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
376 | goto done; /* err = -EADDRNOTAVAIL */ | 376 | goto done; /* err = -EADDRNOTAVAIL */ |
377 | rv = !0; | 377 | rv = !0; |
378 | for (i=0; i<psl->sl_count; i++) { | 378 | for (i=0; i<psl->sl_count; i++) { |
379 | rv = memcmp(&psl->sl_addr[i], source, | 379 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
380 | sizeof(struct in6_addr)); | ||
381 | if (rv == 0) | 380 | if (rv == 0) |
382 | break; | 381 | break; |
383 | } | 382 | } |
@@ -427,12 +426,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
427 | } | 426 | } |
428 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ | 427 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ |
429 | for (i=0; i<psl->sl_count; i++) { | 428 | for (i=0; i<psl->sl_count; i++) { |
430 | rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr)); | 429 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
431 | if (rv == 0) | 430 | if (rv == 0) /* There is an error in the address. */ |
432 | break; | 431 | goto done; |
433 | } | 432 | } |
434 | if (rv == 0) /* address already there is an error */ | ||
435 | goto done; | ||
436 | for (j=psl->sl_count-1; j>=i; j--) | 433 | for (j=psl->sl_count-1; j>=i; j--) |
437 | psl->sl_addr[j+1] = psl->sl_addr[j]; | 434 | psl->sl_addr[j+1] = psl->sl_addr[j]; |
438 | psl->sl_addr[i] = *source; | 435 | psl->sl_addr[i] = *source; |
@@ -935,33 +932,6 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) | |||
935 | } | 932 | } |
936 | 933 | ||
937 | /* | 934 | /* |
938 | * identify MLD packets for MLD filter exceptions | ||
939 | */ | ||
940 | bool ipv6_is_mld(struct sk_buff *skb, int nexthdr) | ||
941 | { | ||
942 | struct icmp6hdr *pic; | ||
943 | |||
944 | if (nexthdr != IPPROTO_ICMPV6) | ||
945 | return false; | ||
946 | |||
947 | if (!pskb_may_pull(skb, sizeof(struct icmp6hdr))) | ||
948 | return false; | ||
949 | |||
950 | pic = icmp6_hdr(skb); | ||
951 | |||
952 | switch (pic->icmp6_type) { | ||
953 | case ICMPV6_MGM_QUERY: | ||
954 | case ICMPV6_MGM_REPORT: | ||
955 | case ICMPV6_MGM_REDUCTION: | ||
956 | case ICMPV6_MLD2_REPORT: | ||
957 | return true; | ||
958 | default: | ||
959 | break; | ||
960 | } | ||
961 | return false; | ||
962 | } | ||
963 | |||
964 | /* | ||
965 | * check if the interface/address pair is valid | 935 | * check if the interface/address pair is valid |
966 | */ | 936 | */ |
967 | bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | 937 | bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, |
@@ -1340,6 +1310,31 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) | |||
1340 | return scount; | 1310 | return scount; |
1341 | } | 1311 | } |
1342 | 1312 | ||
1313 | static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb, | ||
1314 | struct net_device *dev, | ||
1315 | const struct in6_addr *saddr, | ||
1316 | const struct in6_addr *daddr, | ||
1317 | int proto, int len) | ||
1318 | { | ||
1319 | struct ipv6hdr *hdr; | ||
1320 | |||
1321 | skb->protocol = htons(ETH_P_IPV6); | ||
1322 | skb->dev = dev; | ||
1323 | |||
1324 | skb_reset_network_header(skb); | ||
1325 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
1326 | hdr = ipv6_hdr(skb); | ||
1327 | |||
1328 | ip6_flow_hdr(hdr, 0, 0); | ||
1329 | |||
1330 | hdr->payload_len = htons(len); | ||
1331 | hdr->nexthdr = proto; | ||
1332 | hdr->hop_limit = inet6_sk(sk)->hop_limit; | ||
1333 | |||
1334 | hdr->saddr = *saddr; | ||
1335 | hdr->daddr = *daddr; | ||
1336 | } | ||
1337 | |||
1343 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) | 1338 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) |
1344 | { | 1339 | { |
1345 | struct net *net = dev_net(dev); | 1340 | struct net *net = dev_net(dev); |
@@ -1375,7 +1370,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1375 | } else | 1370 | } else |
1376 | saddr = &addr_buf; | 1371 | saddr = &addr_buf; |
1377 | 1372 | ||
1378 | ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); | 1373 | ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); |
1379 | 1374 | ||
1380 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1375 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1381 | 1376 | ||
@@ -1418,7 +1413,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1418 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, | 1413 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, |
1419 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1414 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1420 | skb->dev->ifindex); | 1415 | skb->dev->ifindex); |
1421 | dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); | 1416 | dst = icmp6_dst_alloc(skb->dev, &fl6); |
1422 | 1417 | ||
1423 | err = 0; | 1418 | err = 0; |
1424 | if (IS_ERR(dst)) { | 1419 | if (IS_ERR(dst)) { |
@@ -1767,7 +1762,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1767 | } else | 1762 | } else |
1768 | saddr = &addr_buf; | 1763 | saddr = &addr_buf; |
1769 | 1764 | ||
1770 | ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); | 1765 | ip6_mc_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); |
1771 | 1766 | ||
1772 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1767 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1773 | 1768 | ||
@@ -1786,7 +1781,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1786 | icmpv6_flow_init(sk, &fl6, type, | 1781 | icmpv6_flow_init(sk, &fl6, type, |
1787 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1782 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1788 | skb->dev->ifindex); | 1783 | skb->dev->ifindex); |
1789 | dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); | 1784 | dst = icmp6_dst_alloc(skb->dev, &fl6); |
1790 | if (IS_ERR(dst)) { | 1785 | if (IS_ERR(dst)) { |
1791 | err = PTR_ERR(dst); | 1786 | err = PTR_ERR(dst); |
1792 | goto err_out; | 1787 | goto err_out; |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 6574175795df..76ef4353d518 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -143,16 +143,12 @@ struct neigh_table nd_tbl = { | |||
143 | .gc_thresh3 = 1024, | 143 | .gc_thresh3 = 1024, |
144 | }; | 144 | }; |
145 | 145 | ||
146 | static inline int ndisc_opt_addr_space(struct net_device *dev) | 146 | static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data) |
147 | { | 147 | { |
148 | return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type)); | 148 | int pad = ndisc_addr_option_pad(skb->dev->type); |
149 | } | 149 | int data_len = skb->dev->addr_len; |
150 | 150 | int space = ndisc_opt_addr_space(skb->dev); | |
151 | static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, | 151 | u8 *opt = skb_put(skb, space); |
152 | unsigned short addr_type) | ||
153 | { | ||
154 | int pad = ndisc_addr_option_pad(addr_type); | ||
155 | int space = NDISC_OPT_SPACE(data_len + pad); | ||
156 | 152 | ||
157 | opt[0] = type; | 153 | opt[0] = type; |
158 | opt[1] = space>>3; | 154 | opt[1] = space>>3; |
@@ -166,7 +162,6 @@ static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len, | |||
166 | opt += data_len; | 162 | opt += data_len; |
167 | if ((space -= data_len) > 0) | 163 | if ((space -= data_len) > 0) |
168 | memset(opt, 0, space); | 164 | memset(opt, 0, space); |
169 | return opt + space; | ||
170 | } | 165 | } |
171 | 166 | ||
172 | static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | 167 | static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, |
@@ -370,91 +365,88 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
370 | ipv6_dev_mc_dec(dev, &maddr); | 365 | ipv6_dev_mc_dec(dev, &maddr); |
371 | } | 366 | } |
372 | 367 | ||
373 | static struct sk_buff *ndisc_build_skb(struct net_device *dev, | 368 | static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, |
374 | const struct in6_addr *daddr, | 369 | int len) |
375 | const struct in6_addr *saddr, | ||
376 | struct icmp6hdr *icmp6h, | ||
377 | const struct in6_addr *target, | ||
378 | int llinfo) | ||
379 | { | 370 | { |
380 | struct net *net = dev_net(dev); | ||
381 | struct sock *sk = net->ipv6.ndisc_sk; | ||
382 | struct sk_buff *skb; | ||
383 | struct icmp6hdr *hdr; | ||
384 | int hlen = LL_RESERVED_SPACE(dev); | 371 | int hlen = LL_RESERVED_SPACE(dev); |
385 | int tlen = dev->needed_tailroom; | 372 | int tlen = dev->needed_tailroom; |
386 | int len; | 373 | struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; |
374 | struct sk_buff *skb; | ||
387 | int err; | 375 | int err; |
388 | u8 *opt; | ||
389 | |||
390 | if (!dev->addr_len) | ||
391 | llinfo = 0; | ||
392 | |||
393 | len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); | ||
394 | if (llinfo) | ||
395 | len += ndisc_opt_addr_space(dev); | ||
396 | 376 | ||
397 | skb = sock_alloc_send_skb(sk, | 377 | skb = sock_alloc_send_skb(sk, |
398 | (MAX_HEADER + sizeof(struct ipv6hdr) + | 378 | hlen + sizeof(struct ipv6hdr) + len + tlen, |
399 | len + hlen + tlen), | ||
400 | 1, &err); | 379 | 1, &err); |
401 | if (!skb) { | 380 | if (!skb) { |
402 | ND_PRINTK(0, err, "ND: %s failed to allocate an skb, err=%d\n", | 381 | ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb, err=%d\n", |
403 | __func__, err); | 382 | __func__, err); |
404 | return NULL; | 383 | return NULL; |
405 | } | 384 | } |
406 | 385 | ||
407 | skb_reserve(skb, hlen); | 386 | skb->protocol = htons(ETH_P_IPV6); |
408 | ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); | 387 | skb->dev = dev; |
409 | 388 | ||
410 | skb->transport_header = skb->tail; | 389 | skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); |
411 | skb_put(skb, len); | 390 | skb_reset_transport_header(skb); |
412 | 391 | ||
413 | hdr = (struct icmp6hdr *)skb_transport_header(skb); | 392 | return skb; |
414 | memcpy(hdr, icmp6h, sizeof(*hdr)); | 393 | } |
415 | 394 | ||
416 | opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); | 395 | static void ip6_nd_hdr(struct sk_buff *skb, |
417 | if (target) { | 396 | const struct in6_addr *saddr, |
418 | *(struct in6_addr *)opt = *target; | 397 | const struct in6_addr *daddr, |
419 | opt += sizeof(*target); | 398 | int hop_limit, int len) |
420 | } | 399 | { |
400 | struct ipv6hdr *hdr; | ||
421 | 401 | ||
422 | if (llinfo) | 402 | skb_push(skb, sizeof(*hdr)); |
423 | ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, | 403 | skb_reset_network_header(skb); |
424 | dev->addr_len, dev->type); | 404 | hdr = ipv6_hdr(skb); |
425 | 405 | ||
426 | hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, | 406 | ip6_flow_hdr(hdr, 0, 0); |
427 | IPPROTO_ICMPV6, | ||
428 | csum_partial(hdr, | ||
429 | len, 0)); | ||
430 | 407 | ||
431 | return skb; | 408 | hdr->payload_len = htons(len); |
409 | hdr->nexthdr = IPPROTO_ICMPV6; | ||
410 | hdr->hop_limit = hop_limit; | ||
411 | |||
412 | hdr->saddr = *saddr; | ||
413 | hdr->daddr = *daddr; | ||
432 | } | 414 | } |
433 | 415 | ||
434 | static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, | 416 | static void ndisc_send_skb(struct sk_buff *skb, |
435 | struct neighbour *neigh, | ||
436 | const struct in6_addr *daddr, | 417 | const struct in6_addr *daddr, |
437 | const struct in6_addr *saddr, | 418 | const struct in6_addr *saddr) |
438 | struct icmp6hdr *icmp6h) | ||
439 | { | 419 | { |
440 | struct flowi6 fl6; | 420 | struct dst_entry *dst = skb_dst(skb); |
441 | struct dst_entry *dst; | 421 | struct net *net = dev_net(skb->dev); |
442 | struct net *net = dev_net(dev); | ||
443 | struct sock *sk = net->ipv6.ndisc_sk; | 422 | struct sock *sk = net->ipv6.ndisc_sk; |
444 | struct inet6_dev *idev; | 423 | struct inet6_dev *idev; |
445 | int err; | 424 | int err; |
425 | struct icmp6hdr *icmp6h = icmp6_hdr(skb); | ||
446 | u8 type; | 426 | u8 type; |
447 | 427 | ||
448 | type = icmp6h->icmp6_type; | 428 | type = icmp6h->icmp6_type; |
449 | 429 | ||
450 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); | 430 | if (!dst) { |
451 | dst = icmp6_dst_alloc(dev, neigh, &fl6); | 431 | struct sock *sk = net->ipv6.ndisc_sk; |
452 | if (IS_ERR(dst)) { | 432 | struct flowi6 fl6; |
453 | kfree_skb(skb); | 433 | |
454 | return; | 434 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex); |
435 | dst = icmp6_dst_alloc(skb->dev, &fl6); | ||
436 | if (IS_ERR(dst)) { | ||
437 | kfree_skb(skb); | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | skb_dst_set(skb, dst); | ||
455 | } | 442 | } |
456 | 443 | ||
457 | skb_dst_set(skb, dst); | 444 | icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, |
445 | IPPROTO_ICMPV6, | ||
446 | csum_partial(icmp6h, | ||
447 | skb->len, 0)); | ||
448 | |||
449 | ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); | ||
458 | 450 | ||
459 | rcu_read_lock(); | 451 | rcu_read_lock(); |
460 | idev = __in6_dev_get(dst->dev); | 452 | idev = __in6_dev_get(dst->dev); |
@@ -470,36 +462,17 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev, | |||
470 | rcu_read_unlock(); | 462 | rcu_read_unlock(); |
471 | } | 463 | } |
472 | 464 | ||
473 | /* | ||
474 | * Send a Neighbour Discover packet | ||
475 | */ | ||
476 | static void __ndisc_send(struct net_device *dev, | ||
477 | struct neighbour *neigh, | ||
478 | const struct in6_addr *daddr, | ||
479 | const struct in6_addr *saddr, | ||
480 | struct icmp6hdr *icmp6h, const struct in6_addr *target, | ||
481 | int llinfo) | ||
482 | { | ||
483 | struct sk_buff *skb; | ||
484 | |||
485 | skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); | ||
486 | if (!skb) | ||
487 | return; | ||
488 | |||
489 | ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); | ||
490 | } | ||
491 | |||
492 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 465 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
493 | const struct in6_addr *daddr, | 466 | const struct in6_addr *daddr, |
494 | const struct in6_addr *solicited_addr, | 467 | const struct in6_addr *solicited_addr, |
495 | int router, int solicited, int override, int inc_opt) | 468 | bool router, bool solicited, bool override, bool inc_opt) |
496 | { | 469 | { |
470 | struct sk_buff *skb; | ||
497 | struct in6_addr tmpaddr; | 471 | struct in6_addr tmpaddr; |
498 | struct inet6_ifaddr *ifp; | 472 | struct inet6_ifaddr *ifp; |
499 | const struct in6_addr *src_addr; | 473 | const struct in6_addr *src_addr; |
500 | struct icmp6hdr icmp6h = { | 474 | struct nd_msg *msg; |
501 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | 475 | int optlen = 0; |
502 | }; | ||
503 | 476 | ||
504 | /* for anycast or proxy, solicited_addr != src_addr */ | 477 | /* for anycast or proxy, solicited_addr != src_addr */ |
505 | ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); | 478 | ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); |
@@ -517,13 +490,32 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
517 | src_addr = &tmpaddr; | 490 | src_addr = &tmpaddr; |
518 | } | 491 | } |
519 | 492 | ||
520 | icmp6h.icmp6_router = router; | 493 | if (!dev->addr_len) |
521 | icmp6h.icmp6_solicited = solicited; | 494 | inc_opt = 0; |
522 | icmp6h.icmp6_override = override; | 495 | if (inc_opt) |
496 | optlen += ndisc_opt_addr_space(dev); | ||
497 | |||
498 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
499 | if (!skb) | ||
500 | return; | ||
523 | 501 | ||
524 | __ndisc_send(dev, neigh, daddr, src_addr, | 502 | msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); |
525 | &icmp6h, solicited_addr, | 503 | *msg = (struct nd_msg) { |
526 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 504 | .icmph = { |
505 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | ||
506 | .icmp6_router = router, | ||
507 | .icmp6_solicited = solicited, | ||
508 | .icmp6_override = override, | ||
509 | }, | ||
510 | .target = *solicited_addr, | ||
511 | }; | ||
512 | |||
513 | if (inc_opt) | ||
514 | ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, | ||
515 | dev->dev_addr); | ||
516 | |||
517 | |||
518 | ndisc_send_skb(skb, daddr, src_addr); | ||
527 | } | 519 | } |
528 | 520 | ||
529 | static void ndisc_send_unsol_na(struct net_device *dev) | 521 | static void ndisc_send_unsol_na(struct net_device *dev) |
@@ -551,10 +543,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
551 | const struct in6_addr *solicit, | 543 | const struct in6_addr *solicit, |
552 | const struct in6_addr *daddr, const struct in6_addr *saddr) | 544 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
553 | { | 545 | { |
546 | struct sk_buff *skb; | ||
554 | struct in6_addr addr_buf; | 547 | struct in6_addr addr_buf; |
555 | struct icmp6hdr icmp6h = { | 548 | int inc_opt = dev->addr_len; |
556 | .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, | 549 | int optlen = 0; |
557 | }; | 550 | struct nd_msg *msg; |
558 | 551 | ||
559 | if (saddr == NULL) { | 552 | if (saddr == NULL) { |
560 | if (ipv6_get_lladdr(dev, &addr_buf, | 553 | if (ipv6_get_lladdr(dev, &addr_buf, |
@@ -563,18 +556,37 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
563 | saddr = &addr_buf; | 556 | saddr = &addr_buf; |
564 | } | 557 | } |
565 | 558 | ||
566 | __ndisc_send(dev, neigh, daddr, saddr, | 559 | if (ipv6_addr_any(saddr)) |
567 | &icmp6h, solicit, | 560 | inc_opt = 0; |
568 | !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); | 561 | if (inc_opt) |
562 | optlen += ndisc_opt_addr_space(dev); | ||
563 | |||
564 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
565 | if (!skb) | ||
566 | return; | ||
567 | |||
568 | msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); | ||
569 | *msg = (struct nd_msg) { | ||
570 | .icmph = { | ||
571 | .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, | ||
572 | }, | ||
573 | .target = *solicit, | ||
574 | }; | ||
575 | |||
576 | if (inc_opt) | ||
577 | ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, | ||
578 | dev->dev_addr); | ||
579 | |||
580 | ndisc_send_skb(skb, daddr, saddr); | ||
569 | } | 581 | } |
570 | 582 | ||
571 | void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, | 583 | void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, |
572 | const struct in6_addr *daddr) | 584 | const struct in6_addr *daddr) |
573 | { | 585 | { |
574 | struct icmp6hdr icmp6h = { | 586 | struct sk_buff *skb; |
575 | .icmp6_type = NDISC_ROUTER_SOLICITATION, | 587 | struct rs_msg *msg; |
576 | }; | ||
577 | int send_sllao = dev->addr_len; | 588 | int send_sllao = dev->addr_len; |
589 | int optlen = 0; | ||
578 | 590 | ||
579 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 591 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
580 | /* | 592 | /* |
@@ -598,9 +610,27 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, | |||
598 | } | 610 | } |
599 | } | 611 | } |
600 | #endif | 612 | #endif |
601 | __ndisc_send(dev, NULL, daddr, saddr, | 613 | if (!dev->addr_len) |
602 | &icmp6h, NULL, | 614 | send_sllao = 0; |
603 | send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); | 615 | if (send_sllao) |
616 | optlen += ndisc_opt_addr_space(dev); | ||
617 | |||
618 | skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); | ||
619 | if (!skb) | ||
620 | return; | ||
621 | |||
622 | msg = (struct rs_msg *)skb_put(skb, sizeof(*msg)); | ||
623 | *msg = (struct rs_msg) { | ||
624 | .icmph = { | ||
625 | .icmp6_type = NDISC_ROUTER_SOLICITATION, | ||
626 | }, | ||
627 | }; | ||
628 | |||
629 | if (send_sllao) | ||
630 | ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, | ||
631 | dev->dev_addr); | ||
632 | |||
633 | ndisc_send_skb(skb, daddr, saddr); | ||
604 | } | 634 | } |
605 | 635 | ||
606 | 636 | ||
@@ -676,6 +706,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
676 | bool inc; | 706 | bool inc; |
677 | int is_router = -1; | 707 | int is_router = -1; |
678 | 708 | ||
709 | if (skb->len < sizeof(struct nd_msg)) { | ||
710 | ND_PRINTK(2, warn, "NS: packet too short\n"); | ||
711 | return; | ||
712 | } | ||
713 | |||
679 | if (ipv6_addr_is_multicast(&msg->target)) { | 714 | if (ipv6_addr_is_multicast(&msg->target)) { |
680 | ND_PRINTK(2, warn, "NS: multicast target address\n"); | 715 | ND_PRINTK(2, warn, "NS: multicast target address\n"); |
681 | return; | 716 | return; |
@@ -685,11 +720,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
685 | * RFC2461 7.1.1: | 720 | * RFC2461 7.1.1: |
686 | * DAD has to be destined for solicited node multicast address. | 721 | * DAD has to be destined for solicited node multicast address. |
687 | */ | 722 | */ |
688 | if (dad && | 723 | if (dad && !ipv6_addr_is_solict_mult(daddr)) { |
689 | !(daddr->s6_addr32[0] == htonl(0xff020000) && | ||
690 | daddr->s6_addr32[1] == htonl(0x00000000) && | ||
691 | daddr->s6_addr32[2] == htonl(0x00000001) && | ||
692 | daddr->s6_addr [12] == 0xff )) { | ||
693 | ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); | 724 | ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); |
694 | return; | 725 | return; |
695 | } | 726 | } |
@@ -780,11 +811,11 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
780 | } | 811 | } |
781 | 812 | ||
782 | if (is_router < 0) | 813 | if (is_router < 0) |
783 | is_router = !!idev->cnf.forwarding; | 814 | is_router = idev->cnf.forwarding; |
784 | 815 | ||
785 | if (dad) { | 816 | if (dad) { |
786 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, | 817 | ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, |
787 | is_router, 0, (ifp != NULL), 1); | 818 | !!is_router, false, (ifp != NULL), true); |
788 | goto out; | 819 | goto out; |
789 | } | 820 | } |
790 | 821 | ||
@@ -805,8 +836,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
805 | NEIGH_UPDATE_F_OVERRIDE); | 836 | NEIGH_UPDATE_F_OVERRIDE); |
806 | if (neigh || !dev->header_ops) { | 837 | if (neigh || !dev->header_ops) { |
807 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 838 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
808 | is_router, | 839 | !!is_router, |
809 | 1, (ifp != NULL && inc), inc); | 840 | true, (ifp != NULL && inc), inc); |
810 | if (neigh) | 841 | if (neigh) |
811 | neigh_release(neigh); | 842 | neigh_release(neigh); |
812 | } | 843 | } |
@@ -1350,25 +1381,34 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1350 | icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); | 1381 | icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); |
1351 | } | 1382 | } |
1352 | 1383 | ||
1384 | static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, | ||
1385 | struct sk_buff *orig_skb, | ||
1386 | int rd_len) | ||
1387 | { | ||
1388 | u8 *opt = skb_put(skb, rd_len); | ||
1389 | |||
1390 | memset(opt, 0, 8); | ||
1391 | *(opt++) = ND_OPT_REDIRECT_HDR; | ||
1392 | *(opt++) = (rd_len >> 3); | ||
1393 | opt += 6; | ||
1394 | |||
1395 | memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); | ||
1396 | } | ||
1397 | |||
1353 | void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | 1398 | void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) |
1354 | { | 1399 | { |
1355 | struct net_device *dev = skb->dev; | 1400 | struct net_device *dev = skb->dev; |
1356 | struct net *net = dev_net(dev); | 1401 | struct net *net = dev_net(dev); |
1357 | struct sock *sk = net->ipv6.ndisc_sk; | 1402 | struct sock *sk = net->ipv6.ndisc_sk; |
1358 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1403 | int optlen = 0; |
1359 | struct inet_peer *peer; | 1404 | struct inet_peer *peer; |
1360 | struct sk_buff *buff; | 1405 | struct sk_buff *buff; |
1361 | struct icmp6hdr *icmph; | 1406 | struct rd_msg *msg; |
1362 | struct in6_addr saddr_buf; | 1407 | struct in6_addr saddr_buf; |
1363 | struct in6_addr *addrp; | ||
1364 | struct rt6_info *rt; | 1408 | struct rt6_info *rt; |
1365 | struct dst_entry *dst; | 1409 | struct dst_entry *dst; |
1366 | struct inet6_dev *idev; | ||
1367 | struct flowi6 fl6; | 1410 | struct flowi6 fl6; |
1368 | u8 *opt; | ||
1369 | int hlen, tlen; | ||
1370 | int rd_len; | 1411 | int rd_len; |
1371 | int err; | ||
1372 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; | 1412 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; |
1373 | bool ret; | 1413 | bool ret; |
1374 | 1414 | ||
@@ -1424,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | |||
1424 | memcpy(ha_buf, neigh->ha, dev->addr_len); | 1464 | memcpy(ha_buf, neigh->ha, dev->addr_len); |
1425 | read_unlock_bh(&neigh->lock); | 1465 | read_unlock_bh(&neigh->lock); |
1426 | ha = ha_buf; | 1466 | ha = ha_buf; |
1427 | len += ndisc_opt_addr_space(dev); | 1467 | optlen += ndisc_opt_addr_space(dev); |
1428 | } else | 1468 | } else |
1429 | read_unlock_bh(&neigh->lock); | 1469 | read_unlock_bh(&neigh->lock); |
1430 | 1470 | ||
@@ -1432,80 +1472,40 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) | |||
1432 | } | 1472 | } |
1433 | 1473 | ||
1434 | rd_len = min_t(unsigned int, | 1474 | rd_len = min_t(unsigned int, |
1435 | IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); | 1475 | IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen, |
1476 | skb->len + 8); | ||
1436 | rd_len &= ~0x7; | 1477 | rd_len &= ~0x7; |
1437 | len += rd_len; | 1478 | optlen += rd_len; |
1438 | |||
1439 | hlen = LL_RESERVED_SPACE(dev); | ||
1440 | tlen = dev->needed_tailroom; | ||
1441 | buff = sock_alloc_send_skb(sk, | ||
1442 | (MAX_HEADER + sizeof(struct ipv6hdr) + | ||
1443 | len + hlen + tlen), | ||
1444 | 1, &err); | ||
1445 | if (buff == NULL) { | ||
1446 | ND_PRINTK(0, err, | ||
1447 | "Redirect: %s failed to allocate an skb, err=%d\n", | ||
1448 | __func__, err); | ||
1449 | goto release; | ||
1450 | } | ||
1451 | |||
1452 | skb_reserve(buff, hlen); | ||
1453 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, | ||
1454 | IPPROTO_ICMPV6, len); | ||
1455 | |||
1456 | skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); | ||
1457 | skb_put(buff, len); | ||
1458 | icmph = icmp6_hdr(buff); | ||
1459 | |||
1460 | memset(icmph, 0, sizeof(struct icmp6hdr)); | ||
1461 | icmph->icmp6_type = NDISC_REDIRECT; | ||
1462 | 1479 | ||
1463 | /* | 1480 | buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); |
1464 | * copy target and destination addresses | 1481 | if (!buff) |
1465 | */ | 1482 | goto release; |
1466 | |||
1467 | addrp = (struct in6_addr *)(icmph + 1); | ||
1468 | *addrp = *target; | ||
1469 | addrp++; | ||
1470 | *addrp = ipv6_hdr(skb)->daddr; | ||
1471 | 1483 | ||
1472 | opt = (u8*) (addrp + 1); | 1484 | msg = (struct rd_msg *)skb_put(buff, sizeof(*msg)); |
1485 | *msg = (struct rd_msg) { | ||
1486 | .icmph = { | ||
1487 | .icmp6_type = NDISC_REDIRECT, | ||
1488 | }, | ||
1489 | .target = *target, | ||
1490 | .dest = ipv6_hdr(skb)->daddr, | ||
1491 | }; | ||
1473 | 1492 | ||
1474 | /* | 1493 | /* |
1475 | * include target_address option | 1494 | * include target_address option |
1476 | */ | 1495 | */ |
1477 | 1496 | ||
1478 | if (ha) | 1497 | if (ha) |
1479 | opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, | 1498 | ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha); |
1480 | dev->addr_len, dev->type); | ||
1481 | 1499 | ||
1482 | /* | 1500 | /* |
1483 | * build redirect option and copy skb over to the new packet. | 1501 | * build redirect option and copy skb over to the new packet. |
1484 | */ | 1502 | */ |
1485 | 1503 | ||
1486 | memset(opt, 0, 8); | 1504 | if (rd_len) |
1487 | *(opt++) = ND_OPT_REDIRECT_HDR; | 1505 | ndisc_fill_redirect_hdr_option(buff, skb, rd_len); |
1488 | *(opt++) = (rd_len >> 3); | ||
1489 | opt += 6; | ||
1490 | |||
1491 | memcpy(opt, ipv6_hdr(skb), rd_len - 8); | ||
1492 | |||
1493 | icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, | ||
1494 | len, IPPROTO_ICMPV6, | ||
1495 | csum_partial(icmph, len, 0)); | ||
1496 | 1506 | ||
1497 | skb_dst_set(buff, dst); | 1507 | skb_dst_set(buff, dst); |
1498 | rcu_read_lock(); | 1508 | ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); |
1499 | idev = __in6_dev_get(dst->dev); | ||
1500 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | ||
1501 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, | ||
1502 | dst_output); | ||
1503 | if (!err) { | ||
1504 | ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT); | ||
1505 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | ||
1506 | } | ||
1507 | |||
1508 | rcu_read_unlock(); | ||
1509 | return; | 1509 | return; |
1510 | 1510 | ||
1511 | release: | 1511 | release: |
@@ -1522,7 +1522,7 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1522 | { | 1522 | { |
1523 | struct nd_msg *msg; | 1523 | struct nd_msg *msg; |
1524 | 1524 | ||
1525 | if (!pskb_may_pull(skb, skb->len)) | 1525 | if (skb_linearize(skb)) |
1526 | return 0; | 1526 | return 0; |
1527 | 1527 | ||
1528 | msg = (struct nd_msg *)skb_transport_header(skb); | 1528 | msg = (struct nd_msg *)skb_transport_header(skb); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 125a90d6a795..341b54ade72c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -1098,7 +1098,7 @@ static int get_info(struct net *net, void __user *user, | |||
1098 | #endif | 1098 | #endif |
1099 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), | 1099 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), |
1100 | "ip6table_%s", name); | 1100 | "ip6table_%s", name); |
1101 | if (t && !IS_ERR(t)) { | 1101 | if (!IS_ERR_OR_NULL(t)) { |
1102 | struct ip6t_getinfo info; | 1102 | struct ip6t_getinfo info; |
1103 | const struct xt_table_info *private = t->private; | 1103 | const struct xt_table_info *private = t->private; |
1104 | #ifdef CONFIG_COMPAT | 1104 | #ifdef CONFIG_COMPAT |
@@ -1157,7 +1157,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, | |||
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | t = xt_find_table_lock(net, AF_INET6, get.name); | 1159 | t = xt_find_table_lock(net, AF_INET6, get.name); |
1160 | if (t && !IS_ERR(t)) { | 1160 | if (!IS_ERR_OR_NULL(t)) { |
1161 | struct xt_table_info *private = t->private; | 1161 | struct xt_table_info *private = t->private; |
1162 | duprintf("t->private->number = %u\n", private->number); | 1162 | duprintf("t->private->number = %u\n", private->number); |
1163 | if (get.size == private->size) | 1163 | if (get.size == private->size) |
@@ -1197,7 +1197,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1197 | 1197 | ||
1198 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), | 1198 | t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name), |
1199 | "ip6table_%s", name); | 1199 | "ip6table_%s", name); |
1200 | if (!t || IS_ERR(t)) { | 1200 | if (IS_ERR_OR_NULL(t)) { |
1201 | ret = t ? PTR_ERR(t) : -ENOENT; | 1201 | ret = t ? PTR_ERR(t) : -ENOENT; |
1202 | goto free_newinfo_counters_untrans; | 1202 | goto free_newinfo_counters_untrans; |
1203 | } | 1203 | } |
@@ -1355,7 +1355,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | t = xt_find_table_lock(net, AF_INET6, name); | 1357 | t = xt_find_table_lock(net, AF_INET6, name); |
1358 | if (!t || IS_ERR(t)) { | 1358 | if (IS_ERR_OR_NULL(t)) { |
1359 | ret = t ? PTR_ERR(t) : -ENOENT; | 1359 | ret = t ? PTR_ERR(t) : -ENOENT; |
1360 | goto free; | 1360 | goto free; |
1361 | } | 1361 | } |
@@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, | |||
1939 | 1939 | ||
1940 | xt_compat_lock(AF_INET6); | 1940 | xt_compat_lock(AF_INET6); |
1941 | t = xt_find_table_lock(net, AF_INET6, get.name); | 1941 | t = xt_find_table_lock(net, AF_INET6, get.name); |
1942 | if (t && !IS_ERR(t)) { | 1942 | if (!IS_ERR_OR_NULL(t)) { |
1943 | const struct xt_table_info *private = t->private; | 1943 | const struct xt_table_info *private = t->private; |
1944 | struct xt_table_info info; | 1944 | struct xt_table_info info; |
1945 | duprintf("t->private->number = %u\n", private->number); | 1945 | duprintf("t->private->number = %u\n", private->number); |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 029623dbd411..ed3b427b2841 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -126,7 +126,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
126 | skb_put(nskb, sizeof(struct ipv6hdr)); | 126 | skb_put(nskb, sizeof(struct ipv6hdr)); |
127 | skb_reset_network_header(nskb); | 127 | skb_reset_network_header(nskb); |
128 | ip6h = ipv6_hdr(nskb); | 128 | ip6h = ipv6_hdr(nskb); |
129 | *(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20)); | 129 | ip6_flow_hdr(ip6h, tclass, 0); |
130 | ip6h->hop_limit = ip6_dst_hoplimit(dst); | 130 | ip6h->hop_limit = ip6_dst_hoplimit(dst); |
131 | ip6h->nexthdr = IPPROTO_TCP; | 131 | ip6h->nexthdr = IPPROTO_TCP; |
132 | ip6h->saddr = oip6h->daddr; | 132 | ip6h->saddr = oip6h->daddr; |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 7431121b87de..6134a1ebfb1b 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/netfilter_ipv6/ip6_tables.h> | 12 | #include <linux/netfilter_ipv6/ip6_tables.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <net/ipv6.h> | ||
14 | 15 | ||
15 | MODULE_LICENSE("GPL"); | 16 | MODULE_LICENSE("GPL"); |
16 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 17 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -60,8 +61,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
60 | dev_net(out)->ipv6.ip6table_mangle); | 61 | dev_net(out)->ipv6.ip6table_mangle); |
61 | 62 | ||
62 | if (ret != NF_DROP && ret != NF_STOLEN && | 63 | if (ret != NF_DROP && ret != NF_STOLEN && |
63 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | 64 | (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || |
64 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | 65 | !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) || |
65 | skb->mark != mark || | 66 | skb->mark != mark || |
66 | ipv6_hdr(skb)->hop_limit != hop_limit || | 67 | ipv6_hdr(skb)->hop_limit != hop_limit || |
67 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) | 68 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 137e245860ab..8a45bb20bedb 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -421,54 +421,43 @@ static int ipv6_net_init(struct net *net) | |||
421 | { | 421 | { |
422 | int ret = 0; | 422 | int ret = 0; |
423 | 423 | ||
424 | ret = nf_conntrack_l4proto_register(net, | 424 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6); |
425 | &nf_conntrack_l4proto_tcp6); | ||
426 | if (ret < 0) { | 425 | if (ret < 0) { |
427 | printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n"); | 426 | pr_err("nf_conntrack_tcp6: pernet registration failed\n"); |
428 | goto out; | 427 | goto out; |
429 | } | 428 | } |
430 | ret = nf_conntrack_l4proto_register(net, | 429 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6); |
431 | &nf_conntrack_l4proto_udp6); | ||
432 | if (ret < 0) { | 430 | if (ret < 0) { |
433 | printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n"); | 431 | pr_err("nf_conntrack_udp6: pernet registration failed\n"); |
434 | goto cleanup_tcp6; | 432 | goto cleanup_tcp6; |
435 | } | 433 | } |
436 | ret = nf_conntrack_l4proto_register(net, | 434 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6); |
437 | &nf_conntrack_l4proto_icmpv6); | ||
438 | if (ret < 0) { | 435 | if (ret < 0) { |
439 | printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n"); | 436 | pr_err("nf_conntrack_icmp6: pernet registration failed\n"); |
440 | goto cleanup_udp6; | 437 | goto cleanup_udp6; |
441 | } | 438 | } |
442 | ret = nf_conntrack_l3proto_register(net, | 439 | ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6); |
443 | &nf_conntrack_l3proto_ipv6); | ||
444 | if (ret < 0) { | 440 | if (ret < 0) { |
445 | printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n"); | 441 | pr_err("nf_conntrack_ipv6: pernet registration failed.\n"); |
446 | goto cleanup_icmpv6; | 442 | goto cleanup_icmpv6; |
447 | } | 443 | } |
448 | return 0; | 444 | return 0; |
449 | cleanup_icmpv6: | 445 | cleanup_icmpv6: |
450 | nf_conntrack_l4proto_unregister(net, | 446 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
451 | &nf_conntrack_l4proto_icmpv6); | ||
452 | cleanup_udp6: | 447 | cleanup_udp6: |
453 | nf_conntrack_l4proto_unregister(net, | 448 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
454 | &nf_conntrack_l4proto_udp6); | ||
455 | cleanup_tcp6: | 449 | cleanup_tcp6: |
456 | nf_conntrack_l4proto_unregister(net, | 450 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
457 | &nf_conntrack_l4proto_tcp6); | ||
458 | out: | 451 | out: |
459 | return ret; | 452 | return ret; |
460 | } | 453 | } |
461 | 454 | ||
462 | static void ipv6_net_exit(struct net *net) | 455 | static void ipv6_net_exit(struct net *net) |
463 | { | 456 | { |
464 | nf_conntrack_l3proto_unregister(net, | 457 | nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6); |
465 | &nf_conntrack_l3proto_ipv6); | 458 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
466 | nf_conntrack_l4proto_unregister(net, | 459 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
467 | &nf_conntrack_l4proto_icmpv6); | 460 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
468 | nf_conntrack_l4proto_unregister(net, | ||
469 | &nf_conntrack_l4proto_udp6); | ||
470 | nf_conntrack_l4proto_unregister(net, | ||
471 | &nf_conntrack_l4proto_tcp6); | ||
472 | } | 461 | } |
473 | 462 | ||
474 | static struct pernet_operations ipv6_net_ops = { | 463 | static struct pernet_operations ipv6_net_ops = { |
@@ -491,19 +480,52 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
491 | 480 | ||
492 | ret = register_pernet_subsys(&ipv6_net_ops); | 481 | ret = register_pernet_subsys(&ipv6_net_ops); |
493 | if (ret < 0) | 482 | if (ret < 0) |
494 | goto cleanup_pernet; | 483 | goto cleanup_sockopt; |
484 | |||
495 | ret = nf_register_hooks(ipv6_conntrack_ops, | 485 | ret = nf_register_hooks(ipv6_conntrack_ops, |
496 | ARRAY_SIZE(ipv6_conntrack_ops)); | 486 | ARRAY_SIZE(ipv6_conntrack_ops)); |
497 | if (ret < 0) { | 487 | if (ret < 0) { |
498 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " | 488 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " |
499 | "hook.\n"); | 489 | "hook.\n"); |
500 | goto cleanup_ipv6; | 490 | goto cleanup_pernet; |
491 | } | ||
492 | |||
493 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6); | ||
494 | if (ret < 0) { | ||
495 | pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n"); | ||
496 | goto cleanup_hooks; | ||
497 | } | ||
498 | |||
499 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6); | ||
500 | if (ret < 0) { | ||
501 | pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n"); | ||
502 | goto cleanup_tcp6; | ||
503 | } | ||
504 | |||
505 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6); | ||
506 | if (ret < 0) { | ||
507 | pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n"); | ||
508 | goto cleanup_udp6; | ||
509 | } | ||
510 | |||
511 | ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6); | ||
512 | if (ret < 0) { | ||
513 | pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n"); | ||
514 | goto cleanup_icmpv6; | ||
501 | } | 515 | } |
502 | return ret; | 516 | return ret; |
503 | 517 | ||
504 | cleanup_ipv6: | 518 | cleanup_icmpv6: |
505 | unregister_pernet_subsys(&ipv6_net_ops); | 519 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); |
520 | cleanup_udp6: | ||
521 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
522 | cleanup_tcp6: | ||
523 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
524 | cleanup_hooks: | ||
525 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | ||
506 | cleanup_pernet: | 526 | cleanup_pernet: |
527 | unregister_pernet_subsys(&ipv6_net_ops); | ||
528 | cleanup_sockopt: | ||
507 | nf_unregister_sockopt(&so_getorigdst6); | 529 | nf_unregister_sockopt(&so_getorigdst6); |
508 | return ret; | 530 | return ret; |
509 | } | 531 | } |
@@ -511,6 +533,10 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
511 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) | 533 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) |
512 | { | 534 | { |
513 | synchronize_net(); | 535 | synchronize_net(); |
536 | nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | ||
537 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
538 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
539 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); | ||
514 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | 540 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); |
515 | unregister_pernet_subsys(&ipv6_net_ops); | 541 | unregister_pernet_subsys(&ipv6_net_ops); |
516 | nf_unregister_sockopt(&so_getorigdst6); | 542 | nf_unregister_sockopt(&so_getorigdst6); |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 3dacecc99065..c674f158efa8 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -319,7 +319,7 @@ found: | |||
319 | fq->q.meat += skb->len; | 319 | fq->q.meat += skb->len; |
320 | if (payload_len > fq->q.max_size) | 320 | if (payload_len > fq->q.max_size) |
321 | fq->q.max_size = payload_len; | 321 | fq->q.max_size = payload_len; |
322 | atomic_add(skb->truesize, &fq->q.net->mem); | 322 | add_frag_mem_limit(&fq->q, skb->truesize); |
323 | 323 | ||
324 | /* The first fragment. | 324 | /* The first fragment. |
325 | * nhoffset is obtained from the first fragment, of course. | 325 | * nhoffset is obtained from the first fragment, of course. |
@@ -328,9 +328,8 @@ found: | |||
328 | fq->nhoffset = nhoff; | 328 | fq->nhoffset = nhoff; |
329 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 329 | fq->q.last_in |= INET_FRAG_FIRST_IN; |
330 | } | 330 | } |
331 | write_lock(&nf_frags.lock); | 331 | |
332 | list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list); | 332 | inet_frag_lru_move(&fq->q); |
333 | write_unlock(&nf_frags.lock); | ||
334 | return 0; | 333 | return 0; |
335 | 334 | ||
336 | discard_fq: | 335 | discard_fq: |
@@ -398,7 +397,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
398 | clone->ip_summed = head->ip_summed; | 397 | clone->ip_summed = head->ip_summed; |
399 | 398 | ||
400 | NFCT_FRAG6_CB(clone)->orig = NULL; | 399 | NFCT_FRAG6_CB(clone)->orig = NULL; |
401 | atomic_add(clone->truesize, &fq->q.net->mem); | 400 | add_frag_mem_limit(&fq->q, clone->truesize); |
402 | } | 401 | } |
403 | 402 | ||
404 | /* We have to remove fragment header from datagram and to relocate | 403 | /* We have to remove fragment header from datagram and to relocate |
@@ -422,7 +421,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev) | |||
422 | head->csum = csum_add(head->csum, fp->csum); | 421 | head->csum = csum_add(head->csum, fp->csum); |
423 | head->truesize += fp->truesize; | 422 | head->truesize += fp->truesize; |
424 | } | 423 | } |
425 | atomic_sub(head->truesize, &fq->q.net->mem); | 424 | sub_frag_mem_limit(&fq->q, head->truesize); |
426 | 425 | ||
427 | head->local_df = 1; | 426 | head->local_df = 1; |
428 | head->next = NULL; | 427 | head->next = NULL; |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index e5253ec9e0fc..bab2c270f292 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -327,7 +327,7 @@ found: | |||
327 | } | 327 | } |
328 | fq->q.stamp = skb->tstamp; | 328 | fq->q.stamp = skb->tstamp; |
329 | fq->q.meat += skb->len; | 329 | fq->q.meat += skb->len; |
330 | atomic_add(skb->truesize, &fq->q.net->mem); | 330 | add_frag_mem_limit(&fq->q, skb->truesize); |
331 | 331 | ||
332 | /* The first fragment. | 332 | /* The first fragment. |
333 | * nhoffset is obtained from the first fragment, of course. | 333 | * nhoffset is obtained from the first fragment, of course. |
@@ -341,9 +341,7 @@ found: | |||
341 | fq->q.meat == fq->q.len) | 341 | fq->q.meat == fq->q.len) |
342 | return ip6_frag_reasm(fq, prev, dev); | 342 | return ip6_frag_reasm(fq, prev, dev); |
343 | 343 | ||
344 | write_lock(&ip6_frags.lock); | 344 | inet_frag_lru_move(&fq->q); |
345 | list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list); | ||
346 | write_unlock(&ip6_frags.lock); | ||
347 | return -1; | 345 | return -1; |
348 | 346 | ||
349 | discard_fq: | 347 | discard_fq: |
@@ -429,7 +427,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
429 | head->len -= clone->len; | 427 | head->len -= clone->len; |
430 | clone->csum = 0; | 428 | clone->csum = 0; |
431 | clone->ip_summed = head->ip_summed; | 429 | clone->ip_summed = head->ip_summed; |
432 | atomic_add(clone->truesize, &fq->q.net->mem); | 430 | add_frag_mem_limit(&fq->q, clone->truesize); |
433 | } | 431 | } |
434 | 432 | ||
435 | /* We have to remove fragment header from datagram and to relocate | 433 | /* We have to remove fragment header from datagram and to relocate |
@@ -467,7 +465,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
467 | } | 465 | } |
468 | fp = next; | 466 | fp = next; |
469 | } | 467 | } |
470 | atomic_sub(sum_truesize, &fq->q.net->mem); | 468 | sub_frag_mem_limit(&fq->q, sum_truesize); |
471 | 469 | ||
472 | head->next = NULL; | 470 | head->next = NULL; |
473 | head->dev = dev; | 471 | head->dev = dev; |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 363d8b7772e8..f3328bc1174f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -145,25 +145,12 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, | |||
145 | struct neighbour *n; | 145 | struct neighbour *n; |
146 | 146 | ||
147 | daddr = choose_neigh_daddr(rt, skb, daddr); | 147 | daddr = choose_neigh_daddr(rt, skb, daddr); |
148 | n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr); | 148 | n = __ipv6_neigh_lookup(dst->dev, daddr); |
149 | if (n) | 149 | if (n) |
150 | return n; | 150 | return n; |
151 | return neigh_create(&nd_tbl, daddr, dst->dev); | 151 | return neigh_create(&nd_tbl, daddr, dst->dev); |
152 | } | 152 | } |
153 | 153 | ||
154 | static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev) | ||
155 | { | ||
156 | struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway); | ||
157 | if (!n) { | ||
158 | n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev); | ||
159 | if (IS_ERR(n)) | ||
160 | return PTR_ERR(n); | ||
161 | } | ||
162 | rt->n = n; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct dst_ops ip6_dst_ops_template = { | 154 | static struct dst_ops ip6_dst_ops_template = { |
168 | .family = AF_INET6, | 155 | .family = AF_INET6, |
169 | .protocol = cpu_to_be16(ETH_P_IPV6), | 156 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -301,9 +288,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
301 | struct rt6_info *rt = (struct rt6_info *)dst; | 288 | struct rt6_info *rt = (struct rt6_info *)dst; |
302 | struct inet6_dev *idev = rt->rt6i_idev; | 289 | struct inet6_dev *idev = rt->rt6i_idev; |
303 | 290 | ||
304 | if (rt->n) | ||
305 | neigh_release(rt->n); | ||
306 | |||
307 | if (!(rt->dst.flags & DST_HOST)) | 291 | if (!(rt->dst.flags & DST_HOST)) |
308 | dst_destroy_metrics_generic(dst); | 292 | dst_destroy_metrics_generic(dst); |
309 | 293 | ||
@@ -354,11 +338,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
354 | in6_dev_put(idev); | 338 | in6_dev_put(idev); |
355 | } | 339 | } |
356 | } | 340 | } |
357 | if (rt->n && rt->n->dev == dev) { | ||
358 | rt->n->dev = loopback_dev; | ||
359 | dev_hold(loopback_dev); | ||
360 | dev_put(dev); | ||
361 | } | ||
362 | } | 341 | } |
363 | } | 342 | } |
364 | 343 | ||
@@ -388,15 +367,8 @@ static int rt6_info_hash_nhsfn(unsigned int candidate_count, | |||
388 | { | 367 | { |
389 | unsigned int val = fl6->flowi6_proto; | 368 | unsigned int val = fl6->flowi6_proto; |
390 | 369 | ||
391 | val ^= (__force u32)fl6->daddr.s6_addr32[0]; | 370 | val ^= ipv6_addr_hash(&fl6->daddr); |
392 | val ^= (__force u32)fl6->daddr.s6_addr32[1]; | 371 | val ^= ipv6_addr_hash(&fl6->saddr); |
393 | val ^= (__force u32)fl6->daddr.s6_addr32[2]; | ||
394 | val ^= (__force u32)fl6->daddr.s6_addr32[3]; | ||
395 | |||
396 | val ^= (__force u32)fl6->saddr.s6_addr32[0]; | ||
397 | val ^= (__force u32)fl6->saddr.s6_addr32[1]; | ||
398 | val ^= (__force u32)fl6->saddr.s6_addr32[2]; | ||
399 | val ^= (__force u32)fl6->saddr.s6_addr32[3]; | ||
400 | 372 | ||
401 | /* Work only if this not encapsulated */ | 373 | /* Work only if this not encapsulated */ |
402 | switch (fl6->flowi6_proto) { | 374 | switch (fl6->flowi6_proto) { |
@@ -505,24 +477,34 @@ static void rt6_probe(struct rt6_info *rt) | |||
505 | * Router Reachability Probe MUST be rate-limited | 477 | * Router Reachability Probe MUST be rate-limited |
506 | * to no more than one per minute. | 478 | * to no more than one per minute. |
507 | */ | 479 | */ |
508 | neigh = rt ? rt->n : NULL; | 480 | if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) |
509 | if (!neigh || (neigh->nud_state & NUD_VALID)) | ||
510 | return; | 481 | return; |
511 | read_lock_bh(&neigh->lock); | 482 | rcu_read_lock_bh(); |
512 | if (!(neigh->nud_state & NUD_VALID) && | 483 | neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); |
484 | if (neigh) { | ||
485 | write_lock(&neigh->lock); | ||
486 | if (neigh->nud_state & NUD_VALID) | ||
487 | goto out; | ||
488 | } | ||
489 | |||
490 | if (!neigh || | ||
513 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 491 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
514 | struct in6_addr mcaddr; | 492 | struct in6_addr mcaddr; |
515 | struct in6_addr *target; | 493 | struct in6_addr *target; |
516 | 494 | ||
517 | neigh->updated = jiffies; | 495 | if (neigh) { |
518 | read_unlock_bh(&neigh->lock); | 496 | neigh->updated = jiffies; |
497 | write_unlock(&neigh->lock); | ||
498 | } | ||
519 | 499 | ||
520 | target = (struct in6_addr *)&neigh->primary_key; | 500 | target = (struct in6_addr *)&rt->rt6i_gateway; |
521 | addrconf_addr_solict_mult(target, &mcaddr); | 501 | addrconf_addr_solict_mult(target, &mcaddr); |
522 | ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL); | 502 | ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL); |
523 | } else { | 503 | } else { |
524 | read_unlock_bh(&neigh->lock); | 504 | out: |
505 | write_unlock(&neigh->lock); | ||
525 | } | 506 | } |
507 | rcu_read_unlock_bh(); | ||
526 | } | 508 | } |
527 | #else | 509 | #else |
528 | static inline void rt6_probe(struct rt6_info *rt) | 510 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -549,20 +531,24 @@ static inline bool rt6_check_neigh(struct rt6_info *rt) | |||
549 | struct neighbour *neigh; | 531 | struct neighbour *neigh; |
550 | bool ret = false; | 532 | bool ret = false; |
551 | 533 | ||
552 | neigh = rt->n; | ||
553 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 534 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
554 | !(rt->rt6i_flags & RTF_GATEWAY)) | 535 | !(rt->rt6i_flags & RTF_GATEWAY)) |
555 | ret = true; | 536 | return true; |
556 | else if (neigh) { | 537 | |
557 | read_lock_bh(&neigh->lock); | 538 | rcu_read_lock_bh(); |
539 | neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); | ||
540 | if (neigh) { | ||
541 | read_lock(&neigh->lock); | ||
558 | if (neigh->nud_state & NUD_VALID) | 542 | if (neigh->nud_state & NUD_VALID) |
559 | ret = true; | 543 | ret = true; |
560 | #ifdef CONFIG_IPV6_ROUTER_PREF | 544 | #ifdef CONFIG_IPV6_ROUTER_PREF |
561 | else if (!(neigh->nud_state & NUD_FAILED)) | 545 | else if (!(neigh->nud_state & NUD_FAILED)) |
562 | ret = true; | 546 | ret = true; |
563 | #endif | 547 | #endif |
564 | read_unlock_bh(&neigh->lock); | 548 | read_unlock(&neigh->lock); |
565 | } | 549 | } |
550 | rcu_read_unlock_bh(); | ||
551 | |||
566 | return ret; | 552 | return ret; |
567 | } | 553 | } |
568 | 554 | ||
@@ -838,8 +824,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
838 | rt = ip6_rt_copy(ort, daddr); | 824 | rt = ip6_rt_copy(ort, daddr); |
839 | 825 | ||
840 | if (rt) { | 826 | if (rt) { |
841 | int attempts = !in_softirq(); | ||
842 | |||
843 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { | 827 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { |
844 | if (ort->rt6i_dst.plen != 128 && | 828 | if (ort->rt6i_dst.plen != 128 && |
845 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) | 829 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
@@ -855,32 +839,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
855 | rt->rt6i_src.plen = 128; | 839 | rt->rt6i_src.plen = 128; |
856 | } | 840 | } |
857 | #endif | 841 | #endif |
858 | |||
859 | retry: | ||
860 | if (rt6_bind_neighbour(rt, rt->dst.dev)) { | ||
861 | struct net *net = dev_net(rt->dst.dev); | ||
862 | int saved_rt_min_interval = | ||
863 | net->ipv6.sysctl.ip6_rt_gc_min_interval; | ||
864 | int saved_rt_elasticity = | ||
865 | net->ipv6.sysctl.ip6_rt_gc_elasticity; | ||
866 | |||
867 | if (attempts-- > 0) { | ||
868 | net->ipv6.sysctl.ip6_rt_gc_elasticity = 1; | ||
869 | net->ipv6.sysctl.ip6_rt_gc_min_interval = 0; | ||
870 | |||
871 | ip6_dst_gc(&net->ipv6.ip6_dst_ops); | ||
872 | |||
873 | net->ipv6.sysctl.ip6_rt_gc_elasticity = | ||
874 | saved_rt_elasticity; | ||
875 | net->ipv6.sysctl.ip6_rt_gc_min_interval = | ||
876 | saved_rt_min_interval; | ||
877 | goto retry; | ||
878 | } | ||
879 | |||
880 | net_warn_ratelimited("Neighbour table overflow\n"); | ||
881 | dst_free(&rt->dst); | ||
882 | return NULL; | ||
883 | } | ||
884 | } | 842 | } |
885 | 843 | ||
886 | return rt; | 844 | return rt; |
@@ -891,10 +849,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, | |||
891 | { | 849 | { |
892 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); | 850 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); |
893 | 851 | ||
894 | if (rt) { | 852 | if (rt) |
895 | rt->rt6i_flags |= RTF_CACHE; | 853 | rt->rt6i_flags |= RTF_CACHE; |
896 | rt->n = neigh_clone(ort->n); | ||
897 | } | ||
898 | return rt; | 854 | return rt; |
899 | } | 855 | } |
900 | 856 | ||
@@ -928,7 +884,7 @@ restart: | |||
928 | dst_hold(&rt->dst); | 884 | dst_hold(&rt->dst); |
929 | read_unlock_bh(&table->tb6_lock); | 885 | read_unlock_bh(&table->tb6_lock); |
930 | 886 | ||
931 | if (!rt->n && !(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_LOCAL))) | 887 | if (!(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY))) |
932 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 888 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
933 | else if (!(rt->dst.flags & DST_HOST)) | 889 | else if (!(rt->dst.flags & DST_HOST)) |
934 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 890 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
@@ -994,7 +950,7 @@ void ip6_route_input(struct sk_buff *skb) | |||
994 | .flowi6_iif = skb->dev->ifindex, | 950 | .flowi6_iif = skb->dev->ifindex, |
995 | .daddr = iph->daddr, | 951 | .daddr = iph->daddr, |
996 | .saddr = iph->saddr, | 952 | .saddr = iph->saddr, |
997 | .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK, | 953 | .flowlabel = ip6_flowinfo(iph), |
998 | .flowi6_mark = skb->mark, | 954 | .flowi6_mark = skb->mark, |
999 | .flowi6_proto = iph->nexthdr, | 955 | .flowi6_proto = iph->nexthdr, |
1000 | }; | 956 | }; |
@@ -1159,7 +1115,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, | |||
1159 | fl6.flowi6_flags = 0; | 1115 | fl6.flowi6_flags = 0; |
1160 | fl6.daddr = iph->daddr; | 1116 | fl6.daddr = iph->daddr; |
1161 | fl6.saddr = iph->saddr; | 1117 | fl6.saddr = iph->saddr; |
1162 | fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK; | 1118 | fl6.flowlabel = ip6_flowinfo(iph); |
1163 | 1119 | ||
1164 | dst = ip6_route_output(net, NULL, &fl6); | 1120 | dst = ip6_route_output(net, NULL, &fl6); |
1165 | if (!dst->error) | 1121 | if (!dst->error) |
@@ -1187,7 +1143,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) | |||
1187 | fl6.flowi6_flags = 0; | 1143 | fl6.flowi6_flags = 0; |
1188 | fl6.daddr = iph->daddr; | 1144 | fl6.daddr = iph->daddr; |
1189 | fl6.saddr = iph->saddr; | 1145 | fl6.saddr = iph->saddr; |
1190 | fl6.flowlabel = (*(__be32 *) iph) & IPV6_FLOWINFO_MASK; | 1146 | fl6.flowlabel = ip6_flowinfo(iph); |
1191 | 1147 | ||
1192 | dst = ip6_route_output(net, NULL, &fl6); | 1148 | dst = ip6_route_output(net, NULL, &fl6); |
1193 | if (!dst->error) | 1149 | if (!dst->error) |
@@ -1247,7 +1203,6 @@ static struct dst_entry *icmp6_dst_gc_list; | |||
1247 | static DEFINE_SPINLOCK(icmp6_dst_lock); | 1203 | static DEFINE_SPINLOCK(icmp6_dst_lock); |
1248 | 1204 | ||
1249 | struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | 1205 | struct dst_entry *icmp6_dst_alloc(struct net_device *dev, |
1250 | struct neighbour *neigh, | ||
1251 | struct flowi6 *fl6) | 1206 | struct flowi6 *fl6) |
1252 | { | 1207 | { |
1253 | struct dst_entry *dst; | 1208 | struct dst_entry *dst; |
@@ -1265,20 +1220,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1265 | goto out; | 1220 | goto out; |
1266 | } | 1221 | } |
1267 | 1222 | ||
1268 | if (neigh) | ||
1269 | neigh_hold(neigh); | ||
1270 | else { | ||
1271 | neigh = ip6_neigh_lookup(&rt->dst, NULL, &fl6->daddr); | ||
1272 | if (IS_ERR(neigh)) { | ||
1273 | in6_dev_put(idev); | ||
1274 | dst_free(&rt->dst); | ||
1275 | return ERR_CAST(neigh); | ||
1276 | } | ||
1277 | } | ||
1278 | |||
1279 | rt->dst.flags |= DST_HOST; | 1223 | rt->dst.flags |= DST_HOST; |
1280 | rt->dst.output = ip6_output; | 1224 | rt->dst.output = ip6_output; |
1281 | rt->n = neigh; | ||
1282 | atomic_set(&rt->dst.__refcnt, 1); | 1225 | atomic_set(&rt->dst.__refcnt, 1); |
1283 | rt->rt6i_dst.addr = fl6->daddr; | 1226 | rt->rt6i_dst.addr = fl6->daddr; |
1284 | rt->rt6i_dst.plen = 128; | 1227 | rt->rt6i_dst.plen = 128; |
@@ -1587,12 +1530,6 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1587 | } else | 1530 | } else |
1588 | rt->rt6i_prefsrc.plen = 0; | 1531 | rt->rt6i_prefsrc.plen = 0; |
1589 | 1532 | ||
1590 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | ||
1591 | err = rt6_bind_neighbour(rt, dev); | ||
1592 | if (err) | ||
1593 | goto out; | ||
1594 | } | ||
1595 | |||
1596 | rt->rt6i_flags = cfg->fc_flags; | 1533 | rt->rt6i_flags = cfg->fc_flags; |
1597 | 1534 | ||
1598 | install_route: | 1535 | install_route: |
@@ -1705,37 +1642,32 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1705 | struct net *net = dev_net(skb->dev); | 1642 | struct net *net = dev_net(skb->dev); |
1706 | struct netevent_redirect netevent; | 1643 | struct netevent_redirect netevent; |
1707 | struct rt6_info *rt, *nrt = NULL; | 1644 | struct rt6_info *rt, *nrt = NULL; |
1708 | const struct in6_addr *target; | ||
1709 | struct ndisc_options ndopts; | 1645 | struct ndisc_options ndopts; |
1710 | const struct in6_addr *dest; | ||
1711 | struct neighbour *old_neigh; | ||
1712 | struct inet6_dev *in6_dev; | 1646 | struct inet6_dev *in6_dev; |
1713 | struct neighbour *neigh; | 1647 | struct neighbour *neigh; |
1714 | struct icmp6hdr *icmph; | 1648 | struct rd_msg *msg; |
1715 | int optlen, on_link; | 1649 | int optlen, on_link; |
1716 | u8 *lladdr; | 1650 | u8 *lladdr; |
1717 | 1651 | ||
1718 | optlen = skb->tail - skb->transport_header; | 1652 | optlen = skb->tail - skb->transport_header; |
1719 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1653 | optlen -= sizeof(*msg); |
1720 | 1654 | ||
1721 | if (optlen < 0) { | 1655 | if (optlen < 0) { |
1722 | net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); | 1656 | net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); |
1723 | return; | 1657 | return; |
1724 | } | 1658 | } |
1725 | 1659 | ||
1726 | icmph = icmp6_hdr(skb); | 1660 | msg = (struct rd_msg *)icmp6_hdr(skb); |
1727 | target = (const struct in6_addr *) (icmph + 1); | ||
1728 | dest = target + 1; | ||
1729 | 1661 | ||
1730 | if (ipv6_addr_is_multicast(dest)) { | 1662 | if (ipv6_addr_is_multicast(&msg->dest)) { |
1731 | net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); | 1663 | net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); |
1732 | return; | 1664 | return; |
1733 | } | 1665 | } |
1734 | 1666 | ||
1735 | on_link = 0; | 1667 | on_link = 0; |
1736 | if (ipv6_addr_equal(dest, target)) { | 1668 | if (ipv6_addr_equal(&msg->dest, &msg->target)) { |
1737 | on_link = 1; | 1669 | on_link = 1; |
1738 | } else if (ipv6_addr_type(target) != | 1670 | } else if (ipv6_addr_type(&msg->target) != |
1739 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { | 1671 | (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { |
1740 | net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); | 1672 | net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); |
1741 | return; | 1673 | return; |
@@ -1752,7 +1684,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1752 | * first-hop router for the specified ICMP Destination Address. | 1684 | * first-hop router for the specified ICMP Destination Address. |
1753 | */ | 1685 | */ |
1754 | 1686 | ||
1755 | if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { | 1687 | if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) { |
1756 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); | 1688 | net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); |
1757 | return; | 1689 | return; |
1758 | } | 1690 | } |
@@ -1779,15 +1711,10 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1779 | */ | 1711 | */ |
1780 | dst_confirm(&rt->dst); | 1712 | dst_confirm(&rt->dst); |
1781 | 1713 | ||
1782 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1714 | neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); |
1783 | if (!neigh) | 1715 | if (!neigh) |
1784 | return; | 1716 | return; |
1785 | 1717 | ||
1786 | /* Duplicate redirect: silently ignore. */ | ||
1787 | old_neigh = rt->n; | ||
1788 | if (neigh == old_neigh) | ||
1789 | goto out; | ||
1790 | |||
1791 | /* | 1718 | /* |
1792 | * We have finally decided to accept it. | 1719 | * We have finally decided to accept it. |
1793 | */ | 1720 | */ |
@@ -1799,7 +1726,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1799 | NEIGH_UPDATE_F_ISROUTER)) | 1726 | NEIGH_UPDATE_F_ISROUTER)) |
1800 | ); | 1727 | ); |
1801 | 1728 | ||
1802 | nrt = ip6_rt_copy(rt, dest); | 1729 | nrt = ip6_rt_copy(rt, &msg->dest); |
1803 | if (!nrt) | 1730 | if (!nrt) |
1804 | goto out; | 1731 | goto out; |
1805 | 1732 | ||
@@ -1808,16 +1735,14 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1808 | nrt->rt6i_flags &= ~RTF_GATEWAY; | 1735 | nrt->rt6i_flags &= ~RTF_GATEWAY; |
1809 | 1736 | ||
1810 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; | 1737 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; |
1811 | nrt->n = neigh_clone(neigh); | ||
1812 | 1738 | ||
1813 | if (ip6_ins_rt(nrt)) | 1739 | if (ip6_ins_rt(nrt)) |
1814 | goto out; | 1740 | goto out; |
1815 | 1741 | ||
1816 | netevent.old = &rt->dst; | 1742 | netevent.old = &rt->dst; |
1817 | netevent.old_neigh = old_neigh; | ||
1818 | netevent.new = &nrt->dst; | 1743 | netevent.new = &nrt->dst; |
1819 | netevent.new_neigh = neigh; | 1744 | netevent.daddr = &msg->dest; |
1820 | netevent.daddr = dest; | 1745 | netevent.neigh = neigh; |
1821 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1746 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
1822 | 1747 | ||
1823 | if (rt->rt6i_flags & RTF_CACHE) { | 1748 | if (rt->rt6i_flags & RTF_CACHE) { |
@@ -2123,7 +2048,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2123 | { | 2048 | { |
2124 | struct net *net = dev_net(idev->dev); | 2049 | struct net *net = dev_net(idev->dev); |
2125 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); | 2050 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); |
2126 | int err; | ||
2127 | 2051 | ||
2128 | if (!rt) { | 2052 | if (!rt) { |
2129 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); | 2053 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); |
@@ -2142,11 +2066,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2142 | rt->rt6i_flags |= RTF_ANYCAST; | 2066 | rt->rt6i_flags |= RTF_ANYCAST; |
2143 | else | 2067 | else |
2144 | rt->rt6i_flags |= RTF_LOCAL; | 2068 | rt->rt6i_flags |= RTF_LOCAL; |
2145 | err = rt6_bind_neighbour(rt, rt->dst.dev); | ||
2146 | if (err) { | ||
2147 | dst_free(&rt->dst); | ||
2148 | return ERR_PTR(err); | ||
2149 | } | ||
2150 | 2069 | ||
2151 | rt->rt6i_dst.addr = *addr; | 2070 | rt->rt6i_dst.addr = *addr; |
2152 | rt->rt6i_dst.plen = 128; | 2071 | rt->rt6i_dst.plen = 128; |
@@ -2492,7 +2411,6 @@ static int rt6_fill_node(struct net *net, | |||
2492 | struct nlmsghdr *nlh; | 2411 | struct nlmsghdr *nlh; |
2493 | long expires; | 2412 | long expires; |
2494 | u32 table; | 2413 | u32 table; |
2495 | struct neighbour *n; | ||
2496 | 2414 | ||
2497 | if (prefix) { /* user wants prefix routes only */ | 2415 | if (prefix) { /* user wants prefix routes only */ |
2498 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 2416 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -2605,9 +2523,8 @@ static int rt6_fill_node(struct net *net, | |||
2605 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2523 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2606 | goto nla_put_failure; | 2524 | goto nla_put_failure; |
2607 | 2525 | ||
2608 | n = rt->n; | 2526 | if (rt->rt6i_flags & RTF_GATEWAY) { |
2609 | if (n) { | 2527 | if (nla_put(skb, RTA_GATEWAY, 16, &rt->rt6i_gateway) < 0) |
2610 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) | ||
2611 | goto nla_put_failure; | 2528 | goto nla_put_failure; |
2612 | } | 2529 | } |
2613 | 2530 | ||
@@ -2802,7 +2719,6 @@ struct rt6_proc_arg | |||
2802 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) | 2719 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) |
2803 | { | 2720 | { |
2804 | struct seq_file *m = p_arg; | 2721 | struct seq_file *m = p_arg; |
2805 | struct neighbour *n; | ||
2806 | 2722 | ||
2807 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | 2723 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); |
2808 | 2724 | ||
@@ -2811,9 +2727,8 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2811 | #else | 2727 | #else |
2812 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2728 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2813 | #endif | 2729 | #endif |
2814 | n = rt->n; | 2730 | if (rt->rt6i_flags & RTF_GATEWAY) { |
2815 | if (n) { | 2731 | seq_printf(m, "%pi6", &rt->rt6i_gateway); |
2816 | seq_printf(m, "%pi6", n->primary_key); | ||
2817 | } else { | 2732 | } else { |
2818 | seq_puts(m, "00000000000000000000000000000000"); | 2733 | seq_puts(m, "00000000000000000000000000000000"); |
2819 | } | 2734 | } |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cfba99b2c2a4..02f96dcbcf02 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); | |||
72 | static int ipip6_tunnel_init(struct net_device *dev); | 72 | static int ipip6_tunnel_init(struct net_device *dev); |
73 | static void ipip6_tunnel_setup(struct net_device *dev); | 73 | static void ipip6_tunnel_setup(struct net_device *dev); |
74 | static void ipip6_dev_free(struct net_device *dev); | 74 | static void ipip6_dev_free(struct net_device *dev); |
75 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, | ||
76 | __be32 *v4dst); | ||
75 | static struct rtnl_link_ops sit_link_ops __read_mostly; | 77 | static struct rtnl_link_ops sit_link_ops __read_mostly; |
76 | 78 | ||
77 | static int sit_net_id __read_mostly; | 79 | static int sit_net_id __read_mostly; |
@@ -590,17 +592,21 @@ out: | |||
590 | return err; | 592 | return err; |
591 | } | 593 | } |
592 | 594 | ||
595 | static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr, | ||
596 | const struct in6_addr *v6addr) | ||
597 | { | ||
598 | __be32 v4embed = 0; | ||
599 | if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed) | ||
600 | return true; | ||
601 | return false; | ||
602 | } | ||
603 | |||
593 | static int ipip6_rcv(struct sk_buff *skb) | 604 | static int ipip6_rcv(struct sk_buff *skb) |
594 | { | 605 | { |
595 | const struct iphdr *iph; | 606 | const struct iphdr *iph = ip_hdr(skb); |
596 | struct ip_tunnel *tunnel; | 607 | struct ip_tunnel *tunnel; |
597 | int err; | 608 | int err; |
598 | 609 | ||
599 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
600 | goto out; | ||
601 | |||
602 | iph = ip_hdr(skb); | ||
603 | |||
604 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 610 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
605 | iph->saddr, iph->daddr); | 611 | iph->saddr, iph->daddr); |
606 | if (tunnel != NULL) { | 612 | if (tunnel != NULL) { |
@@ -613,10 +619,19 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
613 | skb->protocol = htons(ETH_P_IPV6); | 619 | skb->protocol = htons(ETH_P_IPV6); |
614 | skb->pkt_type = PACKET_HOST; | 620 | skb->pkt_type = PACKET_HOST; |
615 | 621 | ||
616 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 622 | if (tunnel->dev->priv_flags & IFF_ISATAP) { |
617 | !isatap_chksrc(skb, iph, tunnel)) { | 623 | if (!isatap_chksrc(skb, iph, tunnel)) { |
618 | tunnel->dev->stats.rx_errors++; | 624 | tunnel->dev->stats.rx_errors++; |
619 | goto out; | 625 | goto out; |
626 | } | ||
627 | } else { | ||
628 | if (is_spoofed_6rd(tunnel, iph->saddr, | ||
629 | &ipv6_hdr(skb)->saddr) || | ||
630 | is_spoofed_6rd(tunnel, iph->daddr, | ||
631 | &ipv6_hdr(skb)->daddr)) { | ||
632 | tunnel->dev->stats.rx_errors++; | ||
633 | goto out; | ||
634 | } | ||
620 | } | 635 | } |
621 | 636 | ||
622 | __skb_tunnel_rx(skb, tunnel->dev); | 637 | __skb_tunnel_rx(skb, tunnel->dev); |
@@ -650,14 +665,12 @@ out: | |||
650 | } | 665 | } |
651 | 666 | ||
652 | /* | 667 | /* |
653 | * Returns the embedded IPv4 address if the IPv6 address | 668 | * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function |
654 | * comes from 6rd / 6to4 (RFC 3056) addr space. | 669 | * stores the embedded IPv4 address in v4dst and returns true. |
655 | */ | 670 | */ |
656 | static inline | 671 | static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, |
657 | __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | 672 | __be32 *v4dst) |
658 | { | 673 | { |
659 | __be32 dst = 0; | ||
660 | |||
661 | #ifdef CONFIG_IPV6_SIT_6RD | 674 | #ifdef CONFIG_IPV6_SIT_6RD |
662 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 675 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
663 | tunnel->ip6rd.prefixlen)) { | 676 | tunnel->ip6rd.prefixlen)) { |
@@ -676,14 +689,24 @@ __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) | |||
676 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> | 689 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> |
677 | (32 - pbi1); | 690 | (32 - pbi1); |
678 | 691 | ||
679 | dst = tunnel->ip6rd.relay_prefix | htonl(d); | 692 | *v4dst = tunnel->ip6rd.relay_prefix | htonl(d); |
693 | return true; | ||
680 | } | 694 | } |
681 | #else | 695 | #else |
682 | if (v6dst->s6_addr16[0] == htons(0x2002)) { | 696 | if (v6dst->s6_addr16[0] == htons(0x2002)) { |
683 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ | 697 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ |
684 | memcpy(&dst, &v6dst->s6_addr16[1], 4); | 698 | memcpy(v4dst, &v6dst->s6_addr16[1], 4); |
699 | return true; | ||
685 | } | 700 | } |
686 | #endif | 701 | #endif |
702 | return false; | ||
703 | } | ||
704 | |||
705 | static inline __be32 try_6rd(struct ip_tunnel *tunnel, | ||
706 | const struct in6_addr *v6dst) | ||
707 | { | ||
708 | __be32 dst = 0; | ||
709 | check_6rd(tunnel, v6dst, &dst); | ||
687 | return dst; | 710 | return dst; |
688 | } | 711 | } |
689 | 712 | ||
@@ -744,7 +767,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
744 | } | 767 | } |
745 | 768 | ||
746 | if (!dst) | 769 | if (!dst) |
747 | dst = try_6rd(&iph6->daddr, tunnel); | 770 | dst = try_6rd(tunnel, &iph6->daddr); |
748 | 771 | ||
749 | if (!dst) { | 772 | if (!dst) { |
750 | struct neighbour *neigh = NULL; | 773 | struct neighbour *neigh = NULL; |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 40161977f7cf..8a0848b60b35 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -179,7 +179,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
179 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 179 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
180 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); | 180 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); |
181 | 181 | ||
182 | if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) | 182 | if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok)) |
183 | goto out; | 183 | goto out; |
184 | 184 | ||
185 | ret = NULL; | 185 | ret = NULL; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4f43537197ef..bbb28ae7e5f3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -835,7 +835,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
835 | * no RST generated if md5 hash doesn't match. | 835 | * no RST generated if md5 hash doesn't match. |
836 | */ | 836 | */ |
837 | sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), | 837 | sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), |
838 | &tcp_hashinfo, &ipv6h->daddr, | 838 | &tcp_hashinfo, &ipv6h->saddr, |
839 | th->source, &ipv6h->daddr, | ||
839 | ntohs(th->source), inet6_iif(skb)); | 840 | ntohs(th->source), inet6_iif(skb)); |
840 | if (!sk1) | 841 | if (!sk1) |
841 | return; | 842 | return; |
@@ -1030,7 +1031,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1030 | treq->rmt_addr = ipv6_hdr(skb)->saddr; | 1031 | treq->rmt_addr = ipv6_hdr(skb)->saddr; |
1031 | treq->loc_addr = ipv6_hdr(skb)->daddr; | 1032 | treq->loc_addr = ipv6_hdr(skb)->daddr; |
1032 | if (!want_cookie || tmp_opt.tstamp_ok) | 1033 | if (!want_cookie || tmp_opt.tstamp_ok) |
1033 | TCP_ECN_create_request(req, skb); | 1034 | TCP_ECN_create_request(req, skb, sock_net(sk)); |
1034 | 1035 | ||
1035 | treq->iif = sk->sk_bound_dev_if; | 1036 | treq->iif = sk->sk_bound_dev_if; |
1036 | 1037 | ||
@@ -1167,7 +1168,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1167 | newnp->opt = NULL; | 1168 | newnp->opt = NULL; |
1168 | newnp->mcast_oif = inet6_iif(skb); | 1169 | newnp->mcast_oif = inet6_iif(skb); |
1169 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1170 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1170 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1171 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1171 | 1172 | ||
1172 | /* | 1173 | /* |
1173 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count | 1174 | * No need to charge this sock to the relevant IPv6 refcnt debug socks count |
@@ -1247,7 +1248,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1247 | newnp->opt = NULL; | 1248 | newnp->opt = NULL; |
1248 | newnp->mcast_oif = inet6_iif(skb); | 1249 | newnp->mcast_oif = inet6_iif(skb); |
1249 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; | 1250 | newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; |
1250 | newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1251 | newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1251 | 1252 | ||
1252 | /* Clone native IPv6 options from listening socket (if any) | 1253 | /* Clone native IPv6 options from listening socket (if any) |
1253 | 1254 | ||
@@ -1460,7 +1461,7 @@ ipv6_pktoptions: | |||
1460 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) | 1461 | if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) |
1461 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; | 1462 | np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; |
1462 | if (np->rxopt.bits.rxtclass) | 1463 | if (np->rxopt.bits.rxtclass) |
1463 | np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); | 1464 | np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); |
1464 | if (ipv6_opt_accepted(sk, opt_skb)) { | 1465 | if (ipv6_opt_accepted(sk, opt_skb)) { |
1465 | skb_set_owner_r(opt_skb, sk); | 1466 | skb_set_owner_r(opt_skb, sk); |
1466 | opt_skb = xchg(&np->pktoptions, opt_skb); | 1467 | opt_skb = xchg(&np->pktoptions, opt_skb); |
@@ -1602,6 +1603,7 @@ do_time_wait: | |||
1602 | struct sock *sk2; | 1603 | struct sock *sk2; |
1603 | 1604 | ||
1604 | sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, | 1605 | sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, |
1606 | &ipv6_hdr(skb)->saddr, th->source, | ||
1605 | &ipv6_hdr(skb)->daddr, | 1607 | &ipv6_hdr(skb)->daddr, |
1606 | ntohs(th->dest), inet6_iif(skb)); | 1608 | ntohs(th->dest), inet6_iif(skb)); |
1607 | if (sk2 != NULL) { | 1609 | if (sk2 != NULL) { |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index fb083295ff0b..599e1ba6d1ce 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <net/tcp_states.h> | 45 | #include <net/tcp_states.h> |
46 | #include <net/ip6_checksum.h> | 46 | #include <net/ip6_checksum.h> |
47 | #include <net/xfrm.h> | 47 | #include <net/xfrm.h> |
48 | #include <net/inet6_hashtables.h> | ||
48 | 49 | ||
49 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
50 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
203 | { | 204 | { |
204 | struct sock *sk, *result; | 205 | struct sock *sk, *result; |
205 | struct hlist_nulls_node *node; | 206 | struct hlist_nulls_node *node; |
206 | int score, badness; | 207 | int score, badness, matches = 0, reuseport = 0; |
208 | u32 hash = 0; | ||
207 | 209 | ||
208 | begin: | 210 | begin: |
209 | result = NULL; | 211 | result = NULL; |
@@ -214,8 +216,18 @@ begin: | |||
214 | if (score > badness) { | 216 | if (score > badness) { |
215 | result = sk; | 217 | result = sk; |
216 | badness = score; | 218 | badness = score; |
217 | if (score == SCORE2_MAX) | 219 | reuseport = sk->sk_reuseport; |
220 | if (reuseport) { | ||
221 | hash = inet6_ehashfn(net, daddr, hnum, | ||
222 | saddr, sport); | ||
223 | matches = 1; | ||
224 | } else if (score == SCORE2_MAX) | ||
218 | goto exact_match; | 225 | goto exact_match; |
226 | } else if (score == badness && reuseport) { | ||
227 | matches++; | ||
228 | if (((u64)hash * matches) >> 32 == 0) | ||
229 | result = sk; | ||
230 | hash = next_pseudo_random32(hash); | ||
219 | } | 231 | } |
220 | } | 232 | } |
221 | /* | 233 | /* |
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
249 | unsigned short hnum = ntohs(dport); | 261 | unsigned short hnum = ntohs(dport); |
250 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); | 262 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); |
251 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; | 263 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; |
252 | int score, badness; | 264 | int score, badness, matches = 0, reuseport = 0; |
265 | u32 hash = 0; | ||
253 | 266 | ||
254 | rcu_read_lock(); | 267 | rcu_read_lock(); |
255 | if (hslot->count > 10) { | 268 | if (hslot->count > 10) { |
@@ -284,6 +297,17 @@ begin: | |||
284 | if (score > badness) { | 297 | if (score > badness) { |
285 | result = sk; | 298 | result = sk; |
286 | badness = score; | 299 | badness = score; |
300 | reuseport = sk->sk_reuseport; | ||
301 | if (reuseport) { | ||
302 | hash = inet6_ehashfn(net, daddr, hnum, | ||
303 | saddr, sport); | ||
304 | matches = 1; | ||
305 | } | ||
306 | } else if (score == badness && reuseport) { | ||
307 | matches++; | ||
308 | if (((u64)hash * matches) >> 32 == 0) | ||
309 | result = sk; | ||
310 | hash = next_pseudo_random32(hash); | ||
287 | } | 311 | } |
288 | } | 312 | } |
289 | /* | 313 | /* |
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
752 | return 0; | 776 | return 0; |
753 | } | 777 | } |
754 | 778 | ||
755 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | ||
756 | int proto) | ||
757 | { | ||
758 | int err; | ||
759 | |||
760 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
761 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
762 | |||
763 | if (proto == IPPROTO_UDPLITE) { | ||
764 | err = udplite_checksum_init(skb, uh); | ||
765 | if (err) | ||
766 | return err; | ||
767 | } | ||
768 | |||
769 | if (uh->check == 0) { | ||
770 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
771 | this error. Well, it is reasonable. | ||
772 | */ | ||
773 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
774 | return 1; | ||
775 | } | ||
776 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
777 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
778 | skb->len, proto, skb->csum)) | ||
779 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
780 | |||
781 | if (!skb_csum_unnecessary(skb)) | ||
782 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
783 | &ipv6_hdr(skb)->daddr, | ||
784 | skb->len, proto, 0)); | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 779 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
790 | int proto) | 780 | int proto) |
791 | { | 781 | { |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index c9844135c9ca..128273744332 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -110,7 +110,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
110 | 110 | ||
111 | /* Sheit... I remember I did this right. Apparently, | 111 | /* Sheit... I remember I did this right. Apparently, |
112 | * it was magically lost, so this code needs audit */ | 112 | * it was magically lost, so this code needs audit */ |
113 | xdst->u.rt6.n = neigh_clone(rt->n); | ||
114 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | | 113 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | |
115 | RTF_LOCAL); | 114 | RTF_LOCAL); |
116 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; | 115 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index ee5a7065aacc..6cc48012b730 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -72,7 +72,7 @@ static inline unsigned int xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *ad | |||
72 | { | 72 | { |
73 | unsigned int h; | 73 | unsigned int h; |
74 | 74 | ||
75 | h = (__force u32)(addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]); | 75 | h = ipv6_addr_hash((const struct in6_addr *)addr); |
76 | h ^= h >> 16; | 76 | h ^= h >> 16; |
77 | h ^= h >> 8; | 77 | h ^= h >> 8; |
78 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; | 78 | h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; |
@@ -94,7 +94,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const | |||
94 | hlist_for_each_entry_rcu(x6spi, pos, | 94 | hlist_for_each_entry_rcu(x6spi, pos, |
95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
96 | list_byaddr) { | 96 | list_byaddr) { |
97 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 97 | if (xfrm6_addr_equal(&x6spi->addr, saddr)) |
98 | return x6spi; | 98 | return x6spi; |
99 | } | 99 | } |
100 | 100 | ||
@@ -211,7 +211,7 @@ static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | |||
211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
212 | list_byaddr) | 212 | list_byaddr) |
213 | { | 213 | { |
214 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 214 | if (xfrm6_addr_equal(&x6spi->addr, saddr)) { |
215 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 215 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
216 | hlist_del_rcu(&x6spi->list_byaddr); | 216 | hlist_del_rcu(&x6spi->list_byaddr); |
217 | hlist_del_rcu(&x6spi->list_byspi); | 217 | hlist_del_rcu(&x6spi->list_byspi); |