summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/gldutil.c
diff options
context:
space:
mode:
authordg199075 <none@none>2006-09-19 11:16:27 -0700
committerdg199075 <none@none>2006-09-19 11:16:27 -0700
commit605445d5657096e69d948ccb554c9ff024fa34df (patch)
treec0acbb1d49d8259bf1a104d24f427270905e955c /usr/src/uts/common/io/gldutil.c
parent8bc68872f6b178bf5e1d324c663e29fb6ccb1eab (diff)
downloadillumos-gate-605445d5657096e69d948ccb554c9ff024fa34df.tar.gz
PSARC/2006/358 VLAN Observability Enhancement
4095699 snoop: add support for 802.1Q VLAN tagging 6292043 DL_PROMISC_SAP should see *all* traffic, not just untagged traffic on GLDv2 links 6306794 GLDv2 drivers incorrectly strip the VLAN tag in raw mode 6309233 GLDv3 drivers incorrectly process VLAN packets in raw mode 6375633 GLDv2 processes DL_PROMISC{ON,OFF}_REQ incorrectly 6425678 DL_PROMISC_SAP should make all VLAN traffic visible on physical GLDv3 links 6434082 Enhance snoop's VLAN filtering capability 6434130 i_dls_ether_header() doesn't generate VLAN header when priority is non-zero 6436003 QoS should be supported on non VLAN streams as well 6438679 GLDv3 doesn't respect QoS priorities in some cases 6442753 GLDv2/GLDv3 has several VLAN packet processing issues 6453746 Change definition of enprintf in pfmod.c 6457476 GLDv2 kstats are not MT-protected, could cause missing increment in some cases 6464397 mac_header_{cook,uncook}() failure can cause a message to be freed twice
Diffstat (limited to 'usr/src/uts/common/io/gldutil.c')
-rw-r--r--usr/src/uts/common/io/gldutil.c160
1 files changed, 120 insertions, 40 deletions
diff --git a/usr/src/uts/common/io/gldutil.c b/usr/src/uts/common/io/gldutil.c
index 7fe5cb66c5..c3e9f2bedb 100644
--- a/usr/src/uts/common/io/gldutil.c
+++ b/usr/src/uts/common/io/gldutil.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,7 +18,7 @@
*
* CDDL HEADER END
*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -98,7 +97,7 @@ gld_init_ether(gld_mac_info_t *macinfo)
ASSERT(macinfo->gldm_addrlen == 6);
ASSERT(macinfo->gldm_saplen == -2);
#ifndef lint
- ASSERT(sizeof (struct ether_mac_frm) == 14);
+ ASSERT(sizeof (struct ether_header) == 14);
ASSERT(sizeof (mac_addr_t) == 6);
#endif
@@ -145,11 +144,12 @@ int
gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
packet_flag_t flags)
{
- struct ether_mac_frm *mh;
+ struct ether_header *mh;
gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
struct llc_snap_hdr *snaphdr;
- mblk_t *pmp = NULL;
+ mblk_t *pmp = NULL, *savemp = mp;
unsigned short typelen;
+ int ret = 0;
/*
* Quickly handle receive fastpath for IPQ hack.
@@ -160,13 +160,13 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
* Check whether the header is contiguous, which
* also implicitly makes sure the packet is big enough.
*/
- if (MBLKL(mp) < sizeof (struct ether_mac_frm))
+ if (MBLKL(mp) < sizeof (struct ether_header))
return (-1);
- mh = (struct ether_mac_frm *)mp->b_rptr;
+ mh = (struct ether_header *)mp->b_rptr;
pktinfo->ethertype = REF_NET_USHORT(mh->ether_type);
- pktinfo->isForMe = mac_eq(mh->ether_dhost,
+ pktinfo->isForMe = mac_eq(&mh->ether_dhost,
mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
- pktinfo->macLen = sizeof (struct ether_mac_frm);
+ pktinfo->macLen = sizeof (struct ether_header);
return (0);
}
@@ -176,11 +176,11 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
pktinfo->pktLen = msgdsize(mp);
/* make sure packet has at least a whole mac header */
- if (pktinfo->pktLen < sizeof (struct ether_mac_frm))
+ if (pktinfo->pktLen < sizeof (struct ether_header))
return (-1);
/* make sure the mac header falls into contiguous memory */
- if (MBLKL(mp) < sizeof (struct ether_mac_frm)) {
+ if (MBLKL(mp) < sizeof (struct ether_header)) {
if ((pmp = msgpullup(mp, -1)) == NULL) {
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
@@ -192,12 +192,12 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
mp = pmp; /* this mblk contains the whole mac header */
}
- mh = (struct ether_mac_frm *)mp->b_rptr;
+ mh = (struct ether_header *)mp->b_rptr;
/* Check to see if the mac is a broadcast or multicast address. */
- if (mac_eq(mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen))
+ if (mac_eq(&mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen))
pktinfo->isBroadcast = 1;
- else if (mh->ether_dhost[0] & 1)
+ else if (mh->ether_dhost.ether_addr_octet[0] & 1)
pktinfo->isMulticast = 1;
typelen = REF_NET_USHORT(mh->ether_type);
@@ -208,11 +208,40 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
* of non null 'macinfo->gldm_send_tagged'.
*/
if (flags == GLD_TX) {
- if ((typelen == VLAN_TPID) &&
- (macinfo->gldm_send_tagged != NULL)) {
- ovbcopy(mp->b_rptr,
- mp->b_rptr + VTAG_SIZE,
- 2 * ETHERADDRL);
+ if ((typelen == ETHERTYPE_VLAN) &&
+ (macinfo->gldm_send_tagged != NULL)) {
+ struct ether_vlan_header *evhp;
+ uint16_t tci;
+
+ if ((MBLKL(mp) < sizeof (struct ether_vlan_header)) &&
+ (pullupmsg(mp, sizeof (struct ether_vlan_header))
+ == 0)) {
+ ret = -1;
+ goto out;
+ }
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ tci = REF_NET_USHORT(evhp->ether_tci);
+
+ /*
+ * We don't allow the VID and priority are both zero.
+ */
+ if ((GLD_VTAG_PRI((int32_t)tci) == 0 &&
+ GLD_VTAG_VID((int32_t)tci) == VLAN_VID_NONE) ||
+ (GLD_VTAG_CFI((uint32_t)tci)) != VLAN_CFI_ETHER) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Remember the VTAG info in order to reinsert it,
+ * Then strip the tag. This is required because some
+ * drivers do not allow the size of message (passed
+ * by the gldm_send_tagged() function) to be greater
+ * than ETHERMAX.
+ */
+ GLD_SAVE_MBLK_VTAG(savemp, GLD_TCI2VTAG(tci));
+ ovbcopy(mp->b_rptr, mp->b_rptr + VTAG_SIZE,
+ 2 * ETHERADDRL);
mp->b_rptr += VTAG_SIZE;
}
goto out; /* Got all info we need for xmit case */
@@ -224,15 +253,15 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
* Deal with the mac header
*/
- mac_copy(mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
- mac_copy(mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen);
+ mac_copy(&mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
+ mac_copy(&mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen);
pktinfo->isLooped = mac_eq(pktinfo->shost,
mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
pktinfo->isForMe = mac_eq(pktinfo->dhost,
mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
- pktinfo->macLen = sizeof (struct ether_mac_frm);
+ pktinfo->macLen = sizeof (struct ether_header);
if (typelen > ETHERMTU) {
pktinfo->ethertype = typelen; /* use type interpretation */
@@ -247,7 +276,7 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
*/
{
int delta = pktinfo->pktLen -
- (sizeof (struct ether_mac_frm) + typelen);
+ (sizeof (struct ether_header) + typelen);
if (delta > 0 && adjmsg(mp, -delta))
pktinfo->pktLen -= delta;
@@ -263,10 +292,10 @@ gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
pktinfo->isLLC = 1;
if (gld_global_options & GLD_OPT_NO_ETHRXSNAP ||
- pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
+ pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
goto out;
- if (MBLKL(mp) < sizeof (struct ether_mac_frm) + LLC_SNAP_HDR_LEN &&
+ if (MBLKL(mp) < sizeof (struct ether_header) + LLC_SNAP_HDR_LEN &&
MBLKL(mp) < pktinfo->pktLen) {
/*
* we don't have the entire packet within the first mblk (and
@@ -298,7 +327,7 @@ out:
if (pmp != NULL)
freemsg(pmp);
- return (0);
+ return (ret);
}
mblk_t *
@@ -310,7 +339,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp)
mac_addr_t dhost;
unsigned short typelen;
mblk_t *nmp;
- struct ether_mac_frm *mh;
+ struct ether_header *mh;
int hdrlen;
uint32_t vptag;
gld_vlan_t *gld_vlan;
@@ -335,7 +364,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp)
if (typelen <= ETHERMTU)
typelen = msgdsize(mp);
- hdrlen = sizeof (struct ether_mac_frm);
+ hdrlen = sizeof (struct ether_header);
/*
* Check to see if VLAN is enabled on this stream
@@ -371,7 +400,7 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp)
nmp->b_rptr -= sizeof (typelen);
SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
- if (hdrlen > sizeof (struct ether_mac_frm)) {
+ if (hdrlen > sizeof (struct ether_header)) {
nmp->b_rptr -= sizeof (uint16_t);
SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
vptag >>= 16;
@@ -379,16 +408,67 @@ gld_unitdata_ether(gld_t *gld, mblk_t *mp)
SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
}
nmp->b_rptr -= (ETHERADDRL * 2);
- mh = (struct ether_mac_frm *)nmp->b_rptr;
- mac_copy(dhost, mh->ether_dhost, macinfo->gldm_addrlen);
+ mh = (struct ether_header *)nmp->b_rptr;
+ mac_copy(dhost, &mh->ether_dhost, macinfo->gldm_addrlen);
/*
* We access the mac address without the mutex to prevent
* mutex contention (BUG 4211361)
*/
mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
- mh->ether_shost, macinfo->gldm_addrlen);
+ &mh->ether_shost, macinfo->gldm_addrlen);
+
+ return (nmp);
+}
+
+/*
+ * Insert the VLAN tag into the packet. The packet now is an Ethernet header
+ * without VLAN tag information.
+ */
+mblk_t *
+gld_insert_vtag_ether(mblk_t *mp, uint32_t vtag)
+{
+ struct ether_vlan_header *evhp;
+ struct ether_header *ehp;
+ mblk_t *nmp;
+
+ if (vtag == VLAN_VID_NONE)
+ return (mp);
+
+ if (DB_REF(mp) == 1 && MBLKHEAD(mp) >= VTAG_SIZE) {
+ /* it fits at the beginning of the message block */
+ nmp = mp;
+ ovbcopy(nmp->b_rptr, nmp->b_rptr - VTAG_SIZE, 2 * ETHERADDRL);
+ nmp->b_rptr -= VTAG_SIZE;
+ evhp = (struct ether_vlan_header *)nmp->b_rptr;
+ } else {
+ /* we need to allocate one */
+ if ((nmp = allocb(sizeof (struct ether_vlan_header),
+ BPRI_MED)) == NULL) {
+ return (NULL);
+ }
+ nmp->b_wptr += sizeof (struct ether_vlan_header);
+
+ /* transfer the ether_header fields */
+ evhp = (struct ether_vlan_header *)nmp->b_rptr;
+ ehp = (struct ether_header *)mp->b_rptr;
+ mac_copy(&ehp->ether_dhost, &evhp->ether_dhost, ETHERADDRL);
+ mac_copy(&ehp->ether_shost, &evhp->ether_shost, ETHERADDRL);
+ bcopy(&ehp->ether_type, &evhp->ether_type, sizeof (uint16_t));
+
+ /* offset the mp of the MAC header length. */
+ mp->b_rptr += sizeof (struct ether_header);
+ if (MBLKL(mp) == 0) {
+ nmp->b_cont = mp->b_cont;
+ freeb(mp);
+ } else {
+ nmp->b_cont = mp;
+ }
+ }
+ SET_NET_USHORT(evhp->ether_tci, vtag);
+ vtag >>= 16;
+ SET_NET_USHORT(evhp->ether_tpid, vtag);
return (nmp);
}
@@ -400,7 +480,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp)
struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
unsigned short typelen;
mblk_t *nmp;
- struct ether_mac_frm *mh;
+ struct ether_header *mh;
int hdrlen;
uint32_t vptag;
gld_vlan_t *gld_vlan;
@@ -425,7 +505,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp)
* Initialize the fast path header to include the
* basic source address information and type field.
*/
- hdrlen = sizeof (struct ether_mac_frm);
+ hdrlen = sizeof (struct ether_header);
/*
* Check to see if VLAN is enabled on this stream
@@ -452,7 +532,7 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp)
* If the header is for a VLAN stream, then add
* in the VLAN tag to the clone header.
*/
- if (hdrlen > sizeof (struct ether_mac_frm)) {
+ if (hdrlen > sizeof (struct ether_header)) {
nmp->b_rptr -= sizeof (uint16_t);
SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
vptag >>= 16;
@@ -460,12 +540,12 @@ gld_fastpath_ether(gld_t *gld, mblk_t *mp)
SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
}
nmp->b_rptr -= (ETHERADDRL * 2);
- mh = (struct ether_mac_frm *)nmp->b_rptr;
- mac_copy(gldp->glda_addr, mh->ether_dhost, macinfo->gldm_addrlen);
+ mh = (struct ether_header *)nmp->b_rptr;
+ mac_copy(gldp->glda_addr, &mh->ether_dhost, macinfo->gldm_addrlen);
GLDM_LOCK(macinfo, RW_WRITER);
mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
- mh->ether_shost, macinfo->gldm_addrlen);
+ &mh->ether_shost, macinfo->gldm_addrlen);
GLDM_UNLOCK(macinfo);
return (nmp);