diff options
| -rw-r--r-- | include/linux/skbuff.h | 1 | ||||
| -rw-r--r-- | include/net/udp.h | 5 | ||||
| -rw-r--r-- | include/net/udplite.h | 39 | ||||
| -rw-r--r-- | net/core/datagram.c | 10 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 96 | ||||
| -rw-r--r-- | net/ipv4/udplite.c | 2 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 74 | ||||
| -rw-r--r-- | net/ipv6/udplite.c | 2 |
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 | ||
| 1375 | extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len); | ||
| 1375 | extern __sum16 __skb_checksum_complete(struct sk_buff *skb); | 1376 | extern __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 | */ |
| 73 | static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) | 73 | static 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 | ||
| 81 | static inline int udp_lib_checksum_complete(struct sk_buff *skb) | 78 | static 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 | ||
| 77 | static __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 | |||
| 88 | static __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 | |||
| 99 | static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) | 72 | static 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 | } |
| 426 | EXPORT_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 | } | ||
| 426 | EXPORT_SYMBOL(__skb_checksum_complete); | 432 | EXPORT_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 | ||
| 880 | out_free: | 879 | out_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 | */ |
| 1169 | static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh) | 1167 | static 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 | ||
| 1194 | int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], | 1203 | int __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 | ||
| 1263 | short_packet: | 1269 | short_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); |
| 1286 | drop: | 1292 | drop: |
| 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 | ||
| 1297 | int udp_destroy_sock(struct sock *sk) | 1303 | int 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 | ||
| 32 | static int udplite_rcv(struct sk_buff *skb) | 32 | static 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 | ||
| 37 | static void udplite_err(struct sk_buff *skb, u32 info) | 37 | static 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 | ||
| 199 | out_free: | 201 | out_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 | ||
| 371 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh) | 373 | static 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 | ||
| 395 | int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[], | 407 | int __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 | ||
| 476 | short_packet: | 485 | short_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 | ||
| 480 | discard: | 490 | discard: |
| 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 | ||
| 486 | static __inline__ int udpv6_rcv(struct sk_buff **pskb) | 496 | static __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 | ||
| 20 | static int udplitev6_rcv(struct sk_buff **pskb) | 20 | static 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 | ||
| 25 | static void udplitev6_err(struct sk_buff *skb, | 25 | static void udplitev6_err(struct sk_buff *skb, |
