Subject: Re: 802.1q hardware support
To: None <tech-net@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: tech-net
Date: 11/14/2000 17:28:37
--8t9RHnE3ZwKMSgU+
Content-Type: text/plain; charset=us-ascii

On Tue, Nov 14, 2000 at 09:35:19AM +0100, Manuel Bouyer wrote:
> On Mon, Nov 13, 2000 at 04:39:40PM -0800, Jason R Thorpe wrote:
> > Yes, please.  Symmetry is good.  It also means you can eliminate
> > #if NVLAN from the ti driver.  It also means you can eliminte that
> > extra vlan_input_ifv() function, and replace it with a simple goto :-)
> 
> I'm not sure this is a good idea; we'd have to test for M_VLAN1Q 2 times:
> one in ether_input and one in vlan_input. I don't know which one costs more.

Ok, after more though it's better to do this than have 2 input functions
(if we ever want to modularize this ...).

> 
> Ok. I'll cook up a second patch with these changes.

Attached. The whole diff to if_ti.c (changes from FreeBSD for newer firmware,
newer boards and a few improvements) is here but not the associated
firmware patch (not interesting to read :).
Could someone check what ti_jfree() is doing and how it's used ?
I see a call to MCLINITREFERENCE() but nothing to other associated
macros. Is this normal ?
(previsouly if_ti had its own ref count mechanism, but FreeBSD changed this
for a generic mechanism but unfortunably it's not the same as ours).

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--

--8t9RHnE3ZwKMSgU+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="vlan.diff"

Index: dev/pci/if_ti.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_ti.c,v
retrieving revision 1.12
diff -u -r1.12 if_ti.c
--- dev/pci/if_ti.c	2000/11/12 18:32:43	1.12
+++ dev/pci/if_ti.c	2000/11/14 15:09:22
@@ -1,4 +1,4 @@
-/* $NetBSD: if_ti.c,v 1.12 2000/11/12 18:32:43 bouyer Exp $ */
+/* $NetBSD: if_ti.c,v 1.8.4.1 2000/09/26 20:18:16 martin Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999
@@ -81,6 +81,7 @@
  */
 
 #include "bpfilter.h"
+#include "vlan.h"
 #include "opt_inet.h"
 #include "opt_ns.h"
 
@@ -135,11 +136,15 @@
 
 static struct ti_type ti_devs[] = {
 	{ PCI_VENDOR_ALTEON,	PCI_PRODUCT_ALTEON_ACENIC,
-		"Alteon AceNIC Gigabit Ethernet" },
+		"Alteon AceNIC 1000baseSX Gigabit Ethernet" },
+	{ PCI_VENDOR_ALTEON,	PCI_PRODUCT_ALTEON_ACENIC_COPPER,
+		"Alteon AceNIC 1000baseT Gigabit Ethernet" },
 	{ PCI_VENDOR_3COM,	PCI_PRODUCT_3COM_3C985,
 		"3Com 3c985-SX Gigabit Ethernet" },
 	{ PCI_VENDOR_NETGEAR, PCI_PRODUCT_NETGEAR_GA620,
-		"Netgear GA620 Gigabit Ethernet" },
+		"Netgear GA620 1000baseSX Gigabit Ethernet" },
+	{ PCI_VENDOR_NETGEAR, PCI_PRODUCT_NETGEAR_GA620T,
+		"Netgear GA620 1000baseT Gigabit Ethernet" },
 	{ PCI_VENDOR_SGI, PCI_PRODUCT_SGI_TIGON,
 		"Silicon Graphics Gigabit Ethernet" },
 	{ 0, 0, NULL }
@@ -625,21 +630,12 @@
 
 	/*
 	 * Now divide it up into 9K pieces and save the addresses
-	 * in an array. Note that we play an evil trick here by using
-	 * the first few bytes in the buffer to hold the address
-	 * of the softc structure for this interface. This is because
-	 * ti_jfree() needs it, but it is called by the mbuf management
-	 * code which will not pass it to us explicitly.
+	 * in an array.
 	 */
 	ptr = sc->ti_cdata.ti_jumbo_buf;
 	for (i = 0; i < TI_JSLOTS; i++) {
-		u_int64_t		**aptr;
-		aptr = (u_int64_t **)ptr;
-		aptr[0] = (u_int64_t *)sc;
-		ptr += sizeof(u_int64_t);
-		sc->ti_cdata.ti_jslots[i].ti_buf = ptr;
-		sc->ti_cdata.ti_jslots[i].ti_inuse = 0;
-		ptr += (TI_JLEN - sizeof(u_int64_t));
+		sc->ti_cdata.ti_jslots[i] = ptr;
+		ptr += TI_JLEN;
 		entry = malloc(sizeof(struct ti_jpool_entry), 
 			       M_DEVBUF, M_NOWAIT);
 		if (entry == NULL) {
@@ -674,8 +670,7 @@
 
 	SIMPLEQ_REMOVE_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries);
 	SIMPLEQ_INSERT_HEAD(&sc->ti_jinuse_listhead, entry, jpool_entries);
-	sc->ti_cdata.ti_jslots[entry->slot].ti_inuse = 1;
-	return(sc->ti_cdata.ti_jslots[entry->slot].ti_buf);
+	return(sc->ti_cdata.ti_jslots[entry->slot]);
 }
 
 /*
@@ -684,45 +679,33 @@
 static void ti_jfree(buf, size, arg)
 	caddr_t			buf;
 	u_int			size;
-	void *arg; /* XXX NetBSD: we should really use it */
+	void *arg;
 {
 	struct ti_softc		*sc;
-	u_int64_t		**aptr;
 	int		        i;
 	struct ti_jpool_entry   *entry;
 
 	/* Extract the softc struct pointer. */
-	aptr = (u_int64_t **)(buf - sizeof(u_int64_t));
-	sc = (struct ti_softc *)(aptr[0]);
+	sc = (struct ti_softc *)arg;
 
 	if (sc == NULL)
-		panic("ti_jfree: can't find softc pointer!");
+		panic("ti_jfree: didn't get softc pointer!");
 
-	if (size != TI_JUMBO_FRAMELEN)
-		panic("ti_jfree: freeing buffer of wrong size!");
-
 	/* calculate the slot this buffer belongs to */
 
-	i = ((caddr_t)aptr 
+	i = ((caddr_t)buf
 	     - (caddr_t)sc->ti_cdata.ti_jumbo_buf) / TI_JLEN;
 
 	if ((i < 0) || (i >= TI_JSLOTS))
 		panic("ti_jfree: asked to free buffer that we don't manage!");
-	else if (sc->ti_cdata.ti_jslots[i].ti_inuse == 0)
-		panic("ti_jfree: buffer already free!");
-	else {
-		sc->ti_cdata.ti_jslots[i].ti_inuse--;
-		if(sc->ti_cdata.ti_jslots[i].ti_inuse == 0) {
-			entry = SIMPLEQ_FIRST(&sc->ti_jinuse_listhead);
-			if (entry == NULL)
-				panic("ti_jfree: buffer not in use!");
-			entry->slot = i;
-			SIMPLEQ_REMOVE_HEAD(&sc->ti_jinuse_listhead, 
-					    entry, jpool_entries);
-			SIMPLEQ_INSERT_HEAD(&sc->ti_jfree_listhead, 
-					     entry, jpool_entries);
-		}
-	}
+	entry = SIMPLEQ_FIRST(&sc->ti_jinuse_listhead);
+	if (entry == NULL)
+		panic("ti_jfree: buffer not in use!");
+	entry->slot = i;
+	SIMPLEQ_REMOVE_HEAD(&sc->ti_jinuse_listhead, 
+	    entry, jpool_entries);
+	SIMPLEQ_INSERT_HEAD(&sc->ti_jfree_listhead, 
+	     entry, jpool_entries);
 
 	return;
 }
@@ -1484,9 +1467,7 @@
 #ifdef TI_CSUM_OFFLOAD
 	rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM|TI_RCB_FLAG_IP_CKSUM;
 #endif
-#if NVLAN > 0
 	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
-#endif
 
 	/* Set up the jumbo receive ring. */
 	rcb = &sc->ti_rdata->ti_info.ti_jumbo_rx_rcb;
@@ -1497,9 +1478,7 @@
 #ifdef TI_CSUM_OFFLOAD
 	rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM|TI_RCB_FLAG_IP_CKSUM;
 #endif
-#if NVLAN > 0
 	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
-#endif
 
 	/*
 	 * Set up the mini ring. Only activated on the
@@ -1517,9 +1496,7 @@
 #ifdef TI_CSUM_OFFLOAD
 	rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM|TI_RCB_FLAG_IP_CKSUM;
 #endif
-#if NVLAN > 0
 	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
-#endif
 
 	/*
 	 * Set up the receive return ring.
@@ -1554,9 +1531,7 @@
 		rcb->ti_flags = 0;
 	else
 		rcb->ti_flags = TI_RCB_FLAG_HOST_RING;
-#if NVLAN > 0
 	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
-#endif
 	rcb->ti_max_len = TI_TX_RING_CNT;
 	if (sc->ti_hwrev == TI_HWREV_TIGON)
 		TI_HOSTADDR(rcb->ti_hostaddr) = TI_TX_RING_BASE;
@@ -1785,6 +1760,21 @@
 		goto fail2;
 	}
 
+	/*
+	 * We really need a better way to tell a 1000baseTX card
+	 * from a 1000baseSX one, since in theory there could be
+	 * OEMed 1000baseTX cards from lame vendors who aren't
+	 * clever enough to change the PCI ID. For the moment
+	 * though, the AceNIC is the only copper card available.
+	 */
+	if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALTEON &&
+	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALTEON_ACENIC_COPPER) ||
+	    (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NETGEAR &&
+	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NETGEAR_GA620T))
+		sc->ti_copper = 1;
+	else
+		sc->ti_copper = 0;
+
 	/* Set default tuneable values. */
 	sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC;
 	sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000;
@@ -1806,16 +1796,34 @@
 	/*
 	 * We can support 802.1Q VLAN-sized frames.
 	 */
-	sc->ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
+	sc->ethercom.ec_capabilities |=
+	    ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING;
 
 	/* Set up ifmedia support. */
 	ifmedia_init(&sc->ifmedia, IFM_IMASK, ti_ifmedia_upd, ti_ifmedia_sts);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL, 0, NULL);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_FL|IFM_FDX, 0, NULL);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_FX, 0, NULL);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_FX|IFM_FDX, 0, NULL);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
-	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+	if (sc->ti_copper) {
+                /*
+                 * Copper cards allow manual 10/100 mode selection,
+                 * but not manual 1000baseTX mode selection. Why?
+                 * Becuase currently there's no way to specify the
+                 * master/slave setting through the firmware interface,
+                 * so Alteon decided to just bag it and handle it
+                 * via autonegotiation.
+                 */
+                ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
+                ifmedia_add(&sc->ifmedia,
+                    IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+                ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
+                ifmedia_add(&sc->ifmedia,
+                    IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
+                ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_TX, 0, NULL);
+                ifmedia_add(&sc->ifmedia,
+                    IFM_ETHER|IFM_1000_TX|IFM_FDX, 0, NULL);
+	} else {
+		/* Fiber cards don't support 10/100 modes. */
+		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
+		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL);
+	}
 	ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
 	ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO);
 
@@ -1859,10 +1867,8 @@
 		struct ti_rx_desc	*cur_rx;
 		u_int32_t		rxidx;
 		struct mbuf		*m = NULL;
-#if NVLAN > 0
 		u_int16_t		vlan_tag = 0;
 		int			have_tag = 0;
-#endif
 #ifdef TI_CSUM_OFFLOAD
 		struct ip		*ip;
 #endif
@@ -1873,12 +1879,10 @@
 		rxidx = cur_rx->ti_idx;
 		TI_INC(sc->ti_rx_saved_considx, TI_RETURN_RING_CNT);
 
-#if NVLAN > 0
 		if (cur_rx->ti_flags & TI_BDFLAG_VLAN_TAG) {
 			have_tag = 1;
 			vlan_tag = cur_rx->ti_vlan_tag;
 		}
-#endif
 
 		if (cur_rx->ti_flags & TI_BDFLAG_JUMBO_RING) {
 			TI_INC(sc->ti_jumbo, TI_JUMBO_RX_RING_CNT);
@@ -1953,17 +1957,11 @@
 			m->m_flags |= M_HWCKSUM;
 #endif
 
-#if NVLAN > 0 /* XXX NetBSD: broken because m points to ether pkt */
-		/*
-		 * If we received a packet with a vlan tag, pass it
-		 * to vlan_input() instead of ether_input().
-		 */
 		if (have_tag) {
-			vlan_input_tag(eh, m, vlan_tag);
+			m->m_pkthdr.mph_info.mph_info = vlan_tag;
+			m->m_flags |= M_VLAN1Q;
 			have_tag = vlan_tag = 0;
-			continue;
 		}
-#endif
 		(*ifp->if_input)(ifp, m);
 	}
 
@@ -2102,15 +2100,7 @@
 	struct txdmamap_pool_entry *dma;
 	bus_dmamap_t dmamap;
 	int error, i;
-#if NVLAN > 0
-	struct ifvlan		*ifv = NULL;
 
-	if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
-	    m_head->m_pkthdr.rcvif != NULL &&
-	    m_head->m_pkthdr.rcvif->if_type == IFT_8021_VLAN)
-		ifv = m_head->m_pkthdr.rcvif->if_softc;
-#endif
-
 	dma = SIMPLEQ_FIRST(&sc->txdma_list);
 	if (dma == NULL) {
 		return ENOMEM;
@@ -2157,14 +2147,13 @@
 			TI_HOSTADDR(f->ti_addr) = dmamap->dm_segs[i].ds_addr;
 			f->ti_len = dmamap->dm_segs[i].ds_len;
 			f->ti_flags = 0;
-#if NVLAN > 0
-			if (ifv != NULL) {
+			if (m_head->m_flags & M_VLAN1Q) {
 				f->ti_flags |= TI_BDFLAG_VLAN_TAG;
-				f->ti_vlan_tag = ifv->ifv_tag;
+				f->ti_vlan_tag =
+				    m_head->m_pkthdr.mph_info.mph_info;
 			} else {
 				f->ti_vlan_tag = 0;
 			}
-#endif
 			/*
 			 * Sanity check: avoid coming within 16 descriptors
 			 * of the end of the ring.
@@ -2391,17 +2380,28 @@
 		    TI_CMD_CODE_NEGOTIATE_BOTH, 0);
 		break;
 	case IFM_1000_SX:
-		CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB|
-		    TI_GLNK_FULL_DUPLEX|TI_GLNK_RX_FLOWCTL_Y|TI_GLNK_ENB);
+	case IFM_1000_TX:
+		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) {
+			CSR_WRITE_4(sc, TI_GCR_GLINK,
+			    TI_GLNK_PREF|TI_GLNK_1000MB|TI_GLNK_FULL_DUPLEX|
+			    TI_GLNK_RX_FLOWCTL_Y|TI_GLNK_ENB);
+		} else {
+			CSR_WRITE_4(sc, TI_GCR_GLINK,
+			    TI_GLNK_PREF|TI_GLNK_1000MB|
+			    TI_GLNK_RX_FLOWCTL_Y|TI_GLNK_ENB);
+		}
 		CSR_WRITE_4(sc, TI_GCR_LINK, 0);
 		TI_DO_CMD(TI_CMD_LINK_NEGOTIATION,
 		    TI_CMD_CODE_NEGOTIATE_GIGABIT, 0);
 		break;
 	case IFM_100_FX:
 	case IFM_10_FL:
+	case IFM_100_TX:
+	case IFM_10_T:
 		CSR_WRITE_4(sc, TI_GCR_GLINK, 0);
 		CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_ENB|TI_LNK_PREF);
-		if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX) {
+		if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX ||
+		    IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
 			TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_100MB);
 		} else {
 			TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_10MB);
@@ -2430,6 +2430,7 @@
 	struct ifmediareq	*ifmr;
 {
 	struct ti_softc		*sc;
+	u_int32_t               media = 0;
 
 	sc = ifp->if_softc;
 
@@ -2441,15 +2442,29 @@
 
 	ifmr->ifm_status |= IFM_ACTIVE;
 
-	if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP)
-		ifmr->ifm_active |= IFM_1000_SX|IFM_FDX;
-	else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
-		u_int32_t		media;
+	if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) {
+		media = CSR_READ_4(sc, TI_GCR_GLINK_STAT);
+		if (sc->ti_copper)
+			ifmr->ifm_active |= IFM_1000_TX;
+		else
+			ifmr->ifm_active |= IFM_1000_SX;
+		if (media & TI_GLNK_FULL_DUPLEX)
+			ifmr->ifm_active |= IFM_FDX;
+		else
+			ifmr->ifm_active |= IFM_HDX;
+	} else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
 		media = CSR_READ_4(sc, TI_GCR_LINK_STAT);
-		if (media & TI_LNK_100MB)
-			ifmr->ifm_active |= IFM_100_FX;
-		if (media & TI_LNK_10MB)
-			ifmr->ifm_active |= IFM_10_FL;
+		if (sc->ti_copper) {
+			if (media & TI_LNK_100MB)
+				ifmr->ifm_active |= IFM_100_TX;
+			if (media & TI_LNK_10MB)
+				ifmr->ifm_active |= IFM_10_T;
+		} else {
+			if (media & TI_LNK_100MB)
+				ifmr->ifm_active |= IFM_100_FX;
+			if (media & TI_LNK_10MB)
+				ifmr->ifm_active |= IFM_10_FL;
+		}
 		if (media & TI_LNK_FULL_DUPLEX)
 			ifmr->ifm_active |= IFM_FDX;
 		if (media & TI_LNK_HALF_DUPLEX)
Index: dev/pci/if_tireg.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_tireg.h,v
retrieving revision 1.1
diff -u -r1.1 if_tireg.h
--- dev/pci/if_tireg.h	1999/09/01 11:47:46	1.1
+++ dev/pci/if_tireg.h	2000/11/14 15:09:24
@@ -92,8 +92,8 @@
  * Firmware revision that we want.
  */
 #define TI_FIRMWARE_MAJOR		0xc
-#define TI_FIRMWARE_MINOR		0x3
-#define TI_FIRMWARE_FIX			0xc
+#define TI_FIRMWARE_MINOR		0x4
+#define TI_FIRMWARE_FIX			0xd
 
 /*
  * Miscelaneous Local Control register.
@@ -1001,11 +1001,6 @@
 #define TI_RESID (TI_JPAGESZ - (TI_JLEN * TI_JSLOTS) % TI_JPAGESZ)
 #define TI_JMEM ((TI_JLEN * TI_JSLOTS) + TI_RESID)
 
-struct ti_jslot {
-	caddr_t			ti_buf;
-	int			ti_inuse;
-};
-
 /*
  * Ring structures. Most of these reside in host memory and we tell
  * the NIC where they are via the ring control blocks. The exceptions
@@ -1045,7 +1040,7 @@
 	struct mbuf		*ti_rx_jumbo_chain[TI_JUMBO_RX_RING_CNT];
 	struct mbuf		*ti_rx_mini_chain[TI_MINI_RX_RING_CNT];
 	/* Stick the jumbo mem management stuff here too. */
-	struct ti_jslot		ti_jslots[TI_JSLOTS];
+	caddr_t			ti_jslots[TI_JSLOTS];
 	void			*ti_jumbo_buf;
 };
 
@@ -1091,6 +1086,7 @@
 	u_int8_t		ti_unit;	/* interface number */
 #endif
 	u_int8_t		ti_hwrev;	/* Tigon rev (1 or 2) */
+	u_int8_t		ti_copper;	/* 1000baseTX card */
 	u_int8_t		ti_linkstat;	/* Link state */
 	struct ti_ring_data	*ti_rdata;	/* rings */
 	struct ti_chain_data	ti_cdata;	/* mbufs */
Index: net/if_ether.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_ether.h,v
retrieving revision 1.20
diff -u -r1.20 if_ether.h
--- net/if_ether.h	2000/10/11 16:53:41	1.20
+++ net/if_ether.h	2000/11/14 15:09:43
@@ -98,6 +98,7 @@
  * Ethernet-specific mbuf flags.
  */
 #define	M_HASFCS	M_LINK0		/* FCS included at end of frame */
+#define	M_VLAN1Q	M_LINK1		/* has 802.1q tag */
 
 #ifdef _KERNEL
 /*
@@ -154,7 +155,7 @@
 };
 
 #define	ETHERCAP_VLAN_MTU	0x00000001	/* VLAN-compatible MTU */
-#define	ETHERCAP_VLAN_TAGGING	0x00000002	/* VLAN tag support */
+#define	ETHERCAP_VLAN_HWTAGGING	0x00000002	/* hardware VLAN tag support */
 
 #ifdef	_KERNEL
 extern u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN];
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_ethersubr.c,v
retrieving revision 1.68
diff -u -r1.68 if_ethersubr.c
--- net/if_ethersubr.c	2000/10/15 19:49:55	1.68
+++ net/if_ethersubr.c	2000/11/14 15:09:43
@@ -538,6 +538,21 @@
 		return;
 	}
 
+	/* Check if the mbuf has a VLAN tag */
+	if (m->m_flags & M_VLAN1Q) {
+#if NVLAN > 0
+		/*
+		 * vlan_input_tag() will either recursively call ether_input()
+		 * or drop the packet.
+		 */
+		if (((struct ethercom *)ifp)->ec_nvlans != 0)
+			vlan_input(ifp, m);
+		else
+#endif
+			m_freem(m);
+		return;
+	}
+
 	/*
 	 * Handle protocols that expect to have the Ethernet header
 	 * (and possibly FCS) intact.
Index: net/if_vlan.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_vlan.c,v
retrieving revision 1.21
diff -u -r1.21 if_vlan.c
--- net/if_vlan.c	2000/11/12 19:39:42	1.21
+++ net/if_vlan.c	2000/11/14 15:09:44
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vlan.c,v 1.21 2000/11/12 19:39:42 bouyer Exp $	*/
+/*	$NetBSD: if_vlan.c,v 1.20 2000/11/10 02:31:53 enami Exp $	*/
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -672,6 +672,7 @@
 {
 	struct ifvlan *ifv = ifp->if_softc;
 	struct ifnet *p = ifv->ifv_p;
+	struct ethercom *ec = (void *) ifv->ifv_p;
 	struct mbuf *m;
 
 	ifp->if_flags |= IFF_OACTIVE;
@@ -685,51 +686,59 @@
 		if (ifp->if_bpf)
 			bpf_mtap(ifp->if_bpf, m);
 #endif
-
 		/*
-		 * XXX Should handle the case where the underlying hardware
-		 * interface can do VLAN tag insertion itself.
+		 * If the parent can insert the tag itself, just mark
+		 * the tag in the mbuf header.
 		 */
-		M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
-		if (m == NULL) {
-			printf("%s: unable to prepend encap header",
-			    ifv->ifv_p->if_xname);
-			ifp->if_oerrors++;
-			continue;
-		}
-
-		switch (p->if_type) {
-		case IFT_ETHER:
-		    {
-			struct ether_vlan_header *evl;
-
-			if (m->m_len < sizeof(struct ether_vlan_header) &&
-			    (m = m_pullup(m,
-			     sizeof(struct ether_vlan_header))) == NULL) {
-				printf("%s: unable to pullup encap header",
+		if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
+			m->m_flags |= M_VLAN1Q;
+			m->m_pkthdr.mph_info.mph_info = ifv->ifv_tag;
+		} else {
+			/*
+			 * insert the tag ourselve
+			 */
+			M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
+			if (m == NULL) {
+				printf("%s: unable to prepend encap header",
 				    ifv->ifv_p->if_xname);
 				ifp->if_oerrors++;
 				continue;
 			}
 
-			/*
-			 * Transform the Ethernet header into an Ethernet
-			 * header with 802.1Q encapsulation.
-			 */
-			memmove(mtod(m, caddr_t),
-			    mtod(m, caddr_t) + ifv->ifv_encaplen, 
-			    sizeof(struct ether_header));
-			evl = mtod(m, struct ether_vlan_header *);
-			evl->evl_proto = evl->evl_encap_proto;
-			evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
-			evl->evl_tag = htons(ifv->ifv_tag);
-			break;
-		    }
+			switch (p->if_type) {
+			case IFT_ETHER:
+			    {
+				struct ether_vlan_header *evl;
+
+				if (m->m_len < sizeof(struct ether_vlan_header))
+					m = m_pullup(m,
+					    sizeof(struct ether_vlan_header));
+				if (m == NULL) {
+					printf("%s: unable to pullup encap "
+					    "header", ifv->ifv_p->if_xname);
+					ifp->if_oerrors++;
+					continue;
+				}
+
+				/*
+				 * Transform the Ethernet header into an
+				 * Ethernet header with 802.1Q encapsulation.
+				 */
+				memmove(mtod(m, caddr_t),
+				    mtod(m, caddr_t) + ifv->ifv_encaplen, 
+				    sizeof(struct ether_header));
+				evl = mtod(m, struct ether_vlan_header *);
+				evl->evl_proto = evl->evl_encap_proto;
+				evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+				evl->evl_tag = htons(ifv->ifv_tag);
+				break;
+			    }
 
 #ifdef DIAGNOSTIC
-		default:
-			panic("vlan_start: impossible");
+			default:
+				panic("vlan_start: impossible");
 #endif
+			}
 		}
 
 		/*
@@ -745,9 +754,9 @@
 		}
 	
 		IF_ENQUEUE(&p->if_snd, m);
+		ifp->if_opackets++;
 		if ((p->if_flags & IFF_OACTIVE) == 0) {
 			(*p->if_start)(p);
-			ifp->if_opackets++;
 		}
 	}
 
@@ -765,43 +774,64 @@
 	struct ifvlan *ifv;
 	u_int tag;
 
-	switch (ifp->if_type) {
-	case IFT_ETHER:
-	    {
-		struct ether_vlan_header *evl;
+	if (m->m_flags & M_VLAN1Q) {
+	/* m contains a normal ethernet frame, the tag is in mph_info */
+		m->m_flags &= ~M_VLAN1Q;
+		tag = m->m_pkthdr.mph_info.mph_info;
+		for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
+		    ifv = LIST_NEXT(ifv, ifv_list))
+			if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
+				break;
+	} else {
+		switch (ifp->if_type) {
+		case IFT_ETHER:
+		    {
+			struct ether_vlan_header *evl;
 
-		if (m->m_len < sizeof(struct ether_vlan_header) &&
-		    (m = m_pullup(m,
-		     sizeof(struct ether_vlan_header))) == NULL) {
-			printf("%s: no memory for VLAN header, "
-			    "dropping packet.\n", ifp->if_xname);
-			return;
-		}
-		evl = mtod(m, struct ether_vlan_header *);
-		KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
+			if (m->m_len < sizeof(struct ether_vlan_header) &&
+			    (m = m_pullup(m,
+			     sizeof(struct ether_vlan_header))) == NULL) {
+				printf("%s: no memory for VLAN header, "
+				    "dropping packet.\n", ifp->if_xname);
+				return;
+			}
+			evl = mtod(m, struct ether_vlan_header *);
+			KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
 
-		tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+			tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
 
-		/*
-		 * Restore the original ethertype.  We'll remove
-		 * the encapsulation after we've found the vlan
-		 * interface corresponding to the tag.
-		 */
-		evl->evl_encap_proto = evl->evl_proto;
-		break;
-	    }
+			/*
+			 * Restore the original ethertype.  We'll remove
+			 * the encapsulation after we've found the vlan
+			 * interface corresponding to the tag.
+			 */
+			evl->evl_encap_proto = evl->evl_proto;
+			break;
+		    }
 
-	default:
-		tag = (u_int) -1;	/* XXX GCC */
+		default:
+			tag = (u_int) -1;	/* XXX GCC */
 #ifdef DIAGNOSTIC
-		panic("vlan_input: impossible");
+			panic("vlan_input: impossible");
 #endif
-	}
+		}
 
-	for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
-	     ifv = LIST_NEXT(ifv, ifv_list))
-		if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
-			break;
+		for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
+		     ifv = LIST_NEXT(ifv, ifv_list))
+			if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
+				break;
+
+
+		/*
+		 * Now, remove the encapsulation header.  The original
+		 * header has already been fixed up above.
+		 */
+		if (ifv) {
+			memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
+			    mtod(m, caddr_t), ifv->ifv_encaplen);
+			m_adj(m, ifv->ifv_encaplen);
+		}
+	}
 
 	if (ifv == NULL ||
 	    (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
@@ -810,15 +840,6 @@
 		ifp->if_noproto++;
 		return;
 	}
-
-	/*
-	 * Now, remove the encapsulation header.  The original
-	 * header has already been fixed up above.
-	 */
-	memmove(mtod(m, caddr_t) + ifv->ifv_encaplen, mtod(m, caddr_t),
-	    ifv->ifv_encaplen);
-	m_adj(m, ifv->ifv_encaplen);
-
 	m->m_pkthdr.rcvif = &ifv->ifv_if;
 	ifv->ifv_if.if_ipackets++;
 
Index: sys/mbuf.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/mbuf.h,v
retrieving revision 1.53
diff -u -r1.53 mbuf.h
--- sys/mbuf.h	2000/08/18 16:19:23	1.53
+++ sys/mbuf.h	2000/11/14 15:09:47
@@ -121,6 +121,10 @@
 	struct	ifnet *rcvif;		/* rcv interface */
 	int	len;			/* total packet length */
 	struct mbuf *aux;		/* extra data buffer; ipsec/others */
+	union   {
+		int mph_info;
+		void *mph_infop;
+	} mph_info;			/* link-layer specific info */
 };
 
 /* description of external storage mapped into mbuf, valid if M_EXT set */

--8t9RHnE3ZwKMSgU+--