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