|
@@ -760,6 +760,17 @@ static void flush_stack(struct sock **stack, unsigned int count,
|
|
|
if (unlikely(skb1))
|
|
|
kfree_skb(skb1);
|
|
|
}
|
|
|
+
|
|
|
+static void udp6_csum_zero_error(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ /* RFC 2460 section 8.1 says that we SHOULD log
|
|
|
+ * this error. Well, it is reasonable.
|
|
|
+ */
|
|
|
+ LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
|
|
|
+ &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
|
|
|
+ &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Note: called only from the BH handler context,
|
|
|
* so we don't need to lock the hashes.
|
|
@@ -779,7 +790,12 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
|
|
|
dif = inet6_iif(skb);
|
|
|
sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
|
|
|
while (sk) {
|
|
|
- stack[count++] = sk;
|
|
|
+ /* If zero checksum and sk_no_check is not on for
|
|
|
+ * the socket then skip it.
|
|
|
+ */
|
|
|
+ if (uh->check || sk->sk_no_check)
|
|
|
+ stack[count++] = sk;
|
|
|
+
|
|
|
sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr,
|
|
|
uh->source, saddr, dif);
|
|
|
if (unlikely(count == ARRAY_SIZE(stack))) {
|
|
@@ -867,6 +883,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|
|
if (sk != NULL) {
|
|
|
int ret;
|
|
|
|
|
|
+ if (!uh->check && !sk->sk_no_check) {
|
|
|
+ udp6_csum_zero_error(skb);
|
|
|
+ goto csum_error;
|
|
|
+ }
|
|
|
+
|
|
|
ret = udpv6_queue_rcv_skb(sk, skb);
|
|
|
sock_put(sk);
|
|
|
|
|
@@ -879,6 +900,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ if (!uh->check) {
|
|
|
+ udp6_csum_zero_error(skb);
|
|
|
+ goto csum_error;
|
|
|
+ }
|
|
|
+
|
|
|
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
|
|
|
goto discard;
|
|
|
|
|
@@ -1006,7 +1032,10 @@ static int udp_v6_push_pending_frames(struct sock *sk)
|
|
|
|
|
|
if (is_udplite)
|
|
|
csum = udplite_csum_outgoing(sk, skb);
|
|
|
- else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
|
|
|
+ else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */
|
|
|
+ skb->ip_summed = CHECKSUM_NONE;
|
|
|
+ goto send;
|
|
|
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */
|
|
|
udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr,
|
|
|
up->len);
|
|
|
goto send;
|