summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c30
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h15
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c113
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c265
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c451
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h57
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3861
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc1
-rw-r--r--usr/src/uts/common/inet/ip.h7
-rw-r--r--usr/src/uts/common/inet/ip/ip.c15
-rw-r--r--usr/src/uts/common/inet/ip/ip_squeue.c4
-rw-r--r--usr/src/uts/common/io/aggr/aggr_send.c2
-rw-r--r--usr/src/uts/common/io/bge/bge_recv2.c2
-rw-r--r--usr/src/uts/common/io/bge/bge_send.c2
-rw-r--r--usr/src/uts/common/io/dld/dld_proto.c68
-rw-r--r--usr/src/uts/common/io/dld/dld_str.c332
-rw-r--r--usr/src/uts/common/io/dls/dls.c96
-rw-r--r--usr/src/uts/common/io/dls/dls_link.c646
-rw-r--r--usr/src/uts/common/io/dls/dls_soft_ring.c13
-rw-r--r--usr/src/uts/common/io/gld.c658
-rw-r--r--usr/src/uts/common/io/gldutil.c160
-rw-r--r--usr/src/uts/common/io/mac/mac.c4
-rw-r--r--usr/src/uts/common/io/pfmod.c126
-rwxr-xr-xusr/src/uts/common/io/rge/rge_rxtx.c4
-rw-r--r--usr/src/uts/common/sys/Makefile1
-rw-r--r--usr/src/uts/common/sys/dld_impl.h9
-rw-r--r--usr/src/uts/common/sys/dls.h5
-rw-r--r--usr/src/uts/common/sys/dls_impl.h5
-rw-r--r--usr/src/uts/common/sys/dls_soft_ring.h9
-rw-r--r--usr/src/uts/common/sys/ethernet.h17
-rw-r--r--usr/src/uts/common/sys/gld.h23
-rw-r--r--usr/src/uts/common/sys/gldpriv.h67
-rw-r--r--usr/src/uts/common/sys/mac.h3
-rw-r--r--usr/src/uts/common/sys/pfmod.h69
-rw-r--r--usr/src/uts/common/sys/stream.h11
-rw-r--r--usr/src/uts/common/sys/vlan.h15
-rw-r--r--usr/src/uts/sun4u/io/dmfe/dmfe_main.c10
38 files changed, 2248 insertions, 1073 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
index 386fcbce85..ff43c225a7 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c
@@ -88,6 +88,8 @@ boolean_t zflg = B_FALSE; /* debugging packet corrupt flag */
#endif
struct Pf_ext_packetfilt pf;
+static int vlanid = 0;
+
static void usage(void);
void show_count();
static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
@@ -584,6 +586,11 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
}
}
+ if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) {
+ (void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid);
+ lp += strlen(lp);
+ }
+
if (flags & F_WHO) {
(void) sprintf(lp, "%12s -> %-12s ", src, dst);
lp += strlen(lp);
@@ -622,7 +629,7 @@ show_pktinfo(flags, num, src, dst, ptvp, tvp, drops, len)
}
/*
- * The following two routines are called back
+ * The following three routines are called back
* from the interpreters to display their stuff.
* The theory is that when snoop becomes a window
* based tool we can just supply a new version of
@@ -658,6 +665,27 @@ get_detail_line(off, len)
}
/*
+ * This function exists to make sure that VLAN information is
+ * prepended to summary lines displayed. The problem this function
+ * solves is how to display VLAN information while in summary mode.
+ * Each interpretor uses the get_sum_line and get_detail_line functions
+ * to get a character buffer to display information to the user.
+ * get_sum_line is the important one here. Each call to get_sum_line
+ * gets a buffer which stores one line of information. In summary mode,
+ * the last line generated is the line printed. Instead of changing each
+ * interpreter to add VLAN information to the summary line, the ethernet
+ * interpreter changes to call this function and set an ID. If the ID is not
+ * zero and snoop is in default summary mode, snoop displays the
+ * VLAN information at the beginning of the output line. Otherwise,
+ * no VLAN information is displayed.
+ */
+void
+set_vlan_id(int id)
+{
+ vlanid = id;
+}
+
+/*
* Print an error.
* Works like printf (fmt string and variable args)
* except that it will substitute an error message
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
index fe9bf31253..017317e765 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.h
@@ -126,6 +126,7 @@ extern char *prot_nest_prefix;
extern char *get_sum_line(void);
extern char *get_detail_line(int, int);
+extern void set_vlan_id(int);
extern struct timeval prev_time;
extern void process_pkt(struct sb_hdr *, char *, int, int);
extern char *getflag(int, int, char *, char *);
@@ -263,23 +264,29 @@ extern char *print_ethertype(int);
* The mac_type is one of the supported DLPI media
* types (see <sys/dlpi.h>).
* The mtu_size is the size of the largest frame.
+ * network_type_offset is where the network type
+ * is located in the link layer header.
* The header length is returned by a function to
* allow for variable header size - for ethernet it's
* just a constant 14 octets.
* The interpreter is the function that "knows" how
* to interpret the frame.
+ * try_kernel_filter tells snoop to first try a kernel
+ * filter (because the header size is fixed, or if it could
+ * be of variable size where the variable size is easy for a kernel
+ * filter to handle, for example, Ethernet and VLAN tags)
+ * and only use a user space filter if the filter expression
+ * cannot be expressed in kernel space.
*/
typedef struct interface {
uint_t mac_type;
uint_t mtu_size;
+ uint_t network_type_offset;
uint_t (*header_len)(char *);
uint_t (*interpreter)(int, char *, int, int);
- uint_t mac_hdr_fixed_size;
+ uint_t try_kernel_filter;
} interface_t;
-#define IF_HDR_FIXED 0
-#define IF_HDR_VAR 1
-
extern interface_t INTERFACES[], *interface;
extern char *device;
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
index e3e7bd75fd..5d24744e66 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_capture.c
@@ -240,10 +240,7 @@ check_device(char **devicep, int *ppap)
if (interface->mtu_size > (uint_t)netdl.info_ack.dl_max_sdu)
netdl.info_ack.dl_max_sdu = (t_scalar_t)interface->mtu_size;
- if (interface->mac_hdr_fixed_size == IF_HDR_FIXED)
- return (B_TRUE);
-
- return (B_FALSE);
+ return (interface->try_kernel_filter);
}
/*
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c
index f3214def05..8db0a37930 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ether.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.
@@ -20,7 +19,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.
*/
@@ -30,6 +29,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
+#include <stddef.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
@@ -44,11 +44,13 @@
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <sys/ib/clients/ibd/ibd.h>
+#include <sys/ethernet.h>
+#include <sys/vlan.h>
#include "at.h"
#include "snoop.h"
-static uint_t ether_header_len(char *), fddi_header_len(char *),
+static uint_t ether_header_len(char *), fddi_header_len(char *),
tr_header_len(char *), ib_header_len(char *);
static uint_t interpret_ether(), interpret_fddi(), interpret_tr();
static uint_t interpret_ib(int, char *, int, int);
@@ -58,25 +60,24 @@ interface_t *interface;
interface_t INTERFACES[] = {
/* IEEE 802.3 CSMA/CD network */
- { DL_CSMACD, 1550, ether_header_len, interpret_ether, IF_HDR_FIXED },
+ { DL_CSMACD, 1550, 12, ether_header_len, interpret_ether, B_TRUE },
/* Ethernet Bus */
- { DL_ETHER, 1550, ether_header_len, interpret_ether, IF_HDR_FIXED },
+ { DL_ETHER, 1550, 12, ether_header_len, interpret_ether, B_TRUE },
/* Fiber Distributed data interface */
- { DL_FDDI, 4500, fddi_header_len, interpret_fddi, IF_HDR_VAR },
+ { DL_FDDI, 4500, 19, fddi_header_len, interpret_fddi, B_FALSE },
/* Token Ring interface */
- { DL_TPR, 17800, tr_header_len, interpret_tr, IF_HDR_VAR },
+ { DL_TPR, 17800, 0, tr_header_len, interpret_tr, B_FALSE },
/* Infiniband */
- { DL_IB, 4096, ib_header_len, interpret_ib, IF_HDR_FIXED },
+ { DL_IB, 4096, 0, ib_header_len, interpret_ib, B_TRUE },
- { (uint_t)-1, 0, 0, 0, 0 }
+ { (uint_t)-1, 0, 0, 0, 0, 0 }
};
-
/* externals */
extern char *dlc_header;
extern int pi_frame;
@@ -109,6 +110,7 @@ interpret_ether(flags, e, elen, origlen)
extern char *dst_name;
int ethertype;
boolean_t data_copied = B_FALSE;
+ struct ether_vlan_extinfo *evx = NULL;
int blen = MAX(origlen, ETHERMTU);
if (data != NULL && datalen != 0 && datalen < blen) {
@@ -153,7 +155,7 @@ interpret_ether(flags, e, elen, origlen)
if (ethertype <= 1514) {
/*
* Fake out the IEEE 802.3 packets.
- * Should be DSAP=170, SSAP=170, control=3
+ * Should be DSAP=0xAA, SSAP=0xAA, control=0x03
* then three padding bytes of zero,
* followed by a normal ethernet-type packet.
*/
@@ -163,6 +165,29 @@ interpret_ether(flags, e, elen, origlen)
len -= 8;
}
+ if (ethertype == ETHERTYPE_VLAN) {
+ if (origlen < sizeof (struct ether_vlan_header)) {
+ if (flags & F_SUM) {
+ (void) sprintf(get_sum_line(),
+ "RUNT (short VLAN packet - %d bytes)",
+ origlen);
+ }
+ if (flags & F_DTAIL) {
+ show_header("RUNT: ", "Short VLAN packet",
+ origlen);
+ }
+ return (elen);
+ }
+ if (len < sizeof (struct ether_vlan_extinfo))
+ return (elen);
+
+ evx = (struct ether_vlan_extinfo *)off;
+ off += sizeof (struct ether_vlan_extinfo);
+ len -= sizeof (struct ether_vlan_extinfo);
+
+ ethertype = ntohs(evx->ether_type);
+ }
+
/*
* We cannot trust the length field in the header to be correct.
* But we should continue to process the packet. Then user can
@@ -174,11 +199,27 @@ interpret_ether(flags, e, elen, origlen)
}
if (flags & F_SUM) {
- (void) sprintf(get_sum_line(),
- "ETHER Type=%04X (%s), size = %d bytes",
- ethertype,
- print_ethertype(ethertype),
- origlen);
+ /*
+ * Set the flag that says don't display VLAN information.
+ * If it needs to change, that will be done later if the
+ * packet is VLAN tagged and if snoop is in its default
+ * summary mode.
+ */
+ set_vlan_id(0);
+ if (evx == NULL) {
+ (void) sprintf(get_sum_line(),
+ "ETHER Type=%04X (%s), size=%d bytes",
+ ethertype, print_ethertype(ethertype),
+ origlen);
+ } else {
+ (void) sprintf(get_sum_line(),
+ "ETHER Type=%04X (%s), VLAN ID=%hu, size=%d "
+ "bytes", ethertype, print_ethertype(ethertype),
+ VLAN_ID(ntohs(evx->ether_tci)), origlen);
+
+ if (!(flags & F_ALLSUM))
+ set_vlan_id(VLAN_ID(ntohs(evx->ether_tci)));
+ }
}
if (flags & F_DTAIL) {
@@ -200,10 +241,16 @@ interpret_ether(flags, e, elen, origlen)
"Source = %s, %s",
printether(&e->ether_shost),
print_etherinfo(&e->ether_shost));
- if (ieee8023 > 0)
+ if (ieee8023 > 0) {
(void) sprintf(get_line(12, 2),
- "IEEE 802.3 length = %d bytes",
- ieee8023);
+ "IEEE 802.3 length = %d bytes", ieee8023);
+ }
+ if (evx != NULL) {
+ (void) sprintf(get_line(0, 0),
+ "VLAN ID = %hu", VLAN_ID(ntohs(evx->ether_tci)));
+ (void) sprintf(get_line(0, 0),
+ "VLAN Priority = %hu", VLAN_PRI(ntohs(evx->ether_tci)));
+ }
(void) sprintf(get_line(12, 2),
"Ethertype = %04X (%s)",
ethertype, print_ethertype(ethertype));
@@ -242,12 +289,32 @@ interpret_ether(flags, e, elen, origlen)
return (elen);
}
-/* ARGSUSED */
+/*
+ * Return the length of the ethernet header. In the case
+ * where we have a VLAN tagged packet, return the length of
+ * the ethernet header plus the length of the VLAN tag.
+ *
+ * INPUTS: e - A buffer pointer. Passing a NULL pointer
+ * is not allowed, e must be non-NULL.
+ * OUTPUTS: Return the size of an untagged ethernet header
+ * if the packet is not VLAN tagged, and the size
+ * of an untagged ethernet header plus the size of
+ * a VLAN header otherwise.
+ */
uint_t
ether_header_len(e)
char *e;
{
- return (14);
+ uint16_t ether_type = 0;
+ e += (offsetof(struct ether_header, ether_type));
+
+ GETINT16(ether_type, e);
+
+ if (ether_type == (uint16_t)ETHERTYPE_VLAN) {
+ return (sizeof (struct ether_vlan_header));
+ } else {
+ return (sizeof (struct ether_header));
+ }
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c
index f025214510..a0793502a7 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_filter.c
@@ -37,6 +37,7 @@
#include <sys/socket.h>
#include <sys/sockio.h>
+#include <sys/vlan.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
@@ -54,6 +55,7 @@
#include <sys/dlpi.h>
#include <snoop.h>
+#include "snoop_vlan.h"
#define IPV4_ONLY 0
#define IPV6_ONLY 1
@@ -73,6 +75,7 @@
#define MASKED_IPV6_VERS 0x60
#define IP_HDR_LEN(p) (((*(uchar_t *)p) & 0xf) * 4)
#define TCP_HDR_LEN(p) ((((*((uchar_t *)p+12)) >> 4) & 0xf) * 4)
+
/*
* Coding the constant below is tacky, but the compiler won't let us
* be more clever. E.g., &((struct ip *)0)->ip_xxx
@@ -128,6 +131,11 @@ int opstack; /* operand stack depth */
* It points the base at the cached RPC header. For the
* purposes of selection, RPC reply headers look like call
* headers except for the direction value.
+ * OP_OFFSET_ETHERTYPE sets base according to the following
+ * algorithm:
+ * if the packet is not VLAN tagged, then set base to
+ * the ethertype field in the ethernet header
+ * else set base to the ethertype field of the VLAN header
* OP_OFFSET_POP restores the offset base to the value prior
* to the most recent OP_OFFSET call.
*/
@@ -163,6 +171,7 @@ enum optype {
OP_OFFSET_UDP,
OP_OFFSET_RPC,
OP_OFFSET_SLP,
+ OP_OFFSET_ETHERTYPE,
OP_LAST
};
@@ -198,6 +207,7 @@ static char *opnames[] = {
"OFFSET_UDP",
"OFFSET_RPC",
"OP_OFFSET_SLP",
+ "OFFSET_ETHERTYPE",
""
};
@@ -219,6 +229,27 @@ static struct xid_entry *find_rpc();
static void optimize();
static void ethertype_match();
+/*
+ * Get a ushort from a possibly unaligned character buffer.
+ *
+ * INPUTS: buffer - where the data is. Must be at least
+ * sizeof(uint16_t) bytes long.
+ * OUPUTS: An unsigned short that contains the data at buffer.
+ * No calls to ntohs or htons are done on the data.
+ */
+static uint16_t
+get_u16(uchar_t *buffer)
+{
+ uint8_t *bufraw = buffer;
+
+ /*
+ * ntohs is used only as a cheap way to flip the bits
+ * around on a little endian platform. The value will
+ * still be in host order or network order, depending on
+ * the order it was in when it was passed in.
+ */
+ return (ntohs(bufraw[0] << 8 | bufraw[1]));
+}
/*
* Returns the ULP for an IPv4 or IPv6 packet
@@ -524,6 +555,7 @@ want_packet(uchar_t *pkt, int len, int origlen)
uchar_t **offp; /* current offset */
uchar_t *opkt = NULL;
uint_t olen;
+ uint_t ethertype = 0;
sp = stack;
*sp = 1;
@@ -546,21 +578,7 @@ want_packet(uchar_t *pkt, int len, int origlen)
if ((base + off + sizeof (uint16_t) - 1) > (pkt + len))
return (0); /* packet too short */
- /*
- * Handle 2 possible alignments
- */
- switch ((((unsigned)base)+off) % sizeof (ushort_t)) {
- case 0:
- *sp = ntohs(*((ushort_t *)(base + *sp)));
- break;
- case 1:
- *((uchar_t *)(sp)) =
- *((uchar_t *)(base + off));
- *(((uchar_t *)sp) + 1) =
- *((uchar_t *)(base + off) + 1);
- *sp = ntohs(*(ushort_t *)sp);
- break;
- }
+ *sp = ntohs(get_u16((uchar_t *)(base + off)));
break;
case OP_LOAD_LONG:
off = *sp;
@@ -900,6 +918,45 @@ want_packet(uchar_t *pkt, int len, int origlen)
return (0);
*(++sp) = 0;
break;
+ case OP_OFFSET_ETHERTYPE:
+ /*
+ * Set base to the location of the ethertype.
+ * If the packet is VLAN tagged, move base
+ * to the ethertype field in the VLAN header.
+ * Otherwise, set it to the appropriate field
+ * for this link type.
+ */
+ if (offp >= &offstack[MAXSS])
+ return (0);
+ *++offp = base;
+ base = pkt + interface->network_type_offset;
+ if (base > pkt + len) {
+ /* Went too far, drop the packet */
+ return (0);
+ }
+
+ /*
+ * VLAN links are only supported on Ethernet-like
+ * links.
+ */
+ if (interface->mac_type == DL_ETHER ||
+ interface->mac_type == DL_CSMACD) {
+ if (ntohs(get_u16(base)) == ETHERTYPE_VLAN) {
+ /*
+ * We need to point to the
+ * ethertype field in the VLAN
+ * tag, so also move past the
+ * ethertype field in the
+ * ethernet header.
+ */
+ base += (ENCAP_ETHERTYPE_OFF);
+ }
+ if (base > pkt + len) {
+ /* Went too far, drop the packet */
+ return (0);
+ }
+ }
+ break;
}
}
@@ -1250,36 +1307,36 @@ static struct match_type {
} match_types[] = {
/*
* Table initialized assuming Ethernet data link headers.
+ * m_offset is an offset beyond the offset op, which is why
+ * the offset is zero for when snoop needs to check an ethertype.
*/
- "ip", 12, 2, ETHERTYPE_IP, -1, OP_OFFSET_ZERO,
- "ip6", 12, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ZERO,
- "arp", 12, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ZERO,
- "rarp", 12, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ZERO,
- "pppoed", 12, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ZERO,
- "pppoes", 12, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ZERO,
- "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK,
- "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK,
- "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK,
- "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK,
- "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK,
- "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK,
- "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK,
- "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK,
- "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK,
- "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK,
- "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK,
- "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK,
- "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK,
- "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK,
- "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK,
- 0, 0, 0, 0, 0, 0
+ "ip", 0, 2, ETHERTYPE_IP, -1, OP_OFFSET_ETHERTYPE,
+ "ip6", 0, 2, ETHERTYPE_IPV6, -1, OP_OFFSET_ETHERTYPE,
+ "arp", 0, 2, ETHERTYPE_ARP, -1, OP_OFFSET_ETHERTYPE,
+ "rarp", 0, 2, ETHERTYPE_REVARP, -1, OP_OFFSET_ETHERTYPE,
+ "pppoed", 0, 2, ETHERTYPE_PPPOED, -1, OP_OFFSET_ETHERTYPE,
+ "pppoes", 0, 2, ETHERTYPE_PPPOES, -1, OP_OFFSET_ETHERTYPE,
+ "tcp", 9, 1, IPPROTO_TCP, 0, OP_OFFSET_LINK,
+ "tcp", 6, 1, IPPROTO_TCP, 1, OP_OFFSET_LINK,
+ "udp", 9, 1, IPPROTO_UDP, 0, OP_OFFSET_LINK,
+ "udp", 6, 1, IPPROTO_UDP, 1, OP_OFFSET_LINK,
+ "icmp", 9, 1, IPPROTO_ICMP, 0, OP_OFFSET_LINK,
+ "icmp6", 6, 1, IPPROTO_ICMPV6, 1, OP_OFFSET_LINK,
+ "ospf", 9, 1, IPPROTO_OSPF, 0, OP_OFFSET_LINK,
+ "ospf", 6, 1, IPPROTO_OSPF, 1, OP_OFFSET_LINK,
+ "ip-in-ip", 9, 1, IPPROTO_ENCAP, 0, OP_OFFSET_LINK,
+ "esp", 9, 1, IPPROTO_ESP, 0, OP_OFFSET_LINK,
+ "esp", 6, 1, IPPROTO_ESP, 1, OP_OFFSET_LINK,
+ "ah", 9, 1, IPPROTO_AH, 0, OP_OFFSET_LINK,
+ "ah", 6, 1, IPPROTO_AH, 1, OP_OFFSET_LINK,
+ "sctp", 9, 1, IPPROTO_SCTP, 0, OP_OFFSET_LINK,
+ "sctp", 6, 1, IPPROTO_SCTP, 1, OP_OFFSET_LINK,
+ 0, 0, 0, 0, 0, 0
};
static void
generate_check(struct match_type *mtp)
{
- int offset;
-
/*
* Note: this code assumes the above dependencies are
* not cyclic. This *should* always be true.
@@ -1287,45 +1344,10 @@ generate_check(struct match_type *mtp)
if (mtp->m_depend != -1)
generate_check(&match_types[mtp->m_depend]);
- offset = mtp->m_offset;
- if (mtp->m_optype == OP_OFFSET_ZERO) {
-
- /*
- * The table is filled with ethernet offsets. Here we
- * fudge the value based on what know about the
- * interface. It is okay to do this because we are
- * checking what we believe to be an IP/ARP/RARP
- * packet, and we know those are carried in LLC-SNAP
- * headers on FDDI. We assume that it's unlikely
- * another kind of packet, with a shorter FDDI header
- * will happen to match the filter.
- *
- * Ether FDDI IPoIB
- * edst addr 0 1 none
- * esrc addr 6 7 none
- * ethertype 12 19 0
- *
- * XXX token ring?
- */
- if (interface->mac_type == DL_FDDI) {
- if (offset < 12)
- offset++;
- else if (offset == 12)
- offset = 19;
- } else if (interface->mac_type == DL_IB) {
- offset = 0;
- }
- }
-
- if (mtp->m_optype != OP_OFFSET_ZERO) {
- emitop(mtp->m_optype);
- load_value(offset, mtp->m_size);
- load_const(mtp->m_value);
- emitop(OP_OFFSET_POP);
- } else {
- load_value(offset, mtp->m_size);
- load_const(mtp->m_value);
- }
+ emitop(mtp->m_optype);
+ load_value(mtp->m_offset, mtp->m_size);
+ load_const(mtp->m_value);
+ emitop(OP_OFFSET_POP);
emitop(OP_EQ);
@@ -1732,6 +1754,7 @@ etheraddr_match(enum direction which, char *hostname)
memcpy(&addr, (ushort_t *)ep, 4);
addrp = (ushort_t *)ep + 2;
+ emitop(OP_OFFSET_ZERO);
switch (which) {
case TO:
compare_value(to_offset, 4, ntohl(addr));
@@ -1760,33 +1783,40 @@ etheraddr_match(enum direction which, char *hostname)
resolve_chain(m);
break;
}
+ emitop(OP_OFFSET_POP);
}
static void
ethertype_match(int val)
{
- int m;
- int ether_offset;
-
- switch (interface->mac_type) {
- case DL_ETHER:
- ether_offset = 12;
- break;
-
- case DL_IB:
- ether_offset = 0;
- break;
+ int ether_offset = interface->network_type_offset;
- case DL_FDDI:
- /* XXX Okay to assume LLC SNAP? */
- ether_offset = 19;
- break;
-
- default:
- load_const(1); /* Assume a match */
- return;
+ /*
+ * If the user is interested in ethertype VLAN,
+ * then we need to set the offset to the beginning of the packet.
+ * But if the user is interested in another ethertype,
+ * such as IPv4, then we need to take into consideration
+ * the fact that the packet might be VLAN tagged.
+ */
+ if (interface->mac_type == DL_ETHER ||
+ interface->mac_type == DL_CSMACD) {
+ if (val != ETHERTYPE_VLAN) {
+ /*
+ * OP_OFFSET_ETHERTYPE puts us at the ethertype
+ * field whether or not there is a VLAN tag,
+ * so ether_offset goes to zero if we get here.
+ */
+ emitop(OP_OFFSET_ETHERTYPE);
+ ether_offset = 0;
+ } else {
+ emitop(OP_OFFSET_ZERO);
+ }
+ }
+ compare_value(ether_offset, 2, val);
+ if (interface->mac_type == DL_ETHER ||
+ interface->mac_type == DL_CSMACD) {
+ emitop(OP_OFFSET_POP);
}
- compare_value(ether_offset, 2, val); /* XXX.sparker */
}
/*
@@ -2076,9 +2106,11 @@ primary()
* bytes long, this works for FDDI & ethernet.
* XXX - Token ring?
*/
+ emitop(OP_OFFSET_ZERO);
if (interface->mac_type == DL_IB)
pr_err("filter option unsupported on media");
compare_value(1, 4, 0xffffffff);
+ emitop(OP_OFFSET_POP);
opstack++;
next();
break;
@@ -2086,6 +2118,7 @@ primary()
if (EQ("multicast")) {
/* XXX Token ring? */
+ emitop(OP_OFFSET_ZERO);
if (interface->mac_type == DL_FDDI) {
compare_value_mask(1, 1, 0x01, 0x01);
} else if (interface->mac_type == DL_IB) {
@@ -2093,6 +2126,7 @@ primary()
} else {
compare_value_mask(0, 1, 0x01, 0x01);
}
+ emitop(OP_OFFSET_POP);
opstack++;
next();
break;
@@ -2111,21 +2145,40 @@ primary()
emitop(OP_LE);
resolve_chain(m);
} else {
- load_value(12, 2); /* ether type */
+ emitop(OP_OFFSET_ETHERTYPE);
+ load_value(0, 2); /* ether type */
load_const(0x6000);
emitop(OP_GE);
emitop(OP_BRFL);
m = chain(0);
- load_value(12, 2); /* ether type */
+ load_value(0, 2); /* ether type */
load_const(0x6009);
emitop(OP_LE);
resolve_chain(m);
+ emitop(OP_OFFSET_POP);
}
opstack++;
next();
break;
}
+ if (EQ("vlan-id")) {
+ next();
+ if (tokentype != NUMBER)
+ pr_err("vlan id expected");
+ emitop(OP_OFFSET_ZERO);
+ ethertype_match(ETHERTYPE_VLAN);
+ emitop(OP_BRFL);
+ m = chain(0);
+ compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
+ VLAN_ID_MASK);
+ resolve_chain(m);
+ emitop(OP_OFFSET_POP);
+ opstack++;
+ next();
+ break;
+ }
+
if (EQ("apple")) {
/*
* Appletalk also appears in 802.2
@@ -2148,6 +2201,16 @@ primary()
break;
}
+ if (EQ("vlan")) {
+ ethertype_match(ETHERTYPE_VLAN);
+ compare_value_mask(VLAN_ID_OFFSET, 2, 0, VLAN_ID_MASK);
+ emitop(OP_NOT);
+ emitop(OP_AND);
+ opstack++;
+ next();
+ break;
+ }
+
if (EQ("bootp") || EQ("dhcp")) {
emitop(OP_OFFSET_LINK);
emitop(OP_LOAD_CONST);
@@ -2163,6 +2226,8 @@ primary()
compare_value(0, 4,
(IPPORT_BOOTPC << 16 | IPPORT_BOOTPS));
resolve_chain(m);
+ emitop(OP_OFFSET_POP);
+ emitop(OP_OFFSET_POP);
opstack++;
dir = ANY;
next();
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c
index 8ef09a2fc9..072d05f833 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.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.
@@ -20,13 +19,14 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */
#include <stdio.h>
+#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
@@ -38,6 +38,7 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/dlpi.h>
+#include <sys/vlan.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
@@ -51,6 +52,7 @@
#include <sys/pfmod.h>
#include "snoop.h"
+#include "snoop_vlan.h"
/*
* This module generates code for the kernel packet filter.
@@ -97,8 +99,8 @@ static int link_addr_len = 6;
#define IPV4_DSTADDR_OFFSET (link_header_len + 16)
#define IPV6_SRCADDR_OFFSET (link_header_len + 8)
#define IPV6_DSTADDR_OFFSET (link_header_len + 24)
-#define IPV4_TYPE_OFFSET (link_header_len + 9)
-#define IPV6_TYPE_OFFSET (link_header_len + 6)
+#define IPV4_TYPE_HEADER_OFFSET (9)
+#define IPV6_TYPE_HEADER_OFFSET (6)
static int inBrace = 0, inBraceOR = 0;
static int foundOR = 0;
@@ -114,6 +116,26 @@ enum direction dir;
extern void next();
static void pf_expression();
+static void pf_check_vlan_tag(uint_t offset);
+static void pf_clear_offset_register();
+static void pf_emit_load_offset(uint_t offset);
+static void pf_match_ethertype(uint_t ethertype);
+static void pf_check_transport_protocol(uint_t transport_protocol);
+static void pf_compare_value_mask_generic(int offset, uint_t len,
+ uint_t val, int mask, uint_t op);
+
+/*
+ * This pointer points to the function that last generated
+ * instructions to change the offset register. It's used
+ * for comparisons to see if we need to issue more instructions
+ * to change the register.
+ *
+ * It's initialized to pf_clear_offset_register because the offset
+ * register in pfmod is initialized to zero, similar to the state
+ * it would be in after executing the instructions issued by
+ * pf_clear_offset_register.
+ */
+static void *last_offset_operation = (void*)pf_clear_offset_register;
static void
pf_emit(x)
@@ -170,6 +192,18 @@ pf_codeprint(code, len)
printf("PUSH00FF ");
break;
#endif
+ case ENF_LOAD_OFFSET:
+ printf("LOAD_OFFSET ");
+ break;
+ case ENF_BRTR:
+ printf("BRTR ");
+ break;
+ case ENF_BRFL:
+ printf("BRFL ");
+ break;
+ case ENF_POP:
+ printf("POP ");
+ break;
}
if (action >= ENF_PUSHWORD)
@@ -217,7 +251,10 @@ pf_codeprint(code, len)
break;
}
- if (action == ENF_PUSHLIT) {
+ if (action == ENF_PUSHLIT ||
+ action == ENF_LOAD_OFFSET ||
+ action == ENF_BRTR ||
+ action == ENF_BRFL) {
pc++;
printf("\n\t%3d: %d (0x%04x)", pc - code, *pc, *pc);
}
@@ -323,11 +360,36 @@ pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
/*
* Same as above except mask the field value
- * before doing the comparison.
+ * before doing the comparison. The comparison checks
+ * to make sure the values are equal.
*/
static void
pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
{
+ pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
+}
+
+/*
+ * Same as above except the values are compared to see if they are not
+ * equal.
+ */
+static void
+pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
+{
+ pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
+}
+
+/*
+ * Similar to pf_compare_value.
+ *
+ * This is the utility function that does the actual work to compare
+ * two values using a mask. The comparison operation is passed into
+ * the function.
+ */
+static void
+pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
+ uint_t op)
+{
/*
* If the property being filtered on is absent in the media
* packet, error out.
@@ -346,12 +408,12 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
{
pf_emit(ENF_PUSHLIT | ENF_AND);
pf_emit(mask & 0x00ff);
- pf_emit(ENF_PUSHLIT | ENF_EQ);
+ pf_emit(ENF_PUSHLIT | op);
pf_emit(val);
} else {
pf_emit(ENF_PUSHLIT | ENF_AND);
pf_emit((mask << 8) & 0xff00);
- pf_emit(ENF_PUSHLIT | ENF_EQ);
+ pf_emit(ENF_PUSHLIT | op);
pf_emit(val << 8);
}
break;
@@ -360,7 +422,7 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
pf_emit(ENF_PUSHWORD + offset / 2);
pf_emit(ENF_PUSHLIT | ENF_AND);
pf_emit(htons((ushort_t)mask));
- pf_emit(ENF_PUSHLIT | ENF_EQ);
+ pf_emit(ENF_PUSHLIT | op);
pf_emit(htons((ushort_t)val));
break;
@@ -368,13 +430,13 @@ pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
pf_emit(ENF_PUSHWORD + offset / 2);
pf_emit(ENF_PUSHLIT | ENF_AND);
pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
- pf_emit(ENF_PUSHLIT | ENF_EQ);
+ pf_emit(ENF_PUSHLIT | op);
pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
pf_emit(ENF_PUSHLIT | ENF_AND);
pf_emit(htons((ushort_t)(mask & 0xffff)));
- pf_emit(ENF_PUSHLIT | ENF_EQ);
+ pf_emit(ENF_PUSHLIT | op);
pf_emit(htons((ushort_t)(val & 0xffff)));
pf_emit(ENF_AND);
@@ -491,7 +553,8 @@ pf_ipaddr_match(which, hostname, inet_type)
}
if (hp != NULL && hp->h_addrtype == AF_INET) {
- pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_IP));
+ pf_match_ethertype(ETHERTYPE_IP);
+ pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
h_addr_index = 0;
addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
while (addr4ptr != NULL) {
@@ -520,8 +583,9 @@ pf_ipaddr_match(which, hostname, inet_type)
while (addr6ptr != NULL) {
if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
if (first) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
+ pf_match_ethertype(ETHERTYPE_IP);
+ pf_check_vlan_tag(
+ ENCAP_ETHERTYPE_OFF/2);
pass++;
}
IN6_V4MAPPED_TO_INADDR(addr6ptr,
@@ -556,8 +620,9 @@ pf_ipaddr_match(which, hostname, inet_type)
while (addr6ptr != NULL) {
if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
if (first) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
+ pf_match_ethertype(ETHERTYPE_IPV6);
+ pf_check_vlan_tag(
+ ENCAP_ETHERTYPE_OFF/2);
pass++;
}
if (addr6offset == -1) {
@@ -651,6 +716,8 @@ pf_etheraddr_match(which, hostname)
ep = &e;
}
+ pf_clear_offset_register();
+
switch (which) {
case TO:
pf_compare_address(link_dest_offset, link_addr_len,
@@ -705,6 +772,8 @@ pf_netaddr_match(which, netname)
}
}
+ pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
+
switch (which) {
case TO:
pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
@@ -720,6 +789,223 @@ pf_netaddr_match(which, netname)
}
}
+/*
+ * A helper function to keep the code to emit instructions
+ * to change the offset register in one place.
+ *
+ * INPUTS: offset - An value representing an offset in 16-bit
+ * words.
+ * OUTPUTS: If there is enough room in the storage for the
+ * packet filtering program, instructions to load
+ * a constant to the offset register. Otherwise,
+ * nothing.
+ */
+static void
+pf_emit_load_offset(uint_t offset)
+{
+ pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
+ pf_emit(offset);
+}
+
+/*
+ * Clear pfmod's offset register.
+ *
+ * INPUTS: none
+ * OUTPUTS: Instructions to clear the offset register if
+ * there is enough space remaining in the packet
+ * filtering program structure's storage, and
+ * the last thing done to the offset register was
+ * not clearing the offset register. Otherwise,
+ * nothing.
+ */
+static void
+pf_clear_offset_register()
+{
+ if (last_offset_operation != (void*)pf_clear_offset_register) {
+ pf_emit_load_offset(0);
+ last_offset_operation = (void*)pf_clear_offset_register;
+ }
+}
+
+/*
+ * This function will issue opcodes to check if a packet
+ * is VLAN tagged, and if so, update the offset register
+ * with the appropriate offset.
+ *
+ * Note that if the packet is not VLAN tagged, then the offset
+ * register will be cleared.
+ *
+ * If the interface type is not an ethernet type, then this
+ * function returns without doing anything.
+ *
+ * If the last attempt to change the offset register occured because
+ * of a call to this function that was called with the same offset,
+ * then we don't issue packet filtering instructions.
+ *
+ * INPUTS: offset - an offset in 16 bit words. The function
+ * will set the offset register to this
+ * value if the packet is VLAN tagged.
+ * OUTPUTS: If the conditions are met, packet filtering instructions.
+ */
+static void
+pf_check_vlan_tag(uint_t offset)
+{
+ static uint_t last_offset = 0;
+
+ if ((interface->mac_type == DL_ETHER ||
+ interface->mac_type == DL_CSMACD) &&
+ (last_offset_operation != (void*)pf_check_vlan_tag ||
+ last_offset != offset)) {
+ /*
+ * First thing is to clear the offset register.
+ * We don't know what state it is in, and if it
+ * is not zero, then we have no idea what we load
+ * when we execute ENF_PUSHWORD.
+ */
+ pf_clear_offset_register();
+
+ /*
+ * Check the ethertype.
+ */
+ pf_compare_value(link_type_offset, 2, htons(ETHERTYPE_VLAN));
+
+ /*
+ * And if it's not VLAN, don't load offset to the offset
+ * register.
+ */
+ pf_emit(ENF_BRFL | ENF_NOP);
+ pf_emit(3);
+
+ /*
+ * Otherwise, load offset to the offset register.
+ */
+ pf_emit_load_offset(offset);
+
+ /*
+ * Now get rid of the results of the comparison,
+ * we don't want the results of the comparison to affect
+ * other logic in the packet filtering program.
+ */
+ pf_emit(ENF_POP | ENF_NOP);
+
+ /*
+ * Set the last operation at the end, or any time
+ * after the call to pf_clear_offset because
+ * pf_clear_offset uses it.
+ */
+ last_offset_operation = (void*)pf_check_vlan_tag;
+ last_offset = offset;
+ }
+}
+
+/*
+ * Utility function used to emit packet filtering code
+ * to match an ethertype.
+ *
+ * INPUTS: ethertype - The ethertype we want to check for.
+ * Don't call htons on the ethertype before
+ * calling this function.
+ * OUTPUTS: If there is sufficient storage available, packet
+ * filtering code to check an ethertype. Otherwise,
+ * nothing.
+ */
+static void
+pf_match_ethertype(uint_t ethertype)
+{
+ /*
+ * If the user wants to filter on ethertype VLAN,
+ * then clear the offset register so that the offset
+ * for ENF_PUSHWORD points to the right place in the
+ * packet.
+ *
+ * Otherwise, call pf_check_vlan_tag to set the offset
+ * register such that the contents of the offset register
+ * plus the argument for ENF_PUSHWORD point to the right
+ * part of the packet, whether or not the packet is VLAN
+ * tagged. We call pf_check_vlan_tag with an offset of
+ * two words because if the packet is VLAN tagged, we have
+ * to move past the ethertype in the ethernet header, and
+ * past the lower two octets of the VLAN header to get to
+ * the ethertype in the VLAN header.
+ */
+ if (ethertype == ETHERTYPE_VLAN)
+ pf_clear_offset_register();
+ else
+ pf_check_vlan_tag(2);
+
+ pf_compare_value(link_type_offset, 2, htons(ethertype));
+}
+
+typedef struct {
+ int transport_protocol;
+ int network_protocol;
+ /*
+ * offset is the offset in bytes from the beginning
+ * of the network protocol header to where the transport
+ * protocol type is.
+ */
+ int offset;
+} transport_protocol_table_t;
+
+static transport_protocol_table_t mapping_table[] = {
+ {IPPROTO_TCP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_UDP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_OSPF, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_SCTP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_ICMP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_ENCAP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_ESP, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {IPPROTO_AH, ETHERTYPE_IP, IPV4_TYPE_HEADER_OFFSET},
+ {IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
+ {-1, 0, 0} /* must be the final entry */
+};
+
+/*
+ * This function uses the table above to generate a
+ * piece of a packet filtering program to check a transport
+ * protocol type.
+ *
+ * INPUTS: tranport_protocol - the transport protocol we're
+ * interested in.
+ * OUTPUTS: If there is sufficient storage, then packet filtering
+ * code to check a transport protocol type. Otherwise,
+ * nothing.
+ */
+static void
+pf_check_transport_protocol(uint_t transport_protocol)
+{
+ int i = 0;
+ uint_t number_of_matches = 0;
+
+ for (i = 0; mapping_table[i].transport_protocol != -1; i++) {
+ if (transport_protocol ==
+ (uint_t)mapping_table[i].transport_protocol) {
+ number_of_matches++;
+ pf_match_ethertype(mapping_table[i].network_protocol);
+ pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
+ pf_compare_value(
+ mapping_table[i].offset + link_header_len, 1,
+ transport_protocol);
+ pf_emit(ENF_AND);
+ if (number_of_matches > 1) {
+ /*
+ * Since we have two or more matches, in
+ * order to have a correct and complete
+ * program we need to OR the result of
+ * each block of comparisons together.
+ */
+ pf_emit(ENF_OR);
+ }
+ }
+ }
+}
+
static void
pf_primary()
{
@@ -728,26 +1014,22 @@ pf_primary()
break;
if (EQ("ip")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
+ pf_match_ethertype(ETHERTYPE_IP);
opstack++;
next();
break;
}
if (EQ("ip6")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
+ pf_match_ethertype(ETHERTYPE_IPV6);
opstack++;
next();
break;
}
if (EQ("pppoe")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_PPPOED));
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_PPPOES));
+ pf_match_ethertype(ETHERTYPE_PPPOED);
+ pf_match_ethertype(ETHERTYPE_PPPOES);
pf_emit(ENF_OR);
opstack++;
next();
@@ -755,77 +1037,72 @@ pf_primary()
}
if (EQ("pppoed")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_PPPOED));
+ pf_match_ethertype(ETHERTYPE_PPPOED);
opstack++;
next();
break;
}
if (EQ("pppoes")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_PPPOES));
+ pf_match_ethertype(ETHERTYPE_PPPOES);
opstack++;
next();
break;
}
if (EQ("arp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_ARP));
+ pf_match_ethertype(ETHERTYPE_ARP);
+ opstack++;
+ next();
+ break;
+ }
+
+ if (EQ("vlan")) {
+ pf_match_ethertype(ETHERTYPE_VLAN);
+ pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
+ 0, VLAN_ID_MASK);
+ pf_emit(ENF_AND);
+ opstack++;
+ next();
+ break;
+ }
+
+ if (EQ("vlan-id")) {
+ next();
+ if (tokentype != NUMBER)
+ pr_err("VLAN ID expected");
+ pf_match_ethertype(ETHERTYPE_VLAN);
+ pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
+ VLAN_ID_MASK);
+ pf_emit(ENF_AND);
opstack++;
next();
break;
}
if (EQ("rarp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_REVARP));
+ pf_match_ethertype(ETHERTYPE_REVARP);
opstack++;
next();
break;
}
if (EQ("tcp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_TCP);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_TCP);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_TCP);
opstack++;
next();
break;
}
if (EQ("udp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_UDP);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_UDP);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_UDP);
opstack++;
next();
break;
}
if (EQ("ospf")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_OSPF);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_OSPF);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_OSPF);
opstack++;
next();
break;
@@ -833,75 +1110,42 @@ pf_primary()
if (EQ("sctp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_SCTP);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_SCTP);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_SCTP);
opstack++;
next();
break;
}
if (EQ("icmp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ICMP);
- pf_emit(ENF_AND);
+ pf_check_transport_protocol(IPPROTO_ICMP);
opstack++;
next();
break;
}
if (EQ("icmp6")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ICMPV6);
- pf_emit(ENF_AND);
+ pf_check_transport_protocol(IPPROTO_ICMPV6);
opstack++;
next();
break;
}
if (EQ("ip-in-ip")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ENCAP);
- pf_emit(ENF_AND);
+ pf_check_transport_protocol(IPPROTO_ENCAP);
opstack++;
next();
break;
}
if (EQ("esp")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_ESP);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_ESP);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_ESP);
opstack++;
next();
break;
}
if (EQ("ah")) {
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IP));
- pf_compare_value(IPV4_TYPE_OFFSET, 1, IPPROTO_AH);
- pf_emit(ENF_AND);
- pf_compare_value(link_type_offset, 2,
- htons(ETHERTYPE_IPV6));
- pf_compare_value(IPV6_TYPE_OFFSET, 1, IPPROTO_AH);
- pf_emit(ENF_AND);
- pf_emit(ENF_OR);
+ pf_check_transport_protocol(IPPROTO_AH);
opstack++;
next();
break;
@@ -966,13 +1210,15 @@ pf_primary()
next();
if (tokentype != NUMBER)
pr_err("IP proto type expected");
- pf_compare_value(IPV4_TYPE_OFFSET, 1, tokenval);
+ pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
+ pf_compare_value(IPV4_TYPE_HEADER_OFFSET, 1, tokenval);
opstack++;
next();
break;
}
if (EQ("broadcast")) {
+ pf_clear_offset_register();
pf_compare_value(link_dest_offset, 4, 0xffffffff);
opstack++;
next();
@@ -980,6 +1226,7 @@ pf_primary()
}
if (EQ("multicast")) {
+ pf_clear_offset_register();
pf_compare_value_mask(link_dest_offset, 1, 0x01, 0x01);
opstack++;
next();
@@ -990,7 +1237,7 @@ pf_primary()
next();
if (tokentype != NUMBER)
pr_err("ether type expected");
- pf_compare_value(link_type_offset, 2, htons(tokenval));
+ pf_match_ethertype(tokenval);
opstack++;
next();
break;
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h
new file mode 100644
index 0000000000..068bcb577b
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_vlan.h
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * 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.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SNOOP_VLAN_H
+#define _SNOOP_VLAN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ethernet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The offset in bytes, in a VLAN tagged packet, from the
+ * ethernet header ethertype (which is ETHERTYPE_VLAN) to
+ * the encapsulated ethertype.
+ */
+#define ENCAP_ETHERTYPE_OFF (offsetof(struct ether_vlan_header, ether_type) -\
+ offsetof(struct ether_vlan_header, ether_tpid))
+
+/*
+ * The offset in bytes, from the beginning of an ethernet header,
+ * to the VLAN ID.
+ */
+#define VLAN_ID_OFFSET (offsetof(struct ether_vlan_header, ether_tci) -\
+ offsetof(struct ether_vlan_header, ether_dhost))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SNOOP_VLAN_H */
diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386
index c208110ff3..245922942f 100644
--- a/usr/src/pkgdefs/etc/exception_list_i386
+++ b/usr/src/pkgdefs/etc/exception_list_i386
@@ -501,6 +501,7 @@ usr/include/sys/dumpadm.h i386
usr/include/sys/ontrap.h i386
usr/include/sys/sysmsg_impl.h i386
usr/include/sys/cryptmod.h i386
+usr/include/sys/vlan.h i386
#
# These files are installed in the proto area so lvm can use
# them during the build process.
diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc
index 2eeae9517a..565291281e 100644
--- a/usr/src/pkgdefs/etc/exception_list_sparc
+++ b/usr/src/pkgdefs/etc/exception_list_sparc
@@ -508,6 +508,7 @@ usr/include/sys/dumpadm.h sparc
usr/include/sys/ontrap.h sparc
usr/include/sys/sysmsg_impl.h sparc
usr/include/sys/cryptmod.h sparc
+usr/include/sys/vlan.h sparc
#
# These files are installed in the proto area so lvm can use
# them during the build process.
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 7ff59d9b84..079b88d8e5 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -2968,6 +2968,8 @@ extern uint32_t ipsechw_debug;
struct ipsec_out_s;
+struct mac_header_info_s;
+
extern const char *dlpi_prim_str(int);
extern const char *dlpi_err_str(int);
extern void ill_frag_timer(void *);
@@ -3002,7 +3004,8 @@ extern int ip_reassemble(mblk_t *, ipf_t *, uint_t, boolean_t, ill_t *,
extern int ip_opt_set_ill(conn_t *, int, boolean_t, boolean_t,
int, int, mblk_t *);
extern void ip_rput(queue_t *, mblk_t *);
-extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, size_t);
+extern void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *,
+ struct mac_header_info_s *);
extern void ip_rput_dlpi(queue_t *, mblk_t *);
extern void ip_rput_forward(ire_t *, ipha_t *, mblk_t *, ill_t *);
extern void ip_rput_forward_multicast(ipaddr_t, mblk_t *, ipif_t *);
@@ -3308,7 +3311,7 @@ extern int ip_squeue_bind_get(queue_t *, mblk_t *, caddr_t, cred_t *);
extern void ip_squeue_clean(void *, mblk_t *, void *);
extern void ip_resume_tcp_bind(void *, mblk_t *, void *);
extern void ip_soft_ring_assignment(ill_t *, ill_rx_ring_t *,
- mblk_t *, size_t);
+ mblk_t *, struct mac_header_info_s *);
extern void tcp_wput(queue_t *, mblk_t *);
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index aa0d4f3ead..00a1e4275f 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -836,8 +836,6 @@ static int ip_conn_report(queue_t *, mblk_t *, caddr_t, cred_t *);
static mblk_t *ip_tcp_input(mblk_t *, ipha_t *, ill_t *, boolean_t,
ire_t *, mblk_t *, uint_t, queue_t *, ill_rx_ring_t *);
-void ip_input(ill_t *, ill_rx_ring_t *, mblk_t *, size_t);
-
static void ip_rput_process_forward(queue_t *, mblk_t *, ire_t *,
ipha_t *, ill_t *, boolean_t);
@@ -14358,7 +14356,7 @@ ip_rput(queue_t *q, mblk_t *mp)
TRACE_2(TR_FAC_IP, TR_IP_RPUT_END,
"ip_rput_end: q %p (%S)", q, "end");
- ip_input(ill, NULL, mp, 0);
+ ip_input(ill, NULL, mp, NULL);
}
/*
@@ -14369,10 +14367,19 @@ ip_rput(queue_t *q, mblk_t *mp)
*
* The ill will always be valid if this function is called directly from
* the driver.
+ *
+ * If ip_input() is called from GLDv3:
+ *
+ * - This must be a non-VLAN IP stream.
+ * - 'mp' is either an untagged or a special priority-tagged packet.
+ * - Any VLAN tag that was in the MAC header has been stripped.
+ *
+ * Thus, there is no need to adjust b_rptr in this function.
*/
/* ARGSUSED */
void
-ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, size_t hdrlen)
+ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain,
+ struct mac_header_info_s *mhip)
{
ipaddr_t dst = NULL;
ipaddr_t prev_dst;
diff --git a/usr/src/uts/common/inet/ip/ip_squeue.c b/usr/src/uts/common/inet/ip/ip_squeue.c
index 417b1580eb..5c1da7c964 100644
--- a/usr/src/uts/common/inet/ip/ip_squeue.c
+++ b/usr/src/uts/common/inet/ip/ip_squeue.c
@@ -596,7 +596,7 @@ ip_squeue_soft_ring_affinity(void *arg)
/* ARGSUSED */
void
ip_soft_ring_assignment(ill_t *ill, ill_rx_ring_t *ip_ring,
-mblk_t *mp_chain, size_t hdrlen)
+ mblk_t *mp_chain, struct mac_header_info_s *mhip)
{
ip_taskq_arg_t *taskq_arg;
boolean_t refheld;
@@ -645,7 +645,7 @@ mblk_t *mp_chain, size_t hdrlen)
kmem_free(taskq_arg, sizeof (ip_taskq_arg_t));
out:
- ip_input(ill, NULL, mp_chain, hdrlen);
+ ip_input(ill, NULL, mp_chain, mhip);
}
static squeue_t *
diff --git a/usr/src/uts/common/io/aggr/aggr_send.c b/usr/src/uts/common/io/aggr/aggr_send.c
index 9c13d1b50d..6c5787a297 100644
--- a/usr/src/uts/common/io/aggr/aggr_send.c
+++ b/usr/src/uts/common/io/aggr/aggr_send.c
@@ -84,7 +84,7 @@ aggr_send_port(aggr_grp_t *grp, mblk_t *mp)
/* skip ethernet header */
- if (ntohs(ehp->ether_type) == VLAN_TPID) {
+ if (ntohs(ehp->ether_type) == ETHERTYPE_VLAN) {
struct ether_vlan_header *evhp;
ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header));
diff --git a/usr/src/uts/common/io/bge/bge_recv2.c b/usr/src/uts/common/io/bge/bge_recv2.c
index 8126e05b9a..8eea27b476 100644
--- a/usr/src/uts/common/io/bge/bge_recv2.c
+++ b/usr/src/uts/common/io/bge/bge_recv2.c
@@ -208,7 +208,7 @@ bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p)
mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM - VLAN_TAGSZ;
bcopy(DMA_VPTR(srbdp->pbuf), dp, 2 * ETHERADDRL);
ehp = (struct ether_vlan_header *)dp;
- ehp->ether_tpid = ntohs(VLAN_TPID);
+ ehp->ether_tpid = ntohs(ETHERTYPE_VLAN);
ehp->ether_tci = ntohs(hw_rbd.vlan_tci);
bcopy(((uchar_t *)(DMA_VPTR(srbdp->pbuf))) + 2 * ETHERADDRL,
dp + 2 * ETHERADDRL + VLAN_TAGSZ,
diff --git a/usr/src/uts/common/io/bge/bge_send.c b/usr/src/uts/common/io/bge/bge_send.c
index d872b813c4..d886d19636 100644
--- a/usr/src/uts/common/io/bge/bge_send.c
+++ b/usr/src/uts/common/io/bge/bge_send.c
@@ -407,7 +407,7 @@ bge_send(bge_t *bgep, mblk_t *mp)
ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
ehp = (struct ether_vlan_header *)mp->b_rptr;
- if (ehp->ether_tpid == htons(VLAN_TPID)) {
+ if (ehp->ether_tpid == htons(ETHERTYPE_VLAN)) {
if (MBLKL(mp) < sizeof (struct ether_vlan_header)) {
uint32_t pflags;
diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c
index 467d55c2d1..3d5db8d82e 100644
--- a/usr/src/uts/common/io/dld/dld_proto.c
+++ b/usr/src/uts/common/io/dld/dld_proto.c
@@ -301,46 +301,35 @@ proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
dlp->dl_brdcst_addr_length = addr_length;
}
- /*
- * We only support QoS information for VLAN interfaces.
- */
- if (dsp->ds_vid != VLAN_ID_NONE) {
- dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
- dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
+ dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
+ dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
- rangep->dl_qos_type = DL_QOS_CL_RANGE1;
- rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
- rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
- rangep->dl_protection.dl_min = DL_UNKNOWN;
- rangep->dl_protection.dl_max = DL_UNKNOWN;
- rangep->dl_residual_error = DL_UNKNOWN;
+ rangep->dl_qos_type = DL_QOS_CL_RANGE1;
+ rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
+ rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
+ rangep->dl_protection.dl_min = DL_UNKNOWN;
+ rangep->dl_protection.dl_max = DL_UNKNOWN;
+ rangep->dl_residual_error = DL_UNKNOWN;
- /*
- * Specify the supported range of priorities.
- */
- rangep->dl_priority.dl_min = 0;
- rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
+ /*
+ * Specify the supported range of priorities.
+ */
+ rangep->dl_priority.dl_min = 0;
+ rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
- dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
- dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
+ dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
+ dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
- selp->dl_qos_type = DL_QOS_CL_SEL1;
- selp->dl_trans_delay = DL_UNKNOWN;
- selp->dl_protection = DL_UNKNOWN;
- selp->dl_residual_error = DL_UNKNOWN;
+ selp->dl_qos_type = DL_QOS_CL_SEL1;
+ selp->dl_trans_delay = DL_UNKNOWN;
+ selp->dl_protection = DL_UNKNOWN;
+ selp->dl_residual_error = DL_UNKNOWN;
- /*
- * Specify the current priority (which can be changed by
- * the DL_UDQOS_REQ primitive).
- */
- selp->dl_priority = dsp->ds_pri;
- } else {
- /*
- * Shorten the buffer to lose the unused QoS information
- * structures.
- */
- mp->b_wptr = (uint8_t *)rangep;
- }
+ /*
+ * Specify the current priority (which can be changed by
+ * the DL_UDQOS_REQ primitive).
+ */
+ selp->dl_priority = dsp->ds_pri;
dlp->dl_addr_length = addr_length + sizeof (uint16_t);
if (dsp->ds_dlstate == DL_IDLE) {
@@ -1100,8 +1089,7 @@ proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
goto failed;
}
- if (dsp->ds_vid == VLAN_ID_NONE ||
- selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
+ if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
selp->dl_priority < 0) {
dl_err = DL_BADQOSPARAM;
goto failed;
@@ -1476,8 +1464,8 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
/*
* Build a packet header.
*/
- bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri, payload);
- if (bp == NULL) {
+ if ((bp = dls_header(dsp->ds_dc, addr, sap, dlp->dl_priority.dl_max,
+ &payload)) == NULL) {
dl_err = DL_BADADDR;
goto failed;
}
@@ -1500,7 +1488,7 @@ proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp)
ASSERT(bp->b_cont == NULL);
bp->b_cont = payload;
- str_mdata_fastpath_put(dsp, bp);
+ dld_tx_single(dsp, bp);
rw_exit(&dsp->ds_lock);
return (B_TRUE);
failed:
diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c
index 29ea09c260..d8335c4fe5 100644
--- a/usr/src/uts/common/io/dld/dld_str.c
+++ b/usr/src/uts/common/io/dld/dld_str.c
@@ -42,7 +42,7 @@
static int str_constructor(void *, void *, int);
static void str_destructor(void *, void *);
-static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *);
+static mblk_t *str_unitdata_ind(dld_str_t *, mblk_t *, boolean_t);
static void str_notify_promisc_on_phys(dld_str_t *);
static void str_notify_promisc_off_phys(dld_str_t *);
static void str_notify_phys_addr(dld_str_t *, const uint8_t *);
@@ -58,6 +58,9 @@ static void ioc(dld_str_t *, mblk_t *);
static void dld_ioc(dld_str_t *, mblk_t *);
static minor_t dld_minor_hold(boolean_t);
static void dld_minor_rele(minor_t);
+static void str_mdata_raw_put(dld_str_t *, mblk_t *);
+static mblk_t *i_dld_ether_header_update_tag(mblk_t *, uint_t, uint16_t);
+static mblk_t *i_dld_ether_header_strip_tag(mblk_t *);
static uint32_t str_count;
static kmem_cache_t *str_cachep;
@@ -79,8 +82,8 @@ static mod_hash_t *str_hashp;
* the DL_CAPAB_POLL negotiation. The put procedure handles all control
* and data operations, while the fast-path routine deals only with M_DATA
* fast-path packets. Regardless of the entry point, all outbound packets
- * will end up in str_mdata_fastpath_put(), where they will be delivered to
- * the MAC driver.
+ * will end up in dld_tx_single(), where they will be delivered to the MAC
+ * driver.
*
* The transmit logic operates in two modes: a "not busy" mode where the
* packets will be delivered to the MAC for a send attempt, or "busy" mode
@@ -452,7 +455,7 @@ dld_wsrv(queue_t *wq)
* Discard packets unless we are attached and bound; note that
* the driver mode (fastpath/raw/unitdata) is irrelevant here,
* because regardless of the mode all transmit will end up in
- * str_mdata_fastpath_put() where the packets may be queued.
+ * dld_tx_single() where the packets may be queued.
*/
ASSERT(DB_TYPE(mp) == M_DATA);
if (dsp->ds_dlstate != DL_IDLE) {
@@ -786,10 +789,10 @@ str_destructor(void *buf, void *cdrarg)
}
/*
- * M_DATA put (IP fast-path mode)
+ * M_DATA put. Note that mp is a single message, not a chained message.
*/
void
-str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp)
+dld_tx_single(dld_str_t *dsp, mblk_t *mp)
{
/*
* This function can be called from within dld or from an upper
@@ -811,14 +814,133 @@ str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp)
}
/*
- * M_DATA put (raw mode)
+ * Update the priority bits and VID (may need to insert tag if mp points
+ * to an untagged packet.
+ * If vid is VLAN_ID_NONE, use the VID encoded in the packet.
+ */
+static mblk_t *
+i_dld_ether_header_update_tag(mblk_t *mp, uint_t pri, uint16_t vid)
+{
+ mblk_t *hmp;
+ struct ether_vlan_header *evhp;
+ struct ether_header *ehp;
+ uint16_t old_tci = 0;
+ size_t len;
+
+ ASSERT(pri != 0 || vid != VLAN_ID_NONE);
+
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN) {
+ /*
+ * Tagged packet, update the priority bits.
+ */
+ old_tci = ntohs(evhp->ether_tci);
+ len = sizeof (struct ether_vlan_header);
+
+ if ((DB_REF(mp) > 1) || (MBLKL(mp) < len)) {
+ /*
+ * In case some drivers only check the db_ref
+ * count of the first mblk, we pullup the
+ * message into a single mblk.
+ */
+ hmp = msgpullup(mp, -1);
+ if ((hmp == NULL) || (MBLKL(hmp) < len)) {
+ freemsg(hmp);
+ return (NULL);
+ } else {
+ freemsg(mp);
+ mp = hmp;
+ }
+ }
+
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ } else {
+ /*
+ * Untagged packet. Insert the special priority tag.
+ * First allocate a header mblk.
+ */
+ hmp = allocb(sizeof (struct ether_vlan_header), BPRI_MED);
+ if (hmp == NULL)
+ return (NULL);
+
+ evhp = (struct ether_vlan_header *)hmp->b_rptr;
+ ehp = (struct ether_header *)mp->b_rptr;
+
+ /*
+ * Copy the MAC addresses and typelen
+ */
+ bcopy(ehp, evhp, (ETHERADDRL * 2));
+ evhp->ether_type = ehp->ether_type;
+ evhp->ether_tpid = htons(ETHERTYPE_VLAN);
+
+ hmp->b_wptr += sizeof (struct ether_vlan_header);
+ mp->b_rptr += sizeof (struct ether_header);
+
+ /*
+ * Free the original message if it's now empty. Link the
+ * rest of messages to the header message.
+ */
+ if (MBLKL(mp) == 0) {
+ hmp->b_cont = mp->b_cont;
+ freeb(mp);
+ } else {
+ hmp->b_cont = mp;
+ }
+ mp = hmp;
+ }
+
+ if (pri == 0)
+ pri = VLAN_PRI(old_tci);
+ if (vid == VLAN_ID_NONE)
+ vid = VLAN_ID(old_tci);
+ evhp->ether_tci = htons(VLAN_TCI(pri, VLAN_CFI(old_tci), vid));
+ return (mp);
+}
+
+/*
+ * M_DATA put (IP fast-path mode)
*/
void
+str_mdata_fastpath_put(dld_str_t *dsp, mblk_t *mp)
+{
+ boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
+ mblk_t *newmp;
+ uint_t pri;
+
+ if (is_ethernet) {
+ /*
+ * Update the priority bits to the assigned priority.
+ */
+ pri = (VLAN_MBLKPRI(mp) == 0) ? dsp->ds_pri : VLAN_MBLKPRI(mp);
+
+ if (pri != 0) {
+ newmp = i_dld_ether_header_update_tag(mp, pri,
+ VLAN_ID_NONE);
+ if (newmp == NULL)
+ goto discard;
+ mp = newmp;
+ }
+ }
+
+ dld_tx_single(dsp, mp);
+ return;
+
+discard:
+ /* TODO: bump kstat? */
+ freemsg(mp);
+}
+
+/*
+ * M_DATA put (DLIOCRAW mode)
+ */
+static void
str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
{
- mblk_t *bp, *newmp;
- size_t size;
- mac_header_info_t mhi;
+ boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
+ mblk_t *bp, *newmp;
+ size_t size;
+ mac_header_info_t mhi;
+ uint_t pri, vid;
/*
* Certain MAC type plugins provide an illusion for raw DLPI
@@ -854,23 +976,43 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp)
if (size > dsp->ds_mip->mi_sdu_max + mhi.mhi_hdrsize)
goto discard;
- if (dsp->ds_mip->mi_media == DL_ETHER && mhi.mhi_origsap == VLAN_TPID) {
- struct ether_vlan_header *evhp;
+ if (is_ethernet) {
+ /*
+ * Discard the packet if this is a VLAN stream but the VID in
+ * the packet is not correct.
+ */
+ vid = VLAN_ID(mhi.mhi_tci);
+ if ((dsp->ds_vid != VLAN_ID_NONE) && (vid != VLAN_ID_NONE))
+ goto discard;
- if (size < sizeof (struct ether_vlan_header))
+ /*
+ * Discard the packet if this packet is a tagged packet
+ * but both pri and VID are 0.
+ */
+ pri = VLAN_PRI(mhi.mhi_tci);
+ if (mhi.mhi_istagged && (pri == 0) && (vid == VLAN_ID_NONE))
goto discard;
+
/*
- * Replace vtag with our own
+ * Update the priority bits to the per-stream priority if
+ * priority is not set in the packet. Update the VID for
+ * packets on a VLAN stream.
*/
- evhp = (struct ether_vlan_header *)mp->b_rptr;
- evhp->ether_tci = htons(VLAN_TCI(dsp->ds_pri,
- ETHER_CFI, dsp->ds_vid));
+ pri = (pri == 0) ? dsp->ds_pri : 0;
+ if ((pri != 0) || (dsp->ds_vid != VLAN_ID_NONE)) {
+ if ((newmp = i_dld_ether_header_update_tag(mp,
+ pri, dsp->ds_vid)) == NULL) {
+ goto discard;
+ }
+ mp = newmp;
+ }
}
- str_mdata_fastpath_put(dsp, mp);
+ dld_tx_single(dsp, mp);
return;
discard:
+ /* TODO: bump kstat? */
freemsg(mp);
}
@@ -979,15 +1121,56 @@ dld_str_detach(dld_str_t *dsp)
}
/*
+ * This function is only called for VLAN streams. In raw mode, we strip VLAN
+ * tags before sending packets up to the DLS clients, with the exception of
+ * special priority tagged packets, in that case, we set the VID to 0.
+ * mp must be a VLAN tagged packet.
+ */
+static mblk_t *
+i_dld_ether_header_strip_tag(mblk_t *mp)
+{
+ mblk_t *newmp;
+ struct ether_vlan_header *evhp;
+ uint16_t tci, new_tci;
+
+ ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header));
+ if (DB_REF(mp) > 1) {
+ newmp = copymsg(mp);
+ if (newmp == NULL)
+ return (NULL);
+ freemsg(mp);
+ mp = newmp;
+ }
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+
+ tci = ntohs(evhp->ether_tci);
+ if (VLAN_PRI(tci) == 0) {
+ /*
+ * Priority is 0, strip the tag.
+ */
+ ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 2 * ETHERADDRL);
+ mp->b_rptr += VLAN_TAGSZ;
+ } else {
+ /*
+ * Priority is not 0, update the VID to 0.
+ */
+ new_tci = VLAN_TCI(VLAN_PRI(tci), VLAN_CFI(tci), VLAN_ID_NONE);
+ evhp->ether_tci = htons(new_tci);
+ }
+ return (mp);
+}
+
+/*
* Raw mode receive function.
*/
/*ARGSUSED*/
void
dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
- size_t header_length)
+ mac_header_info_t *mhip)
{
- dld_str_t *dsp = (dld_str_t *)arg;
- mblk_t *next, *newmp;
+ dld_str_t *dsp = (dld_str_t *)arg;
+ boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
+ mblk_t *next, *newmp;
ASSERT(mp != NULL);
do {
@@ -1001,8 +1184,8 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
/*
* Wind back b_rptr to point at the MAC header.
*/
- ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length);
- mp->b_rptr -= header_length;
+ ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
+ mp->b_rptr -= mhip->mhi_hdrsize;
/*
* Certain MAC type plugins provide an illusion for raw
@@ -1017,24 +1200,22 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
*/
if ((newmp = mac_header_uncook(dsp->ds_mh, mp)) == NULL) {
freemsg(mp);
- mp = next;
- continue;
+ goto next;
}
mp = newmp;
- if (dsp->ds_mip->mi_media == DL_ETHER) {
- struct ether_header *ehp =
- (struct ether_header *)mp->b_rptr;
-
- if (ntohs(ehp->ether_type) == VLAN_TPID) {
- /*
- * Strip off the vtag
- */
- ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
- 2 * ETHERADDRL);
- mp->b_rptr += VLAN_TAGSZ;
+ /*
+ * Strip the VLAN tag for VLAN streams.
+ */
+ if (is_ethernet && dsp->ds_vid != VLAN_ID_NONE) {
+ newmp = i_dld_ether_header_strip_tag(mp);
+ if (newmp == NULL) {
+ freemsg(mp);
+ goto next;
}
+ mp = newmp;
}
+
/*
* Pass the packet on.
*/
@@ -1043,6 +1224,7 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
else
freemsg(mp);
+next:
/*
* Move on to the next packet in the chain.
*/
@@ -1056,10 +1238,32 @@ dld_str_rx_raw(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
/*ARGSUSED*/
void
dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
- size_t header_length)
+ mac_header_info_t *mhip)
{
- dld_str_t *dsp = (dld_str_t *)arg;
- mblk_t *next;
+ dld_str_t *dsp = (dld_str_t *)arg;
+ mblk_t *next;
+ size_t offset = 0;
+
+ /*
+ * MAC header stripping rules:
+ * - Tagged packets:
+ * a. VLAN streams. Strip the whole VLAN header including the tag.
+ * b. Physical streams
+ * - VLAN packets (non-zero VID). The stream must be either a
+ * DL_PROMISC_SAP listener or a ETHERTYPE_VLAN listener.
+ * Strip the Ethernet header but keep the VLAN header.
+ * - Special tagged packets (zero VID)
+ * * The stream is either a DL_PROMISC_SAP listener or a
+ * ETHERTYPE_VLAN listener, strip the Ethernet header but
+ * keep the VLAN header.
+ * * Otherwise, strip the whole VLAN header.
+ * - Untagged packets. Strip the whole MAC header.
+ */
+ if (mhip->mhi_istagged && (dsp->ds_vid == VLAN_ID_NONE) &&
+ ((dsp->ds_sap == ETHERTYPE_VLAN) ||
+ (dsp->ds_promisc & DLS_PROMISC_SAP))) {
+ offset = VLAN_TAGSZ;
+ }
ASSERT(mp != NULL);
do {
@@ -1071,6 +1275,12 @@ dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
mp->b_next = NULL;
/*
+ * Wind back b_rptr to point at the VLAN header.
+ */
+ ASSERT(mp->b_rptr >= DB_BASE(mp) + offset);
+ mp->b_rptr -= offset;
+
+ /*
* Pass the packet on.
*/
if (canputnext(dsp->ds_rq))
@@ -1090,11 +1300,23 @@ dld_str_rx_fastpath(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
/*ARGSUSED*/
void
dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
- size_t header_length)
+ mac_header_info_t *mhip)
{
dld_str_t *dsp = (dld_str_t *)arg;
mblk_t *ud_mp;
mblk_t *next;
+ size_t offset = 0;
+ boolean_t strip_vlan = B_TRUE;
+
+ /*
+ * See MAC header stripping rules in the dld_str_rx_fastpath() function.
+ */
+ if (mhip->mhi_istagged && (dsp->ds_vid == VLAN_ID_NONE) &&
+ ((dsp->ds_sap == ETHERTYPE_VLAN) ||
+ (dsp->ds_promisc & DLS_PROMISC_SAP))) {
+ offset = VLAN_TAGSZ;
+ strip_vlan = B_FALSE;
+ }
ASSERT(mp != NULL);
do {
@@ -1108,21 +1330,21 @@ dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
/*
* Wind back b_rptr to point at the MAC header.
*/
- ASSERT(mp->b_rptr >= DB_BASE(mp) + header_length);
- mp->b_rptr -= header_length;
+ ASSERT(mp->b_rptr >= DB_BASE(mp) + mhip->mhi_hdrsize);
+ mp->b_rptr -= mhip->mhi_hdrsize;
/*
* Create the DL_UNITDATA_IND M_PROTO.
*/
- if ((ud_mp = str_unitdata_ind(dsp, mp)) == NULL) {
+ if ((ud_mp = str_unitdata_ind(dsp, mp, strip_vlan)) == NULL) {
freemsgchain(mp);
return;
}
/*
- * Advance b_rptr to point at the payload again.
+ * Advance b_rptr to point at the payload (or the VLAN header).
*/
- mp->b_rptr += header_length;
+ mp->b_rptr += (mhip->mhi_hdrsize - offset);
/*
* Prepend the DL_UNITDATA_IND.
@@ -1167,7 +1389,7 @@ typedef struct dl_unitdata_ind_wrapper {
* Create a DL_UNITDATA_IND M_PROTO message.
*/
static mblk_t *
-str_unitdata_ind(dld_str_t *dsp, mblk_t *mp)
+str_unitdata_ind(dld_str_t *dsp, mblk_t *mp, boolean_t strip_vlan)
{
mblk_t *nmp;
dl_unitdata_ind_wrapper_t *dlwp;
@@ -1207,9 +1429,12 @@ str_unitdata_ind(dld_str_t *dsp, mblk_t *mp)
bcopy(mhi.mhi_daddr, daddr, addr_length);
/*
- * Set the destination DLSAP to our bound DLSAP value.
+ * Set the destination DLSAP to the SAP value encoded in the packet.
*/
- *(uint16_t *)(daddr + addr_length) = dsp->ds_sap;
+ if (mhi.mhi_istagged && !strip_vlan)
+ *(uint16_t *)(daddr + addr_length) = ETHERTYPE_VLAN;
+ else
+ *(uint16_t *)(daddr + addr_length) = mhi.mhi_bindsap;
dlp->dl_dest_addr_length = addr_length + sizeof (uint16_t);
/*
@@ -1703,6 +1928,15 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp)
goto failed;
}
+ /*
+ * DLIOCHDRINFO should only come from IP. The one initiated from
+ * user-land should not be allowed.
+ */
+ if (((struct iocblk *)mp->b_rptr)->ioc_cr != kcred) {
+ err = EINVAL;
+ goto failed;
+ }
+
nmp = mp->b_cont;
if (nmp == NULL || MBLKL(nmp) < sizeof (dl_unitdata_req_t) ||
(dlp = (dl_unitdata_req_t *)nmp->b_rptr,
@@ -1737,7 +1971,7 @@ ioc_fast(dld_str_t *dsp, mblk_t *mp)
sap = *(uint16_t *)(nmp->b_rptr + off + addr_length);
dc = dsp->ds_dc;
- if ((hmp = dls_header(dc, addr, sap, dsp->ds_pri, NULL)) == NULL) {
+ if ((hmp = dls_header(dc, addr, sap, 0, NULL)) == NULL) {
rw_exit(&dsp->ds_lock);
err = ENOMEM;
goto failed;
diff --git a/usr/src/uts/common/io/dls/dls.c b/usr/src/uts/common/io/dls/dls.c
index 51456292d5..a8e1089776 100644
--- a/usr/src/uts/common/io/dls/dls.c
+++ b/usr/src/uts/common/io/dls/dls.c
@@ -602,42 +602,90 @@ done:
mblk_t *
dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri,
- mblk_t *payload)
+ mblk_t **payloadp)
{
- dls_impl_t *dip = (dls_impl_t *)dc;
- uint16_t vid;
- size_t extra_len;
- uint16_t mac_sap;
- mblk_t *mp;
+ dls_impl_t *dip = (dls_impl_t *)dc;
+ uint16_t vid;
+ size_t extra_len;
+ uint16_t mac_sap;
+ mblk_t *mp, *payload;
+ boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER);
struct ether_vlan_header *evhp;
vid = dip->di_dvp->dv_id;
- if (vid != VLAN_ID_NONE) {
- /*
- * We know ahead of time that we'll need to fill in
- * additional VLAN information in the link-layer header.
- * We will tell the MAC layer to pre-allocate some space at
- * the end of the Ethernet header for us.
- */
- ASSERT(dip->di_mip->mi_media == DL_ETHER);
+ payload = (payloadp == NULL) ? NULL : (*payloadp);
+
+ /*
+ * If the following conditions are satisfied:
+ * - This is not a ETHERTYPE_VLAN listener; and
+ * - This is either a VLAN stream or this is a physical stream
+ * but the priority is not 0.
+ *
+ * then we know ahead of time that we'll need to fill in additional
+ * VLAN information in the link-layer header. We will tell the MAC
+ * layer to pre-allocate some space at the end of the Ethernet
+ * header for us.
+ */
+ if (is_ethernet && sap != ETHERTYPE_VLAN &&
+ (vid != VLAN_ID_NONE || pri != 0)) {
extra_len = sizeof (struct ether_vlan_header) -
sizeof (struct ether_header);
- mac_sap = VLAN_TPID;
+ mac_sap = ETHERTYPE_VLAN;
} else {
extra_len = 0;
mac_sap = sap;
}
mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len);
- if (vid == VLAN_ID_NONE || mp == NULL)
+ if (mp == NULL)
+ return (NULL);
+
+ if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet)
return (mp);
- /* This is an Ethernet VLAN link. Fill in the VLAN information */
+ /*
+ * Fill in the tag information.
+ */
ASSERT(MBLKL(mp) == sizeof (struct ether_header));
- mp->b_wptr += extra_len;
- evhp = (struct ether_vlan_header *)mp->b_rptr;
- evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
- evhp->ether_type = htons(sap);
+ if (extra_len != 0) {
+ mp->b_wptr += extra_len;
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
+ evhp->ether_type = htons(sap);
+ } else {
+ /*
+ * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
+ * in the payload. Update the priority.
+ */
+ struct ether_vlan_extinfo *extinfo;
+ size_t len = sizeof (struct ether_vlan_extinfo);
+
+ ASSERT(sap == ETHERTYPE_VLAN);
+ ASSERT(payload != NULL);
+
+ if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
+ mblk_t *newmp;
+
+ /*
+ * Because some DLS consumers only check the db_ref
+ * count of the first mblk, we pullup 'payload' into
+ * a single mblk.
+ */
+ newmp = msgpullup(payload, -1);
+ if ((newmp == NULL) || (MBLKL(newmp) < len)) {
+ freemsg(newmp);
+ freemsg(mp);
+ return (NULL);
+ } else {
+ freemsg(payload);
+ *payloadp = payload = newmp;
+ }
+ }
+
+ extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
+ extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
+ VLAN_ID(ntohs(extinfo->ether_tci))));
+ }
return (mp);
}
@@ -645,7 +693,7 @@ int
dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip)
{
return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp,
- mp, mhip, NULL));
+ mp, mhip));
}
void
@@ -738,8 +786,10 @@ accept:
return (B_TRUE);
}
+/* ARGSUSED */
boolean_t
-dls_accept_loopback(dls_impl_t *dip, dls_rx_t *di_rx, void **di_rx_arg)
+dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx,
+ void **di_rx_arg)
{
/*
* We must not accept packets if the dls_impl_t is not marked as bound
diff --git a/usr/src/uts/common/io/dls/dls_link.c b/usr/src/uts/common/io/dls/dls_link.c
index 47b0d99169..19e2f12976 100644
--- a/usr/src/uts/common/io/dls/dls_link.c
+++ b/usr/src/uts/common/io/dls/dls_link.c
@@ -119,51 +119,70 @@ i_dls_link_destructor(void *buf, void *arg)
}
/*
+ * - Parse the mac header information of the given packet.
+ * - Strip the padding and skip over the header. Note that because some
+ * DLS consumers only check the db_ref count of the first mblk, we
+ * pullup the message into a single mblk. The dls_link_header_info()
+ * function ensures that the size of the pulled message is greater
+ * than the MAC header size.
+ *
+ * We choose to use a macro for performance reasons.
+ */
+#define DLS_PREPARE_PKT(dlp, mp, mhip, err) { \
+ mblk_t *nextp = (mp)->b_next; \
+ if (((err) = dls_link_header_info((dlp), (mp), (mhip))) == 0) { \
+ DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \
+ if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \
+ mblk_t *newmp; \
+ if ((newmp = msgpullup((mp), -1)) == NULL) { \
+ (err) = EINVAL; \
+ } else { \
+ freemsg((mp)); \
+ (mp) = newmp; \
+ (mp)->b_next = nextp; \
+ (mp)->b_rptr += (mhip)->mhi_hdrsize; \
+ } \
+ } else { \
+ (mp)->b_rptr += (mhip)->mhi_hdrsize; \
+ } \
+ } \
+}
+
+/*
* Truncate the chain starting at mp such that all packets in the chain
- * have identical source and destination addresses, saps, and VLAN tags (if
- * any). It returns a pointer to the mblk following the chain, NULL if
- * there is no further packet following the processed chain. The countp
- * argument is set to the number of valid packets in the chain. It is set
- * to 0 if the function encountered a problem with the first packet.
+ * have identical source and destination addresses, saps, and tag types
+ * (see below). It returns a pointer to the mblk following the chain,
+ * NULL if there is no further packet following the processed chain.
+ * The countp argument is set to the number of valid packets in the chain.
+ * Note that the whole MAC header (including the VLAN tag if any) in each
+ * packet will be stripped.
*/
static mblk_t *
-i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip,
- uint16_t *vidp, uint_t *countp)
+i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, const mac_header_info_t *mhip,
+ uint_t *countp)
{
- mblk_t **pp;
- mblk_t *p;
- uint_t npacket;
+ mblk_t *prevp;
+ uint_t npacket = 1;
size_t addr_size = dlp->dl_mip->mi_addr_length;
-
- /*
- * Packets should always be at least 16 bit aligned.
- */
- ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
-
- if (dls_link_header_info(dlp, mp, mhip, vidp) != 0) {
- /*
- * Something is wrong with the initial header. No chain is
- * possible.
- */
- p = mp->b_next;
- mp->b_next = NULL;
- *countp = 0;
- return (p);
- }
+ uint16_t vid = VLAN_ID(mhip->mhi_tci);
+ uint16_t pri = VLAN_PRI(mhip->mhi_tci);
/*
* Compare with subsequent headers until we find one that has
* differing header information. After checking each packet
* strip padding and skip over the header.
*/
- npacket = 1;
- for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) {
+ for (prevp = mp; (mp = mp->b_next) != NULL; prevp = mp) {
mac_header_info_t cmhi;
- uint16_t cvid;
+ uint16_t cvid, cpri;
+ int err;
- if (dls_link_header_info(dlp, p, &cmhi, &cvid) != 0)
+ DLS_PREPARE_PKT(dlp, mp, &cmhi, err);
+ if (err != 0)
break;
+ prevp->b_next = mp;
+
/*
* The source, destination, sap, and vlan id must all match
* in a given subchain.
@@ -171,30 +190,46 @@ i_dls_link_subchain(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip,
if (memcmp(mhip->mhi_daddr, cmhi.mhi_daddr, addr_size) != 0 ||
memcmp(mhip->mhi_saddr, cmhi.mhi_saddr, addr_size) != 0 ||
mhip->mhi_bindsap != cmhi.mhi_bindsap) {
+ /*
+ * Note that we don't need to restore the padding.
+ */
+ mp->b_rptr -= cmhi.mhi_hdrsize;
break;
}
- if (cvid != *vidp)
+ cvid = VLAN_ID(cmhi.mhi_tci);
+ cpri = VLAN_PRI(cmhi.mhi_tci);
+
+ /*
+ * There are several types of packets. Packets don't match
+ * if they are classified to different type or if they are
+ * VLAN packets but belong to different VLANs:
+ *
+ * packet type tagged vid pri
+ * ---------------------------------------------------------
+ * untagged No zero zero
+ * VLAN packets Yes non-zero -
+ * priority tagged Yes zero non-zero
+ * 0 tagged Yes zero zero
+ */
+ if ((mhip->mhi_istagged != cmhi.mhi_istagged) ||
+ (vid != cvid) || ((vid == VLAN_ID_NONE) &&
+ (((pri == 0) && (cpri != 0)) ||
+ ((pri != 0) && (cpri == 0))))) {
+ mp->b_rptr -= cmhi.mhi_hdrsize;
break;
+ }
- DLS_STRIP_PADDING(cmhi.mhi_pktsize, p);
- p->b_rptr += cmhi.mhi_hdrsize;
npacket++;
}
/*
- * Strip padding and skip over the initial packet's header.
- */
- DLS_STRIP_PADDING(mhip->mhi_pktsize, mp);
- mp->b_rptr += mhip->mhi_hdrsize;
-
- /*
* Break the chain at this point and return a pointer to the next
* sub-chain.
*/
- *pp = NULL;
+ prevp->b_next = NULL;
*countp = npacket;
- return (p);
+ return (mp);
}
static void
@@ -226,156 +261,80 @@ i_dls_head_free(dls_head_t *dhp)
kmem_free(dhp, sizeof (dls_head_t));
}
-static void
-i_dls_link_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
+/*
+ * Try to send mp up to the streams of the given sap and vid. Return B_TRUE
+ * if this message is sent to any streams.
+ * Note that this function will copy the message chain and the original
+ * mp will remain valid after this function
+ */
+static uint_t
+i_dls_link_rx_func(dls_link_t *dlp, mac_resource_handle_t mrh,
+ mac_header_info_t *mhip, mblk_t *mp, uint32_t sap, uint16_t vid,
+ boolean_t (*acceptfunc)())
{
- dls_link_t *dlp = arg;
- mod_hash_t *hash = dlp->dl_impl_hash;
- mblk_t *nextp;
- mac_header_info_t mhi;
- uint16_t vid;
- dls_head_t *dhp;
- dls_impl_t *dip;
- dls_impl_t *ndip;
- mblk_t *nmp;
- mod_hash_key_t key;
- uint_t npacket;
- boolean_t accepted;
- dls_rx_t di_rx, ndi_rx;
- void *di_rx_arg, *ndi_rx_arg;
+ mod_hash_t *hash = dlp->dl_impl_hash;
+ mod_hash_key_t key;
+ dls_head_t *dhp;
+ dls_impl_t *dip;
+ mblk_t *nmp;
+ dls_rx_t di_rx;
+ void *di_rx_arg;
+ uint_t naccepted = 0;
/*
- * Walk the packet chain.
+ * Construct a hash key from the VLAN identifier and the
+ * DLSAP that represents dls_impl_t in promiscuous mode.
*/
- while (mp != NULL) {
- /*
- * Wipe the accepted state.
- */
- accepted = B_FALSE;
-
- /*
- * Grab the longest sub-chain we can process as a single
- * unit.
- */
- nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket);
-
- if (npacket == 0) {
- /*
- * The first packet had an unrecognized header.
- * Modify npacket so that this stray can be
- * accounted for.
- */
- npacket = 1;
- freemsg(mp);
- goto loop;
- }
-
- /*
- * Construct a hash key from the VLAN identifier and the
- * DLSAP.
- */
- key = MAKE_KEY(mhi.mhi_bindsap, vid);
+ key = MAKE_KEY(sap, vid);
- /*
- * Search the has table for dls_impl_t eligible to receive
- * a packet chain for this DLSAP/VLAN combination.
- */
- rw_enter(&dlp->dl_impl_lock, RW_READER);
- if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
- rw_exit(&dlp->dl_impl_lock);
- freemsgchain(mp);
- goto loop;
- }
- i_dls_head_hold(dhp);
+ /*
+ * Search the hash table for dls_impl_t eligible to receive
+ * a packet chain for this DLSAP/VLAN combination.
+ */
+ rw_enter(&dlp->dl_impl_lock, RW_READER);
+ if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
rw_exit(&dlp->dl_impl_lock);
+ return (B_FALSE);
+ }
+ i_dls_head_hold(dhp);
+ rw_exit(&dlp->dl_impl_lock);
- /*
- * Find the first dls_impl_t that will accept the sub-chain.
- */
- for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp)
- if (dls_accept(dip, &mhi, &di_rx, &di_rx_arg))
- break;
-
- /*
- * If we did not find any dls_impl_t willing to accept the
- * sub-chain then throw it away.
- */
- if (dip == NULL) {
- i_dls_head_rele(dhp);
- freemsgchain(mp);
- goto loop;
- }
+ /*
+ * Find dls_impl_t that will accept the sub-chain.
+ */
+ for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
+ if (!acceptfunc(dip, mhip, &di_rx, &di_rx_arg))
+ continue;
/*
* We have at least one acceptor.
*/
- accepted = B_TRUE;
- for (;;) {
- /*
- * Find the next dls_impl_t that will accept the
- * sub-chain.
- */
- for (ndip = dip->di_nextp; ndip != NULL;
- ndip = ndip->di_nextp)
- if (dls_accept(ndip, &mhi, &ndi_rx,
- &ndi_rx_arg))
- break;
-
- /*
- * If there are no more dls_impl_t that are willing
- * to accept the sub-chain then we don't need to dup
- * it before handing it to the current one.
- */
- if (ndip == NULL) {
- di_rx(di_rx_arg, mrh, mp, mhi.mhi_hdrsize);
-
- /*
- * Since there are no more dls_impl_t, we're
- * done.
- */
- break;
- }
-
- /*
- * There are more dls_impl_t so dup the sub-chain.
- */
- if ((nmp = copymsgchain(mp)) != NULL)
- di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize);
-
- dip = ndip;
- di_rx = ndi_rx;
- di_rx_arg = ndi_rx_arg;
- }
-
- /*
- * Release the hold on the dls_impl_t chain now that we have
- * finished walking it.
- */
- i_dls_head_rele(dhp);
-
-loop:
- /*
- * If there were no acceptors then add the packet count to the
- * 'unknown' count.
- */
- if (!accepted)
- atomic_add_32(&(dlp->dl_unknowns), npacket);
+ naccepted ++;
/*
- * Move onto the next sub-chain.
+ * There will normally be at least more dls_impl_t
+ * (since we've yet to check for non-promiscuous
+ * dls_impl_t) so dup the sub-chain.
*/
- mp = nextp;
+ if ((nmp = copymsgchain(mp)) != NULL)
+ di_rx(di_rx_arg, mrh, nmp, mhip);
}
+
+ /*
+ * Release the hold on the dls_impl_t chain now that we have
+ * finished walking it.
+ */
+ i_dls_head_rele(dhp);
+ return (naccepted);
}
static void
-i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
+i_dls_link_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
{
dls_link_t *dlp = arg;
mod_hash_t *hash = dlp->dl_impl_hash;
mblk_t *nextp;
mac_header_info_t mhi;
- uint16_t vid;
dls_head_t *dhp;
dls_impl_t *dip;
dls_impl_t *ndip;
@@ -385,80 +344,64 @@ i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
boolean_t accepted;
dls_rx_t di_rx, ndi_rx;
void *di_rx_arg, *ndi_rx_arg;
+ uint16_t vid;
+ int err;
/*
* Walk the packet chain.
*/
- while (mp != NULL) {
+ for (; mp != NULL; mp = nextp) {
/*
* Wipe the accepted state.
*/
accepted = B_FALSE;
- /*
- * Grab the longest sub-chain we can process as a single
- * unit.
- */
- nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket);
-
- if (npacket == 0) {
- /*
- * The first packet had an unrecognized header.
- * Modify npacket so that this stray can be
- * accounted for.
- */
- npacket = 1;
+ DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ if (err != 0) {
+ atomic_add_32(&(dlp->dl_unknowns), 1);
+ nextp = mp->b_next;
freemsg(mp);
- goto loop;
+ continue;
}
/*
- * Construct a hash key from the VLAN identifier and the
- * DLSAP that represents dls_impl_t in promiscuous mode.
+ * Grab the longest sub-chain we can process as a single
+ * unit.
*/
- key = MAKE_KEY(DLS_SAP_PROMISC, vid);
+ nextp = i_dls_link_subchain(dlp, mp, &mhi, &npacket);
+ ASSERT(npacket != 0);
- /*
- * Search the has table for dls_impl_t eligible to receive
- * a packet chain for this DLSAP/VLAN combination.
- */
- rw_enter(&dlp->dl_impl_lock, RW_READER);
- if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
- rw_exit(&dlp->dl_impl_lock);
- goto non_promisc;
- }
- i_dls_head_hold(dhp);
- rw_exit(&dlp->dl_impl_lock);
-
- /*
- * Find dls_impl_t that will accept the sub-chain.
- */
- for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
- if (!dls_accept(dip, &mhi, &di_rx, &di_rx_arg))
- continue;
+ vid = VLAN_ID(mhi.mhi_tci);
+ if (mhi.mhi_istagged) {
/*
- * We have at least one acceptor.
+ * If it is tagged traffic, send it upstream to
+ * all dls_impl_t which are attached to the physical
+ * link and bound to SAP 0x8100.
*/
- accepted = B_TRUE;
+ if (i_dls_link_rx_func(dlp, mrh, &mhi, mp,
+ ETHERTYPE_VLAN, VLAN_ID_NONE, dls_accept) > 0) {
+ accepted = B_TRUE;
+ }
/*
- * There will normally be at least more dls_impl_t
- * (since we've yet to check for non-promiscuous
- * dls_impl_t) so dup the sub-chain.
+ * Don't pass the packets up if they are tagged
+ * packets and:
+ * - their VID and priority are both zero (invalid
+ * packets).
+ * - their sap is ETHERTYPE_VLAN and their VID is
+ * zero as they have already been sent upstreams.
*/
- if ((nmp = copymsgchain(mp)) != NULL)
- di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize);
+ if ((vid == VLAN_ID_NONE &&
+ VLAN_PRI(mhi.mhi_tci) == 0) ||
+ (mhi.mhi_bindsap == ETHERTYPE_VLAN &&
+ vid == VLAN_ID_NONE)) {
+ freemsgchain(mp);
+ goto loop;
+ }
}
/*
- * Release the hold on the dls_impl_t chain now that we have
- * finished walking it.
- */
- i_dls_head_rele(dhp);
-
-non_promisc:
- /*
* Construct a hash key from the VLAN identifier and the
* DLSAP.
*/
@@ -515,7 +458,7 @@ non_promisc:
* it before handing it to the current one.
*/
if (ndip == NULL) {
- di_rx(di_rx_arg, mrh, mp, mhi.mhi_hdrsize);
+ di_rx(di_rx_arg, mrh, mp, &mhi);
/*
* Since there are no more dls_impl_t, we're
@@ -528,7 +471,7 @@ non_promisc:
* There are more dls_impl_t so dup the sub-chain.
*/
if ((nmp = copymsgchain(mp)) != NULL)
- di_rx(di_rx_arg, mrh, nmp, mhi.mhi_hdrsize);
+ di_rx(di_rx_arg, mrh, nmp, &mhi);
dip = ndip;
di_rx = ndi_rx;
@@ -548,92 +491,112 @@ loop:
*/
if (!accepted)
atomic_add_32(&(dlp->dl_unknowns), npacket);
+ }
+}
- /*
- * Move onto the next sub-chain.
- */
- mp = nextp;
+/*
+ * Try to send mp up to the DLS_SAP_PROMISC listeners. Return B_TRUE if this
+ * message is sent to any streams.
+ */
+static uint_t
+i_dls_link_rx_common_promisc(dls_link_t *dlp, mac_resource_handle_t mrh,
+ mac_header_info_t *mhip, mblk_t *mp, uint16_t vid,
+ boolean_t (*acceptfunc)())
+{
+ uint_t naccepted;
+
+ naccepted = i_dls_link_rx_func(dlp, mrh, mhip, mp, DLS_SAP_PROMISC,
+ vid, acceptfunc);
+
+ if (vid != VLAN_ID_NONE) {
+ naccepted += i_dls_link_rx_func(dlp, mrh, mhip, mp,
+ DLS_SAP_PROMISC, VLAN_ID_NONE, acceptfunc);
}
+ return (naccepted);
}
static void
-i_dls_link_txloop(void *arg, mblk_t *mp)
+i_dls_link_rx_common(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
+ boolean_t (*acceptfunc)())
{
dls_link_t *dlp = arg;
mod_hash_t *hash = dlp->dl_impl_hash;
mblk_t *nextp;
mac_header_info_t mhi;
- uint16_t vid;
+ uint16_t vid, vidkey, pri;
dls_head_t *dhp;
dls_impl_t *dip;
- dls_impl_t *ndip;
mblk_t *nmp;
mod_hash_key_t key;
uint_t npacket;
- dls_rx_t di_rx, ndi_rx;
- void *di_rx_arg, *ndi_rx_arg;
+ uint32_t sap;
+ boolean_t accepted;
+ dls_rx_t di_rx, fdi_rx;
+ void *di_rx_arg, *fdi_rx_arg;
+ boolean_t pass2;
+ int err;
/*
* Walk the packet chain.
*/
- while (mp != NULL) {
+ for (; mp != NULL; mp = nextp) {
/*
- * Grab the longest sub-chain we can process as a single
- * unit.
+ * Wipe the accepted state and the receive information of
+ * the first eligible dls_impl_t.
*/
- nextp = i_dls_link_subchain(dlp, mp, &mhi, &vid, &npacket);
-
- if (npacket == 0) {
+ accepted = B_FALSE;
+ pass2 = B_FALSE;
+ fdi_rx = NULL;
+ fdi_rx_arg = NULL;
+
+ DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ if (err != 0) {
+ if (acceptfunc == dls_accept)
+ atomic_add_32(&(dlp->dl_unknowns), 1);
+ nextp = mp->b_next;
freemsg(mp);
- goto loop;
+ continue;
}
/*
- * Construct a hash key from the VLAN identifier and the
- * DLSAP.
+ * Grab the longest sub-chain we can process as a single
+ * unit.
*/
- key = MAKE_KEY(mhi.mhi_bindsap, vid);
+ nextp = i_dls_link_subchain(dlp, mp, &mhi, &npacket);
+ ASSERT(npacket != 0);
- /*
- * Search the has table for dls_impl_t eligible to receive
- * a packet chain for this DLSAP/VLAN combination.
- */
- rw_enter(&dlp->dl_impl_lock, RW_READER);
- if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
- rw_exit(&dlp->dl_impl_lock);
- goto promisc;
- }
- i_dls_head_hold(dhp);
- rw_exit(&dlp->dl_impl_lock);
+ vid = VLAN_ID(mhi.mhi_tci);
+ pri = VLAN_PRI(mhi.mhi_tci);
+
+ vidkey = vid;
/*
- * Find dls_impl_t that will accept the sub-chain.
+ * Note that we need to first send to the dls_impl_t
+ * in promiscuous mode in order to avoid the packet reordering
+ * when snooping.
*/
- for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
- if (!dls_accept_loopback(dip, &di_rx, &di_rx_arg))
- continue;
-
- /*
- * There should be at least more dls_impl_t (since
- * we've yet to check for dls_impl_t in promiscuous
- * mode) so dup the sub-chain.
- */
- if ((nmp = copymsgchain(mp)) != NULL)
- di_rx(di_rx_arg, NULL, nmp, mhi.mhi_hdrsize);
+ if (i_dls_link_rx_common_promisc(dlp, mrh, &mhi, mp, vidkey,
+ acceptfunc) > 0) {
+ accepted = B_TRUE;
}
/*
- * Release the hold on the dls_impl_t chain now that we have
- * finished walking it.
+ * Non promisc case. Two passes:
+ * 1. send tagged packets to ETHERTYPE_VLAN listeners
+ * 2. send packets to listeners bound to the specific SAP.
*/
- i_dls_head_rele(dhp);
-
-promisc:
+ if (mhi.mhi_istagged) {
+ vidkey = VLAN_ID_NONE;
+ sap = ETHERTYPE_VLAN;
+ } else {
+ goto non_promisc_loop;
+ }
+non_promisc:
/*
* Construct a hash key from the VLAN identifier and the
- * DLSAP that represents dls_impl_t in promiscuous mode.
+ * DLSAP.
*/
- key = MAKE_KEY(DLS_SAP_PROMISC, vid);
+ key = MAKE_KEY(sap, vidkey);
/*
* Search the has table for dls_impl_t eligible to receive
@@ -642,8 +605,7 @@ promisc:
rw_enter(&dlp->dl_impl_lock, RW_READER);
if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
rw_exit(&dlp->dl_impl_lock);
- freemsgchain(mp);
- goto loop;
+ goto non_promisc_loop;
}
i_dls_head_hold(dhp);
rw_exit(&dlp->dl_impl_lock);
@@ -651,56 +613,25 @@ promisc:
/*
* Find the first dls_impl_t that will accept the sub-chain.
*/
- for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp)
- if (dls_accept_loopback(dip, &di_rx, &di_rx_arg))
- break;
-
- /*
- * If we did not find any dls_impl_t willing to accept the
- * sub-chain then throw it away.
- */
- if (dip == NULL) {
- i_dls_head_rele(dhp);
- freemsgchain(mp);
- goto loop;
- }
+ for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
+ if (!acceptfunc(dip, &mhi, &di_rx, &di_rx_arg))
+ continue;
- for (;;) {
- /*
- * Find the next dls_impl_t that will accept the
- * sub-chain.
- */
- for (ndip = dip->di_nextp; ndip != NULL;
- ndip = ndip->di_nextp)
- if (dls_accept_loopback(ndip, &ndi_rx,
- &ndi_rx_arg)) {
- break;
- }
+ accepted = B_TRUE;
/*
- * If there are no more dls_impl_t that are willing
- * to accept the sub-chain then we don't need to dup
- * it before handing it to the current one.
+ * To avoid the extra copymsgchain(), if this
+ * is the first eligible dls_impl_t, remember required
+ * information and send up the message afterwards.
*/
- if (ndip == NULL) {
- di_rx(di_rx_arg, NULL, mp, mhi.mhi_hdrsize);
-
- /*
- * Since there are no more dls_impl_t, we're
- * done.
- */
- break;
+ if (fdi_rx == NULL) {
+ fdi_rx = di_rx;
+ fdi_rx_arg = di_rx_arg;
+ continue;
}
- /*
- * There are more dls_impl_t so dup the sub-chain.
- */
if ((nmp = copymsgchain(mp)) != NULL)
- di_rx(di_rx_arg, NULL, nmp, mhi.mhi_hdrsize);
-
- dip = ndip;
- di_rx = ndi_rx;
- di_rx_arg = ndi_rx_arg;
+ di_rx(di_rx_arg, mrh, nmp, &mhi);
}
/*
@@ -709,14 +640,54 @@ promisc:
*/
i_dls_head_rele(dhp);
-loop:
+non_promisc_loop:
+ /*
+ * Don't pass the packets up again if:
+ * - First pass is done and the packets are tagged and their:
+ * - VID and priority are both zero (invalid packets).
+ * - their sap is ETHERTYPE_VLAN and their VID is zero
+ * (they have already been sent upstreams).
+ * - Second pass is done:
+ */
+ if (pass2 || (mhi.mhi_istagged &&
+ ((vid == VLAN_ID_NONE && pri == 0) ||
+ (mhi.mhi_bindsap == ETHERTYPE_VLAN &&
+ vid == VLAN_ID_NONE)))) {
+ /*
+ * Send the message up to the first eligible dls_impl_t.
+ */
+ if (fdi_rx != NULL)
+ fdi_rx(fdi_rx_arg, mrh, mp, &mhi);
+ else
+ freemsgchain(mp);
+ } else {
+ vidkey = vid;
+ sap = mhi.mhi_bindsap;
+ pass2 = B_TRUE;
+ goto non_promisc;
+ }
+
/*
- * Move onto the next sub-chain.
+ * If there were no acceptors then add the packet count to the
+ * 'unknown' count.
*/
- mp = nextp;
+ if (!accepted && (acceptfunc == dls_accept))
+ atomic_add_32(&(dlp->dl_unknowns), npacket);
}
}
+static void
+i_dls_link_rx_promisc(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
+{
+ i_dls_link_rx_common(arg, mrh, mp, dls_accept);
+}
+
+static void
+i_dls_link_txloop(void *arg, mblk_t *mp)
+{
+ i_dls_link_rx_common(arg, NULL, mp, dls_accept_loopback);
+}
+
/*ARGSUSED*/
static uint_t
i_dls_link_walk(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
@@ -1125,32 +1096,55 @@ dls_link_remove(dls_link_t *dlp, dls_impl_t *dip)
}
int
-dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip,
- uint16_t *vidp)
+dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip)
{
boolean_t is_ethernet = (dlp->dl_mip->mi_media == DL_ETHER);
int err = 0;
+ /*
+ * Packets should always be at least 16 bit aligned.
+ */
+ ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
+
if ((err = mac_header_info(dlp->dl_mh, mp, mhip)) != 0)
return (err);
/*
* If this is a VLAN-tagged Ethernet packet, then the SAP in the
- * mac_header_info_t as returned by mac_header_info() is VLAN_TPID.
- * We need to grab the ethertype from the VLAN header.
+ * mac_header_info_t as returned by mac_header_info() is
+ * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
*/
- if (is_ethernet && (mhip->mhi_bindsap == VLAN_TPID)) {
+ if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
struct ether_vlan_header *evhp;
uint16_t sap;
+ mblk_t *tmp = NULL;
+ size_t size;
+
+ size = sizeof (struct ether_vlan_header);
+ if (MBLKL(mp) < size) {
+ /*
+ * Pullup the message in order to get the MAC header
+ * infomation. Note that this is a read-only function,
+ * we keep the input packet intact.
+ */
+ if ((tmp = msgpullup(mp, size)) == NULL)
+ return (EINVAL);
+ mp = tmp;
+ }
evhp = (struct ether_vlan_header *)mp->b_rptr;
sap = ntohs(evhp->ether_type);
(void) mac_sap_verify(dlp->dl_mh, sap, &mhip->mhi_bindsap);
mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
- if (vidp != NULL)
- *vidp = VLAN_ID(ntohs(evhp->ether_tci));
- } else if (vidp != NULL) {
- *vidp = VLAN_ID_NONE;
+ mhip->mhi_tci = ntohs(evhp->ether_tci);
+ mhip->mhi_istagged = B_TRUE;
+ freemsg(tmp);
+
+ if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
+ return (EINVAL);
+ } else {
+ mhip->mhi_istagged = B_FALSE;
+ mhip->mhi_tci = 0;
}
return (0);
}
diff --git a/usr/src/uts/common/io/dls/dls_soft_ring.c b/usr/src/uts/common/io/dls/dls_soft_ring.c
index cfd75e724a..56c79edb1c 100644
--- a/usr/src/uts/common/io/dls/dls_soft_ring.c
+++ b/usr/src/uts/common/io/dls/dls_soft_ring.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.
@@ -20,7 +19,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.
*/
@@ -371,7 +370,7 @@ soft_ring_process(soft_ring_t *ringp, mblk_t *mp_chain, uint8_t tag)
arg2 = ringp->s_ring_upcall_arg2;
mutex_exit(&ringp->s_ring_lock);
- (*proc)(arg1, arg2, mp_chain, -1);
+ (*proc)(arg1, arg2, mp_chain, NULL);
ASSERT(MUTEX_NOT_HELD(&ringp->s_ring_lock));
mutex_enter(&ringp->s_ring_lock);
@@ -481,7 +480,7 @@ soft_ring_drain(soft_ring_t *ringp, clock_t expire)
tid = 0;
}
- (*proc)(arg1, arg2, mp, -1);
+ (*proc)(arg1, arg2, mp, NULL);
mutex_enter(&ringp->s_ring_lock);
}
@@ -632,7 +631,7 @@ dls_soft_ring_enable(dls_channel_t dc, dl_capab_dls_t *soft_ringp)
/* ARGSUSED */
void
dls_ether_soft_ring_fanout(void *rx_handle, void *rx_cookie, mblk_t *mp_chain,
- size_t hdrlen)
+ mac_header_info_t *mhip)
{
ipha_t *ipha = (ipha_t *)mp_chain->b_rptr;
dls_impl_t *dip = (dls_impl_t *)rx_handle;
diff --git a/usr/src/uts/common/io/gld.c b/usr/src/uts/common/io/gld.c
index c70b2c53cd..240d81c25e 100644
--- a/usr/src/uts/common/io/gld.c
+++ b/usr/src/uts/common/io/gld.c
@@ -68,27 +68,52 @@
#include <sys/sunddi.h>
/*
- * Macro to atomically increment counters of type uint32_t, uint64_t
- * and ulong_t.
+ * Macros to increment statistics.
*/
-#define BUMP(stat, delta) do { \
+
+/*
+ * Increase kstats. Note this operation is not atomic. It can be used when
+ * GLDM_LOCK_HELD_WRITE(macinfo).
+ */
+#define BUMP(stats, vstats, stat, delta) do { \
+ ((stats)->stat) += (delta); \
+ _NOTE(CONSTANTCONDITION) \
+ if ((vstats) != NULL) \
+ ((struct gld_stats *)(vstats))->stat += (delta); \
+ _NOTE(CONSTANTCONDITION) \
+} while (0)
+
+#define ATOMIC_BUMP_STAT(stat, delta) do { \
_NOTE(CONSTANTCONDITION) \
- if (sizeof (stat) == sizeof (uint32_t)) { \
- atomic_add_32((uint32_t *)&stat, delta); \
+ if (sizeof ((stat)) == sizeof (uint32_t)) { \
+ atomic_add_32((uint32_t *)&(stat), (delta)); \
_NOTE(CONSTANTCONDITION) \
- } else if (sizeof (stat) == sizeof (uint64_t)) { \
- atomic_add_64((uint64_t *)&stat, delta); \
+ } else if (sizeof ((stat)) == sizeof (uint64_t)) { \
+ atomic_add_64((uint64_t *)&(stat), (delta)); \
} \
_NOTE(CONSTANTCONDITION) \
} while (0)
-#define UPDATE_STATS(vlan, pktinfo, number) { \
- if ((pktinfo).isBroadcast) \
- (vlan)->gldv_stats->glds_brdcstxmt += (number); \
- else if ((pktinfo).isMulticast) \
- (vlan)->gldv_stats->glds_multixmt += (number); \
- (vlan)->gldv_stats->glds_bytexmt64 += (pktinfo).pktLen; \
- (vlan)->gldv_stats->glds_pktxmt64 += (number); \
+#define ATOMIC_BUMP(stats, vstats, stat, delta) do { \
+ ATOMIC_BUMP_STAT((stats)->stat, (delta)); \
+ _NOTE(CONSTANTCONDITION) \
+ if ((vstats) != NULL) { \
+ ATOMIC_BUMP_STAT(((struct gld_stats *)(vstats))->stat, \
+ (delta)); \
+ } \
+ _NOTE(CONSTANTCONDITION) \
+} while (0)
+
+#define UPDATE_STATS(stats, vstats, pktinfo, delta) { \
+ if ((pktinfo).isBroadcast) { \
+ ATOMIC_BUMP((stats), (vstats), \
+ glds_brdcstxmt, (delta)); \
+ } else if ((pktinfo).isMulticast) { \
+ ATOMIC_BUMP((stats), (vstats), glds_multixmt, (delta)); \
+ } \
+ ATOMIC_BUMP((stats), (vstats), glds_bytexmt64, \
+ ((pktinfo).pktLen)); \
+ ATOMIC_BUMP((stats), (vstats), glds_pktxmt64, (delta)); \
}
#ifdef GLD_DEBUG
@@ -114,12 +139,12 @@ static int gld_start(queue_t *, mblk_t *, int, uint32_t);
static int gld_start_mdt(queue_t *, mblk_t *, int);
/* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */
-static void gld_precv(gld_mac_info_t *, gld_vlan_t *, mblk_t *);
+static void gld_precv(gld_mac_info_t *, mblk_t *, uint32_t, struct gld_stats *);
static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *,
pdesc_t *, pktinfo_t *);
/* receive group: called from gld_recv and gld_precv* with maclock held */
-static void gld_sendup(gld_mac_info_t *, gld_vlan_t *, pktinfo_t *, mblk_t *,
+static void gld_sendup(gld_mac_info_t *, pktinfo_t *, mblk_t *,
int (*)());
static int gld_accept(gld_t *, pktinfo_t *);
static int gld_mcmatch(gld_t *, pktinfo_t *);
@@ -127,7 +152,7 @@ static int gld_multicast(unsigned char *, gld_t *);
static int gld_paccept(gld_t *, pktinfo_t *);
static void gld_passon(gld_t *, mblk_t *, pktinfo_t *,
void (*)(queue_t *, mblk_t *));
-static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *);
+static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *, boolean_t);
/* wsrv group: called from wsrv, single threaded per queue */
static int gld_ioctl(queue_t *, mblk_t *);
@@ -241,33 +266,6 @@ static char *gld_duplex[] = {
"full" /* GLD_DUPLEX_FULL */
};
-extern int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
-extern int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
-extern int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
-extern int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
-extern void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *,
- pktinfo_t *, int);
-
-extern mblk_t *gld_fastpath_ether(gld_t *, mblk_t *);
-extern mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *);
-extern mblk_t *gld_fastpath_tr(gld_t *, mblk_t *);
-extern mblk_t *gld_fastpath_ib(gld_t *, mblk_t *);
-
-extern mblk_t *gld_unitdata_ether(gld_t *, mblk_t *);
-extern mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *);
-extern mblk_t *gld_unitdata_tr(gld_t *, mblk_t *);
-extern mblk_t *gld_unitdata_ib(gld_t *, mblk_t *);
-
-extern void gld_init_ether(gld_mac_info_t *);
-extern void gld_init_fddi(gld_mac_info_t *);
-extern void gld_init_tr(gld_mac_info_t *);
-extern void gld_init_ib(gld_mac_info_t *);
-
-extern void gld_uninit_ether(gld_mac_info_t *);
-extern void gld_uninit_fddi(gld_mac_info_t *);
-extern void gld_uninit_tr(gld_mac_info_t *);
-extern void gld_uninit_ib(gld_mac_info_t *);
-
/*
* Interface types currently supported by GLD.
* If you add new types, you must check all "XXX" strings in the GLD source
@@ -283,7 +281,7 @@ static gld_interface_t interfaces[] = {
{
DL_ETHER,
(uint_t)-1,
- sizeof (struct ether_mac_frm),
+ sizeof (struct ether_header),
gld_interpret_ether,
NULL,
gld_fastpath_ether,
@@ -1703,6 +1701,7 @@ gld_wput(queue_t *q, mblk_t *mp)
gld_t *gld = (gld_t *)(q->q_ptr);
int rc;
boolean_t multidata = B_TRUE;
+ uint32_t upri;
#ifdef GLD_DEBUG
if (gld_debug & GLDTRACE)
@@ -1720,6 +1719,11 @@ gld_wput(queue_t *q, mblk_t *mp)
merror(q, mp, EPROTO);
break;
}
+ /*
+ * Cleanup MBLK_VTAG in case it is set by other
+ * modules. MBLK_VTAG is used to save the vtag information.
+ */
+ GLD_CLEAR_MBLK_VTAG(mp);
multidata = B_FALSE;
/* LINTED: E_CASE_FALLTHRU */
case M_MULTIDATA:
@@ -1752,8 +1756,15 @@ gld_wput(queue_t *q, mblk_t *mp)
goto use_wsrv;
}
+ /*
+ * Get the priority value. Note that in raw mode, the
+ * per-packet priority value kept in b_band is ignored.
+ */
+ upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri :
+ UPRI(gld, mp->b_band);
+
rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) :
- gld_start(q, mp, GLD_WPUT, UPRI(gld, mp->b_band));
+ gld_start(q, mp, GLD_WPUT, upri);
/* Allow DL_UNBIND again */
membar_exit();
@@ -1828,6 +1839,7 @@ gld_wsrv(queue_t *q)
union DL_primitives *prim;
int err;
boolean_t multidata;
+ uint32_t upri;
#ifdef GLD_DEBUG
if (gld_debug & GLDTRACE)
@@ -1868,8 +1880,16 @@ gld_wsrv(queue_t *q)
gld->gld_sched_ran = B_FALSE;
membar_enter();
+
+ /*
+ * Get the priority value. Note that in raw mode, the
+ * per-packet priority value kept in b_band is ignored.
+ */
+ upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri :
+ UPRI(gld, mp->b_band);
+
err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) :
- gld_start(q, mp, GLD_WSRV, UPRI(gld, mp->b_band));
+ gld_start(q, mp, GLD_WSRV, upri);
if (err == GLD_NORESOURCES) {
/* gld_sched will qenable us later */
gld->gld_xwait = B_TRUE; /* want qenable */
@@ -1992,6 +2012,25 @@ gld_wsrv(queue_t *q)
* and the DL_DETACH will succeed. It's hard to test this since the odds
* of the failure even trying to happen are so small. I probably could
* have ignored the whole issue and never been the worse for it.
+ *
+ * Because some GLDv2 Ethernet drivers do not allow the size of transmitted
+ * packet to be greater than ETHERMAX, we must first strip the VLAN tag
+ * from a tagged packet before passing it to the driver's gld_send() entry
+ * point function, and pass the VLAN tag as a separate argument. The
+ * gld_send() function may fail. In that case, the packet will need to be
+ * queued in order to be processed again in GLD's service routine. As the
+ * VTAG has already been stripped at that time, we save the VTAG information
+ * in (the unused fields of) dblk using GLD_SAVE_MBLK_VTAG(), so that the
+ * VTAG can also be queued and be able to be got when gld_start() is called
+ * next time from gld_wsrv().
+ *
+ * Some rules to use GLD_{CLEAR|SAVE}_MBLK_VTAG macros:
+ *
+ * - GLD_SAVE_MBLK_VTAG() must be called to save the VTAG information each time
+ * the message is queued by putbq().
+ *
+ * - GLD_CLEAR_MBLK_VTAG() must be called to clear the bogus VTAG information
+ * (if any) in dblk before the message is passed to the gld_start() function.
*/
static int
gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
@@ -2003,24 +2042,95 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
int rc;
gld_interface_t *ifp;
pktinfo_t pktinfo;
- uint32_t vtag;
+ uint32_t vtag, vid;
+ uint32_t raw_vtag = 0;
gld_vlan_t *vlan;
+ struct gld_stats *stats0, *stats = NULL;
ASSERT(DB_TYPE(mp) == M_DATA);
macinfo = gld->gld_mac_info;
mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
ifp = mac_pvt->interfacep;
vlan = (gld_vlan_t *)gld->gld_vlan;
+ vid = vlan->gldv_id;
+
+ /*
+ * If this interface is a VLAN, the kstats of corresponding
+ * "VLAN 0" should also be updated. Note that the gld_vlan_t
+ * structure for VLAN 0 might not exist if there are no DLPI
+ * consumers attaching on VLAN 0. Fortunately we can directly
+ * access VLAN 0's kstats from macinfo.
+ *
+ * Therefore, stats0 (VLAN 0's kstats) must always be
+ * updated, and stats must to be updated if it is not NULL.
+ */
+ stats0 = mac_pvt->statistics;
+ if (vid != VLAN_VID_NONE)
+ stats = vlan->gldv_stats;
if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) {
- freemsg(mp);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
"gld_start: failed to interpret outbound packet");
#endif
- vlan->gldv_stats->glds_xmtbadinterp++;
- return (GLD_BADARG);
+ goto badarg;
+ }
+
+ vtag = VLAN_VID_NONE;
+ raw_vtag = GLD_GET_MBLK_VTAG(mp);
+ if (GLD_VTAG_TCI(raw_vtag) != 0) {
+ uint16_t raw_pri, raw_vid, evid;
+
+ /*
+ * Tagged packet.
+ */
+ raw_pri = GLD_VTAG_PRI(raw_vtag);
+ raw_vid = GLD_VTAG_VID(raw_vtag);
+ GLD_CLEAR_MBLK_VTAG(mp);
+
+ if (gld->gld_flags & GLD_RAW) {
+ /*
+ * In raw mode, we only expect untagged packets or
+ * special priority-tagged packets on a VLAN stream.
+ * Drop the packet if its VID is not zero.
+ */
+ if (vid != VLAN_VID_NONE && raw_vid != VLAN_VID_NONE)
+ goto badarg;
+
+ /*
+ * If it is raw mode, use the per-stream priority if
+ * the priority is not specified in the packet.
+ * Otherwise, ignore the priority bits in the packet.
+ */
+ upri = (raw_pri != 0) ? raw_pri : upri;
+ }
+
+ if (vid == VLAN_VID_NONE && vid != raw_vid) {
+ gld_vlan_t *tmp_vlan;
+
+ /*
+ * This link is a physical link but the packet is
+ * a VLAN tagged packet, the kstats of corresponding
+ * VLAN (if any) should also be updated.
+ */
+ tmp_vlan = gld_find_vlan(macinfo, raw_vid);
+ if (tmp_vlan != NULL)
+ stats = tmp_vlan->gldv_stats;
+ }
+
+ evid = (vid == VLAN_VID_NONE) ? raw_vid : vid;
+ if (evid != VLAN_VID_NONE || upri != 0)
+ vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, evid);
+ } else {
+ /*
+ * Untagged packet:
+ * Get vtag from the attached PPA of this stream.
+ */
+ if ((vid != VLAN_VID_NONE) ||
+ ((macinfo->gldm_type == DL_ETHER) && (upri != 0))) {
+ vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, vid);
+ }
}
/*
@@ -2039,6 +2149,7 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
* driver's send routine.
*/
if (caller == GLD_WPUT) {
+ GLD_SAVE_MBLK_VTAG(mp, raw_vtag);
(void) putbq(q, mp);
return (GLD_NORESOURCES);
}
@@ -2049,11 +2160,9 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
} else
nmp = NULL; /* we need no loopback */
- vtag = GLD_MK_VTAG(vlan->gldv_ptag, upri);
if (ifp->hdr_size > 0 &&
pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
macinfo->gldm_maxpkt) {
- freemsg(mp); /* discard oversized outbound packet */
if (nmp)
freemsg(nmp); /* free the duped message */
#ifdef GLD_DEBUG
@@ -2061,23 +2170,24 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
cmn_err(CE_WARN,
"gld_start: oversize outbound packet, size %d,"
"max %d", pktinfo.pktLen,
- ifp->hdr_size + macinfo->gldm_maxpkt);
+ ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
+ macinfo->gldm_maxpkt);
#endif
- vlan->gldv_stats->glds_xmtbadinterp++;
- return (GLD_BADARG);
+ goto badarg;
}
rc = (*gld->gld_send)(macinfo, mp, vtag);
if (rc != GLD_SUCCESS) {
if (rc == GLD_NORESOURCES) {
- vlan->gldv_stats->glds_xmtretry++;
+ ATOMIC_BUMP(stats0, stats, glds_xmtretry, 1);
+ GLD_SAVE_MBLK_VTAG(mp, raw_vtag);
(void) putbq(q, mp);
} else {
/* transmit error; drop the packet */
freemsg(mp);
/* We're supposed to count failed attempts as well */
- UPDATE_STATS(vlan, pktinfo, 1);
+ UPDATE_STATS(stats0, stats, pktinfo, 1);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
@@ -2089,21 +2199,27 @@ gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
return (rc);
}
- UPDATE_STATS(vlan, pktinfo, 1);
+ UPDATE_STATS(stats0, stats, pktinfo, 1);
/*
* Loopback case. The message needs to be returned back on
- * the read side. This would silently fail if the dumpmsg fails
+ * the read side. This would silently fail if the dupmsg fails
* above. This is probably OK, if there is no memory to dup the
* block, then there isn't much we could do anyway.
*/
if (nmp) {
GLDM_LOCK(macinfo, RW_WRITER);
- gld_precv(macinfo, vlan, nmp);
+ gld_precv(macinfo, nmp, vtag, stats);
GLDM_UNLOCK(macinfo);
}
return (GLD_SUCCESS);
+
+badarg:
+ freemsg(mp);
+
+ ATOMIC_BUMP(stats0, stats, glds_xmtbadinterp, 1);
+ return (GLD_BADARG);
}
/*
@@ -2244,7 +2360,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
}
(*macinfo->gldm_mdt_post)(macinfo, mp, cookie);
pktinfo.pktLen = totLen;
- UPDATE_STATS(vlan, pktinfo, numpacks);
+ UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, numpacks);
/*
* In the noresources case (when driver indicates it
@@ -2260,7 +2376,8 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
&pinfo);
mmd_rempdesc(dl_pkt);
}
- vlan->gldv_stats->glds_xmtretry++;
+ ATOMIC_BUMP(vlan->gldv_stats, NULL,
+ glds_xmtretry, 1);
mp->b_cont = nextmp;
(void) putbq(q, mp);
return (GLD_NORESOURCES);
@@ -2270,7 +2387,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
* Driver indicates it can not transmit any packets
* currently and will request retrial later.
*/
- vlan->gldv_stats->glds_xmtretry++;
+ ATOMIC_BUMP(vlan->gldv_stats, NULL, glds_xmtretry, 1);
mp->b_cont = nextmp;
(void) putbq(q, mp);
return (GLD_NORESOURCES);
@@ -2293,7 +2410,7 @@ gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo);
}
pktinfo.pktLen = totLen;
- UPDATE_STATS(vlan, pktinfo, mdtpacks);
+ UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, mdtpacks);
/*
* Transmit error; drop the message, move on
@@ -2373,11 +2490,15 @@ gld_sched(gld_mac_info_t *macinfo)
}
/*
- * gld_precv (macinfo, mp)
+ * gld_precv (macinfo, mp, vtag, stats)
* called from gld_start to loopback a packet when in promiscuous mode
+ *
+ * VLAN 0's statistics need to be updated. If stats is not NULL,
+ * it needs to be updated as well.
*/
static void
-gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
+gld_precv(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag,
+ struct gld_stats *stats)
{
gld_mac_pvt_t *mac_pvt;
gld_interface_t *ifp;
@@ -2393,7 +2514,7 @@ gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
*/
if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) {
freemsg(mp);
- BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
+ BUMP(mac_pvt->statistics, stats, glds_rcvbadinterp, 1);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
@@ -2402,12 +2523,23 @@ gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
return;
}
- gld_sendup(macinfo, vlan, &pktinfo, mp, gld_paccept);
+ /*
+ * Update the vtag information.
+ */
+ pktinfo.isTagged = (vtag != VLAN_VID_NONE);
+ pktinfo.vid = GLD_VTAG_VID(vtag);
+ pktinfo.cfi = GLD_VTAG_CFI(vtag);
+ pktinfo.user_pri = GLD_VTAG_PRI(vtag);
+
+ gld_sendup(macinfo, &pktinfo, mp, gld_paccept);
}
/*
- * called from gld_start_mdt to loopback packet(s) when in promiscuous mode
+ * Called from gld_start_mdt to loopback packet(s) when in promiscuous mode.
+ * Note that 'vlan' is always a physical link, because MDT can only be
+ * enabled on non-VLAN streams.
*/
+/*ARGSUSED*/
static void
gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
pdesc_t *dl_pkt, pktinfo_t *pktinfo)
@@ -2424,7 +2556,7 @@ gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo,
GLD_MDT_RXLOOP);
if ((adjmp = mmd_transform(dl_pkt)) != NULL)
- gld_sendup(macinfo, vlan, pktinfo, adjmp, gld_paccept);
+ gld_sendup(macinfo, pktinfo, adjmp, gld_paccept);
}
/*
@@ -2448,8 +2580,10 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
pktinfo_t pktinfo;
gld_interface_t *ifp;
queue_t *ipq = NULL;
- gld_vlan_t *vlan;
+ gld_vlan_t *vlan = NULL, *vlan0 = NULL, *vlann = NULL;
+ struct gld_stats *stats0, *stats = NULL;
uint32_t vid;
+ int err;
ASSERT(macinfo != NULL);
ASSERT(mp->b_datap->db_ref);
@@ -2462,21 +2596,62 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
goto done;
}
+ /*
+ * If this packet is a VLAN tagged packet, the kstats of corresponding
+ * "VLAN 0" should also be updated. We can directly access VLAN 0's
+ * kstats from macinfo.
+ *
+ * Further, the packets needs to be passed to VLAN 0 if there is
+ * any DLPI consumer on VLAN 0 who is interested in tagged packets
+ * (DL_PROMISC_SAP is on or is bounded to ETHERTYPE_VLAN SAP).
+ */
+ mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
+ stats0 = mac_pvt->statistics;
+
vid = GLD_VTAG_VID(vtag);
- if ((vlan = gld_find_vlan(macinfo, vid)) == NULL) {
+ vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE);
+ if (vid != VLAN_VID_NONE) {
+ /*
+ * If there are no physical DLPI consumers interested in the
+ * VLAN packet, clear vlan0.
+ */
+ if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0))
+ vlan0 = NULL;
+ /*
+ * vlann is the VLAN with the same VID as the VLAN packet.
+ */
+ vlann = gld_find_vlan(macinfo, vid);
+ if (vlann != NULL)
+ stats = vlann->gldv_stats;
+ }
+
+ vlan = (vid == VLAN_VID_NONE) ? vlan0 : vlann;
+
+ ifp = mac_pvt->interfacep;
+ err = (*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXQUICK);
+
+ BUMP(stats0, stats, glds_bytercv64, pktinfo.pktLen);
+ BUMP(stats0, stats, glds_pktrcv64, 1);
+
+ if ((vlann == NULL) && (vlan0 == NULL)) {
freemsg(mp);
goto done;
}
/*
- * Check whether underlying media code supports the IPQ hack,
- * and if so, whether the interpreter can quickly parse the
- * packet to get some relevant parameters.
+ * Check whether underlying media code supports the IPQ hack:
+ *
+ * - the interpreter could quickly parse the packet
+ * - the device type supports IPQ (ethernet and IPoIB)
+ * - there is one, and only one, IP stream bound (to this VLAN)
+ * - that stream is a "fastpath" stream
+ * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
+ * - there are no streams in promiscuous mode (on this VLAN)
+ * - if this packet is tagged, there is no need to send this
+ * packet to physical streams
*/
- mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
- ifp = mac_pvt->interfacep;
- if (((*ifp->interpreter)(macinfo, mp, &pktinfo,
- GLD_RXQUICK) == 0) && (vlan->gldv_ipq_flags == 0)) {
+ if ((err != 0) && ((vlan != NULL) && (vlan->gldv_nprom == 0)) &&
+ (vlan == vlan0 || vlan0 == NULL)) {
switch (pktinfo.ethertype) {
case ETHERTYPE_IP:
ipq = vlan->gldv_ipq;
@@ -2487,19 +2662,9 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
}
}
- BUMP(vlan->gldv_stats->glds_bytercv64, pktinfo.pktLen);
- BUMP(vlan->gldv_stats->glds_pktrcv64, 1);
-
/*
* Special case for IP; we can simply do the putnext here, if:
- * o ipq != NULL, and therefore:
- * - the device type supports IPQ (ethernet and IPoIB);
- * - the interpreter could quickly parse the packet;
- * - there are no PROMISC_SAP streams (on this VLAN);
- * - there is one, and only one, IP stream bound (to this VLAN);
- * - that stream is a "fastpath" stream;
- * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
- *
+ * o The IPQ hack is possible (ipq != NULL).
* o the packet is specifically for me, and therefore:
* - the packet is not multicast or broadcast (fastpath only
* wants unicast packets).
@@ -2522,7 +2687,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
* call the media specific packet interpreter routine
*/
if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) {
- BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
+ BUMP(stats0, stats, glds_rcvbadinterp, 1);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
@@ -2535,7 +2700,6 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
/*
* This is safe even if vtag is VLAN_VTAG_NONE
*/
-
pktinfo.vid = vid;
pktinfo.cfi = GLD_VTAG_CFI(vtag);
#ifdef GLD_DEBUG
@@ -2543,6 +2707,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI");
#endif
pktinfo.user_pri = GLD_VTAG_PRI(vtag);
+ pktinfo.isTagged = (vtag != VLAN_VID_NONE);
#ifdef GLD_DEBUG
if ((gld_debug & GLDRECV) &&
@@ -2567,7 +2732,7 @@ gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
}
#endif
- gld_sendup(macinfo, vlan, &pktinfo, mp, gld_accept);
+ gld_sendup(macinfo, &pktinfo, mp, gld_accept);
done:
GLDM_UNLOCK(macinfo);
@@ -2578,63 +2743,33 @@ done:
/* =================================================================== */
/*
- * gld_sendup (macinfo, mp)
- * called with an ethernet packet in a mblock; must decide whether
- * packet is for us and which streams to queue it to.
+ * Search all the streams attached to the specified VLAN looking for
+ * those eligible to receive the packet.
+ * Note that in order to avoid an extra dupmsg(), if this is the first
+ * eligible stream, remember it (in fgldp) so that we can send up the
+ * message after this function.
+ *
+ * Return errno if fails. Currently the only error is ENOMEM.
*/
-static void
-gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
- mblk_t *mp, int (*acceptfunc)())
+static int
+gld_sendup_vlan(gld_vlan_t *vlan, pktinfo_t *pktinfo, mblk_t *mp,
+ int (*acceptfunc)(), void (*send)(), int (*cansend)(), gld_t **fgldp)
{
- gld_t *gld;
- gld_t *fgld = NULL;
mblk_t *nmp;
- void (*send)(queue_t *qp, mblk_t *mp);
- int (*cansend)(queue_t *qp);
-
-#ifdef GLD_DEBUG
- if (gld_debug & GLDTRACE)
- cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
- (void *)macinfo);
-#endif
+ gld_t *gld;
+ int err = 0;
- ASSERT(mp != NULL);
- ASSERT(macinfo != NULL);
ASSERT(vlan != NULL);
- ASSERT(pktinfo != NULL);
- ASSERT(GLDM_LOCK_HELD(macinfo));
-
- /*
- * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
- * gld_recv returns to the caller's interrupt routine. The total
- * network throughput would normally be lower when selecting this
- * option, because we putq the messages and process them later,
- * instead of sending them with putnext now. Some time critical
- * device might need this, so it's here but undocumented.
- */
- if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
- send = (void (*)(queue_t *, mblk_t *))putq;
- cansend = canput;
- } else {
- send = (void (*)(queue_t *, mblk_t *))putnext;
- cansend = canputnext;
- }
-
- /*
- * Search all the streams attached to this macinfo looking for
- * those eligible to receive the present packet.
- */
- for (gld = vlan->gldv_str_next;
- gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
+ for (gld = vlan->gldv_str_next; gld != (gld_t *)&vlan->gldv_str_next;
+ gld = gld->gld_next) {
#ifdef GLD_VERBOSE_DEBUG
- cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p QSTATE: %s",
+ cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p "QSTATE: %s",
gld->gld_sap, (void *)gld->gld_qptr,
gld->gld_state == DL_IDLE ? "IDLE": "NOT IDLE");
#endif
ASSERT(gld->gld_qptr != NULL);
ASSERT(gld->gld_state == DL_IDLE ||
gld->gld_state == DL_UNBOUND);
- ASSERT(gld->gld_mac_info == macinfo);
ASSERT(gld->gld_vlan == vlan);
if (gld->gld_state != DL_IDLE)
@@ -2660,7 +2795,7 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
*/
if ((*acceptfunc)(gld, pktinfo)) {
/* sap matches */
- pktinfo->wasAccepted = 1; /* known protocol */
+ pktinfo->wasAccepted = 1; /* known protocol */
if (!(*cansend)(gld->gld_qptr)) {
/*
@@ -2673,36 +2808,114 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
cmn_err(CE_WARN,
"gld_sendup: canput failed");
#endif
- BUMP(vlan->gldv_stats->glds_blocked, 1);
+ BUMP(vlan->gldv_stats, NULL, glds_blocked, 1);
qenable(gld->gld_qptr);
continue;
}
/*
- * we are trying to avoid an extra dumpmsg() here.
- * If this is the first eligible queue, remember the
- * queue and send up the message after the loop.
+ * In order to avoid an extra dupmsg(), remember this
+ * gld if this is the first eligible stream.
*/
- if (!fgld) {
- fgld = gld;
+ if (*fgldp == NULL) {
+ *fgldp = gld;
continue;
}
/* duplicate the packet for this stream */
nmp = dupmsg(mp);
if (nmp == NULL) {
- BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
+ BUMP(vlan->gldv_stats, NULL,
+ glds_gldnorcvbuf, 1);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
"gld_sendup: dupmsg failed");
#endif
- break; /* couldn't get resources; drop it */
+ /* couldn't get resources; drop it */
+ err = ENOMEM;
+ break;
}
/* pass the message up the stream */
gld_passon(gld, nmp, pktinfo, send);
}
}
+ return (err);
+}
+
+/*
+ * gld_sendup (macinfo, pktinfo, mp, acceptfunc)
+ * called with an ethernet packet in an mblk; must decide whether
+ * packet is for us and which streams to queue it to.
+ */
+static void
+gld_sendup(gld_mac_info_t *macinfo, pktinfo_t *pktinfo,
+ mblk_t *mp, int (*acceptfunc)())
+{
+ gld_t *fgld = NULL;
+ void (*send)(queue_t *qp, mblk_t *mp);
+ int (*cansend)(queue_t *qp);
+ gld_vlan_t *vlan0, *vlann = NULL;
+ struct gld_stats *stats0, *stats = NULL;
+ int err = 0;
+
+#ifdef GLD_DEBUG
+ if (gld_debug & GLDTRACE)
+ cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
+ (void *)macinfo);
+#endif
+
+ ASSERT(mp != NULL);
+ ASSERT(macinfo != NULL);
+ ASSERT(pktinfo != NULL);
+ ASSERT(GLDM_LOCK_HELD(macinfo));
+
+ /*
+ * The tagged packets should also be looped back (transmit-side)
+ * or sent up (receive-side) to VLAN 0 if VLAN 0 is set to
+ * DL_PROMISC_SAP or there is any DLPI consumer bind to the
+ * ETHERTYPE_VLAN SAP. The kstats of VLAN 0 needs to be updated
+ * as well.
+ */
+ stats0 = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->statistics;
+ vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE);
+ if (pktinfo->vid != VLAN_VID_NONE) {
+ if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0))
+ vlan0 = NULL;
+ vlann = gld_find_vlan(macinfo, pktinfo->vid);
+ if (vlann != NULL)
+ stats = vlann->gldv_stats;
+ }
+
+ ASSERT((vlan0 != NULL) || (vlann != NULL));
+
+ /*
+ * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
+ * gld_recv returns to the caller's interrupt routine. The total
+ * network throughput would normally be lower when selecting this
+ * option, because we putq the messages and process them later,
+ * instead of sending them with putnext now. Some time critical
+ * device might need this, so it's here but undocumented.
+ */
+ if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
+ send = (void (*)(queue_t *, mblk_t *))putq;
+ cansend = canput;
+ } else {
+ send = (void (*)(queue_t *, mblk_t *))putnext;
+ cansend = canputnext;
+ }
+
+ /*
+ * Send the packets for all eligible streams.
+ */
+ if (vlan0 != NULL) {
+ err = gld_sendup_vlan(vlan0, pktinfo, mp, acceptfunc, send,
+ cansend, &fgld);
+ }
+ if ((err == 0) && (vlann != NULL)) {
+ err = gld_sendup_vlan(vlann, pktinfo, mp, acceptfunc, send,
+ cansend, &fgld);
+ }
ASSERT(mp);
/* send the original dup of the packet up the first stream found */
@@ -2716,23 +2929,28 @@ gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
return; /* transmit loopback case */
if (pktinfo->isBroadcast)
- BUMP(vlan->gldv_stats->glds_brdcstrcv, 1);
+ BUMP(stats0, stats, glds_brdcstrcv, 1);
else if (pktinfo->isMulticast)
- BUMP(vlan->gldv_stats->glds_multircv, 1);
+ BUMP(stats0, stats, glds_multircv, 1);
/* No stream accepted this packet */
if (!pktinfo->wasAccepted)
- BUMP(vlan->gldv_stats->glds_unknowns, 1);
+ BUMP(stats0, stats, glds_unknowns, 1);
}
+#define GLD_IS_PHYS(gld) \
+ (((gld_vlan_t *)gld->gld_vlan)->gldv_id == VLAN_VID_NONE)
+
/*
* A packet matches a stream if:
- * the stream accepts EtherType encoded packets and the type matches
- * or the stream accepts LLC packets and the packet is an LLC packet
+ * The stream's VLAN id is the same as the one in the packet.
+ * and the stream accepts EtherType encoded packets and the type matches
+ * or the stream accepts LLC packets and the packet is an LLC packet
*/
#define MATCH(stream, pktinfo) \
+ ((((gld_vlan_t *)stream->gld_vlan)->gldv_id == pktinfo->vid) && \
((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \
- (!stream->gld_ethertype && pktinfo->isLLC))
+ (!stream->gld_ethertype && pktinfo->isLLC)))
/*
* This function validates a packet for sending up a particular
@@ -2745,8 +2963,16 @@ gld_accept(gld_t *gld, pktinfo_t *pktinfo)
{
/*
* if there is no match do not bother checking further.
+ * Note that it is okay to examine gld_vlan because
+ * macinfo->gldm_lock is held.
+ *
+ * Because all tagged packets have SAP value ETHERTYPE_VLAN,
+ * these packets will pass the SAP filter check if the stream
+ * is a ETHERTYPE_VLAN listener.
*/
- if (!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP))
+ if ((!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP) &&
+ !(GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN &&
+ pktinfo->isTagged)))
return (0);
/*
@@ -2836,15 +3062,29 @@ gld_multicast(unsigned char *macaddr, gld_t *gld)
static int
gld_paccept(gld_t *gld, pktinfo_t *pktinfo)
{
+ /*
+ * Note that it is okay to examine gld_vlan because macinfo->gldm_lock
+ * is held.
+ *
+ * If a stream is a ETHERTYPE_VLAN listener, it must
+ * accept all tagged packets as those packets have SAP value
+ * ETHERTYPE_VLAN.
+ */
return (gld->gld_flags & GLD_PROM_PHYS &&
- (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP));
+ (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP ||
+ (GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN &&
+ pktinfo->isTagged)));
+
}
static void
gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
void (*send)(queue_t *qp, mblk_t *mp))
{
+ boolean_t is_phys = GLD_IS_PHYS(gld);
int skiplen;
+ boolean_t addtag = B_FALSE;
+ uint32_t vtag = 0;
#ifdef GLD_DEBUG
if (gld_debug & GLDTRACE)
@@ -2857,26 +3097,39 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
(void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor,
gld->gld_sap);
#endif
-
/*
* Figure out how much of the packet header to throw away.
*
- * RAW streams expect to see the whole packet.
- *
- * Other streams expect to see the packet with the MAC header
- * removed.
- *
* Normal DLPI (non RAW/FAST) streams also want the
* DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA.
*/
if (gld->gld_flags & GLD_RAW) {
+ /*
+ * The packet will be tagged in the following cases:
+ * - if priority is not 0
+ * - a tagged packet sent on a physical link
+ */
+ if ((pktinfo->isTagged && is_phys) || (pktinfo->user_pri != 0))
+ addtag = B_TRUE;
skiplen = 0;
} else {
+ /*
+ * The packet will be tagged if it meets all below conditions:
+ * - this is a physical stream
+ * - this packet is tagged packet
+ * - the stream is either a DL_PROMISC_SAP listener or a
+ * ETHERTYPE_VLAN listener
+ */
+ if (is_phys && pktinfo->isTagged &&
+ ((gld->gld_sap == ETHERTYPE_VLAN) ||
+ (gld->gld_flags & GLD_PROM_SAP))) {
+ addtag = B_TRUE;
+ }
+
skiplen = pktinfo->macLen; /* skip mac header */
if (gld->gld_ethertype)
skiplen += pktinfo->hdrLen; /* skip any extra */
}
-
if (skiplen >= pktinfo->pktLen) {
/*
* If the interpreter did its job right, then it cannot be
@@ -2891,6 +3144,17 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
return;
}
+ if (addtag) {
+ mblk_t *savemp = mp;
+
+ vtag = GLD_MAKE_VTAG(pktinfo->user_pri, pktinfo->cfi,
+ is_phys ? pktinfo->vid : VLAN_VID_NONE);
+ if ((mp = gld_insert_vtag_ether(mp, vtag)) == NULL) {
+ freemsg(savemp);
+ return;
+ }
+ }
+
/*
* Skip over the header(s), taking care to possibly handle message
* fragments shorter than the amount we need to skip. Hopefully
@@ -2898,11 +3162,11 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
* header, into a single message block. But we handle it if not.
*/
while (skiplen >= MBLKL(mp)) {
- mblk_t *tmp = mp;
+ mblk_t *savemp = mp;
skiplen -= MBLKL(mp);
mp = mp->b_cont;
ASSERT(mp != NULL); /* because skiplen < pktinfo->pktLen */
- freeb(tmp);
+ freeb(savemp);
}
mp->b_rptr += skiplen;
@@ -2913,7 +3177,7 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
(*send)(gld->gld_qptr, mp);
} else {
/* everybody else wants to see a unitdata_ind structure */
- mp = gld_addudind(gld, mp, pktinfo);
+ mp = gld_addudind(gld, mp, pktinfo, addtag);
if (mp)
(*send)(gld->gld_qptr, mp);
/* if it failed, gld_addudind already bumped statistic */
@@ -2925,7 +3189,7 @@ gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
* format a DL_UNITDATA_IND message to be sent upstream to the user
*/
static mblk_t *
-gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
+gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, boolean_t tagged)
{
gld_mac_info_t *macinfo = gld->gld_mac_info;
gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
@@ -2949,7 +3213,7 @@ gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen));
if ((nmp = allocb(size, BPRI_MED)) == NULL) {
freemsg(mp);
- BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
+ BUMP(vlan->gldv_stats, NULL, glds_gldnorcvbuf, 1);
#ifdef GLD_DEBUG
if (gld_debug & GLDERRS)
cmn_err(CE_WARN,
@@ -2960,7 +3224,11 @@ gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
DB_TYPE(nmp) = M_PROTO;
nmp->b_rptr = nmp->b_datap->db_lim - size;
- type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
+ if (tagged)
+ type = ETHERTYPE_VLAN;
+ else
+ type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
+
/*
* now setup the DL_UNITDATA_IND header
@@ -3116,7 +3384,12 @@ gld_ioctl(queue_t *q, mblk_t *mp)
break;
case DL_IOC_HDR_INFO: /* fastpath */
- if (gld_global_options & GLD_OPT_NO_FASTPATH) {
+ /*
+ * DL_IOC_HDR_INFO should only come from IP. The one
+ * initiated from user-land should not be allowed.
+ */
+ if ((gld_global_options & GLD_OPT_NO_FASTPATH) ||
+ (iocp->ioc_cr != kcred)) {
miocnak(q, mp, 0, EINVAL);
break;
}
@@ -3157,7 +3430,6 @@ gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
t_scalar_t off, len;
uint_t maclen;
int error;
- gld_vlan_t *vlan;
if (gld->gld_state != DL_IDLE) {
miocnak(q, mp, 0, EINVAL);
@@ -3194,8 +3466,6 @@ gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
*/
GLDM_LOCK(macinfo, RW_WRITER);
gld->gld_flags |= GLD_FAST;
- vlan = (gld_vlan_t *)gld->gld_vlan;
- vlan->gldv_ipq_flags &= ~IPQ_DISABLED;
GLDM_UNLOCK(macinfo);
ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
@@ -3952,6 +4222,8 @@ gld_bind(queue_t *q, mblk_t *mp)
GLDM_LOCK(macinfo, RW_WRITER);
gld->gld_state = DL_IDLE; /* bound and ready */
gld->gld_sap = sap;
+ if ((macinfo->gldm_type == DL_ETHER) && (sap == ETHERTYPE_VLAN))
+ ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap++;
gld_set_ipq(gld);
#ifdef GLD_DEBUG
@@ -4017,6 +4289,10 @@ gld_unbind(queue_t *q, mblk_t *mp)
}
GLDM_LOCK(macinfo, RW_WRITER);
+ if ((macinfo->gldm_type == DL_ETHER) &&
+ (gld->gld_sap == ETHERTYPE_VLAN)) {
+ ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap--;
+ }
gld->gld_state = DL_UNBOUND;
gld->gld_sap = 0;
gld_set_ipq(gld);
@@ -4052,7 +4328,6 @@ gld_inforeq(queue_t *q, mblk_t *mp)
int sap_length;
int brdcst_offset;
int brdcst_length;
- gld_vlan_t *vlan;
uchar_t *sapp;
#ifdef GLD_DEBUG
@@ -4088,8 +4363,7 @@ gld_inforeq(queue_t *q, mblk_t *mp)
brdcst_offset = bufsize;
bufsize += brdcst_length;
- if ((vlan = (gld_vlan_t *)gld->gld_vlan) != NULL &&
- vlan->gldv_id != VLAN_VID_NONE) {
+ if (((gld_vlan_t *)gld->gld_vlan) != NULL) {
sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t);
@@ -4276,6 +4550,7 @@ gld_unitdata(queue_t *q, mblk_t *mp)
(void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value,
flags, 0);
+ GLD_CLEAR_MBLK_VTAG(nmp);
if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) {
qenable(q);
return (GLDE_RETRY);
@@ -4458,8 +4733,6 @@ gldunattach(queue_t *q, mblk_t *mp)
mult_off = (gld->gld_flags & GLD_PROM_MULT &&
--mac_pvt->nprom_multi == 0);
- gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
-
if (phys_off) {
op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE :
GLD_MAC_PROMISC_MULTI;
@@ -4471,6 +4744,18 @@ gldunattach(queue_t *q, mblk_t *mp)
if (op != GLD_MAC_PROMISC_NOOP)
(void) (*macinfo->gldm_set_promiscuous)(macinfo, op);
+ vlan = (gld_vlan_t *)gld->gld_vlan;
+ if (gld->gld_flags & GLD_PROM_PHYS)
+ vlan->gldv_nprom--;
+ if (gld->gld_flags & GLD_PROM_MULT)
+ vlan->gldv_nprom--;
+ if (gld->gld_flags & GLD_PROM_SAP) {
+ vlan->gldv_nprom--;
+ vlan->gldv_nvlan_sap--;
+ }
+
+ gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
+
GLDM_UNLOCK(macinfo);
if (phys_off)
@@ -4486,7 +4771,6 @@ gldunattach(queue_t *q, mblk_t *mp)
/* disassociate this stream with its vlan and underlying mac */
gldremque(gld);
- vlan = (gld_vlan_t *)gld->gld_vlan;
if (--vlan->gldv_nstreams == 0) {
gld_rem_vlan(vlan);
gld->gld_vlan = NULL;
@@ -4909,16 +5193,20 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
switch (prim->promiscon_req.dl_level) {
case DL_PROMISC_PHYS:
mac_pvt->nprom++;
+ vlan->gldv_nprom++;
gld->gld_flags |= GLD_PROM_PHYS;
break;
case DL_PROMISC_MULTI:
mac_pvt->nprom_multi++;
+ vlan->gldv_nprom++;
gld->gld_flags |= GLD_PROM_MULT;
break;
case DL_PROMISC_SAP:
gld->gld_flags |= GLD_PROM_SAP;
+ vlan->gldv_nprom++;
+ vlan->gldv_nvlan_sap++;
break;
default:
@@ -4928,16 +5216,20 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
switch (prim->promiscoff_req.dl_level) {
case DL_PROMISC_PHYS:
mac_pvt->nprom--;
+ vlan->gldv_nprom--;
gld->gld_flags &= ~GLD_PROM_PHYS;
break;
case DL_PROMISC_MULTI:
mac_pvt->nprom_multi--;
+ vlan->gldv_nprom--;
gld->gld_flags &= ~GLD_PROM_MULT;
break;
case DL_PROMISC_SAP:
gld->gld_flags &= ~GLD_PROM_SAP;
+ vlan->gldv_nvlan_sap--;
+ vlan->gldv_nprom--;
break;
default:
@@ -4953,14 +5245,6 @@ gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
gld->gld_xwait = B_TRUE;
}
- /*
- * Update VLAN IPQ status -- it may have changed
- */
- if (gld->gld_flags & (GLD_PROM_SAP | GLD_PROM_MULT | GLD_PROM_PHYS))
- vlan->gldv_ipq_flags |= IPQ_FORBIDDEN;
- else
- vlan->gldv_ipq_flags &= ~IPQ_FORBIDDEN;
-
GLDM_UNLOCK(macinfo);
/*
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);
diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c
index 80d3583fbd..3f414af351 100644
--- a/usr/src/uts/common/io/mac/mac.c
+++ b/usr/src/uts/common/io/mac/mac.c
@@ -1719,6 +1719,8 @@ mac_header_cook(mac_handle_t mh, mblk_t *mp)
if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
if (DB_REF(mp) > 1) {
mblk_t *newmp = copymsg(mp);
+ if (newmp == NULL)
+ return (NULL);
freemsg(mp);
mp = newmp;
}
@@ -1735,6 +1737,8 @@ mac_header_uncook(mac_handle_t mh, mblk_t *mp)
if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
if (DB_REF(mp) > 1) {
mblk_t *newmp = copymsg(mp);
+ if (newmp == NULL)
+ return (NULL);
freemsg(mp);
mp = newmp;
}
diff --git a/usr/src/uts/common/io/pfmod.c b/usr/src/uts/common/io/pfmod.c
index 8f13b47877..9a7d66e995 100644
--- a/usr/src/uts/common/io/pfmod.c
+++ b/usr/src/uts/common/io/pfmod.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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -343,7 +342,9 @@ pfioctl(queue_t *wq, mblk_t *mp)
struct Pf_ext_packetfilt *upfp;
struct packetfilt *opfp;
ushort_t *fwp;
- int maxoff, arg;
+ int arg;
+ int maxoff = 0;
+ int maxoffreg = 0;
struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
int error;
@@ -406,7 +407,6 @@ pfioctl(queue_t *wq, mblk_t *mp)
* body to pull up. This code depends on the
* filter encoding.
*/
- maxoff = 0;
for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) {
arg = *fwp & ((1 << ENF_NBPA) - 1);
switch (arg) {
@@ -415,7 +415,16 @@ pfioctl(queue_t *wq, mblk_t *mp)
maxoff = arg;
break;
+ case ENF_LOAD_OFFSET:
+ /* Point to the offset */
+ fwp++;
+ if (*fwp > maxoffreg)
+ maxoffreg = *fwp;
+ break;
+
case ENF_PUSHLIT:
+ case ENF_BRTR:
+ case ENF_BRFL:
/* Skip over the literal. */
fwp++;
break;
@@ -426,6 +435,7 @@ pfioctl(queue_t *wq, mblk_t *mp)
case ENF_PUSHFF00:
case ENF_PUSH00FF:
case ENF_NOPUSH:
+ case ENF_POP:
break;
}
}
@@ -433,8 +443,7 @@ pfioctl(queue_t *wq, mblk_t *mp)
/*
* Convert word offset to length in bytes.
*/
- pfp->pf_PByteLen = (maxoff + 1) * sizeof (ushort_t);
-
+ pfp->pf_PByteLen = (maxoff + maxoffreg + 1) * sizeof (ushort_t);
miocack(wq, mp, 0, 0);
break;
@@ -448,23 +457,10 @@ pfioctl(queue_t *wq, mblk_t *mp)
/* #define INNERDEBUG 1 */
#ifdef INNERDEBUG
-#define enprintf(flags) if (enDebug & (flags)) printf
-
-/*
- * Symbolic definitions for enDebug flag bits
- * ENDBG_TRACE should be 1 because it is the most common
- * use in the code, and the compiler generates faster code
- * for testing the low bit in a word.
- */
-
-#define ENDBG_TRACE 1 /* trace most operations */
-#define ENDBG_DESQ 2 /* trace descriptor queues */
-#define ENDBG_INIT 4 /* initialization info */
-#define ENDBG_SCAV 8 /* scavenger operation */
-#define ENDBG_ABNORM 16 /* abnormal events */
-
-int enDebug = /* ENDBG_ABNORM | ENDBG_INIT | ENDBG_TRACE */ -1;
-#endif /* INNERDEBUG */
+#define enprintf(a) printf a
+#else
+#define enprintf(a)
+#endif
/*
* Apply the packet filter given by pfp to the packet given by
@@ -493,15 +489,13 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
ushort_t *fpe;
unsigned op;
unsigned arg;
+ unsigned offreg = 0;
ushort_t stack[ENMAXFILTERS+1];
fp = &pfp->pf_Filter[0];
fpe = pfp->pf_FilterEnd;
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("FilterPacket(%p, %p, %p, %p):\n",
- pp, pfp, fp, fpe);
-#endif
+ enprintf(("FilterPacket(%p, %p, %p, %p):\n", pp, pfp, fp, fpe));
/*
* Push TRUE on stack to start. The stack size is chosen such
@@ -525,14 +519,12 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
* if it were less than ENF_PUSHWORD before,
* it would now be huge.
*/
- if (arg < maxhdr)
- *--sp = pp->pd_hdr[arg];
- else if (arg < maxword)
- *--sp = pp->pd_body[arg - maxhdr];
+ if (arg + offreg < maxhdr)
+ *--sp = pp->pd_hdr[arg + offreg];
+ else if (arg + offreg < maxword)
+ *--sp = pp->pd_body[arg - maxhdr + offreg];
else {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>0(len)\n");
-#endif
+ enprintf(("=>0(len)\n"));
return (0);
}
break;
@@ -554,14 +546,42 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
case ENF_PUSH00FF:
*--sp = 0x00ff;
break;
+ case ENF_LOAD_OFFSET:
+ offreg = *fp++;
+ break;
+ case ENF_BRTR:
+ if (*sp != 0)
+ fp += *fp;
+ else
+ fp++;
+ if (fp >= fpe) {
+ enprintf(("BRTR: fp>=fpe\n"));
+ return (0);
+ }
+ break;
+ case ENF_BRFL:
+ if (*sp == 0)
+ fp += *fp;
+ else
+ fp++;
+ if (fp >= fpe) {
+ enprintf(("BRFL: fp>=fpe\n"));
+ return (0);
+ }
+ break;
+ case ENF_POP:
+ ++sp;
+ if (sp > &stack[ENMAXFILTERS]) {
+ enprintf(("stack underflow\n"));
+ return (0);
+ }
+ break;
case ENF_NOPUSH:
break;
}
if (sp < &stack[2]) { /* check stack overflow: small yellow zone */
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>0(--sp)\n");
-#endif
+ enprintf(("=>0(--sp)\n"));
return (0);
}
@@ -573,18 +593,14 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
* on stack to evaluate.
*/
if (sp > &stack[ENMAXFILTERS-2]) {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>0(sp++)\n");
-#endif
+ enprintf(("=>0(sp++)\n"));
return (0);
}
arg = *sp++;
switch (op) {
default:
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>0(def)\n");
-#endif
+ enprintf(("=>0(def)\n"));
return (0);
case opx(ENF_AND):
*sp &= arg;
@@ -618,40 +634,30 @@ FilterPacket(struct packdesc *pp, struct epacketfilt *pfp)
case opx(ENF_COR):
if (*sp++ == arg) {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
-#endif
+ enprintf(("=>COR %x\n", *sp));
return (1);
}
break;
case opx(ENF_CAND):
if (*sp++ != arg) {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>CAND %x\n", *sp);
-#endif
+ enprintf(("=>CAND %x\n", *sp));
return (0);
}
break;
case opx(ENF_CNOR):
if (*sp++ == arg) {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>COR %x\n", *sp);
-#endif
+ enprintf(("=>COR %x\n", *sp));
return (0);
}
break;
case opx(ENF_CNAND):
if (*sp++ != arg) {
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>CNAND %x\n", *sp);
-#endif
+ enprintf(("=>CNAND %x\n", *sp));
return (1);
}
break;
}
}
-#ifdef INNERDEBUG
- enprintf(ENDBG_TRACE)("=>%x\n", *sp);
-#endif
+ enprintf(("=>%x\n", *sp));
return (*sp);
}
diff --git a/usr/src/uts/common/io/rge/rge_rxtx.c b/usr/src/uts/common/io/rge/rge_rxtx.c
index 561800271d..3585da8135 100755
--- a/usr/src/uts/common/io/rge/rge_rxtx.c
+++ b/usr/src/uts/common/io/rge/rge_rxtx.c
@@ -276,7 +276,7 @@ rge_receive_packet(rge_t *rgep, uint32_t slot)
2 * ETHERADDRL);
mp->b_rptr -= VLAN_TAGSZ;
ehp = (struct ether_vlan_header *)mp->b_rptr;
- ehp->ether_tpid = htons(VLAN_TPID);
+ ehp->ether_tpid = htons(ETHERTYPE_VLAN);
ehp->ether_tci = htons(vtag);
rgep->stats.rbytes += VLAN_TAGSZ;
}
@@ -627,7 +627,7 @@ rge_send(rge_t *rgep, mblk_t *mp)
ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
tci = 0;
ehp = (struct ether_vlan_header *)mp->b_rptr;
- if (ehp->ether_tpid == htons(VLAN_TPID))
+ if (ehp->ether_tpid == htons(ETHERTYPE_VLAN))
tci = ntohs(ehp->ether_tci);
/*
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 2754405b01..df16a73f89 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -533,6 +533,7 @@ CHKHDRS= \
vfstab.h \
vgareg.h \
visual_io.h \
+ vlan.h \
vm.h \
vmem.h \
vmem_impl.h \
diff --git a/usr/src/uts/common/sys/dld_impl.h b/usr/src/uts/common/sys/dld_impl.h
index 6c1c3ade21..c3274aea0b 100644
--- a/usr/src/uts/common/sys/dld_impl.h
+++ b/usr/src/uts/common/sys/dld_impl.h
@@ -216,17 +216,16 @@ extern void dld_str_destroy(dld_str_t *);
extern int dld_str_attach(dld_str_t *, t_uscalar_t);
extern void dld_str_detach(dld_str_t *);
extern void dld_str_rx_raw(void *, mac_resource_handle_t,
- mblk_t *, size_t);
+ mblk_t *, mac_header_info_t *);
extern void dld_str_rx_fastpath(void *, mac_resource_handle_t,
- mblk_t *, size_t);
+ mblk_t *, mac_header_info_t *);
extern void dld_str_rx_unitdata(void *, mac_resource_handle_t,
- mblk_t *, size_t);
+ mblk_t *, mac_header_info_t *);
extern void dld_tx_flush(dld_str_t *);
extern void dld_tx_enqueue(dld_str_t *, mblk_t *, boolean_t);
extern void dld_str_notify_ind(dld_str_t *);
-
extern void str_mdata_fastpath_put(dld_str_t *, mblk_t *);
-extern void str_mdata_raw_put(dld_str_t *, mblk_t *);
+extern void dld_tx_single(dld_str_t *, mblk_t *);
/*
* dld_proto.c
diff --git a/usr/src/uts/common/sys/dls.h b/usr/src/uts/common/sys/dls.h
index 12f9a6a8a2..f43cb816de 100644
--- a/usr/src/uts/common/sys/dls.h
+++ b/usr/src/uts/common/sys/dls.h
@@ -91,10 +91,11 @@ extern int dls_multicst_add(dls_channel_t, const uint8_t *);
extern int dls_multicst_remove(dls_channel_t, const uint8_t *);
extern mblk_t *dls_header(dls_channel_t, const uint8_t *, uint16_t, uint_t,
- mblk_t *);
+ mblk_t **);
extern int dls_header_info(dls_channel_t, mblk_t *, mac_header_info_t *);
-typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *, size_t);
+typedef void (*dls_rx_t)(void *, mac_resource_handle_t, mblk_t *,
+ mac_header_info_t *);
extern void dls_rx_set(dls_channel_t, dls_rx_t, void *);
diff --git a/usr/src/uts/common/sys/dls_impl.h b/usr/src/uts/common/sys/dls_impl.h
index ad97fe72da..0b5dec3fb1 100644
--- a/usr/src/uts/common/sys/dls_impl.h
+++ b/usr/src/uts/common/sys/dls_impl.h
@@ -118,7 +118,7 @@ extern void dls_link_rele(dls_link_t *);
extern void dls_link_add(dls_link_t *, uint32_t, dls_impl_t *);
extern void dls_link_remove(dls_link_t *, dls_impl_t *);
extern int dls_link_header_info(dls_link_t *, mblk_t *,
- mac_header_info_t *, uint16_t *);
+ mac_header_info_t *);
extern int dls_mac_hold(dls_link_t *);
extern void dls_mac_rele(dls_link_t *);
@@ -138,7 +138,8 @@ extern void dls_init(void);
extern int dls_fini(void);
extern boolean_t dls_accept(dls_impl_t *, mac_header_info_t *,
dls_rx_t *, void **);
-extern boolean_t dls_accept_loopback(dls_impl_t *, dls_rx_t *, void **);
+extern boolean_t dls_accept_loopback(dls_impl_t *, mac_header_info_t *,
+ dls_rx_t *, void **);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/dls_soft_ring.h b/usr/src/uts/common/sys/dls_soft_ring.h
index 96a5e7ccc4..cc7365c9dc 100644
--- a/usr/src/uts/common/sys/dls_soft_ring.h
+++ b/usr/src/uts/common/sys/dls_soft_ring.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -16,10 +16,11 @@ extern "C" {
#include <sys/processor.h>
#include <sys/stream.h>
#include <sys/squeue.h>
+#include <sys/mac.h>
#define S_RING_NAMELEN 64
-typedef void (*s_ring_proc_t)(void *, void *, mblk_t *, size_t);
+typedef void (*s_ring_proc_t)(void *, void *, mblk_t *, mac_header_info_t *);
typedef struct soft_ring_s {
/* Keep the most used members 64bytes cache aligned */
@@ -85,8 +86,8 @@ extern void soft_ring_set_destroy(soft_ring_t **, int);
extern void soft_ring_process(soft_ring_t *, mblk_t *, uint8_t);
extern void soft_ring_bind(void *, processorid_t);
extern void soft_ring_unbind(void *);
-extern void dls_ether_soft_ring_fanout(void *,
- void *, mblk_t *, size_t);
+extern void dls_ether_soft_ring_fanout(void *, void *, mblk_t *,
+ mac_header_info_t *);
extern boolean_t dls_soft_ring_enable(dls_channel_t, dl_capab_dls_t *);
extern void dls_soft_ring_disable(dls_channel_t);
extern boolean_t dls_soft_ring_workers(dls_channel_t);
diff --git a/usr/src/uts/common/sys/ethernet.h b/usr/src/uts/common/sys/ethernet.h
index 3161f73608..9e35b2ec3d 100644
--- a/usr/src/uts/common/sys/ethernet.h
+++ b/usr/src/uts/common/sys/ethernet.h
@@ -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.
@@ -20,7 +19,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.
*/
@@ -71,6 +70,15 @@ struct ether_vlan_header {
ushort_t ether_type;
};
+/*
+ * The VLAN tag. Available for applications that cannot make use of struct
+ * ether_vlan_header because they assume Ethernet encapsulation.
+ */
+struct ether_vlan_extinfo {
+ ushort_t ether_tci;
+ ushort_t ether_type;
+};
+
#define ETHERTYPE_PUP (0x0200) /* PUP protocol */
#define ETHERTYPE_802_MIN (0x0600) /* Min valid ethernet type */
/* under IEEE 802.3 rules */
@@ -79,6 +87,7 @@ struct ether_vlan_header {
#define ETHERTYPE_REVARP (0x8035) /* Reverse ARP */
#define ETHERTYPE_AT (0x809b) /* AppleTalk protocol */
#define ETHERTYPE_AARP (0x80f3) /* AppleTalk ARP */
+#define ETHERTYPE_VLAN (0x8100) /* 802.1Q VLAN */
#define ETHERTYPE_IPV6 (0x86dd) /* IPv6 */
#define ETHERTYPE_SLOW (0x8809) /* Slow Protocol */
#define ETHERTYPE_PPPOED (0x8863) /* PPPoE Discovery Stage */
diff --git a/usr/src/uts/common/sys/gld.h b/usr/src/uts/common/sys/gld.h
index e42bb62f28..3f3c01848e 100644
--- a/usr/src/uts/common/sys/gld.h
+++ b/usr/src/uts/common/sys/gld.h
@@ -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.
@@ -20,7 +19,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.
*/
@@ -344,21 +343,27 @@ extern int gld_rsrv(queue_t *);
/*
* Macros to construct a TCI or VTAG. The user must ensure values are in
- * range. In particular, VID 0 is not a valid argument to these constructor
- * macros; when the VID is 0 (VLAN_VID_NONE), the whole VTAG should be 0
- * (VLAN_VTAG_NONE), not 0x81000000.
+ * range. Note that in the special case of priority tag, VLAN_VID_NONE
+ * is also a valid argument to these constructor macros.
*/
#define GLD_MAKE_TCI(pri, cfi, vid) (((pri) << VLAN_PRI_SHIFT) | \
((cfi) << VLAN_CFI_SHIFT) | \
((vid) << VLAN_VID_SHIFT))
-#define GLD_MAKE_VTAG(tci) ((VLAN_TPID << VLAN_TPID_SHIFT) | (tci))
+#define GLD_MAKE_VTAG(pri, cfi, vid) \
+ (((uint32_t)ETHERTYPE_VLAN << VLAN_TPID_SHIFT) | \
+ ((pri) << VLAN_PRI_SHIFT) | \
+ ((cfi) << VLAN_CFI_SHIFT) | \
+ ((vid) << VLAN_VID_SHIFT))
+
+#define GLD_TCI2VTAG(tci) \
+ (((uint32_t)ETHERTYPE_VLAN << VLAN_TPID_SHIFT) | (tci))
/*
* Macros to construct a prototype TCI/VTAG and then convert it to a real one
*/
#define GLD_MK_PTCI(cfi, vid) GLD_MAKE_TCI(VLAN_PRI_MAX, cfi, vid)
-#define GLD_MK_PTAG(cfi, vid) GLD_MAKE_VTAG(GLD_MK_PTCI(cfi, vid))
+#define GLD_MK_PTAG(cfi, vid) GLD_MAKE_VTAG(VLAN_PRI_MAX, cfi, vid)
#define GLD_MK_PMSK(pri) (((pri) << VLAN_PRI_SHIFT) | ~VLAN_PRI_MASK)
#define GLD_MK_VTAG(ptag, pri) ((ptag) & GLD_MK_PMSK(pri))
diff --git a/usr/src/uts/common/sys/gldpriv.h b/usr/src/uts/common/sys/gldpriv.h
index 6b864064b9..cbbb872232 100644
--- a/usr/src/uts/common/sys/gldpriv.h
+++ b/usr/src/uts/common/sys/gldpriv.h
@@ -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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -207,6 +206,7 @@ typedef struct pktinfo {
uint_t vid:12;
uint_t wasAccepted:1;
uint_t nosource:1;
+ uint_t isTagged:1;
uint_t macLen;
uint_t hdrLen;
uint_t pktLen;
@@ -246,9 +246,10 @@ typedef struct {
uint_t mac_type;
uint_t mtu_size;
int hdr_size;
- int (*interpreter)(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
+ int (*interpreter)(gld_mac_info_t *, mblk_t *, pktinfo_t *,
+ packet_flag_t);
void (*interpreter_mdt)(gld_mac_info_t *, mblk_t *,
- struct pdescinfo_s *, pktinfo_t *, int);
+ struct pdescinfo_s *, pktinfo_t *, mdt_packet_flag_t);
mblk_t *(*mkfastpath)(gld_t *, mblk_t *);
mblk_t *(*mkunitdata)(gld_t *, mblk_t *);
void (*init)(gld_mac_info_t *);
@@ -338,16 +339,16 @@ typedef struct gld_vlan {
gld_mac_info_t *gldv_mac;
queue_t *gldv_ipq;
queue_t *gldv_ipv6q;
- uint8_t gldv_ipq_flags;
struct gld *gldv_str_next; /* list of attached streams */
struct gld *gldv_str_prev;
kstat_t *gldv_kstatp;
struct gld_stats *gldv_stats;
+ /* The number of streams that are in promiscous mode */
+ uint_t gldv_nprom;
+ /* The number of streams that are interested in VLAN tagged packets. */
+ uint_t gldv_nvlan_sap;
} gld_vlan_t;
-#define IPQ_DISABLED 0x01
-#define IPQ_FORBIDDEN 0x02
-
#define VLAN_HASHSZ 23
/* Per-mac info used by GLD */
@@ -587,16 +588,6 @@ struct llc_snap_hdr {
#define LSAP_SNAP 0xaa /* SAP for SubNet Access Protocol */
#define CNTL_LLC_UI 0x03 /* un-numbered information packet */
-/* ============================ */
-/* Ethernet related definitions */
-/* ============================ */
-
-struct ether_mac_frm {
- mac_addr_t ether_dhost;
- mac_addr_t ether_shost;
- ushort_t ether_type;
-};
-
/* ======================== */
/* FDDI related definitions */
/* ======================== */
@@ -626,6 +617,42 @@ struct tr_mac_frm {
struct gld_ri tr_ri; /* Routing Information Field */
};
+/*
+ * Note that the pad field is used to save the value of tci.
+ */
+#define GLD_SAVE_MBLK_VTAG(mp, vtag) (DB_TCI(mp) = GLD_VTAG_TCI(vtag))
+#define GLD_CLEAR_MBLK_VTAG(mp) GLD_SAVE_MBLK_VTAG(mp, 0)
+#define GLD_GET_MBLK_VTAG(mp) GLD_TCI2VTAG(DB_TCI(mp))
+
+int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t);
+int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t);
+int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t);
+int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, packet_flag_t);
+void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *,
+ pktinfo_t *, mdt_packet_flag_t);
+
+mblk_t *gld_fastpath_ether(gld_t *, mblk_t *);
+mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *);
+mblk_t *gld_fastpath_tr(gld_t *, mblk_t *);
+mblk_t *gld_fastpath_ib(gld_t *, mblk_t *);
+
+mblk_t *gld_insert_vtag_ether(mblk_t *, uint32_t);
+
+mblk_t *gld_unitdata_ether(gld_t *, mblk_t *);
+mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *);
+mblk_t *gld_unitdata_tr(gld_t *, mblk_t *);
+mblk_t *gld_unitdata_ib(gld_t *, mblk_t *);
+
+void gld_init_ether(gld_mac_info_t *);
+void gld_init_fddi(gld_mac_info_t *);
+void gld_init_tr(gld_mac_info_t *);
+void gld_init_ib(gld_mac_info_t *);
+
+void gld_uninit_ether(gld_mac_info_t *);
+void gld_uninit_fddi(gld_mac_info_t *);
+void gld_uninit_tr(gld_mac_info_t *);
+void gld_uninit_ib(gld_mac_info_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h
index 729ecfaa9e..ee51f24423 100644
--- a/usr/src/uts/common/sys/mac.h
+++ b/usr/src/uts/common/sys/mac.h
@@ -28,6 +28,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <sys/types.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/stream.h>
@@ -350,6 +351,8 @@ typedef struct mac_header_info_s {
uint32_t mhi_origsap;
uint32_t mhi_bindsap;
mac_addrtype_t mhi_dsttype;
+ boolean_t mhi_istagged;
+ uint16_t mhi_tci;
} mac_header_info_t;
/*
diff --git a/usr/src/uts/common/sys/pfmod.h b/usr/src/uts/common/sys/pfmod.h
index 682f3ec03d..379847e3e6 100644
--- a/usr/src/uts/common/sys/pfmod.h
+++ b/usr/src/uts/common/sys/pfmod.h
@@ -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.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 1991,1997-1998 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ifndef _SYS_PFMOD_H
@@ -43,7 +42,7 @@ extern "C" {
#define PF_MAXFILTERS 2047 /* max short words for newpacketfilt */
/*
- * filter structure for SETF
+ * filter structure for SETF
*/
struct packetfilt {
uchar_t Pf_Priority; /* priority of filter */
@@ -61,34 +60,34 @@ struct Pf_ext_packetfilt {
};
/*
- * We now allow specification of up to MAXFILTERS (short) words of a filter
- * command list to be applied to incoming packets to determine if
- * those packets should be given to a particular open ethernet file.
- * Alternatively, PF_MAXFILTERS and Pf_ext_packetfilt structure can be
- * used in case even bigger filter command list is needed.
+ * We now allow specification of up to MAXFILTERS (short) words of a filter
+ * command list to be applied to incoming packets to determine if
+ * those packets should be given to a particular open ethernet file.
+ * Alternatively, PF_MAXFILTERS and Pf_ext_packetfilt structure can be
+ * used in case even bigger filter command list is needed.
*
- * In this context, "word" means a short (16-bit) integer.
+ * In this context, "word" means a short (16-bit) integer.
*
- * Each open enet file specifies the filter command list via ioctl.
- * Each filter command list specifies a sequence of actions that leaves a
- * boolean value on the top of an internal stack. Each word of the
- * command list specifies an action from the set {PUSHLIT, PUSHZERO,
- * PUSHWORD+N} which respectively push the next word of the filter, zero,
- * or word N of the incoming packet on the stack, and a binary operator
- * from the set {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the
- * top two elements of the stack and replaces them with its result. The
- * special action NOPUSH and the special operator NOP can be used to only
- * perform the binary operation or to only push a value on the stack.
+ * The filter command list is specified using ioctl(). Each filter command
+ * list specifies a sequence of actions that leaves a boolean value on the
+ * top of an internal stack. There is also an offset register which is
+ * initialized to zero. Each word of the command list specifies an action
+ * from the set {PUSHLIT, PUSHZERO, PUSHWORD+N, LOAD_OFFSET, BRTR, BRFL, POP}
+ * (see #defines below for definitions), and a binary operator from the set
+ * {EQ, LT, LE, GT, GE, AND, OR, XOR} which operates on the top two elements
+ * of the stack and replaces them with its result. The special action NOPUSH
+ * and the special operator NOP can be used to only perform the binary
+ * operation or to only push a value on the stack.
*
- * If the final value of the filter operation is true, then the packet is
- * accepted for the open file which specified the filter.
+ * If the final value of the filter operation is true, then the packet is
+ * accepted for the open file which specified the filter.
*/
-/* these must sum to sizeof (ushort_t)! */
+/* these must sum to sizeof (ushort_t)! */
#define ENF_NBPA 10 /* # bits / action */
#define ENF_NBPO 6 /* # bits / operator */
-/* binary operators */
+/* binary operators */
#define ENF_NOP (0 << ENF_NBPA)
#define ENF_EQ (1 << ENF_NBPA)
#define ENF_LT (2 << ENF_NBPA)
@@ -104,14 +103,18 @@ struct Pf_ext_packetfilt {
#define ENF_CNAND (12 << ENF_NBPA)
#define ENF_NEQ (13 << ENF_NBPA)
-/* stack actions */
+/* stack actions */
#define ENF_NOPUSH 0
-#define ENF_PUSHLIT 1
-#define ENF_PUSHZERO 2
-#define ENF_PUSHONE 3
-#define ENF_PUSHFFFF 4
-#define ENF_PUSHFF00 5
-#define ENF_PUSH00FF 6
+#define ENF_PUSHLIT 1 /* Push the next word on the stack */
+#define ENF_PUSHZERO 2 /* Push 0 on the stack */
+#define ENF_PUSHONE 3 /* Push 1 on the stack */
+#define ENF_PUSHFFFF 4 /* Push 0xffff on the stack */
+#define ENF_PUSHFF00 5 /* Push 0xff00 on the stack */
+#define ENF_PUSH00FF 6 /* Push 0x00ff on the stack */
+#define ENF_LOAD_OFFSET 7 /* Load the next word into the offset register */
+#define ENF_BRTR 8 /* Branch if the stack's top element is true */
+#define ENF_BRFL 9 /* Branch if the stack's top element is false */
+#define ENF_POP 10 /* Pop the top element from the stack */
#define ENF_PUSHWORD 16
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h
index 6fd38f724a..cb5a92b7d3 100644
--- a/usr/src/uts/common/sys/stream.h
+++ b/usr/src/uts/common/sys/stream.h
@@ -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.
@@ -20,7 +19,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.
*/
@@ -357,6 +356,10 @@ typedef struct datab {
#define DB_CRED(mp) ((mp)->b_datap->db_credp)
#define DB_CREDDEF(mp, cr) (DB_CRED(mp) != NULL ? DB_CRED(mp) : (cr))
#define DB_FTHDR(mp) ((mp)->b_datap->db_fthdr)
+/*
+ * Used by GLDv2 to store the TCI information.
+ */
+#define DB_TCI(mp) ((mp)->b_datap->db_struioun.cksum.pad)
/*
* Message block descriptor
diff --git a/usr/src/uts/common/sys/vlan.h b/usr/src/uts/common/sys/vlan.h
index eba8ea3c4e..2a4e4c8ef0 100644
--- a/usr/src/uts/common/sys/vlan.h
+++ b/usr/src/uts/common/sys/vlan.h
@@ -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.
@@ -20,7 +19,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.
*/
@@ -39,8 +38,6 @@ extern "C" {
#define VLAN_TAGSZ 4
-#define VLAN_TPID 0x8100u
-
#define VLAN_ID_MASK 0x0fffu
#define VLAN_ID_SIZE 12
#define VLAN_ID_SHIFT 0
@@ -69,6 +66,12 @@ extern "C" {
#define VLAN_CFI(tci) (((tci) >> VLAN_CFI_SHIFT) & VLAN_CFI_MASK)
#define VLAN_ID(tci) (((tci) >> VLAN_ID_SHIFT) & VLAN_ID_MASK)
+#define VLAN_BAND_MAP 32
+
+#define VLAN_MBLKPRI(mp) \
+ ((((mp)->b_band) / VLAN_BAND_MAP) > 7 ? 0 : \
+ (((mp)->b_band) / VLAN_BAND_MAP))
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/sun4u/io/dmfe/dmfe_main.c b/usr/src/uts/sun4u/io/dmfe/dmfe_main.c
index 20e616f24d..c8c1d479dd 100644
--- a/usr/src/uts/sun4u/io/dmfe/dmfe_main.c
+++ b/usr/src/uts/sun4u/io/dmfe/dmfe_main.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.
@@ -20,7 +19,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.
*/
@@ -760,7 +759,8 @@ dmfe_getp(dmfe_t *dmfep)
#if !defined(VLAN_VID_NONE)
bcopy(rxb, dp, packet_length);
#else
- if (ehp->ether_type != VLAN_TPID || gld_recv_tagged == NULL) {
+ if (ehp->ether_type != ETHERTYPE_VLAN ||
+ gld_recv_tagged == NULL) {
/*
* An untagged packet (or, there's no runtime support
* for tagging so we treat all packets as untagged).