diff options
Diffstat (limited to 'usr/src')
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). |