diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 123 |
1 files changed, 68 insertions, 55 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f590db57a7c9..b083c09e3d2d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -93,10 +93,10 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, | |||
93 | continue; | 93 | continue; |
94 | score++; | 94 | score++; |
95 | } | 95 | } |
96 | if(score == 4) { | 96 | if (score == 4) { |
97 | result = sk; | 97 | result = sk; |
98 | break; | 98 | break; |
99 | } else if(score > badness) { | 99 | } else if (score > badness) { |
100 | result = sk; | 100 | result = sk; |
101 | badness = score; | 101 | badness = score; |
102 | } | 102 | } |
@@ -120,8 +120,9 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
120 | struct ipv6_pinfo *np = inet6_sk(sk); | 120 | struct ipv6_pinfo *np = inet6_sk(sk); |
121 | struct inet_sock *inet = inet_sk(sk); | 121 | struct inet_sock *inet = inet_sk(sk); |
122 | struct sk_buff *skb; | 122 | struct sk_buff *skb; |
123 | size_t copied; | 123 | unsigned int ulen, copied; |
124 | int err, copy_only, is_udplite = IS_UDPLITE(sk); | 124 | int err; |
125 | int is_udplite = IS_UDPLITE(sk); | ||
125 | 126 | ||
126 | if (addr_len) | 127 | if (addr_len) |
127 | *addr_len=sizeof(struct sockaddr_in6); | 128 | *addr_len=sizeof(struct sockaddr_in6); |
@@ -134,24 +135,25 @@ try_again: | |||
134 | if (!skb) | 135 | if (!skb) |
135 | goto out; | 136 | goto out; |
136 | 137 | ||
137 | copied = skb->len - sizeof(struct udphdr); | 138 | ulen = skb->len - sizeof(struct udphdr); |
138 | if (copied > len) { | 139 | copied = len; |
139 | copied = len; | 140 | if (copied > ulen) |
141 | copied = ulen; | ||
142 | else if (copied < ulen) | ||
140 | msg->msg_flags |= MSG_TRUNC; | 143 | msg->msg_flags |= MSG_TRUNC; |
141 | } | ||
142 | 144 | ||
143 | /* | 145 | /* |
144 | * Decide whether to checksum and/or copy data. | 146 | * If checksum is needed at all, try to do it while copying the |
147 | * data. If the data is truncated, or if we only want a partial | ||
148 | * coverage checksum (UDP-Lite), do it before the copy. | ||
145 | */ | 149 | */ |
146 | copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY); | ||
147 | 150 | ||
148 | if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { | 151 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { |
149 | if (__udp_lib_checksum_complete(skb)) | 152 | if (udp_lib_checksum_complete(skb)) |
150 | goto csum_copy_err; | 153 | goto csum_copy_err; |
151 | copy_only = 1; | ||
152 | } | 154 | } |
153 | 155 | ||
154 | if (copy_only) | 156 | if (skb_csum_unnecessary(skb)) |
155 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 157 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
156 | msg->msg_iov, copied ); | 158 | msg->msg_iov, copied ); |
157 | else { | 159 | else { |
@@ -170,15 +172,16 @@ try_again: | |||
170 | 172 | ||
171 | sin6 = (struct sockaddr_in6 *) msg->msg_name; | 173 | sin6 = (struct sockaddr_in6 *) msg->msg_name; |
172 | sin6->sin6_family = AF_INET6; | 174 | sin6->sin6_family = AF_INET6; |
173 | sin6->sin6_port = skb->h.uh->source; | 175 | sin6->sin6_port = udp_hdr(skb)->source; |
174 | sin6->sin6_flowinfo = 0; | 176 | sin6->sin6_flowinfo = 0; |
175 | sin6->sin6_scope_id = 0; | 177 | sin6->sin6_scope_id = 0; |
176 | 178 | ||
177 | if (skb->protocol == htons(ETH_P_IP)) | 179 | if (skb->protocol == htons(ETH_P_IP)) |
178 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, | 180 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, |
179 | htonl(0xffff), skb->nh.iph->saddr); | 181 | htonl(0xffff), ip_hdr(skb)->saddr); |
180 | else { | 182 | else { |
181 | ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); | 183 | ipv6_addr_copy(&sin6->sin6_addr, |
184 | &ipv6_hdr(skb)->saddr); | ||
182 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 185 | if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
183 | sin6->sin6_scope_id = IP6CB(skb)->iif; | 186 | sin6->sin6_scope_id = IP6CB(skb)->iif; |
184 | } | 187 | } |
@@ -194,7 +197,7 @@ try_again: | |||
194 | 197 | ||
195 | err = copied; | 198 | err = copied; |
196 | if (flags & MSG_TRUNC) | 199 | if (flags & MSG_TRUNC) |
197 | err = skb->len - sizeof(struct udphdr); | 200 | err = ulen; |
198 | 201 | ||
199 | out_free: | 202 | out_free: |
200 | skb_free_datagram(sk, skb); | 203 | skb_free_datagram(sk, skb); |
@@ -279,8 +282,10 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
279 | } | 282 | } |
280 | } | 283 | } |
281 | 284 | ||
282 | if (udp_lib_checksum_complete(skb)) | 285 | if (sk->sk_filter) { |
283 | goto drop; | 286 | if (udp_lib_checksum_complete(skb)) |
287 | goto drop; | ||
288 | } | ||
284 | 289 | ||
285 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 290 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
286 | /* Note that an ENOMEM error is charged twice */ | 291 | /* Note that an ENOMEM error is charged twice */ |
@@ -325,7 +330,7 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, | |||
325 | if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) | 330 | if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) |
326 | continue; | 331 | continue; |
327 | } | 332 | } |
328 | if(!inet6_mc_check(s, loc_addr, rmt_addr)) | 333 | if (!inet6_mc_check(s, loc_addr, rmt_addr)) |
329 | continue; | 334 | continue; |
330 | return s; | 335 | return s; |
331 | } | 336 | } |
@@ -341,7 +346,7 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, | |||
341 | struct in6_addr *daddr, struct hlist_head udptable[]) | 346 | struct in6_addr *daddr, struct hlist_head udptable[]) |
342 | { | 347 | { |
343 | struct sock *sk, *sk2; | 348 | struct sock *sk, *sk2; |
344 | const struct udphdr *uh = skb->h.uh; | 349 | const struct udphdr *uh = udp_hdr(skb); |
345 | int dif; | 350 | int dif; |
346 | 351 | ||
347 | read_lock(&udp_hash_lock); | 352 | read_lock(&udp_hash_lock); |
@@ -366,9 +371,20 @@ out: | |||
366 | return 0; | 371 | return 0; |
367 | } | 372 | } |
368 | 373 | ||
369 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) | 374 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, |
370 | 375 | int proto) | |
371 | { | 376 | { |
377 | int err; | ||
378 | |||
379 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
380 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
381 | |||
382 | if (proto == IPPROTO_UDPLITE) { | ||
383 | err = udplite_checksum_init(skb, uh); | ||
384 | if (err) | ||
385 | return err; | ||
386 | } | ||
387 | |||
372 | if (uh->check == 0) { | 388 | if (uh->check == 0) { |
373 | /* RFC 2460 section 8.1 says that we SHOULD log | 389 | /* RFC 2460 section 8.1 says that we SHOULD log |
374 | this error. Well, it is reasonable. | 390 | this error. Well, it is reasonable. |
@@ -377,21 +393,20 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) | |||
377 | return 1; | 393 | return 1; |
378 | } | 394 | } |
379 | if (skb->ip_summed == CHECKSUM_COMPLETE && | 395 | if (skb->ip_summed == CHECKSUM_COMPLETE && |
380 | !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, | 396 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
381 | skb->len, IPPROTO_UDP, skb->csum )) | 397 | skb->len, proto, skb->csum)) |
382 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 398 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
383 | 399 | ||
384 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 400 | if (!skb_csum_unnecessary(skb)) |
385 | skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr, | 401 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, |
386 | &skb->nh.ipv6h->daddr, | 402 | &ipv6_hdr(skb)->daddr, |
387 | skb->len, IPPROTO_UDP, | 403 | skb->len, proto, 0)); |
388 | 0)); | ||
389 | 404 | ||
390 | return (UDP_SKB_CB(skb)->partial_cov = 0); | 405 | return 0; |
391 | } | 406 | } |
392 | 407 | ||
393 | int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | 408 | int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], |
394 | int is_udplite) | 409 | int proto) |
395 | { | 410 | { |
396 | struct sk_buff *skb = *pskb; | 411 | struct sk_buff *skb = *pskb; |
397 | struct sock *sk; | 412 | struct sock *sk; |
@@ -403,15 +418,16 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | |||
403 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 418 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
404 | goto short_packet; | 419 | goto short_packet; |
405 | 420 | ||
406 | saddr = &skb->nh.ipv6h->saddr; | 421 | saddr = &ipv6_hdr(skb)->saddr; |
407 | daddr = &skb->nh.ipv6h->daddr; | 422 | daddr = &ipv6_hdr(skb)->daddr; |
408 | uh = skb->h.uh; | 423 | uh = udp_hdr(skb); |
409 | 424 | ||
410 | ulen = ntohs(uh->len); | 425 | ulen = ntohs(uh->len); |
411 | if (ulen > skb->len) | 426 | if (ulen > skb->len) |
412 | goto short_packet; | 427 | goto short_packet; |
413 | 428 | ||
414 | if(! is_udplite ) { /* UDP validates ulen. */ | 429 | if (proto == IPPROTO_UDP) { |
430 | /* UDP validates ulen. */ | ||
415 | 431 | ||
416 | /* Check for jumbo payload */ | 432 | /* Check for jumbo payload */ |
417 | if (ulen == 0) | 433 | if (ulen == 0) |
@@ -423,19 +439,15 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | |||
423 | if (ulen < skb->len) { | 439 | if (ulen < skb->len) { |
424 | if (pskb_trim_rcsum(skb, ulen)) | 440 | if (pskb_trim_rcsum(skb, ulen)) |
425 | goto short_packet; | 441 | goto short_packet; |
426 | saddr = &skb->nh.ipv6h->saddr; | 442 | saddr = &ipv6_hdr(skb)->saddr; |
427 | daddr = &skb->nh.ipv6h->daddr; | 443 | daddr = &ipv6_hdr(skb)->daddr; |
428 | uh = skb->h.uh; | 444 | uh = udp_hdr(skb); |
429 | } | 445 | } |
430 | |||
431 | if (udp6_csum_init(skb, uh)) | ||
432 | goto discard; | ||
433 | |||
434 | } else { /* UDP-Lite validates cscov. */ | ||
435 | if (udplite6_csum_init(skb, uh)) | ||
436 | goto discard; | ||
437 | } | 446 | } |
438 | 447 | ||
448 | if (udp6_csum_init(skb, uh, proto)) | ||
449 | goto discard; | ||
450 | |||
439 | /* | 451 | /* |
440 | * Multicast receive code | 452 | * Multicast receive code |
441 | */ | 453 | */ |
@@ -457,33 +469,34 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | |||
457 | 469 | ||
458 | if (udp_lib_checksum_complete(skb)) | 470 | if (udp_lib_checksum_complete(skb)) |
459 | goto discard; | 471 | goto discard; |
460 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); | 472 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); |
461 | 473 | ||
462 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 474 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); |
463 | 475 | ||
464 | kfree_skb(skb); | 476 | kfree_skb(skb); |
465 | return(0); | 477 | return 0; |
466 | } | 478 | } |
467 | 479 | ||
468 | /* deliver */ | 480 | /* deliver */ |
469 | 481 | ||
470 | udpv6_queue_rcv_skb(sk, skb); | 482 | udpv6_queue_rcv_skb(sk, skb); |
471 | sock_put(sk); | 483 | sock_put(sk); |
472 | return(0); | 484 | return 0; |
473 | 485 | ||
474 | short_packet: | 486 | short_packet: |
475 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", | 487 | LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", |
476 | is_udplite? "-Lite" : "", ulen, skb->len); | 488 | proto == IPPROTO_UDPLITE ? "-Lite" : "", |
489 | ulen, skb->len); | ||
477 | 490 | ||
478 | discard: | 491 | discard: |
479 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); | 492 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); |
480 | kfree_skb(skb); | 493 | kfree_skb(skb); |
481 | return(0); | 494 | return 0; |
482 | } | 495 | } |
483 | 496 | ||
484 | static __inline__ int udpv6_rcv(struct sk_buff **pskb) | 497 | static __inline__ int udpv6_rcv(struct sk_buff **pskb) |
485 | { | 498 | { |
486 | return __udp6_lib_rcv(pskb, udp_hash, 0); | 499 | return __udp6_lib_rcv(pskb, udp_hash, IPPROTO_UDP); |
487 | } | 500 | } |
488 | 501 | ||
489 | /* | 502 | /* |
@@ -521,7 +534,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
521 | /* | 534 | /* |
522 | * Create a UDP header | 535 | * Create a UDP header |
523 | */ | 536 | */ |
524 | uh = skb->h.uh; | 537 | uh = udp_hdr(skb); |
525 | uh->source = fl->fl_ip_sport; | 538 | uh->source = fl->fl_ip_sport; |
526 | uh->dest = fl->fl_ip_dport; | 539 | uh->dest = fl->fl_ip_dport; |
527 | uh->len = htons(up->len); | 540 | uh->len = htons(up->len); |