diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 139 |
1 files changed, 108 insertions, 31 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0a073a263720..0ae038a4c7a8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -902,9 +902,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
902 | ipc.addr = inet->inet_saddr; | 902 | ipc.addr = inet->inet_saddr; |
903 | 903 | ||
904 | ipc.oif = sk->sk_bound_dev_if; | 904 | ipc.oif = sk->sk_bound_dev_if; |
905 | err = sock_tx_timestamp(sk, &ipc.tx_flags); | 905 | |
906 | if (err) | 906 | sock_tx_timestamp(sk, &ipc.tx_flags); |
907 | return err; | 907 | |
908 | if (msg->msg_controllen) { | 908 | if (msg->msg_controllen) { |
909 | err = ip_cmsg_send(sock_net(sk), msg, &ipc); | 909 | err = ip_cmsg_send(sock_net(sk), msg, &ipc); |
910 | if (err) | 910 | if (err) |
@@ -1131,6 +1131,8 @@ static unsigned int first_packet_length(struct sock *sk) | |||
1131 | spin_lock_bh(&rcvq->lock); | 1131 | spin_lock_bh(&rcvq->lock); |
1132 | while ((skb = skb_peek(rcvq)) != NULL && | 1132 | while ((skb = skb_peek(rcvq)) != NULL && |
1133 | udp_lib_checksum_complete(skb)) { | 1133 | udp_lib_checksum_complete(skb)) { |
1134 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, | ||
1135 | IS_UDPLITE(sk)); | ||
1134 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, | 1136 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, |
1135 | IS_UDPLITE(sk)); | 1137 | IS_UDPLITE(sk)); |
1136 | atomic_inc(&sk->sk_drops); | 1138 | atomic_inc(&sk->sk_drops); |
@@ -1286,8 +1288,10 @@ out: | |||
1286 | 1288 | ||
1287 | csum_copy_err: | 1289 | csum_copy_err: |
1288 | slow = lock_sock_fast(sk); | 1290 | slow = lock_sock_fast(sk); |
1289 | if (!skb_kill_datagram(sk, skb, flags)) | 1291 | if (!skb_kill_datagram(sk, skb, flags)) { |
1292 | UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); | ||
1290 | UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); | 1293 | UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite); |
1294 | } | ||
1291 | unlock_sock_fast(sk, slow); | 1295 | unlock_sock_fast(sk, slow); |
1292 | 1296 | ||
1293 | if (noblock) | 1297 | if (noblock) |
@@ -1513,7 +1517,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
1513 | 1517 | ||
1514 | if (rcu_access_pointer(sk->sk_filter) && | 1518 | if (rcu_access_pointer(sk->sk_filter) && |
1515 | udp_lib_checksum_complete(skb)) | 1519 | udp_lib_checksum_complete(skb)) |
1516 | goto drop; | 1520 | goto csum_error; |
1517 | 1521 | ||
1518 | 1522 | ||
1519 | if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) | 1523 | if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) |
@@ -1533,6 +1537,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
1533 | 1537 | ||
1534 | return rc; | 1538 | return rc; |
1535 | 1539 | ||
1540 | csum_error: | ||
1541 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); | ||
1536 | drop: | 1542 | drop: |
1537 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); | 1543 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); |
1538 | atomic_inc(&sk->sk_drops); | 1544 | atomic_inc(&sk->sk_drops); |
@@ -1749,6 +1755,7 @@ csum_error: | |||
1749 | proto == IPPROTO_UDPLITE ? "Lite" : "", | 1755 | proto == IPPROTO_UDPLITE ? "Lite" : "", |
1750 | &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), | 1756 | &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), |
1751 | ulen); | 1757 | ulen); |
1758 | UDP_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); | ||
1752 | drop: | 1759 | drop: |
1753 | UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); | 1760 | UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); |
1754 | kfree_skb(skb); | 1761 | kfree_skb(skb); |
@@ -2093,7 +2100,7 @@ static void udp_seq_stop(struct seq_file *seq, void *v) | |||
2093 | 2100 | ||
2094 | int udp_seq_open(struct inode *inode, struct file *file) | 2101 | int udp_seq_open(struct inode *inode, struct file *file) |
2095 | { | 2102 | { |
2096 | struct udp_seq_afinfo *afinfo = PDE(inode)->data; | 2103 | struct udp_seq_afinfo *afinfo = PDE_DATA(inode); |
2097 | struct udp_iter_state *s; | 2104 | struct udp_iter_state *s; |
2098 | int err; | 2105 | int err; |
2099 | 2106 | ||
@@ -2279,31 +2286,93 @@ void __init udp_init(void) | |||
2279 | 2286 | ||
2280 | int udp4_ufo_send_check(struct sk_buff *skb) | 2287 | int udp4_ufo_send_check(struct sk_buff *skb) |
2281 | { | 2288 | { |
2282 | const struct iphdr *iph; | 2289 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
2283 | struct udphdr *uh; | ||
2284 | |||
2285 | if (!pskb_may_pull(skb, sizeof(*uh))) | ||
2286 | return -EINVAL; | 2290 | return -EINVAL; |
2287 | 2291 | ||
2288 | iph = ip_hdr(skb); | 2292 | if (likely(!skb->encapsulation)) { |
2289 | uh = udp_hdr(skb); | 2293 | const struct iphdr *iph; |
2294 | struct udphdr *uh; | ||
2295 | |||
2296 | iph = ip_hdr(skb); | ||
2297 | uh = udp_hdr(skb); | ||
2290 | 2298 | ||
2291 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, | 2299 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, |
2292 | IPPROTO_UDP, 0); | 2300 | IPPROTO_UDP, 0); |
2293 | skb->csum_start = skb_transport_header(skb) - skb->head; | 2301 | skb->csum_start = skb_transport_header(skb) - skb->head; |
2294 | skb->csum_offset = offsetof(struct udphdr, check); | 2302 | skb->csum_offset = offsetof(struct udphdr, check); |
2295 | skb->ip_summed = CHECKSUM_PARTIAL; | 2303 | skb->ip_summed = CHECKSUM_PARTIAL; |
2304 | } | ||
2296 | return 0; | 2305 | return 0; |
2297 | } | 2306 | } |
2298 | 2307 | ||
2308 | static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | ||
2309 | netdev_features_t features) | ||
2310 | { | ||
2311 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
2312 | int mac_len = skb->mac_len; | ||
2313 | int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); | ||
2314 | struct ethhdr *inner_eth = (struct ethhdr *)skb_inner_mac_header(skb); | ||
2315 | __be16 protocol = skb->protocol; | ||
2316 | netdev_features_t enc_features; | ||
2317 | int outer_hlen; | ||
2318 | |||
2319 | if (unlikely(!pskb_may_pull(skb, tnl_hlen))) | ||
2320 | goto out; | ||
2321 | |||
2322 | skb->encapsulation = 0; | ||
2323 | __skb_pull(skb, tnl_hlen); | ||
2324 | skb_reset_mac_header(skb); | ||
2325 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
2326 | skb->mac_len = skb_inner_network_offset(skb); | ||
2327 | inner_eth = (struct ethhdr *)skb_mac_header(skb); | ||
2328 | skb->protocol = inner_eth->h_proto; | ||
2329 | |||
2330 | /* segment inner packet. */ | ||
2331 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
2332 | segs = skb_mac_gso_segment(skb, enc_features); | ||
2333 | if (!segs || IS_ERR(segs)) | ||
2334 | goto out; | ||
2335 | |||
2336 | outer_hlen = skb_tnl_header_len(skb); | ||
2337 | skb = segs; | ||
2338 | do { | ||
2339 | struct udphdr *uh; | ||
2340 | int udp_offset = outer_hlen - tnl_hlen; | ||
2341 | |||
2342 | skb->mac_len = mac_len; | ||
2343 | |||
2344 | skb_push(skb, outer_hlen); | ||
2345 | skb_reset_mac_header(skb); | ||
2346 | skb_set_network_header(skb, mac_len); | ||
2347 | skb_set_transport_header(skb, udp_offset); | ||
2348 | uh = udp_hdr(skb); | ||
2349 | uh->len = htons(skb->len - udp_offset); | ||
2350 | |||
2351 | /* csum segment if tunnel sets skb with csum. */ | ||
2352 | if (unlikely(uh->check)) { | ||
2353 | struct iphdr *iph = ip_hdr(skb); | ||
2354 | |||
2355 | uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
2356 | skb->len - udp_offset, | ||
2357 | IPPROTO_UDP, 0); | ||
2358 | uh->check = csum_fold(skb_checksum(skb, udp_offset, | ||
2359 | skb->len - udp_offset, 0)); | ||
2360 | if (uh->check == 0) | ||
2361 | uh->check = CSUM_MANGLED_0; | ||
2362 | |||
2363 | } | ||
2364 | skb->ip_summed = CHECKSUM_NONE; | ||
2365 | skb->protocol = protocol; | ||
2366 | } while ((skb = skb->next)); | ||
2367 | out: | ||
2368 | return segs; | ||
2369 | } | ||
2370 | |||
2299 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | 2371 | struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, |
2300 | netdev_features_t features) | 2372 | netdev_features_t features) |
2301 | { | 2373 | { |
2302 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 2374 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
2303 | unsigned int mss; | 2375 | unsigned int mss; |
2304 | int offset; | ||
2305 | __wsum csum; | ||
2306 | |||
2307 | mss = skb_shinfo(skb)->gso_size; | 2376 | mss = skb_shinfo(skb)->gso_size; |
2308 | if (unlikely(skb->len <= mss)) | 2377 | if (unlikely(skb->len <= mss)) |
2309 | goto out; | 2378 | goto out; |
@@ -2313,6 +2382,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
2313 | int type = skb_shinfo(skb)->gso_type; | 2382 | int type = skb_shinfo(skb)->gso_type; |
2314 | 2383 | ||
2315 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | 2384 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | |
2385 | SKB_GSO_UDP_TUNNEL | | ||
2316 | SKB_GSO_GRE) || | 2386 | SKB_GSO_GRE) || |
2317 | !(type & (SKB_GSO_UDP)))) | 2387 | !(type & (SKB_GSO_UDP)))) |
2318 | goto out; | 2388 | goto out; |
@@ -2323,20 +2393,27 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
2323 | goto out; | 2393 | goto out; |
2324 | } | 2394 | } |
2325 | 2395 | ||
2326 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | ||
2327 | * do checksum of UDP packets sent as multiple IP fragments. | ||
2328 | */ | ||
2329 | offset = skb_checksum_start_offset(skb); | ||
2330 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
2331 | offset += skb->csum_offset; | ||
2332 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
2333 | skb->ip_summed = CHECKSUM_NONE; | ||
2334 | |||
2335 | /* Fragment the skb. IP headers of the fragments are updated in | 2396 | /* Fragment the skb. IP headers of the fragments are updated in |
2336 | * inet_gso_segment() | 2397 | * inet_gso_segment() |
2337 | */ | 2398 | */ |
2338 | segs = skb_segment(skb, features); | 2399 | if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) |
2400 | segs = skb_udp_tunnel_segment(skb, features); | ||
2401 | else { | ||
2402 | int offset; | ||
2403 | __wsum csum; | ||
2404 | |||
2405 | /* Do software UFO. Complete and fill in the UDP checksum as | ||
2406 | * HW cannot do checksum of UDP packets sent as multiple | ||
2407 | * IP fragments. | ||
2408 | */ | ||
2409 | offset = skb_checksum_start_offset(skb); | ||
2410 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | ||
2411 | offset += skb->csum_offset; | ||
2412 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | ||
2413 | skb->ip_summed = CHECKSUM_NONE; | ||
2414 | |||
2415 | segs = skb_segment(skb, features); | ||
2416 | } | ||
2339 | out: | 2417 | out: |
2340 | return segs; | 2418 | return segs; |
2341 | } | 2419 | } |
2342 | |||