xref: /illumos-gate/usr/src/uts/common/io/dls/dls.c (revision 8a5251963032143e4d8c00bee444d848a79095cc)
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 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
25  */
26 
27 /*
28  * Copyright 2019 Joyent, Inc.
29  * Copyright 2025 Oxide Computer Company
30  */
31 
32 /*
33  * Data-Link Services Module
34  */
35 
36 #include	<sys/stdbit.h>
37 #include	<sys/strsun.h>
38 #include	<sys/vlan.h>
39 #include	<sys/dld_impl.h>
40 #include	<sys/mac_client_priv.h>
41 
42 int
dls_open(dls_link_t * dlp,dls_dl_handle_t ddh,dld_str_t * dsp)43 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
44 {
45 	zoneid_t	zid = getzoneid();
46 	boolean_t	local;
47 	int		err;
48 
49 	/*
50 	 * Check whether this client belongs to the zone of this dlp. Note that
51 	 * a global zone client is allowed to open a local zone dlp.
52 	 */
53 	if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
54 		return (ENOENT);
55 
56 	/*
57 	 * mac_start() is required for non-legacy MACs to show accurate
58 	 * kstats even before the interface is brought up. For legacy
59 	 * drivers, this is not needed. Further, calling mac_start() for
60 	 * legacy drivers would make the shared-lower-stream to stay in
61 	 * the DL_IDLE state, which in turn causes performance regression.
62 	 */
63 	if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
64 	    ((err = mac_start(dlp->dl_mh)) != 0)) {
65 		return (err);
66 	}
67 
68 	local = (zid == dlp->dl_zid);
69 	dlp->dl_zone_ref += (local ? 1 : 0);
70 
71 	/*
72 	 * Cache a copy of the MAC interface handle, a pointer to the
73 	 * immutable MAC info.
74 	 */
75 	dsp->ds_dlp = dlp;
76 	dsp->ds_mh = dlp->dl_mh;
77 	dsp->ds_mch = dlp->dl_mch;
78 	dsp->ds_mip = dlp->dl_mip;
79 	dsp->ds_ddh = ddh;
80 	dsp->ds_local = local;
81 
82 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
83 	return (0);
84 }
85 
86 void
dls_close(dld_str_t * dsp)87 dls_close(dld_str_t *dsp)
88 {
89 	dls_link_t		*dlp = dsp->ds_dlp;
90 	dls_multicst_addr_t	*p;
91 	dls_multicst_addr_t	*nextp;
92 
93 	ASSERT(dsp->ds_datathr_cnt == 0);
94 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
95 
96 	if (dsp->ds_local)
97 		dlp->dl_zone_ref--;
98 	dsp->ds_local = B_FALSE;
99 
100 	/*
101 	 * Walk the list of multicast addresses, disabling each at the MAC.
102 	 * Note that we must remove multicast address before
103 	 * mac_unicast_remove() (called by dls_active_clear()) because
104 	 * mac_multicast_remove() relies on the unicast flows on the mac
105 	 * client.
106 	 */
107 	for (p = dsp->ds_dmap; p != NULL; p = nextp) {
108 		(void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
109 		nextp = p->dma_nextp;
110 		kmem_free(p, sizeof (dls_multicst_addr_t));
111 	}
112 	dsp->ds_dmap = NULL;
113 
114 	dls_active_clear(dsp, B_TRUE);
115 
116 	/*
117 	 * If the dld_str_t is bound then unbind it.
118 	 */
119 	if (dsp->ds_dlstate == DL_IDLE) {
120 		dls_unbind(dsp);
121 		dsp->ds_dlstate = DL_UNBOUND;
122 	}
123 
124 	/*
125 	 * If the MAC has been set in promiscuous mode then disable it.
126 	 * This needs to be done before resetting ds_rx.
127 	 */
128 	(void) dls_promisc(dsp, 0);
129 
130 	/*
131 	 * At this point we have cutoff inbound packet flow from the mac
132 	 * for this 'dsp'. The dls_link_remove above cut off packets meant
133 	 * for us and waited for upcalls to finish. Similarly the dls_promisc
134 	 * reset above waited for promisc callbacks to finish. Now we can
135 	 * safely reset ds_rx to NULL
136 	 */
137 	dsp->ds_rx = NULL;
138 	dsp->ds_rx_arg = NULL;
139 
140 	dsp->ds_dlp = NULL;
141 
142 	if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
143 		mac_stop(dsp->ds_mh);
144 
145 	/*
146 	 * Release our reference to the dls_link_t allowing that to be
147 	 * destroyed if there are no more dls_impl_t.
148 	 */
149 	dls_link_rele(dlp);
150 }
151 
152 int
dls_bind(dld_str_t * dsp,uint32_t sap)153 dls_bind(dld_str_t *dsp, uint32_t sap)
154 {
155 	uint32_t	dls_sap;
156 
157 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
158 
159 	/*
160 	 * Check to see the value is legal for the media type.
161 	 */
162 	if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
163 		return (EINVAL);
164 
165 	if (dsp->ds_promisc & DLS_PROMISC_SAP)
166 		dls_sap = DLS_SAP_PROMISC;
167 
168 	/*
169 	 * Set up the dld_str_t to mark it as able to receive packets.
170 	 */
171 	dsp->ds_sap = sap;
172 
173 	/*
174 	 * The MAC layer does the VLAN demultiplexing and will only pass up
175 	 * untagged packets to non-promiscuous primary MAC clients. In order to
176 	 * support binding to the VLAN SAP, which is required by DLPI, DLS
177 	 * needs to get a copy of all tagged packets when the client binds to
178 	 * the VLAN SAP. We do this by registering a separate promiscuous
179 	 * callback for each DLS client binding to that SAP.
180 	 *
181 	 * Note: even though there are two promiscuous handles in dld_str_t,
182 	 * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
183 	 * to receive VLAN traffic when promiscuous mode is not on. Only one of
184 	 * them can be non-NULL at the same time, to avoid receiving duplicate
185 	 * copies of packets.
186 	 */
187 	if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
188 		int err;
189 
190 		if (dsp->ds_vlan_mph != NULL)
191 			return (EINVAL);
192 		err = mac_promisc_add(dsp->ds_mch,
193 		    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
194 		    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
195 
196 		if (err == 0 && dsp->ds_nonip &&
197 		    dsp->ds_dlp->dl_nonip_cnt++ == 0)
198 			mac_rx_bypass_disable(dsp->ds_mch);
199 
200 		return (err);
201 	}
202 
203 	/*
204 	 * Now bind the dld_str_t by adding it into the hash table in the
205 	 * dls_link_t.
206 	 */
207 	dls_link_add(dsp->ds_dlp, dls_sap, dsp);
208 	if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
209 		mac_rx_bypass_disable(dsp->ds_mch);
210 
211 	return (0);
212 }
213 
214 void
dls_unbind(dld_str_t * dsp)215 dls_unbind(dld_str_t *dsp)
216 {
217 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
218 
219 	if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
220 		mac_rx_bypass_enable(dsp->ds_mch);
221 
222 	/*
223 	 * A VLAN SAP does not actually add itself to the STREAM head today.
224 	 * While we initially set up a VLAN handle below, it's possible that
225 	 * something else will have come in and clobbered it.
226 	 */
227 	if (dsp->ds_sap == ETHERTYPE_VLAN) {
228 		if (dsp->ds_vlan_mph != NULL) {
229 			mac_promisc_remove(dsp->ds_vlan_mph);
230 			dsp->ds_vlan_mph = NULL;
231 		}
232 		return;
233 	}
234 
235 	/*
236 	 * Unbind the dld_str_t by removing it from the hash table in the
237 	 * dls_link_t.
238 	 */
239 	dls_link_remove(dsp->ds_dlp, dsp);
240 	dsp->ds_sap = 0;
241 }
242 
243 /*
244  * In order to prevent promiscuous-mode processing with dsp->ds_promisc
245  * set to inaccurate values, this function sets dsp->ds_promisc with new
246  * flags.  For enabling (mac_promisc_add), the flags are set prior to the
247  * actual enabling.  For disabling (mac_promisc_remove), the flags are set
248  * after the actual disabling.
249  */
250 int
dls_promisc(dld_str_t * dsp,uint32_t new_flags)251 dls_promisc(dld_str_t *dsp, uint32_t new_flags)
252 {
253 	int err = 0;
254 	uint32_t old_flags = dsp->ds_promisc;
255 	const uint32_t option_flags = DLS_PROMISC_RX_ONLY |
256 	    DLS_PROMISC_INCOMING | DLS_PROMISC_OUTGOING;
257 	uint32_t old_type = old_flags & ~option_flags;
258 	uint32_t new_type = new_flags & ~option_flags;
259 	mac_client_promisc_type_t mptype = MAC_CLIENT_PROMISC_ALL;
260 	uint16_t mac_flags = 0;
261 
262 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
263 	ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
264 	    DLS_PROMISC_PHYS | option_flags)));
265 
266 	/*
267 	 * If the user has only requested DLS_PROMISC_MULTI then we need to make
268 	 * sure that they don't see all packets.
269 	 */
270 	if (new_type == DLS_PROMISC_MULTI)
271 		mptype = MAC_CLIENT_PROMISC_MULTI;
272 
273 	/* Can choose only one of Rx-only or incoming/outoing. */
274 	if (stdc_count_ones_ui(new_flags & option_flags) > 1)
275 		return (EINVAL);
276 
277 	/*
278 	 * Look at new flags and figure out the correct mac promisc flags.
279 	 * If we've only requested DLS_PROMISC_SAP and not _MULTI or _PHYS,
280 	 * don't turn on physical promisc mode.
281 	 *
282 	 * Note that there are two MAC flags, MAC_PROMISC_FLAGS_NO_TX_LOOP and
283 	 * MAC_PROMISC_FLAGS_RX_ONLY, which are similar but subtly different.
284 	 * NO_TX_LOOP stops outgoing packets transmitted by a MAC client from
285 	 * being delivered to a promsic handler on the same client. Whereas
286 	 * RX_ONLY suppresses outgoing packets across all MAC clients. For
287 	 * backwards compatibility, we map DLS_PROMISC_RX_ONLY to
288 	 * MAC_PROMISC_FLAGS_NO_TX_LOOP and DLS_PROMISC_INCOMING/OUTGOING to
289 	 * MAC_PROMISC_FLAGS_RX_ONLY/MAC_PROMISC_FLAGS_TX_ONLY.
290 	 */
291 	if (new_flags & DLS_PROMISC_RX_ONLY)
292 		mac_flags |= MAC_PROMISC_FLAGS_NO_TX_LOOP;
293 	if (new_flags & DLS_PROMISC_INCOMING)
294 		mac_flags |= MAC_PROMISC_FLAGS_RX_ONLY;
295 	if (new_flags & DLS_PROMISC_OUTGOING)
296 		mac_flags |= MAC_PROMISC_FLAGS_TX_ONLY;
297 	if (new_type == DLS_PROMISC_SAP)
298 		mac_flags |= MAC_PROMISC_FLAGS_NO_PHYS;
299 
300 	/*
301 	 * There are three cases we care about here with respect to MAC. Going
302 	 * from nothing to something, something to nothing, something to
303 	 * something where we need to change how we're getting stuff from mac.
304 	 * In the last case, as long as they're not equal, we need to assume
305 	 * something has changed and do something about it.
306 	 */
307 	if (old_type == 0 && new_type == 0) {
308 		/*
309 		 * If there are only option flags in the old and new flags
310 		 * then there is no need to talk to MAC. Just update the flags.
311 		 */
312 		dsp->ds_promisc = new_flags;
313 	} else if (old_type == 0 && new_type != 0) {
314 		dsp->ds_promisc = new_flags;
315 		err = mac_promisc_add(dsp->ds_mch, mptype,
316 		    dls_rx_promisc, dsp, &dsp->ds_mph, mac_flags);
317 		if (err != 0) {
318 			dsp->ds_promisc = old_flags;
319 			return (err);
320 		}
321 
322 		/* Remove vlan promisc handle to avoid sending dup copy up */
323 		if (dsp->ds_vlan_mph != NULL) {
324 			mac_promisc_remove(dsp->ds_vlan_mph);
325 			dsp->ds_vlan_mph = NULL;
326 		}
327 	} else if (old_type != 0 && new_type == 0) {
328 		ASSERT(dsp->ds_mph != NULL);
329 
330 		mac_promisc_remove(dsp->ds_mph);
331 		dsp->ds_promisc = new_flags;
332 		dsp->ds_mph = NULL;
333 
334 		if (dsp->ds_sap == ETHERTYPE_VLAN &&
335 		    dsp->ds_dlstate != DL_UNBOUND) {
336 			if (dsp->ds_vlan_mph != NULL)
337 				return (EINVAL);
338 			err = mac_promisc_add(dsp->ds_mch,
339 			    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
340 			    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
341 		}
342 	} else if (new_flags != old_flags) {
343 		ASSERT(dsp->ds_mph != NULL);
344 		mac_promisc_remove(dsp->ds_mph);
345 		/* Honors both after-remove and before-add semantics! */
346 		dsp->ds_promisc = new_flags;
347 		err = mac_promisc_add(dsp->ds_mch, mptype,
348 		    dls_rx_promisc, dsp, &dsp->ds_mph, mac_flags);
349 		if (err != 0)
350 			dsp->ds_promisc = old_flags;
351 	}
352 
353 	return (err);
354 }
355 
356 int
dls_multicst_add(dld_str_t * dsp,const uint8_t * addr)357 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
358 {
359 	int			err;
360 	dls_multicst_addr_t	**pp;
361 	dls_multicst_addr_t	*p;
362 	uint_t			addr_length;
363 
364 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
365 
366 	/*
367 	 * Check whether the address is in the list of enabled addresses for
368 	 * this dld_str_t.
369 	 */
370 	addr_length = dsp->ds_mip->mi_addr_length;
371 
372 	/*
373 	 * Protect against concurrent access of ds_dmap by data threads using
374 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
375 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
376 	 * ok and is also required by the locking protocol.
377 	 */
378 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
379 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
380 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
381 			/*
382 			 * It is there so there's nothing to do.
383 			 */
384 			err = 0;
385 			goto done;
386 		}
387 	}
388 
389 	/*
390 	 * Allocate a new list item and add it to the list.
391 	 */
392 	p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
393 	bcopy(addr, p->dma_addr, addr_length);
394 	*pp = p;
395 	rw_exit(&dsp->ds_rw_lock);
396 
397 	/*
398 	 * Enable the address at the MAC.
399 	 */
400 	err = mac_multicast_add(dsp->ds_mch, addr);
401 	if (err == 0)
402 		return (0);
403 
404 	/* Undo the operation as it has failed */
405 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
406 	ASSERT(*pp == p && p->dma_nextp == NULL);
407 	*pp = NULL;
408 	kmem_free(p, sizeof (dls_multicst_addr_t));
409 done:
410 	rw_exit(&dsp->ds_rw_lock);
411 	return (err);
412 }
413 
414 int
dls_multicst_remove(dld_str_t * dsp,const uint8_t * addr)415 dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
416 {
417 	dls_multicst_addr_t	**pp;
418 	dls_multicst_addr_t	*p;
419 	uint_t			addr_length;
420 
421 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
422 
423 	/*
424 	 * Find the address in the list of enabled addresses for this
425 	 * dld_str_t.
426 	 */
427 	addr_length = dsp->ds_mip->mi_addr_length;
428 
429 	/*
430 	 * Protect against concurrent access to ds_dmap by data threads using
431 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
432 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
433 	 * ok and is also required by the locking protocol.
434 	 */
435 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
436 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
437 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
438 			break;
439 	}
440 
441 	/*
442 	 * If we walked to the end of the list then the given address is
443 	 * not currently enabled for this dld_str_t.
444 	 */
445 	if (p == NULL) {
446 		rw_exit(&dsp->ds_rw_lock);
447 		return (ENOENT);
448 	}
449 
450 	/*
451 	 * Remove the address from the list.
452 	 */
453 	*pp = p->dma_nextp;
454 	rw_exit(&dsp->ds_rw_lock);
455 
456 	/*
457 	 * Disable the address at the MAC.
458 	 */
459 	mac_multicast_remove(dsp->ds_mch, addr);
460 	kmem_free(p, sizeof (dls_multicst_addr_t));
461 	return (0);
462 }
463 
464 mblk_t *
dls_header(dld_str_t * dsp,const uint8_t * addr,uint16_t sap,uint_t pri,mblk_t ** payloadp)465 dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
466     mblk_t **payloadp)
467 {
468 	uint16_t vid;
469 	size_t extra_len;
470 	uint16_t mac_sap;
471 	mblk_t *mp, *payload;
472 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
473 	struct ether_vlan_header *evhp;
474 
475 	vid = mac_client_vid(dsp->ds_mch);
476 	payload = (payloadp == NULL) ? NULL : (*payloadp);
477 
478 	/*
479 	 * In the case of Ethernet, we need to tell mac_header() if we need
480 	 * extra room beyond the Ethernet header for a VLAN header.  We'll
481 	 * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
482 	 * (because such streams will be handling VLAN headers on their own)
483 	 * and one of the following conditions is satisfied:
484 	 *
485 	 * - This is a VLAN stream
486 	 * - This is a physical stream, the priority is not 0, and user
487 	 *   priority tagging is allowed.
488 	 */
489 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
490 	    (vid != VLAN_ID_NONE ||
491 	    (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
492 		extra_len = sizeof (struct ether_vlan_header) -
493 		    sizeof (struct ether_header);
494 		mac_sap = ETHERTYPE_VLAN;
495 	} else {
496 		extra_len = 0;
497 		mac_sap = sap;
498 	}
499 
500 	mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
501 	if (mp == NULL)
502 		return (NULL);
503 
504 	if ((vid == VLAN_ID_NONE && (pri == 0 ||
505 	    dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
506 		return (mp);
507 
508 	/*
509 	 * Fill in the tag information.
510 	 */
511 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
512 	if (extra_len != 0) {
513 		mp->b_wptr += extra_len;
514 		evhp = (struct ether_vlan_header *)mp->b_rptr;
515 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
516 		evhp->ether_type = htons(sap);
517 	} else {
518 		/*
519 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
520 		 * in the payload. Update the priority.
521 		 */
522 		struct ether_vlan_extinfo *extinfo;
523 		size_t len = sizeof (struct ether_vlan_extinfo);
524 
525 		ASSERT(sap == ETHERTYPE_VLAN);
526 		ASSERT(payload != NULL);
527 
528 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
529 			mblk_t *newmp;
530 
531 			/*
532 			 * Because some DLS consumers only check the db_ref
533 			 * count of the first mblk, we pullup 'payload' into
534 			 * a single mblk.
535 			 */
536 			newmp = msgpullup(payload, -1);
537 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
538 				freemsg(newmp);
539 				freemsg(mp);
540 				return (NULL);
541 			} else {
542 				freemsg(payload);
543 				*payloadp = payload = newmp;
544 			}
545 		}
546 
547 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
548 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
549 		    VLAN_ID(ntohs(extinfo->ether_tci))));
550 	}
551 	return (mp);
552 }
553 
554 void
dls_rx_set(dld_str_t * dsp,dls_rx_t rx,void * arg)555 dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
556 {
557 	mutex_enter(&dsp->ds_lock);
558 	dsp->ds_rx = rx;
559 	dsp->ds_rx_arg = arg;
560 	mutex_exit(&dsp->ds_lock);
561 }
562 
563 static boolean_t
dls_accept_common(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg,boolean_t promisc,boolean_t promisc_loopback)564 dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
565     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
566 {
567 	dls_multicst_addr_t	*dmap;
568 	size_t			addr_length = dsp->ds_mip->mi_addr_length;
569 
570 	/*
571 	 * We must not accept packets if the dld_str_t is not marked as bound
572 	 * or is being removed.
573 	 */
574 	if (dsp->ds_dlstate != DL_IDLE)
575 		goto refuse;
576 
577 	if (dsp->ds_promisc != 0) {
578 		/*
579 		 * Filter out packets that arrived from the data path
580 		 * (i_dls_link_rx) when promisc mode is on. We need to correlate
581 		 * the ds_promisc flags with the mac header destination type. If
582 		 * only DLS_PROMISC_MULTI is enabled, we need to only reject
583 		 * multicast packets as those are the only ones which filter up
584 		 * the promiscuous path. If we have DLS_PROMISC_PHYS or
585 		 * DLS_PROMISC_SAP set, then we know that we'll be seeing
586 		 * everything, so we should drop it now.
587 		 */
588 		if (!promisc && !(dsp->ds_promisc == DLS_PROMISC_MULTI &&
589 		    mhip->mhi_dsttype != MAC_ADDRTYPE_MULTICAST))
590 			goto refuse;
591 		/*
592 		 * If the dls_impl_t is in 'all physical' mode then
593 		 * always accept.
594 		 */
595 		if (dsp->ds_promisc & DLS_PROMISC_PHYS)
596 			goto accept;
597 
598 		/*
599 		 * Loopback packets i.e. packets sent out by DLS on a given
600 		 * mac end point, will be accepted back by DLS on loopback
601 		 * from the mac, only in the 'all physical' mode which has been
602 		 * covered by the previous check above
603 		 */
604 		if (promisc_loopback)
605 			goto refuse;
606 	}
607 
608 	switch (mhip->mhi_dsttype) {
609 	case MAC_ADDRTYPE_UNICAST:
610 	case MAC_ADDRTYPE_BROADCAST:
611 		/*
612 		 * We can accept unicast and broadcast packets because
613 		 * filtering is already done by the mac layer.
614 		 */
615 		goto accept;
616 	case MAC_ADDRTYPE_MULTICAST:
617 		/*
618 		 * Additional filtering is needed for multicast addresses
619 		 * because different streams may be interested in different
620 		 * addresses.
621 		 */
622 		if (dsp->ds_promisc & DLS_PROMISC_MULTI)
623 			goto accept;
624 
625 		rw_enter(&dsp->ds_rw_lock, RW_READER);
626 		for (dmap = dsp->ds_dmap; dmap != NULL;
627 		    dmap = dmap->dma_nextp) {
628 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
629 			    addr_length) == 0) {
630 				rw_exit(&dsp->ds_rw_lock);
631 				goto accept;
632 			}
633 		}
634 		rw_exit(&dsp->ds_rw_lock);
635 		break;
636 	}
637 
638 refuse:
639 	return (B_FALSE);
640 
641 accept:
642 	/*
643 	 * the returned ds_rx and ds_rx_arg will always be in sync.
644 	 */
645 	mutex_enter(&dsp->ds_lock);
646 	*ds_rx = dsp->ds_rx;
647 	*ds_rx_arg = dsp->ds_rx_arg;
648 	mutex_exit(&dsp->ds_lock);
649 
650 	return (B_TRUE);
651 }
652 
653 /* ARGSUSED */
654 boolean_t
dls_accept(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg)655 dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
656     void **ds_rx_arg)
657 {
658 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
659 	    B_FALSE));
660 }
661 
662 boolean_t
dls_accept_promisc(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg,boolean_t loopback)663 dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
664     void **ds_rx_arg, boolean_t loopback)
665 {
666 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
667 	    loopback));
668 }
669 
670 int
dls_mac_active_set(dls_link_t * dlp)671 dls_mac_active_set(dls_link_t *dlp)
672 {
673 	int err = 0;
674 
675 	/*
676 	 * First client; add the primary unicast address.
677 	 */
678 	if (dlp->dl_nactive == 0) {
679 		/*
680 		 * First client; add the primary unicast address.
681 		 */
682 		mac_diag_t diag;
683 
684 		/* request the primary MAC address */
685 		if ((err = mac_unicast_add(dlp->dl_mch, NULL,
686 		    MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
687 		    MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah,
688 		    VLAN_ID_NONE, &diag)) != 0) {
689 			return (err);
690 		}
691 
692 		/*
693 		 * Set the function to start receiving packets.
694 		 */
695 		mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
696 	}
697 	dlp->dl_nactive++;
698 	return (0);
699 }
700 
701 void
dls_mac_active_clear(dls_link_t * dlp)702 dls_mac_active_clear(dls_link_t *dlp)
703 {
704 	if (--dlp->dl_nactive == 0) {
705 		ASSERT(dlp->dl_mah != NULL);
706 		(void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
707 		dlp->dl_mah = NULL;
708 		mac_rx_clear(dlp->dl_mch);
709 	}
710 }
711 
712 int
dls_active_set(dld_str_t * dsp)713 dls_active_set(dld_str_t *dsp)
714 {
715 	int err = 0;
716 
717 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
718 
719 	if (dsp->ds_passivestate == DLD_PASSIVE)
720 		return (0);
721 
722 	/* If we're already active, then there's nothing more to do. */
723 	if ((dsp->ds_nactive == 0) &&
724 	    ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
725 		/* except for ENXIO all other errors are mapped to EBUSY */
726 		if (err != ENXIO)
727 			return (EBUSY);
728 		return (err);
729 	}
730 
731 	dsp->ds_passivestate = DLD_ACTIVE;
732 	dsp->ds_nactive++;
733 	return (0);
734 }
735 
736 /*
737  * Note that dls_active_set() is called whenever an active operation
738  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
739  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
740  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
741  * a stream is closed without every active operation being undone and we
742  * need to clear all the "active" states by calling
743  * dls_active_clear(dsp, B_TRUE).
744  */
745 void
dls_active_clear(dld_str_t * dsp,boolean_t all)746 dls_active_clear(dld_str_t *dsp, boolean_t all)
747 {
748 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
749 
750 	if (dsp->ds_passivestate == DLD_PASSIVE)
751 		return;
752 
753 	if (all && dsp->ds_nactive == 0)
754 		return;
755 
756 	ASSERT(dsp->ds_nactive > 0);
757 
758 	dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
759 	if (dsp->ds_nactive != 0)
760 		return;
761 
762 	ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
763 	dls_mac_active_clear(dsp->ds_dlp);
764 	dsp->ds_passivestate = DLD_UNINITIALIZED;
765 }
766