aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c54
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
110static 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
214csum_copy_err: 237csum_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
316static struct sock *udp_v6_mcast_next(struct sock *sk, 345static 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))