diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index a6aecf76a71b..8b48512ebf6a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -107,6 +107,21 @@ static struct sock *__udp6_lib_lookup(struct net *net, | |||
107 | return result; | 107 | return result; |
108 | } | 108 | } |
109 | 109 | ||
110 | static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, | ||
111 | __be16 sport, __be16 dport, | ||
112 | struct hlist_head udptable[]) | ||
113 | { | ||
114 | struct sock *sk; | ||
115 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
116 | |||
117 | if (unlikely(sk = skb_steal_sock(skb))) | ||
118 | return sk; | ||
119 | else | ||
120 | return __udp6_lib_lookup(dev_net(skb->dst->dev), &iph->saddr, sport, | ||
121 | &iph->daddr, dport, inet6_iif(skb), | ||
122 | udptable); | ||
123 | } | ||
124 | |||
110 | /* | 125 | /* |
111 | * This should be easy, if there is something there we | 126 | * This should be easy, if there is something there we |
112 | * return it, otherwise we block. | 127 | * return it, otherwise we block. |
@@ -123,6 +138,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
123 | int peeked; | 138 | int peeked; |
124 | int err; | 139 | int err; |
125 | int is_udplite = IS_UDPLITE(sk); | 140 | int is_udplite = IS_UDPLITE(sk); |
141 | int is_udp4; | ||
126 | 142 | ||
127 | if (addr_len) | 143 | if (addr_len) |
128 | *addr_len=sizeof(struct sockaddr_in6); | 144 | *addr_len=sizeof(struct sockaddr_in6); |
@@ -143,6 +159,8 @@ try_again: | |||
143 | else if (copied < ulen) | 159 | else if (copied < ulen) |
144 | msg->msg_flags |= MSG_TRUNC; | 160 | msg->msg_flags |= MSG_TRUNC; |
145 | 161 | ||
162 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | ||
163 | |||
146 | /* | 164 | /* |
147 | * If checksum is needed at all, try to do it while copying the | 165 | * If checksum is needed at all, try to do it while copying the |
148 | * data. If the data is truncated, or if we only want a partial | 166 | * data. If the data is truncated, or if we only want a partial |
@@ -165,9 +183,14 @@ try_again: | |||
165 | if (err) | 183 | if (err) |
166 | goto out_free; | 184 | goto out_free; |
167 | 185 | ||
168 | if (!peeked) | 186 | if (!peeked) { |
169 | UDP6_INC_STATS_USER(sock_net(sk), | 187 | if (is_udp4) |
170 | UDP_MIB_INDATAGRAMS, is_udplite); | 188 | UDP_INC_STATS_USER(sock_net(sk), |
189 | UDP_MIB_INDATAGRAMS, is_udplite); | ||
190 | else | ||
191 | UDP6_INC_STATS_USER(sock_net(sk), | ||
192 | UDP_MIB_INDATAGRAMS, is_udplite); | ||
193 | } | ||
171 | 194 | ||
172 | sock_recv_timestamp(msg, sk, skb); | 195 | sock_recv_timestamp(msg, sk, skb); |
173 | 196 | ||
@@ -181,7 +204,7 @@ try_again: | |||
181 | sin6->sin6_flowinfo = 0; | 204 | sin6->sin6_flowinfo = 0; |
182 | sin6->sin6_scope_id = 0; | 205 | sin6->sin6_scope_id = 0; |
183 | 206 | ||
184 | if (skb->protocol == htons(ETH_P_IP)) | 207 | if (is_udp4) |
185 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, | 208 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, |
186 | htonl(0xffff), ip_hdr(skb)->saddr); | 209 | htonl(0xffff), ip_hdr(skb)->saddr); |
187 | else { | 210 | else { |
@@ -192,7 +215,7 @@ try_again: | |||
192 | } | 215 | } |
193 | 216 | ||
194 | } | 217 | } |
195 | if (skb->protocol == htons(ETH_P_IP)) { | 218 | if (is_udp4) { |
196 | if (inet->cmsg_flags) | 219 | if (inet->cmsg_flags) |
197 | ip_cmsg_recv(msg, skb); | 220 | ip_cmsg_recv(msg, skb); |
198 | } else { | 221 | } else { |
@@ -213,8 +236,14 @@ out: | |||
213 | 236 | ||
214 | csum_copy_err: | 237 | csum_copy_err: |
215 | lock_sock(sk); | 238 | lock_sock(sk); |
216 | if (!skb_kill_datagram(sk, skb, flags)) | 239 | if (!skb_kill_datagram(sk, skb, flags)) { |
217 | UDP6_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); | 240 | if (is_udp4) |
241 | UDP_INC_STATS_USER(sock_net(sk), | ||
242 | UDP_MIB_INERRORS, is_udplite); | ||
243 | else | ||
244 | UDP6_INC_STATS_USER(sock_net(sk), | ||
245 | UDP_MIB_INERRORS, is_udplite); | ||
246 | } | ||
218 | release_sock(sk); | 247 | release_sock(sk); |
219 | 248 | ||
220 | if (flags & MSG_DONTWAIT) | 249 | if (flags & MSG_DONTWAIT) |
@@ -313,7 +342,7 @@ drop: | |||
313 | return -1; | 342 | return -1; |
314 | } | 343 | } |
315 | 344 | ||
316 | static struct sock *udp_v6_mcast_next(struct sock *sk, | 345 | static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, |
317 | __be16 loc_port, struct in6_addr *loc_addr, | 346 | __be16 loc_port, struct in6_addr *loc_addr, |
318 | __be16 rmt_port, struct in6_addr *rmt_addr, | 347 | __be16 rmt_port, struct in6_addr *rmt_addr, |
319 | int dif) | 348 | int dif) |
@@ -325,7 +354,7 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, | |||
325 | sk_for_each_from(s, node) { | 354 | sk_for_each_from(s, node) { |
326 | struct inet_sock *inet = inet_sk(s); | 355 | struct inet_sock *inet = inet_sk(s); |
327 | 356 | ||
328 | if (sock_net(s) != sock_net(sk)) | 357 | if (!net_eq(sock_net(s), net)) |
329 | continue; | 358 | continue; |
330 | 359 | ||
331 | if (s->sk_hash == num && s->sk_family == PF_INET6) { | 360 | if (s->sk_hash == num && s->sk_family == PF_INET6) { |
@@ -368,14 +397,14 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
368 | read_lock(&udp_hash_lock); | 397 | read_lock(&udp_hash_lock); |
369 | sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); | 398 | sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); |
370 | dif = inet6_iif(skb); | 399 | dif = inet6_iif(skb); |
371 | sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); | 400 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); |
372 | if (!sk) { | 401 | if (!sk) { |
373 | kfree_skb(skb); | 402 | kfree_skb(skb); |
374 | goto out; | 403 | goto out; |
375 | } | 404 | } |
376 | 405 | ||
377 | sk2 = sk; | 406 | sk2 = sk; |
378 | while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, | 407 | while ((sk2 = udp_v6_mcast_next(net, sk_next(sk2), uh->dest, daddr, |
379 | uh->source, saddr, dif))) { | 408 | uh->source, saddr, dif))) { |
380 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); | 409 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); |
381 | if (buff) { | 410 | if (buff) { |
@@ -488,8 +517,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], | |||
488 | * check socket cache ... must talk to Alan about his plans | 517 | * check socket cache ... must talk to Alan about his plans |
489 | * for sock caches... i'll skip this for now. | 518 | * for sock caches... i'll skip this for now. |
490 | */ | 519 | */ |
491 | sk = __udp6_lib_lookup(net, saddr, uh->source, | 520 | sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable); |
492 | daddr, uh->dest, inet6_iif(skb), udptable); | ||
493 | 521 | ||
494 | if (sk == NULL) { | 522 | if (sk == NULL) { |
495 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 523 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |