diff options
Diffstat (limited to 'net/ipv6/udp.c')
| -rw-r--r-- | net/ipv6/udp.c | 66 |
1 files changed, 46 insertions, 20 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1e586d92260e..95c834799288 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -634,6 +634,10 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 634 | if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { | 634 | if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { |
| 635 | int ret; | 635 | int ret; |
| 636 | 636 | ||
| 637 | /* Verify checksum before giving to encap */ | ||
| 638 | if (udp_lib_checksum_complete(skb)) | ||
| 639 | goto csum_error; | ||
| 640 | |||
| 637 | ret = encap_rcv(sk, skb); | 641 | ret = encap_rcv(sk, skb); |
| 638 | if (ret <= 0) { | 642 | if (ret <= 0) { |
| 639 | UDP_INC_STATS_BH(sock_net(sk), | 643 | UDP_INC_STATS_BH(sock_net(sk), |
| @@ -701,17 +705,16 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
| 701 | int dif) | 705 | int dif) |
| 702 | { | 706 | { |
| 703 | struct hlist_nulls_node *node; | 707 | struct hlist_nulls_node *node; |
| 704 | struct sock *s = sk; | ||
| 705 | unsigned short num = ntohs(loc_port); | 708 | unsigned short num = ntohs(loc_port); |
| 706 | 709 | ||
| 707 | sk_nulls_for_each_from(s, node) { | 710 | sk_nulls_for_each_from(sk, node) { |
| 708 | struct inet_sock *inet = inet_sk(s); | 711 | struct inet_sock *inet = inet_sk(sk); |
| 709 | 712 | ||
| 710 | if (!net_eq(sock_net(s), net)) | 713 | if (!net_eq(sock_net(sk), net)) |
| 711 | continue; | 714 | continue; |
| 712 | 715 | ||
| 713 | if (udp_sk(s)->udp_port_hash == num && | 716 | if (udp_sk(sk)->udp_port_hash == num && |
| 714 | s->sk_family == PF_INET6) { | 717 | sk->sk_family == PF_INET6) { |
| 715 | if (inet->inet_dport) { | 718 | if (inet->inet_dport) { |
| 716 | if (inet->inet_dport != rmt_port) | 719 | if (inet->inet_dport != rmt_port) |
| 717 | continue; | 720 | continue; |
| @@ -720,16 +723,16 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
| 720 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) | 723 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) |
| 721 | continue; | 724 | continue; |
| 722 | 725 | ||
| 723 | if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) | 726 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) |
| 724 | continue; | 727 | continue; |
| 725 | 728 | ||
| 726 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { | 729 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
| 727 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) | 730 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) |
| 728 | continue; | 731 | continue; |
| 729 | } | 732 | } |
| 730 | if (!inet6_mc_check(s, loc_addr, rmt_addr)) | 733 | if (!inet6_mc_check(sk, loc_addr, rmt_addr)) |
| 731 | continue; | 734 | continue; |
| 732 | return s; | 735 | return sk; |
| 733 | } | 736 | } |
| 734 | } | 737 | } |
| 735 | return NULL; | 738 | return NULL; |
| @@ -760,6 +763,17 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
| 760 | if (unlikely(skb1)) | 763 | if (unlikely(skb1)) |
| 761 | kfree_skb(skb1); | 764 | kfree_skb(skb1); |
| 762 | } | 765 | } |
| 766 | |||
| 767 | static void udp6_csum_zero_error(struct sk_buff *skb) | ||
| 768 | { | ||
| 769 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
| 770 | * this error. Well, it is reasonable. | ||
| 771 | */ | ||
| 772 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", | ||
| 773 | &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), | ||
| 774 | &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); | ||
| 775 | } | ||
| 776 | |||
| 763 | /* | 777 | /* |
| 764 | * Note: called only from the BH handler context, | 778 | * Note: called only from the BH handler context, |
| 765 | * so we don't need to lock the hashes. | 779 | * so we don't need to lock the hashes. |
| @@ -779,7 +793,12 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
| 779 | dif = inet6_iif(skb); | 793 | dif = inet6_iif(skb); |
| 780 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); | 794 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); |
| 781 | while (sk) { | 795 | while (sk) { |
| 782 | stack[count++] = sk; | 796 | /* If zero checksum and no_check is not on for |
| 797 | * the socket then skip it. | ||
| 798 | */ | ||
| 799 | if (uh->check || udp_sk(sk)->no_check6_rx) | ||
| 800 | stack[count++] = sk; | ||
| 801 | |||
| 783 | sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, | 802 | sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, |
| 784 | uh->source, saddr, dif); | 803 | uh->source, saddr, dif); |
| 785 | if (unlikely(count == ARRAY_SIZE(stack))) { | 804 | if (unlikely(count == ARRAY_SIZE(stack))) { |
| @@ -867,6 +886,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
| 867 | if (sk != NULL) { | 886 | if (sk != NULL) { |
| 868 | int ret; | 887 | int ret; |
| 869 | 888 | ||
| 889 | if (!uh->check && !udp_sk(sk)->no_check6_rx) { | ||
| 890 | sock_put(sk); | ||
| 891 | udp6_csum_zero_error(skb); | ||
| 892 | goto csum_error; | ||
| 893 | } | ||
| 894 | |||
| 870 | ret = udpv6_queue_rcv_skb(sk, skb); | 895 | ret = udpv6_queue_rcv_skb(sk, skb); |
| 871 | sock_put(sk); | 896 | sock_put(sk); |
| 872 | 897 | ||
| @@ -879,6 +904,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
| 879 | return 0; | 904 | return 0; |
| 880 | } | 905 | } |
| 881 | 906 | ||
| 907 | if (!uh->check) { | ||
| 908 | udp6_csum_zero_error(skb); | ||
| 909 | goto csum_error; | ||
| 910 | } | ||
| 911 | |||
| 882 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 912 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
| 883 | goto discard; | 913 | goto discard; |
| 884 | 914 | ||
| @@ -1006,7 +1036,10 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
| 1006 | 1036 | ||
| 1007 | if (is_udplite) | 1037 | if (is_udplite) |
| 1008 | csum = udplite_csum_outgoing(sk, skb); | 1038 | csum = udplite_csum_outgoing(sk, skb); |
| 1009 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | 1039 | else if (up->no_check6_tx) { /* UDP csum disabled */ |
| 1040 | skb->ip_summed = CHECKSUM_NONE; | ||
| 1041 | goto send; | ||
| 1042 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | ||
| 1010 | udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, | 1043 | udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, |
| 1011 | up->len); | 1044 | up->len); |
| 1012 | goto send; | 1045 | goto send; |
| @@ -1232,14 +1265,8 @@ do_udp_sendmsg: | |||
| 1232 | goto out; | 1265 | goto out; |
| 1233 | } | 1266 | } |
| 1234 | 1267 | ||
| 1235 | if (hlimit < 0) { | 1268 | if (hlimit < 0) |
| 1236 | if (ipv6_addr_is_multicast(&fl6.daddr)) | 1269 | hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); |
| 1237 | hlimit = np->mcast_hops; | ||
| 1238 | else | ||
| 1239 | hlimit = np->hop_limit; | ||
| 1240 | if (hlimit < 0) | ||
| 1241 | hlimit = ip6_dst_hoplimit(dst); | ||
| 1242 | } | ||
| 1243 | 1270 | ||
| 1244 | if (tclass < 0) | 1271 | if (tclass < 0) |
| 1245 | tclass = np->tclass; | 1272 | tclass = np->tclass; |
| @@ -1479,7 +1506,6 @@ static struct inet_protosw udpv6_protosw = { | |||
| 1479 | .protocol = IPPROTO_UDP, | 1506 | .protocol = IPPROTO_UDP, |
| 1480 | .prot = &udpv6_prot, | 1507 | .prot = &udpv6_prot, |
| 1481 | .ops = &inet6_dgram_ops, | 1508 | .ops = &inet6_dgram_ops, |
| 1482 | .no_check = UDP_CSUM_DEFAULT, | ||
| 1483 | .flags = INET_PROTOSW_PERMANENT, | 1509 | .flags = INET_PROTOSW_PERMANENT, |
| 1484 | }; | 1510 | }; |
| 1485 | 1511 | ||
