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