diff options
author | tuexen <tuexen@FreeBSD.org> | 2014-05-05 17:30:05 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2014-05-05 17:30:05 +0000 |
commit | a83f2bfbbd6c98c7b7caac7e8efa18e49be0b241 (patch) | |
tree | a9d6461e181bf886177b0ce0204b211c631825b8 | |
parent | 204a407ff5ba304f6796196f87b75bd91286e712 (diff) | |
download | FreeBSD-src-a83f2bfbbd6c98c7b7caac7e8efa18e49be0b241.zip FreeBSD-src-a83f2bfbbd6c98c7b7caac7e8efa18e49be0b241.tar.gz |
Fill in csum_data only for UDP or TCP packets. This fixes a bug where
SCTP were reported to have always a correct checksum if they don't
contain any ethernet padding.
MFC after: 3 days
-rw-r--r-- | sys/dev/usb/net/if_smsc.c | 48 |
1 files changed, 29 insertions, 19 deletions
diff --git a/sys/dev/usb/net/if_smsc.c b/sys/dev/usb/net/if_smsc.c index 6a02925..55d3560 100644 --- a/sys/dev/usb/net/if_smsc.c +++ b/sys/dev/usb/net/if_smsc.c @@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> +#include <netinet/in.h> +#include <netinet/ip.h> + #include "opt_platform.h" #ifdef FDT @@ -1025,25 +1028,32 @@ smsc_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) * * Ignore H/W csum for non-IPv4 packets. */ - if (be16toh(eh->ether_type) == ETHERTYPE_IP && pktlen > ETHER_MIN_LEN) { - - /* Indicate the UDP/TCP csum has been calculated */ - m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; - - /* Copy the TCP/UDP checksum from the last 2 bytes - * of the transfer and put in the csum_data field. - */ - usbd_copy_out(pc, (off + pktlen), - &m->m_pkthdr.csum_data, 2); - - /* The data is copied in network order, but the - * csum algorithm in the kernel expects it to be - * in host network order. - */ - m->m_pkthdr.csum_data = ntohs(m->m_pkthdr.csum_data); - - smsc_dbg_printf(sc, "RX checksum offloaded (0x%04x)\n", - m->m_pkthdr.csum_data); + if ((be16toh(eh->ether_type) == ETHERTYPE_IP) && + (pktlen > ETHER_MIN_LEN)) { + struct ip *ip; + + ip = (struct ip *)(eh + 1); + if ((ip->ip_v == IPVERSION) && + ((ip->ip_p == IPPROTO_TCP) || + (ip->ip_p == IPPROTO_UDP))) { + /* Indicate the UDP/TCP csum has been calculated */ + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; + + /* Copy the TCP/UDP checksum from the last 2 bytes + * of the transfer and put in the csum_data field. + */ + usbd_copy_out(pc, (off + pktlen), + &m->m_pkthdr.csum_data, 2); + + /* The data is copied in network order, but the + * csum algorithm in the kernel expects it to be + * in host network order. + */ + m->m_pkthdr.csum_data = ntohs(m->m_pkthdr.csum_data); + + smsc_dbg_printf(sc, "RX checksum offloaded (0x%04x)\n", + m->m_pkthdr.csum_data); + } } /* Need to adjust the offset as well or we'll be off |