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