Re: Yes it did the trick - Re[3]: Re[2]: em0, VLAN and bpf(?) trouble w/RELENG_5

From: Robert Watson <rwatson_at_freebsd.org>
Date: Thu, 11 Nov 2004 13:34:18 +0000 (GMT)
On Thu, 11 Nov 2004, Robert Watson wrote:

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

That patch excluded the addition of a new variable to the adapter
structure in if_em.h.  Full patch below.

==== //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;
 }
 
==== //depot/vendor/freebsd/src/sys/dev/em/if_em.h#26 - /zoo/rwatson/p4/vendor/freebsd/src/sys/dev/em/if_em.h ====
_at__at_ -346,6 +346,7 _at__at_
 	int             io_rid;
 	u_int8_t        unit;
 	struct mtx	mtx;
+	int		em_vlan_tag_workaround;
 
 	/* Info about the board itself */
 	u_int32_t       part_num;
Received on Thu Nov 11 2004 - 12:35:31 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:21 UTC