aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/skbuff.h1
-rw-r--r--include/net/udp.h5
-rw-r--r--include/net/udplite.h39
-rw-r--r--net/core/datagram.c10
-rw-r--r--net/ipv4/udp.c96
-rw-r--r--net/ipv4/udplite.c2
-rw-r--r--net/ipv6/udp.c74
-rw-r--r--net/ipv6/udplite.c2
8 files changed, 109 insertions, 120 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 30089adb2e78..df229bd5f1a9 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1372,6 +1372,7 @@ static inline void __net_timestamp(struct sk_buff *skb)
1372} 1372}
1373 1373
1374 1374
1375extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
1375extern __sum16 __skb_checksum_complete(struct sk_buff *skb); 1376extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
1376 1377
1377/** 1378/**
diff --git a/include/net/udp.h b/include/net/udp.h
index 1b921fa81474..4a9699f79281 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -72,10 +72,7 @@ struct sk_buff;
72 */ 72 */
73static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) 73static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb)
74{ 74{
75 if (! UDP_SKB_CB(skb)->partial_cov) 75 return __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov);
76 return __skb_checksum_complete(skb);
77 return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov,
78 skb->csum));
79} 76}
80 77
81static inline int udp_lib_checksum_complete(struct sk_buff *skb) 78static inline int udp_lib_checksum_complete(struct sk_buff *skb)
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 67ac51424307..d99df75fe54c 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -47,11 +47,10 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
47 return 1; 47 return 1;
48 } 48 }
49 49
50 UDP_SKB_CB(skb)->partial_cov = 0;
51 cscov = ntohs(uh->len); 50 cscov = ntohs(uh->len);
52 51
53 if (cscov == 0) /* Indicates that full coverage is required. */ 52 if (cscov == 0) /* Indicates that full coverage is required. */
54 cscov = skb->len; 53 ;
55 else if (cscov < 8 || cscov > skb->len) { 54 else if (cscov < 8 || cscov > skb->len) {
56 /* 55 /*
57 * Coverage length violates RFC 3828: log and discard silently. 56 * Coverage length violates RFC 3828: log and discard silently.
@@ -60,42 +59,16 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
60 cscov, skb->len); 59 cscov, skb->len);
61 return 1; 60 return 1;
62 61
63 } else if (cscov < skb->len) 62 } else if (cscov < skb->len) {
64 UDP_SKB_CB(skb)->partial_cov = 1; 63 UDP_SKB_CB(skb)->partial_cov = 1;
65 64 UDP_SKB_CB(skb)->cscov = cscov;
66 UDP_SKB_CB(skb)->cscov = cscov; 65 if (skb->ip_summed == CHECKSUM_COMPLETE)
67 66 skb->ip_summed = CHECKSUM_NONE;
68 /* 67 }
69 * There is no known NIC manufacturer supporting UDP-Lite yet,
70 * hence ip_summed is always (re-)set to CHECKSUM_NONE.
71 */
72 skb->ip_summed = CHECKSUM_NONE;
73 68
74 return 0; 69 return 0;
75} 70}
76 71
77static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh)
78{
79 int rc = udplite_checksum_init(skb, uh);
80
81 if (!rc)
82 skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr,
83 skb->nh.iph->daddr,
84 skb->len, IPPROTO_UDPLITE, 0);
85 return rc;
86}
87
88static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh)
89{
90 int rc = udplite_checksum_init(skb, uh);
91
92 if (!rc)
93 skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
94 &skb->nh.ipv6h->daddr,
95 skb->len, IPPROTO_UDPLITE, 0));
96 return rc;
97}
98
99static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) 72static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh)
100{ 73{
101 int cscov = up->len; 74 int cscov = up->len;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 186212b5b7da..cb056f476126 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -411,11 +411,11 @@ fault:
411 return -EFAULT; 411 return -EFAULT;
412} 412}
413 413
414__sum16 __skb_checksum_complete(struct sk_buff *skb) 414__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
415{ 415{
416 __sum16 sum; 416 __sum16 sum;
417 417
418 sum = csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); 418 sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
419 if (likely(!sum)) { 419 if (likely(!sum)) {
420 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) 420 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
421 netdev_rx_csum_fault(skb->dev); 421 netdev_rx_csum_fault(skb->dev);
@@ -423,6 +423,12 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
423 } 423 }
424 return sum; 424 return sum;
425} 425}
426EXPORT_SYMBOL(__skb_checksum_complete_head);
427
428__sum16 __skb_checksum_complete(struct sk_buff *skb)
429{
430 return __skb_checksum_complete_head(skb, skb->len);
431}
426EXPORT_SYMBOL(__skb_checksum_complete); 432EXPORT_SYMBOL(__skb_checksum_complete);
427 433
428/** 434/**
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fc620a7c1db4..86368832d481 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -810,7 +810,9 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
810 struct inet_sock *inet = inet_sk(sk); 810 struct inet_sock *inet = inet_sk(sk);
811 struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; 811 struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
812 struct sk_buff *skb; 812 struct sk_buff *skb;
813 int copied, err, copy_only, is_udplite = IS_UDPLITE(sk); 813 unsigned int ulen, copied;
814 int err;
815 int is_udplite = IS_UDPLITE(sk);
814 816
815 /* 817 /*
816 * Check any passed addresses 818 * Check any passed addresses
@@ -826,28 +828,25 @@ try_again:
826 if (!skb) 828 if (!skb)
827 goto out; 829 goto out;
828 830
829 copied = skb->len - sizeof(struct udphdr); 831 ulen = skb->len - sizeof(struct udphdr);
830 if (copied > len) { 832 copied = len;
831 copied = len; 833 if (copied > ulen)
834 copied = ulen;
835 else if (copied < ulen)
832 msg->msg_flags |= MSG_TRUNC; 836 msg->msg_flags |= MSG_TRUNC;
833 }
834 837
835 /* 838 /*
836 * Decide whether to checksum and/or copy data. 839 * If checksum is needed at all, try to do it while copying the
837 * 840 * data. If the data is truncated, or if we only want a partial
838 * UDP: checksum may have been computed in HW, 841 * coverage checksum (UDP-Lite), do it before the copy.
839 * (re-)compute it if message is truncated.
840 * UDP-Lite: always needs to checksum, no HW support.
841 */ 842 */
842 copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY);
843 843
844 if (is_udplite || (!copy_only && msg->msg_flags&MSG_TRUNC)) { 844 if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
845 if (__udp_lib_checksum_complete(skb)) 845 if (udp_lib_checksum_complete(skb))
846 goto csum_copy_err; 846 goto csum_copy_err;
847 copy_only = 1;
848 } 847 }
849 848
850 if (copy_only) 849 if (skb->ip_summed == CHECKSUM_UNNECESSARY)
851 err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), 850 err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
852 msg->msg_iov, copied ); 851 msg->msg_iov, copied );
853 else { 852 else {
@@ -875,7 +874,7 @@ try_again:
875 874
876 err = copied; 875 err = copied;
877 if (flags & MSG_TRUNC) 876 if (flags & MSG_TRUNC)
878 err = skb->len - sizeof(struct udphdr); 877 err = ulen;
879 878
880out_free: 879out_free:
881 skb_free_datagram(sk, skb); 880 skb_free_datagram(sk, skb);
@@ -1095,10 +1094,9 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
1095 } 1094 }
1096 } 1095 }
1097 1096
1098 if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { 1097 if (sk->sk_filter) {
1099 if (__udp_lib_checksum_complete(skb)) 1098 if (udp_lib_checksum_complete(skb))
1100 goto drop; 1099 goto drop;
1101 skb->ip_summed = CHECKSUM_UNNECESSARY;
1102 } 1100 }
1103 1101
1104 if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { 1102 if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
@@ -1166,25 +1164,36 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
1166 * Otherwise, csum completion requires chacksumming packet body, 1164 * Otherwise, csum completion requires chacksumming packet body,
1167 * including udp header and folding it to skb->csum. 1165 * including udp header and folding it to skb->csum.
1168 */ 1166 */
1169static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) 1167static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
1168 int proto)
1170{ 1169{
1170 int err;
1171
1172 UDP_SKB_CB(skb)->partial_cov = 0;
1173 UDP_SKB_CB(skb)->cscov = skb->len;
1174
1175 if (proto == IPPROTO_UDPLITE) {
1176 err = udplite_checksum_init(skb, uh);
1177 if (err)
1178 return err;
1179 }
1180
1171 if (uh->check == 0) { 1181 if (uh->check == 0) {
1172 skb->ip_summed = CHECKSUM_UNNECESSARY; 1182 skb->ip_summed = CHECKSUM_UNNECESSARY;
1173 } else if (skb->ip_summed == CHECKSUM_COMPLETE) { 1183 } else if (skb->ip_summed == CHECKSUM_COMPLETE) {
1174 if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, 1184 if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
1175 skb->len, IPPROTO_UDP, skb->csum )) 1185 skb->len, proto, skb->csum))
1176 skb->ip_summed = CHECKSUM_UNNECESSARY; 1186 skb->ip_summed = CHECKSUM_UNNECESSARY;
1177 } 1187 }
1178 if (skb->ip_summed != CHECKSUM_UNNECESSARY) 1188 if (skb->ip_summed != CHECKSUM_UNNECESSARY)
1179 skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, 1189 skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr,
1180 skb->nh.iph->daddr, 1190 skb->nh.iph->daddr,
1181 skb->len, IPPROTO_UDP, 0); 1191 skb->len, proto, 0);
1182 /* Probably, we should checksum udp header (it should be in cache 1192 /* Probably, we should checksum udp header (it should be in cache
1183 * in any case) and data in tiny packets (< rx copybreak). 1193 * in any case) and data in tiny packets (< rx copybreak).
1184 */ 1194 */
1185 1195
1186 /* UDP = UDP-Lite with a non-partial checksum coverage */ 1196 return 0;
1187 UDP_SKB_CB(skb)->partial_cov = 0;
1188} 1197}
1189 1198
1190/* 1199/*
@@ -1192,7 +1201,7 @@ static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh)
1192 */ 1201 */
1193 1202
1194int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], 1203int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1195 int is_udplite) 1204 int proto)
1196{ 1205{
1197 struct sock *sk; 1206 struct sock *sk;
1198 struct udphdr *uh = skb->h.uh; 1207 struct udphdr *uh = skb->h.uh;
@@ -1211,19 +1220,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1211 if (ulen > skb->len) 1220 if (ulen > skb->len)
1212 goto short_packet; 1221 goto short_packet;
1213 1222
1214 if(! is_udplite ) { /* UDP validates ulen. */ 1223 if (proto == IPPROTO_UDP) {
1215 1224 /* UDP validates ulen. */
1216 if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) 1225 if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))
1217 goto short_packet; 1226 goto short_packet;
1218 uh = skb->h.uh; 1227 uh = skb->h.uh;
1219
1220 udp4_csum_init(skb, uh);
1221
1222 } else { /* UDP-Lite validates cscov. */
1223 if (udplite4_csum_init(skb, uh))
1224 goto csum_error;
1225 } 1228 }
1226 1229
1230 if (udp4_csum_init(skb, uh, proto))
1231 goto csum_error;
1232
1227 if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) 1233 if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
1228 return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); 1234 return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
1229 1235
@@ -1250,7 +1256,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1250 if (udp_lib_checksum_complete(skb)) 1256 if (udp_lib_checksum_complete(skb))
1251 goto csum_error; 1257 goto csum_error;
1252 1258
1253 UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite); 1259 UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
1254 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 1260 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1255 1261
1256 /* 1262 /*
@@ -1262,7 +1268,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1262 1268
1263short_packet: 1269short_packet:
1264 LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", 1270 LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
1265 is_udplite? "-Lite" : "", 1271 proto == IPPROTO_UDPLITE ? "-Lite" : "",
1266 NIPQUAD(saddr), 1272 NIPQUAD(saddr),
1267 ntohs(uh->source), 1273 ntohs(uh->source),
1268 ulen, 1274 ulen,
@@ -1277,21 +1283,21 @@ csum_error:
1277 * the network is concerned, anyway) as per 4.1.3.4 (MUST). 1283 * the network is concerned, anyway) as per 4.1.3.4 (MUST).
1278 */ 1284 */
1279 LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", 1285 LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
1280 is_udplite? "-Lite" : "", 1286 proto == IPPROTO_UDPLITE ? "-Lite" : "",
1281 NIPQUAD(saddr), 1287 NIPQUAD(saddr),
1282 ntohs(uh->source), 1288 ntohs(uh->source),
1283 NIPQUAD(daddr), 1289 NIPQUAD(daddr),
1284 ntohs(uh->dest), 1290 ntohs(uh->dest),
1285 ulen); 1291 ulen);
1286drop: 1292drop:
1287 UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); 1293 UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
1288 kfree_skb(skb); 1294 kfree_skb(skb);
1289 return(0); 1295 return(0);
1290} 1296}
1291 1297
1292__inline__ int udp_rcv(struct sk_buff *skb) 1298__inline__ int udp_rcv(struct sk_buff *skb)
1293{ 1299{
1294 return __udp4_lib_rcv(skb, udp_hash, 0); 1300 return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);
1295} 1301}
1296 1302
1297int udp_destroy_sock(struct sock *sk) 1303int udp_destroy_sock(struct sock *sk)
@@ -1486,15 +1492,11 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
1486 struct sk_buff *skb; 1492 struct sk_buff *skb;
1487 1493
1488 spin_lock_bh(&rcvq->lock); 1494 spin_lock_bh(&rcvq->lock);
1489 while ((skb = skb_peek(rcvq)) != NULL) { 1495 while ((skb = skb_peek(rcvq)) != NULL &&
1490 if (udp_lib_checksum_complete(skb)) { 1496 udp_lib_checksum_complete(skb)) {
1491 UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite); 1497 UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite);
1492 __skb_unlink(skb, rcvq); 1498 __skb_unlink(skb, rcvq);
1493 kfree_skb(skb); 1499 kfree_skb(skb);
1494 } else {
1495 skb->ip_summed = CHECKSUM_UNNECESSARY;
1496 break;
1497 }
1498 } 1500 }
1499 spin_unlock_bh(&rcvq->lock); 1501 spin_unlock_bh(&rcvq->lock);
1500 1502
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index b28fe1edf98b..f34fd686a8f1 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -31,7 +31,7 @@ static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
31 31
32static int udplite_rcv(struct sk_buff *skb) 32static int udplite_rcv(struct sk_buff *skb)
33{ 33{
34 return __udp4_lib_rcv(skb, udplite_hash, 1); 34 return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
35} 35}
36 36
37static void udplite_err(struct sk_buff *skb, u32 info) 37static void udplite_err(struct sk_buff *skb, u32 info)
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/*
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 629f97162fbc..f54016a55004 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -19,7 +19,7 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly;
19 19
20static int udplitev6_rcv(struct sk_buff **pskb) 20static int udplitev6_rcv(struct sk_buff **pskb)
21{ 21{
22 return __udp6_lib_rcv(pskb, udplite_hash, 1); 22 return __udp6_lib_rcv(pskb, udplite_hash, IPPROTO_UDPLITE);
23} 23}
24 24
25static void udplitev6_err(struct sk_buff *skb, 25static void udplitev6_err(struct sk_buff *skb,