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