aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-03-25 23:10:56 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:51 -0400
commit759e5d006462d53fb708daa8284b4ad909415da1 (patch)
treeedcc4e9d975199b3fe5e2aadc3d1e06824755e75 /net/ipv6/udp.c
parent1ab6eb62b02e0949a392fb19bf31ba59ae1022b1 (diff)
[UDP]: Clean up UDP-Lite receive checksum
This patch eliminates some duplicate code for the verification of receive checksums between UDP-Lite and UDP. It does this by introducing __skb_checksum_complete_head which is identical to __skb_checksum_complete_head apart from the fact that it takes a length parameter rather than computing the first skb->len bytes. As a result UDP-Lite will be able to use hardware checksum offload for packets which do not use partial coverage checksums. It also means that UDP-Lite loopback no longer does unnecessary checksum verification. If any NICs start support UDP-Lite this would also start working automatically. This patch removes the assumption that msg_flags has MSG_TRUNC clear upon entry in recvmsg. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c74
1 files changed, 42 insertions, 32 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3413fc22ce4a..733371689795 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -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->ip_summed == CHECKSUM_UNNECESSARY)
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 {
@@ -194,7 +196,7 @@ try_again:
194 196
195 err = copied; 197 err = copied;
196 if (flags & MSG_TRUNC) 198 if (flags & MSG_TRUNC)
197 err = skb->len - sizeof(struct udphdr); 199 err = ulen;
198 200
199out_free: 201out_free:
200 skb_free_datagram(sk, skb); 202 skb_free_datagram(sk, skb);
@@ -368,9 +370,20 @@ out:
368 return 0; 370 return 0;
369} 371}
370 372
371static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) 373static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
372 374 int proto)
373{ 375{
376 int err;
377
378 UDP_SKB_CB(skb)->partial_cov = 0;
379 UDP_SKB_CB(skb)->cscov = skb->len;
380
381 if (proto == IPPROTO_UDPLITE) {
382 err = udplite_checksum_init(skb, uh);
383 if (err)
384 return err;
385 }
386
374 if (uh->check == 0) { 387 if (uh->check == 0) {
375 /* RFC 2460 section 8.1 says that we SHOULD log 388 /* RFC 2460 section 8.1 says that we SHOULD log
376 this error. Well, it is reasonable. 389 this error. Well, it is reasonable.
@@ -380,20 +393,19 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh)
380 } 393 }
381 if (skb->ip_summed == CHECKSUM_COMPLETE && 394 if (skb->ip_summed == CHECKSUM_COMPLETE &&
382 !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, 395 !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
383 skb->len, IPPROTO_UDP, skb->csum )) 396 skb->len, proto, skb->csum))
384 skb->ip_summed = CHECKSUM_UNNECESSARY; 397 skb->ip_summed = CHECKSUM_UNNECESSARY;
385 398
386 if (skb->ip_summed != CHECKSUM_UNNECESSARY) 399 if (skb->ip_summed != CHECKSUM_UNNECESSARY)
387 skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr, 400 skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
388 &skb->nh.ipv6h->daddr, 401 &skb->nh.ipv6h->daddr,
389 skb->len, IPPROTO_UDP, 402 skb->len, proto, 0));
390 0));
391 403
392 return (UDP_SKB_CB(skb)->partial_cov = 0); 404 return 0;
393} 405}
394 406
395int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], 407int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
396 int is_udplite) 408 int proto)
397{ 409{
398 struct sk_buff *skb = *pskb; 410 struct sk_buff *skb = *pskb;
399 struct sock *sk; 411 struct sock *sk;
@@ -413,7 +425,8 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
413 if (ulen > skb->len) 425 if (ulen > skb->len)
414 goto short_packet; 426 goto short_packet;
415 427
416 if(! is_udplite ) { /* UDP validates ulen. */ 428 if (proto == IPPROTO_UDP) {
429 /* UDP validates ulen. */
417 430
418 /* Check for jumbo payload */ 431 /* Check for jumbo payload */
419 if (ulen == 0) 432 if (ulen == 0)
@@ -429,15 +442,11 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
429 daddr = &skb->nh.ipv6h->daddr; 442 daddr = &skb->nh.ipv6h->daddr;
430 uh = skb->h.uh; 443 uh = skb->h.uh;
431 } 444 }
432
433 if (udp6_csum_init(skb, uh))
434 goto discard;
435
436 } else { /* UDP-Lite validates cscov. */
437 if (udplite6_csum_init(skb, uh))
438 goto discard;
439 } 445 }
440 446
447 if (udp6_csum_init(skb, uh, proto))
448 goto discard;
449
441 /* 450 /*
442 * Multicast receive code 451 * Multicast receive code
443 */ 452 */
@@ -459,7 +468,7 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
459 468
460 if (udp_lib_checksum_complete(skb)) 469 if (udp_lib_checksum_complete(skb))
461 goto discard; 470 goto discard;
462 UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); 471 UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
463 472
464 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); 473 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
465 474
@@ -475,17 +484,18 @@ int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
475 484
476short_packet: 485short_packet:
477 LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", 486 LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n",
478 is_udplite? "-Lite" : "", ulen, skb->len); 487 proto == IPPROTO_UDPLITE ? "-Lite" : "",
488 ulen, skb->len);
479 489
480discard: 490discard:
481 UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); 491 UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
482 kfree_skb(skb); 492 kfree_skb(skb);
483 return(0); 493 return(0);
484} 494}
485 495
486static __inline__ int udpv6_rcv(struct sk_buff **pskb) 496static __inline__ int udpv6_rcv(struct sk_buff **pskb)
487{ 497{
488 return __udp6_lib_rcv(pskb, udp_hash, 0); 498 return __udp6_lib_rcv(pskb, udp_hash, IPPROTO_UDP);
489} 499}
490 500
491/* 501/*