xref: /onnv-gate/usr/src/uts/common/io/gldutil.c (revision 2760:38f12e308f6d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2760Sdg199075  * Common Development and Distribution License (the "License").
6*2760Sdg199075  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
21*2760Sdg199075  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * gld - Generic LAN Driver
290Sstevel@tonic-gate  * media dependent routines
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/errno.h>
340Sstevel@tonic-gate #include <sys/stropts.h>
350Sstevel@tonic-gate #include <sys/stream.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/stat.h>
380Sstevel@tonic-gate #include <sys/modctl.h>
390Sstevel@tonic-gate #include <sys/kstat.h>
400Sstevel@tonic-gate #include <sys/debug.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <sys/byteorder.h>
430Sstevel@tonic-gate #include <sys/strsun.h>
440Sstevel@tonic-gate #include <sys/dlpi.h>
450Sstevel@tonic-gate #include <sys/ethernet.h>
460Sstevel@tonic-gate #include <sys/multidata.h>
470Sstevel@tonic-gate #include <sys/gld.h>
480Sstevel@tonic-gate #include <sys/gldpriv.h>
490Sstevel@tonic-gate #include <sys/ddi.h>
500Sstevel@tonic-gate #include <sys/sunddi.h>
510Sstevel@tonic-gate #include <sys/sysmacros.h>
520Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
530Sstevel@tonic-gate #include <sys/pattr.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	DLSAPLENGTH(macinfo) \
560Sstevel@tonic-gate 	((macinfo)->gldm_addrlen + ABS((macinfo)->gldm_saplen))
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #ifdef GLD_DEBUG
590Sstevel@tonic-gate extern int gld_debug;
600Sstevel@tonic-gate #endif
610Sstevel@tonic-gate 
620Sstevel@tonic-gate extern void gld_bitrevcopy(caddr_t src, caddr_t target, size_t n);
630Sstevel@tonic-gate extern char *gld_macaddr_sprintf(char *, unsigned char *, int);
640Sstevel@tonic-gate extern gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
650Sstevel@tonic-gate extern uint32_t gld_global_options;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static struct	llc_snap_hdr llc_snap_def = {
680Sstevel@tonic-gate 	LSAP_SNAP,		/* DLSAP 0xaa */
690Sstevel@tonic-gate 	LSAP_SNAP,		/* SLSAP 0xaa */
700Sstevel@tonic-gate 	CNTL_LLC_UI,		/* Control 0x03 */
710Sstevel@tonic-gate 	0x00, 0x00, 0x00,	/* Org[3] */
720Sstevel@tonic-gate 	0x00			/* Type */
730Sstevel@tonic-gate };
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #define	ISETHERTYPE(snaphdr) \
760Sstevel@tonic-gate 	(snaphdr->d_lsap == LSAP_SNAP && \
770Sstevel@tonic-gate 	snaphdr->s_lsap == LSAP_SNAP && \
780Sstevel@tonic-gate 	snaphdr->control == CNTL_LLC_UI && \
790Sstevel@tonic-gate 	snaphdr->org[0] == 0 && \
800Sstevel@tonic-gate 	snaphdr->org[1] == 0 && \
810Sstevel@tonic-gate 	snaphdr->org[2] == 0)
820Sstevel@tonic-gate 
830Sstevel@tonic-gate /* ======== */
840Sstevel@tonic-gate /* Ethernet */
850Sstevel@tonic-gate /* ======== */
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static mac_addr_t ether_broadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
880Sstevel@tonic-gate 
890Sstevel@tonic-gate void
gld_init_ether(gld_mac_info_t * macinfo)900Sstevel@tonic-gate gld_init_ether(gld_mac_info_t *macinfo)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	struct gldkstats *sp =
930Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/* Assumptions we make for this medium */
960Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_ETHER);
970Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
980Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
990Sstevel@tonic-gate #ifndef	lint
100*2760Sdg199075 	ASSERT(sizeof (struct ether_header) == 14);
1010Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	kstat_named_init(&sp->glds_frame, "align_errors", KSTAT_DATA_ULONG);
1050Sstevel@tonic-gate 	kstat_named_init(&sp->glds_crc, "fcs_errors", KSTAT_DATA_ULONG);
1060Sstevel@tonic-gate 	kstat_named_init(&sp->glds_collisions, "collisions", KSTAT_DATA_ULONG);
1070Sstevel@tonic-gate 	kstat_named_init(&sp->glds_nocarrier, "carrier_errors",
1080Sstevel@tonic-gate 	    KSTAT_DATA_ULONG);
1090Sstevel@tonic-gate 	kstat_named_init(&sp->glds_defer, "defer_xmts", KSTAT_DATA_ULONG);
1100Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtlatecoll, "tx_late_collisions",
1110Sstevel@tonic-gate 					KSTAT_DATA_ULONG);
1120Sstevel@tonic-gate 	kstat_named_init(&sp->glds_short, "runt_errors", KSTAT_DATA_ULONG);
1130Sstevel@tonic-gate 	kstat_named_init(&sp->glds_excoll, "ex_collisions", KSTAT_DATA_ULONG);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/*
1160Sstevel@tonic-gate 	 * only initialize the new statistics if the driver
1170Sstevel@tonic-gate 	 * knows about them.
1180Sstevel@tonic-gate 	 */
1190Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION_200)
1200Sstevel@tonic-gate 		return;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_first_coll,
1230Sstevel@tonic-gate 	    "first_collisions", KSTAT_DATA_UINT32);
1240Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_multi_coll,
1250Sstevel@tonic-gate 	    "multi_collisions", KSTAT_DATA_UINT32);
1260Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_sqe_error,
1270Sstevel@tonic-gate 	    "sqe_errors", KSTAT_DATA_UINT32);
1280Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_mac_xmt_error,
1290Sstevel@tonic-gate 	    "macxmt_errors", KSTAT_DATA_UINT32);
1300Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_mac_rcv_error,
1310Sstevel@tonic-gate 	    "macrcv_errors", KSTAT_DATA_UINT32);
1320Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_frame_too_long,
1330Sstevel@tonic-gate 	    "toolong_errors", KSTAT_DATA_UINT32);
1340Sstevel@tonic-gate 	kstat_named_init(&sp->glds_duplex, "duplex", KSTAT_DATA_CHAR);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /*ARGSUSED*/
1380Sstevel@tonic-gate void
gld_uninit_ether(gld_mac_info_t * macinfo)1390Sstevel@tonic-gate gld_uninit_ether(gld_mac_info_t *macinfo)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
gld_interpret_ether(gld_mac_info_t * macinfo,mblk_t * mp,pktinfo_t * pktinfo,packet_flag_t flags)1440Sstevel@tonic-gate gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
1450Sstevel@tonic-gate     packet_flag_t flags)
1460Sstevel@tonic-gate {
147*2760Sdg199075 	struct ether_header *mh;
1480Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1490Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
150*2760Sdg199075 	mblk_t *pmp = NULL, *savemp = mp;
1510Sstevel@tonic-gate 	unsigned short typelen;
152*2760Sdg199075 	int ret = 0;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * Quickly handle receive fastpath for IPQ hack.
1560Sstevel@tonic-gate 	 */
1570Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
1580Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
1590Sstevel@tonic-gate 		/*
1600Sstevel@tonic-gate 		 * Check whether the header is contiguous, which
1610Sstevel@tonic-gate 		 * also implicitly makes sure the packet is big enough.
1620Sstevel@tonic-gate 		 */
163*2760Sdg199075 		if (MBLKL(mp) < sizeof (struct ether_header))
1640Sstevel@tonic-gate 			return (-1);
165*2760Sdg199075 		mh = (struct ether_header *)mp->b_rptr;
1660Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(mh->ether_type);
167*2760Sdg199075 		pktinfo->isForMe = mac_eq(&mh->ether_dhost,
1680Sstevel@tonic-gate 		    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
169*2760Sdg199075 		pktinfo->macLen = sizeof (struct ether_header);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 		return (0);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
179*2760Sdg199075 	if (pktinfo->pktLen < sizeof (struct ether_header))
1800Sstevel@tonic-gate 		return (-1);
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
183*2760Sdg199075 	if (MBLKL(mp) < sizeof (struct ether_header)) {
1840Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
1850Sstevel@tonic-gate #ifdef GLD_DEBUG
1860Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1870Sstevel@tonic-gate 				cmn_err(CE_WARN,
1880Sstevel@tonic-gate 				    "GLD: interpret_ether cannot msgpullup");
1890Sstevel@tonic-gate #endif
1900Sstevel@tonic-gate 			return (-1);
1910Sstevel@tonic-gate 		}
1920Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
195*2760Sdg199075 	mh = (struct ether_header *)mp->b_rptr;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
198*2760Sdg199075 	if (mac_eq(&mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen))
1990Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
200*2760Sdg199075 	else if (mh->ether_dhost.ether_addr_octet[0] & 1)
2010Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	typelen = REF_NET_USHORT(mh->ether_type);
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * If the hardware is capable of VLAN tag insertion
2060Sstevel@tonic-gate 	 * strip out the VLAN tag info. Knowing hardware is
2070Sstevel@tonic-gate 	 * capable of VLAN can be established by the presance
2080Sstevel@tonic-gate 	 * of non null 'macinfo->gldm_send_tagged'.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	if (flags == GLD_TX) {
211*2760Sdg199075 		if ((typelen == ETHERTYPE_VLAN) &&
212*2760Sdg199075 		    (macinfo->gldm_send_tagged != NULL)) {
213*2760Sdg199075 			struct ether_vlan_header *evhp;
214*2760Sdg199075 			uint16_t tci;
215*2760Sdg199075 
216*2760Sdg199075 			if ((MBLKL(mp) < sizeof (struct ether_vlan_header)) &&
217*2760Sdg199075 			    (pullupmsg(mp, sizeof (struct ether_vlan_header))
218*2760Sdg199075 			    == 0)) {
219*2760Sdg199075 				ret = -1;
220*2760Sdg199075 				goto out;
221*2760Sdg199075 			}
222*2760Sdg199075 			evhp = (struct ether_vlan_header *)mp->b_rptr;
223*2760Sdg199075 			tci = REF_NET_USHORT(evhp->ether_tci);
224*2760Sdg199075 
225*2760Sdg199075 			/*
226*2760Sdg199075 			 * We don't allow the VID and priority are both zero.
227*2760Sdg199075 			 */
228*2760Sdg199075 			if ((GLD_VTAG_PRI((int32_t)tci) == 0 &&
229*2760Sdg199075 			    GLD_VTAG_VID((int32_t)tci) == VLAN_VID_NONE) ||
230*2760Sdg199075 			    (GLD_VTAG_CFI((uint32_t)tci)) != VLAN_CFI_ETHER) {
231*2760Sdg199075 				ret = -1;
232*2760Sdg199075 				goto out;
233*2760Sdg199075 			}
234*2760Sdg199075 
235*2760Sdg199075 			/*
236*2760Sdg199075 			 * Remember the VTAG info in order to reinsert it,
237*2760Sdg199075 			 * Then strip the tag. This is required because some
238*2760Sdg199075 			 * drivers do not allow the size of message (passed
239*2760Sdg199075 			 * by the gldm_send_tagged() function) to be greater
240*2760Sdg199075 			 * than ETHERMAX.
241*2760Sdg199075 			 */
242*2760Sdg199075 			GLD_SAVE_MBLK_VTAG(savemp, GLD_TCI2VTAG(tci));
243*2760Sdg199075 			ovbcopy(mp->b_rptr, mp->b_rptr + VTAG_SIZE,
244*2760Sdg199075 			    2 * ETHERADDRL);
2450Sstevel@tonic-gate 			mp->b_rptr += VTAG_SIZE;
2460Sstevel@tonic-gate 		}
2470Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * Deal with the mac header
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 
256*2760Sdg199075 	mac_copy(&mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
257*2760Sdg199075 	mac_copy(&mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
2600Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
2610Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
2620Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
2630Sstevel@tonic-gate 
264*2760Sdg199075 	pktinfo->macLen = sizeof (struct ether_header);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if (typelen > ETHERMTU) {
2670Sstevel@tonic-gate 		pktinfo->ethertype = typelen; /* use type interpretation */
2680Sstevel@tonic-gate 		goto out;
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/*
2720Sstevel@tonic-gate 	 * Packet is 802.3 so the ether type/length field
2730Sstevel@tonic-gate 	 * specifies the number of bytes that should be present
2740Sstevel@tonic-gate 	 * in the data field.  Additional bytes are padding, and
2750Sstevel@tonic-gate 	 * should be removed
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	{
2780Sstevel@tonic-gate 	int delta = pktinfo->pktLen -
279*2760Sdg199075 	    (sizeof (struct ether_header) + typelen);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (delta > 0 && adjmsg(mp, -delta))
2820Sstevel@tonic-gate 		pktinfo->pktLen -= delta;
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the LLC
2870Sstevel@tonic-gate 	 * header exists, and that both it and any SNAP header are contiguous.
2880Sstevel@tonic-gate 	 */
2890Sstevel@tonic-gate 	if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
2900Sstevel@tonic-gate 		goto out;	/* LLC hdr should have been there! */
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	pktinfo->isLLC = 1;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (gld_global_options & GLD_OPT_NO_ETHRXSNAP ||
295*2760Sdg199075 	    pktinfo->pktLen <  pktinfo->macLen + LLC_SNAP_HDR_LEN)
2960Sstevel@tonic-gate 		goto out;
2970Sstevel@tonic-gate 
298*2760Sdg199075 	if (MBLKL(mp) < sizeof (struct ether_header) + LLC_SNAP_HDR_LEN &&
2990Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
3000Sstevel@tonic-gate 		/*
3010Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
3020Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
3030Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
3040Sstevel@tonic-gate 		 */
3050Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
3060Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
3070Sstevel@tonic-gate #ifdef GLD_DEBUG
3080Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
3090Sstevel@tonic-gate 				cmn_err(CE_WARN,
3100Sstevel@tonic-gate 				    "GLD: interpret_ether cannot msgpullup2");
3110Sstevel@tonic-gate #endif
3120Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * Check SAP/SNAP information for EtherType.
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
3220Sstevel@tonic-gate 	if (ISETHERTYPE(snaphdr)) {
3230Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
3240Sstevel@tonic-gate 		pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate out:
3270Sstevel@tonic-gate 	if (pmp != NULL)
3280Sstevel@tonic-gate 		freemsg(pmp);
3290Sstevel@tonic-gate 
330*2760Sdg199075 	return (ret);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate mblk_t *
gld_unitdata_ether(gld_t * gld,mblk_t * mp)3340Sstevel@tonic-gate gld_unitdata_ether(gld_t *gld, mblk_t *mp)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
3370Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
3380Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
3390Sstevel@tonic-gate 	mac_addr_t dhost;
3400Sstevel@tonic-gate 	unsigned short typelen;
3410Sstevel@tonic-gate 	mblk_t *nmp;
342*2760Sdg199075 	struct ether_header *mh;
3430Sstevel@tonic-gate 	int hdrlen;
3440Sstevel@tonic-gate 	uint32_t vptag;
3450Sstevel@tonic-gate 	gld_vlan_t *gld_vlan;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	ASSERT(macinfo);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
3500Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
3530Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
3540Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
3550Sstevel@tonic-gate 		typelen = REF_HOST_USHORT(gldp->glda_sap);
3560Sstevel@tonic-gate 	else
3570Sstevel@tonic-gate 		typelen = gld->gld_sap;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/*
3600Sstevel@tonic-gate 	 * We take values less than or equal to ETHERMTU to mean that the
3610Sstevel@tonic-gate 	 * packet should not have an encoded EtherType and so we use the
3620Sstevel@tonic-gate 	 * IEEE 802.3 length interpretation of the type/length field.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	if (typelen <= ETHERMTU)
3650Sstevel@tonic-gate 		typelen = msgdsize(mp);
3660Sstevel@tonic-gate 
367*2760Sdg199075 	hdrlen = sizeof (struct ether_header);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	/*
3700Sstevel@tonic-gate 	 * Check to see if VLAN is enabled on this stream
3710Sstevel@tonic-gate 	 * if so then make the header bigger to hold a clone
3720Sstevel@tonic-gate 	 * vlan tag.
3730Sstevel@tonic-gate 	 */
3740Sstevel@tonic-gate 	gld_vlan = (gld_vlan_t *)gld->gld_vlan;
3750Sstevel@tonic-gate 	if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
3760Sstevel@tonic-gate 		hdrlen += VTAG_SIZE;
3770Sstevel@tonic-gate 		vptag = gld_vlan->gldv_ptag;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
3810Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
3820Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
3830Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
3840Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
3850Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
3860Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
3870Sstevel@tonic-gate 		nmp = mp;
3880Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
3890Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
3900Sstevel@tonic-gate 	} else {
3910Sstevel@tonic-gate 		/* we need to allocate one */
3920Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
3930Sstevel@tonic-gate 			return (NULL);
3940Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
3950Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
3960Sstevel@tonic-gate 		freeb(mp);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (typelen);
4020Sstevel@tonic-gate 	SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
403*2760Sdg199075 	if (hdrlen > sizeof (struct ether_header)) {
4040Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
4050Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
4060Sstevel@tonic-gate 		vptag >>= 16;
4070Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
4080Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 	nmp->b_rptr -= (ETHERADDRL * 2);
411*2760Sdg199075 	mh = (struct ether_header *)nmp->b_rptr;
412*2760Sdg199075 	mac_copy(dhost, &mh->ether_dhost, macinfo->gldm_addrlen);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
4160Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
419*2760Sdg199075 	    &mh->ether_shost, macinfo->gldm_addrlen);
420*2760Sdg199075 
421*2760Sdg199075 	return (nmp);
422*2760Sdg199075 }
423*2760Sdg199075 
424*2760Sdg199075 /*
425*2760Sdg199075  * Insert the VLAN tag into the packet. The packet now is an Ethernet header
426*2760Sdg199075  * without VLAN tag information.
427*2760Sdg199075  */
428*2760Sdg199075 mblk_t *
gld_insert_vtag_ether(mblk_t * mp,uint32_t vtag)429*2760Sdg199075 gld_insert_vtag_ether(mblk_t *mp, uint32_t vtag)
430*2760Sdg199075 {
431*2760Sdg199075 	struct ether_vlan_header *evhp;
432*2760Sdg199075 	struct ether_header *ehp;
433*2760Sdg199075 	mblk_t *nmp;
434*2760Sdg199075 
435*2760Sdg199075 	if (vtag == VLAN_VID_NONE)
436*2760Sdg199075 		return (mp);
4370Sstevel@tonic-gate 
438*2760Sdg199075 	if (DB_REF(mp) == 1 && MBLKHEAD(mp) >= VTAG_SIZE) {
439*2760Sdg199075 		/* it fits at the beginning of the message block */
440*2760Sdg199075 		nmp = mp;
441*2760Sdg199075 		ovbcopy(nmp->b_rptr, nmp->b_rptr - VTAG_SIZE, 2 * ETHERADDRL);
442*2760Sdg199075 		nmp->b_rptr -= VTAG_SIZE;
443*2760Sdg199075 		evhp = (struct ether_vlan_header *)nmp->b_rptr;
444*2760Sdg199075 	} else {
445*2760Sdg199075 		/* we need to allocate one */
446*2760Sdg199075 		if ((nmp = allocb(sizeof (struct ether_vlan_header),
447*2760Sdg199075 		    BPRI_MED)) == NULL) {
448*2760Sdg199075 			return (NULL);
449*2760Sdg199075 		}
450*2760Sdg199075 		nmp->b_wptr += sizeof (struct ether_vlan_header);
451*2760Sdg199075 
452*2760Sdg199075 		/* transfer the ether_header fields */
453*2760Sdg199075 		evhp = (struct ether_vlan_header *)nmp->b_rptr;
454*2760Sdg199075 		ehp = (struct ether_header *)mp->b_rptr;
455*2760Sdg199075 		mac_copy(&ehp->ether_dhost, &evhp->ether_dhost, ETHERADDRL);
456*2760Sdg199075 		mac_copy(&ehp->ether_shost, &evhp->ether_shost, ETHERADDRL);
457*2760Sdg199075 		bcopy(&ehp->ether_type, &evhp->ether_type, sizeof (uint16_t));
458*2760Sdg199075 
459*2760Sdg199075 		/* offset the mp of the MAC header length. */
460*2760Sdg199075 		mp->b_rptr += sizeof (struct ether_header);
461*2760Sdg199075 		if (MBLKL(mp) == 0) {
462*2760Sdg199075 			nmp->b_cont = mp->b_cont;
463*2760Sdg199075 			freeb(mp);
464*2760Sdg199075 		} else {
465*2760Sdg199075 			nmp->b_cont = mp;
466*2760Sdg199075 		}
467*2760Sdg199075 	}
468*2760Sdg199075 
469*2760Sdg199075 	SET_NET_USHORT(evhp->ether_tci, vtag);
470*2760Sdg199075 	vtag >>= 16;
471*2760Sdg199075 	SET_NET_USHORT(evhp->ether_tpid, vtag);
4720Sstevel@tonic-gate 	return (nmp);
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate mblk_t *
gld_fastpath_ether(gld_t * gld,mblk_t * mp)4760Sstevel@tonic-gate gld_fastpath_ether(gld_t *gld, mblk_t *mp)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
4790Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
4800Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
4810Sstevel@tonic-gate 	unsigned short typelen;
4820Sstevel@tonic-gate 	mblk_t *nmp;
483*2760Sdg199075 	struct ether_header *mh;
4840Sstevel@tonic-gate 	int hdrlen;
4850Sstevel@tonic-gate 	uint32_t vptag;
4860Sstevel@tonic-gate 	gld_vlan_t *gld_vlan;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	ASSERT(macinfo);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
4910Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
4920Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
4930Sstevel@tonic-gate 		typelen = REF_HOST_USHORT(gldp->glda_sap);
4940Sstevel@tonic-gate 	else
4950Sstevel@tonic-gate 		typelen = gld->gld_sap;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * We only do fast-path for EtherType encoding because this is the only
4990Sstevel@tonic-gate 	 * case where the media header will be consistent from packet to packet.
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	if (typelen <= ETHERMTU)
5020Sstevel@tonic-gate 		return (NULL);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/*
5050Sstevel@tonic-gate 	 * Initialize the fast path header to include the
5060Sstevel@tonic-gate 	 * basic source address information and type field.
5070Sstevel@tonic-gate 	 */
508*2760Sdg199075 	hdrlen = sizeof (struct ether_header);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	/*
5110Sstevel@tonic-gate 	 * Check to see if VLAN is enabled on this stream
5120Sstevel@tonic-gate 	 * if so then make the header bigger to hold a clone
5130Sstevel@tonic-gate 	 * vlan tag.
5140Sstevel@tonic-gate 	 */
5150Sstevel@tonic-gate 	gld_vlan = (gld_vlan_t *)gld->gld_vlan;
5160Sstevel@tonic-gate 	if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
5170Sstevel@tonic-gate 		hdrlen += VTAG_SIZE;
5180Sstevel@tonic-gate 		vptag = gld_vlan->gldv_ptag;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
5220Sstevel@tonic-gate 		return (NULL);
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (typelen);
5290Sstevel@tonic-gate 	SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	/*
5320Sstevel@tonic-gate 	 * If the header is for a VLAN stream, then add
5330Sstevel@tonic-gate 	 * in the VLAN tag to the clone header.
5340Sstevel@tonic-gate 	 */
535*2760Sdg199075 	if (hdrlen > sizeof (struct ether_header)) {
5360Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
5370Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
5380Sstevel@tonic-gate 		vptag >>= 16;
5390Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
5400Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 	nmp->b_rptr -= (ETHERADDRL * 2);
543*2760Sdg199075 	mh = (struct ether_header *)nmp->b_rptr;
544*2760Sdg199075 	mac_copy(gldp->glda_addr, &mh->ether_dhost, macinfo->gldm_addrlen);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
5470Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
548*2760Sdg199075 	    &mh->ether_shost, macinfo->gldm_addrlen);
5490Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	return (nmp);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /* == */
5550Sstevel@tonic-gate /* IB */
5560Sstevel@tonic-gate /* == */
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate void
gld_init_ib(gld_mac_info_t * macinfo)5590Sstevel@tonic-gate gld_init_ib(gld_mac_info_t *macinfo)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	/*
5620Sstevel@tonic-gate 	 * Currently, the generic stats maintained by GLD is
5630Sstevel@tonic-gate 	 * sufficient for IPoIB.
5640Sstevel@tonic-gate 	 */
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	/* Assumptions we make for this medium */
5670Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_IB);
5680Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == IPOIB_ADDRL);
5690Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /* ARGSUSED */
5730Sstevel@tonic-gate void
gld_uninit_ib(gld_mac_info_t * macinfo)5740Sstevel@tonic-gate gld_uninit_ib(gld_mac_info_t *macinfo)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate }
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate /*
5790Sstevel@tonic-gate  * The packet format sent to the driver is:
5800Sstevel@tonic-gate  * IPOIB_ADDRL bytes dest addr :: 2b sap :: 2b 0s :: data
5810Sstevel@tonic-gate  * The packet format received from the driver is:
5820Sstevel@tonic-gate  * IPOIB_GRH_SIZE bytes pseudo GRH :: 2b sap :: 2b 0s :: data.
5830Sstevel@tonic-gate  */
5840Sstevel@tonic-gate int
gld_interpret_ib(gld_mac_info_t * macinfo,mblk_t * mp,pktinfo_t * pktinfo,packet_flag_t flags)5850Sstevel@tonic-gate gld_interpret_ib(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
5860Sstevel@tonic-gate     packet_flag_t flags)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate 	ipoib_pgrh_t *grh;
5890Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp;
5900Sstevel@tonic-gate 	mblk_t *pmp = NULL;
5910Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * Quickly handle receive fastpath for IPQ hack.
5950Sstevel@tonic-gate 	 */
5960Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
5970Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp) - IPOIB_GRH_SIZE;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		/*
6000Sstevel@tonic-gate 		 * Check whether the header is contiguous, which
6010Sstevel@tonic-gate 		 * also implicitly makes sure the packet is big enough.
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
6040Sstevel@tonic-gate 			return (-1);
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 		/*
6070Sstevel@tonic-gate 		 * Almost all times, unicast will not have
6080Sstevel@tonic-gate 		 * a valid pgrh; quickly identify and ask for
6090Sstevel@tonic-gate 		 * IPQ hack optimization only in that case.
6100Sstevel@tonic-gate 		 */
6110Sstevel@tonic-gate 		grh = (ipoib_pgrh_t *)mp->b_rptr;
6120Sstevel@tonic-gate 		if (grh->ipoib_vertcflow == 0) {
6130Sstevel@tonic-gate 			struct ipoib_header *ihp = (struct ipoib_header *)
6140Sstevel@tonic-gate 			    (mp->b_rptr + IPOIB_GRH_SIZE);
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 			pktinfo->isForMe = 1;
6170Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(ihp->ipoib_type);
6180Sstevel@tonic-gate 			pktinfo->macLen = IPOIB_GRH_SIZE + IPOIB_HDRSIZE;
6190Sstevel@tonic-gate 			return (0);
6200Sstevel@tonic-gate 		} else {
6210Sstevel@tonic-gate 			return (-1);
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	/*
6260Sstevel@tonic-gate 	 * Handle the GLD_TX, GLD_RX, GLD_RXLOOP cases now.
6270Sstevel@tonic-gate 	 */
6280Sstevel@tonic-gate 	ASSERT(flags != GLD_RXQUICK);
6290Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (flags != GLD_RX) {
6320Sstevel@tonic-gate 		/*
6330Sstevel@tonic-gate 		 * GLD_TX and GLD_RXLOOP cases.
6340Sstevel@tonic-gate 		 */
6350Sstevel@tonic-gate 		gldp = (ipoib_ptxhdr_t *)mp->b_rptr;
6360Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 		/* make sure packet has at least a pseudo header */
6390Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (ipoib_ptxhdr_t))
6400Sstevel@tonic-gate 			return (-1);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		/* make sure the mac header falls into contiguous memory */
6430Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (ipoib_ptxhdr_t)) {
6440Sstevel@tonic-gate 			if ((pmp = msgpullup(mp, -1)) == NULL) {
6450Sstevel@tonic-gate #ifdef GLD_DEBUG
6460Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
6470Sstevel@tonic-gate 					cmn_err(CE_WARN,
6480Sstevel@tonic-gate 					    "GLD: interpret_ib "
6490Sstevel@tonic-gate 					    "cannot msgpullup");
6500Sstevel@tonic-gate #endif
6510Sstevel@tonic-gate 				return (-1);
6520Sstevel@tonic-gate 			}
6530Sstevel@tonic-gate 			/* this mblk contains the whole mac header */
6540Sstevel@tonic-gate 			mp = pmp;
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 		/*
6580Sstevel@tonic-gate 		 * Check if mac is broadcast or multicast address; all these
6590Sstevel@tonic-gate 		 * types of address have the top 4 bytes as 0x00FFFFFF.
6600Sstevel@tonic-gate 		 */
6610Sstevel@tonic-gate 		if (mac_eq(&gldp->ipoib_dest, macinfo->gldm_broadcast_addr,
6620Sstevel@tonic-gate 		    sizeof (uint32_t))) {
6630Sstevel@tonic-gate 			if (mac_eq(&gldp->ipoib_dest,
6640Sstevel@tonic-gate 			    macinfo->gldm_broadcast_addr, IPOIB_ADDRL))
6650Sstevel@tonic-gate 				pktinfo->isBroadcast = 1;
6660Sstevel@tonic-gate 			else
6670Sstevel@tonic-gate 				pktinfo->isMulticast = 1;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * Only count bytes we will be sending over the wire
6720Sstevel@tonic-gate 		 * or looping back.
6730Sstevel@tonic-gate 		 */
6740Sstevel@tonic-gate 		pktinfo->pktLen -= IPOIB_ADDRL;
6750Sstevel@tonic-gate 		if (flags == GLD_TX)
6760Sstevel@tonic-gate 			goto out;	/* Got all info we need for xmit case */
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 		/*
6790Sstevel@tonic-gate 		 * Loopback case: this is a dup'ed message.
6800Sstevel@tonic-gate 		 */
6810Sstevel@tonic-gate 		mp->b_rptr += IPOIB_ADDRL;
6820Sstevel@tonic-gate 		mac_copy(&gldp->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
6830Sstevel@tonic-gate 		mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
6840Sstevel@tonic-gate 	} else {
6850Sstevel@tonic-gate 		/*
6860Sstevel@tonic-gate 		 * GLD_RX case; process packet sent from driver.
6870Sstevel@tonic-gate 		 */
6880Sstevel@tonic-gate 		ipoib_mac_t *mact, *tact;
6890Sstevel@tonic-gate 		ib_qpn_t dqpn;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
6920Sstevel@tonic-gate 		/* make sure packet has at least pgrh and mac header */
6930Sstevel@tonic-gate 		if (pktinfo->pktLen < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
6940Sstevel@tonic-gate 			return (-1);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 		/* make sure the header falls into contiguous memory */
6970Sstevel@tonic-gate 		if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE)) {
6980Sstevel@tonic-gate 			if ((pmp = msgpullup(mp, -1)) == NULL) {
6990Sstevel@tonic-gate #ifdef GLD_DEBUG
7000Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
7010Sstevel@tonic-gate 					cmn_err(CE_WARN,
7020Sstevel@tonic-gate 					    "GLD: interpret_ib "
7030Sstevel@tonic-gate 					    "cannot msgpullup2");
7040Sstevel@tonic-gate #endif
7050Sstevel@tonic-gate 				return (-1);
7060Sstevel@tonic-gate 			}
7070Sstevel@tonic-gate 			/* this mblk contains the whole mac header */
7080Sstevel@tonic-gate 			mp = pmp;
7090Sstevel@tonic-gate 		}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		grh = (ipoib_pgrh_t *)mp->b_rptr;
7120Sstevel@tonic-gate 		mp->b_rptr += IPOIB_GRH_SIZE;
7130Sstevel@tonic-gate 		pktinfo->pktLen -= IPOIB_GRH_SIZE;
7140Sstevel@tonic-gate 		if (grh->ipoib_vertcflow) {
7150Sstevel@tonic-gate 			/*
7160Sstevel@tonic-gate 			 * First, copy source address from grh.
7170Sstevel@tonic-gate 			 */
7180Sstevel@tonic-gate 			mact = (ipoib_mac_t *)pktinfo->shost;
7190Sstevel@tonic-gate 			mac_copy(&grh->ipoib_sqpn, &mact->ipoib_qpn,
7200Sstevel@tonic-gate 			    IPOIB_ADDRL);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 			/*
7230Sstevel@tonic-gate 			 * Then copy destination address from grh;
7240Sstevel@tonic-gate 			 * first, the 16 bytes of GID.
7250Sstevel@tonic-gate 			 */
7260Sstevel@tonic-gate 			mact = (ipoib_mac_t *)pktinfo->dhost;
7270Sstevel@tonic-gate 			mac_copy(&grh->ipoib_dgid_pref,
7280Sstevel@tonic-gate 			    &mact->ipoib_gidpref, IPOIB_ADDRL -
7290Sstevel@tonic-gate 			    sizeof (mact->ipoib_qpn));
7300Sstevel@tonic-gate 			tact = (ipoib_mac_t *)mac_pvt->curr_macaddr;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 			/* Is this a multicast address */
7330Sstevel@tonic-gate 			if (*(uchar_t *)(grh->ipoib_dgid_pref) == 0xFF) {
7340Sstevel@tonic-gate 				/*
7350Sstevel@tonic-gate 				 * Only check for hardware looping in
7360Sstevel@tonic-gate 				 * multicast case. It is assumed higher
7370Sstevel@tonic-gate 				 * layer code (IP) will stop unicast loops;
7380Sstevel@tonic-gate 				 * ie will prevent a transmit to self.
7390Sstevel@tonic-gate 				 */
7400Sstevel@tonic-gate 				if (bcmp(&grh->ipoib_sqpn, tact,
7410Sstevel@tonic-gate 				    IPOIB_ADDRL) == 0)
7420Sstevel@tonic-gate 					pktinfo->isLooped = 1;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 				tact = (ipoib_mac_t *)macinfo->
7450Sstevel@tonic-gate 				    gldm_broadcast_addr;
7460Sstevel@tonic-gate 				if (mac_eq(tact->ipoib_gidpref,
7470Sstevel@tonic-gate 				    grh->ipoib_dgid_pref,
7480Sstevel@tonic-gate 				    IPOIB_ADDRL - sizeof (tact->ipoib_qpn)))
7490Sstevel@tonic-gate 					pktinfo->isBroadcast = 1;
7500Sstevel@tonic-gate 				else
7510Sstevel@tonic-gate 					pktinfo->isMulticast = 1;
7520Sstevel@tonic-gate 				/*
7530Sstevel@tonic-gate 				 * Now copy the 4 bytes QPN part of the
7540Sstevel@tonic-gate 				 * destination address.
7550Sstevel@tonic-gate 				 */
7560Sstevel@tonic-gate 				dqpn = htonl(IB_MC_QPN);
7570Sstevel@tonic-gate 				mac_copy(&dqpn, &mact->ipoib_qpn,
7580Sstevel@tonic-gate 				    sizeof (mact->ipoib_qpn));
7590Sstevel@tonic-gate 			} else {
7600Sstevel@tonic-gate 				/*
7610Sstevel@tonic-gate 				 * Now copy the 4 bytes QPN part of the
7620Sstevel@tonic-gate 				 * destination address.
7630Sstevel@tonic-gate 				 */
7640Sstevel@tonic-gate 				mac_copy(&tact->ipoib_qpn, &mact->ipoib_qpn,
7650Sstevel@tonic-gate 				    sizeof (mact->ipoib_qpn));
7660Sstevel@tonic-gate 				/*
7670Sstevel@tonic-gate 				 * Any unicast packets received on IBA are
7680Sstevel@tonic-gate 				 * for the node.
7690Sstevel@tonic-gate 				 */
7700Sstevel@tonic-gate 				pktinfo->isForMe = 1;
7710Sstevel@tonic-gate 			}
7720Sstevel@tonic-gate 		} else {
7730Sstevel@tonic-gate 			/*
7740Sstevel@tonic-gate 			 * It can not be a IBA multicast packet.
7750Sstevel@tonic-gate 			 * Must have been unicast to us. We do not
7760Sstevel@tonic-gate 			 * have shost information, which is used in
7770Sstevel@tonic-gate 			 * gld_addudind(); IP/ARP does not care.
7780Sstevel@tonic-gate 			 */
7790Sstevel@tonic-gate 			pktinfo->nosource = 1;
7800Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr, pktinfo->dhost,
7810Sstevel@tonic-gate 			    IPOIB_ADDRL);
7820Sstevel@tonic-gate 			/*
7830Sstevel@tonic-gate 			 * Any unicast packets received on IBA are
7840Sstevel@tonic-gate 			 * for the node.
7850Sstevel@tonic-gate 			 */
7860Sstevel@tonic-gate 			pktinfo->isForMe = 1;
7870Sstevel@tonic-gate 		}
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	ASSERT((flags == GLD_RX) || (flags == GLD_RXLOOP));
7910Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
7920Sstevel@tonic-gate 	pktinfo->ethertype = REF_NET_USHORT(((ipoib_hdr_t *)
7930Sstevel@tonic-gate 	    (mp->b_rptr))->ipoib_type);
7940Sstevel@tonic-gate 	pktinfo->macLen = IPOIB_HDRSIZE;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate out:
7970Sstevel@tonic-gate 	if (pmp != NULL)
7980Sstevel@tonic-gate 		freemsg(pmp);
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	return (0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate /*
8040Sstevel@tonic-gate  * The packet format sent to the driver is: 2b sap :: 2b 0s :: data
8050Sstevel@tonic-gate  */
8060Sstevel@tonic-gate void
gld_interpret_mdt_ib(gld_mac_info_t * macinfo,mblk_t * mp,pdescinfo_t * pinfo,pktinfo_t * pktinfo,mdt_packet_flag_t flags)8070Sstevel@tonic-gate gld_interpret_mdt_ib(gld_mac_info_t *macinfo, mblk_t *mp, pdescinfo_t *pinfo,
8080Sstevel@tonic-gate     pktinfo_t *pktinfo, mdt_packet_flag_t flags)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
8110Sstevel@tonic-gate 	multidata_t *dlmdp;
8120Sstevel@tonic-gate 	pattrinfo_t attr_info = { PATTR_DSTADDRSAP, };
8130Sstevel@tonic-gate 	pattr_t *patr;
8140Sstevel@tonic-gate 	ipoib_ptxhdr_t *dlap = NULL;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/*
8170Sstevel@tonic-gate 	 * Per packet formatting.
8180Sstevel@tonic-gate 	 */
8190Sstevel@tonic-gate 	if (flags == GLD_MDT_TXPKT) {
8200Sstevel@tonic-gate 		ipoib_hdr_t *hptr;
8210Sstevel@tonic-gate 		uint_t seg;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 		if (PDESC_HDRL(pinfo) == 0)
8240Sstevel@tonic-gate 			return;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		/*
8270Sstevel@tonic-gate 		 * Update packet's link header.
8280Sstevel@tonic-gate 		 */
8290Sstevel@tonic-gate 		pinfo->hdr_rptr -= IPOIB_HDRSIZE;
8300Sstevel@tonic-gate 		hptr = (ipoib_hdr_t *)pinfo->hdr_rptr;
8310Sstevel@tonic-gate 		hptr->ipoib_mbz = htons(0);
8320Sstevel@tonic-gate 		hptr->ipoib_type = pktinfo->ethertype;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 		/*
8350Sstevel@tonic-gate 		 * Total #bytes that will be put on wire.
8360Sstevel@tonic-gate 		 */
8370Sstevel@tonic-gate 		pktinfo->pktLen = PDESC_HDRL(pinfo);
8380Sstevel@tonic-gate 		for (seg = 0; seg < pinfo->pld_cnt; seg++)
8390Sstevel@tonic-gate 			pktinfo->pktLen += PDESC_PLDL(pinfo, seg);
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		return;
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	/*
8450Sstevel@tonic-gate 	 * The following two cases of GLD_MDT_TX and GLD_MDT_RXLOOP are per
8460Sstevel@tonic-gate 	 * MDT message processing.
8470Sstevel@tonic-gate 	 */
8480Sstevel@tonic-gate 	dlmdp = mmd_getmultidata(mp);
8490Sstevel@tonic-gate 	patr = mmd_getpattr(dlmdp, NULL, &attr_info);
8500Sstevel@tonic-gate 	ASSERT(patr != NULL);
8510Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
8520Sstevel@tonic-gate 	if (patr != NULL)
8530Sstevel@tonic-gate 		dlap = (ipoib_ptxhdr_t *)((pattr_addr_t *)attr_info.buf)->addr;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	if (flags == GLD_MDT_TX) {
8560Sstevel@tonic-gate 		bzero((void *)pktinfo, sizeof (*pktinfo));
8570Sstevel@tonic-gate 		if (dlap == NULL)
8580Sstevel@tonic-gate 			return;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		/*
8610Sstevel@tonic-gate 		 * Check if mac is broadcast or multicast address; all these
8620Sstevel@tonic-gate 		 * types of address have the top 4 bytes as 0x00FFFFFF.
8630Sstevel@tonic-gate 		 */
8640Sstevel@tonic-gate 		if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
8650Sstevel@tonic-gate 		    sizeof (uint32_t))) {
8660Sstevel@tonic-gate 			if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
8670Sstevel@tonic-gate 			    IPOIB_ADDRL))
8680Sstevel@tonic-gate 				pktinfo->isBroadcast = 1;
8690Sstevel@tonic-gate 			else
8700Sstevel@tonic-gate 				pktinfo->isMulticast = 1;
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(dlap->
8730Sstevel@tonic-gate 		    ipoib_rhdr.ipoib_type);
8740Sstevel@tonic-gate 	} else {
8750Sstevel@tonic-gate 		ASSERT(flags == GLD_MDT_RXLOOP);
8760Sstevel@tonic-gate 		pktinfo->macLen = IPOIB_HDRSIZE;
8770Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
8780Sstevel@tonic-gate 		mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
8790Sstevel@tonic-gate 		if (dlap == NULL)
8800Sstevel@tonic-gate 			return;
8810Sstevel@tonic-gate 		mac_copy(&dlap->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate mblk_t *
gld_unitdata_ib(gld_t * gld,mblk_t * mp)8860Sstevel@tonic-gate gld_unitdata_ib(gld_t *gld, mblk_t *mp)
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
8890Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
8900Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
8910Sstevel@tonic-gate 	ipoib_mac_t dhost;
8920Sstevel@tonic-gate 	unsigned short type;
8930Sstevel@tonic-gate 	mblk_t *nmp;
8940Sstevel@tonic-gate 	int hdrlen;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
8990Sstevel@tonic-gate 	mac_copy(&gldp->ipoib_dest, &dhost, IPOIB_ADDRL);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
9020Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
9030Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
9040Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
9050Sstevel@tonic-gate 	else
9060Sstevel@tonic-gate 		type = gld->gld_sap;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	hdrlen = sizeof (ipoib_ptxhdr_t);
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
9110Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
9120Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
9130Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
9140Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
9150Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
9160Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
9170Sstevel@tonic-gate 		nmp = mp;
9180Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
9190Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
9200Sstevel@tonic-gate 	} else {
9210Sstevel@tonic-gate 		/* we need to allocate one */
9220Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
9230Sstevel@tonic-gate 			return (NULL);
9240Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
9250Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
9260Sstevel@tonic-gate 		freeb(mp);
9270Sstevel@tonic-gate 	}
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
9320Sstevel@tonic-gate 	gldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
9330Sstevel@tonic-gate 	SET_NET_USHORT(gldp->ipoib_rhdr.ipoib_type, type);
9340Sstevel@tonic-gate 	gldp->ipoib_rhdr.ipoib_mbz = 0;
9350Sstevel@tonic-gate 	mac_copy(&dhost, &gldp->ipoib_dest, IPOIB_ADDRL);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	return (nmp);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate mblk_t *
gld_fastpath_ib(gld_t * gld,mblk_t * mp)9410Sstevel@tonic-gate gld_fastpath_ib(gld_t *gld, mblk_t *mp)
9420Sstevel@tonic-gate {
9430Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
9440Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
9450Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
9460Sstevel@tonic-gate 	unsigned short type;
9470Sstevel@tonic-gate 	mblk_t *nmp;
9480Sstevel@tonic-gate 	ipoib_ptxhdr_t *tgldp;
9490Sstevel@tonic-gate 	int hdrlen;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
9540Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
9550Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
9560Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
9570Sstevel@tonic-gate 	else
9580Sstevel@tonic-gate 		type = gld->gld_sap;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	hdrlen = sizeof (ipoib_ptxhdr_t);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
9630Sstevel@tonic-gate 		return (NULL);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
9700Sstevel@tonic-gate 	tgldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
9710Sstevel@tonic-gate 	tgldp->ipoib_rhdr.ipoib_type = htons(type);
9720Sstevel@tonic-gate 	tgldp->ipoib_rhdr.ipoib_mbz = 0;
9730Sstevel@tonic-gate 	mac_copy(&gldp->ipoib_dest, &tgldp->ipoib_dest, IPOIB_ADDRL);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	return (nmp);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate /* ==== */
9790Sstevel@tonic-gate /* FDDI */
9800Sstevel@tonic-gate /* ==== */
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate void
gld_init_fddi(gld_mac_info_t * macinfo)9830Sstevel@tonic-gate gld_init_fddi(gld_mac_info_t *macinfo)
9840Sstevel@tonic-gate {
9850Sstevel@tonic-gate 	struct gldkstats *sp =
9860Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	/* Assumptions we make for this medium */
9890Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_FDDI);
9900Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
9910Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
9920Sstevel@tonic-gate #ifndef	lint
9930Sstevel@tonic-gate 	ASSERT(sizeof (struct fddi_mac_frm) == 13);
9940Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
9950Sstevel@tonic-gate #endif
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	/* Wire address format is bit reversed from canonical format */
9980Sstevel@tonic-gate 	macinfo->gldm_options |= GLDOPT_CANONICAL_ADDR;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_error,
10010Sstevel@tonic-gate 	    "mac_errors", KSTAT_DATA_UINT32);
10020Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_lost,
10030Sstevel@tonic-gate 	    "mac_lost_errors", KSTAT_DATA_UINT32);
10040Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_token,
10050Sstevel@tonic-gate 	    "mac_tokens", KSTAT_DATA_UINT32);
10060Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_tvx_expired,
10070Sstevel@tonic-gate 	    "mac_tvx_expired", KSTAT_DATA_UINT32);
10080Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_late,
10090Sstevel@tonic-gate 	    "mac_late", KSTAT_DATA_UINT32);
10100Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_ring_op,
10110Sstevel@tonic-gate 	    "mac_ring_ops", KSTAT_DATA_UINT32);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*ARGSUSED*/
10150Sstevel@tonic-gate void
gld_uninit_fddi(gld_mac_info_t * macinfo)10160Sstevel@tonic-gate gld_uninit_fddi(gld_mac_info_t *macinfo)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate int
gld_interpret_fddi(gld_mac_info_t * macinfo,mblk_t * mp,pktinfo_t * pktinfo,packet_flag_t flags)10210Sstevel@tonic-gate gld_interpret_fddi(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
10220Sstevel@tonic-gate     packet_flag_t flags)
10230Sstevel@tonic-gate {
10240Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
10250Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
10260Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
10270Sstevel@tonic-gate 	mblk_t *pmp = NULL;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	/*
10300Sstevel@tonic-gate 	 * Quickly handle receive fastpath; FDDI does not support IPQ hack.
10310Sstevel@tonic-gate 	 */
10320Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
10330Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
10340Sstevel@tonic-gate 		return (-1);
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
10420Sstevel@tonic-gate 	if (pktinfo->pktLen < sizeof (struct fddi_mac_frm))
10430Sstevel@tonic-gate 		return (-1);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
10460Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct fddi_mac_frm)) {
10470Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
10480Sstevel@tonic-gate #ifdef GLD_DEBUG
10490Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
10500Sstevel@tonic-gate 				cmn_err(CE_WARN,
10510Sstevel@tonic-gate 				    "GLD: interpret_fddi cannot msgpullup");
10520Sstevel@tonic-gate #endif
10530Sstevel@tonic-gate 			return (-1);
10540Sstevel@tonic-gate 		}
10550Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
10560Sstevel@tonic-gate 	}
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)mp->b_rptr;
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
10610Sstevel@tonic-gate 	/* NB we are still in wire format (non canonical) */
10620Sstevel@tonic-gate 	/* mac_eq works because ether_broadcast is the same either way */
10630Sstevel@tonic-gate 	if (mac_eq(mh->fddi_dhost, ether_broadcast, macinfo->gldm_addrlen))
10640Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
10650Sstevel@tonic-gate 	else if (mh->fddi_dhost[0] & 0x80)
10660Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	if (flags == GLD_TX)
10690Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/*
10740Sstevel@tonic-gate 	 * Deal with the mac header
10750Sstevel@tonic-gate 	 */
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	cmac_copy(mh->fddi_dhost, pktinfo->dhost,
10780Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
10790Sstevel@tonic-gate 	cmac_copy(mh->fddi_shost, pktinfo->shost,
10800Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
10830Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
10840Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
10850Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
10860Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	pktinfo->macLen = sizeof (struct fddi_mac_frm);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the LLC
10920Sstevel@tonic-gate 	 * header exists, and that both it and any SNAP header are contiguous.
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct fddi_mac_frm) + LLC_SNAP_HDR_LEN &&
10950Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
10960Sstevel@tonic-gate 		/*
10970Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
10980Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
10990Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
11000Sstevel@tonic-gate 		 */
11010Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
11020Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
11030Sstevel@tonic-gate #ifdef GLD_DEBUG
11040Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
11050Sstevel@tonic-gate 				cmn_err(CE_WARN,
11060Sstevel@tonic-gate 				    "GLD: interpret_fddi cannot msgpullup2");
11070Sstevel@tonic-gate #endif
11080Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	/*
11140Sstevel@tonic-gate 	 * Check SAP/SNAP information.
11150Sstevel@tonic-gate 	 */
11160Sstevel@tonic-gate 	if ((mh->fddi_fc & 0x70) == 0x50) {
11170Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
11180Sstevel@tonic-gate 			goto out;
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		pktinfo->isLLC = 1;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
11230Sstevel@tonic-gate 			goto out;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
11260Sstevel@tonic-gate 		if (ISETHERTYPE(snaphdr)) {
11270Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
11280Sstevel@tonic-gate 			pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
11290Sstevel@tonic-gate 		}
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate out:
11320Sstevel@tonic-gate 	if (pmp != NULL)
11330Sstevel@tonic-gate 		freemsg(pmp);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	return (0);
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate mblk_t *
gld_unitdata_fddi(gld_t * gld,mblk_t * mp)11390Sstevel@tonic-gate gld_unitdata_fddi(gld_t *gld, mblk_t *mp)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
11420Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
11430Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
11440Sstevel@tonic-gate 	mac_addr_t dhost;
11450Sstevel@tonic-gate 	unsigned short type;
11460Sstevel@tonic-gate 	mblk_t *nmp;
11470Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
11480Sstevel@tonic-gate 	int hdrlen;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	ASSERT(macinfo);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
11530Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
11560Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
11570Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
11580Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
11590Sstevel@tonic-gate 	else
11600Sstevel@tonic-gate 		type = gld->gld_sap;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	hdrlen = sizeof (struct fddi_mac_frm);
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	/*
11660Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
11670Sstevel@tonic-gate 	 * is LLC.
11680Sstevel@tonic-gate 	 */
11690Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
11700Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
11730Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
11740Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
11750Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
11760Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
11770Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
11780Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
11790Sstevel@tonic-gate 		nmp = mp;
11800Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
11810Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
11820Sstevel@tonic-gate 	} else {
11830Sstevel@tonic-gate 		/* we need to allocate one */
11840Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
11850Sstevel@tonic-gate 			return (NULL);
11860Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
11870Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
11880Sstevel@tonic-gate 		freeb(mp);
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
11930Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
11940Sstevel@tonic-gate 		/* create the snap header */
11950Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
11960Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
11970Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
11980Sstevel@tonic-gate 		*snap = llc_snap_def;
11990Sstevel@tonic-gate 		SET_NET_USHORT(snap->type, type);
12000Sstevel@tonic-gate 	}
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct fddi_mac_frm);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)nmp->b_rptr;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	mh->fddi_fc = 0x50;
12070Sstevel@tonic-gate 	cmac_copy(dhost, mh->fddi_dhost, macinfo->gldm_addrlen, macinfo);
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	/*
12100Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
12110Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
12120Sstevel@tonic-gate 	 */
12130Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
12140Sstevel@tonic-gate 	    mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
12150Sstevel@tonic-gate 	return (nmp);
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate mblk_t *
gld_fastpath_fddi(gld_t * gld,mblk_t * mp)12190Sstevel@tonic-gate gld_fastpath_fddi(gld_t *gld, mblk_t *mp)
12200Sstevel@tonic-gate {
12210Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
12220Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
12230Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
12240Sstevel@tonic-gate 	unsigned short type;
12250Sstevel@tonic-gate 	mblk_t *nmp;
12260Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
12270Sstevel@tonic-gate 	int hdrlen;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	ASSERT(macinfo);
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
12320Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
12330Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
12340Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
12350Sstevel@tonic-gate 	else
12360Sstevel@tonic-gate 		type = gld->gld_sap;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	hdrlen = sizeof (struct fddi_mac_frm);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	/*
12410Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
12420Sstevel@tonic-gate 	 * will be LLC.
12430Sstevel@tonic-gate 	 */
12440Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
12450Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
12480Sstevel@tonic-gate 		return (NULL);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
12550Sstevel@tonic-gate 		/* create the snap header */
12560Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
12570Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
12580Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
12590Sstevel@tonic-gate 		*snap = llc_snap_def;
12600Sstevel@tonic-gate 		snap->type = htons(type);	/* we know it's aligned */
12610Sstevel@tonic-gate 	}
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct fddi_mac_frm);
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)nmp->b_rptr;
12660Sstevel@tonic-gate 	mh->fddi_fc = 0x50;
12670Sstevel@tonic-gate 	cmac_copy(gldp->glda_addr, mh->fddi_dhost,
12680Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
12710Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
12720Sstevel@tonic-gate 	    mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
12730Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	return (nmp);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate /* ========== */
12790Sstevel@tonic-gate /* Token Ring */
12800Sstevel@tonic-gate /* ========== */
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate #define	GLD_SR_VAR(macinfo)	\
12830Sstevel@tonic-gate 	(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->data)
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate #define	GLD_SR_HASH(macinfo)	((struct srtab **)GLD_SR_VAR(macinfo))
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate #define	GLD_SR_MUTEX(macinfo)	\
12880Sstevel@tonic-gate 	(&((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->datalock)
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate static void gld_sr_clear(gld_mac_info_t *);
12910Sstevel@tonic-gate static void gld_rcc_receive(gld_mac_info_t *, pktinfo_t *, struct gld_ri *,
12920Sstevel@tonic-gate     uchar_t *, int);
12930Sstevel@tonic-gate static void gld_rcc_send(gld_mac_info_t *, queue_t *, uchar_t *,
12940Sstevel@tonic-gate     struct gld_ri **, uchar_t *);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate static mac_addr_t tokenbroadcastaddr2 = { 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff };
12970Sstevel@tonic-gate static struct gld_ri ri_ste_def;
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate void
gld_init_tr(gld_mac_info_t * macinfo)13000Sstevel@tonic-gate gld_init_tr(gld_mac_info_t *macinfo)
13010Sstevel@tonic-gate {
13020Sstevel@tonic-gate 	struct gldkstats *sp =
13030Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	/* avoid endian-dependent code by initializing here instead of static */
13060Sstevel@tonic-gate 	ri_ste_def.len = 2;
13070Sstevel@tonic-gate 	ri_ste_def.rt = RT_STE;
13080Sstevel@tonic-gate 	ri_ste_def.mtu = RT_MTU_MAX;
13090Sstevel@tonic-gate 	ri_ste_def.dir = 0;
13100Sstevel@tonic-gate 	ri_ste_def.res = 0;
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	/* Assumptions we make for this medium */
13130Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_TPR);
13140Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
13150Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
13160Sstevel@tonic-gate #ifndef	lint
13170Sstevel@tonic-gate 	ASSERT(sizeof (struct tr_mac_frm_nori) == 14);
13180Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
13190Sstevel@tonic-gate #endif
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	mutex_init(GLD_SR_MUTEX(macinfo), NULL, MUTEX_DRIVER, NULL);
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	GLD_SR_VAR(macinfo) = kmem_zalloc(sizeof (struct srtab *)*SR_HASH_SIZE,
13240Sstevel@tonic-gate 				KM_SLEEP);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	/* Default is RDE enabled for this medium */
13270Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled =
13280Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
13290Sstevel@tonic-gate 	    "gld_rde_enable", 1);
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	/*
13320Sstevel@tonic-gate 	 * Default is to use STE for unknown paths if RDE is enabled.
13330Sstevel@tonic-gate 	 * If RDE is disabled, default is to use NULL RIF fields.
13340Sstevel@tonic-gate 	 *
13350Sstevel@tonic-gate 	 * It's possible to force use of STE for ALL packets:
13360Sstevel@tonic-gate 	 * disable RDE but enable STE.  This may be useful for
13370Sstevel@tonic-gate 	 * non-transparent bridges, when it is not desired to run
13380Sstevel@tonic-gate 	 * the RDE algorithms.
13390Sstevel@tonic-gate 	 */
13400Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste =
13410Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
13420Sstevel@tonic-gate 	    "gld_rde_str_indicator_ste",
13430Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	/* Default 10 second route timeout on lack of activity */
13460Sstevel@tonic-gate 	{
13470Sstevel@tonic-gate 	int t = ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
13480Sstevel@tonic-gate 	    "gld_rde_timeout", 10);
13490Sstevel@tonic-gate 	if (t < 1)
13500Sstevel@tonic-gate 		t = 1;		/* Let's be reasonable */
13510Sstevel@tonic-gate 	if (t > 600)
13520Sstevel@tonic-gate 		t = 600;	/* Let's be reasonable */
13530Sstevel@tonic-gate 	/* We're using ticks (lbolts) for our timeout -- convert from seconds */
13540Sstevel@tonic-gate 	t = drv_usectohz(1000000 * t);
13550Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout = t;
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_line_error,
13590Sstevel@tonic-gate 	    "line_errors", KSTAT_DATA_UINT32);
13600Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_burst_error,
13610Sstevel@tonic-gate 	    "burst_errors", KSTAT_DATA_UINT32);
13620Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_signal_loss,
13630Sstevel@tonic-gate 	    "signal_losses", KSTAT_DATA_UINT32);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/*
13660Sstevel@tonic-gate 	 * only initialize the new statistics if the driver
13670Sstevel@tonic-gate 	 * knows about them.
13680Sstevel@tonic-gate 	 */
13690Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION_200)
13700Sstevel@tonic-gate 		return;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_ace_error,
13730Sstevel@tonic-gate 	    "ace_errors", KSTAT_DATA_UINT32);
13740Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_internal_error,
13750Sstevel@tonic-gate 	    "internal_errors", KSTAT_DATA_UINT32);
13760Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_lost_frame_error,
13770Sstevel@tonic-gate 	    "lost_frame_errors", KSTAT_DATA_UINT32);
13780Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_frame_copied_error,
13790Sstevel@tonic-gate 	    "frame_copied_errors", KSTAT_DATA_UINT32);
13800Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_token_error,
13810Sstevel@tonic-gate 	    "token_errors", KSTAT_DATA_UINT32);
13820Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_freq_error,
13830Sstevel@tonic-gate 	    "freq_errors", KSTAT_DATA_UINT32);
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate void
gld_uninit_tr(gld_mac_info_t * macinfo)13870Sstevel@tonic-gate gld_uninit_tr(gld_mac_info_t *macinfo)
13880Sstevel@tonic-gate {
13890Sstevel@tonic-gate 	mutex_destroy(GLD_SR_MUTEX(macinfo));
13900Sstevel@tonic-gate 	gld_sr_clear(macinfo);
13910Sstevel@tonic-gate 	kmem_free(GLD_SR_VAR(macinfo), sizeof (struct srtab *) * SR_HASH_SIZE);
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate int
gld_interpret_tr(gld_mac_info_t * macinfo,mblk_t * mp,pktinfo_t * pktinfo,packet_flag_t flags)13950Sstevel@tonic-gate gld_interpret_tr(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
13960Sstevel@tonic-gate     packet_flag_t flags)
13970Sstevel@tonic-gate {
13980Sstevel@tonic-gate 	struct tr_mac_frm *mh;
13990Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
14000Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
14010Sstevel@tonic-gate 	mblk_t *pmp = NULL;
14020Sstevel@tonic-gate 	struct gld_ri *rh;
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	/*
14050Sstevel@tonic-gate 	 * Quickly handle receive fastpath; TR does not support IPQ hack.
14060Sstevel@tonic-gate 	 */
14070Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
14080Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
14090Sstevel@tonic-gate 		return (-1);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
14170Sstevel@tonic-gate 	if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori))
14180Sstevel@tonic-gate 		return (-1);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
14210Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct tr_mac_frm_nori)) {
14220Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
14230Sstevel@tonic-gate #ifdef GLD_DEBUG
14240Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
14250Sstevel@tonic-gate 				cmn_err(CE_WARN,
14260Sstevel@tonic-gate 				    "GLD: interpret_tr cannot msgpullup");
14270Sstevel@tonic-gate #endif
14280Sstevel@tonic-gate 			return (-1);
14290Sstevel@tonic-gate 		}
14300Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	mh = (struct tr_mac_frm *)mp->b_rptr;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
14360Sstevel@tonic-gate 	if (mac_eq(mh->tr_dhost, ether_broadcast, macinfo->gldm_addrlen) ||
14370Sstevel@tonic-gate 	    mac_eq(mh->tr_dhost, tokenbroadcastaddr2, macinfo->gldm_addrlen))
14380Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
14390Sstevel@tonic-gate 	else if (mh->tr_dhost[0] & 0x80)
14400Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	if (flags == GLD_TX)
14430Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/*
14480Sstevel@tonic-gate 	 * Deal with the mac header
14490Sstevel@tonic-gate 	 */
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	mac_copy(mh->tr_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
14520Sstevel@tonic-gate 	mac_copy(mh->tr_shost, pktinfo->shost, macinfo->gldm_addrlen);
14530Sstevel@tonic-gate 	pktinfo->shost[0] &= ~0x80;	/* turn off RIF indicator */
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
14560Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
14570Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
14580Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
14590Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	rh = (struct gld_ri *)NULL;
14620Sstevel@tonic-gate 	pktinfo->macLen = sizeof (struct tr_mac_frm_nori);
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	/*
14650Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the data
14660Sstevel@tonic-gate 	 * structures are all contiguously where we can conveniently look at
14670Sstevel@tonic-gate 	 * them.  We'll use a worst-case estimate of how many bytes into the
14680Sstevel@tonic-gate 	 * packet data we'll be needing to look.  Things will be more efficient
14690Sstevel@tonic-gate 	 * if the driver puts at least this much into the first mblk.
14700Sstevel@tonic-gate 	 *
14710Sstevel@tonic-gate 	 * Even after this, we still will have to do checks against the total
14720Sstevel@tonic-gate 	 * length of the packet.  A bad incoming packet may not hold all the
14730Sstevel@tonic-gate 	 * data structures it says it does.
14740Sstevel@tonic-gate 	 */
14750Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct tr_mac_frm) +
14760Sstevel@tonic-gate 	    LLC_HDR1_LEN + sizeof (struct rde_pdu) &&
14770Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
14780Sstevel@tonic-gate 		/*
14790Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
14800Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
14810Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
14820Sstevel@tonic-gate 		 */
14830Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
14840Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
14850Sstevel@tonic-gate #ifdef GLD_DEBUG
14860Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
14870Sstevel@tonic-gate 				cmn_err(CE_WARN,
14880Sstevel@tonic-gate 				    "GLD: interpret_tr cannot msgpullup2");
14890Sstevel@tonic-gate #endif
14900Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
14910Sstevel@tonic-gate 		}
14920Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
14930Sstevel@tonic-gate 		mh = (struct tr_mac_frm *)mp->b_rptr;	/* to look at RIF */
14940Sstevel@tonic-gate 	}
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	if (mh->tr_shost[0] & 0x80) {
14970Sstevel@tonic-gate 		/* Routing Information Field (RIF) is present */
14980Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + 2)
14990Sstevel@tonic-gate 			goto out;	/* RIF should have been there! */
15000Sstevel@tonic-gate 		rh = (struct gld_ri *)&mh->tr_ri;
15010Sstevel@tonic-gate 		if ((rh->len & 1) || rh->len < 2) {
15020Sstevel@tonic-gate 			/* Bogus RIF, don't handle this packet */
15030Sstevel@tonic-gate #ifdef GLD_DEBUG
15040Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
15050Sstevel@tonic-gate 				cmn_err(CE_WARN,
15060Sstevel@tonic-gate 				    "GLD: received TR packet with "
15070Sstevel@tonic-gate 				    "bogus RIF length %d",
15080Sstevel@tonic-gate 				    rh->len);
15090Sstevel@tonic-gate #endif
15100Sstevel@tonic-gate 			goto out;
15110Sstevel@tonic-gate 		}
15120Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + rh->len)
15130Sstevel@tonic-gate 			goto out;	/* RIF should have been there! */
15140Sstevel@tonic-gate 		pktinfo->macLen += rh->len;
15150Sstevel@tonic-gate 	}
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if ((mh->tr_fc & 0xc0) == 0x40) {
15180Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
15190Sstevel@tonic-gate 			goto out;
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 		pktinfo->isLLC = 1;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
15240Sstevel@tonic-gate 			goto out;
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
15270Sstevel@tonic-gate 		if (ISETHERTYPE(snaphdr)) {
15280Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
15290Sstevel@tonic-gate 			pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
15300Sstevel@tonic-gate 		}
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 		/* Inform the Route Control Component of received LLC frame */
15330Sstevel@tonic-gate 		gld_rcc_receive(macinfo, pktinfo, rh,
15340Sstevel@tonic-gate 		    mp->b_rptr + pktinfo->macLen,
15350Sstevel@tonic-gate 		    pktinfo->pktLen - pktinfo->macLen);
15360Sstevel@tonic-gate 	}
15370Sstevel@tonic-gate out:
15380Sstevel@tonic-gate 	if (pmp != NULL)
15390Sstevel@tonic-gate 		freemsg(pmp);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	return (0);
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate mblk_t *
gld_unitdata_tr(gld_t * gld,mblk_t * mp)15450Sstevel@tonic-gate gld_unitdata_tr(gld_t *gld, mblk_t *mp)
15460Sstevel@tonic-gate {
15470Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
15480Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
15490Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
15500Sstevel@tonic-gate 	mac_addr_t dhost;
15510Sstevel@tonic-gate 	unsigned short type;
15520Sstevel@tonic-gate 	mblk_t *nmp, *llcmp, *pmp = NULL;
15530Sstevel@tonic-gate 	struct tr_mac_frm_nori *mh;
15540Sstevel@tonic-gate 	int hdrlen;
15550Sstevel@tonic-gate 	struct gld_ri *rh;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	ASSERT(macinfo);
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
15600Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
15630Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
15640Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
15650Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
15660Sstevel@tonic-gate 	else
15670Sstevel@tonic-gate 		type = gld->gld_sap;
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	/* includes maximum possible Routing Information Field (RIF) size */
15700Sstevel@tonic-gate 	hdrlen = sizeof (struct tr_mac_frm);
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	/*
15730Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
15740Sstevel@tonic-gate 	 * is LLC.
15750Sstevel@tonic-gate 	 */
15760Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
15770Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
15800Sstevel@tonic-gate 	llcmp = nmp = mp->b_cont; /* where the packet payload M_DATA is */
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 	/*
15830Sstevel@tonic-gate 	 * We are going to need to look at the LLC header, so make sure it
15840Sstevel@tonic-gate 	 * is contiguously in a single mblk.  If we're the ones who create
15850Sstevel@tonic-gate 	 * the LLC header (below, in the case where sap > 0xff) then we don't
15860Sstevel@tonic-gate 	 * have to worry about it here.
15870Sstevel@tonic-gate 	 */
15880Sstevel@tonic-gate 	ASSERT(nmp != NULL);	/* gld_unitdata guarantees msgdsize > 0 */
15890Sstevel@tonic-gate 	if (type <= GLD_MAX_802_SAP) {
15900Sstevel@tonic-gate 		if (MBLKL(llcmp) < LLC_HDR1_LEN) {
15910Sstevel@tonic-gate 			llcmp = pmp = msgpullup(nmp, LLC_HDR1_LEN);
15920Sstevel@tonic-gate 			if (pmp == NULL) {
15930Sstevel@tonic-gate #ifdef GLD_DEBUG
15940Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
15950Sstevel@tonic-gate 					cmn_err(CE_WARN,
15960Sstevel@tonic-gate 					    "GLD: unitdata_tr "
15970Sstevel@tonic-gate 					    "cannot msgpullup");
15980Sstevel@tonic-gate #endif
15990Sstevel@tonic-gate 				return (NULL);
16000Sstevel@tonic-gate 			}
16010Sstevel@tonic-gate 		}
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
16050Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
16060Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
16070Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
16080Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
16090Sstevel@tonic-gate 		nmp = mp;
16100Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
16110Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
16120Sstevel@tonic-gate 	} else {
16130Sstevel@tonic-gate 		/* we need to allocate one */
16140Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL) {
16150Sstevel@tonic-gate 			if (pmp != NULL)
16160Sstevel@tonic-gate 				freemsg(pmp);
16170Sstevel@tonic-gate 			return (NULL);
16180Sstevel@tonic-gate 		}
16190Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
16200Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
16210Sstevel@tonic-gate 		freeb(mp);
16220Sstevel@tonic-gate 	}
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
16250Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
16260Sstevel@tonic-gate 		/* create the snap header */
16270Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
16280Sstevel@tonic-gate 		llcmp = nmp;	/* LLC header is going to be in this mblk */
16290Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
16300Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
16310Sstevel@tonic-gate 		*snap = llc_snap_def;
16320Sstevel@tonic-gate 		SET_NET_USHORT(snap->type, type);
16330Sstevel@tonic-gate 	}
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 	/* Hold SR tables still while we maybe point at an entry */
16360Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	gld_rcc_send(macinfo, WR(gld->gld_qptr), dhost, &rh, llcmp->b_rptr);
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	if (rh != NULL) {
16410Sstevel@tonic-gate 		/* copy in the RIF */
16420Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
16430Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
16440Sstevel@tonic-gate 		bcopy((caddr_t)rh, (caddr_t)nmp->b_rptr, rh->len);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 	/* no longer need the pulled-up mblk */
16500Sstevel@tonic-gate 	if (pmp != NULL)
16510Sstevel@tonic-gate 		freemsg(pmp);
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	/*
16540Sstevel@tonic-gate 	 * fill in token ring header
16550Sstevel@tonic-gate 	 */
16560Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
16570Sstevel@tonic-gate 	mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
16580Sstevel@tonic-gate 	mh->tr_ac = 0x10;
16590Sstevel@tonic-gate 	mh->tr_fc = 0x40;
16600Sstevel@tonic-gate 	mac_copy(dhost, mh->tr_dhost, macinfo->gldm_addrlen);
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	/*
16630Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
16640Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
16650Sstevel@tonic-gate 	 */
16660Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
16670Sstevel@tonic-gate 	    mh->tr_shost, macinfo->gldm_addrlen);
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	if (rh != NULL)
16700Sstevel@tonic-gate 		mh->tr_shost[0] |= 0x80;
16710Sstevel@tonic-gate 	else
16720Sstevel@tonic-gate 		mh->tr_shost[0] &= ~0x80;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	return (nmp);
16750Sstevel@tonic-gate }
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate /*
16780Sstevel@tonic-gate  * We cannot have our client sending us "fastpath" M_DATA messages,
16790Sstevel@tonic-gate  * because to do that we must provide to him a fixed MAC header to
16800Sstevel@tonic-gate  * be prepended to each outgoing packet.  But with Source Routing
16810Sstevel@tonic-gate  * media, the length and content of the MAC header changes as the
16820Sstevel@tonic-gate  * routes change, so there is no fixed header we can provide.  So
16830Sstevel@tonic-gate  * we decline to accept M_DATA messages if Source Routing is enabled.
16840Sstevel@tonic-gate  */
16850Sstevel@tonic-gate mblk_t *
gld_fastpath_tr(gld_t * gld,mblk_t * mp)16860Sstevel@tonic-gate gld_fastpath_tr(gld_t *gld, mblk_t *mp)
16870Sstevel@tonic-gate {
16880Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
16890Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
16900Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
16910Sstevel@tonic-gate 	unsigned short type;
16920Sstevel@tonic-gate 	mblk_t *nmp;
16930Sstevel@tonic-gate 	struct tr_mac_frm_nori *mh;
16940Sstevel@tonic-gate 	int hdrlen;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	ASSERT(macinfo);
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 	/*
16990Sstevel@tonic-gate 	 * If we are doing Source Routing, then we cannot provide a fixed
17000Sstevel@tonic-gate 	 * MAC header, so fail.
17010Sstevel@tonic-gate 	 */
17020Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
17030Sstevel@tonic-gate 		return (NULL);
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
17060Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
17070Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
17080Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
17090Sstevel@tonic-gate 	else
17100Sstevel@tonic-gate 		type = gld->gld_sap;
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	hdrlen = sizeof (struct tr_mac_frm_nori);
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
17150Sstevel@tonic-gate 		hdrlen += ri_ste_def.len;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	/*
17180Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
17190Sstevel@tonic-gate 	 * will be LLC.
17200Sstevel@tonic-gate 	 */
17210Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
17220Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
17250Sstevel@tonic-gate 		return (NULL);
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
17320Sstevel@tonic-gate 		/* create the snap header */
17330Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
17340Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
17350Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
17360Sstevel@tonic-gate 		*snap = llc_snap_def;
17370Sstevel@tonic-gate 		snap->type = htons(type);	/* we know it's aligned */
17380Sstevel@tonic-gate 	}
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 	/* RDE is disabled, use NULL RIF, or STE RIF */
17410Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
17420Sstevel@tonic-gate 		nmp->b_rptr -= ri_ste_def.len;
17430Sstevel@tonic-gate 		bcopy((caddr_t)&ri_ste_def, (caddr_t)nmp->b_rptr,
17440Sstevel@tonic-gate 		    ri_ste_def.len);
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 	/*
17480Sstevel@tonic-gate 	 * fill in token ring header
17490Sstevel@tonic-gate 	 */
17500Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
17510Sstevel@tonic-gate 	mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
17520Sstevel@tonic-gate 	mh->tr_ac = 0x10;
17530Sstevel@tonic-gate 	mh->tr_fc = 0x40;
17540Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, mh->tr_dhost, macinfo->gldm_addrlen);
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
17570Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
17580Sstevel@tonic-gate 	    mh->tr_shost, macinfo->gldm_addrlen);
17590Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
17620Sstevel@tonic-gate 		mh->tr_shost[0] |= 0x80;
17630Sstevel@tonic-gate 	else
17640Sstevel@tonic-gate 		mh->tr_shost[0] &= ~0x80;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	return (nmp);
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate /*
17700Sstevel@tonic-gate  * Route Determination Entity (ISO 8802-2 / IEEE 802.2 : 1994, Section 9)
17710Sstevel@tonic-gate  *
17720Sstevel@tonic-gate  * RDE is an LLC layer entity.  GLD is a MAC layer entity.  The proper
17730Sstevel@tonic-gate  * solution to this architectural anomaly is to move RDE support out of GLD
17740Sstevel@tonic-gate  * and into LLC where it belongs.  In particular, only LLC has the knowledge
17750Sstevel@tonic-gate  * necessary to reply to XID and TEST packets.  If and when it comes time to
17760Sstevel@tonic-gate  * move RDE out of GLD to LLC, the LLC-to-GLD interface should be modified
17770Sstevel@tonic-gate  * to use MA_UNITDATA structures rather than DL_UNITDATA structures.  Of
17780Sstevel@tonic-gate  * course, GLD will still have to continue to also support the DL_ structures
17790Sstevel@tonic-gate  * as long as IP is not layered over LLC.  Another, perhaps better, idea
17800Sstevel@tonic-gate  * would be to make RDE an autopush module on top of the token ring drivers:
17810Sstevel@tonic-gate  * RDE would sit between LLC and GLD.  It would then also sit between IP and
17820Sstevel@tonic-gate  * GLD, providing services to all clients of GLD/tokenring.  In that case,
17830Sstevel@tonic-gate  * GLD would still have to continue to support the DL_ interface for non-
17840Sstevel@tonic-gate  * Token Ring interfaces, using the MA_ interface only for media supporting
17850Sstevel@tonic-gate  * Source Routing media.
17860Sstevel@tonic-gate  *
17870Sstevel@tonic-gate  * At present, Token Ring is the only source routing medium we support.
17880Sstevel@tonic-gate  * Since Token Ring is not at this time a strategic network medium for Sun,
17890Sstevel@tonic-gate  * rather than devote a large amount of resources to creating a proper
17900Sstevel@tonic-gate  * architecture and implementation of RDE, we do the minimum necessary to
17910Sstevel@tonic-gate  * get it to work.  The interface between the above token ring code and the
17920Sstevel@tonic-gate  * below RDE code is designed to make it relatively easy to change to an
17930Sstevel@tonic-gate  * MA_UNITDATA model later should this ever become a priority.
17940Sstevel@tonic-gate  */
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate static void gld_send_rqr(gld_mac_info_t *, uchar_t *, struct gld_ri *,
17970Sstevel@tonic-gate     struct rde_pdu *, int);
17980Sstevel@tonic-gate static void gld_rde_pdu_req(gld_mac_info_t *, queue_t *, uchar_t *,
17990Sstevel@tonic-gate     struct gld_ri *, uchar_t, uchar_t, uchar_t);
18000Sstevel@tonic-gate static void gld_get_route(gld_mac_info_t *, queue_t *, uchar_t *,
18010Sstevel@tonic-gate     struct gld_ri **, uchar_t, uchar_t);
18020Sstevel@tonic-gate static void gld_reset_route(gld_mac_info_t *, queue_t *,
18030Sstevel@tonic-gate     uchar_t *, uchar_t, uchar_t);
18040Sstevel@tonic-gate static void gld_rde_pdu_ind(gld_mac_info_t *, struct gld_ri *, struct rde_pdu *,
18050Sstevel@tonic-gate     int);
18060Sstevel@tonic-gate static void gld_rif_ind(gld_mac_info_t *, struct gld_ri *, uchar_t *,
18070Sstevel@tonic-gate     uchar_t, uchar_t);
18080Sstevel@tonic-gate static struct srtab **gld_sr_hash(struct srtab **, uchar_t *, int);
18090Sstevel@tonic-gate static struct srtab *gld_sr_lookup_entry(gld_mac_info_t *, uchar_t *);
18100Sstevel@tonic-gate static struct srtab *gld_sr_create_entry(gld_mac_info_t *, uchar_t *);
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate /*
18130Sstevel@tonic-gate  * This routine implements a modified subset of the 802.2 RDE RCC receive
18140Sstevel@tonic-gate  * actions:
18150Sstevel@tonic-gate  *   we implement RCC receive events 3 to 12 (ISO 8802-2:1994 9.6.3.4);
18160Sstevel@tonic-gate  *   we omit special handling for the NULL SAP;
18170Sstevel@tonic-gate  *   we omit XID/TEST handling;
18180Sstevel@tonic-gate  *   we pass all packets (including RDE) upstream to LLC.
18190Sstevel@tonic-gate  */
18200Sstevel@tonic-gate static void
gld_rcc_receive(gld_mac_info_t * macinfo,pktinfo_t * pktinfo,struct gld_ri * rh,uchar_t * llcpkt,int llcpktlen)18210Sstevel@tonic-gate gld_rcc_receive(gld_mac_info_t *macinfo, pktinfo_t *pktinfo, struct gld_ri *rh,
18220Sstevel@tonic-gate     uchar_t *llcpkt, int llcpktlen)
18230Sstevel@tonic-gate {
18240Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
18270Sstevel@tonic-gate 		return;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	/*
18300Sstevel@tonic-gate 	 * First, ensure this packet wasn't something we received just
18310Sstevel@tonic-gate 	 * because we were in promiscuous mode.  Since none of the below
18320Sstevel@tonic-gate 	 * code wants to see group addressed packets anyway, we can do
18330Sstevel@tonic-gate 	 * this check up front.  Since we're doing that, we can omit the
18340Sstevel@tonic-gate 	 * checks for group addressed packets below.
18350Sstevel@tonic-gate 	 */
18360Sstevel@tonic-gate 	if (!pktinfo->isForMe)
18370Sstevel@tonic-gate 		return;		/* Event 6 */
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	/* Process a subset of Route Determination Entity (RDE) packets */
18400Sstevel@tonic-gate 	if (snaphdr->d_lsap == LSAP_RDE) {
18410Sstevel@tonic-gate 		struct rde_pdu *pdu = (struct rde_pdu *)(llcpkt + LLC_HDR1_LEN);
18420Sstevel@tonic-gate 		int pdulen = llcpktlen - LLC_HDR1_LEN;
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 		/* sanity check the PDU */
18450Sstevel@tonic-gate 		if ((pdulen < sizeof (struct rde_pdu)) ||
18460Sstevel@tonic-gate 		    (snaphdr->s_lsap != LSAP_RDE))
18470Sstevel@tonic-gate 			return;
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 		/* we only handle route discovery PDUs, not XID/TEST/other */
18500Sstevel@tonic-gate 		if (snaphdr->control != CNTL_LLC_UI)
18510Sstevel@tonic-gate 			return;
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 		switch (pdu->rde_ptype) {
18540Sstevel@tonic-gate 		case RDE_RQC:	/* Route Query Command; Events 8 - 11 */
18550Sstevel@tonic-gate 			gld_send_rqr(macinfo, pktinfo->shost, rh, pdu, pdulen);
18560Sstevel@tonic-gate 			/* FALLTHROUGH */
18570Sstevel@tonic-gate 		case RDE_RQR:	/* Route Query Response; Event 12 */
18580Sstevel@tonic-gate 		case RDE_RS:	/* Route Selected; Event 7 */
18590Sstevel@tonic-gate 			gld_rde_pdu_ind(macinfo, rh, pdu, pdulen);
18600Sstevel@tonic-gate 			break;
18610Sstevel@tonic-gate 		default:	/* ignore if unrecognized ptype */
18620Sstevel@tonic-gate 			return;
18630Sstevel@tonic-gate 		}
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		return;
18660Sstevel@tonic-gate 	}
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	/* Consider routes seen in other IA SRF packets */
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	if (rh == NULL)
18710Sstevel@tonic-gate 		return;		/* no RIF; Event 3 */
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 	if ((rh->rt & 0x04) != 0)
18740Sstevel@tonic-gate 		return;		/* not SRF; Event 5 */
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	gld_rif_ind(macinfo, rh, pktinfo->shost, snaphdr->s_lsap,
18770Sstevel@tonic-gate 	    snaphdr->d_lsap);	/* Event 4 */
18780Sstevel@tonic-gate }
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate /*
18810Sstevel@tonic-gate  * Send RQR: 802.2 9.6.3.4.2(9) RCC Receive Events 8-11
18820Sstevel@tonic-gate  *
18830Sstevel@tonic-gate  * The routing processing really doesn't belong here; it should be handled in
18840Sstevel@tonic-gate  * the LLC layer above.  If that were the case then RDE could just send down
18850Sstevel@tonic-gate  * an extra MA_UNITDATA_REQ with the info needed to construct the packet.  But
18860Sstevel@tonic-gate  * at the time we get control here, it's not a particularly good time to be
18870Sstevel@tonic-gate  * constructing packets and trying to send them.  Specifically, at this layer
18880Sstevel@tonic-gate  * we need to construct the full media packet, which means the below routine
18890Sstevel@tonic-gate  * knows that it is dealing with Token Ring media.  If this were instead done
18900Sstevel@tonic-gate  * via a proper MA_UNITDATA interface, the RDE stuff could all be completely
18910Sstevel@tonic-gate  * media independent.  But since TR is the only source routing medium we
18920Sstevel@tonic-gate  * support, this works even though it is not clean.
18930Sstevel@tonic-gate  *
18940Sstevel@tonic-gate  * We "know" that the only time we can get here is from the "interpret"
18950Sstevel@tonic-gate  * routine, and only when it was called at receive time.
18960Sstevel@tonic-gate  */
18970Sstevel@tonic-gate static void
gld_send_rqr(gld_mac_info_t * macinfo,uchar_t * shost,struct gld_ri * rh,struct rde_pdu * pdu,int pdulen)18980Sstevel@tonic-gate gld_send_rqr(gld_mac_info_t *macinfo, uchar_t *shost, struct gld_ri *rh,
18990Sstevel@tonic-gate     struct rde_pdu *pdu, int pdulen)
19000Sstevel@tonic-gate {
19010Sstevel@tonic-gate 	mblk_t *nmp;
19020Sstevel@tonic-gate 	int nlen;
19030Sstevel@tonic-gate 	struct tr_mac_frm_nori *nmh;
19040Sstevel@tonic-gate 	struct gld_ri *nrh;
19050Sstevel@tonic-gate 	struct llc_snap_hdr *nsnaphdr;
19060Sstevel@tonic-gate 	struct rde_pdu *npdu;
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	/* We know and assume we're on the receive path */
19090Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	if (pdulen < sizeof (struct rde_pdu))
19120Sstevel@tonic-gate 		return;		/* Bad incoming PDU */
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 	nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
19150Sstevel@tonic-gate 	    sizeof (struct rde_pdu);
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
19180Sstevel@tonic-gate 		return;
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct rde_pdu);
19230Sstevel@tonic-gate 	npdu = (struct rde_pdu *)(nmp->b_rptr);
19240Sstevel@tonic-gate 	*npdu = *pdu;	/* copy orig/target macaddr/saps */
19250Sstevel@tonic-gate 	npdu->rde_ver = 1;
19260Sstevel@tonic-gate 	npdu->rde_ptype = RDE_RQR;
19270Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
19280Sstevel@tonic-gate 	    npdu->rde_target_mac, macinfo->gldm_addrlen);
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	nmp->b_rptr -= LLC_HDR1_LEN;
19310Sstevel@tonic-gate 	nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
19320Sstevel@tonic-gate 	nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
19330Sstevel@tonic-gate 	nsnaphdr->control = CNTL_LLC_UI;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	if (rh == NULL || (rh->rt & 0x06) == 0x06 ||
19360Sstevel@tonic-gate 	    rh->len > sizeof (struct gld_ri)) {
19370Sstevel@tonic-gate 		/* no RIF (Event 8), or RIF type STE (Event 9): send ARE RQR */
19380Sstevel@tonic-gate 		nmp->b_rptr -= 2;
19390Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
19400Sstevel@tonic-gate 		nrh->len = 2;
19410Sstevel@tonic-gate 		nrh->rt = RT_ARE;
19420Sstevel@tonic-gate 		nrh->dir = 0;
19430Sstevel@tonic-gate 		nrh->res = 0;
19440Sstevel@tonic-gate 		nrh->mtu = RT_MTU_MAX;
19450Sstevel@tonic-gate 	} else {
19460Sstevel@tonic-gate 		/*
19470Sstevel@tonic-gate 		 * RIF must be ARE (Event 10) or SRF (Event 11):
19480Sstevel@tonic-gate 		 * send SRF (reverse) RQR
19490Sstevel@tonic-gate 		 */
19500Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
19510Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
19520Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
19530Sstevel@tonic-gate 		bcopy(rh, nrh, rh->len);	/* copy incoming RIF */
19540Sstevel@tonic-gate 		nrh->rt = RT_SRF;		/* make it SRF */
19550Sstevel@tonic-gate 		nrh->dir ^= 1;			/* reverse direction */
19560Sstevel@tonic-gate 	}
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
19590Sstevel@tonic-gate 	nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
19600Sstevel@tonic-gate 	nmh->tr_ac = 0x10;
19610Sstevel@tonic-gate 	nmh->tr_fc = 0x40;
19620Sstevel@tonic-gate 	mac_copy(shost, nmh->tr_dhost, macinfo->gldm_addrlen);
19630Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
19640Sstevel@tonic-gate 	    nmh->tr_shost, macinfo->gldm_addrlen);
19650Sstevel@tonic-gate 	nmh->tr_shost[0] |= 0x80;		/* indicate RIF present */
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	/*
19680Sstevel@tonic-gate 	 * Packet assembled; send it.
19690Sstevel@tonic-gate 	 *
19700Sstevel@tonic-gate 	 * As noted before, this is not really a good time to be trying to
19710Sstevel@tonic-gate 	 * send out packets.  We have no obvious queue to use if the packet
19720Sstevel@tonic-gate 	 * can't be sent right away.  We pick one arbitrarily.
19730Sstevel@tonic-gate 	 */
19740Sstevel@tonic-gate 	{
19750Sstevel@tonic-gate 	gld_vlan_t *vlan;
19760Sstevel@tonic-gate 	queue_t *q;
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
19790Sstevel@tonic-gate 		/* oops, no vlan on the list for this macinfo! */
19800Sstevel@tonic-gate 		/* this should not happen */
19810Sstevel@tonic-gate 		freeb(nmp);
19820Sstevel@tonic-gate 		return;
19830Sstevel@tonic-gate 	}
19840Sstevel@tonic-gate 	q = vlan->gldv_str_next->gld_qptr;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	/*
19870Sstevel@tonic-gate 	 * Queue the packet and let gld_wsrv
19880Sstevel@tonic-gate 	 * handle it, thus preventing a panic
19890Sstevel@tonic-gate 	 * caused by v2 TR in promiscuous mode
19900Sstevel@tonic-gate 	 * where it attempts to get the mutex
19910Sstevel@tonic-gate 	 * in this thread while already holding
19920Sstevel@tonic-gate 	 * it.
19930Sstevel@tonic-gate 	 */
19940Sstevel@tonic-gate 	(void) putbq(WR(q), nmp);
19950Sstevel@tonic-gate 	qenable(WR(q));
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate /*
20000Sstevel@tonic-gate  * This routine implements a modified subset of the 802.2 RDE RCC send actions:
20010Sstevel@tonic-gate  *   we implement RCC send events 5 to 10 (ISO 8802-2:1994 9.6.3.5);
20020Sstevel@tonic-gate  *   we omit special handling for the NULL SAP;
20030Sstevel@tonic-gate  *   events 11 to 12 are handled by gld_rde_pdu_req below;
20040Sstevel@tonic-gate  *   we require an immediate response to our GET_ROUTE_REQUEST.
20050Sstevel@tonic-gate  */
20060Sstevel@tonic-gate static void
gld_rcc_send(gld_mac_info_t * macinfo,queue_t * q,uchar_t * dhost,struct gld_ri ** rhp,uchar_t * llcpkt)20070Sstevel@tonic-gate gld_rcc_send(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
20080Sstevel@tonic-gate     struct gld_ri **rhp, uchar_t *llcpkt)
20090Sstevel@tonic-gate {
20100Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	/*
20130Sstevel@tonic-gate 	 * Our caller has to take the mutex because: to avoid an extra bcopy
20140Sstevel@tonic-gate 	 * of the RIF on every transmit, we pass back a pointer to our sr
20150Sstevel@tonic-gate 	 * table entry via rhp.  He has to keep the mutex until he has a
20160Sstevel@tonic-gate 	 * chance to copy the RIF out into the outgoing packet, so that we
20170Sstevel@tonic-gate 	 * don't modify the entry while he's trying to copy it.  This is a
20180Sstevel@tonic-gate 	 * little ugly, but saves the extra bcopy.
20190Sstevel@tonic-gate 	 */
20200Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	*rhp = (struct gld_ri *)NULL;	/* start off clean (no RIF) */
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 	if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled) {
20250Sstevel@tonic-gate 		/* RDE is disabled -- use NULL or STE always */
20260Sstevel@tonic-gate 		if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
20270Sstevel@tonic-gate 		    rde_str_indicator_ste)
20280Sstevel@tonic-gate 			*rhp = &ri_ste_def;	/* STE option */
20290Sstevel@tonic-gate 		return;
20300Sstevel@tonic-gate 	}
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	if (!(dhost[0] & 0x80)) {
20330Sstevel@tonic-gate 		/* individual address; Events 7 - 10 */
20340Sstevel@tonic-gate 		if ((snaphdr->control & 0xef) == 0xe3) {
20350Sstevel@tonic-gate 			/* TEST command, reset the route */
20360Sstevel@tonic-gate 			gld_reset_route(macinfo, q,
20370Sstevel@tonic-gate 			    dhost, snaphdr->d_lsap, snaphdr->s_lsap);
20380Sstevel@tonic-gate 		}
20390Sstevel@tonic-gate 		gld_get_route(macinfo, q,
20400Sstevel@tonic-gate 		    dhost, rhp, snaphdr->d_lsap, snaphdr->s_lsap);
20410Sstevel@tonic-gate 	}
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	if (*rhp == NULL) {
20440Sstevel@tonic-gate 		/*
20450Sstevel@tonic-gate 		 * group address (Events 5 - 6),
20460Sstevel@tonic-gate 		 * or no route available (Events 8 - 9):
20470Sstevel@tonic-gate 		 * Need to send NSR or STE, as configured.
20480Sstevel@tonic-gate 		 */
20490Sstevel@tonic-gate 		if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
20500Sstevel@tonic-gate 		    rde_str_indicator_ste)
20510Sstevel@tonic-gate 			*rhp = &ri_ste_def;	/* STE option */
20520Sstevel@tonic-gate 	}
20530Sstevel@tonic-gate }
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate /*
20560Sstevel@tonic-gate  * RCC send events 11 - 12
20570Sstevel@tonic-gate  *
20580Sstevel@tonic-gate  * At present we only handle the RQC ptype.
20590Sstevel@tonic-gate  *
20600Sstevel@tonic-gate  * We "know" that the only time we can get here is from the "unitdata"
20610Sstevel@tonic-gate  * routine, called at wsrv time.
20620Sstevel@tonic-gate  *
20630Sstevel@tonic-gate  * If we ever implement the RS ptype (Event 13), this may no longer be true!
20640Sstevel@tonic-gate  */
20650Sstevel@tonic-gate static void
gld_rde_pdu_req(gld_mac_info_t * macinfo,queue_t * q,uchar_t * dhost,struct gld_ri * rh,uchar_t dsap,uchar_t ssap,uchar_t ptype)20660Sstevel@tonic-gate gld_rde_pdu_req(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
20670Sstevel@tonic-gate     struct gld_ri *rh, uchar_t dsap, uchar_t ssap, uchar_t ptype)
20680Sstevel@tonic-gate {
20690Sstevel@tonic-gate 	mblk_t *nmp;
20700Sstevel@tonic-gate 	int nlen;
20710Sstevel@tonic-gate 	struct tr_mac_frm_nori *nmh;
20720Sstevel@tonic-gate 	struct gld_ri *nrh;
20730Sstevel@tonic-gate 	struct llc_snap_hdr *nsnaphdr;
20740Sstevel@tonic-gate 	struct rde_pdu *npdu;
20750Sstevel@tonic-gate 	int srpresent = 0;
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 	/* if you change this to process other types, review all code below */
20780Sstevel@tonic-gate 	ASSERT(ptype == RDE_RQC);
20790Sstevel@tonic-gate 	ASSERT(rh == NULL);	/* RQC never uses SRF */
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
20820Sstevel@tonic-gate 	    sizeof (struct rde_pdu);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
20850Sstevel@tonic-gate 		return;
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct rde_pdu);
20900Sstevel@tonic-gate 	npdu = (struct rde_pdu *)(nmp->b_rptr);
20910Sstevel@tonic-gate 	npdu->rde_ver = 1;
20920Sstevel@tonic-gate 	npdu->rde_ptype = ptype;
20930Sstevel@tonic-gate 	mac_copy(dhost, &npdu->rde_target_mac, 6);
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 	/*
20960Sstevel@tonic-gate 	 * access the mac address without a mutex - take a risk -
20970Sstevel@tonic-gate 	 * to prevent mutex contention (BUG 4211361)
20980Sstevel@tonic-gate 	 */
20990Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
21000Sstevel@tonic-gate 	    &npdu->rde_orig_mac, 6);
21010Sstevel@tonic-gate 	npdu->rde_target_sap = dsap;
21020Sstevel@tonic-gate 	npdu->rde_orig_sap = ssap;
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 	nmp->b_rptr -= LLC_HDR1_LEN;
21050Sstevel@tonic-gate 	nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
21060Sstevel@tonic-gate 	nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
21070Sstevel@tonic-gate 	nsnaphdr->control = CNTL_LLC_UI;
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate #if 0	/* we don't need this for now */
21100Sstevel@tonic-gate 	if (rh != NULL) {
21110Sstevel@tonic-gate 		/* send an SRF frame with specified RIF */
21120Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
21130Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
21140Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
21150Sstevel@tonic-gate 		bcopy(rh, nrh, rh->len);
21160Sstevel@tonic-gate 		ASSERT(nrh->rt == RT_SRF);
21170Sstevel@tonic-gate 		srpresent = 1;
21180Sstevel@tonic-gate 	} else
21190Sstevel@tonic-gate #endif
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	/* Need to send NSR or STE, as configured.  */
21220Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
21230Sstevel@tonic-gate 		/* send an STE frame */
21240Sstevel@tonic-gate 		nmp->b_rptr -= 2;
21250Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
21260Sstevel@tonic-gate 		nrh->len = 2;
21270Sstevel@tonic-gate 		nrh->rt = RT_STE;
21280Sstevel@tonic-gate 		nrh->dir = 0;
21290Sstevel@tonic-gate 		nrh->res = 0;
21300Sstevel@tonic-gate 		nrh->mtu = RT_MTU_MAX;
21310Sstevel@tonic-gate 		srpresent = 1;
21320Sstevel@tonic-gate 	} /* else send an NSR frame */
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
21350Sstevel@tonic-gate 	nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
21360Sstevel@tonic-gate 	nmh->tr_ac = 0x10;
21370Sstevel@tonic-gate 	nmh->tr_fc = 0x40;
21380Sstevel@tonic-gate 	mac_copy(dhost, nmh->tr_dhost, macinfo->gldm_addrlen);
21390Sstevel@tonic-gate 	/*
21400Sstevel@tonic-gate 	 * access the mac address without a mutex - take a risk -
21410Sstevel@tonic-gate 	 * to prevent mutex contention  - BUG 4211361
21420Sstevel@tonic-gate 	 */
21430Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
21440Sstevel@tonic-gate 	    nmh->tr_shost, macinfo->gldm_addrlen);
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	if (srpresent)
21470Sstevel@tonic-gate 		nmh->tr_shost[0] |= 0x80;
21480Sstevel@tonic-gate 	else
21490Sstevel@tonic-gate 		nmh->tr_shost[0] &= ~0x80;
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 	/*
21520Sstevel@tonic-gate 	 * Packet assembled; send it.
21530Sstevel@tonic-gate 	 *
21540Sstevel@tonic-gate 	 * Since we own the SR_MUTEX, we don't want to take the maclock
21550Sstevel@tonic-gate 	 * mutex (since they are acquired in the opposite order on the
21560Sstevel@tonic-gate 	 * receive path, so deadlock could occur).  We could rearrange
21570Sstevel@tonic-gate 	 * the code in gld_get_route() and drop the SR_MUTEX around the
21580Sstevel@tonic-gate 	 * call to gld_rde_pdu_req(), but that's kind of ugly.  Rather,
21590Sstevel@tonic-gate 	 * we just refrain from calling gld_start() from here, and
21600Sstevel@tonic-gate 	 * instead just queue the packet for wsrv to send next.  Besides,
21610Sstevel@tonic-gate 	 * it's more important to get the packet we're working on out
21620Sstevel@tonic-gate 	 * quickly than this RQC.
21630Sstevel@tonic-gate 	 */
21640Sstevel@tonic-gate 	(void) putbq(WR(q), nmp);
21650Sstevel@tonic-gate 	qenable(WR(q));
21660Sstevel@tonic-gate }
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate /*
21690Sstevel@tonic-gate  * Route Determination Component (RDC)
21700Sstevel@tonic-gate  *
21710Sstevel@tonic-gate  * We do not implement separate routes for each SAP, as specified by
21720Sstevel@tonic-gate  * ISO 8802-2; instead we implement only one route per remote mac address.
21730Sstevel@tonic-gate  */
21740Sstevel@tonic-gate static void
gld_get_route(gld_mac_info_t * macinfo,queue_t * q,uchar_t * dhost,struct gld_ri ** rhp,uchar_t dsap,uchar_t ssap)21750Sstevel@tonic-gate gld_get_route(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
21760Sstevel@tonic-gate     struct gld_ri **rhp, uchar_t dsap, uchar_t ssap)
21770Sstevel@tonic-gate {
21780Sstevel@tonic-gate 	struct srtab *sr;
21790Sstevel@tonic-gate 	clock_t t = ddi_get_lbolt();
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	sr = gld_sr_lookup_entry(macinfo, dhost);
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	if (sr == NULL) {
21860Sstevel@tonic-gate 		/*
21870Sstevel@tonic-gate 		 * we have no entry -- never heard of this address:
21880Sstevel@tonic-gate 		 * create an empty entry and initiate RQC
21890Sstevel@tonic-gate 		 */
21900Sstevel@tonic-gate 		sr = gld_sr_create_entry(macinfo, dhost);
21910Sstevel@tonic-gate 		gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
21920Sstevel@tonic-gate 		    dsap, ssap, RDE_RQC);
21930Sstevel@tonic-gate 		if (sr)
21940Sstevel@tonic-gate 			sr->sr_timer = t;
21950Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route yet */
21960Sstevel@tonic-gate 		return;
21970Sstevel@tonic-gate 	}
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 	/* we have an entry; see if we know a route yet */
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	if (sr->sr_ri.len == 0) {
22020Sstevel@tonic-gate 		/* Have asked RQC, but no reply (yet) */
22030Sstevel@tonic-gate 		if (t - sr->sr_timer >
22040Sstevel@tonic-gate 		    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
22050Sstevel@tonic-gate 			/* RQR overdue, resend RQC */
22060Sstevel@tonic-gate 			gld_rde_pdu_req(macinfo, q, dhost,
22070Sstevel@tonic-gate 			    (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
22080Sstevel@tonic-gate 			sr->sr_timer = t;
22090Sstevel@tonic-gate 		}
22100Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route yet */
22110Sstevel@tonic-gate 		return;
22120Sstevel@tonic-gate 	}
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	/* we know a route, or it's local */
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	/* if it might be stale, reset and get a new one */
22170Sstevel@tonic-gate 	if (t - sr->sr_timer >
22180Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
22190Sstevel@tonic-gate 		gld_rde_pdu_req(macinfo, q, dhost,
22200Sstevel@tonic-gate 		    (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
22210Sstevel@tonic-gate 		sr->sr_ri.len = 0;
22220Sstevel@tonic-gate 		sr->sr_timer = t;
22230Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route */
22240Sstevel@tonic-gate 		return;
22250Sstevel@tonic-gate 	}
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	if (sr->sr_ri.len == 2) {
22280Sstevel@tonic-gate 		/* the remote site is on our local ring -- no route needed */
22290Sstevel@tonic-gate 		*rhp = NULL;
22300Sstevel@tonic-gate 		return;
22310Sstevel@tonic-gate 	}
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 	*rhp = &sr->sr_ri;	/* we have a route, return it */
22340Sstevel@tonic-gate }
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate /*
22370Sstevel@tonic-gate  * zap the specified entry and reinitiate RQC
22380Sstevel@tonic-gate  */
22390Sstevel@tonic-gate static void
gld_reset_route(gld_mac_info_t * macinfo,queue_t * q,uchar_t * dhost,uchar_t dsap,uchar_t ssap)22400Sstevel@tonic-gate gld_reset_route(gld_mac_info_t *macinfo, queue_t *q,
22410Sstevel@tonic-gate     uchar_t *dhost, uchar_t dsap, uchar_t ssap)
22420Sstevel@tonic-gate {
22430Sstevel@tonic-gate 	struct srtab *sr;
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 	sr = gld_sr_create_entry(macinfo, dhost);
22480Sstevel@tonic-gate 	gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
22490Sstevel@tonic-gate 	    dsap, ssap, RDE_RQC);
22500Sstevel@tonic-gate 	if (sr == NULL)
22510Sstevel@tonic-gate 		return;
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	sr->sr_ri.len = 0;
22540Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
22550Sstevel@tonic-gate }
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate /*
22580Sstevel@tonic-gate  * This routine is called when an RDE PDU is received from our peer.
22590Sstevel@tonic-gate  * If it is an RS (Route Selected) PDU, we adopt the specified route.
22600Sstevel@tonic-gate  * If it is an RQR (reply to our previous RQC), we evaluate the
22610Sstevel@tonic-gate  * specified route in comparison with our current known route, if any,
22620Sstevel@tonic-gate  * and we keep the "better" of the two routes.
22630Sstevel@tonic-gate  */
22640Sstevel@tonic-gate static void
gld_rde_pdu_ind(gld_mac_info_t * macinfo,struct gld_ri * rh,struct rde_pdu * pdu,int pdulen)22650Sstevel@tonic-gate gld_rde_pdu_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, struct rde_pdu *pdu,
22660Sstevel@tonic-gate     int pdulen)
22670Sstevel@tonic-gate {
22680Sstevel@tonic-gate 	struct srtab *sr;
22690Sstevel@tonic-gate 	uchar_t *otherhost;
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 	if (pdulen < sizeof (struct rde_pdu))
22720Sstevel@tonic-gate 		return;		/* Bad incoming PDU */
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQC)
22750Sstevel@tonic-gate 		return;			/* ignore RQC */
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 	if (pdu->rde_ptype != RDE_RQR && pdu->rde_ptype != RDE_RS) {
22780Sstevel@tonic-gate #ifdef GLD_DEBUG
22790Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
22800Sstevel@tonic-gate 			cmn_err(CE_WARN, "gld: bogus RDE ptype 0x%x received",
22810Sstevel@tonic-gate 			    pdu->rde_ptype);
22820Sstevel@tonic-gate #endif
22830Sstevel@tonic-gate 		return;
22840Sstevel@tonic-gate 	}
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 	if (rh == NULL) {
22870Sstevel@tonic-gate #ifdef GLD_DEBUG
22880Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
22890Sstevel@tonic-gate 			cmn_err(CE_WARN,
22900Sstevel@tonic-gate 			    "gld: bogus NULL RIF, ptype 0x%x received",
22910Sstevel@tonic-gate 			    pdu->rde_ptype);
22920Sstevel@tonic-gate #endif
22930Sstevel@tonic-gate 		return;
22940Sstevel@tonic-gate 	}
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate 	ASSERT(rh->len >= 2);
22970Sstevel@tonic-gate 	ASSERT(rh->len <= sizeof (struct gld_ri));
22980Sstevel@tonic-gate 	ASSERT((rh->len & 1) == 0);
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQR) {
23010Sstevel@tonic-gate 		/* A reply to our RQC has his address as target mac */
23020Sstevel@tonic-gate 		otherhost = pdu->rde_target_mac;
23030Sstevel@tonic-gate 	} else {
23040Sstevel@tonic-gate 		ASSERT(pdu->rde_ptype == RDE_RS);
23050Sstevel@tonic-gate 		/* An RS has his address as orig mac */
23060Sstevel@tonic-gate 		otherhost = pdu->rde_orig_mac;
23070Sstevel@tonic-gate 	}
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	if ((sr = gld_sr_create_entry(macinfo, otherhost)) == NULL) {
23120Sstevel@tonic-gate 		mutex_exit(GLD_SR_MUTEX(macinfo));
23130Sstevel@tonic-gate 		return;		/* oh well, out of memory */
23140Sstevel@tonic-gate 	}
23150Sstevel@tonic-gate 
23160Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQR) {
23170Sstevel@tonic-gate 		/* see if new route is better than what we may already have */
23180Sstevel@tonic-gate 		if (sr->sr_ri.len != 0 &&
23190Sstevel@tonic-gate 		    sr->sr_ri.len <= rh->len) {
23200Sstevel@tonic-gate 			mutex_exit(GLD_SR_MUTEX(macinfo));
23210Sstevel@tonic-gate 			return;	/* we have one, and new one is no shorter */
23220Sstevel@tonic-gate 		}
23230Sstevel@tonic-gate 	}
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	/* adopt the new route */
23260Sstevel@tonic-gate 	bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
23270Sstevel@tonic-gate 	sr->sr_ri.rt = RT_SRF;	/* make it a clean SRF */
23280Sstevel@tonic-gate 	sr->sr_ri.dir ^= 1;	/* reverse direction */
23290Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
23320Sstevel@tonic-gate }
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate /*
23350Sstevel@tonic-gate  * This routine is called when a packet with a RIF is received.  Our
23360Sstevel@tonic-gate  * policy is to adopt the route.
23370Sstevel@tonic-gate  */
23380Sstevel@tonic-gate /* ARGSUSED3 */
23390Sstevel@tonic-gate static void
gld_rif_ind(gld_mac_info_t * macinfo,struct gld_ri * rh,uchar_t * shost,uchar_t ssap,uchar_t dsap)23400Sstevel@tonic-gate gld_rif_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, uchar_t *shost,
23410Sstevel@tonic-gate     uchar_t ssap, uchar_t dsap)
23420Sstevel@tonic-gate {
23430Sstevel@tonic-gate 	struct srtab *sr;
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	ASSERT(rh != NULL);		/* ensure RIF */
23460Sstevel@tonic-gate 	ASSERT((rh->rt & 0x04) == 0);	/* ensure SRF */
23470Sstevel@tonic-gate 	ASSERT(rh->len >= 2);
23480Sstevel@tonic-gate 	ASSERT(rh->len <= sizeof (struct gld_ri));
23490Sstevel@tonic-gate 	ASSERT((rh->len & 1) == 0);
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	if ((sr = gld_sr_create_entry(macinfo, shost)) == NULL) {
23540Sstevel@tonic-gate 		mutex_exit(GLD_SR_MUTEX(macinfo));
23550Sstevel@tonic-gate 		return;		/* oh well, out of memory */
23560Sstevel@tonic-gate 	}
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	/* we have an entry; fill it in */
23590Sstevel@tonic-gate 	bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
23600Sstevel@tonic-gate 	sr->sr_ri.rt = RT_SRF;	/* make it a clean SRF */
23610Sstevel@tonic-gate 	sr->sr_ri.dir ^= 1;	/* reverse direction */
23620Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
23630Sstevel@tonic-gate 
23640Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
23650Sstevel@tonic-gate }
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate static struct srtab **
gld_sr_hash(struct srtab ** sr_hash_tbl,uchar_t * addr,int addr_length)23680Sstevel@tonic-gate gld_sr_hash(struct srtab **sr_hash_tbl, uchar_t *addr, int addr_length)
23690Sstevel@tonic-gate {
23700Sstevel@tonic-gate 	uint_t hashval = 0;
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	while (--addr_length >= 0)
23730Sstevel@tonic-gate 		hashval ^= *addr++;
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 	return (&sr_hash_tbl[hashval % SR_HASH_SIZE]);
23760Sstevel@tonic-gate }
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate static struct srtab *
gld_sr_lookup_entry(gld_mac_info_t * macinfo,uchar_t * macaddr)23790Sstevel@tonic-gate gld_sr_lookup_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
23800Sstevel@tonic-gate {
23810Sstevel@tonic-gate 	struct srtab *sr;
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	for (sr = *gld_sr_hash(GLD_SR_HASH(macinfo), macaddr,
23860Sstevel@tonic-gate 	    macinfo->gldm_addrlen); sr; sr = sr->sr_next)
23870Sstevel@tonic-gate 		if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
23880Sstevel@tonic-gate 			return (sr);
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 	return ((struct srtab *)0);
23910Sstevel@tonic-gate }
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate static struct srtab *
gld_sr_create_entry(gld_mac_info_t * macinfo,uchar_t * macaddr)23940Sstevel@tonic-gate gld_sr_create_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
23950Sstevel@tonic-gate {
23960Sstevel@tonic-gate 	struct srtab *sr;
23970Sstevel@tonic-gate 	struct srtab **srp;
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	ASSERT(!(macaddr[0] & 0x80));	/* no group addresses here */
24000Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 	srp = gld_sr_hash(GLD_SR_HASH(macinfo), macaddr, macinfo->gldm_addrlen);
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	for (sr = *srp; sr; sr = sr->sr_next)
24050Sstevel@tonic-gate 		if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
24060Sstevel@tonic-gate 			return (sr);
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate 	if (!(sr = kmem_zalloc(sizeof (struct srtab), KM_NOSLEEP))) {
24090Sstevel@tonic-gate #ifdef GLD_DEBUG
24100Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
24110Sstevel@tonic-gate 			cmn_err(CE_WARN,
24120Sstevel@tonic-gate 			    "gld: gld_sr_create_entry kmem_alloc failed");
24130Sstevel@tonic-gate #endif
24140Sstevel@tonic-gate 		return ((struct srtab *)0);
24150Sstevel@tonic-gate 	}
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 	bcopy((caddr_t)macaddr, (caddr_t)sr->sr_mac, macinfo->gldm_addrlen);
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate 	sr->sr_next = *srp;
24200Sstevel@tonic-gate 	*srp = sr;
24210Sstevel@tonic-gate 	return (sr);
24220Sstevel@tonic-gate }
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate static void
gld_sr_clear(gld_mac_info_t * macinfo)24250Sstevel@tonic-gate gld_sr_clear(gld_mac_info_t *macinfo)
24260Sstevel@tonic-gate {
24270Sstevel@tonic-gate 	int i;
24280Sstevel@tonic-gate 	struct srtab **sr_hash_tbl = GLD_SR_HASH(macinfo);
24290Sstevel@tonic-gate 	struct srtab **srp, *sr;
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate 	/*
24320Sstevel@tonic-gate 	 * Walk through the table, deleting all entries.
24330Sstevel@tonic-gate 	 *
24340Sstevel@tonic-gate 	 * Only called from uninit, so don't need the mutex.
24350Sstevel@tonic-gate 	 */
24360Sstevel@tonic-gate 	for (i = 0; i < SR_HASH_SIZE; i++) {
24370Sstevel@tonic-gate 		for (srp = &sr_hash_tbl[i]; (sr = *srp) != NULL; ) {
24380Sstevel@tonic-gate 			*srp = sr->sr_next;
24390Sstevel@tonic-gate 			kmem_free((char *)sr, sizeof (struct srtab));
24400Sstevel@tonic-gate 		}
24410Sstevel@tonic-gate 	}
24420Sstevel@tonic-gate }
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate #ifdef	DEBUG
24450Sstevel@tonic-gate void
gld_sr_dump(gld_mac_info_t * macinfo)24460Sstevel@tonic-gate gld_sr_dump(gld_mac_info_t *macinfo)
24470Sstevel@tonic-gate {
24480Sstevel@tonic-gate 	int i, j;
24490Sstevel@tonic-gate 	struct srtab **sr_hash_tbl;
24500Sstevel@tonic-gate 	struct srtab *sr;
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate 	sr_hash_tbl = GLD_SR_HASH(macinfo);
24530Sstevel@tonic-gate 	if (sr_hash_tbl == NULL)
24540Sstevel@tonic-gate 		return;
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	/*
24590Sstevel@tonic-gate 	 * Walk through the table, printing all entries
24600Sstevel@tonic-gate 	 */
24610Sstevel@tonic-gate 	cmn_err(CE_NOTE, "GLD Source Routing Table (0x%p):", (void *)macinfo);
24620Sstevel@tonic-gate 	cmn_err(CE_CONT, "Addr len,rt,dir,mtu,res rng,brg0 rng,brg1...\n");
24630Sstevel@tonic-gate 	for (i = 0; i < SR_HASH_SIZE; i++) {
24640Sstevel@tonic-gate 		for (sr = sr_hash_tbl[i]; sr; sr = sr->sr_next) {
24650Sstevel@tonic-gate 			cmn_err(CE_CONT,
24660Sstevel@tonic-gate 			    "%x:%x:%x:%x:%x:%x %d,%x,%x,%x,%x ",
24670Sstevel@tonic-gate 			    sr->sr_mac[0], sr->sr_mac[1], sr->sr_mac[2],
24680Sstevel@tonic-gate 			    sr->sr_mac[3], sr->sr_mac[4], sr->sr_mac[5],
24690Sstevel@tonic-gate 			    sr->sr_ri.len, sr->sr_ri.rt, sr->sr_ri.dir,
24700Sstevel@tonic-gate 			    sr->sr_ri.mtu, sr->sr_ri.res);
24710Sstevel@tonic-gate 			if (sr->sr_ri.len)
24720Sstevel@tonic-gate 				for (j = 0; j < (sr->sr_ri.len - 2) / 2; j++)
24730Sstevel@tonic-gate 					cmn_err(CE_CONT, "%x ",
24740Sstevel@tonic-gate 					    REF_NET_USHORT(*(unsigned short *)
24750Sstevel@tonic-gate 					    &sr->sr_ri.rd[j]));
24760Sstevel@tonic-gate 			cmn_err(CE_CONT, "\n");
24770Sstevel@tonic-gate 		}
24780Sstevel@tonic-gate 	}
24790Sstevel@tonic-gate 
24800Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
24810Sstevel@tonic-gate }
24820Sstevel@tonic-gate #endif
2483