xref: /illumos-gate/usr/src/uts/common/io/dls/dls_link.c (revision 814a60b13c0ad90e5d2edfd29a7a84bbf416cc1a)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Data-Link Services Module
31  */
32 
33 #include	<sys/types.h>
34 #include	<sys/stream.h>
35 #include	<sys/strsun.h>
36 #include	<sys/strsubr.h>
37 #include	<sys/sysmacros.h>
38 #include	<sys/atomic.h>
39 #include	<sys/modhash.h>
40 #include	<sys/dlpi.h>
41 #include	<sys/ethernet.h>
42 #include	<sys/byteorder.h>
43 #include	<sys/vlan.h>
44 #include	<sys/mac.h>
45 #include	<sys/sdt.h>
46 
47 #include	<sys/dls.h>
48 #include	<sys/dld_impl.h>
49 #include	<sys/dls_impl.h>
50 
51 static kmem_cache_t	*i_dls_link_cachep;
52 static mod_hash_t	*i_dls_link_hash;
53 static uint_t		i_dls_link_count;
54 static krwlock_t	i_dls_link_lock;
55 
56 #define		LINK_HASHSZ	67	/* prime */
57 #define		IMPL_HASHSZ	67	/* prime */
58 
59 /*
60  * Construct a hash key encompassing both DLSAP value and VLAN idenitifier.
61  */
62 #define	MAKE_KEY(_sap, _vid)						\
63 	((mod_hash_key_t)(uintptr_t)					\
64 	(((_sap) << VLAN_ID_SIZE) | (_vid) & VLAN_ID_MASK))
65 
66 /*
67  * Extract the DLSAP value from the hash key.
68  */
69 #define	KEY_SAP(_key)							\
70 	(((uint32_t)(uintptr_t)(_key)) >> VLAN_ID_SIZE)
71 
72 /*
73  * Private functions.
74  */
75 
76 /*ARGSUSED*/
77 static int
78 i_dls_link_constructor(void *buf, void *arg, int kmflag)
79 {
80 	dls_link_t	*dlp = buf;
81 	char		name[MAXNAMELEN];
82 
83 	bzero(buf, sizeof (dls_link_t));
84 
85 	(void) sprintf(name, "dls_link_t_%p_hash", buf);
86 	dlp->dl_impl_hash = mod_hash_create_idhash(name, IMPL_HASHSZ,
87 	    mod_hash_null_valdtor);
88 
89 	mutex_init(&dlp->dl_lock, NULL, MUTEX_DEFAULT, NULL);
90 	mutex_init(&dlp->dl_promisc_lock, NULL, MUTEX_DEFAULT, NULL);
91 	rw_init(&dlp->dl_impl_lock, NULL, RW_DEFAULT, NULL);
92 	return (0);
93 }
94 
95 /*ARGSUSED*/
96 static void
97 i_dls_link_destructor(void *buf, void *arg)
98 {
99 	dls_link_t	*dlp = buf;
100 
101 	ASSERT(dlp->dl_ref == 0);
102 	ASSERT(dlp->dl_mh == NULL);
103 	ASSERT(dlp->dl_unknowns == 0);
104 
105 	mod_hash_destroy_idhash(dlp->dl_impl_hash);
106 	dlp->dl_impl_hash = NULL;
107 
108 	mutex_destroy(&dlp->dl_lock);
109 	mutex_destroy(&dlp->dl_promisc_lock);
110 	rw_destroy(&dlp->dl_impl_lock);
111 }
112 
113 #define	ETHER_MATCH(_pkt_a, _pkt_b)					\
114 	((((uint16_t *)(_pkt_a))[0] == ((uint16_t *)(_pkt_b))[0]) &&	\
115 	(((uint16_t *)(_pkt_a))[1] == ((uint16_t *)(_pkt_b))[1]) &&	\
116 	(((uint16_t *)(_pkt_a))[2] == ((uint16_t *)(_pkt_b))[2]) &&	\
117 	(((uint16_t *)(_pkt_a))[6] == ((uint16_t *)(_pkt_b))[6]))
118 
119 #define	ETHER_VLAN_MATCH(_pkt_a, _pkt_b)				\
120 	((((uint16_t *)(_pkt_a))[0] == ((uint16_t *)(_pkt_b))[0]) &&	\
121 	(((uint16_t *)(_pkt_a))[1] == ((uint16_t *)(_pkt_b))[1]) &&	\
122 	(((uint16_t *)(_pkt_a))[2] == ((uint16_t *)(_pkt_b))[2]) &&	\
123 	(((uint16_t *)(_pkt_a))[6] == ((uint16_t *)(_pkt_b))[6]) &&	\
124 	(((uint16_t *)(_pkt_a))[7] == ((uint16_t *)(_pkt_b))[7]) &&	\
125 	(((uint16_t *)(_pkt_a))[8] == ((uint16_t *)(_pkt_b))[8]))
126 
127 static mblk_t *
128 i_dls_link_ether_subchain(mblk_t *mp, uint_t *header_lengthp,
129     uint8_t **daddrp, uint16_t *type_lengthp, uint16_t *vidp,
130     uint_t *countp)
131 {
132 	struct ether_header		*ehp;
133 	struct ether_vlan_header	*evhp;
134 	mblk_t				**pp;
135 	mblk_t				*p;
136 	uint_t				npacket;
137 
138 	/*
139 	 * Packets should always be at least 16 bit aligned.
140 	 */
141 	ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
142 
143 	/*
144 	 * Determine whether this is a VLAN or non-VLAN packet.
145 	 */
146 	ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
147 	ehp = (struct ether_header *)mp->b_rptr;
148 	if ((*type_lengthp = ntohs(ehp->ether_type)) == VLAN_TPID)
149 		goto vlan;
150 
151 	/*
152 	 * It is a non-VLAN header.
153 	 */
154 	*header_lengthp = sizeof (struct ether_header);
155 
156 	/*
157 	 * Parse the rest of the header information that we need.
158 	 */
159 	*daddrp = (uint8_t *)&(ehp->ether_dhost);
160 	*vidp = VLAN_ID_NONE;
161 
162 	/*
163 	 * Compare with subsequent headers until we find one that has
164 	 * differing header information. After checking each packet skip over
165 	 * the header.
166 	 */
167 	npacket = 1;
168 	for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) {
169 		if (!ETHER_MATCH(p->b_rptr, mp->b_rptr) != 0)
170 			break;
171 		p->b_rptr += sizeof (struct ether_header);
172 		npacket++;
173 	}
174 
175 	/*
176 	 * Skip over the initial packet's header.
177 	 */
178 	mp->b_rptr += sizeof (struct ether_header);
179 	goto done;
180 
181 vlan:
182 	/*
183 	 * It is a VLAN header.
184 	 */
185 	evhp = (struct ether_vlan_header *)mp->b_rptr;
186 	*header_lengthp = sizeof (struct ether_vlan_header);
187 
188 	/*
189 	 * Parse the header information.
190 	 */
191 	*daddrp = (uint8_t *)&(evhp->ether_dhost);
192 	*vidp = VLAN_ID(ntohs(evhp->ether_tci));
193 	*type_lengthp = ntohs(evhp->ether_type);
194 
195 	/*
196 	 * Compare with subsequent headers until we find one that has
197 	 * differing header information. After checking each packet skip over
198 	 * the header.
199 	 */
200 	npacket = 1;
201 	for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) {
202 		if (!ETHER_VLAN_MATCH(p->b_rptr, mp->b_rptr) != 0)
203 			break;
204 		p->b_rptr += sizeof (struct ether_vlan_header);
205 		npacket++;
206 	}
207 
208 	/*
209 	 * Skip over the initial packet's header.
210 	 */
211 	mp->b_rptr += sizeof (struct ether_vlan_header);
212 
213 done:
214 	/*
215 	 * Break the chain at this point and return a pointer to the next
216 	 * sub-chain.
217 	 */
218 	*pp = NULL;
219 	*countp = npacket;
220 	return (p);
221 }
222 
223 static void
224 i_dls_head_hold(dls_head_t *dhp)
225 {
226 	atomic_inc_32(&dhp->dh_ref);
227 }
228 
229 static void
230 i_dls_head_rele(dls_head_t *dhp)
231 {
232 	atomic_dec_32(&dhp->dh_ref);
233 }
234 
235 static dls_head_t *
236 i_dls_head_alloc(mod_hash_key_t key)
237 {
238 	dls_head_t	*dhp;
239 
240 	dhp = kmem_zalloc(sizeof (dls_head_t), KM_SLEEP);
241 	dhp->dh_key = key;
242 	return (dhp);
243 }
244 
245 static void
246 i_dls_head_free(dls_head_t *dhp)
247 {
248 	ASSERT(dhp->dh_ref == 0);
249 	kmem_free(dhp, sizeof (dls_head_t));
250 }
251 
252 static void
253 i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
254 {
255 	dls_link_t			*dlp = arg;
256 	mod_hash_t			*hash = dlp->dl_impl_hash;
257 	mblk_t				*nextp;
258 	uint_t				header_length;
259 	uint8_t				*daddr;
260 	uint16_t			type_length;
261 	uint16_t			vid;
262 	uint16_t			sap;
263 	dls_head_t			*dhp;
264 	dls_impl_t			*dip;
265 	dls_impl_t			*ndip;
266 	mblk_t				*nmp;
267 	mod_hash_key_t			key;
268 	uint_t				npacket;
269 	boolean_t			accepted;
270 
271 	/*
272 	 * Walk the packet chain.
273 	 */
274 	while (mp != NULL) {
275 		/*
276 		 * Wipe the accepted state.
277 		 */
278 		accepted = B_FALSE;
279 
280 		/*
281 		 * Grab the longest sub-chain we can process as a single
282 		 * unit.
283 		 */
284 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
285 		    &type_length, &vid, &npacket);
286 
287 		/*
288 		 * Calculate the DLSAP: LLC (0) if the type/length field is
289 		 * interpreted as a length, otherwise it is the value of the
290 		 * type/length field.
291 		 */
292 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
293 
294 		/*
295 		 * Construct a hash key from the VLAN identifier and the
296 		 * DLSAP.
297 		 */
298 		key = MAKE_KEY(sap, vid);
299 
300 		/*
301 		 * Search the has table for dls_impl_t eligible to receive
302 		 * a packet chain for this DLSAP/VLAN combination.
303 		 */
304 		rw_enter(&dlp->dl_impl_lock, RW_READER);
305 		if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
306 			rw_exit(&dlp->dl_impl_lock);
307 			freemsgchain(mp);
308 			goto loop;
309 		}
310 		i_dls_head_hold(dhp);
311 		rw_exit(&dlp->dl_impl_lock);
312 
313 		/*
314 		 * Find the first dls_impl_t that will accept the sub-chain.
315 		 */
316 		for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp)
317 			if (dls_accept(dip, daddr))
318 				break;
319 
320 		/*
321 		 * If we did not find any dls_impl_t willing to accept the
322 		 * sub-chain then throw it away.
323 		 */
324 		if (dip == NULL) {
325 			i_dls_head_rele(dhp);
326 			freemsgchain(mp);
327 			goto loop;
328 		}
329 
330 		/*
331 		 * We have at least one acceptor.
332 		 */
333 		accepted = B_TRUE;
334 		for (;;) {
335 			/*
336 			 * Find the next dls_impl_t that will accept the
337 			 * sub-chain.
338 			 */
339 			for (ndip = dip->di_nextp; ndip != NULL;
340 			    ndip = ndip->di_nextp)
341 				if (dls_accept(ndip, daddr))
342 					break;
343 
344 			/*
345 			 * If there are no more dls_impl_t that are willing
346 			 * to accept the sub-chain then we don't need to dup
347 			 * it before handing it to the current one.
348 			 */
349 			if (ndip == NULL) {
350 				dip->di_rx(dip->di_rx_arg, mrh, mp,
351 				    header_length);
352 
353 				/*
354 				 * Since there are no more dls_impl_t, we're
355 				 * done.
356 				 */
357 				break;
358 			}
359 
360 			/*
361 			 * There are more dls_impl_t so dup the sub-chain.
362 			 */
363 			if ((nmp = copymsgchain(mp)) != NULL)
364 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
365 				    header_length);
366 
367 			dip = ndip;
368 		}
369 
370 		/*
371 		 * Release the hold on the dls_impl_t chain now that we have
372 		 * finished walking it.
373 		 */
374 		i_dls_head_rele(dhp);
375 
376 loop:
377 		/*
378 		 * If there were no acceptors then add the packet count to the
379 		 * 'unknown' count.
380 		 */
381 		if (!accepted)
382 			atomic_add_32(&(dlp->dl_unknowns), npacket);
383 
384 		/*
385 		 * Move onto the next sub-chain.
386 		 */
387 		mp = nextp;
388 	}
389 }
390 
391 static void
392 i_dls_link_ether_rx_promisc(void *arg, mac_resource_handle_t mrh,
393     mblk_t *mp)
394 {
395 	dls_link_t			*dlp = arg;
396 	mod_hash_t			*hash = dlp->dl_impl_hash;
397 	mblk_t				*nextp;
398 	uint_t				header_length;
399 	uint8_t				*daddr;
400 	uint16_t			type_length;
401 	uint16_t			vid;
402 	uint16_t			sap;
403 	dls_head_t			*dhp;
404 	dls_impl_t			*dip;
405 	dls_impl_t			*ndip;
406 	mblk_t				*nmp;
407 	mod_hash_key_t			key;
408 	uint_t				npacket;
409 	boolean_t			accepted;
410 
411 	/*
412 	 * Walk the packet chain.
413 	 */
414 	while (mp != NULL) {
415 		/*
416 		 * Wipe the accepted state.
417 		 */
418 		accepted = B_FALSE;
419 
420 		/*
421 		 * Grab the longest sub-chain we can process as a single
422 		 * unit.
423 		 */
424 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
425 		    &type_length, &vid, &npacket);
426 
427 		/*
428 		 * Construct a hash key from the VLAN identifier and the
429 		 * DLSAP that represents dls_impl_t in promiscuous mode.
430 		 */
431 		key = MAKE_KEY(DLS_SAP_PROMISC, vid);
432 
433 		/*
434 		 * Search the has table for dls_impl_t eligible to receive
435 		 * a packet chain for this DLSAP/VLAN combination.
436 		 */
437 		rw_enter(&dlp->dl_impl_lock, RW_READER);
438 		if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
439 			rw_exit(&dlp->dl_impl_lock);
440 			goto non_promisc;
441 		}
442 		i_dls_head_hold(dhp);
443 		rw_exit(&dlp->dl_impl_lock);
444 
445 		/*
446 		 * Find dls_impl_t that will accept the sub-chain.
447 		 */
448 		for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
449 			if (!dls_accept(dip, daddr))
450 				continue;
451 
452 			/*
453 			 * We have at least one acceptor.
454 			 */
455 			accepted = B_TRUE;
456 
457 			/*
458 			 * There will normally be at least more dls_impl_t
459 			 * (since we've yet to check for non-promiscuous
460 			 * dls_impl_t) so dup the sub-chain.
461 			 */
462 			if ((nmp = copymsgchain(mp)) != NULL)
463 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
464 				    header_length);
465 		}
466 
467 		/*
468 		 * Release the hold on the dls_impl_t chain now that we have
469 		 * finished walking it.
470 		 */
471 		i_dls_head_rele(dhp);
472 
473 non_promisc:
474 		/*
475 		 * Calculate the DLSAP: LLC (0) if the type/length field is
476 		 * interpreted as a length, otherwise it is the value of the
477 		 * type/length field.
478 		 */
479 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
480 
481 		/*
482 		 * Construct a hash key from the VLAN identifier and the
483 		 * DLSAP.
484 		 */
485 		key = MAKE_KEY(sap, vid);
486 
487 		/*
488 		 * Search the has table for dls_impl_t eligible to receive
489 		 * a packet chain for this DLSAP/VLAN combination.
490 		 */
491 		rw_enter(&dlp->dl_impl_lock, RW_READER);
492 		if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
493 			rw_exit(&dlp->dl_impl_lock);
494 			freemsgchain(mp);
495 			goto loop;
496 		}
497 		i_dls_head_hold(dhp);
498 		rw_exit(&dlp->dl_impl_lock);
499 
500 		/*
501 		 * Find the first dls_impl_t that will accept the sub-chain.
502 		 */
503 		for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp)
504 			if (dls_accept(dip, daddr))
505 				break;
506 
507 		/*
508 		 * If we did not find any dls_impl_t willing to accept the
509 		 * sub-chain then throw it away.
510 		 */
511 		if (dip == NULL) {
512 			i_dls_head_rele(dhp);
513 			freemsgchain(mp);
514 			goto loop;
515 		}
516 
517 		/*
518 		 * We have at least one acceptor.
519 		 */
520 		accepted = B_TRUE;
521 		for (;;) {
522 			/*
523 			 * Find the next dls_impl_t that will accept the
524 			 * sub-chain.
525 			 */
526 			for (ndip = dip->di_nextp; ndip != NULL;
527 			    ndip = ndip->di_nextp)
528 				if (dls_accept(ndip, daddr))
529 					break;
530 
531 			/*
532 			 * If there are no more dls_impl_t that are willing
533 			 * to accept the sub-chain then we don't need to dup
534 			 * it before handing it to the current one.
535 			 */
536 			if (ndip == NULL) {
537 				dip->di_rx(dip->di_rx_arg, mrh, mp,
538 				    header_length);
539 
540 				/*
541 				 * Since there are no more dls_impl_t, we're
542 				 * done.
543 				 */
544 				break;
545 			}
546 
547 			/*
548 			 * There are more dls_impl_t so dup the sub-chain.
549 			 */
550 			if ((nmp = copymsgchain(mp)) != NULL)
551 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
552 				    header_length);
553 
554 			dip = ndip;
555 		}
556 
557 		/*
558 		 * Release the hold on the dls_impl_t chain now that we have
559 		 * finished walking it.
560 		 */
561 		i_dls_head_rele(dhp);
562 
563 loop:
564 		/*
565 		 * If there were no acceptors then add the packet count to the
566 		 * 'unknown' count.
567 		 */
568 		if (!accepted)
569 			atomic_add_32(&(dlp->dl_unknowns), npacket);
570 
571 		/*
572 		 * Move onto the next sub-chain.
573 		 */
574 		mp = nextp;
575 	}
576 }
577 
578 static void
579 i_dls_link_ether_loopback(void *arg, mblk_t *mp)
580 {
581 	dls_link_t			*dlp = arg;
582 	mod_hash_t			*hash = dlp->dl_impl_hash;
583 	mblk_t				*nextp;
584 	uint_t				header_length;
585 	uint8_t				*daddr;
586 	uint16_t			type_length;
587 	uint16_t			vid;
588 	uint16_t			sap;
589 	dls_head_t			*dhp;
590 	dls_impl_t			*dip;
591 	dls_impl_t			*ndip;
592 	mblk_t				*nmp;
593 	mod_hash_key_t			key;
594 	uint_t				npacket;
595 
596 	/*
597 	 * Walk the packet chain.
598 	 */
599 	while (mp != NULL) {
600 		/*
601 		 * Grab the longest sub-chain we can process as a single
602 		 * unit.
603 		 */
604 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
605 		    &type_length, &vid, &npacket);
606 
607 		/*
608 		 * Calculate the DLSAP: LLC (0) if the type/length field is
609 		 * interpreted as a length, otherwise it is the value of the
610 		 * type/length field.
611 		 */
612 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
613 
614 		/*
615 		 * Construct a hash key from the VLAN identifier and the
616 		 * DLSAP.
617 		 */
618 		key = MAKE_KEY(sap, vid);
619 
620 		/*
621 		 * Search the has table for dls_impl_t eligible to receive
622 		 * a packet chain for this DLSAP/VLAN combination.
623 		 */
624 		rw_enter(&dlp->dl_impl_lock, RW_READER);
625 		if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
626 			rw_exit(&dlp->dl_impl_lock);
627 			goto promisc;
628 		}
629 		i_dls_head_hold(dhp);
630 		rw_exit(&dlp->dl_impl_lock);
631 
632 		/*
633 		 * Find dls_impl_t that will accept the sub-chain.
634 		 */
635 		for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp) {
636 			if (!dls_accept_loopback(dip, daddr))
637 				continue;
638 
639 			/*
640 			 * There should be at least more dls_impl_t (since
641 			 * we've yet to check for dls_impl_t in promiscuous
642 			 * mode) so dup the sub-chain.
643 			 */
644 			if ((nmp = copymsgchain(mp)) != NULL)
645 				dip->di_rx(dip->di_rx_arg, NULL, nmp,
646 				    header_length);
647 		}
648 
649 		/*
650 		 * Release the hold on the dls_impl_t chain now that we have
651 		 * finished walking it.
652 		 */
653 		i_dls_head_rele(dhp);
654 
655 promisc:
656 		/*
657 		 * Construct a hash key from the VLAN identifier and the
658 		 * DLSAP that represents dls_impl_t in promiscuous mode.
659 		 */
660 		key = MAKE_KEY(DLS_SAP_PROMISC, vid);
661 
662 		/*
663 		 * Search the has table for dls_impl_t eligible to receive
664 		 * a packet chain for this DLSAP/VLAN combination.
665 		 */
666 		rw_enter(&dlp->dl_impl_lock, RW_READER);
667 		if (mod_hash_find(hash, key, (mod_hash_val_t *)&dhp) != 0) {
668 			rw_exit(&dlp->dl_impl_lock);
669 			freemsgchain(mp);
670 			goto loop;
671 		}
672 		i_dls_head_hold(dhp);
673 		rw_exit(&dlp->dl_impl_lock);
674 
675 		/*
676 		 * Find the first dls_impl_t that will accept the sub-chain.
677 		 */
678 		for (dip = dhp->dh_list; dip != NULL; dip = dip->di_nextp)
679 			if (dls_accept_loopback(dip, daddr))
680 				break;
681 
682 		/*
683 		 * If we did not find any dls_impl_t willing to accept the
684 		 * sub-chain then throw it away.
685 		 */
686 		if (dip == NULL) {
687 			i_dls_head_rele(dhp);
688 			freemsgchain(mp);
689 			goto loop;
690 		}
691 
692 		for (;;) {
693 			/*
694 			 * Find the next dls_impl_t that will accept the
695 			 * sub-chain.
696 			 */
697 			for (ndip = dip->di_nextp; ndip != NULL;
698 			    ndip = ndip->di_nextp)
699 				if (dls_accept_loopback(ndip, daddr))
700 					break;
701 
702 			/*
703 			 * If there are no more dls_impl_t that are willing
704 			 * to accept the sub-chain then we don't need to dup
705 			 * it before handing it to the current one.
706 			 */
707 			if (ndip == NULL) {
708 				dip->di_rx(dip->di_rx_arg, NULL, mp,
709 				    header_length);
710 
711 				/*
712 				 * Since there are no more dls_impl_t, we're
713 				 * done.
714 				 */
715 				break;
716 			}
717 
718 			/*
719 			 * There are more dls_impl_t so dup the sub-chain.
720 			 */
721 			if ((nmp = copymsgchain(mp)) != NULL)
722 				dip->di_rx(dip->di_rx_arg, NULL, nmp,
723 				    header_length);
724 
725 			dip = ndip;
726 		}
727 
728 		/*
729 		 * Release the hold on the dls_impl_t chain now that we have
730 		 * finished walking it.
731 		 */
732 		i_dls_head_rele(dhp);
733 
734 loop:
735 		/*
736 		 * Move onto the next sub-chain.
737 		 */
738 		mp = nextp;
739 	}
740 }
741 
742 /*ARGSUSED*/
743 static uint_t
744 i_dls_link_walk(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
745 {
746 	boolean_t	*promiscp = arg;
747 	uint32_t	sap = KEY_SAP(key);
748 
749 	if (sap == DLS_SAP_PROMISC) {
750 		*promiscp = B_TRUE;
751 		return (MH_WALK_TERMINATE);
752 	}
753 
754 	return (MH_WALK_CONTINUE);
755 }
756 
757 static int
758 i_dls_link_create(const char *dev, uint_t port, dls_link_t **dlpp)
759 {
760 	dls_link_t		*dlp;
761 
762 	/*
763 	 * Allocate a new dls_link_t structure.
764 	 */
765 	dlp = kmem_cache_alloc(i_dls_link_cachep, KM_SLEEP);
766 
767 	/*
768 	 * Name the dls_link_t after the MAC interface it represents.
769 	 */
770 	MAC_NAME(dlp->dl_name, dev, port);
771 	(void) strlcpy(dlp->dl_dev, dev, MAXNAMELEN);
772 	dlp->dl_port = port;
773 
774 	/*
775 	 * Set the packet loopback function for use when the MAC is in
776 	 * promiscuous mode, and initialize promiscuous bookeeping fields.
777 	 */
778 	dlp->dl_loopback = i_dls_link_ether_loopback;
779 	dlp->dl_npromisc = 0;
780 	dlp->dl_mth = NULL;
781 
782 	*dlpp = dlp;
783 	return (0);
784 }
785 
786 static void
787 i_dls_link_destroy(dls_link_t *dlp)
788 {
789 	ASSERT(dlp->dl_npromisc == 0);
790 	ASSERT(dlp->dl_nactive == 0);
791 	ASSERT(dlp->dl_mth == NULL);
792 	ASSERT(dlp->dl_macref == 0);
793 	ASSERT(dlp->dl_mh == NULL);
794 	ASSERT(dlp->dl_mip == NULL);
795 	ASSERT(dlp->dl_impl_count == 0);
796 	ASSERT(dlp->dl_mrh == NULL);
797 
798 	/*
799 	 * Free the structure back to the cache.
800 	 */
801 	dlp->dl_unknowns = 0;
802 	kmem_cache_free(i_dls_link_cachep, dlp);
803 }
804 
805 /*
806  * Module initialization functions.
807  */
808 
809 void
810 dls_link_init(void)
811 {
812 	/*
813 	 * Create a kmem_cache of dls_link_t structures.
814 	 */
815 	i_dls_link_cachep = kmem_cache_create("dls_link_cache",
816 	    sizeof (dls_link_t), 0, i_dls_link_constructor,
817 	    i_dls_link_destructor, NULL, NULL, NULL, 0);
818 	ASSERT(i_dls_link_cachep != NULL);
819 
820 	/*
821 	 * Create a dls_link_t hash table and associated lock.
822 	 */
823 	i_dls_link_hash = mod_hash_create_extended("dls_link_hash",
824 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
825 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
826 	rw_init(&i_dls_link_lock, NULL, RW_DEFAULT, NULL);
827 	i_dls_link_count = 0;
828 }
829 
830 int
831 dls_link_fini(void)
832 {
833 	if (i_dls_link_count > 0)
834 		return (EBUSY);
835 
836 	/*
837 	 * Destroy the kmem_cache.
838 	 */
839 	kmem_cache_destroy(i_dls_link_cachep);
840 
841 	/*
842 	 * Destroy the hash table and associated lock.
843 	 */
844 	mod_hash_destroy_hash(i_dls_link_hash);
845 	rw_destroy(&i_dls_link_lock);
846 	return (0);
847 }
848 
849 /*
850  * Exported functions.
851  */
852 
853 int
854 dls_link_hold(const char *dev, uint_t port, dls_link_t **dlpp)
855 {
856 	char			name[MAXNAMELEN];
857 	dls_link_t		*dlp;
858 	int			err;
859 
860 	/*
861 	 * Construct a copy of the name used to identify any existing
862 	 * dls_link_t.
863 	 */
864 	MAC_NAME(name, dev, port);
865 
866 	/*
867 	 * Look up a dls_link_t corresponding to the given mac_handle_t
868 	 * in the global hash table. We need to hold i_dls_link_lock in
869 	 * order to atomically find and insert a dls_link_t into the
870 	 * hash table.
871 	 */
872 	rw_enter(&i_dls_link_lock, RW_WRITER);
873 	if ((err = mod_hash_find(i_dls_link_hash, (mod_hash_key_t)name,
874 	    (mod_hash_val_t *)&dlp)) == 0)
875 		goto done;
876 
877 	ASSERT(err == MH_ERR_NOTFOUND);
878 
879 	/*
880 	 * We didn't find anything so we need to create one.
881 	 */
882 	if ((err = i_dls_link_create(dev, port, &dlp)) != 0) {
883 		rw_exit(&i_dls_link_lock);
884 		return (err);
885 	}
886 
887 	/*
888 	 * Insert the dls_link_t.
889 	 */
890 	err = mod_hash_insert(i_dls_link_hash, (mod_hash_key_t)dlp->dl_name,
891 	    (mod_hash_val_t)dlp);
892 	ASSERT(err == 0);
893 
894 	i_dls_link_count++;
895 	ASSERT(i_dls_link_count != 0);
896 
897 done:
898 	/*
899 	 * Bump the reference count and hand back the reference.
900 	 */
901 	dlp->dl_ref++;
902 	*dlpp = dlp;
903 	rw_exit(&i_dls_link_lock);
904 	return (0);
905 }
906 
907 void
908 dls_link_rele(dls_link_t *dlp)
909 {
910 	mod_hash_val_t	val;
911 
912 	rw_enter(&i_dls_link_lock, RW_WRITER);
913 
914 	/*
915 	 * Check if there are any more references.
916 	 */
917 	if (--dlp->dl_ref != 0) {
918 		/*
919 		 * There are more references so there's nothing more to do.
920 		 */
921 		goto done;
922 	}
923 
924 	(void) mod_hash_remove(i_dls_link_hash,
925 	    (mod_hash_key_t)dlp->dl_name, &val);
926 	ASSERT(dlp == (dls_link_t *)val);
927 
928 	/*
929 	 * Destroy the dls_link_t.
930 	 */
931 	i_dls_link_destroy(dlp);
932 	ASSERT(i_dls_link_count > 0);
933 	i_dls_link_count--;
934 done:
935 	rw_exit(&i_dls_link_lock);
936 }
937 
938 int
939 dls_mac_hold(dls_link_t *dlp)
940 {
941 	int err = 0;
942 
943 	mutex_enter(&dlp->dl_lock);
944 
945 	ASSERT(IMPLY(dlp->dl_macref != 0, dlp->dl_mh != NULL));
946 	ASSERT(IMPLY(dlp->dl_macref == 0, dlp->dl_mh == NULL));
947 
948 	if (dlp->dl_macref == 0) {
949 		/*
950 		 * First reference; hold open the MAC interface.
951 		 */
952 		err = mac_open(dlp->dl_dev, dlp->dl_port, &dlp->dl_mh);
953 		if (err != 0)
954 			goto done;
955 
956 		dlp->dl_mip = mac_info(dlp->dl_mh);
957 	}
958 
959 	dlp->dl_macref++;
960 done:
961 	mutex_exit(&dlp->dl_lock);
962 	return (err);
963 }
964 
965 void
966 dls_mac_rele(dls_link_t *dlp)
967 {
968 	mutex_enter(&dlp->dl_lock);
969 	ASSERT(dlp->dl_mh != NULL);
970 
971 	if (--dlp->dl_macref == 0) {
972 		mac_close(dlp->dl_mh);
973 		dlp->dl_mh = NULL;
974 		dlp->dl_mip = NULL;
975 	}
976 	mutex_exit(&dlp->dl_lock);
977 }
978 
979 void
980 dls_link_add(dls_link_t *dlp, uint32_t sap, dls_impl_t *dip)
981 {
982 	dls_vlan_t	*dvp = dip->di_dvp;
983 	mod_hash_t	*hash = dlp->dl_impl_hash;
984 	mod_hash_key_t	key;
985 	dls_head_t	*dhp;
986 	dls_impl_t	*p;
987 	mac_rx_t	rx;
988 	int		err;
989 	boolean_t	promisc = B_FALSE;
990 
991 	/*
992 	 * For ethernet media, sap values less than or equal to
993 	 * ETHERMTU (1500) represent LLC channels. (See PSARC 2003/150).
994 	 * We strictly use 0 to represent LLC channels.
995 	 */
996 	sap = (sap <= ETHERMTU) ? 0 : sap;
997 
998 	/*
999 	 * Make the appropriate key value depending on whether the
1000 	 * dls_impl_t is in promiscuous mode or not.
1001 	 */
1002 	key = MAKE_KEY(sap, dvp->dv_id);
1003 
1004 	/*
1005 	 * We need dl_lock here because we want to be able to walk
1006 	 * the hash table *and* set the mac rx func atomically. if
1007 	 * these two operations are separate, someone else could
1008 	 * insert/remove dls_impl_t from the hash table after we
1009 	 * drop the hash lock and this could cause our chosen rx
1010 	 * func to be incorrect. note that we cannot call mac_rx_add
1011 	 * when holding the hash lock because this can cause deadlock.
1012 	 */
1013 	mutex_enter(&dlp->dl_lock);
1014 
1015 	/*
1016 	 * Search the table for a list head with this key.
1017 	 */
1018 	rw_enter(&dlp->dl_impl_lock, RW_WRITER);
1019 
1020 	if ((err = mod_hash_find(hash, key, (mod_hash_val_t *)&dhp)) != 0) {
1021 		ASSERT(err == MH_ERR_NOTFOUND);
1022 
1023 		dhp = i_dls_head_alloc(key);
1024 		err = mod_hash_insert(hash, key, (mod_hash_val_t)dhp);
1025 		ASSERT(err == 0);
1026 	}
1027 
1028 	/*
1029 	 * Add the dls_impl_t to the head of the list.
1030 	 */
1031 	ASSERT(dip->di_nextp == NULL);
1032 	p = dhp->dh_list;
1033 	dip->di_nextp = p;
1034 	dhp->dh_list = dip;
1035 
1036 	/*
1037 	 * Save a pointer to the list head.
1038 	 */
1039 	dip->di_headp = dhp;
1040 	dlp->dl_impl_count++;
1041 
1042 	/*
1043 	 * Walk the bound dls_impl_t to see if there are any
1044 	 * in promiscuous 'all sap' mode.
1045 	 */
1046 	mod_hash_walk(hash, i_dls_link_walk, (void *)&promisc);
1047 	rw_exit(&dlp->dl_impl_lock);
1048 
1049 	/*
1050 	 * If there are then we need to use a receive routine
1051 	 * which will route packets to those dls_impl_t as well
1052 	 * as ones bound to the  DLSAP of the packet.
1053 	 */
1054 	if (promisc)
1055 		rx = i_dls_link_ether_rx_promisc;
1056 	else
1057 		rx = i_dls_link_ether_rx;
1058 
1059 	/* Replace the existing receive function if there is one. */
1060 	if (dlp->dl_mrh != NULL)
1061 		mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
1062 	dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp);
1063 	mutex_exit(&dlp->dl_lock);
1064 }
1065 
1066 void
1067 dls_link_remove(dls_link_t *dlp, dls_impl_t *dip)
1068 {
1069 	mod_hash_t	*hash = dlp->dl_impl_hash;
1070 	dls_impl_t	**pp;
1071 	dls_impl_t	*p;
1072 	dls_head_t	*dhp;
1073 	mac_rx_t	rx;
1074 
1075 	/*
1076 	 * We need dl_lock here because we want to be able to walk
1077 	 * the hash table *and* set the mac rx func atomically. if
1078 	 * these two operations are separate, someone else could
1079 	 * insert/remove dls_impl_t from the hash table after we
1080 	 * drop the hash lock and this could cause our chosen rx
1081 	 * func to be incorrect. note that we cannot call mac_rx_add
1082 	 * when holding the hash lock because this can cause deadlock.
1083 	 */
1084 	mutex_enter(&dlp->dl_lock);
1085 	rw_enter(&dlp->dl_impl_lock, RW_WRITER);
1086 
1087 	/*
1088 	 * Poll the hash table entry until all references have been dropped.
1089 	 * We need to drop all locks before sleeping because we don't want
1090 	 * the interrupt handler to block. We set di_removing here to
1091 	 * tell the receive callbacks not to pass up packets anymore.
1092 	 * This is only a hint to quicken the decrease of the refcnt so
1093 	 * the assignment need not be protected by any lock.
1094 	 */
1095 	dhp = dip->di_headp;
1096 	dip->di_removing = B_TRUE;
1097 	while (dhp->dh_ref != 0) {
1098 		rw_exit(&dlp->dl_impl_lock);
1099 		mutex_exit(&dlp->dl_lock);
1100 		delay(drv_usectohz(1000));	/* 1ms delay */
1101 		mutex_enter(&dlp->dl_lock);
1102 		rw_enter(&dlp->dl_impl_lock, RW_WRITER);
1103 	}
1104 
1105 	/*
1106 	 * Walk the list and remove the dls_impl_t.
1107 	 */
1108 	for (pp = &dhp->dh_list; (p = *pp) != NULL; pp = &(p->di_nextp)) {
1109 		if (p == dip)
1110 			break;
1111 	}
1112 	ASSERT(p != NULL);
1113 	*pp = p->di_nextp;
1114 	p->di_nextp = NULL;
1115 
1116 	ASSERT(dlp->dl_impl_count > 0);
1117 	dlp->dl_impl_count--;
1118 
1119 	if (dhp->dh_list == NULL) {
1120 		mod_hash_val_t	val = NULL;
1121 
1122 		/*
1123 		 * The list is empty so remove the hash table entry.
1124 		 */
1125 		(void) mod_hash_remove(hash, dhp->dh_key, &val);
1126 		ASSERT(dhp == (dls_head_t *)val);
1127 		i_dls_head_free(dhp);
1128 	}
1129 	dip->di_removing = B_FALSE;
1130 
1131 	/*
1132 	 * If there are no dls_impl_t then there's no need to register a
1133 	 * receive function with the mac.
1134 	 */
1135 	if (dlp->dl_impl_count == 0) {
1136 		rw_exit(&dlp->dl_impl_lock);
1137 		mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
1138 		dlp->dl_mrh = NULL;
1139 	} else {
1140 		boolean_t promisc = B_FALSE;
1141 
1142 		/*
1143 		 * Walk the bound dls_impl_t to see if there are any
1144 		 * in promiscuous 'all sap' mode.
1145 		 */
1146 		mod_hash_walk(hash, i_dls_link_walk, (void *)&promisc);
1147 		rw_exit(&dlp->dl_impl_lock);
1148 
1149 		/*
1150 		 * If there are then we need to use a receive routine
1151 		 * which will route packets to those dls_impl_t as well
1152 		 * as ones bound to the  DLSAP of the packet.
1153 		 */
1154 		if (promisc)
1155 			rx = i_dls_link_ether_rx_promisc;
1156 		else
1157 			rx = i_dls_link_ether_rx;
1158 
1159 		mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
1160 		dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp);
1161 	}
1162 	mutex_exit(&dlp->dl_lock);
1163 }
1164