Under IPv4, when I send a UDP packet with invalid checksum, kernel used
udp_rcv() to up packet to UDP layer, application used udp_recvmsg to
receive message. So if one UDP packet with invalid checksum is arrived
to host, UDP_MIB_INDATAGRAMS will be increased 1, UDP_MIB_INERRORS
should be increased 1.
int udp_rcv(struct sk_buff *skb) {
    ...
    udp_queue_rcv_skb();
    ...
}

static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) {
    ...
    if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
         if (__udp_checksum_complete(skb)) {
         UDP_INC_STATS_BH(UDP_MIB_INERRORS);
         kfree_skb(skb);
         return -1;
        }
        skb->ip_summed = CHECKSUM_UNNECESSARY;
    }
    ....
    UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
    ...
}

static int udp_recvmsg(...) {
    ...
csum_copy_err:
    UDP_INC_STATS_BH(UDP_MIB_INERRORS);
    ...
}

In my test, I send a to a IPv4 UDP packet with invalid checksum to echo-
udp, I can find the following message in file /var/log/messages:
xinetd[4468]: service echo-dgram, recvfrom: Resource temporarily
unavailable (errno = 11)
and UDP_MIB_INDATAGRAMS increased 1, UDP_MIB_INERRORS increased 0.
xinetd used other fucntion to receive message, not udp_recvmsg()?

The other question is why discard the packet with invalid checksum only
when sk->sk_filter is set?

By the way, under IPv6, packet with invalid checksum be discard in
udpv6_rcv(), so So if one UDP packet with invalid checksum is arrived to
IPv6 host, UDP_MIB_INDATAGRAMS will be increased 0, UDP_MIB_INERRORS
should be increased 1.

static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) {
    ...
    udpv6_queue_rcv_skb();
    ...
}

static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff
*skb) {
    ...
    if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
         if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len,
skb->csum))) {
             UDP6_INC_STATS_BH(UDP_MIB_INERRORS);
             kfree_skb(skb);
            return 0;
         }
         skb->ip_summed = CHECKSUM_UNNECESSARY;
    }
    ...
    UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
    ...
}

One packet with invalid checksum arrived to IPv4 and IPv6 host, the
count of UDP_MIB_INDATAGRAMS and UDP_MIB_INERRORS get different
increase. There definition of the two count are some difference between
IPv4 and IPv6?


> > IPv4 UDP does not discard the datagram with invalid checksum. UDP can
> > validate UDP checksums correctly only when socket filtering
> instructions
> > is set. If socket filtering instructions is not set, datagram with
> > invalid checksum will be passed to the application.
> 
> We check the checksum later, in parallel with the copy of
> the packet data into userspace.
> 
> See udp_recvmsg(), where we do this:
> 
>         if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
>                 err = skb_copy_datagram_iovec(skb, sizeof(struct
> udphdr), msg->msg_iov,
>                                               copied);
>         } else if (msg->msg_flags&MSG_TRUNC) {
>                 if (__udp_checksum_complete(skb))
>                         goto csum_copy_err;
>                 err = skb_copy_datagram_iovec(skb, sizeof(struct
> udphdr), msg->msg_iov,
>                                               copied);
>         } else {
>                 err = skb_copy_and_csum_datagram_iovec(skb, sizeof
> (struct udphdr), msg->msg_iov);
> 
>                 if (err == -EINVAL)
>                         goto csum_copy_err;
>         }


-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to