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
This commit is contained in:
tuexen 2014-05-05 17:30:05 +00:00
parent 204a407ff5
commit a83f2bfbbd

View File

@ -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