diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/datagram.c | 8 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 4 | ||||
-rw-r--r-- | net/ipv6/ping.c | 3 | ||||
-rw-r--r-- | net/ipv6/protocol.c | 4 | ||||
-rw-r--r-- | net/ipv6/raw.c | 4 | ||||
-rw-r--r-- | net/ipv6/sit.c | 50 | ||||
-rw-r--r-- | net/ipv6/tcpv6_offload.c | 32 | ||||
-rw-r--r-- | net/ipv6/udp.c | 4 |
8 files changed, 70 insertions, 39 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index a454b0ff57c7..8dfe1f4d3c1a 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -318,7 +318,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu) | |||
318 | /* | 318 | /* |
319 | * Handle MSG_ERRQUEUE | 319 | * Handle MSG_ERRQUEUE |
320 | */ | 320 | */ |
321 | int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | 321 | int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) |
322 | { | 322 | { |
323 | struct ipv6_pinfo *np = inet6_sk(sk); | 323 | struct ipv6_pinfo *np = inet6_sk(sk); |
324 | struct sock_exterr_skb *serr; | 324 | struct sock_exterr_skb *serr; |
@@ -369,6 +369,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
369 | &sin->sin6_addr); | 369 | &sin->sin6_addr); |
370 | sin->sin6_scope_id = 0; | 370 | sin->sin6_scope_id = 0; |
371 | } | 371 | } |
372 | *addr_len = sizeof(*sin); | ||
372 | } | 373 | } |
373 | 374 | ||
374 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 375 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
@@ -377,6 +378,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
377 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { | 378 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { |
378 | sin->sin6_family = AF_INET6; | 379 | sin->sin6_family = AF_INET6; |
379 | sin->sin6_flowinfo = 0; | 380 | sin->sin6_flowinfo = 0; |
381 | sin->sin6_port = 0; | ||
380 | if (skb->protocol == htons(ETH_P_IPV6)) { | 382 | if (skb->protocol == htons(ETH_P_IPV6)) { |
381 | sin->sin6_addr = ipv6_hdr(skb)->saddr; | 383 | sin->sin6_addr = ipv6_hdr(skb)->saddr; |
382 | if (np->rxopt.all) | 384 | if (np->rxopt.all) |
@@ -423,7 +425,8 @@ EXPORT_SYMBOL_GPL(ipv6_recv_error); | |||
423 | /* | 425 | /* |
424 | * Handle IPV6_RECVPATHMTU | 426 | * Handle IPV6_RECVPATHMTU |
425 | */ | 427 | */ |
426 | int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len) | 428 | int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, |
429 | int *addr_len) | ||
427 | { | 430 | { |
428 | struct ipv6_pinfo *np = inet6_sk(sk); | 431 | struct ipv6_pinfo *np = inet6_sk(sk); |
429 | struct sk_buff *skb; | 432 | struct sk_buff *skb; |
@@ -457,6 +460,7 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len) | |||
457 | sin->sin6_port = 0; | 460 | sin->sin6_port = 0; |
458 | sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; | 461 | sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; |
459 | sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr; | 462 | sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr; |
463 | *addr_len = sizeof(*sin); | ||
460 | } | 464 | } |
461 | 465 | ||
462 | put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); | 466 | put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 59df872e2f4d..4acdb63495db 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -116,8 +116,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
116 | } | 116 | } |
117 | rcu_read_unlock_bh(); | 117 | rcu_read_unlock_bh(); |
118 | 118 | ||
119 | IP6_INC_STATS_BH(dev_net(dst->dev), | 119 | IP6_INC_STATS(dev_net(dst->dev), |
120 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 120 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
121 | kfree_skb(skb); | 121 | kfree_skb(skb); |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | } | 123 | } |
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 8815e31a87fe..a83243c3d656 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
@@ -57,7 +57,8 @@ static struct inet_protosw pingv6_protosw = { | |||
57 | 57 | ||
58 | 58 | ||
59 | /* Compatibility glue so we can support IPv6 when it's compiled as a module */ | 59 | /* Compatibility glue so we can support IPv6 when it's compiled as a module */ |
60 | static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | 60 | static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, |
61 | int *addr_len) | ||
61 | { | 62 | { |
62 | return -EAFNOSUPPORT; | 63 | return -EAFNOSUPPORT; |
63 | } | 64 | } |
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 22d1bd4670da..e048cf1bb6a2 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -36,10 +36,6 @@ int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
36 | } | 36 | } |
37 | EXPORT_SYMBOL(inet6_add_protocol); | 37 | EXPORT_SYMBOL(inet6_add_protocol); |
38 | 38 | ||
39 | /* | ||
40 | * Remove a protocol from the hash tables. | ||
41 | */ | ||
42 | |||
43 | int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 39 | int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
44 | { | 40 | { |
45 | int ret; | 41 | int ret; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e24ff1df0401..7fb4e14c467f 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -466,10 +466,10 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
466 | return -EOPNOTSUPP; | 466 | return -EOPNOTSUPP; |
467 | 467 | ||
468 | if (flags & MSG_ERRQUEUE) | 468 | if (flags & MSG_ERRQUEUE) |
469 | return ipv6_recv_error(sk, msg, len); | 469 | return ipv6_recv_error(sk, msg, len, addr_len); |
470 | 470 | ||
471 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) | 471 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) |
472 | return ipv6_recv_rxpmtu(sk, msg, len); | 472 | return ipv6_recv_rxpmtu(sk, msg, len, addr_len); |
473 | 473 | ||
474 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 474 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
475 | if (!skb) | 475 | if (!skb) |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1b4a4a953675..366fbba3359a 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -478,14 +478,44 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
478 | dev_put(dev); | 478 | dev_put(dev); |
479 | } | 479 | } |
480 | 480 | ||
481 | /* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH | ||
482 | * if sufficient data bytes are available | ||
483 | */ | ||
484 | static int ipip6_err_gen_icmpv6_unreach(struct sk_buff *skb) | ||
485 | { | ||
486 | const struct iphdr *iph = (const struct iphdr *) skb->data; | ||
487 | struct rt6_info *rt; | ||
488 | struct sk_buff *skb2; | ||
489 | |||
490 | if (!pskb_may_pull(skb, iph->ihl * 4 + sizeof(struct ipv6hdr) + 8)) | ||
491 | return 1; | ||
492 | |||
493 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
494 | |||
495 | if (!skb2) | ||
496 | return 1; | ||
497 | |||
498 | skb_dst_drop(skb2); | ||
499 | skb_pull(skb2, iph->ihl * 4); | ||
500 | skb_reset_network_header(skb2); | ||
501 | |||
502 | rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); | ||
503 | |||
504 | if (rt && rt->dst.dev) | ||
505 | skb2->dev = rt->dst.dev; | ||
506 | |||
507 | icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); | ||
508 | |||
509 | if (rt) | ||
510 | ip6_rt_put(rt); | ||
511 | |||
512 | kfree_skb(skb2); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
481 | 516 | ||
482 | static int ipip6_err(struct sk_buff *skb, u32 info) | 517 | static int ipip6_err(struct sk_buff *skb, u32 info) |
483 | { | 518 | { |
484 | |||
485 | /* All the routers (except for Linux) return only | ||
486 | 8 bytes of packet payload. It means, that precise relaying of | ||
487 | ICMP in the real Internet is absolutely infeasible. | ||
488 | */ | ||
489 | const struct iphdr *iph = (const struct iphdr *)skb->data; | 519 | const struct iphdr *iph = (const struct iphdr *)skb->data; |
490 | const int type = icmp_hdr(skb)->type; | 520 | const int type = icmp_hdr(skb)->type; |
491 | const int code = icmp_hdr(skb)->code; | 521 | const int code = icmp_hdr(skb)->code; |
@@ -500,7 +530,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
500 | case ICMP_DEST_UNREACH: | 530 | case ICMP_DEST_UNREACH: |
501 | switch (code) { | 531 | switch (code) { |
502 | case ICMP_SR_FAILED: | 532 | case ICMP_SR_FAILED: |
503 | case ICMP_PORT_UNREACH: | ||
504 | /* Impossible event. */ | 533 | /* Impossible event. */ |
505 | return 0; | 534 | return 0; |
506 | default: | 535 | default: |
@@ -545,6 +574,9 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
545 | goto out; | 574 | goto out; |
546 | 575 | ||
547 | err = 0; | 576 | err = 0; |
577 | if (!ipip6_err_gen_icmpv6_unreach(skb)) | ||
578 | goto out; | ||
579 | |||
548 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) | 580 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) |
549 | goto out; | 581 | goto out; |
550 | 582 | ||
@@ -919,7 +951,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
919 | if (!new_skb) { | 951 | if (!new_skb) { |
920 | ip_rt_put(rt); | 952 | ip_rt_put(rt); |
921 | dev->stats.tx_dropped++; | 953 | dev->stats.tx_dropped++; |
922 | dev_kfree_skb(skb); | 954 | kfree_skb(skb); |
923 | return NETDEV_TX_OK; | 955 | return NETDEV_TX_OK; |
924 | } | 956 | } |
925 | if (skb->sk) | 957 | if (skb->sk) |
@@ -945,7 +977,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
945 | tx_error_icmp: | 977 | tx_error_icmp: |
946 | dst_link_failure(skb); | 978 | dst_link_failure(skb); |
947 | tx_error: | 979 | tx_error: |
948 | dev_kfree_skb(skb); | 980 | kfree_skb(skb); |
949 | out: | 981 | out: |
950 | dev->stats.tx_errors++; | 982 | dev->stats.tx_errors++; |
951 | return NETDEV_TX_OK; | 983 | return NETDEV_TX_OK; |
@@ -985,7 +1017,7 @@ static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, | |||
985 | 1017 | ||
986 | tx_err: | 1018 | tx_err: |
987 | dev->stats.tx_errors++; | 1019 | dev->stats.tx_errors++; |
988 | dev_kfree_skb(skb); | 1020 | kfree_skb(skb); |
989 | return NETDEV_TX_OK; | 1021 | return NETDEV_TX_OK; |
990 | 1022 | ||
991 | } | 1023 | } |
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index c1097c798900..6d18157dc32c 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c | |||
@@ -37,34 +37,32 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | |||
37 | { | 37 | { |
38 | const struct ipv6hdr *iph = skb_gro_network_header(skb); | 38 | const struct ipv6hdr *iph = skb_gro_network_header(skb); |
39 | __wsum wsum; | 39 | __wsum wsum; |
40 | __sum16 sum; | 40 | |
41 | /* Don't bother verifying checksum if we're going to flush anyway. */ | ||
42 | if (NAPI_GRO_CB(skb)->flush) | ||
43 | goto skip_csum; | ||
44 | |||
45 | wsum = skb->csum; | ||
41 | 46 | ||
42 | switch (skb->ip_summed) { | 47 | switch (skb->ip_summed) { |
48 | case CHECKSUM_NONE: | ||
49 | wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), | ||
50 | wsum); | ||
51 | |||
52 | /* fall through */ | ||
53 | |||
43 | case CHECKSUM_COMPLETE: | 54 | case CHECKSUM_COMPLETE: |
44 | if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, | 55 | if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, |
45 | skb->csum)) { | 56 | wsum)) { |
46 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 57 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
47 | break; | 58 | break; |
48 | } | 59 | } |
49 | flush: | 60 | |
50 | NAPI_GRO_CB(skb)->flush = 1; | 61 | NAPI_GRO_CB(skb)->flush = 1; |
51 | return NULL; | 62 | return NULL; |
52 | |||
53 | case CHECKSUM_NONE: | ||
54 | wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, | ||
55 | skb_gro_len(skb), | ||
56 | IPPROTO_TCP, 0)); | ||
57 | sum = csum_fold(skb_checksum(skb, | ||
58 | skb_gro_offset(skb), | ||
59 | skb_gro_len(skb), | ||
60 | wsum)); | ||
61 | if (sum) | ||
62 | goto flush; | ||
63 | |||
64 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
65 | break; | ||
66 | } | 63 | } |
67 | 64 | ||
65 | skip_csum: | ||
68 | return tcp_gro_receive(head, skb); | 66 | return tcp_gro_receive(head, skb); |
69 | } | 67 | } |
70 | 68 | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 81eb8cf8389b..bcd5699313c3 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -393,10 +393,10 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
393 | bool slow; | 393 | bool slow; |
394 | 394 | ||
395 | if (flags & MSG_ERRQUEUE) | 395 | if (flags & MSG_ERRQUEUE) |
396 | return ipv6_recv_error(sk, msg, len); | 396 | return ipv6_recv_error(sk, msg, len, addr_len); |
397 | 397 | ||
398 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) | 398 | if (np->rxpmtu && np->rxopt.bits.rxpmtu) |
399 | return ipv6_recv_rxpmtu(sk, msg, len); | 399 | return ipv6_recv_rxpmtu(sk, msg, len, addr_len); |
400 | 400 | ||
401 | try_again: | 401 | try_again: |
402 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), | 402 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |