On Thu, 11 Nov 2004 astesin_at_ukrtelecom.net wrote: > Micro-patch (#if 0 to comment out 2 lines of code around line 1497) > worked for me (with rev.1.44.2.3 if_em.c) > > Tcpdump -I em0 displays all VLANs simultaneously, though, and do not > display VLAN tags. > > But the interface is working, packets are going through. > > Thank you for the cure, but I think this is not the "fix", just quick > hack for cure... Yes -- this patch was basically to confirm that it was indeed the promiscuous mode toggle of vlan support. Try the attached patch, which modifies the if_em driver to track when vlan support is disabled, and to prepend a vlan header when that is the case. Still not the final patch, since if nothing else I should probably not call it a "workaround" and should abstract the vlan prepend behavior for use by other drivers. This appears to work properly locally. I have an e-mail out to the Intel maintainer of the driver asking about their preferred solution. Robert N M Watson FreeBSD Core Team, TrustedBSD Projects robert_at_fledge.watson.org Principal Research Scientist, McAfee Research ==== //depot/vendor/freebsd/src/sys/dev/em/if_em.c#51 - /zoo/rwatson/p4/vendor/freebsd/src/sys/dev/em/if_em.c ==== _at__at_ -161,7 +161,7 _at__at_ static int em_get_buf(int i, struct adapter *, struct mbuf *); static void em_enable_vlans(struct adapter *); -static int em_encap(struct adapter *, struct mbuf *); +static int em_encap(struct adapter *, struct mbuf **); static void em_smartspeed(struct adapter *); static int em_82547_fifo_workaround(struct adapter *, int); static void em_82547_update_fifo_head(struct adapter *, int); _at__at_ -616,7 +616,7 _at__at_ if (m_head == NULL) break; - if (em_encap(adapter, m_head)) { + if (em_encap(adapter, &m_head)) { ifp->if_flags |= IFF_OACTIVE; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); break; _at__at_ -1176,13 +1176,15 _at__at_ * return 0 on success, positive on failure **********************************************************************/ static int -em_encap(struct adapter *adapter, struct mbuf *m_head) +em_encap(struct adapter *adapter, struct mbuf **m_headp) { u_int32_t txd_upper; u_int32_t txd_lower, txd_used = 0, txd_saved = 0; int i, j, error; u_int64_t address; + struct mbuf *m_head; + /* For 82544 Workaround */ DESC_ARRAY desc_array; u_int32_t array_elements; _at__at_ -1198,6 +1200,8 _at__at_ struct em_tx_desc *current_tx_desc = NULL; struct ifnet *ifp = &adapter->interface_data.ac_if; + m_head = *m_headp; + /* * Force a cleanup if number of TX descriptors * available hits the threshold _at__at_ -1250,6 +1254,36 _at__at_ mtag = VLAN_OUTPUT_TAG(ifp, m_head); #endif + /* + * When operating in promiscuous mode, hardware encapsulation for + * packets is disabled. This means we have to add the vlan + * encapsulation in the driver, since it will have come down from the + * VLAN layer with a tag instead of a VLAN header. + */ + if (mtag != NULL && adapter->em_vlan_tag_workaround) { + struct ether_vlan_header *evl; + struct ether_header eh; + + m_head = m_pullup(m_head, sizeof(eh)); + if (m_head == NULL) + return (ENOBUFS); + eh = *mtod(m_head, struct ether_header *); + M_PREPEND(m_head, sizeof(*evl), M_DONTWAIT); + if (m_head == NULL) + return (ENOBUFS); + m_head = m_pullup(m_head, sizeof(*evl)); + if (m_head == NULL) + return (ENOBUFS); + evl = mtod(m_head, struct ether_vlan_header *); + bcopy(&eh, evl, sizeof(*evl)); + evl->evl_proto = evl->evl_encap_proto; + evl->evl_encap_proto = htons(ETHERTYPE_VLAN); + evl->evl_tag = htons(VLAN_TAG_VALUE(mtag)); + m_tag_delete(m_head, mtag); + mtag = NULL; + *m_headp = m_head; + } + i = adapter->next_avail_tx_desc; if (adapter->pcix_82544) { txd_saved = i; _at__at_ -1497,19 +1531,20 _at__at_ if (ifp->if_flags & IFF_PROMISC) { reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - /* Disable VLAN stripping in promiscous mode * This enables bridging of vlan tagged frames to occur * and also allows vlan tags to be seen in tcpdump */ ctrl &= ~E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - + adapter->em_vlan_tag_workaround = 1; } else if (ifp->if_flags & IFF_ALLMULTI) { reg_rctl |= E1000_RCTL_MPE; reg_rctl &= ~E1000_RCTL_UPE; E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); - } + adapter->em_vlan_tag_workaround = 0; + } else + adapter->em_vlan_tag_workaround = 0; return; } _at__at_ -1526,6 +1561,8 _at__at_ E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl); em_enable_vlans(adapter); + adapter->em_vlan_tag_workaround = 0; + return; }Received on Thu Nov 11 2004 - 12:20:24 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:21 UTC