Module Name: src Committed By: tsutsui Date: Sun Mar 29 07:33:53 UTC 2009
Modified Files: src/sys/dev/ic: hme.c Log Message: Don't assume all RX packets have VLAN headers even if vlanif is configured. Instead, always check ether_type and use appropriate offsets to adjust the hardware RX sum value. XXX: vlan(4) doesn't seem to use csum_data and csum_flags in mbufs anyway. To generate a diff of this commit: cvs rdiff -u -r1.73 -r1.74 src/sys/dev/ic/hme.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/hme.c diff -u src/sys/dev/ic/hme.c:1.73 src/sys/dev/ic/hme.c:1.74 --- src/sys/dev/ic/hme.c:1.73 Mon Mar 16 12:02:00 2009 +++ src/sys/dev/ic/hme.c Sun Mar 29 07:33:52 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: hme.c,v 1.73 2009/03/16 12:02:00 tsutsui Exp $ */ +/* $NetBSD: hme.c,v 1.74 2009/03/29 07:33:52 tsutsui Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hme.c,v 1.73 2009/03/16 12:02:00 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hme.c,v 1.74 2009/03/29 07:33:52 tsutsui Exp $"); /* #define HMEDEBUG */ @@ -62,6 +62,7 @@ #include <net/if_media.h> #ifdef INET +#include <net/if_vlanvar.h> #include <netinet/in.h> #include <netinet/if_inarp.h> #include <netinet/in_systm.h> @@ -591,9 +592,8 @@ /* set h/w rx checksum start offset (# of half-words) */ #ifdef INET - v |= (((ETHER_HDR_LEN + sizeof(struct ip) + - ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? - ETHER_VLAN_ENCAP_LEN : 0)) / 2) << HME_ERX_CFG_CSUMSHIFT) & + v |= (((ETHER_HDR_LEN + sizeof(struct ip)) / sizeof(uint16_t)) + << HME_ERX_CFG_CSUMSHIFT) & HME_ERX_CFG_CSUMSTART; #endif bus_space_write_4(t, erx, HME_ERXI_CFG, v); @@ -721,24 +721,27 @@ /* hardware checksum */ if (ifp->if_csum_flags_rx & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { struct ether_header *eh; + struct ether_vlan_header *evh; struct ip *ip; struct udphdr *uh; uint16_t *opts; int32_t hlen, pktlen; uint32_t temp; - if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) { - pktlen = m0->m_pkthdr.len - ETHER_HDR_LEN - - ETHER_VLAN_ENCAP_LEN; - eh = (struct ether_header *) mtod(m0, void *) + - ETHER_VLAN_ENCAP_LEN; - } else { + eh = mtod(m0, struct ether_header *); + if (ntohs(eh->ether_type) == ETHERTYPE_IP) { + ip = (struct ip *)((char *)eh + ETHER_HDR_LEN); pktlen = m0->m_pkthdr.len - ETHER_HDR_LEN; - eh = mtod(m0, struct ether_header *); - } - if (ntohs(eh->ether_type) != ETHERTYPE_IP) + } else if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) { + evh = (struct ether_vlan_header *)eh; + if (ntohs(evh->evl_proto != ETHERTYPE_IP)) + goto swcsum; + ip = (struct ip *)((char *)eh + ETHER_HDR_LEN + + ETHER_VLAN_ENCAP_LEN); + pktlen = m0->m_pkthdr.len - + ETHER_HDR_LEN - ETHER_VLAN_ENCAP_LEN; + } else goto swcsum; - ip = (struct ip *) ((char *)eh + ETHER_HDR_LEN); /* IPv4 only */ if (ip->ip_v != IPVERSION) @@ -782,13 +785,18 @@ /* w/ M_CSUM_NO_PSEUDOHDR, the uncomplemented sum is expected */ m0->m_pkthdr.csum_data = (~flags) & HME_XD_RXCKSUM; - /* if the pkt had ip options, we have to deduct them */ - if (hlen > sizeof(struct ip)) { + /* + * If data offset is different from RX cksum start offset, + * we have to deduct them. + */ + temp = ((char *)ip + hlen) - + ((char *)eh + ETHER_HDR_LEN + sizeof(struct ip)); + if (temp > 1) { uint32_t optsum; optsum = 0; - temp = hlen - sizeof(struct ip); - opts = (uint16_t *)((char *)ip + sizeof(struct ip)); + opts = (uint16_t *)((char *)eh + + ETHER_HDR_LEN + sizeof(struct ip)); while (temp > 1) { optsum += ntohs(*opts++);