xref: /titanic_51/usr/src/uts/common/io/gldutil.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * gld - Generic LAN Driver
30*7c478bd9Sstevel@tonic-gate  * media dependent routines
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/gld.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/gldpriv.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/pattr.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	DLSAPLENGTH(macinfo) \
57*7c478bd9Sstevel@tonic-gate 	((macinfo)->gldm_addrlen + ABS((macinfo)->gldm_saplen))
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
60*7c478bd9Sstevel@tonic-gate extern int gld_debug;
61*7c478bd9Sstevel@tonic-gate #endif
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate extern void gld_bitrevcopy(caddr_t src, caddr_t target, size_t n);
64*7c478bd9Sstevel@tonic-gate extern char *gld_macaddr_sprintf(char *, unsigned char *, int);
65*7c478bd9Sstevel@tonic-gate extern gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
66*7c478bd9Sstevel@tonic-gate extern uint32_t gld_global_options;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate static struct	llc_snap_hdr llc_snap_def = {
69*7c478bd9Sstevel@tonic-gate 	LSAP_SNAP,		/* DLSAP 0xaa */
70*7c478bd9Sstevel@tonic-gate 	LSAP_SNAP,		/* SLSAP 0xaa */
71*7c478bd9Sstevel@tonic-gate 	CNTL_LLC_UI,		/* Control 0x03 */
72*7c478bd9Sstevel@tonic-gate 	0x00, 0x00, 0x00,	/* Org[3] */
73*7c478bd9Sstevel@tonic-gate 	0x00			/* Type */
74*7c478bd9Sstevel@tonic-gate };
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #define	ISETHERTYPE(snaphdr) \
77*7c478bd9Sstevel@tonic-gate 	(snaphdr->d_lsap == LSAP_SNAP && \
78*7c478bd9Sstevel@tonic-gate 	snaphdr->s_lsap == LSAP_SNAP && \
79*7c478bd9Sstevel@tonic-gate 	snaphdr->control == CNTL_LLC_UI && \
80*7c478bd9Sstevel@tonic-gate 	snaphdr->org[0] == 0 && \
81*7c478bd9Sstevel@tonic-gate 	snaphdr->org[1] == 0 && \
82*7c478bd9Sstevel@tonic-gate 	snaphdr->org[2] == 0)
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /* ======== */
85*7c478bd9Sstevel@tonic-gate /* Ethernet */
86*7c478bd9Sstevel@tonic-gate /* ======== */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static mac_addr_t ether_broadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate void
91*7c478bd9Sstevel@tonic-gate gld_init_ether(gld_mac_info_t *macinfo)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	struct gldkstats *sp =
94*7c478bd9Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	/* Assumptions we make for this medium */
97*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_ETHER);
98*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
99*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
100*7c478bd9Sstevel@tonic-gate #ifndef	lint
101*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (struct ether_mac_frm) == 14);
102*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
103*7c478bd9Sstevel@tonic-gate #endif
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_frame, "align_errors", KSTAT_DATA_ULONG);
106*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_crc, "fcs_errors", KSTAT_DATA_ULONG);
107*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_collisions, "collisions", KSTAT_DATA_ULONG);
108*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_nocarrier, "carrier_errors",
109*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_ULONG);
110*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_defer, "defer_xmts", KSTAT_DATA_ULONG);
111*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtlatecoll, "tx_late_collisions",
112*7c478bd9Sstevel@tonic-gate 					KSTAT_DATA_ULONG);
113*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_short, "runt_errors", KSTAT_DATA_ULONG);
114*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_excoll, "ex_collisions", KSTAT_DATA_ULONG);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	/*
117*7c478bd9Sstevel@tonic-gate 	 * only initialize the new statistics if the driver
118*7c478bd9Sstevel@tonic-gate 	 * knows about them.
119*7c478bd9Sstevel@tonic-gate 	 */
120*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION_200)
121*7c478bd9Sstevel@tonic-gate 		return;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_first_coll,
124*7c478bd9Sstevel@tonic-gate 	    "first_collisions", KSTAT_DATA_UINT32);
125*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_multi_coll,
126*7c478bd9Sstevel@tonic-gate 	    "multi_collisions", KSTAT_DATA_UINT32);
127*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_sqe_error,
128*7c478bd9Sstevel@tonic-gate 	    "sqe_errors", KSTAT_DATA_UINT32);
129*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_mac_xmt_error,
130*7c478bd9Sstevel@tonic-gate 	    "macxmt_errors", KSTAT_DATA_UINT32);
131*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_mac_rcv_error,
132*7c478bd9Sstevel@tonic-gate 	    "macrcv_errors", KSTAT_DATA_UINT32);
133*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot3_frame_too_long,
134*7c478bd9Sstevel@tonic-gate 	    "toolong_errors", KSTAT_DATA_UINT32);
135*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_duplex, "duplex", KSTAT_DATA_CHAR);
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
139*7c478bd9Sstevel@tonic-gate void
140*7c478bd9Sstevel@tonic-gate gld_uninit_ether(gld_mac_info_t *macinfo)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate int
145*7c478bd9Sstevel@tonic-gate gld_interpret_ether(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
146*7c478bd9Sstevel@tonic-gate     packet_flag_t flags)
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate 	struct ether_mac_frm *mh;
149*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
150*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
151*7c478bd9Sstevel@tonic-gate 	mblk_t *pmp = NULL;
152*7c478bd9Sstevel@tonic-gate 	unsigned short typelen;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	/*
155*7c478bd9Sstevel@tonic-gate 	 * Quickly handle receive fastpath for IPQ hack.
156*7c478bd9Sstevel@tonic-gate 	 */
157*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
158*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
159*7c478bd9Sstevel@tonic-gate 		/*
160*7c478bd9Sstevel@tonic-gate 		 * Check whether the header is contiguous, which
161*7c478bd9Sstevel@tonic-gate 		 * also implicitly makes sure the packet is big enough.
162*7c478bd9Sstevel@tonic-gate 		 */
163*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (struct ether_mac_frm))
164*7c478bd9Sstevel@tonic-gate 			return (-1);
165*7c478bd9Sstevel@tonic-gate 		mh = (struct ether_mac_frm *)mp->b_rptr;
166*7c478bd9Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(mh->ether_type);
167*7c478bd9Sstevel@tonic-gate 		pktinfo->isForMe = mac_eq(mh->ether_dhost,
168*7c478bd9Sstevel@tonic-gate 		    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
169*7c478bd9Sstevel@tonic-gate 		pktinfo->macLen = sizeof (struct ether_mac_frm);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 		return (0);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
179*7c478bd9Sstevel@tonic-gate 	if (pktinfo->pktLen < sizeof (struct ether_mac_frm))
180*7c478bd9Sstevel@tonic-gate 		return (-1);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
183*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct ether_mac_frm)) {
184*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
185*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
186*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
187*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
188*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_ether cannot msgpullup");
189*7c478bd9Sstevel@tonic-gate #endif
190*7c478bd9Sstevel@tonic-gate 			return (-1);
191*7c478bd9Sstevel@tonic-gate 		}
192*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	mh = (struct ether_mac_frm *)mp->b_rptr;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
198*7c478bd9Sstevel@tonic-gate 	if (mac_eq(mh->ether_dhost, ether_broadcast, macinfo->gldm_addrlen))
199*7c478bd9Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
200*7c478bd9Sstevel@tonic-gate 	else if (mh->ether_dhost[0] & 1)
201*7c478bd9Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	typelen = REF_NET_USHORT(mh->ether_type);
204*7c478bd9Sstevel@tonic-gate 	/*
205*7c478bd9Sstevel@tonic-gate 	 * If the hardware is capable of VLAN tag insertion
206*7c478bd9Sstevel@tonic-gate 	 * strip out the VLAN tag info. Knowing hardware is
207*7c478bd9Sstevel@tonic-gate 	 * capable of VLAN can be established by the presance
208*7c478bd9Sstevel@tonic-gate 	 * of non null 'macinfo->gldm_send_tagged'.
209*7c478bd9Sstevel@tonic-gate 	 */
210*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_TX) {
211*7c478bd9Sstevel@tonic-gate 		if ((typelen == VLAN_TPID) &&
212*7c478bd9Sstevel@tonic-gate 			(macinfo->gldm_send_tagged != NULL)) {
213*7c478bd9Sstevel@tonic-gate 			ovbcopy(mp->b_rptr,
214*7c478bd9Sstevel@tonic-gate 					mp->b_rptr + VTAG_SIZE,
215*7c478bd9Sstevel@tonic-gate 					2 * ETHERADDRL);
216*7c478bd9Sstevel@tonic-gate 			mp->b_rptr += VTAG_SIZE;
217*7c478bd9Sstevel@tonic-gate 		}
218*7c478bd9Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
219*7c478bd9Sstevel@tonic-gate 	}
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	/*
224*7c478bd9Sstevel@tonic-gate 	 * Deal with the mac header
225*7c478bd9Sstevel@tonic-gate 	 */
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	mac_copy(mh->ether_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
228*7c478bd9Sstevel@tonic-gate 	mac_copy(mh->ether_shost, pktinfo->shost, macinfo->gldm_addrlen);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
231*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
232*7c478bd9Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
233*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	pktinfo->macLen = sizeof (struct ether_mac_frm);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	if (typelen > ETHERMTU) {
238*7c478bd9Sstevel@tonic-gate 		pktinfo->ethertype = typelen; /* use type interpretation */
239*7c478bd9Sstevel@tonic-gate 		goto out;
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Packet is 802.3 so the ether type/length field
244*7c478bd9Sstevel@tonic-gate 	 * specifies the number of bytes that should be present
245*7c478bd9Sstevel@tonic-gate 	 * in the data field.  Additional bytes are padding, and
246*7c478bd9Sstevel@tonic-gate 	 * should be removed
247*7c478bd9Sstevel@tonic-gate 	 */
248*7c478bd9Sstevel@tonic-gate 	{
249*7c478bd9Sstevel@tonic-gate 	int delta = pktinfo->pktLen -
250*7c478bd9Sstevel@tonic-gate 	    (sizeof (struct ether_mac_frm) + typelen);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if (delta > 0 && adjmsg(mp, -delta))
253*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen -= delta;
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	/*
257*7c478bd9Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the LLC
258*7c478bd9Sstevel@tonic-gate 	 * header exists, and that both it and any SNAP header are contiguous.
259*7c478bd9Sstevel@tonic-gate 	 */
260*7c478bd9Sstevel@tonic-gate 	if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
261*7c478bd9Sstevel@tonic-gate 		goto out;	/* LLC hdr should have been there! */
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	pktinfo->isLLC = 1;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	if (gld_global_options & GLD_OPT_NO_ETHRXSNAP ||
266*7c478bd9Sstevel@tonic-gate 	    pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
267*7c478bd9Sstevel@tonic-gate 		goto out;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct ether_mac_frm) + LLC_SNAP_HDR_LEN &&
270*7c478bd9Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
271*7c478bd9Sstevel@tonic-gate 		/*
272*7c478bd9Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
273*7c478bd9Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
274*7c478bd9Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
275*7c478bd9Sstevel@tonic-gate 		 */
276*7c478bd9Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
277*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
278*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
279*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
280*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
281*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_ether cannot msgpullup2");
282*7c478bd9Sstevel@tonic-gate #endif
283*7c478bd9Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
284*7c478bd9Sstevel@tonic-gate 		}
285*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	/*
289*7c478bd9Sstevel@tonic-gate 	 * Check SAP/SNAP information for EtherType.
290*7c478bd9Sstevel@tonic-gate 	 */
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
293*7c478bd9Sstevel@tonic-gate 	if (ISETHERTYPE(snaphdr)) {
294*7c478bd9Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
295*7c478bd9Sstevel@tonic-gate 		pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate out:
298*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL)
299*7c478bd9Sstevel@tonic-gate 		freemsg(pmp);
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	return (0);
302*7c478bd9Sstevel@tonic-gate }
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate mblk_t *
305*7c478bd9Sstevel@tonic-gate gld_unitdata_ether(gld_t *gld, mblk_t *mp)
306*7c478bd9Sstevel@tonic-gate {
307*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
308*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
309*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
310*7c478bd9Sstevel@tonic-gate 	mac_addr_t dhost;
311*7c478bd9Sstevel@tonic-gate 	unsigned short typelen;
312*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
313*7c478bd9Sstevel@tonic-gate 	struct ether_mac_frm *mh;
314*7c478bd9Sstevel@tonic-gate 	int hdrlen;
315*7c478bd9Sstevel@tonic-gate 	uint32_t vptag;
316*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *gld_vlan;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
321*7c478bd9Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
324*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
325*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
326*7c478bd9Sstevel@tonic-gate 		typelen = REF_HOST_USHORT(gldp->glda_sap);
327*7c478bd9Sstevel@tonic-gate 	else
328*7c478bd9Sstevel@tonic-gate 		typelen = gld->gld_sap;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	/*
331*7c478bd9Sstevel@tonic-gate 	 * We take values less than or equal to ETHERMTU to mean that the
332*7c478bd9Sstevel@tonic-gate 	 * packet should not have an encoded EtherType and so we use the
333*7c478bd9Sstevel@tonic-gate 	 * IEEE 802.3 length interpretation of the type/length field.
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 	if (typelen <= ETHERMTU)
336*7c478bd9Sstevel@tonic-gate 		typelen = msgdsize(mp);
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct ether_mac_frm);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	/*
341*7c478bd9Sstevel@tonic-gate 	 * Check to see if VLAN is enabled on this stream
342*7c478bd9Sstevel@tonic-gate 	 * if so then make the header bigger to hold a clone
343*7c478bd9Sstevel@tonic-gate 	 * vlan tag.
344*7c478bd9Sstevel@tonic-gate 	 */
345*7c478bd9Sstevel@tonic-gate 	gld_vlan = (gld_vlan_t *)gld->gld_vlan;
346*7c478bd9Sstevel@tonic-gate 	if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
347*7c478bd9Sstevel@tonic-gate 		hdrlen += VTAG_SIZE;
348*7c478bd9Sstevel@tonic-gate 		vptag = gld_vlan->gldv_ptag;
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
352*7c478bd9Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
353*7c478bd9Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
354*7c478bd9Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
355*7c478bd9Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
356*7c478bd9Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
357*7c478bd9Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
358*7c478bd9Sstevel@tonic-gate 		nmp = mp;
359*7c478bd9Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
360*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
361*7c478bd9Sstevel@tonic-gate 	} else {
362*7c478bd9Sstevel@tonic-gate 		/* we need to allocate one */
363*7c478bd9Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
364*7c478bd9Sstevel@tonic-gate 			return (NULL);
365*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
366*7c478bd9Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
367*7c478bd9Sstevel@tonic-gate 		freeb(mp);
368*7c478bd9Sstevel@tonic-gate 	}
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (typelen);
373*7c478bd9Sstevel@tonic-gate 	SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
374*7c478bd9Sstevel@tonic-gate 	if (hdrlen > sizeof (struct ether_mac_frm)) {
375*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
376*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
377*7c478bd9Sstevel@tonic-gate 		vptag >>= 16;
378*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
379*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= (ETHERADDRL * 2);
382*7c478bd9Sstevel@tonic-gate 	mh = (struct ether_mac_frm *)nmp->b_rptr;
383*7c478bd9Sstevel@tonic-gate 	mac_copy(dhost, mh->ether_dhost, macinfo->gldm_addrlen);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	/*
386*7c478bd9Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
387*7c478bd9Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
388*7c478bd9Sstevel@tonic-gate 	 */
389*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
390*7c478bd9Sstevel@tonic-gate 	    mh->ether_shost, macinfo->gldm_addrlen);
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	return (nmp);
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate mblk_t *
396*7c478bd9Sstevel@tonic-gate gld_fastpath_ether(gld_t *gld, mblk_t *mp)
397*7c478bd9Sstevel@tonic-gate {
398*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
399*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
400*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
401*7c478bd9Sstevel@tonic-gate 	unsigned short typelen;
402*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
403*7c478bd9Sstevel@tonic-gate 	struct ether_mac_frm *mh;
404*7c478bd9Sstevel@tonic-gate 	int hdrlen;
405*7c478bd9Sstevel@tonic-gate 	uint32_t vptag;
406*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *gld_vlan;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
411*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
412*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
413*7c478bd9Sstevel@tonic-gate 		typelen = REF_HOST_USHORT(gldp->glda_sap);
414*7c478bd9Sstevel@tonic-gate 	else
415*7c478bd9Sstevel@tonic-gate 		typelen = gld->gld_sap;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	/*
418*7c478bd9Sstevel@tonic-gate 	 * We only do fast-path for EtherType encoding because this is the only
419*7c478bd9Sstevel@tonic-gate 	 * case where the media header will be consistent from packet to packet.
420*7c478bd9Sstevel@tonic-gate 	 */
421*7c478bd9Sstevel@tonic-gate 	if (typelen <= ETHERMTU)
422*7c478bd9Sstevel@tonic-gate 		return (NULL);
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	/*
425*7c478bd9Sstevel@tonic-gate 	 * Initialize the fast path header to include the
426*7c478bd9Sstevel@tonic-gate 	 * basic source address information and type field.
427*7c478bd9Sstevel@tonic-gate 	 */
428*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct ether_mac_frm);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	/*
431*7c478bd9Sstevel@tonic-gate 	 * Check to see if VLAN is enabled on this stream
432*7c478bd9Sstevel@tonic-gate 	 * if so then make the header bigger to hold a clone
433*7c478bd9Sstevel@tonic-gate 	 * vlan tag.
434*7c478bd9Sstevel@tonic-gate 	 */
435*7c478bd9Sstevel@tonic-gate 	gld_vlan = (gld_vlan_t *)gld->gld_vlan;
436*7c478bd9Sstevel@tonic-gate 	if (gld_vlan && (gld_vlan->gldv_id != VLAN_VID_NONE)) {
437*7c478bd9Sstevel@tonic-gate 		hdrlen += VTAG_SIZE;
438*7c478bd9Sstevel@tonic-gate 		vptag = gld_vlan->gldv_ptag;
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
442*7c478bd9Sstevel@tonic-gate 		return (NULL);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (typelen);
449*7c478bd9Sstevel@tonic-gate 	SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, typelen);
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	/*
452*7c478bd9Sstevel@tonic-gate 	 * If the header is for a VLAN stream, then add
453*7c478bd9Sstevel@tonic-gate 	 * in the VLAN tag to the clone header.
454*7c478bd9Sstevel@tonic-gate 	 */
455*7c478bd9Sstevel@tonic-gate 	if (hdrlen > sizeof (struct ether_mac_frm)) {
456*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
457*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
458*7c478bd9Sstevel@tonic-gate 		vptag >>= 16;
459*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (uint16_t);
460*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(*(uint16_t *)nmp->b_rptr, vptag);
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= (ETHERADDRL * 2);
463*7c478bd9Sstevel@tonic-gate 	mh = (struct ether_mac_frm *)nmp->b_rptr;
464*7c478bd9Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, mh->ether_dhost, macinfo->gldm_addrlen);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
467*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
468*7c478bd9Sstevel@tonic-gate 	    mh->ether_shost, macinfo->gldm_addrlen);
469*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	return (nmp);
472*7c478bd9Sstevel@tonic-gate }
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate /* == */
475*7c478bd9Sstevel@tonic-gate /* IB */
476*7c478bd9Sstevel@tonic-gate /* == */
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate void
479*7c478bd9Sstevel@tonic-gate gld_init_ib(gld_mac_info_t *macinfo)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	/*
482*7c478bd9Sstevel@tonic-gate 	 * Currently, the generic stats maintained by GLD is
483*7c478bd9Sstevel@tonic-gate 	 * sufficient for IPoIB.
484*7c478bd9Sstevel@tonic-gate 	 */
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	/* Assumptions we make for this medium */
487*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_IB);
488*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == IPOIB_ADDRL);
489*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
490*7c478bd9Sstevel@tonic-gate }
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
493*7c478bd9Sstevel@tonic-gate void
494*7c478bd9Sstevel@tonic-gate gld_uninit_ib(gld_mac_info_t *macinfo)
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate /*
499*7c478bd9Sstevel@tonic-gate  * The packet format sent to the driver is:
500*7c478bd9Sstevel@tonic-gate  * IPOIB_ADDRL bytes dest addr :: 2b sap :: 2b 0s :: data
501*7c478bd9Sstevel@tonic-gate  * The packet format received from the driver is:
502*7c478bd9Sstevel@tonic-gate  * IPOIB_GRH_SIZE bytes pseudo GRH :: 2b sap :: 2b 0s :: data.
503*7c478bd9Sstevel@tonic-gate  */
504*7c478bd9Sstevel@tonic-gate int
505*7c478bd9Sstevel@tonic-gate gld_interpret_ib(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
506*7c478bd9Sstevel@tonic-gate     packet_flag_t flags)
507*7c478bd9Sstevel@tonic-gate {
508*7c478bd9Sstevel@tonic-gate 	ipoib_pgrh_t *grh;
509*7c478bd9Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp;
510*7c478bd9Sstevel@tonic-gate 	mblk_t *pmp = NULL;
511*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	/*
514*7c478bd9Sstevel@tonic-gate 	 * Quickly handle receive fastpath for IPQ hack.
515*7c478bd9Sstevel@tonic-gate 	 */
516*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
517*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp) - IPOIB_GRH_SIZE;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		/*
520*7c478bd9Sstevel@tonic-gate 		 * Check whether the header is contiguous, which
521*7c478bd9Sstevel@tonic-gate 		 * also implicitly makes sure the packet is big enough.
522*7c478bd9Sstevel@tonic-gate 		 */
523*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
524*7c478bd9Sstevel@tonic-gate 			return (-1);
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		/*
527*7c478bd9Sstevel@tonic-gate 		 * Almost all times, unicast will not have
528*7c478bd9Sstevel@tonic-gate 		 * a valid pgrh; quickly identify and ask for
529*7c478bd9Sstevel@tonic-gate 		 * IPQ hack optimization only in that case.
530*7c478bd9Sstevel@tonic-gate 		 */
531*7c478bd9Sstevel@tonic-gate 		grh = (ipoib_pgrh_t *)mp->b_rptr;
532*7c478bd9Sstevel@tonic-gate 		if (grh->ipoib_vertcflow == 0) {
533*7c478bd9Sstevel@tonic-gate 			struct ipoib_header *ihp = (struct ipoib_header *)
534*7c478bd9Sstevel@tonic-gate 			    (mp->b_rptr + IPOIB_GRH_SIZE);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 			pktinfo->isForMe = 1;
537*7c478bd9Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(ihp->ipoib_type);
538*7c478bd9Sstevel@tonic-gate 			pktinfo->macLen = IPOIB_GRH_SIZE + IPOIB_HDRSIZE;
539*7c478bd9Sstevel@tonic-gate 			return (0);
540*7c478bd9Sstevel@tonic-gate 		} else {
541*7c478bd9Sstevel@tonic-gate 			return (-1);
542*7c478bd9Sstevel@tonic-gate 		}
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	/*
546*7c478bd9Sstevel@tonic-gate 	 * Handle the GLD_TX, GLD_RX, GLD_RXLOOP cases now.
547*7c478bd9Sstevel@tonic-gate 	 */
548*7c478bd9Sstevel@tonic-gate 	ASSERT(flags != GLD_RXQUICK);
549*7c478bd9Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	if (flags != GLD_RX) {
552*7c478bd9Sstevel@tonic-gate 		/*
553*7c478bd9Sstevel@tonic-gate 		 * GLD_TX and GLD_RXLOOP cases.
554*7c478bd9Sstevel@tonic-gate 		 */
555*7c478bd9Sstevel@tonic-gate 		gldp = (ipoib_ptxhdr_t *)mp->b_rptr;
556*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 		/* make sure packet has at least a pseudo header */
559*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (ipoib_ptxhdr_t))
560*7c478bd9Sstevel@tonic-gate 			return (-1);
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 		/* make sure the mac header falls into contiguous memory */
563*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < sizeof (ipoib_ptxhdr_t)) {
564*7c478bd9Sstevel@tonic-gate 			if ((pmp = msgpullup(mp, -1)) == NULL) {
565*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
566*7c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
567*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
568*7c478bd9Sstevel@tonic-gate 					    "GLD: interpret_ib "
569*7c478bd9Sstevel@tonic-gate 					    "cannot msgpullup");
570*7c478bd9Sstevel@tonic-gate #endif
571*7c478bd9Sstevel@tonic-gate 				return (-1);
572*7c478bd9Sstevel@tonic-gate 			}
573*7c478bd9Sstevel@tonic-gate 			/* this mblk contains the whole mac header */
574*7c478bd9Sstevel@tonic-gate 			mp = pmp;
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 		/*
578*7c478bd9Sstevel@tonic-gate 		 * Check if mac is broadcast or multicast address; all these
579*7c478bd9Sstevel@tonic-gate 		 * types of address have the top 4 bytes as 0x00FFFFFF.
580*7c478bd9Sstevel@tonic-gate 		 */
581*7c478bd9Sstevel@tonic-gate 		if (mac_eq(&gldp->ipoib_dest, macinfo->gldm_broadcast_addr,
582*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t))) {
583*7c478bd9Sstevel@tonic-gate 			if (mac_eq(&gldp->ipoib_dest,
584*7c478bd9Sstevel@tonic-gate 			    macinfo->gldm_broadcast_addr, IPOIB_ADDRL))
585*7c478bd9Sstevel@tonic-gate 				pktinfo->isBroadcast = 1;
586*7c478bd9Sstevel@tonic-gate 			else
587*7c478bd9Sstevel@tonic-gate 				pktinfo->isMulticast = 1;
588*7c478bd9Sstevel@tonic-gate 		}
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 		/*
591*7c478bd9Sstevel@tonic-gate 		 * Only count bytes we will be sending over the wire
592*7c478bd9Sstevel@tonic-gate 		 * or looping back.
593*7c478bd9Sstevel@tonic-gate 		 */
594*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen -= IPOIB_ADDRL;
595*7c478bd9Sstevel@tonic-gate 		if (flags == GLD_TX)
596*7c478bd9Sstevel@tonic-gate 			goto out;	/* Got all info we need for xmit case */
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 		/*
599*7c478bd9Sstevel@tonic-gate 		 * Loopback case: this is a dup'ed message.
600*7c478bd9Sstevel@tonic-gate 		 */
601*7c478bd9Sstevel@tonic-gate 		mp->b_rptr += IPOIB_ADDRL;
602*7c478bd9Sstevel@tonic-gate 		mac_copy(&gldp->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
603*7c478bd9Sstevel@tonic-gate 		mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
604*7c478bd9Sstevel@tonic-gate 	} else {
605*7c478bd9Sstevel@tonic-gate 		/*
606*7c478bd9Sstevel@tonic-gate 		 * GLD_RX case; process packet sent from driver.
607*7c478bd9Sstevel@tonic-gate 		 */
608*7c478bd9Sstevel@tonic-gate 		ipoib_mac_t *mact, *tact;
609*7c478bd9Sstevel@tonic-gate 		ib_qpn_t dqpn;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
612*7c478bd9Sstevel@tonic-gate 		/* make sure packet has at least pgrh and mac header */
613*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE))
614*7c478bd9Sstevel@tonic-gate 			return (-1);
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 		/* make sure the header falls into contiguous memory */
617*7c478bd9Sstevel@tonic-gate 		if (MBLKL(mp) < (IPOIB_GRH_SIZE + IPOIB_HDRSIZE)) {
618*7c478bd9Sstevel@tonic-gate 			if ((pmp = msgpullup(mp, -1)) == NULL) {
619*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
620*7c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
621*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
622*7c478bd9Sstevel@tonic-gate 					    "GLD: interpret_ib "
623*7c478bd9Sstevel@tonic-gate 					    "cannot msgpullup2");
624*7c478bd9Sstevel@tonic-gate #endif
625*7c478bd9Sstevel@tonic-gate 				return (-1);
626*7c478bd9Sstevel@tonic-gate 			}
627*7c478bd9Sstevel@tonic-gate 			/* this mblk contains the whole mac header */
628*7c478bd9Sstevel@tonic-gate 			mp = pmp;
629*7c478bd9Sstevel@tonic-gate 		}
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 		grh = (ipoib_pgrh_t *)mp->b_rptr;
632*7c478bd9Sstevel@tonic-gate 		mp->b_rptr += IPOIB_GRH_SIZE;
633*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen -= IPOIB_GRH_SIZE;
634*7c478bd9Sstevel@tonic-gate 		if (grh->ipoib_vertcflow) {
635*7c478bd9Sstevel@tonic-gate 			/*
636*7c478bd9Sstevel@tonic-gate 			 * First, copy source address from grh.
637*7c478bd9Sstevel@tonic-gate 			 */
638*7c478bd9Sstevel@tonic-gate 			mact = (ipoib_mac_t *)pktinfo->shost;
639*7c478bd9Sstevel@tonic-gate 			mac_copy(&grh->ipoib_sqpn, &mact->ipoib_qpn,
640*7c478bd9Sstevel@tonic-gate 			    IPOIB_ADDRL);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 			/*
643*7c478bd9Sstevel@tonic-gate 			 * Then copy destination address from grh;
644*7c478bd9Sstevel@tonic-gate 			 * first, the 16 bytes of GID.
645*7c478bd9Sstevel@tonic-gate 			 */
646*7c478bd9Sstevel@tonic-gate 			mact = (ipoib_mac_t *)pktinfo->dhost;
647*7c478bd9Sstevel@tonic-gate 			mac_copy(&grh->ipoib_dgid_pref,
648*7c478bd9Sstevel@tonic-gate 			    &mact->ipoib_gidpref, IPOIB_ADDRL -
649*7c478bd9Sstevel@tonic-gate 			    sizeof (mact->ipoib_qpn));
650*7c478bd9Sstevel@tonic-gate 			tact = (ipoib_mac_t *)mac_pvt->curr_macaddr;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 			/* Is this a multicast address */
653*7c478bd9Sstevel@tonic-gate 			if (*(uchar_t *)(grh->ipoib_dgid_pref) == 0xFF) {
654*7c478bd9Sstevel@tonic-gate 				/*
655*7c478bd9Sstevel@tonic-gate 				 * Only check for hardware looping in
656*7c478bd9Sstevel@tonic-gate 				 * multicast case. It is assumed higher
657*7c478bd9Sstevel@tonic-gate 				 * layer code (IP) will stop unicast loops;
658*7c478bd9Sstevel@tonic-gate 				 * ie will prevent a transmit to self.
659*7c478bd9Sstevel@tonic-gate 				 */
660*7c478bd9Sstevel@tonic-gate 				if (bcmp(&grh->ipoib_sqpn, tact,
661*7c478bd9Sstevel@tonic-gate 				    IPOIB_ADDRL) == 0)
662*7c478bd9Sstevel@tonic-gate 					pktinfo->isLooped = 1;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 				tact = (ipoib_mac_t *)macinfo->
665*7c478bd9Sstevel@tonic-gate 				    gldm_broadcast_addr;
666*7c478bd9Sstevel@tonic-gate 				if (mac_eq(tact->ipoib_gidpref,
667*7c478bd9Sstevel@tonic-gate 				    grh->ipoib_dgid_pref,
668*7c478bd9Sstevel@tonic-gate 				    IPOIB_ADDRL - sizeof (tact->ipoib_qpn)))
669*7c478bd9Sstevel@tonic-gate 					pktinfo->isBroadcast = 1;
670*7c478bd9Sstevel@tonic-gate 				else
671*7c478bd9Sstevel@tonic-gate 					pktinfo->isMulticast = 1;
672*7c478bd9Sstevel@tonic-gate 				/*
673*7c478bd9Sstevel@tonic-gate 				 * Now copy the 4 bytes QPN part of the
674*7c478bd9Sstevel@tonic-gate 				 * destination address.
675*7c478bd9Sstevel@tonic-gate 				 */
676*7c478bd9Sstevel@tonic-gate 				dqpn = htonl(IB_MC_QPN);
677*7c478bd9Sstevel@tonic-gate 				mac_copy(&dqpn, &mact->ipoib_qpn,
678*7c478bd9Sstevel@tonic-gate 				    sizeof (mact->ipoib_qpn));
679*7c478bd9Sstevel@tonic-gate 			} else {
680*7c478bd9Sstevel@tonic-gate 				/*
681*7c478bd9Sstevel@tonic-gate 				 * Now copy the 4 bytes QPN part of the
682*7c478bd9Sstevel@tonic-gate 				 * destination address.
683*7c478bd9Sstevel@tonic-gate 				 */
684*7c478bd9Sstevel@tonic-gate 				mac_copy(&tact->ipoib_qpn, &mact->ipoib_qpn,
685*7c478bd9Sstevel@tonic-gate 				    sizeof (mact->ipoib_qpn));
686*7c478bd9Sstevel@tonic-gate 				/*
687*7c478bd9Sstevel@tonic-gate 				 * Any unicast packets received on IBA are
688*7c478bd9Sstevel@tonic-gate 				 * for the node.
689*7c478bd9Sstevel@tonic-gate 				 */
690*7c478bd9Sstevel@tonic-gate 				pktinfo->isForMe = 1;
691*7c478bd9Sstevel@tonic-gate 			}
692*7c478bd9Sstevel@tonic-gate 		} else {
693*7c478bd9Sstevel@tonic-gate 			/*
694*7c478bd9Sstevel@tonic-gate 			 * It can not be a IBA multicast packet.
695*7c478bd9Sstevel@tonic-gate 			 * Must have been unicast to us. We do not
696*7c478bd9Sstevel@tonic-gate 			 * have shost information, which is used in
697*7c478bd9Sstevel@tonic-gate 			 * gld_addudind(); IP/ARP does not care.
698*7c478bd9Sstevel@tonic-gate 			 */
699*7c478bd9Sstevel@tonic-gate 			pktinfo->nosource = 1;
700*7c478bd9Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr, pktinfo->dhost,
701*7c478bd9Sstevel@tonic-gate 			    IPOIB_ADDRL);
702*7c478bd9Sstevel@tonic-gate 			/*
703*7c478bd9Sstevel@tonic-gate 			 * Any unicast packets received on IBA are
704*7c478bd9Sstevel@tonic-gate 			 * for the node.
705*7c478bd9Sstevel@tonic-gate 			 */
706*7c478bd9Sstevel@tonic-gate 			pktinfo->isForMe = 1;
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	ASSERT((flags == GLD_RX) || (flags == GLD_RXLOOP));
711*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
712*7c478bd9Sstevel@tonic-gate 	pktinfo->ethertype = REF_NET_USHORT(((ipoib_hdr_t *)
713*7c478bd9Sstevel@tonic-gate 	    (mp->b_rptr))->ipoib_type);
714*7c478bd9Sstevel@tonic-gate 	pktinfo->macLen = IPOIB_HDRSIZE;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate out:
717*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL)
718*7c478bd9Sstevel@tonic-gate 		freemsg(pmp);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	return (0);
721*7c478bd9Sstevel@tonic-gate }
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate /*
724*7c478bd9Sstevel@tonic-gate  * The packet format sent to the driver is: 2b sap :: 2b 0s :: data
725*7c478bd9Sstevel@tonic-gate  */
726*7c478bd9Sstevel@tonic-gate void
727*7c478bd9Sstevel@tonic-gate gld_interpret_mdt_ib(gld_mac_info_t *macinfo, mblk_t *mp, pdescinfo_t *pinfo,
728*7c478bd9Sstevel@tonic-gate     pktinfo_t *pktinfo, mdt_packet_flag_t flags)
729*7c478bd9Sstevel@tonic-gate {
730*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
731*7c478bd9Sstevel@tonic-gate 	multidata_t *dlmdp;
732*7c478bd9Sstevel@tonic-gate 	pattrinfo_t attr_info = { PATTR_DSTADDRSAP, };
733*7c478bd9Sstevel@tonic-gate 	pattr_t *patr;
734*7c478bd9Sstevel@tonic-gate 	ipoib_ptxhdr_t *dlap = NULL;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	/*
737*7c478bd9Sstevel@tonic-gate 	 * Per packet formatting.
738*7c478bd9Sstevel@tonic-gate 	 */
739*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_MDT_TXPKT) {
740*7c478bd9Sstevel@tonic-gate 		ipoib_hdr_t *hptr;
741*7c478bd9Sstevel@tonic-gate 		uint_t seg;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 		if (PDESC_HDRL(pinfo) == 0)
744*7c478bd9Sstevel@tonic-gate 			return;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 		/*
747*7c478bd9Sstevel@tonic-gate 		 * Update packet's link header.
748*7c478bd9Sstevel@tonic-gate 		 */
749*7c478bd9Sstevel@tonic-gate 		pinfo->hdr_rptr -= IPOIB_HDRSIZE;
750*7c478bd9Sstevel@tonic-gate 		hptr = (ipoib_hdr_t *)pinfo->hdr_rptr;
751*7c478bd9Sstevel@tonic-gate 		hptr->ipoib_mbz = htons(0);
752*7c478bd9Sstevel@tonic-gate 		hptr->ipoib_type = pktinfo->ethertype;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 		/*
755*7c478bd9Sstevel@tonic-gate 		 * Total #bytes that will be put on wire.
756*7c478bd9Sstevel@tonic-gate 		 */
757*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = PDESC_HDRL(pinfo);
758*7c478bd9Sstevel@tonic-gate 		for (seg = 0; seg < pinfo->pld_cnt; seg++)
759*7c478bd9Sstevel@tonic-gate 			pktinfo->pktLen += PDESC_PLDL(pinfo, seg);
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 		return;
762*7c478bd9Sstevel@tonic-gate 	}
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	/*
765*7c478bd9Sstevel@tonic-gate 	 * The following two cases of GLD_MDT_TX and GLD_MDT_RXLOOP are per
766*7c478bd9Sstevel@tonic-gate 	 * MDT message processing.
767*7c478bd9Sstevel@tonic-gate 	 */
768*7c478bd9Sstevel@tonic-gate 	dlmdp = mmd_getmultidata(mp);
769*7c478bd9Sstevel@tonic-gate 	patr = mmd_getpattr(dlmdp, NULL, &attr_info);
770*7c478bd9Sstevel@tonic-gate 	ASSERT(patr != NULL);
771*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
772*7c478bd9Sstevel@tonic-gate 	if (patr != NULL)
773*7c478bd9Sstevel@tonic-gate 		dlap = (ipoib_ptxhdr_t *)((pattr_addr_t *)attr_info.buf)->addr;
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_MDT_TX) {
776*7c478bd9Sstevel@tonic-gate 		bzero((void *)pktinfo, sizeof (*pktinfo));
777*7c478bd9Sstevel@tonic-gate 		if (dlap == NULL)
778*7c478bd9Sstevel@tonic-gate 			return;
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 		/*
781*7c478bd9Sstevel@tonic-gate 		 * Check if mac is broadcast or multicast address; all these
782*7c478bd9Sstevel@tonic-gate 		 * types of address have the top 4 bytes as 0x00FFFFFF.
783*7c478bd9Sstevel@tonic-gate 		 */
784*7c478bd9Sstevel@tonic-gate 		if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
785*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t))) {
786*7c478bd9Sstevel@tonic-gate 			if (mac_eq(dlap, macinfo->gldm_broadcast_addr,
787*7c478bd9Sstevel@tonic-gate 			    IPOIB_ADDRL))
788*7c478bd9Sstevel@tonic-gate 				pktinfo->isBroadcast = 1;
789*7c478bd9Sstevel@tonic-gate 			else
790*7c478bd9Sstevel@tonic-gate 				pktinfo->isMulticast = 1;
791*7c478bd9Sstevel@tonic-gate 		}
792*7c478bd9Sstevel@tonic-gate 		pktinfo->ethertype = REF_NET_USHORT(dlap->
793*7c478bd9Sstevel@tonic-gate 		    ipoib_rhdr.ipoib_type);
794*7c478bd9Sstevel@tonic-gate 	} else {
795*7c478bd9Sstevel@tonic-gate 		ASSERT(flags == GLD_MDT_RXLOOP);
796*7c478bd9Sstevel@tonic-gate 		pktinfo->macLen = IPOIB_HDRSIZE;
797*7c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
798*7c478bd9Sstevel@tonic-gate 		mac_copy(mac_pvt->curr_macaddr, pktinfo->shost, IPOIB_ADDRL);
799*7c478bd9Sstevel@tonic-gate 		if (dlap == NULL)
800*7c478bd9Sstevel@tonic-gate 			return;
801*7c478bd9Sstevel@tonic-gate 		mac_copy(&dlap->ipoib_dest, pktinfo->dhost, IPOIB_ADDRL);
802*7c478bd9Sstevel@tonic-gate 	}
803*7c478bd9Sstevel@tonic-gate }
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate mblk_t *
806*7c478bd9Sstevel@tonic-gate gld_unitdata_ib(gld_t *gld, mblk_t *mp)
807*7c478bd9Sstevel@tonic-gate {
808*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
809*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
810*7c478bd9Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
811*7c478bd9Sstevel@tonic-gate 	ipoib_mac_t dhost;
812*7c478bd9Sstevel@tonic-gate 	unsigned short type;
813*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
814*7c478bd9Sstevel@tonic-gate 	int hdrlen;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
819*7c478bd9Sstevel@tonic-gate 	mac_copy(&gldp->ipoib_dest, &dhost, IPOIB_ADDRL);
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
822*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
823*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
824*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
825*7c478bd9Sstevel@tonic-gate 	else
826*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (ipoib_ptxhdr_t);
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
831*7c478bd9Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
832*7c478bd9Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
833*7c478bd9Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
834*7c478bd9Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
835*7c478bd9Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
836*7c478bd9Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
837*7c478bd9Sstevel@tonic-gate 		nmp = mp;
838*7c478bd9Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
839*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
840*7c478bd9Sstevel@tonic-gate 	} else {
841*7c478bd9Sstevel@tonic-gate 		/* we need to allocate one */
842*7c478bd9Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
843*7c478bd9Sstevel@tonic-gate 			return (NULL);
844*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
845*7c478bd9Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
846*7c478bd9Sstevel@tonic-gate 		freeb(mp);
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
852*7c478bd9Sstevel@tonic-gate 	gldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
853*7c478bd9Sstevel@tonic-gate 	SET_NET_USHORT(gldp->ipoib_rhdr.ipoib_type, type);
854*7c478bd9Sstevel@tonic-gate 	gldp->ipoib_rhdr.ipoib_mbz = 0;
855*7c478bd9Sstevel@tonic-gate 	mac_copy(&dhost, &gldp->ipoib_dest, IPOIB_ADDRL);
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	return (nmp);
858*7c478bd9Sstevel@tonic-gate }
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate mblk_t *
861*7c478bd9Sstevel@tonic-gate gld_fastpath_ib(gld_t *gld, mblk_t *mp)
862*7c478bd9Sstevel@tonic-gate {
863*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
864*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
865*7c478bd9Sstevel@tonic-gate 	ipoib_ptxhdr_t *gldp = IPOIBDLSAP(dlp, dlp->dl_dest_addr_offset);
866*7c478bd9Sstevel@tonic-gate 	unsigned short type;
867*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
868*7c478bd9Sstevel@tonic-gate 	ipoib_ptxhdr_t *tgldp;
869*7c478bd9Sstevel@tonic-gate 	int hdrlen;
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
874*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
875*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type) != 0)
876*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->ipoib_rhdr.ipoib_type);
877*7c478bd9Sstevel@tonic-gate 	else
878*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (ipoib_ptxhdr_t);
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
883*7c478bd9Sstevel@tonic-gate 		return (NULL);
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (ipoib_ptxhdr_t);
890*7c478bd9Sstevel@tonic-gate 	tgldp = (ipoib_ptxhdr_t *)nmp->b_rptr;
891*7c478bd9Sstevel@tonic-gate 	tgldp->ipoib_rhdr.ipoib_type = htons(type);
892*7c478bd9Sstevel@tonic-gate 	tgldp->ipoib_rhdr.ipoib_mbz = 0;
893*7c478bd9Sstevel@tonic-gate 	mac_copy(&gldp->ipoib_dest, &tgldp->ipoib_dest, IPOIB_ADDRL);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	return (nmp);
896*7c478bd9Sstevel@tonic-gate }
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate /* ==== */
899*7c478bd9Sstevel@tonic-gate /* FDDI */
900*7c478bd9Sstevel@tonic-gate /* ==== */
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate void
903*7c478bd9Sstevel@tonic-gate gld_init_fddi(gld_mac_info_t *macinfo)
904*7c478bd9Sstevel@tonic-gate {
905*7c478bd9Sstevel@tonic-gate 	struct gldkstats *sp =
906*7c478bd9Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/* Assumptions we make for this medium */
909*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_FDDI);
910*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
911*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
912*7c478bd9Sstevel@tonic-gate #ifndef	lint
913*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (struct fddi_mac_frm) == 13);
914*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
915*7c478bd9Sstevel@tonic-gate #endif
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	/* Wire address format is bit reversed from canonical format */
918*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_options |= GLDOPT_CANONICAL_ADDR;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_error,
921*7c478bd9Sstevel@tonic-gate 	    "mac_errors", KSTAT_DATA_UINT32);
922*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_lost,
923*7c478bd9Sstevel@tonic-gate 	    "mac_lost_errors", KSTAT_DATA_UINT32);
924*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_token,
925*7c478bd9Sstevel@tonic-gate 	    "mac_tokens", KSTAT_DATA_UINT32);
926*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_tvx_expired,
927*7c478bd9Sstevel@tonic-gate 	    "mac_tvx_expired", KSTAT_DATA_UINT32);
928*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_late,
929*7c478bd9Sstevel@tonic-gate 	    "mac_late", KSTAT_DATA_UINT32);
930*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_fddi_mac_ring_op,
931*7c478bd9Sstevel@tonic-gate 	    "mac_ring_ops", KSTAT_DATA_UINT32);
932*7c478bd9Sstevel@tonic-gate }
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
935*7c478bd9Sstevel@tonic-gate void
936*7c478bd9Sstevel@tonic-gate gld_uninit_fddi(gld_mac_info_t *macinfo)
937*7c478bd9Sstevel@tonic-gate {
938*7c478bd9Sstevel@tonic-gate }
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate int
941*7c478bd9Sstevel@tonic-gate gld_interpret_fddi(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
942*7c478bd9Sstevel@tonic-gate     packet_flag_t flags)
943*7c478bd9Sstevel@tonic-gate {
944*7c478bd9Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
945*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
946*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
947*7c478bd9Sstevel@tonic-gate 	mblk_t *pmp = NULL;
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	/*
950*7c478bd9Sstevel@tonic-gate 	 * Quickly handle receive fastpath; FDDI does not support IPQ hack.
951*7c478bd9Sstevel@tonic-gate 	 */
952*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
953*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
954*7c478bd9Sstevel@tonic-gate 		return (-1);
955*7c478bd9Sstevel@tonic-gate 	}
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
962*7c478bd9Sstevel@tonic-gate 	if (pktinfo->pktLen < sizeof (struct fddi_mac_frm))
963*7c478bd9Sstevel@tonic-gate 		return (-1);
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
966*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct fddi_mac_frm)) {
967*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
968*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
969*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
970*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
971*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_fddi cannot msgpullup");
972*7c478bd9Sstevel@tonic-gate #endif
973*7c478bd9Sstevel@tonic-gate 			return (-1);
974*7c478bd9Sstevel@tonic-gate 		}
975*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)mp->b_rptr;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
981*7c478bd9Sstevel@tonic-gate 	/* NB we are still in wire format (non canonical) */
982*7c478bd9Sstevel@tonic-gate 	/* mac_eq works because ether_broadcast is the same either way */
983*7c478bd9Sstevel@tonic-gate 	if (mac_eq(mh->fddi_dhost, ether_broadcast, macinfo->gldm_addrlen))
984*7c478bd9Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
985*7c478bd9Sstevel@tonic-gate 	else if (mh->fddi_dhost[0] & 0x80)
986*7c478bd9Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_TX)
989*7c478bd9Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	/*
994*7c478bd9Sstevel@tonic-gate 	 * Deal with the mac header
995*7c478bd9Sstevel@tonic-gate 	 */
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	cmac_copy(mh->fddi_dhost, pktinfo->dhost,
998*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
999*7c478bd9Sstevel@tonic-gate 	cmac_copy(mh->fddi_shost, pktinfo->shost,
1000*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1003*7c478bd9Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
1004*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1005*7c478bd9Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
1006*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	pktinfo->macLen = sizeof (struct fddi_mac_frm);
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	/*
1011*7c478bd9Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the LLC
1012*7c478bd9Sstevel@tonic-gate 	 * header exists, and that both it and any SNAP header are contiguous.
1013*7c478bd9Sstevel@tonic-gate 	 */
1014*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct fddi_mac_frm) + LLC_SNAP_HDR_LEN &&
1015*7c478bd9Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
1016*7c478bd9Sstevel@tonic-gate 		/*
1017*7c478bd9Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
1018*7c478bd9Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
1019*7c478bd9Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
1020*7c478bd9Sstevel@tonic-gate 		 */
1021*7c478bd9Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
1022*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
1023*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1024*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1025*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1026*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_fddi cannot msgpullup2");
1027*7c478bd9Sstevel@tonic-gate #endif
1028*7c478bd9Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
1029*7c478bd9Sstevel@tonic-gate 		}
1030*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
1031*7c478bd9Sstevel@tonic-gate 	}
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	/*
1034*7c478bd9Sstevel@tonic-gate 	 * Check SAP/SNAP information.
1035*7c478bd9Sstevel@tonic-gate 	 */
1036*7c478bd9Sstevel@tonic-gate 	if ((mh->fddi_fc & 0x70) == 0x50) {
1037*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
1038*7c478bd9Sstevel@tonic-gate 			goto out;
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 		pktinfo->isLLC = 1;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
1043*7c478bd9Sstevel@tonic-gate 			goto out;
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 		snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
1046*7c478bd9Sstevel@tonic-gate 		if (ISETHERTYPE(snaphdr)) {
1047*7c478bd9Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
1048*7c478bd9Sstevel@tonic-gate 			pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
1049*7c478bd9Sstevel@tonic-gate 		}
1050*7c478bd9Sstevel@tonic-gate 	}
1051*7c478bd9Sstevel@tonic-gate out:
1052*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL)
1053*7c478bd9Sstevel@tonic-gate 		freemsg(pmp);
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	return (0);
1056*7c478bd9Sstevel@tonic-gate }
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate mblk_t *
1059*7c478bd9Sstevel@tonic-gate gld_unitdata_fddi(gld_t *gld, mblk_t *mp)
1060*7c478bd9Sstevel@tonic-gate {
1061*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
1062*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1063*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1064*7c478bd9Sstevel@tonic-gate 	mac_addr_t dhost;
1065*7c478bd9Sstevel@tonic-gate 	unsigned short type;
1066*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1067*7c478bd9Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
1068*7c478bd9Sstevel@tonic-gate 	int hdrlen;
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
1073*7c478bd9Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
1076*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1077*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
1078*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
1079*7c478bd9Sstevel@tonic-gate 	else
1080*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct fddi_mac_frm);
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	/*
1086*7c478bd9Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
1087*7c478bd9Sstevel@tonic-gate 	 * is LLC.
1088*7c478bd9Sstevel@tonic-gate 	 */
1089*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
1090*7c478bd9Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
1093*7c478bd9Sstevel@tonic-gate 	nmp = mp->b_cont;	/* where the packet payload M_DATA is */
1094*7c478bd9Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
1095*7c478bd9Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
1096*7c478bd9Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
1097*7c478bd9Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
1098*7c478bd9Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
1099*7c478bd9Sstevel@tonic-gate 		nmp = mp;
1100*7c478bd9Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
1101*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1102*7c478bd9Sstevel@tonic-gate 	} else {
1103*7c478bd9Sstevel@tonic-gate 		/* we need to allocate one */
1104*7c478bd9Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1105*7c478bd9Sstevel@tonic-gate 			return (NULL);
1106*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1107*7c478bd9Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
1108*7c478bd9Sstevel@tonic-gate 		freeb(mp);
1109*7c478bd9Sstevel@tonic-gate 	}
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
1113*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
1114*7c478bd9Sstevel@tonic-gate 		/* create the snap header */
1115*7c478bd9Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
1116*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1117*7c478bd9Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1118*7c478bd9Sstevel@tonic-gate 		*snap = llc_snap_def;
1119*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(snap->type, type);
1120*7c478bd9Sstevel@tonic-gate 	}
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct fddi_mac_frm);
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)nmp->b_rptr;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	mh->fddi_fc = 0x50;
1127*7c478bd9Sstevel@tonic-gate 	cmac_copy(dhost, mh->fddi_dhost, macinfo->gldm_addrlen, macinfo);
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	/*
1130*7c478bd9Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
1131*7c478bd9Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
1132*7c478bd9Sstevel@tonic-gate 	 */
1133*7c478bd9Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1134*7c478bd9Sstevel@tonic-gate 	    mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
1135*7c478bd9Sstevel@tonic-gate 	return (nmp);
1136*7c478bd9Sstevel@tonic-gate }
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate mblk_t *
1139*7c478bd9Sstevel@tonic-gate gld_fastpath_fddi(gld_t *gld, mblk_t *mp)
1140*7c478bd9Sstevel@tonic-gate {
1141*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
1142*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
1143*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1144*7c478bd9Sstevel@tonic-gate 	unsigned short type;
1145*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1146*7c478bd9Sstevel@tonic-gate 	struct fddi_mac_frm *mh;
1147*7c478bd9Sstevel@tonic-gate 	int hdrlen;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
1152*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1153*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
1154*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
1155*7c478bd9Sstevel@tonic-gate 	else
1156*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct fddi_mac_frm);
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	/*
1161*7c478bd9Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
1162*7c478bd9Sstevel@tonic-gate 	 * will be LLC.
1163*7c478bd9Sstevel@tonic-gate 	 */
1164*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
1165*7c478bd9Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1168*7c478bd9Sstevel@tonic-gate 		return (NULL);
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
1175*7c478bd9Sstevel@tonic-gate 		/* create the snap header */
1176*7c478bd9Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
1177*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1178*7c478bd9Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1179*7c478bd9Sstevel@tonic-gate 		*snap = llc_snap_def;
1180*7c478bd9Sstevel@tonic-gate 		snap->type = htons(type);	/* we know it's aligned */
1181*7c478bd9Sstevel@tonic-gate 	}
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct fddi_mac_frm);
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	mh = (struct fddi_mac_frm *)nmp->b_rptr;
1186*7c478bd9Sstevel@tonic-gate 	mh->fddi_fc = 0x50;
1187*7c478bd9Sstevel@tonic-gate 	cmac_copy(gldp->glda_addr, mh->fddi_dhost,
1188*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen, macinfo);
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
1191*7c478bd9Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1192*7c478bd9Sstevel@tonic-gate 	    mh->fddi_shost, macinfo->gldm_addrlen, macinfo);
1193*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	return (nmp);
1196*7c478bd9Sstevel@tonic-gate }
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate /* ========== */
1199*7c478bd9Sstevel@tonic-gate /* Token Ring */
1200*7c478bd9Sstevel@tonic-gate /* ========== */
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate #define	GLD_SR_VAR(macinfo)	\
1203*7c478bd9Sstevel@tonic-gate 	(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->data)
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate #define	GLD_SR_HASH(macinfo)	((struct srtab **)GLD_SR_VAR(macinfo))
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate #define	GLD_SR_MUTEX(macinfo)	\
1208*7c478bd9Sstevel@tonic-gate 	(&((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->datalock)
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate static void gld_sr_clear(gld_mac_info_t *);
1211*7c478bd9Sstevel@tonic-gate static void gld_rcc_receive(gld_mac_info_t *, pktinfo_t *, struct gld_ri *,
1212*7c478bd9Sstevel@tonic-gate     uchar_t *, int);
1213*7c478bd9Sstevel@tonic-gate static void gld_rcc_send(gld_mac_info_t *, queue_t *, uchar_t *,
1214*7c478bd9Sstevel@tonic-gate     struct gld_ri **, uchar_t *);
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate static mac_addr_t tokenbroadcastaddr2 = { 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff };
1217*7c478bd9Sstevel@tonic-gate static struct gld_ri ri_ste_def;
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate void
1220*7c478bd9Sstevel@tonic-gate gld_init_tr(gld_mac_info_t *macinfo)
1221*7c478bd9Sstevel@tonic-gate {
1222*7c478bd9Sstevel@tonic-gate 	struct gldkstats *sp =
1223*7c478bd9Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->kstatp->ks_data;
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	/* avoid endian-dependent code by initializing here instead of static */
1226*7c478bd9Sstevel@tonic-gate 	ri_ste_def.len = 2;
1227*7c478bd9Sstevel@tonic-gate 	ri_ste_def.rt = RT_STE;
1228*7c478bd9Sstevel@tonic-gate 	ri_ste_def.mtu = RT_MTU_MAX;
1229*7c478bd9Sstevel@tonic-gate 	ri_ste_def.dir = 0;
1230*7c478bd9Sstevel@tonic-gate 	ri_ste_def.res = 0;
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	/* Assumptions we make for this medium */
1233*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_type == DL_TPR);
1234*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen == 6);
1235*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);
1236*7c478bd9Sstevel@tonic-gate #ifndef	lint
1237*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (struct tr_mac_frm_nori) == 14);
1238*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (mac_addr_t) == 6);
1239*7c478bd9Sstevel@tonic-gate #endif
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	mutex_init(GLD_SR_MUTEX(macinfo), NULL, MUTEX_DRIVER, NULL);
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	GLD_SR_VAR(macinfo) = kmem_zalloc(sizeof (struct srtab *)*SR_HASH_SIZE,
1244*7c478bd9Sstevel@tonic-gate 				KM_SLEEP);
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	/* Default is RDE enabled for this medium */
1247*7c478bd9Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled =
1248*7c478bd9Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1249*7c478bd9Sstevel@tonic-gate 	    "gld_rde_enable", 1);
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	/*
1252*7c478bd9Sstevel@tonic-gate 	 * Default is to use STE for unknown paths if RDE is enabled.
1253*7c478bd9Sstevel@tonic-gate 	 * If RDE is disabled, default is to use NULL RIF fields.
1254*7c478bd9Sstevel@tonic-gate 	 *
1255*7c478bd9Sstevel@tonic-gate 	 * It's possible to force use of STE for ALL packets:
1256*7c478bd9Sstevel@tonic-gate 	 * disable RDE but enable STE.  This may be useful for
1257*7c478bd9Sstevel@tonic-gate 	 * non-transparent bridges, when it is not desired to run
1258*7c478bd9Sstevel@tonic-gate 	 * the RDE algorithms.
1259*7c478bd9Sstevel@tonic-gate 	 */
1260*7c478bd9Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste =
1261*7c478bd9Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1262*7c478bd9Sstevel@tonic-gate 	    "gld_rde_str_indicator_ste",
1263*7c478bd9Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled);
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	/* Default 10 second route timeout on lack of activity */
1266*7c478bd9Sstevel@tonic-gate 	{
1267*7c478bd9Sstevel@tonic-gate 	int t = ddi_getprop(DDI_DEV_T_NONE, macinfo->gldm_devinfo, 0,
1268*7c478bd9Sstevel@tonic-gate 	    "gld_rde_timeout", 10);
1269*7c478bd9Sstevel@tonic-gate 	if (t < 1)
1270*7c478bd9Sstevel@tonic-gate 		t = 1;		/* Let's be reasonable */
1271*7c478bd9Sstevel@tonic-gate 	if (t > 600)
1272*7c478bd9Sstevel@tonic-gate 		t = 600;	/* Let's be reasonable */
1273*7c478bd9Sstevel@tonic-gate 	/* We're using ticks (lbolts) for our timeout -- convert from seconds */
1274*7c478bd9Sstevel@tonic-gate 	t = drv_usectohz(1000000 * t);
1275*7c478bd9Sstevel@tonic-gate 	((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout = t;
1276*7c478bd9Sstevel@tonic-gate 	}
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_line_error,
1279*7c478bd9Sstevel@tonic-gate 	    "line_errors", KSTAT_DATA_UINT32);
1280*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_burst_error,
1281*7c478bd9Sstevel@tonic-gate 	    "burst_errors", KSTAT_DATA_UINT32);
1282*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_signal_loss,
1283*7c478bd9Sstevel@tonic-gate 	    "signal_losses", KSTAT_DATA_UINT32);
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	/*
1286*7c478bd9Sstevel@tonic-gate 	 * only initialize the new statistics if the driver
1287*7c478bd9Sstevel@tonic-gate 	 * knows about them.
1288*7c478bd9Sstevel@tonic-gate 	 */
1289*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION_200)
1290*7c478bd9Sstevel@tonic-gate 		return;
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_ace_error,
1293*7c478bd9Sstevel@tonic-gate 	    "ace_errors", KSTAT_DATA_UINT32);
1294*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_internal_error,
1295*7c478bd9Sstevel@tonic-gate 	    "internal_errors", KSTAT_DATA_UINT32);
1296*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_lost_frame_error,
1297*7c478bd9Sstevel@tonic-gate 	    "lost_frame_errors", KSTAT_DATA_UINT32);
1298*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_frame_copied_error,
1299*7c478bd9Sstevel@tonic-gate 	    "frame_copied_errors", KSTAT_DATA_UINT32);
1300*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_token_error,
1301*7c478bd9Sstevel@tonic-gate 	    "token_errors", KSTAT_DATA_UINT32);
1302*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_dot5_freq_error,
1303*7c478bd9Sstevel@tonic-gate 	    "freq_errors", KSTAT_DATA_UINT32);
1304*7c478bd9Sstevel@tonic-gate }
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate void
1307*7c478bd9Sstevel@tonic-gate gld_uninit_tr(gld_mac_info_t *macinfo)
1308*7c478bd9Sstevel@tonic-gate {
1309*7c478bd9Sstevel@tonic-gate 	mutex_destroy(GLD_SR_MUTEX(macinfo));
1310*7c478bd9Sstevel@tonic-gate 	gld_sr_clear(macinfo);
1311*7c478bd9Sstevel@tonic-gate 	kmem_free(GLD_SR_VAR(macinfo), sizeof (struct srtab *) * SR_HASH_SIZE);
1312*7c478bd9Sstevel@tonic-gate }
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate int
1315*7c478bd9Sstevel@tonic-gate gld_interpret_tr(gld_mac_info_t *macinfo, mblk_t *mp, pktinfo_t *pktinfo,
1316*7c478bd9Sstevel@tonic-gate     packet_flag_t flags)
1317*7c478bd9Sstevel@tonic-gate {
1318*7c478bd9Sstevel@tonic-gate 	struct tr_mac_frm *mh;
1319*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
1320*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr;
1321*7c478bd9Sstevel@tonic-gate 	mblk_t *pmp = NULL;
1322*7c478bd9Sstevel@tonic-gate 	struct gld_ri *rh;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	/*
1325*7c478bd9Sstevel@tonic-gate 	 * Quickly handle receive fastpath; TR does not support IPQ hack.
1326*7c478bd9Sstevel@tonic-gate 	 */
1327*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_RXQUICK) {
1328*7c478bd9Sstevel@tonic-gate 		pktinfo->pktLen = msgdsize(mp);
1329*7c478bd9Sstevel@tonic-gate 		return (-1);
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	bzero((void *)pktinfo, sizeof (*pktinfo));
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	pktinfo->pktLen = msgdsize(mp);
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	/* make sure packet has at least a whole mac header */
1337*7c478bd9Sstevel@tonic-gate 	if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori))
1338*7c478bd9Sstevel@tonic-gate 		return (-1);
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate 	/* make sure the mac header falls into contiguous memory */
1341*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct tr_mac_frm_nori)) {
1342*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
1343*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1344*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1345*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1346*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_tr cannot msgpullup");
1347*7c478bd9Sstevel@tonic-gate #endif
1348*7c478bd9Sstevel@tonic-gate 			return (-1);
1349*7c478bd9Sstevel@tonic-gate 		}
1350*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk contains the whole mac header */
1351*7c478bd9Sstevel@tonic-gate 	}
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 	mh = (struct tr_mac_frm *)mp->b_rptr;
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	/* Check to see if the mac is a broadcast or multicast address. */
1356*7c478bd9Sstevel@tonic-gate 	if (mac_eq(mh->tr_dhost, ether_broadcast, macinfo->gldm_addrlen) ||
1357*7c478bd9Sstevel@tonic-gate 	    mac_eq(mh->tr_dhost, tokenbroadcastaddr2, macinfo->gldm_addrlen))
1358*7c478bd9Sstevel@tonic-gate 		pktinfo->isBroadcast = 1;
1359*7c478bd9Sstevel@tonic-gate 	else if (mh->tr_dhost[0] & 0x80)
1360*7c478bd9Sstevel@tonic-gate 		pktinfo->isMulticast = 1;
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	if (flags == GLD_TX)
1363*7c478bd9Sstevel@tonic-gate 		goto out;	/* Got all info we need for xmit case */
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	/*
1368*7c478bd9Sstevel@tonic-gate 	 * Deal with the mac header
1369*7c478bd9Sstevel@tonic-gate 	 */
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	mac_copy(mh->tr_dhost, pktinfo->dhost, macinfo->gldm_addrlen);
1372*7c478bd9Sstevel@tonic-gate 	mac_copy(mh->tr_shost, pktinfo->shost, macinfo->gldm_addrlen);
1373*7c478bd9Sstevel@tonic-gate 	pktinfo->shost[0] &= ~0x80;	/* turn off RIF indicator */
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1376*7c478bd9Sstevel@tonic-gate 	pktinfo->isLooped = mac_eq(pktinfo->shost,
1377*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1378*7c478bd9Sstevel@tonic-gate 	pktinfo->isForMe = mac_eq(pktinfo->dhost,
1379*7c478bd9Sstevel@tonic-gate 	    mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 	rh = (struct gld_ri *)NULL;
1382*7c478bd9Sstevel@tonic-gate 	pktinfo->macLen = sizeof (struct tr_mac_frm_nori);
1383*7c478bd9Sstevel@tonic-gate 
1384*7c478bd9Sstevel@tonic-gate 	/*
1385*7c478bd9Sstevel@tonic-gate 	 * Before trying to look beyond the MAC header, make sure the data
1386*7c478bd9Sstevel@tonic-gate 	 * structures are all contiguously where we can conveniently look at
1387*7c478bd9Sstevel@tonic-gate 	 * them.  We'll use a worst-case estimate of how many bytes into the
1388*7c478bd9Sstevel@tonic-gate 	 * packet data we'll be needing to look.  Things will be more efficient
1389*7c478bd9Sstevel@tonic-gate 	 * if the driver puts at least this much into the first mblk.
1390*7c478bd9Sstevel@tonic-gate 	 *
1391*7c478bd9Sstevel@tonic-gate 	 * Even after this, we still will have to do checks against the total
1392*7c478bd9Sstevel@tonic-gate 	 * length of the packet.  A bad incoming packet may not hold all the
1393*7c478bd9Sstevel@tonic-gate 	 * data structures it says it does.
1394*7c478bd9Sstevel@tonic-gate 	 */
1395*7c478bd9Sstevel@tonic-gate 	if (MBLKL(mp) < sizeof (struct tr_mac_frm) +
1396*7c478bd9Sstevel@tonic-gate 	    LLC_HDR1_LEN + sizeof (struct rde_pdu) &&
1397*7c478bd9Sstevel@tonic-gate 	    MBLKL(mp) < pktinfo->pktLen) {
1398*7c478bd9Sstevel@tonic-gate 		/*
1399*7c478bd9Sstevel@tonic-gate 		 * we don't have the entire packet within the first mblk (and
1400*7c478bd9Sstevel@tonic-gate 		 * therefore we didn't do the msgpullup above), AND the first
1401*7c478bd9Sstevel@tonic-gate 		 * mblk may not contain all the data we need to look at.
1402*7c478bd9Sstevel@tonic-gate 		 */
1403*7c478bd9Sstevel@tonic-gate 		ASSERT(pmp == NULL);	/* couldn't have done msgpullup above */
1404*7c478bd9Sstevel@tonic-gate 		if ((pmp = msgpullup(mp, -1)) == NULL) {
1405*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1406*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1407*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1408*7c478bd9Sstevel@tonic-gate 				    "GLD: interpret_tr cannot msgpullup2");
1409*7c478bd9Sstevel@tonic-gate #endif
1410*7c478bd9Sstevel@tonic-gate 			goto out;	/* can't interpret this pkt further */
1411*7c478bd9Sstevel@tonic-gate 		}
1412*7c478bd9Sstevel@tonic-gate 		mp = pmp;	/* this mblk should contain everything needed */
1413*7c478bd9Sstevel@tonic-gate 		mh = (struct tr_mac_frm *)mp->b_rptr;	/* to look at RIF */
1414*7c478bd9Sstevel@tonic-gate 	}
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	if (mh->tr_shost[0] & 0x80) {
1417*7c478bd9Sstevel@tonic-gate 		/* Routing Information Field (RIF) is present */
1418*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + 2)
1419*7c478bd9Sstevel@tonic-gate 			goto out;	/* RIF should have been there! */
1420*7c478bd9Sstevel@tonic-gate 		rh = (struct gld_ri *)&mh->tr_ri;
1421*7c478bd9Sstevel@tonic-gate 		if ((rh->len & 1) || rh->len < 2) {
1422*7c478bd9Sstevel@tonic-gate 			/* Bogus RIF, don't handle this packet */
1423*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1424*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1425*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1426*7c478bd9Sstevel@tonic-gate 				    "GLD: received TR packet with "
1427*7c478bd9Sstevel@tonic-gate 				    "bogus RIF length %d",
1428*7c478bd9Sstevel@tonic-gate 				    rh->len);
1429*7c478bd9Sstevel@tonic-gate #endif
1430*7c478bd9Sstevel@tonic-gate 			goto out;
1431*7c478bd9Sstevel@tonic-gate 		}
1432*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < sizeof (struct tr_mac_frm_nori) + rh->len)
1433*7c478bd9Sstevel@tonic-gate 			goto out;	/* RIF should have been there! */
1434*7c478bd9Sstevel@tonic-gate 		pktinfo->macLen += rh->len;
1435*7c478bd9Sstevel@tonic-gate 	}
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 	if ((mh->tr_fc & 0xc0) == 0x40) {
1438*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_HDR1_LEN)
1439*7c478bd9Sstevel@tonic-gate 			goto out;
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 		pktinfo->isLLC = 1;
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 		if (pktinfo->pktLen < pktinfo->macLen + LLC_SNAP_HDR_LEN)
1444*7c478bd9Sstevel@tonic-gate 			goto out;
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 		snaphdr = (struct llc_snap_hdr *)(mp->b_rptr + pktinfo->macLen);
1447*7c478bd9Sstevel@tonic-gate 		if (ISETHERTYPE(snaphdr)) {
1448*7c478bd9Sstevel@tonic-gate 			pktinfo->ethertype = REF_NET_USHORT(snaphdr->type);
1449*7c478bd9Sstevel@tonic-gate 			pktinfo->hdrLen = LLC_SNAP_HDR_LEN;
1450*7c478bd9Sstevel@tonic-gate 		}
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 		/* Inform the Route Control Component of received LLC frame */
1453*7c478bd9Sstevel@tonic-gate 		gld_rcc_receive(macinfo, pktinfo, rh,
1454*7c478bd9Sstevel@tonic-gate 		    mp->b_rptr + pktinfo->macLen,
1455*7c478bd9Sstevel@tonic-gate 		    pktinfo->pktLen - pktinfo->macLen);
1456*7c478bd9Sstevel@tonic-gate 	}
1457*7c478bd9Sstevel@tonic-gate out:
1458*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL)
1459*7c478bd9Sstevel@tonic-gate 		freemsg(pmp);
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	return (0);
1462*7c478bd9Sstevel@tonic-gate }
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate mblk_t *
1465*7c478bd9Sstevel@tonic-gate gld_unitdata_tr(gld_t *gld, mblk_t *mp)
1466*7c478bd9Sstevel@tonic-gate {
1467*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
1468*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1469*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1470*7c478bd9Sstevel@tonic-gate 	mac_addr_t dhost;
1471*7c478bd9Sstevel@tonic-gate 	unsigned short type;
1472*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp, *llcmp, *pmp = NULL;
1473*7c478bd9Sstevel@tonic-gate 	struct tr_mac_frm_nori *mh;
1474*7c478bd9Sstevel@tonic-gate 	int hdrlen;
1475*7c478bd9Sstevel@tonic-gate 	struct gld_ri *rh;
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 	/* extract needed info from the mblk before we maybe reuse it */
1480*7c478bd9Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, dhost, macinfo->gldm_addrlen);
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
1483*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1484*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
1485*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
1486*7c478bd9Sstevel@tonic-gate 	else
1487*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 	/* includes maximum possible Routing Information Field (RIF) size */
1490*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct tr_mac_frm);
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	/*
1493*7c478bd9Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
1494*7c478bd9Sstevel@tonic-gate 	 * is LLC.
1495*7c478bd9Sstevel@tonic-gate 	 */
1496*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
1497*7c478bd9Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 	/* need a buffer big enough for the headers */
1500*7c478bd9Sstevel@tonic-gate 	llcmp = nmp = mp->b_cont; /* where the packet payload M_DATA is */
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	/*
1503*7c478bd9Sstevel@tonic-gate 	 * We are going to need to look at the LLC header, so make sure it
1504*7c478bd9Sstevel@tonic-gate 	 * is contiguously in a single mblk.  If we're the ones who create
1505*7c478bd9Sstevel@tonic-gate 	 * the LLC header (below, in the case where sap > 0xff) then we don't
1506*7c478bd9Sstevel@tonic-gate 	 * have to worry about it here.
1507*7c478bd9Sstevel@tonic-gate 	 */
1508*7c478bd9Sstevel@tonic-gate 	ASSERT(nmp != NULL);	/* gld_unitdata guarantees msgdsize > 0 */
1509*7c478bd9Sstevel@tonic-gate 	if (type <= GLD_MAX_802_SAP) {
1510*7c478bd9Sstevel@tonic-gate 		if (MBLKL(llcmp) < LLC_HDR1_LEN) {
1511*7c478bd9Sstevel@tonic-gate 			llcmp = pmp = msgpullup(nmp, LLC_HDR1_LEN);
1512*7c478bd9Sstevel@tonic-gate 			if (pmp == NULL) {
1513*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1514*7c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
1515*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
1516*7c478bd9Sstevel@tonic-gate 					    "GLD: unitdata_tr "
1517*7c478bd9Sstevel@tonic-gate 					    "cannot msgpullup");
1518*7c478bd9Sstevel@tonic-gate #endif
1519*7c478bd9Sstevel@tonic-gate 				return (NULL);
1520*7c478bd9Sstevel@tonic-gate 			}
1521*7c478bd9Sstevel@tonic-gate 		}
1522*7c478bd9Sstevel@tonic-gate 	}
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 	if (DB_REF(nmp) == 1 && MBLKHEAD(nmp) >= hdrlen) {
1525*7c478bd9Sstevel@tonic-gate 		/* it fits at the beginning of the first M_DATA block */
1526*7c478bd9Sstevel@tonic-gate 		freeb(mp);	/* don't need the M_PROTO anymore */
1527*7c478bd9Sstevel@tonic-gate 	} else if (DB_REF(mp) == 1 && MBLKSIZE(mp) >= hdrlen) {
1528*7c478bd9Sstevel@tonic-gate 		/* we can reuse the dl_unitdata_req M_PROTO mblk */
1529*7c478bd9Sstevel@tonic-gate 		nmp = mp;
1530*7c478bd9Sstevel@tonic-gate 		DB_TYPE(nmp) = M_DATA;
1531*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1532*7c478bd9Sstevel@tonic-gate 	} else {
1533*7c478bd9Sstevel@tonic-gate 		/* we need to allocate one */
1534*7c478bd9Sstevel@tonic-gate 		if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL) {
1535*7c478bd9Sstevel@tonic-gate 			if (pmp != NULL)
1536*7c478bd9Sstevel@tonic-gate 				freemsg(pmp);
1537*7c478bd9Sstevel@tonic-gate 			return (NULL);
1538*7c478bd9Sstevel@tonic-gate 		}
1539*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1540*7c478bd9Sstevel@tonic-gate 		linkb(nmp, mp->b_cont);
1541*7c478bd9Sstevel@tonic-gate 		freeb(mp);
1542*7c478bd9Sstevel@tonic-gate 	}
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
1545*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
1546*7c478bd9Sstevel@tonic-gate 		/* create the snap header */
1547*7c478bd9Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
1548*7c478bd9Sstevel@tonic-gate 		llcmp = nmp;	/* LLC header is going to be in this mblk */
1549*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1550*7c478bd9Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1551*7c478bd9Sstevel@tonic-gate 		*snap = llc_snap_def;
1552*7c478bd9Sstevel@tonic-gate 		SET_NET_USHORT(snap->type, type);
1553*7c478bd9Sstevel@tonic-gate 	}
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 	/* Hold SR tables still while we maybe point at an entry */
1556*7c478bd9Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	gld_rcc_send(macinfo, WR(gld->gld_qptr), dhost, &rh, llcmp->b_rptr);
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate 	if (rh != NULL) {
1561*7c478bd9Sstevel@tonic-gate 		/* copy in the RIF */
1562*7c478bd9Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
1563*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
1564*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)rh, (caddr_t)nmp->b_rptr, rh->len);
1565*7c478bd9Sstevel@tonic-gate 	}
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 	/* no longer need the pulled-up mblk */
1570*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL)
1571*7c478bd9Sstevel@tonic-gate 		freemsg(pmp);
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 	/*
1574*7c478bd9Sstevel@tonic-gate 	 * fill in token ring header
1575*7c478bd9Sstevel@tonic-gate 	 */
1576*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1577*7c478bd9Sstevel@tonic-gate 	mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
1578*7c478bd9Sstevel@tonic-gate 	mh->tr_ac = 0x10;
1579*7c478bd9Sstevel@tonic-gate 	mh->tr_fc = 0x40;
1580*7c478bd9Sstevel@tonic-gate 	mac_copy(dhost, mh->tr_dhost, macinfo->gldm_addrlen);
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate 	/*
1583*7c478bd9Sstevel@tonic-gate 	 * We access the mac address without the mutex to prevent
1584*7c478bd9Sstevel@tonic-gate 	 * mutex contention (BUG 4211361)
1585*7c478bd9Sstevel@tonic-gate 	 */
1586*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1587*7c478bd9Sstevel@tonic-gate 	    mh->tr_shost, macinfo->gldm_addrlen);
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 	if (rh != NULL)
1590*7c478bd9Sstevel@tonic-gate 		mh->tr_shost[0] |= 0x80;
1591*7c478bd9Sstevel@tonic-gate 	else
1592*7c478bd9Sstevel@tonic-gate 		mh->tr_shost[0] &= ~0x80;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	return (nmp);
1595*7c478bd9Sstevel@tonic-gate }
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate /*
1598*7c478bd9Sstevel@tonic-gate  * We cannot have our client sending us "fastpath" M_DATA messages,
1599*7c478bd9Sstevel@tonic-gate  * because to do that we must provide to him a fixed MAC header to
1600*7c478bd9Sstevel@tonic-gate  * be prepended to each outgoing packet.  But with Source Routing
1601*7c478bd9Sstevel@tonic-gate  * media, the length and content of the MAC header changes as the
1602*7c478bd9Sstevel@tonic-gate  * routes change, so there is no fixed header we can provide.  So
1603*7c478bd9Sstevel@tonic-gate  * we decline to accept M_DATA messages if Source Routing is enabled.
1604*7c478bd9Sstevel@tonic-gate  */
1605*7c478bd9Sstevel@tonic-gate mblk_t *
1606*7c478bd9Sstevel@tonic-gate gld_fastpath_tr(gld_t *gld, mblk_t *mp)
1607*7c478bd9Sstevel@tonic-gate {
1608*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
1609*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
1610*7c478bd9Sstevel@tonic-gate 	struct gld_dlsap *gldp = DLSAP(dlp, dlp->dl_dest_addr_offset);
1611*7c478bd9Sstevel@tonic-gate 	unsigned short type;
1612*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1613*7c478bd9Sstevel@tonic-gate 	struct tr_mac_frm_nori *mh;
1614*7c478bd9Sstevel@tonic-gate 	int hdrlen;
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 	/*
1619*7c478bd9Sstevel@tonic-gate 	 * If we are doing Source Routing, then we cannot provide a fixed
1620*7c478bd9Sstevel@tonic-gate 	 * MAC header, so fail.
1621*7c478bd9Sstevel@tonic-gate 	 */
1622*7c478bd9Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
1623*7c478bd9Sstevel@tonic-gate 		return (NULL);
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 	/* look in the unitdata request for a sap, else use bound one */
1626*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_dest_addr_length >= DLSAPLENGTH(macinfo) &&
1627*7c478bd9Sstevel@tonic-gate 	    REF_HOST_USHORT(gldp->glda_sap) != 0)
1628*7c478bd9Sstevel@tonic-gate 		type = REF_HOST_USHORT(gldp->glda_sap);
1629*7c478bd9Sstevel@tonic-gate 	else
1630*7c478bd9Sstevel@tonic-gate 		type = gld->gld_sap;
1631*7c478bd9Sstevel@tonic-gate 
1632*7c478bd9Sstevel@tonic-gate 	hdrlen = sizeof (struct tr_mac_frm_nori);
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
1635*7c478bd9Sstevel@tonic-gate 		hdrlen += ri_ste_def.len;
1636*7c478bd9Sstevel@tonic-gate 
1637*7c478bd9Sstevel@tonic-gate 	/*
1638*7c478bd9Sstevel@tonic-gate 	 * Check whether we need to do EtherType encoding or whether the packet
1639*7c478bd9Sstevel@tonic-gate 	 * will be LLC.
1640*7c478bd9Sstevel@tonic-gate 	 */
1641*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP)
1642*7c478bd9Sstevel@tonic-gate 		hdrlen += sizeof (struct llc_snap_hdr);
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(hdrlen, BPRI_MED)) == NULL)
1645*7c478bd9Sstevel@tonic-gate 		return (NULL);
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1648*7c478bd9Sstevel@tonic-gate 
1649*7c478bd9Sstevel@tonic-gate 	/* Got the space, now copy in the header components */
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate 	if (type > GLD_MAX_802_SAP) {
1652*7c478bd9Sstevel@tonic-gate 		/* create the snap header */
1653*7c478bd9Sstevel@tonic-gate 		struct llc_snap_hdr *snap;
1654*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= sizeof (struct llc_snap_hdr);
1655*7c478bd9Sstevel@tonic-gate 		snap  = (struct llc_snap_hdr *)(nmp->b_rptr);
1656*7c478bd9Sstevel@tonic-gate 		*snap = llc_snap_def;
1657*7c478bd9Sstevel@tonic-gate 		snap->type = htons(type);	/* we know it's aligned */
1658*7c478bd9Sstevel@tonic-gate 	}
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate 	/* RDE is disabled, use NULL RIF, or STE RIF */
1661*7c478bd9Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
1662*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= ri_ste_def.len;
1663*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&ri_ste_def, (caddr_t)nmp->b_rptr,
1664*7c478bd9Sstevel@tonic-gate 		    ri_ste_def.len);
1665*7c478bd9Sstevel@tonic-gate 	}
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 	/*
1668*7c478bd9Sstevel@tonic-gate 	 * fill in token ring header
1669*7c478bd9Sstevel@tonic-gate 	 */
1670*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1671*7c478bd9Sstevel@tonic-gate 	mh = (struct tr_mac_frm_nori *)nmp->b_rptr;
1672*7c478bd9Sstevel@tonic-gate 	mh->tr_ac = 0x10;
1673*7c478bd9Sstevel@tonic-gate 	mh->tr_fc = 0x40;
1674*7c478bd9Sstevel@tonic-gate 	mac_copy(gldp->glda_addr, mh->tr_dhost, macinfo->gldm_addrlen);
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
1677*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1678*7c478bd9Sstevel@tonic-gate 	    mh->tr_shost, macinfo->gldm_addrlen);
1679*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
1680*7c478bd9Sstevel@tonic-gate 
1681*7c478bd9Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste)
1682*7c478bd9Sstevel@tonic-gate 		mh->tr_shost[0] |= 0x80;
1683*7c478bd9Sstevel@tonic-gate 	else
1684*7c478bd9Sstevel@tonic-gate 		mh->tr_shost[0] &= ~0x80;
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate 	return (nmp);
1687*7c478bd9Sstevel@tonic-gate }
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate /*
1690*7c478bd9Sstevel@tonic-gate  * Route Determination Entity (ISO 8802-2 / IEEE 802.2 : 1994, Section 9)
1691*7c478bd9Sstevel@tonic-gate  *
1692*7c478bd9Sstevel@tonic-gate  * RDE is an LLC layer entity.  GLD is a MAC layer entity.  The proper
1693*7c478bd9Sstevel@tonic-gate  * solution to this architectural anomaly is to move RDE support out of GLD
1694*7c478bd9Sstevel@tonic-gate  * and into LLC where it belongs.  In particular, only LLC has the knowledge
1695*7c478bd9Sstevel@tonic-gate  * necessary to reply to XID and TEST packets.  If and when it comes time to
1696*7c478bd9Sstevel@tonic-gate  * move RDE out of GLD to LLC, the LLC-to-GLD interface should be modified
1697*7c478bd9Sstevel@tonic-gate  * to use MA_UNITDATA structures rather than DL_UNITDATA structures.  Of
1698*7c478bd9Sstevel@tonic-gate  * course, GLD will still have to continue to also support the DL_ structures
1699*7c478bd9Sstevel@tonic-gate  * as long as IP is not layered over LLC.  Another, perhaps better, idea
1700*7c478bd9Sstevel@tonic-gate  * would be to make RDE an autopush module on top of the token ring drivers:
1701*7c478bd9Sstevel@tonic-gate  * RDE would sit between LLC and GLD.  It would then also sit between IP and
1702*7c478bd9Sstevel@tonic-gate  * GLD, providing services to all clients of GLD/tokenring.  In that case,
1703*7c478bd9Sstevel@tonic-gate  * GLD would still have to continue to support the DL_ interface for non-
1704*7c478bd9Sstevel@tonic-gate  * Token Ring interfaces, using the MA_ interface only for media supporting
1705*7c478bd9Sstevel@tonic-gate  * Source Routing media.
1706*7c478bd9Sstevel@tonic-gate  *
1707*7c478bd9Sstevel@tonic-gate  * At present, Token Ring is the only source routing medium we support.
1708*7c478bd9Sstevel@tonic-gate  * Since Token Ring is not at this time a strategic network medium for Sun,
1709*7c478bd9Sstevel@tonic-gate  * rather than devote a large amount of resources to creating a proper
1710*7c478bd9Sstevel@tonic-gate  * architecture and implementation of RDE, we do the minimum necessary to
1711*7c478bd9Sstevel@tonic-gate  * get it to work.  The interface between the above token ring code and the
1712*7c478bd9Sstevel@tonic-gate  * below RDE code is designed to make it relatively easy to change to an
1713*7c478bd9Sstevel@tonic-gate  * MA_UNITDATA model later should this ever become a priority.
1714*7c478bd9Sstevel@tonic-gate  */
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate static void gld_send_rqr(gld_mac_info_t *, uchar_t *, struct gld_ri *,
1717*7c478bd9Sstevel@tonic-gate     struct rde_pdu *, int);
1718*7c478bd9Sstevel@tonic-gate static void gld_rde_pdu_req(gld_mac_info_t *, queue_t *, uchar_t *,
1719*7c478bd9Sstevel@tonic-gate     struct gld_ri *, uchar_t, uchar_t, uchar_t);
1720*7c478bd9Sstevel@tonic-gate static void gld_get_route(gld_mac_info_t *, queue_t *, uchar_t *,
1721*7c478bd9Sstevel@tonic-gate     struct gld_ri **, uchar_t, uchar_t);
1722*7c478bd9Sstevel@tonic-gate static void gld_reset_route(gld_mac_info_t *, queue_t *,
1723*7c478bd9Sstevel@tonic-gate     uchar_t *, uchar_t, uchar_t);
1724*7c478bd9Sstevel@tonic-gate static void gld_rde_pdu_ind(gld_mac_info_t *, struct gld_ri *, struct rde_pdu *,
1725*7c478bd9Sstevel@tonic-gate     int);
1726*7c478bd9Sstevel@tonic-gate static void gld_rif_ind(gld_mac_info_t *, struct gld_ri *, uchar_t *,
1727*7c478bd9Sstevel@tonic-gate     uchar_t, uchar_t);
1728*7c478bd9Sstevel@tonic-gate static struct srtab **gld_sr_hash(struct srtab **, uchar_t *, int);
1729*7c478bd9Sstevel@tonic-gate static struct srtab *gld_sr_lookup_entry(gld_mac_info_t *, uchar_t *);
1730*7c478bd9Sstevel@tonic-gate static struct srtab *gld_sr_create_entry(gld_mac_info_t *, uchar_t *);
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate /*
1733*7c478bd9Sstevel@tonic-gate  * This routine implements a modified subset of the 802.2 RDE RCC receive
1734*7c478bd9Sstevel@tonic-gate  * actions:
1735*7c478bd9Sstevel@tonic-gate  *   we implement RCC receive events 3 to 12 (ISO 8802-2:1994 9.6.3.4);
1736*7c478bd9Sstevel@tonic-gate  *   we omit special handling for the NULL SAP;
1737*7c478bd9Sstevel@tonic-gate  *   we omit XID/TEST handling;
1738*7c478bd9Sstevel@tonic-gate  *   we pass all packets (including RDE) upstream to LLC.
1739*7c478bd9Sstevel@tonic-gate  */
1740*7c478bd9Sstevel@tonic-gate static void
1741*7c478bd9Sstevel@tonic-gate gld_rcc_receive(gld_mac_info_t *macinfo, pktinfo_t *pktinfo, struct gld_ri *rh,
1742*7c478bd9Sstevel@tonic-gate     uchar_t *llcpkt, int llcpktlen)
1743*7c478bd9Sstevel@tonic-gate {
1744*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled)
1747*7c478bd9Sstevel@tonic-gate 		return;
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 	/*
1750*7c478bd9Sstevel@tonic-gate 	 * First, ensure this packet wasn't something we received just
1751*7c478bd9Sstevel@tonic-gate 	 * because we were in promiscuous mode.  Since none of the below
1752*7c478bd9Sstevel@tonic-gate 	 * code wants to see group addressed packets anyway, we can do
1753*7c478bd9Sstevel@tonic-gate 	 * this check up front.  Since we're doing that, we can omit the
1754*7c478bd9Sstevel@tonic-gate 	 * checks for group addressed packets below.
1755*7c478bd9Sstevel@tonic-gate 	 */
1756*7c478bd9Sstevel@tonic-gate 	if (!pktinfo->isForMe)
1757*7c478bd9Sstevel@tonic-gate 		return;		/* Event 6 */
1758*7c478bd9Sstevel@tonic-gate 
1759*7c478bd9Sstevel@tonic-gate 	/* Process a subset of Route Determination Entity (RDE) packets */
1760*7c478bd9Sstevel@tonic-gate 	if (snaphdr->d_lsap == LSAP_RDE) {
1761*7c478bd9Sstevel@tonic-gate 		struct rde_pdu *pdu = (struct rde_pdu *)(llcpkt + LLC_HDR1_LEN);
1762*7c478bd9Sstevel@tonic-gate 		int pdulen = llcpktlen - LLC_HDR1_LEN;
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 		/* sanity check the PDU */
1765*7c478bd9Sstevel@tonic-gate 		if ((pdulen < sizeof (struct rde_pdu)) ||
1766*7c478bd9Sstevel@tonic-gate 		    (snaphdr->s_lsap != LSAP_RDE))
1767*7c478bd9Sstevel@tonic-gate 			return;
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 		/* we only handle route discovery PDUs, not XID/TEST/other */
1770*7c478bd9Sstevel@tonic-gate 		if (snaphdr->control != CNTL_LLC_UI)
1771*7c478bd9Sstevel@tonic-gate 			return;
1772*7c478bd9Sstevel@tonic-gate 
1773*7c478bd9Sstevel@tonic-gate 		switch (pdu->rde_ptype) {
1774*7c478bd9Sstevel@tonic-gate 		case RDE_RQC:	/* Route Query Command; Events 8 - 11 */
1775*7c478bd9Sstevel@tonic-gate 			gld_send_rqr(macinfo, pktinfo->shost, rh, pdu, pdulen);
1776*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
1777*7c478bd9Sstevel@tonic-gate 		case RDE_RQR:	/* Route Query Response; Event 12 */
1778*7c478bd9Sstevel@tonic-gate 		case RDE_RS:	/* Route Selected; Event 7 */
1779*7c478bd9Sstevel@tonic-gate 			gld_rde_pdu_ind(macinfo, rh, pdu, pdulen);
1780*7c478bd9Sstevel@tonic-gate 			break;
1781*7c478bd9Sstevel@tonic-gate 		default:	/* ignore if unrecognized ptype */
1782*7c478bd9Sstevel@tonic-gate 			return;
1783*7c478bd9Sstevel@tonic-gate 		}
1784*7c478bd9Sstevel@tonic-gate 
1785*7c478bd9Sstevel@tonic-gate 		return;
1786*7c478bd9Sstevel@tonic-gate 	}
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	/* Consider routes seen in other IA SRF packets */
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 	if (rh == NULL)
1791*7c478bd9Sstevel@tonic-gate 		return;		/* no RIF; Event 3 */
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	if ((rh->rt & 0x04) != 0)
1794*7c478bd9Sstevel@tonic-gate 		return;		/* not SRF; Event 5 */
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 	gld_rif_ind(macinfo, rh, pktinfo->shost, snaphdr->s_lsap,
1797*7c478bd9Sstevel@tonic-gate 	    snaphdr->d_lsap);	/* Event 4 */
1798*7c478bd9Sstevel@tonic-gate }
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate /*
1801*7c478bd9Sstevel@tonic-gate  * Send RQR: 802.2 9.6.3.4.2(9) RCC Receive Events 8-11
1802*7c478bd9Sstevel@tonic-gate  *
1803*7c478bd9Sstevel@tonic-gate  * The routing processing really doesn't belong here; it should be handled in
1804*7c478bd9Sstevel@tonic-gate  * the LLC layer above.  If that were the case then RDE could just send down
1805*7c478bd9Sstevel@tonic-gate  * an extra MA_UNITDATA_REQ with the info needed to construct the packet.  But
1806*7c478bd9Sstevel@tonic-gate  * at the time we get control here, it's not a particularly good time to be
1807*7c478bd9Sstevel@tonic-gate  * constructing packets and trying to send them.  Specifically, at this layer
1808*7c478bd9Sstevel@tonic-gate  * we need to construct the full media packet, which means the below routine
1809*7c478bd9Sstevel@tonic-gate  * knows that it is dealing with Token Ring media.  If this were instead done
1810*7c478bd9Sstevel@tonic-gate  * via a proper MA_UNITDATA interface, the RDE stuff could all be completely
1811*7c478bd9Sstevel@tonic-gate  * media independent.  But since TR is the only source routing medium we
1812*7c478bd9Sstevel@tonic-gate  * support, this works even though it is not clean.
1813*7c478bd9Sstevel@tonic-gate  *
1814*7c478bd9Sstevel@tonic-gate  * We "know" that the only time we can get here is from the "interpret"
1815*7c478bd9Sstevel@tonic-gate  * routine, and only when it was called at receive time.
1816*7c478bd9Sstevel@tonic-gate  */
1817*7c478bd9Sstevel@tonic-gate static void
1818*7c478bd9Sstevel@tonic-gate gld_send_rqr(gld_mac_info_t *macinfo, uchar_t *shost, struct gld_ri *rh,
1819*7c478bd9Sstevel@tonic-gate     struct rde_pdu *pdu, int pdulen)
1820*7c478bd9Sstevel@tonic-gate {
1821*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1822*7c478bd9Sstevel@tonic-gate 	int nlen;
1823*7c478bd9Sstevel@tonic-gate 	struct tr_mac_frm_nori *nmh;
1824*7c478bd9Sstevel@tonic-gate 	struct gld_ri *nrh;
1825*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *nsnaphdr;
1826*7c478bd9Sstevel@tonic-gate 	struct rde_pdu *npdu;
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate 	/* We know and assume we're on the receive path */
1829*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	if (pdulen < sizeof (struct rde_pdu))
1832*7c478bd9Sstevel@tonic-gate 		return;		/* Bad incoming PDU */
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 	nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
1835*7c478bd9Sstevel@tonic-gate 	    sizeof (struct rde_pdu);
1836*7c478bd9Sstevel@tonic-gate 
1837*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
1838*7c478bd9Sstevel@tonic-gate 		return;
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
1841*7c478bd9Sstevel@tonic-gate 
1842*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct rde_pdu);
1843*7c478bd9Sstevel@tonic-gate 	npdu = (struct rde_pdu *)(nmp->b_rptr);
1844*7c478bd9Sstevel@tonic-gate 	*npdu = *pdu;	/* copy orig/target macaddr/saps */
1845*7c478bd9Sstevel@tonic-gate 	npdu->rde_ver = 1;
1846*7c478bd9Sstevel@tonic-gate 	npdu->rde_ptype = RDE_RQR;
1847*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1848*7c478bd9Sstevel@tonic-gate 	    npdu->rde_target_mac, macinfo->gldm_addrlen);
1849*7c478bd9Sstevel@tonic-gate 
1850*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= LLC_HDR1_LEN;
1851*7c478bd9Sstevel@tonic-gate 	nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
1852*7c478bd9Sstevel@tonic-gate 	nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
1853*7c478bd9Sstevel@tonic-gate 	nsnaphdr->control = CNTL_LLC_UI;
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate 	if (rh == NULL || (rh->rt & 0x06) == 0x06 ||
1856*7c478bd9Sstevel@tonic-gate 	    rh->len > sizeof (struct gld_ri)) {
1857*7c478bd9Sstevel@tonic-gate 		/* no RIF (Event 8), or RIF type STE (Event 9): send ARE RQR */
1858*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= 2;
1859*7c478bd9Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
1860*7c478bd9Sstevel@tonic-gate 		nrh->len = 2;
1861*7c478bd9Sstevel@tonic-gate 		nrh->rt = RT_ARE;
1862*7c478bd9Sstevel@tonic-gate 		nrh->dir = 0;
1863*7c478bd9Sstevel@tonic-gate 		nrh->res = 0;
1864*7c478bd9Sstevel@tonic-gate 		nrh->mtu = RT_MTU_MAX;
1865*7c478bd9Sstevel@tonic-gate 	} else {
1866*7c478bd9Sstevel@tonic-gate 		/*
1867*7c478bd9Sstevel@tonic-gate 		 * RIF must be ARE (Event 10) or SRF (Event 11):
1868*7c478bd9Sstevel@tonic-gate 		 * send SRF (reverse) RQR
1869*7c478bd9Sstevel@tonic-gate 		 */
1870*7c478bd9Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
1871*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
1872*7c478bd9Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
1873*7c478bd9Sstevel@tonic-gate 		bcopy(rh, nrh, rh->len);	/* copy incoming RIF */
1874*7c478bd9Sstevel@tonic-gate 		nrh->rt = RT_SRF;		/* make it SRF */
1875*7c478bd9Sstevel@tonic-gate 		nrh->dir ^= 1;			/* reverse direction */
1876*7c478bd9Sstevel@tonic-gate 	}
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
1879*7c478bd9Sstevel@tonic-gate 	nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
1880*7c478bd9Sstevel@tonic-gate 	nmh->tr_ac = 0x10;
1881*7c478bd9Sstevel@tonic-gate 	nmh->tr_fc = 0x40;
1882*7c478bd9Sstevel@tonic-gate 	mac_copy(shost, nmh->tr_dhost, macinfo->gldm_addrlen);
1883*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
1884*7c478bd9Sstevel@tonic-gate 	    nmh->tr_shost, macinfo->gldm_addrlen);
1885*7c478bd9Sstevel@tonic-gate 	nmh->tr_shost[0] |= 0x80;		/* indicate RIF present */
1886*7c478bd9Sstevel@tonic-gate 
1887*7c478bd9Sstevel@tonic-gate 	/*
1888*7c478bd9Sstevel@tonic-gate 	 * Packet assembled; send it.
1889*7c478bd9Sstevel@tonic-gate 	 *
1890*7c478bd9Sstevel@tonic-gate 	 * As noted before, this is not really a good time to be trying to
1891*7c478bd9Sstevel@tonic-gate 	 * send out packets.  We have no obvious queue to use if the packet
1892*7c478bd9Sstevel@tonic-gate 	 * can't be sent right away.  We pick one arbitrarily.
1893*7c478bd9Sstevel@tonic-gate 	 */
1894*7c478bd9Sstevel@tonic-gate 	{
1895*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
1896*7c478bd9Sstevel@tonic-gate 	queue_t *q;
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
1899*7c478bd9Sstevel@tonic-gate 		/* oops, no vlan on the list for this macinfo! */
1900*7c478bd9Sstevel@tonic-gate 		/* this should not happen */
1901*7c478bd9Sstevel@tonic-gate 		freeb(nmp);
1902*7c478bd9Sstevel@tonic-gate 		return;
1903*7c478bd9Sstevel@tonic-gate 	}
1904*7c478bd9Sstevel@tonic-gate 	q = vlan->gldv_str_next->gld_qptr;
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	/*
1907*7c478bd9Sstevel@tonic-gate 	 * Queue the packet and let gld_wsrv
1908*7c478bd9Sstevel@tonic-gate 	 * handle it, thus preventing a panic
1909*7c478bd9Sstevel@tonic-gate 	 * caused by v2 TR in promiscuous mode
1910*7c478bd9Sstevel@tonic-gate 	 * where it attempts to get the mutex
1911*7c478bd9Sstevel@tonic-gate 	 * in this thread while already holding
1912*7c478bd9Sstevel@tonic-gate 	 * it.
1913*7c478bd9Sstevel@tonic-gate 	 */
1914*7c478bd9Sstevel@tonic-gate 	(void) putbq(WR(q), nmp);
1915*7c478bd9Sstevel@tonic-gate 	qenable(WR(q));
1916*7c478bd9Sstevel@tonic-gate 	}
1917*7c478bd9Sstevel@tonic-gate }
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate /*
1920*7c478bd9Sstevel@tonic-gate  * This routine implements a modified subset of the 802.2 RDE RCC send actions:
1921*7c478bd9Sstevel@tonic-gate  *   we implement RCC send events 5 to 10 (ISO 8802-2:1994 9.6.3.5);
1922*7c478bd9Sstevel@tonic-gate  *   we omit special handling for the NULL SAP;
1923*7c478bd9Sstevel@tonic-gate  *   events 11 to 12 are handled by gld_rde_pdu_req below;
1924*7c478bd9Sstevel@tonic-gate  *   we require an immediate response to our GET_ROUTE_REQUEST.
1925*7c478bd9Sstevel@tonic-gate  */
1926*7c478bd9Sstevel@tonic-gate static void
1927*7c478bd9Sstevel@tonic-gate gld_rcc_send(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
1928*7c478bd9Sstevel@tonic-gate     struct gld_ri **rhp, uchar_t *llcpkt)
1929*7c478bd9Sstevel@tonic-gate {
1930*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *snaphdr = (struct llc_snap_hdr *)(llcpkt);
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	/*
1933*7c478bd9Sstevel@tonic-gate 	 * Our caller has to take the mutex because: to avoid an extra bcopy
1934*7c478bd9Sstevel@tonic-gate 	 * of the RIF on every transmit, we pass back a pointer to our sr
1935*7c478bd9Sstevel@tonic-gate 	 * table entry via rhp.  He has to keep the mutex until he has a
1936*7c478bd9Sstevel@tonic-gate 	 * chance to copy the RIF out into the outgoing packet, so that we
1937*7c478bd9Sstevel@tonic-gate 	 * don't modify the entry while he's trying to copy it.  This is a
1938*7c478bd9Sstevel@tonic-gate 	 * little ugly, but saves the extra bcopy.
1939*7c478bd9Sstevel@tonic-gate 	 */
1940*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
1941*7c478bd9Sstevel@tonic-gate 
1942*7c478bd9Sstevel@tonic-gate 	*rhp = (struct gld_ri *)NULL;	/* start off clean (no RIF) */
1943*7c478bd9Sstevel@tonic-gate 
1944*7c478bd9Sstevel@tonic-gate 	if (!((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_enabled) {
1945*7c478bd9Sstevel@tonic-gate 		/* RDE is disabled -- use NULL or STE always */
1946*7c478bd9Sstevel@tonic-gate 		if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
1947*7c478bd9Sstevel@tonic-gate 		    rde_str_indicator_ste)
1948*7c478bd9Sstevel@tonic-gate 			*rhp = &ri_ste_def;	/* STE option */
1949*7c478bd9Sstevel@tonic-gate 		return;
1950*7c478bd9Sstevel@tonic-gate 	}
1951*7c478bd9Sstevel@tonic-gate 
1952*7c478bd9Sstevel@tonic-gate 	if (!(dhost[0] & 0x80)) {
1953*7c478bd9Sstevel@tonic-gate 		/* individual address; Events 7 - 10 */
1954*7c478bd9Sstevel@tonic-gate 		if ((snaphdr->control & 0xef) == 0xe3) {
1955*7c478bd9Sstevel@tonic-gate 			/* TEST command, reset the route */
1956*7c478bd9Sstevel@tonic-gate 			gld_reset_route(macinfo, q,
1957*7c478bd9Sstevel@tonic-gate 			    dhost, snaphdr->d_lsap, snaphdr->s_lsap);
1958*7c478bd9Sstevel@tonic-gate 		}
1959*7c478bd9Sstevel@tonic-gate 		gld_get_route(macinfo, q,
1960*7c478bd9Sstevel@tonic-gate 		    dhost, rhp, snaphdr->d_lsap, snaphdr->s_lsap);
1961*7c478bd9Sstevel@tonic-gate 	}
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 	if (*rhp == NULL) {
1964*7c478bd9Sstevel@tonic-gate 		/*
1965*7c478bd9Sstevel@tonic-gate 		 * group address (Events 5 - 6),
1966*7c478bd9Sstevel@tonic-gate 		 * or no route available (Events 8 - 9):
1967*7c478bd9Sstevel@tonic-gate 		 * Need to send NSR or STE, as configured.
1968*7c478bd9Sstevel@tonic-gate 		 */
1969*7c478bd9Sstevel@tonic-gate 		if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->
1970*7c478bd9Sstevel@tonic-gate 		    rde_str_indicator_ste)
1971*7c478bd9Sstevel@tonic-gate 			*rhp = &ri_ste_def;	/* STE option */
1972*7c478bd9Sstevel@tonic-gate 	}
1973*7c478bd9Sstevel@tonic-gate }
1974*7c478bd9Sstevel@tonic-gate 
1975*7c478bd9Sstevel@tonic-gate /*
1976*7c478bd9Sstevel@tonic-gate  * RCC send events 11 - 12
1977*7c478bd9Sstevel@tonic-gate  *
1978*7c478bd9Sstevel@tonic-gate  * At present we only handle the RQC ptype.
1979*7c478bd9Sstevel@tonic-gate  *
1980*7c478bd9Sstevel@tonic-gate  * We "know" that the only time we can get here is from the "unitdata"
1981*7c478bd9Sstevel@tonic-gate  * routine, called at wsrv time.
1982*7c478bd9Sstevel@tonic-gate  *
1983*7c478bd9Sstevel@tonic-gate  * If we ever implement the RS ptype (Event 13), this may no longer be true!
1984*7c478bd9Sstevel@tonic-gate  */
1985*7c478bd9Sstevel@tonic-gate static void
1986*7c478bd9Sstevel@tonic-gate gld_rde_pdu_req(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
1987*7c478bd9Sstevel@tonic-gate     struct gld_ri *rh, uchar_t dsap, uchar_t ssap, uchar_t ptype)
1988*7c478bd9Sstevel@tonic-gate {
1989*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1990*7c478bd9Sstevel@tonic-gate 	int nlen;
1991*7c478bd9Sstevel@tonic-gate 	struct tr_mac_frm_nori *nmh;
1992*7c478bd9Sstevel@tonic-gate 	struct gld_ri *nrh;
1993*7c478bd9Sstevel@tonic-gate 	struct llc_snap_hdr *nsnaphdr;
1994*7c478bd9Sstevel@tonic-gate 	struct rde_pdu *npdu;
1995*7c478bd9Sstevel@tonic-gate 	int srpresent = 0;
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 	/* if you change this to process other types, review all code below */
1998*7c478bd9Sstevel@tonic-gate 	ASSERT(ptype == RDE_RQC);
1999*7c478bd9Sstevel@tonic-gate 	ASSERT(rh == NULL);	/* RQC never uses SRF */
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate 	nlen = sizeof (struct tr_mac_frm) + LLC_HDR1_LEN +
2002*7c478bd9Sstevel@tonic-gate 	    sizeof (struct rde_pdu);
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(nlen, BPRI_MED)) == NULL)
2005*7c478bd9Sstevel@tonic-gate 		return;
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_wptr = DB_LIM(nmp);
2008*7c478bd9Sstevel@tonic-gate 
2009*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct rde_pdu);
2010*7c478bd9Sstevel@tonic-gate 	npdu = (struct rde_pdu *)(nmp->b_rptr);
2011*7c478bd9Sstevel@tonic-gate 	npdu->rde_ver = 1;
2012*7c478bd9Sstevel@tonic-gate 	npdu->rde_ptype = ptype;
2013*7c478bd9Sstevel@tonic-gate 	mac_copy(dhost, &npdu->rde_target_mac, 6);
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 	/*
2016*7c478bd9Sstevel@tonic-gate 	 * access the mac address without a mutex - take a risk -
2017*7c478bd9Sstevel@tonic-gate 	 * to prevent mutex contention (BUG 4211361)
2018*7c478bd9Sstevel@tonic-gate 	 */
2019*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
2020*7c478bd9Sstevel@tonic-gate 	    &npdu->rde_orig_mac, 6);
2021*7c478bd9Sstevel@tonic-gate 	npdu->rde_target_sap = dsap;
2022*7c478bd9Sstevel@tonic-gate 	npdu->rde_orig_sap = ssap;
2023*7c478bd9Sstevel@tonic-gate 
2024*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= LLC_HDR1_LEN;
2025*7c478bd9Sstevel@tonic-gate 	nsnaphdr = (struct llc_snap_hdr *)(nmp->b_rptr);
2026*7c478bd9Sstevel@tonic-gate 	nsnaphdr->s_lsap = nsnaphdr->d_lsap = LSAP_RDE;
2027*7c478bd9Sstevel@tonic-gate 	nsnaphdr->control = CNTL_LLC_UI;
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate #if 0	/* we don't need this for now */
2030*7c478bd9Sstevel@tonic-gate 	if (rh != NULL) {
2031*7c478bd9Sstevel@tonic-gate 		/* send an SRF frame with specified RIF */
2032*7c478bd9Sstevel@tonic-gate 		ASSERT(rh->len <= sizeof (struct gld_ri));
2033*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= rh->len;
2034*7c478bd9Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
2035*7c478bd9Sstevel@tonic-gate 		bcopy(rh, nrh, rh->len);
2036*7c478bd9Sstevel@tonic-gate 		ASSERT(nrh->rt == RT_SRF);
2037*7c478bd9Sstevel@tonic-gate 		srpresent = 1;
2038*7c478bd9Sstevel@tonic-gate 	} else
2039*7c478bd9Sstevel@tonic-gate #endif
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate 	/* Need to send NSR or STE, as configured.  */
2042*7c478bd9Sstevel@tonic-gate 	if (((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_str_indicator_ste) {
2043*7c478bd9Sstevel@tonic-gate 		/* send an STE frame */
2044*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr -= 2;
2045*7c478bd9Sstevel@tonic-gate 		nrh = (struct gld_ri *)(nmp->b_rptr);
2046*7c478bd9Sstevel@tonic-gate 		nrh->len = 2;
2047*7c478bd9Sstevel@tonic-gate 		nrh->rt = RT_STE;
2048*7c478bd9Sstevel@tonic-gate 		nrh->dir = 0;
2049*7c478bd9Sstevel@tonic-gate 		nrh->res = 0;
2050*7c478bd9Sstevel@tonic-gate 		nrh->mtu = RT_MTU_MAX;
2051*7c478bd9Sstevel@tonic-gate 		srpresent = 1;
2052*7c478bd9Sstevel@tonic-gate 	} /* else send an NSR frame */
2053*7c478bd9Sstevel@tonic-gate 
2054*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr -= sizeof (struct tr_mac_frm_nori);
2055*7c478bd9Sstevel@tonic-gate 	nmh = (struct tr_mac_frm_nori *)(nmp->b_rptr);
2056*7c478bd9Sstevel@tonic-gate 	nmh->tr_ac = 0x10;
2057*7c478bd9Sstevel@tonic-gate 	nmh->tr_fc = 0x40;
2058*7c478bd9Sstevel@tonic-gate 	mac_copy(dhost, nmh->tr_dhost, macinfo->gldm_addrlen);
2059*7c478bd9Sstevel@tonic-gate 	/*
2060*7c478bd9Sstevel@tonic-gate 	 * access the mac address without a mutex - take a risk -
2061*7c478bd9Sstevel@tonic-gate 	 * to prevent mutex contention  - BUG 4211361
2062*7c478bd9Sstevel@tonic-gate 	 */
2063*7c478bd9Sstevel@tonic-gate 	mac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
2064*7c478bd9Sstevel@tonic-gate 	    nmh->tr_shost, macinfo->gldm_addrlen);
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 	if (srpresent)
2067*7c478bd9Sstevel@tonic-gate 		nmh->tr_shost[0] |= 0x80;
2068*7c478bd9Sstevel@tonic-gate 	else
2069*7c478bd9Sstevel@tonic-gate 		nmh->tr_shost[0] &= ~0x80;
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 	/*
2072*7c478bd9Sstevel@tonic-gate 	 * Packet assembled; send it.
2073*7c478bd9Sstevel@tonic-gate 	 *
2074*7c478bd9Sstevel@tonic-gate 	 * Since we own the SR_MUTEX, we don't want to take the maclock
2075*7c478bd9Sstevel@tonic-gate 	 * mutex (since they are acquired in the opposite order on the
2076*7c478bd9Sstevel@tonic-gate 	 * receive path, so deadlock could occur).  We could rearrange
2077*7c478bd9Sstevel@tonic-gate 	 * the code in gld_get_route() and drop the SR_MUTEX around the
2078*7c478bd9Sstevel@tonic-gate 	 * call to gld_rde_pdu_req(), but that's kind of ugly.  Rather,
2079*7c478bd9Sstevel@tonic-gate 	 * we just refrain from calling gld_start() from here, and
2080*7c478bd9Sstevel@tonic-gate 	 * instead just queue the packet for wsrv to send next.  Besides,
2081*7c478bd9Sstevel@tonic-gate 	 * it's more important to get the packet we're working on out
2082*7c478bd9Sstevel@tonic-gate 	 * quickly than this RQC.
2083*7c478bd9Sstevel@tonic-gate 	 */
2084*7c478bd9Sstevel@tonic-gate 	(void) putbq(WR(q), nmp);
2085*7c478bd9Sstevel@tonic-gate 	qenable(WR(q));
2086*7c478bd9Sstevel@tonic-gate }
2087*7c478bd9Sstevel@tonic-gate 
2088*7c478bd9Sstevel@tonic-gate /*
2089*7c478bd9Sstevel@tonic-gate  * Route Determination Component (RDC)
2090*7c478bd9Sstevel@tonic-gate  *
2091*7c478bd9Sstevel@tonic-gate  * We do not implement separate routes for each SAP, as specified by
2092*7c478bd9Sstevel@tonic-gate  * ISO 8802-2; instead we implement only one route per remote mac address.
2093*7c478bd9Sstevel@tonic-gate  */
2094*7c478bd9Sstevel@tonic-gate static void
2095*7c478bd9Sstevel@tonic-gate gld_get_route(gld_mac_info_t *macinfo, queue_t *q, uchar_t *dhost,
2096*7c478bd9Sstevel@tonic-gate     struct gld_ri **rhp, uchar_t dsap, uchar_t ssap)
2097*7c478bd9Sstevel@tonic-gate {
2098*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2099*7c478bd9Sstevel@tonic-gate 	clock_t t = ddi_get_lbolt();
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 	sr = gld_sr_lookup_entry(macinfo, dhost);
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	if (sr == NULL) {
2106*7c478bd9Sstevel@tonic-gate 		/*
2107*7c478bd9Sstevel@tonic-gate 		 * we have no entry -- never heard of this address:
2108*7c478bd9Sstevel@tonic-gate 		 * create an empty entry and initiate RQC
2109*7c478bd9Sstevel@tonic-gate 		 */
2110*7c478bd9Sstevel@tonic-gate 		sr = gld_sr_create_entry(macinfo, dhost);
2111*7c478bd9Sstevel@tonic-gate 		gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
2112*7c478bd9Sstevel@tonic-gate 		    dsap, ssap, RDE_RQC);
2113*7c478bd9Sstevel@tonic-gate 		if (sr)
2114*7c478bd9Sstevel@tonic-gate 			sr->sr_timer = t;
2115*7c478bd9Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route yet */
2116*7c478bd9Sstevel@tonic-gate 		return;
2117*7c478bd9Sstevel@tonic-gate 	}
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate 	/* we have an entry; see if we know a route yet */
2120*7c478bd9Sstevel@tonic-gate 
2121*7c478bd9Sstevel@tonic-gate 	if (sr->sr_ri.len == 0) {
2122*7c478bd9Sstevel@tonic-gate 		/* Have asked RQC, but no reply (yet) */
2123*7c478bd9Sstevel@tonic-gate 		if (t - sr->sr_timer >
2124*7c478bd9Sstevel@tonic-gate 		    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
2125*7c478bd9Sstevel@tonic-gate 			/* RQR overdue, resend RQC */
2126*7c478bd9Sstevel@tonic-gate 			gld_rde_pdu_req(macinfo, q, dhost,
2127*7c478bd9Sstevel@tonic-gate 			    (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
2128*7c478bd9Sstevel@tonic-gate 			sr->sr_timer = t;
2129*7c478bd9Sstevel@tonic-gate 		}
2130*7c478bd9Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route yet */
2131*7c478bd9Sstevel@tonic-gate 		return;
2132*7c478bd9Sstevel@tonic-gate 	}
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	/* we know a route, or it's local */
2135*7c478bd9Sstevel@tonic-gate 
2136*7c478bd9Sstevel@tonic-gate 	/* if it might be stale, reset and get a new one */
2137*7c478bd9Sstevel@tonic-gate 	if (t - sr->sr_timer >
2138*7c478bd9Sstevel@tonic-gate 	    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->rde_timeout) {
2139*7c478bd9Sstevel@tonic-gate 		gld_rde_pdu_req(macinfo, q, dhost,
2140*7c478bd9Sstevel@tonic-gate 		    (struct gld_ri *)NULL, dsap, ssap, RDE_RQC);
2141*7c478bd9Sstevel@tonic-gate 		sr->sr_ri.len = 0;
2142*7c478bd9Sstevel@tonic-gate 		sr->sr_timer = t;
2143*7c478bd9Sstevel@tonic-gate 		*rhp = NULL;		/* we have no route */
2144*7c478bd9Sstevel@tonic-gate 		return;
2145*7c478bd9Sstevel@tonic-gate 	}
2146*7c478bd9Sstevel@tonic-gate 
2147*7c478bd9Sstevel@tonic-gate 	if (sr->sr_ri.len == 2) {
2148*7c478bd9Sstevel@tonic-gate 		/* the remote site is on our local ring -- no route needed */
2149*7c478bd9Sstevel@tonic-gate 		*rhp = NULL;
2150*7c478bd9Sstevel@tonic-gate 		return;
2151*7c478bd9Sstevel@tonic-gate 	}
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	*rhp = &sr->sr_ri;	/* we have a route, return it */
2154*7c478bd9Sstevel@tonic-gate }
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate /*
2157*7c478bd9Sstevel@tonic-gate  * zap the specified entry and reinitiate RQC
2158*7c478bd9Sstevel@tonic-gate  */
2159*7c478bd9Sstevel@tonic-gate static void
2160*7c478bd9Sstevel@tonic-gate gld_reset_route(gld_mac_info_t *macinfo, queue_t *q,
2161*7c478bd9Sstevel@tonic-gate     uchar_t *dhost, uchar_t dsap, uchar_t ssap)
2162*7c478bd9Sstevel@tonic-gate {
2163*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2166*7c478bd9Sstevel@tonic-gate 
2167*7c478bd9Sstevel@tonic-gate 	sr = gld_sr_create_entry(macinfo, dhost);
2168*7c478bd9Sstevel@tonic-gate 	gld_rde_pdu_req(macinfo, q, dhost, (struct gld_ri *)NULL,
2169*7c478bd9Sstevel@tonic-gate 	    dsap, ssap, RDE_RQC);
2170*7c478bd9Sstevel@tonic-gate 	if (sr == NULL)
2171*7c478bd9Sstevel@tonic-gate 		return;
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 	sr->sr_ri.len = 0;
2174*7c478bd9Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
2175*7c478bd9Sstevel@tonic-gate }
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate /*
2178*7c478bd9Sstevel@tonic-gate  * This routine is called when an RDE PDU is received from our peer.
2179*7c478bd9Sstevel@tonic-gate  * If it is an RS (Route Selected) PDU, we adopt the specified route.
2180*7c478bd9Sstevel@tonic-gate  * If it is an RQR (reply to our previous RQC), we evaluate the
2181*7c478bd9Sstevel@tonic-gate  * specified route in comparison with our current known route, if any,
2182*7c478bd9Sstevel@tonic-gate  * and we keep the "better" of the two routes.
2183*7c478bd9Sstevel@tonic-gate  */
2184*7c478bd9Sstevel@tonic-gate static void
2185*7c478bd9Sstevel@tonic-gate gld_rde_pdu_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, struct rde_pdu *pdu,
2186*7c478bd9Sstevel@tonic-gate     int pdulen)
2187*7c478bd9Sstevel@tonic-gate {
2188*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2189*7c478bd9Sstevel@tonic-gate 	uchar_t *otherhost;
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 	if (pdulen < sizeof (struct rde_pdu))
2192*7c478bd9Sstevel@tonic-gate 		return;		/* Bad incoming PDU */
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQC)
2195*7c478bd9Sstevel@tonic-gate 		return;			/* ignore RQC */
2196*7c478bd9Sstevel@tonic-gate 
2197*7c478bd9Sstevel@tonic-gate 	if (pdu->rde_ptype != RDE_RQR && pdu->rde_ptype != RDE_RS) {
2198*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2199*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2200*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "gld: bogus RDE ptype 0x%x received",
2201*7c478bd9Sstevel@tonic-gate 			    pdu->rde_ptype);
2202*7c478bd9Sstevel@tonic-gate #endif
2203*7c478bd9Sstevel@tonic-gate 		return;
2204*7c478bd9Sstevel@tonic-gate 	}
2205*7c478bd9Sstevel@tonic-gate 
2206*7c478bd9Sstevel@tonic-gate 	if (rh == NULL) {
2207*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2208*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2209*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2210*7c478bd9Sstevel@tonic-gate 			    "gld: bogus NULL RIF, ptype 0x%x received",
2211*7c478bd9Sstevel@tonic-gate 			    pdu->rde_ptype);
2212*7c478bd9Sstevel@tonic-gate #endif
2213*7c478bd9Sstevel@tonic-gate 		return;
2214*7c478bd9Sstevel@tonic-gate 	}
2215*7c478bd9Sstevel@tonic-gate 
2216*7c478bd9Sstevel@tonic-gate 	ASSERT(rh->len >= 2);
2217*7c478bd9Sstevel@tonic-gate 	ASSERT(rh->len <= sizeof (struct gld_ri));
2218*7c478bd9Sstevel@tonic-gate 	ASSERT((rh->len & 1) == 0);
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQR) {
2221*7c478bd9Sstevel@tonic-gate 		/* A reply to our RQC has his address as target mac */
2222*7c478bd9Sstevel@tonic-gate 		otherhost = pdu->rde_target_mac;
2223*7c478bd9Sstevel@tonic-gate 	} else {
2224*7c478bd9Sstevel@tonic-gate 		ASSERT(pdu->rde_ptype == RDE_RS);
2225*7c478bd9Sstevel@tonic-gate 		/* An RS has his address as orig mac */
2226*7c478bd9Sstevel@tonic-gate 		otherhost = pdu->rde_orig_mac;
2227*7c478bd9Sstevel@tonic-gate 	}
2228*7c478bd9Sstevel@tonic-gate 
2229*7c478bd9Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 	if ((sr = gld_sr_create_entry(macinfo, otherhost)) == NULL) {
2232*7c478bd9Sstevel@tonic-gate 		mutex_exit(GLD_SR_MUTEX(macinfo));
2233*7c478bd9Sstevel@tonic-gate 		return;		/* oh well, out of memory */
2234*7c478bd9Sstevel@tonic-gate 	}
2235*7c478bd9Sstevel@tonic-gate 
2236*7c478bd9Sstevel@tonic-gate 	if (pdu->rde_ptype == RDE_RQR) {
2237*7c478bd9Sstevel@tonic-gate 		/* see if new route is better than what we may already have */
2238*7c478bd9Sstevel@tonic-gate 		if (sr->sr_ri.len != 0 &&
2239*7c478bd9Sstevel@tonic-gate 		    sr->sr_ri.len <= rh->len) {
2240*7c478bd9Sstevel@tonic-gate 			mutex_exit(GLD_SR_MUTEX(macinfo));
2241*7c478bd9Sstevel@tonic-gate 			return;	/* we have one, and new one is no shorter */
2242*7c478bd9Sstevel@tonic-gate 		}
2243*7c478bd9Sstevel@tonic-gate 	}
2244*7c478bd9Sstevel@tonic-gate 
2245*7c478bd9Sstevel@tonic-gate 	/* adopt the new route */
2246*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
2247*7c478bd9Sstevel@tonic-gate 	sr->sr_ri.rt = RT_SRF;	/* make it a clean SRF */
2248*7c478bd9Sstevel@tonic-gate 	sr->sr_ri.dir ^= 1;	/* reverse direction */
2249*7c478bd9Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
2250*7c478bd9Sstevel@tonic-gate 
2251*7c478bd9Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
2252*7c478bd9Sstevel@tonic-gate }
2253*7c478bd9Sstevel@tonic-gate 
2254*7c478bd9Sstevel@tonic-gate /*
2255*7c478bd9Sstevel@tonic-gate  * This routine is called when a packet with a RIF is received.  Our
2256*7c478bd9Sstevel@tonic-gate  * policy is to adopt the route.
2257*7c478bd9Sstevel@tonic-gate  */
2258*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
2259*7c478bd9Sstevel@tonic-gate static void
2260*7c478bd9Sstevel@tonic-gate gld_rif_ind(gld_mac_info_t *macinfo, struct gld_ri *rh, uchar_t *shost,
2261*7c478bd9Sstevel@tonic-gate     uchar_t ssap, uchar_t dsap)
2262*7c478bd9Sstevel@tonic-gate {
2263*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2264*7c478bd9Sstevel@tonic-gate 
2265*7c478bd9Sstevel@tonic-gate 	ASSERT(rh != NULL);		/* ensure RIF */
2266*7c478bd9Sstevel@tonic-gate 	ASSERT((rh->rt & 0x04) == 0);	/* ensure SRF */
2267*7c478bd9Sstevel@tonic-gate 	ASSERT(rh->len >= 2);
2268*7c478bd9Sstevel@tonic-gate 	ASSERT(rh->len <= sizeof (struct gld_ri));
2269*7c478bd9Sstevel@tonic-gate 	ASSERT((rh->len & 1) == 0);
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
2272*7c478bd9Sstevel@tonic-gate 
2273*7c478bd9Sstevel@tonic-gate 	if ((sr = gld_sr_create_entry(macinfo, shost)) == NULL) {
2274*7c478bd9Sstevel@tonic-gate 		mutex_exit(GLD_SR_MUTEX(macinfo));
2275*7c478bd9Sstevel@tonic-gate 		return;		/* oh well, out of memory */
2276*7c478bd9Sstevel@tonic-gate 	}
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate 	/* we have an entry; fill it in */
2279*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)rh, (caddr_t)&sr->sr_ri, rh->len); /* copy incom RIF */
2280*7c478bd9Sstevel@tonic-gate 	sr->sr_ri.rt = RT_SRF;	/* make it a clean SRF */
2281*7c478bd9Sstevel@tonic-gate 	sr->sr_ri.dir ^= 1;	/* reverse direction */
2282*7c478bd9Sstevel@tonic-gate 	sr->sr_timer = ddi_get_lbolt();
2283*7c478bd9Sstevel@tonic-gate 
2284*7c478bd9Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
2285*7c478bd9Sstevel@tonic-gate }
2286*7c478bd9Sstevel@tonic-gate 
2287*7c478bd9Sstevel@tonic-gate static struct srtab **
2288*7c478bd9Sstevel@tonic-gate gld_sr_hash(struct srtab **sr_hash_tbl, uchar_t *addr, int addr_length)
2289*7c478bd9Sstevel@tonic-gate {
2290*7c478bd9Sstevel@tonic-gate 	uint_t hashval = 0;
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate 	while (--addr_length >= 0)
2293*7c478bd9Sstevel@tonic-gate 		hashval ^= *addr++;
2294*7c478bd9Sstevel@tonic-gate 
2295*7c478bd9Sstevel@tonic-gate 	return (&sr_hash_tbl[hashval % SR_HASH_SIZE]);
2296*7c478bd9Sstevel@tonic-gate }
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate static struct srtab *
2299*7c478bd9Sstevel@tonic-gate gld_sr_lookup_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
2300*7c478bd9Sstevel@tonic-gate {
2301*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2304*7c478bd9Sstevel@tonic-gate 
2305*7c478bd9Sstevel@tonic-gate 	for (sr = *gld_sr_hash(GLD_SR_HASH(macinfo), macaddr,
2306*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen); sr; sr = sr->sr_next)
2307*7c478bd9Sstevel@tonic-gate 		if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
2308*7c478bd9Sstevel@tonic-gate 			return (sr);
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate 	return ((struct srtab *)0);
2311*7c478bd9Sstevel@tonic-gate }
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate static struct srtab *
2314*7c478bd9Sstevel@tonic-gate gld_sr_create_entry(gld_mac_info_t *macinfo, uchar_t *macaddr)
2315*7c478bd9Sstevel@tonic-gate {
2316*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2317*7c478bd9Sstevel@tonic-gate 	struct srtab **srp;
2318*7c478bd9Sstevel@tonic-gate 
2319*7c478bd9Sstevel@tonic-gate 	ASSERT(!(macaddr[0] & 0x80));	/* no group addresses here */
2320*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(GLD_SR_MUTEX(macinfo)));
2321*7c478bd9Sstevel@tonic-gate 
2322*7c478bd9Sstevel@tonic-gate 	srp = gld_sr_hash(GLD_SR_HASH(macinfo), macaddr, macinfo->gldm_addrlen);
2323*7c478bd9Sstevel@tonic-gate 
2324*7c478bd9Sstevel@tonic-gate 	for (sr = *srp; sr; sr = sr->sr_next)
2325*7c478bd9Sstevel@tonic-gate 		if (mac_eq(macaddr, sr->sr_mac, macinfo->gldm_addrlen))
2326*7c478bd9Sstevel@tonic-gate 			return (sr);
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 	if (!(sr = kmem_zalloc(sizeof (struct srtab), KM_NOSLEEP))) {
2329*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2330*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2331*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2332*7c478bd9Sstevel@tonic-gate 			    "gld: gld_sr_create_entry kmem_alloc failed");
2333*7c478bd9Sstevel@tonic-gate #endif
2334*7c478bd9Sstevel@tonic-gate 		return ((struct srtab *)0);
2335*7c478bd9Sstevel@tonic-gate 	}
2336*7c478bd9Sstevel@tonic-gate 
2337*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)macaddr, (caddr_t)sr->sr_mac, macinfo->gldm_addrlen);
2338*7c478bd9Sstevel@tonic-gate 
2339*7c478bd9Sstevel@tonic-gate 	sr->sr_next = *srp;
2340*7c478bd9Sstevel@tonic-gate 	*srp = sr;
2341*7c478bd9Sstevel@tonic-gate 	return (sr);
2342*7c478bd9Sstevel@tonic-gate }
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate static void
2345*7c478bd9Sstevel@tonic-gate gld_sr_clear(gld_mac_info_t *macinfo)
2346*7c478bd9Sstevel@tonic-gate {
2347*7c478bd9Sstevel@tonic-gate 	int i;
2348*7c478bd9Sstevel@tonic-gate 	struct srtab **sr_hash_tbl = GLD_SR_HASH(macinfo);
2349*7c478bd9Sstevel@tonic-gate 	struct srtab **srp, *sr;
2350*7c478bd9Sstevel@tonic-gate 
2351*7c478bd9Sstevel@tonic-gate 	/*
2352*7c478bd9Sstevel@tonic-gate 	 * Walk through the table, deleting all entries.
2353*7c478bd9Sstevel@tonic-gate 	 *
2354*7c478bd9Sstevel@tonic-gate 	 * Only called from uninit, so don't need the mutex.
2355*7c478bd9Sstevel@tonic-gate 	 */
2356*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SR_HASH_SIZE; i++) {
2357*7c478bd9Sstevel@tonic-gate 		for (srp = &sr_hash_tbl[i]; (sr = *srp) != NULL; ) {
2358*7c478bd9Sstevel@tonic-gate 			*srp = sr->sr_next;
2359*7c478bd9Sstevel@tonic-gate 			kmem_free((char *)sr, sizeof (struct srtab));
2360*7c478bd9Sstevel@tonic-gate 		}
2361*7c478bd9Sstevel@tonic-gate 	}
2362*7c478bd9Sstevel@tonic-gate }
2363*7c478bd9Sstevel@tonic-gate 
2364*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2365*7c478bd9Sstevel@tonic-gate void
2366*7c478bd9Sstevel@tonic-gate gld_sr_dump(gld_mac_info_t *macinfo)
2367*7c478bd9Sstevel@tonic-gate {
2368*7c478bd9Sstevel@tonic-gate 	int i, j;
2369*7c478bd9Sstevel@tonic-gate 	struct srtab **sr_hash_tbl;
2370*7c478bd9Sstevel@tonic-gate 	struct srtab *sr;
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	sr_hash_tbl = GLD_SR_HASH(macinfo);
2373*7c478bd9Sstevel@tonic-gate 	if (sr_hash_tbl == NULL)
2374*7c478bd9Sstevel@tonic-gate 		return;
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	mutex_enter(GLD_SR_MUTEX(macinfo));
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 	/*
2379*7c478bd9Sstevel@tonic-gate 	 * Walk through the table, printing all entries
2380*7c478bd9Sstevel@tonic-gate 	 */
2381*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "GLD Source Routing Table (0x%p):", (void *)macinfo);
2382*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "Addr len,rt,dir,mtu,res rng,brg0 rng,brg1...\n");
2383*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SR_HASH_SIZE; i++) {
2384*7c478bd9Sstevel@tonic-gate 		for (sr = sr_hash_tbl[i]; sr; sr = sr->sr_next) {
2385*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2386*7c478bd9Sstevel@tonic-gate 			    "%x:%x:%x:%x:%x:%x %d,%x,%x,%x,%x ",
2387*7c478bd9Sstevel@tonic-gate 			    sr->sr_mac[0], sr->sr_mac[1], sr->sr_mac[2],
2388*7c478bd9Sstevel@tonic-gate 			    sr->sr_mac[3], sr->sr_mac[4], sr->sr_mac[5],
2389*7c478bd9Sstevel@tonic-gate 			    sr->sr_ri.len, sr->sr_ri.rt, sr->sr_ri.dir,
2390*7c478bd9Sstevel@tonic-gate 			    sr->sr_ri.mtu, sr->sr_ri.res);
2391*7c478bd9Sstevel@tonic-gate 			if (sr->sr_ri.len)
2392*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < (sr->sr_ri.len - 2) / 2; j++)
2393*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "%x ",
2394*7c478bd9Sstevel@tonic-gate 					    REF_NET_USHORT(*(unsigned short *)
2395*7c478bd9Sstevel@tonic-gate 					    &sr->sr_ri.rd[j]));
2396*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "\n");
2397*7c478bd9Sstevel@tonic-gate 		}
2398*7c478bd9Sstevel@tonic-gate 	}
2399*7c478bd9Sstevel@tonic-gate 
2400*7c478bd9Sstevel@tonic-gate 	mutex_exit(GLD_SR_MUTEX(macinfo));
2401*7c478bd9Sstevel@tonic-gate }
2402*7c478bd9Sstevel@tonic-gate #endif
2403