aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c66
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
767static 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