Print this page
1918 stack overflow from mac_promisc_dispatch()
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/dld/dld_proto.c
+++ new/usr/src/uts/common/io/dld/dld_proto.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 /*
26 27 * Data-Link Driver
27 28 */
28 29 #include <sys/sysmacros.h>
29 30 #include <sys/strsubr.h>
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.h>
34 35 #include <sys/mac_client_impl.h>
35 36 #include <sys/mac_client_priv.h>
36 37
37 38 typedef void proto_reqfunc_t(dld_str_t *, mblk_t *);
38 39
39 40 static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req,
40 41 proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req,
41 42 proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req,
42 43 proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req,
43 44 proto_notify_req, proto_passive_req;
44 45
45 46 static void proto_capability_advertise(dld_str_t *, mblk_t *);
46 47 static int dld_capab_poll_disable(dld_str_t *, dld_capab_poll_t *);
47 48 static boolean_t check_mod_above(queue_t *, const char *);
48 49
49 50 #define DL_ACK_PENDING(state) \
50 51 ((state) == DL_ATTACH_PENDING || \
51 52 (state) == DL_DETACH_PENDING || \
52 53 (state) == DL_BIND_PENDING || \
53 54 (state) == DL_UNBIND_PENDING)
54 55
55 56 /*
56 57 * Process a DLPI protocol message.
57 58 * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ,
58 59 * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an
59 60 * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t
60 61 * as 'passive' and forbids it from being subsequently made 'active'
61 62 * by the above primitives.
62 63 */
63 64 void
64 65 dld_proto(dld_str_t *dsp, mblk_t *mp)
65 66 {
66 67 t_uscalar_t prim;
67 68
68 69 if (MBLKL(mp) < sizeof (t_uscalar_t)) {
69 70 freemsg(mp);
70 71 return;
71 72 }
72 73 prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
73 74
74 75 switch (prim) {
75 76 case DL_INFO_REQ:
76 77 proto_info_req(dsp, mp);
77 78 break;
78 79 case DL_BIND_REQ:
79 80 proto_bind_req(dsp, mp);
80 81 break;
81 82 case DL_UNBIND_REQ:
82 83 proto_unbind_req(dsp, mp);
83 84 break;
84 85 case DL_UNITDATA_REQ:
85 86 proto_unitdata_req(dsp, mp);
86 87 break;
87 88 case DL_UDQOS_REQ:
88 89 proto_udqos_req(dsp, mp);
89 90 break;
90 91 case DL_ATTACH_REQ:
91 92 proto_attach_req(dsp, mp);
92 93 break;
93 94 case DL_DETACH_REQ:
94 95 proto_detach_req(dsp, mp);
95 96 break;
96 97 case DL_ENABMULTI_REQ:
97 98 proto_enabmulti_req(dsp, mp);
98 99 break;
99 100 case DL_DISABMULTI_REQ:
100 101 proto_disabmulti_req(dsp, mp);
101 102 break;
102 103 case DL_PROMISCON_REQ:
103 104 proto_promiscon_req(dsp, mp);
104 105 break;
105 106 case DL_PROMISCOFF_REQ:
106 107 proto_promiscoff_req(dsp, mp);
107 108 break;
108 109 case DL_PHYS_ADDR_REQ:
109 110 proto_physaddr_req(dsp, mp);
110 111 break;
111 112 case DL_SET_PHYS_ADDR_REQ:
112 113 proto_setphysaddr_req(dsp, mp);
113 114 break;
114 115 case DL_NOTIFY_REQ:
115 116 proto_notify_req(dsp, mp);
116 117 break;
117 118 case DL_CAPABILITY_REQ:
118 119 proto_capability_req(dsp, mp);
119 120 break;
120 121 case DL_PASSIVE_REQ:
121 122 proto_passive_req(dsp, mp);
122 123 break;
123 124 default:
124 125 proto_req(dsp, mp);
125 126 break;
126 127 }
127 128 }
128 129
129 130 #define NEG(x) -(x)
130 131 typedef struct dl_info_ack_wrapper {
131 132 dl_info_ack_t dl_info;
132 133 uint8_t dl_addr[MAXMACADDRLEN + sizeof (uint16_t)];
133 134 uint8_t dl_brdcst_addr[MAXMACADDRLEN];
134 135 dl_qos_cl_range1_t dl_qos_range1;
135 136 dl_qos_cl_sel1_t dl_qos_sel1;
136 137 } dl_info_ack_wrapper_t;
137 138
138 139 /*
139 140 * DL_INFO_REQ
140 141 */
141 142 static void
142 143 proto_info_req(dld_str_t *dsp, mblk_t *mp)
143 144 {
144 145 dl_info_ack_wrapper_t *dlwp;
145 146 dl_info_ack_t *dlp;
146 147 dl_qos_cl_sel1_t *selp;
147 148 dl_qos_cl_range1_t *rangep;
148 149 uint8_t *addr;
149 150 uint8_t *brdcst_addr;
150 151 uint_t addr_length;
151 152 uint_t sap_length;
152 153 mac_info_t minfo;
153 154 mac_info_t *minfop;
154 155 queue_t *q = dsp->ds_wq;
155 156
156 157 /*
157 158 * Swap the request message for one large enough to contain the
158 159 * wrapper structure defined above.
159 160 */
160 161 if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t),
161 162 M_PCPROTO, 0)) == NULL)
162 163 return;
163 164
164 165 bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
165 166 dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
166 167
167 168 dlp = &(dlwp->dl_info);
168 169 ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
169 170
170 171 dlp->dl_primitive = DL_INFO_ACK;
171 172
172 173 /*
173 174 * Set up the sub-structure pointers.
174 175 */
175 176 addr = dlwp->dl_addr;
176 177 brdcst_addr = dlwp->dl_brdcst_addr;
177 178 rangep = &(dlwp->dl_qos_range1);
178 179 selp = &(dlwp->dl_qos_sel1);
179 180
180 181 /*
181 182 * This driver supports only version 2 connectionless DLPI provider
182 183 * nodes.
183 184 */
184 185 dlp->dl_service_mode = DL_CLDLS;
185 186 dlp->dl_version = DL_VERSION_2;
186 187
187 188 /*
188 189 * Set the style of the provider
189 190 */
190 191 dlp->dl_provider_style = dsp->ds_style;
191 192 ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
192 193 dlp->dl_provider_style == DL_STYLE2);
193 194
194 195 /*
195 196 * Set the current DLPI state.
196 197 */
197 198 dlp->dl_current_state = dsp->ds_dlstate;
198 199
199 200 /*
200 201 * Gratuitously set the media type. This is to deal with modules
201 202 * that assume the media type is known prior to DL_ATTACH_REQ
202 203 * being completed.
203 204 */
204 205 dlp->dl_mac_type = DL_ETHER;
205 206
206 207 /*
207 208 * If the stream is not at least attached we try to retrieve the
208 209 * mac_info using mac_info_get()
209 210 */
210 211 if (dsp->ds_dlstate == DL_UNATTACHED ||
211 212 dsp->ds_dlstate == DL_ATTACH_PENDING ||
212 213 dsp->ds_dlstate == DL_DETACH_PENDING) {
213 214 if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) {
214 215 /*
215 216 * Cannot find mac_info. giving up.
216 217 */
217 218 goto done;
218 219 }
219 220 minfop = &minfo;
220 221 } else {
221 222 minfop = (mac_info_t *)dsp->ds_mip;
222 223 /* We can only get the sdu if we're attached. */
223 224 mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu);
224 225 }
225 226
226 227 /*
227 228 * Set the media type (properly this time).
228 229 */
229 230 if (dsp->ds_native)
230 231 dlp->dl_mac_type = minfop->mi_nativemedia;
231 232 else
232 233 dlp->dl_mac_type = minfop->mi_media;
233 234
234 235 /*
235 236 * Set the DLSAP length. We only support 16 bit values and they
236 237 * appear after the MAC address portion of DLSAP addresses.
237 238 */
238 239 sap_length = sizeof (uint16_t);
239 240 dlp->dl_sap_length = NEG(sap_length);
240 241
241 242 addr_length = minfop->mi_addr_length;
242 243
243 244 /*
244 245 * Copy in the media broadcast address.
245 246 */
246 247 if (minfop->mi_brdcst_addr != NULL) {
247 248 dlp->dl_brdcst_addr_offset =
248 249 (uintptr_t)brdcst_addr - (uintptr_t)dlp;
249 250 bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length);
250 251 dlp->dl_brdcst_addr_length = addr_length;
251 252 }
252 253
253 254 /* Only VLAN links and links that have a normal tag mode support QOS. */
254 255 if ((dsp->ds_mch != NULL &&
255 256 mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) ||
256 257 (dsp->ds_dlp != NULL &&
257 258 dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_NORMAL)) {
258 259 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
259 260 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
260 261
261 262 rangep->dl_qos_type = DL_QOS_CL_RANGE1;
262 263 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
263 264 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
264 265 rangep->dl_protection.dl_min = DL_UNKNOWN;
265 266 rangep->dl_protection.dl_max = DL_UNKNOWN;
266 267 rangep->dl_residual_error = DL_UNKNOWN;
267 268
268 269 /*
269 270 * Specify the supported range of priorities.
270 271 */
271 272 rangep->dl_priority.dl_min = 0;
272 273 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
273 274
274 275 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
275 276 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
276 277
277 278 selp->dl_qos_type = DL_QOS_CL_SEL1;
278 279 selp->dl_trans_delay = DL_UNKNOWN;
279 280 selp->dl_protection = DL_UNKNOWN;
280 281 selp->dl_residual_error = DL_UNKNOWN;
281 282
282 283 /*
283 284 * Specify the current priority (which can be changed by
284 285 * the DL_UDQOS_REQ primitive).
285 286 */
286 287 selp->dl_priority = dsp->ds_pri;
287 288 }
288 289
289 290 dlp->dl_addr_length = addr_length + sizeof (uint16_t);
290 291 if (dsp->ds_dlstate == DL_IDLE) {
291 292 /*
292 293 * The stream is bound. Therefore we can formulate a valid
293 294 * DLSAP address.
294 295 */
295 296 dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
296 297 if (addr_length > 0)
297 298 mac_unicast_primary_get(dsp->ds_mh, addr);
298 299
299 300 *(uint16_t *)(addr + addr_length) = dsp->ds_sap;
300 301 }
301 302
302 303 done:
303 304 IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0);
304 305 IMPLY(dlp->dl_qos_range_offset != 0,
305 306 dlp->dl_qos_range_length != 0);
306 307 IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0);
307 308 IMPLY(dlp->dl_brdcst_addr_offset != 0,
308 309 dlp->dl_brdcst_addr_length != 0);
309 310
310 311 qreply(q, mp);
311 312 }
312 313
313 314 /*
314 315 * DL_ATTACH_REQ
315 316 */
316 317 static void
317 318 proto_attach_req(dld_str_t *dsp, mblk_t *mp)
318 319 {
319 320 dl_attach_req_t *dlp = (dl_attach_req_t *)mp->b_rptr;
320 321 int err = 0;
321 322 t_uscalar_t dl_err;
322 323 queue_t *q = dsp->ds_wq;
323 324
324 325 if (MBLKL(mp) < sizeof (dl_attach_req_t) ||
325 326 dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) {
326 327 dl_err = DL_BADPRIM;
327 328 goto failed;
328 329 }
329 330
330 331 if (dsp->ds_dlstate != DL_UNATTACHED) {
331 332 dl_err = DL_OUTSTATE;
332 333 goto failed;
333 334 }
334 335
335 336 dsp->ds_dlstate = DL_ATTACH_PENDING;
336 337
337 338 err = dld_str_attach(dsp, dlp->dl_ppa);
338 339 if (err != 0) {
339 340 switch (err) {
340 341 case ENOENT:
341 342 dl_err = DL_BADPPA;
342 343 err = 0;
343 344 break;
344 345 default:
345 346 dl_err = DL_SYSERR;
346 347 break;
347 348 }
348 349 dsp->ds_dlstate = DL_UNATTACHED;
349 350 goto failed;
350 351 }
351 352 ASSERT(dsp->ds_dlstate == DL_UNBOUND);
352 353 dlokack(q, mp, DL_ATTACH_REQ);
353 354 return;
354 355
355 356 failed:
356 357 dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err);
357 358 }
358 359
359 360 /*
360 361 * DL_DETACH_REQ
361 362 */
362 363 static void
363 364 proto_detach_req(dld_str_t *dsp, mblk_t *mp)
364 365 {
365 366 queue_t *q = dsp->ds_wq;
366 367 t_uscalar_t dl_err;
367 368
368 369 if (MBLKL(mp) < sizeof (dl_detach_req_t)) {
369 370 dl_err = DL_BADPRIM;
370 371 goto failed;
371 372 }
372 373
373 374 if (dsp->ds_dlstate != DL_UNBOUND) {
374 375 dl_err = DL_OUTSTATE;
375 376 goto failed;
376 377 }
377 378
378 379 if (dsp->ds_style == DL_STYLE1) {
379 380 dl_err = DL_BADPRIM;
380 381 goto failed;
381 382 }
382 383
383 384 ASSERT(dsp->ds_datathr_cnt == 0);
384 385 dsp->ds_dlstate = DL_DETACH_PENDING;
385 386
386 387 dld_str_detach(dsp);
387 388 dlokack(dsp->ds_wq, mp, DL_DETACH_REQ);
388 389 return;
389 390
390 391 failed:
391 392 dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0);
392 393 }
393 394
394 395 /*
395 396 * DL_BIND_REQ
396 397 */
397 398 static void
398 399 proto_bind_req(dld_str_t *dsp, mblk_t *mp)
399 400 {
400 401 dl_bind_req_t *dlp = (dl_bind_req_t *)mp->b_rptr;
401 402 int err = 0;
402 403 uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)];
403 404 uint_t dlsap_addr_length;
404 405 t_uscalar_t dl_err;
405 406 t_scalar_t sap;
406 407 queue_t *q = dsp->ds_wq;
407 408 mac_perim_handle_t mph;
408 409 void *mdip;
409 410 int32_t intr_cpu;
410 411
411 412 if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
412 413 dl_err = DL_BADPRIM;
413 414 goto failed;
414 415 }
415 416
416 417 if (dlp->dl_xidtest_flg != 0) {
417 418 dl_err = DL_NOAUTO;
418 419 goto failed;
419 420 }
420 421
421 422 if (dlp->dl_service_mode != DL_CLDLS) {
422 423 dl_err = DL_UNSUPPORTED;
423 424 goto failed;
424 425 }
425 426
426 427 if (dsp->ds_dlstate != DL_UNBOUND) {
427 428 dl_err = DL_OUTSTATE;
428 429 goto failed;
429 430 }
430 431
431 432 mac_perim_enter_by_mh(dsp->ds_mh, &mph);
432 433
433 434 if ((err = dls_active_set(dsp)) != 0) {
434 435 dl_err = DL_SYSERR;
435 436 goto failed2;
436 437 }
437 438
438 439 dsp->ds_dlstate = DL_BIND_PENDING;
439 440 /*
440 441 * Set the receive callback.
441 442 */
442 443 dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ?
443 444 dld_str_rx_raw : dld_str_rx_unitdata, dsp);
444 445
445 446 /*
446 447 * Bind the channel such that it can receive packets.
447 448 */
448 449 sap = dlp->dl_sap;
449 450 dsp->ds_nonip = !check_mod_above(dsp->ds_rq, "ip") &&
450 451 !check_mod_above(dsp->ds_rq, "arp");
451 452
452 453 err = dls_bind(dsp, sap);
453 454 if (err != 0) {
454 455 switch (err) {
455 456 case EINVAL:
456 457 dl_err = DL_BADADDR;
457 458 err = 0;
458 459 break;
459 460 default:
460 461 dl_err = DL_SYSERR;
461 462 break;
462 463 }
463 464
464 465 dsp->ds_dlstate = DL_UNBOUND;
465 466 dls_active_clear(dsp, B_FALSE);
466 467 goto failed2;
467 468 }
468 469
469 470 intr_cpu = mac_client_intr_cpu(dsp->ds_mch);
470 471 mdip = mac_get_devinfo(dsp->ds_mh);
471 472 mac_perim_exit(mph);
472 473
473 474 /*
474 475 * We do this after we get out of the perim to avoid deadlocks
475 476 * etc. since part of mac_client_retarget_intr is to walk the
476 477 * device tree in order to find and retarget the interrupts.
477 478 */
478 479 if (intr_cpu != -1)
479 480 mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu);
480 481
481 482 /*
482 483 * Copy in MAC address.
483 484 */
484 485 dlsap_addr_length = dsp->ds_mip->mi_addr_length;
485 486 mac_unicast_primary_get(dsp->ds_mh, dlsap_addr);
486 487
487 488 /*
488 489 * Copy in the SAP.
489 490 */
490 491 *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap;
491 492 dlsap_addr_length += sizeof (uint16_t);
492 493
493 494 dsp->ds_dlstate = DL_IDLE;
494 495 dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0);
495 496 return;
496 497
497 498 failed2:
498 499 mac_perim_exit(mph);
499 500 failed:
500 501 dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err);
501 502 }
502 503
503 504 /*
504 505 * DL_UNBIND_REQ
505 506 */
506 507 static void
507 508 proto_unbind_req(dld_str_t *dsp, mblk_t *mp)
508 509 {
509 510 queue_t *q = dsp->ds_wq;
510 511 t_uscalar_t dl_err;
511 512 mac_perim_handle_t mph;
512 513
513 514 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
514 515 dl_err = DL_BADPRIM;
515 516 goto failed;
516 517 }
517 518
518 519 if (dsp->ds_dlstate != DL_IDLE) {
519 520 dl_err = DL_OUTSTATE;
520 521 goto failed;
521 522 }
522 523
523 524 mutex_enter(&dsp->ds_lock);
524 525 while (dsp->ds_datathr_cnt != 0)
525 526 cv_wait(&dsp->ds_datathr_cv, &dsp->ds_lock);
526 527
527 528 dsp->ds_dlstate = DL_UNBIND_PENDING;
528 529 mutex_exit(&dsp->ds_lock);
529 530
530 531 mac_perim_enter_by_mh(dsp->ds_mh, &mph);
531 532 /*
532 533 * Unbind the channel to stop packets being received.
533 534 */
534 535 dls_unbind(dsp);
535 536
536 537 /*
537 538 * Disable polling mode, if it is enabled.
538 539 */
539 540 (void) dld_capab_poll_disable(dsp, NULL);
540 541
541 542 /*
542 543 * Clear LSO flags.
543 544 */
544 545 dsp->ds_lso = B_FALSE;
545 546 dsp->ds_lso_max = 0;
546 547
547 548 /*
548 549 * Clear the receive callback.
549 550 */
550 551 dls_rx_set(dsp, NULL, NULL);
551 552 dsp->ds_direct = B_FALSE;
552 553
553 554 /*
554 555 * Set the mode back to the default (unitdata).
555 556 */
556 557 dsp->ds_mode = DLD_UNITDATA;
557 558 dsp->ds_dlstate = DL_UNBOUND;
558 559
559 560 dls_active_clear(dsp, B_FALSE);
560 561 mac_perim_exit(mph);
561 562 dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
562 563 return;
563 564 failed:
564 565 dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0);
565 566 }
|
↓ open down ↓ |
533 lines elided |
↑ open up ↑ |
566 567
567 568 /*
568 569 * DL_PROMISCON_REQ
569 570 */
570 571 static void
571 572 proto_promiscon_req(dld_str_t *dsp, mblk_t *mp)
572 573 {
573 574 dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)mp->b_rptr;
574 575 int err = 0;
575 576 t_uscalar_t dl_err;
576 - uint32_t promisc_saved;
577 + uint32_t new_flags, promisc_saved;
577 578 queue_t *q = dsp->ds_wq;
578 579 mac_perim_handle_t mph;
579 580
580 581 if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
581 582 dl_err = DL_BADPRIM;
582 583 goto failed;
583 584 }
584 585
585 586 if (dsp->ds_dlstate == DL_UNATTACHED ||
586 587 DL_ACK_PENDING(dsp->ds_dlstate)) {
587 588 dl_err = DL_OUTSTATE;
588 589 goto failed;
589 590 }
590 591
591 - promisc_saved = dsp->ds_promisc;
592 + mac_perim_enter_by_mh(dsp->ds_mh, &mph);
593 +
594 + new_flags = promisc_saved = dsp->ds_promisc;
592 595 switch (dlp->dl_level) {
593 596 case DL_PROMISC_SAP:
594 - dsp->ds_promisc |= DLS_PROMISC_SAP;
597 + new_flags |= DLS_PROMISC_SAP;
595 598 break;
596 599
597 600 case DL_PROMISC_MULTI:
598 - dsp->ds_promisc |= DLS_PROMISC_MULTI;
601 + new_flags |= DLS_PROMISC_MULTI;
599 602 break;
600 603
601 604 case DL_PROMISC_PHYS:
602 - dsp->ds_promisc |= DLS_PROMISC_PHYS;
605 + new_flags |= DLS_PROMISC_PHYS;
603 606 break;
604 607
605 608 default:
606 609 dl_err = DL_NOTSUPPORTED;
607 610 goto failed;
608 611 }
609 612
610 - mac_perim_enter_by_mh(dsp->ds_mh, &mph);
611 -
612 613 if ((promisc_saved == 0) && (err = dls_active_set(dsp)) != 0) {
613 - dsp->ds_promisc = promisc_saved;
614 + ASSERT(dsp->ds_promisc == promisc_saved);
614 615 dl_err = DL_SYSERR;
615 616 goto failed2;
616 617 }
617 618
618 619 /*
619 620 * Adjust channel promiscuity.
620 621 */
621 - err = dls_promisc(dsp, promisc_saved);
622 + err = dls_promisc(dsp, new_flags);
622 623
623 624 if (err != 0) {
624 625 dl_err = DL_SYSERR;
625 626 dsp->ds_promisc = promisc_saved;
626 627 if (promisc_saved == 0)
627 628 dls_active_clear(dsp, B_FALSE);
628 629 goto failed2;
629 630 }
630 631
631 632 mac_perim_exit(mph);
632 633
633 634 dlokack(q, mp, DL_PROMISCON_REQ);
634 635 return;
635 636
636 637 failed2:
637 638 mac_perim_exit(mph);
638 639 failed:
639 640 dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err);
640 641 }
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
641 642
642 643 /*
643 644 * DL_PROMISCOFF_REQ
644 645 */
645 646 static void
646 647 proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp)
647 648 {
648 649 dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr;
649 650 int err = 0;
650 651 t_uscalar_t dl_err;
651 - uint32_t promisc_saved;
652 + uint32_t new_flags;
652 653 queue_t *q = dsp->ds_wq;
653 654 mac_perim_handle_t mph;
654 655
655 656 if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
656 657 dl_err = DL_BADPRIM;
657 658 goto failed;
658 659 }
659 660
660 661 if (dsp->ds_dlstate == DL_UNATTACHED ||
661 662 DL_ACK_PENDING(dsp->ds_dlstate)) {
662 663 dl_err = DL_OUTSTATE;
663 664 goto failed;
664 665 }
665 666
666 - promisc_saved = dsp->ds_promisc;
667 + mac_perim_enter_by_mh(dsp->ds_mh, &mph);
668 +
669 + new_flags = dsp->ds_promisc;
667 670 switch (dlp->dl_level) {
668 671 case DL_PROMISC_SAP:
669 672 if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) {
670 673 dl_err = DL_NOTENAB;
671 674 goto failed;
672 675 }
673 - dsp->ds_promisc &= ~DLS_PROMISC_SAP;
676 + new_flags &= ~DLS_PROMISC_SAP;
674 677 break;
675 678
676 679 case DL_PROMISC_MULTI:
677 680 if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) {
678 681 dl_err = DL_NOTENAB;
679 682 goto failed;
680 683 }
681 - dsp->ds_promisc &= ~DLS_PROMISC_MULTI;
684 + new_flags &= ~DLS_PROMISC_MULTI;
682 685 break;
683 686
684 687 case DL_PROMISC_PHYS:
685 688 if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) {
686 689 dl_err = DL_NOTENAB;
687 690 goto failed;
688 691 }
689 - dsp->ds_promisc &= ~DLS_PROMISC_PHYS;
692 + new_flags &= ~DLS_PROMISC_PHYS;
690 693 break;
691 694
692 695 default:
693 696 dl_err = DL_NOTSUPPORTED;
694 697 goto failed;
695 698 }
696 699
697 - mac_perim_enter_by_mh(dsp->ds_mh, &mph);
698 700 /*
699 701 * Adjust channel promiscuity.
700 702 */
701 - err = dls_promisc(dsp, promisc_saved);
703 + err = dls_promisc(dsp, new_flags);
702 704
703 705 if (err != 0) {
704 706 mac_perim_exit(mph);
705 707 dl_err = DL_SYSERR;
706 708 goto failed;
707 709 }
708 710
711 + ASSERT(dsp->ds_promisc == new_flags);
709 712 if (dsp->ds_promisc == 0)
710 713 dls_active_clear(dsp, B_FALSE);
711 714
712 715 mac_perim_exit(mph);
713 716
714 717 dlokack(q, mp, DL_PROMISCOFF_REQ);
715 718 return;
716 719 failed:
717 720 dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err);
718 721 }
719 722
720 723 /*
721 724 * DL_ENABMULTI_REQ
722 725 */
723 726 static void
724 727 proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp)
725 728 {
726 729 dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr;
727 730 int err = 0;
728 731 t_uscalar_t dl_err;
729 732 queue_t *q = dsp->ds_wq;
730 733 mac_perim_handle_t mph;
731 734
732 735 if (dsp->ds_dlstate == DL_UNATTACHED ||
733 736 DL_ACK_PENDING(dsp->ds_dlstate)) {
734 737 dl_err = DL_OUTSTATE;
735 738 goto failed;
736 739 }
737 740
738 741 if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
739 742 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
740 743 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
741 744 dl_err = DL_BADPRIM;
742 745 goto failed;
743 746 }
744 747
745 748 mac_perim_enter_by_mh(dsp->ds_mh, &mph);
746 749
747 750 if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) {
748 751 dl_err = DL_SYSERR;
749 752 goto failed2;
750 753 }
751 754
752 755 err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset);
753 756 if (err != 0) {
754 757 switch (err) {
755 758 case EINVAL:
756 759 dl_err = DL_BADADDR;
757 760 err = 0;
758 761 break;
759 762 case ENOSPC:
760 763 dl_err = DL_TOOMANY;
761 764 err = 0;
762 765 break;
763 766 default:
764 767 dl_err = DL_SYSERR;
765 768 break;
766 769 }
767 770 if (dsp->ds_dmap == NULL)
768 771 dls_active_clear(dsp, B_FALSE);
769 772 goto failed2;
770 773 }
771 774
772 775 mac_perim_exit(mph);
773 776
774 777 dlokack(q, mp, DL_ENABMULTI_REQ);
775 778 return;
776 779
777 780 failed2:
778 781 mac_perim_exit(mph);
779 782 failed:
780 783 dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err);
781 784 }
782 785
783 786 /*
784 787 * DL_DISABMULTI_REQ
785 788 */
786 789 static void
787 790 proto_disabmulti_req(dld_str_t *dsp, mblk_t *mp)
788 791 {
789 792 dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)mp->b_rptr;
790 793 int err = 0;
791 794 t_uscalar_t dl_err;
792 795 queue_t *q = dsp->ds_wq;
793 796 mac_perim_handle_t mph;
794 797
795 798 if (dsp->ds_dlstate == DL_UNATTACHED ||
796 799 DL_ACK_PENDING(dsp->ds_dlstate)) {
797 800 dl_err = DL_OUTSTATE;
798 801 goto failed;
799 802 }
800 803
801 804 if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
802 805 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
803 806 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
804 807 dl_err = DL_BADPRIM;
805 808 goto failed;
806 809 }
807 810
808 811 mac_perim_enter_by_mh(dsp->ds_mh, &mph);
809 812 err = dls_multicst_remove(dsp, mp->b_rptr + dlp->dl_addr_offset);
810 813 if ((err == 0) && (dsp->ds_dmap == NULL))
811 814 dls_active_clear(dsp, B_FALSE);
812 815 mac_perim_exit(mph);
813 816
814 817 if (err != 0) {
815 818 switch (err) {
816 819 case EINVAL:
817 820 dl_err = DL_BADADDR;
818 821 err = 0;
819 822 break;
820 823
821 824 case ENOENT:
822 825 dl_err = DL_NOTENAB;
823 826 err = 0;
824 827 break;
825 828
826 829 default:
827 830 dl_err = DL_SYSERR;
828 831 break;
829 832 }
830 833 goto failed;
831 834 }
832 835 dlokack(q, mp, DL_DISABMULTI_REQ);
833 836 return;
834 837 failed:
835 838 dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err);
836 839 }
837 840
838 841 /*
839 842 * DL_PHYS_ADDR_REQ
840 843 */
841 844 static void
842 845 proto_physaddr_req(dld_str_t *dsp, mblk_t *mp)
843 846 {
844 847 dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr;
845 848 queue_t *q = dsp->ds_wq;
846 849 t_uscalar_t dl_err = 0;
847 850 char *addr = NULL;
848 851 uint_t addr_length;
849 852
850 853 if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
851 854 dl_err = DL_BADPRIM;
852 855 goto done;
853 856 }
854 857
855 858 if (dsp->ds_dlstate == DL_UNATTACHED ||
856 859 DL_ACK_PENDING(dsp->ds_dlstate)) {
857 860 dl_err = DL_OUTSTATE;
858 861 goto done;
859 862 }
860 863
861 864 addr_length = dsp->ds_mip->mi_addr_length;
862 865 if (addr_length > 0) {
863 866 addr = kmem_alloc(addr_length, KM_SLEEP);
864 867 switch (dlp->dl_addr_type) {
865 868 case DL_CURR_PHYS_ADDR:
866 869 mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr);
867 870 break;
868 871 case DL_FACT_PHYS_ADDR:
869 872 bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length);
870 873 break;
871 874 case DL_CURR_DEST_ADDR:
872 875 if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr))
873 876 dl_err = DL_NOTSUPPORTED;
874 877 break;
875 878 default:
876 879 dl_err = DL_UNSUPPORTED;
877 880 }
878 881 }
879 882 done:
880 883 if (dl_err == 0)
881 884 dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length);
882 885 else
883 886 dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0);
884 887 if (addr != NULL)
885 888 kmem_free(addr, addr_length);
886 889 }
887 890
888 891 /*
889 892 * DL_SET_PHYS_ADDR_REQ
890 893 */
891 894 static void
892 895 proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
893 896 {
894 897 dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr;
895 898 int err = 0;
896 899 t_uscalar_t dl_err;
897 900 queue_t *q = dsp->ds_wq;
898 901 mac_perim_handle_t mph;
899 902
900 903 if (dsp->ds_dlstate == DL_UNATTACHED ||
901 904 DL_ACK_PENDING(dsp->ds_dlstate)) {
902 905 dl_err = DL_OUTSTATE;
903 906 goto failed;
904 907 }
905 908
906 909 if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
907 910 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
908 911 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
909 912 dl_err = DL_BADPRIM;
910 913 goto failed;
911 914 }
912 915
913 916 mac_perim_enter_by_mh(dsp->ds_mh, &mph);
914 917
915 918 if ((err = dls_active_set(dsp)) != 0) {
916 919 dl_err = DL_SYSERR;
917 920 goto failed2;
918 921 }
919 922
920 923 /*
921 924 * If mac-nospoof is enabled and the link is owned by a
922 925 * non-global zone, changing the mac address is not allowed.
923 926 */
924 927 if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
925 928 mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
926 929 dls_active_clear(dsp, B_FALSE);
927 930 err = EACCES;
928 931 goto failed2;
929 932 }
930 933
931 934 err = mac_unicast_primary_set(dsp->ds_mh,
932 935 mp->b_rptr + dlp->dl_addr_offset);
933 936 if (err != 0) {
934 937 switch (err) {
935 938 case EINVAL:
936 939 dl_err = DL_BADADDR;
937 940 err = 0;
938 941 break;
939 942
940 943 default:
941 944 dl_err = DL_SYSERR;
942 945 break;
943 946 }
944 947 dls_active_clear(dsp, B_FALSE);
945 948 goto failed2;
946 949
947 950 }
948 951
949 952 mac_perim_exit(mph);
950 953
951 954 dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
952 955 return;
953 956
954 957 failed2:
955 958 mac_perim_exit(mph);
956 959 failed:
957 960 dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err);
958 961 }
959 962
960 963 /*
961 964 * DL_UDQOS_REQ
962 965 */
963 966 static void
964 967 proto_udqos_req(dld_str_t *dsp, mblk_t *mp)
965 968 {
966 969 dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr;
967 970 dl_qos_cl_sel1_t *selp;
968 971 int off, len;
969 972 t_uscalar_t dl_err;
970 973 queue_t *q = dsp->ds_wq;
971 974
972 975 off = dlp->dl_qos_offset;
973 976 len = dlp->dl_qos_length;
974 977
975 978 if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
976 979 dl_err = DL_BADPRIM;
977 980 goto failed;
978 981 }
979 982
980 983 selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
981 984 if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
982 985 dl_err = DL_BADQOSTYPE;
983 986 goto failed;
984 987 }
985 988
986 989 if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
987 990 selp->dl_priority < 0) {
988 991 dl_err = DL_BADQOSPARAM;
989 992 goto failed;
990 993 }
991 994
992 995 dsp->ds_pri = selp->dl_priority;
993 996 dlokack(q, mp, DL_UDQOS_REQ);
994 997 return;
995 998 failed:
996 999 dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0);
997 1000 }
998 1001
999 1002 static boolean_t
1000 1003 check_mod_above(queue_t *q, const char *mod)
1001 1004 {
1002 1005 queue_t *next_q;
1003 1006 boolean_t ret = B_TRUE;
1004 1007
1005 1008 claimstr(q);
1006 1009 next_q = q->q_next;
1007 1010 if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, mod) != 0)
1008 1011 ret = B_FALSE;
1009 1012 releasestr(q);
1010 1013 return (ret);
1011 1014 }
1012 1015
1013 1016 /*
1014 1017 * DL_CAPABILITY_REQ
1015 1018 */
1016 1019 static void
1017 1020 proto_capability_req(dld_str_t *dsp, mblk_t *mp)
1018 1021 {
1019 1022 dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
1020 1023 dl_capability_sub_t *sp;
1021 1024 size_t size, len;
1022 1025 offset_t off, end;
1023 1026 t_uscalar_t dl_err;
1024 1027 queue_t *q = dsp->ds_wq;
1025 1028
1026 1029 if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
1027 1030 dl_err = DL_BADPRIM;
1028 1031 goto failed;
1029 1032 }
1030 1033
1031 1034 if (dsp->ds_dlstate == DL_UNATTACHED ||
1032 1035 DL_ACK_PENDING(dsp->ds_dlstate)) {
1033 1036 dl_err = DL_OUTSTATE;
1034 1037 goto failed;
1035 1038 }
1036 1039
1037 1040 /*
1038 1041 * This request is overloaded. If there are no requested capabilities
1039 1042 * then we just want to acknowledge with all the capabilities we
1040 1043 * support. Otherwise we enable the set of capabilities requested.
1041 1044 */
1042 1045 if (dlp->dl_sub_length == 0) {
1043 1046 proto_capability_advertise(dsp, mp);
1044 1047 return;
1045 1048 }
1046 1049
1047 1050 if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
1048 1051 dl_err = DL_BADPRIM;
1049 1052 goto failed;
1050 1053 }
1051 1054
1052 1055 dlp->dl_primitive = DL_CAPABILITY_ACK;
1053 1056
1054 1057 off = dlp->dl_sub_offset;
1055 1058 len = dlp->dl_sub_length;
1056 1059
1057 1060 /*
1058 1061 * Walk the list of capabilities to be enabled.
1059 1062 */
1060 1063 for (end = off + len; off < end; ) {
1061 1064 sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1062 1065 size = sizeof (dl_capability_sub_t) + sp->dl_length;
1063 1066
1064 1067 if (off + size > end ||
1065 1068 !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1066 1069 dl_err = DL_BADPRIM;
1067 1070 goto failed;
1068 1071 }
1069 1072
1070 1073 switch (sp->dl_cap) {
1071 1074 /*
1072 1075 * TCP/IP checksum offload to hardware.
1073 1076 */
1074 1077 case DL_CAPAB_HCKSUM: {
1075 1078 dl_capab_hcksum_t *hcksump;
1076 1079 dl_capab_hcksum_t hcksum;
1077 1080
1078 1081 hcksump = (dl_capab_hcksum_t *)&sp[1];
1079 1082 /*
1080 1083 * Copy for alignment.
1081 1084 */
1082 1085 bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1083 1086 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1084 1087 bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1085 1088 break;
1086 1089 }
1087 1090
1088 1091 case DL_CAPAB_DLD: {
1089 1092 dl_capab_dld_t *dldp;
1090 1093 dl_capab_dld_t dld;
1091 1094
1092 1095 dldp = (dl_capab_dld_t *)&sp[1];
1093 1096 /*
1094 1097 * Copy for alignment.
1095 1098 */
1096 1099 bcopy(dldp, &dld, sizeof (dl_capab_dld_t));
1097 1100 dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1098 1101 bcopy(&dld, dldp, sizeof (dl_capab_dld_t));
1099 1102 break;
1100 1103 }
1101 1104 default:
1102 1105 break;
1103 1106 }
1104 1107 off += size;
1105 1108 }
1106 1109 qreply(q, mp);
1107 1110 return;
1108 1111 failed:
1109 1112 dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
1110 1113 }
1111 1114
1112 1115 /*
1113 1116 * DL_NOTIFY_REQ
1114 1117 */
1115 1118 static void
1116 1119 proto_notify_req(dld_str_t *dsp, mblk_t *mp)
1117 1120 {
1118 1121 dl_notify_req_t *dlp = (dl_notify_req_t *)mp->b_rptr;
1119 1122 t_uscalar_t dl_err;
1120 1123 queue_t *q = dsp->ds_wq;
1121 1124 uint_t note =
1122 1125 DL_NOTE_PROMISC_ON_PHYS |
1123 1126 DL_NOTE_PROMISC_OFF_PHYS |
1124 1127 DL_NOTE_PHYS_ADDR |
1125 1128 DL_NOTE_LINK_UP |
1126 1129 DL_NOTE_LINK_DOWN |
1127 1130 DL_NOTE_CAPAB_RENEG |
1128 1131 DL_NOTE_FASTPATH_FLUSH |
1129 1132 DL_NOTE_SPEED |
1130 1133 DL_NOTE_SDU_SIZE|
1131 1134 DL_NOTE_SDU_SIZE2|
1132 1135 DL_NOTE_ALLOWED_IPS;
1133 1136
1134 1137 if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
1135 1138 dl_err = DL_BADPRIM;
1136 1139 goto failed;
1137 1140 }
1138 1141
1139 1142 if (dsp->ds_dlstate == DL_UNATTACHED ||
1140 1143 DL_ACK_PENDING(dsp->ds_dlstate)) {
1141 1144 dl_err = DL_OUTSTATE;
1142 1145 goto failed;
1143 1146 }
1144 1147
1145 1148 note &= ~(mac_no_notification(dsp->ds_mh));
1146 1149
1147 1150 /*
1148 1151 * Cache the notifications that are being enabled.
1149 1152 */
1150 1153 dsp->ds_notifications = dlp->dl_notifications & note;
1151 1154 /*
1152 1155 * The ACK carries all notifications regardless of which set is
1153 1156 * being enabled.
1154 1157 */
1155 1158 dlnotifyack(q, mp, note);
1156 1159
1157 1160 /*
1158 1161 * Generate DL_NOTIFY_IND messages for each enabled notification.
1159 1162 */
1160 1163 if (dsp->ds_notifications != 0) {
1161 1164 dld_str_notify_ind(dsp);
1162 1165 }
1163 1166 return;
1164 1167 failed:
1165 1168 dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0);
1166 1169 }
1167 1170
1168 1171 /*
1169 1172 * DL_UINTDATA_REQ
1170 1173 */
1171 1174 void
1172 1175 proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
1173 1176 {
1174 1177 queue_t *q = dsp->ds_wq;
1175 1178 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1176 1179 off_t off;
1177 1180 size_t len, size;
1178 1181 const uint8_t *addr;
1179 1182 uint16_t sap;
1180 1183 uint_t addr_length;
1181 1184 mblk_t *bp, *payload;
1182 1185 uint32_t start, stuff, end, value, flags;
1183 1186 t_uscalar_t dl_err;
1184 1187 uint_t max_sdu;
1185 1188
1186 1189 if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
1187 1190 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
1188 1191 return;
1189 1192 }
1190 1193
1191 1194 mutex_enter(&dsp->ds_lock);
1192 1195 if (dsp->ds_dlstate != DL_IDLE) {
1193 1196 mutex_exit(&dsp->ds_lock);
1194 1197 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
1195 1198 return;
1196 1199 }
1197 1200 DLD_DATATHR_INC(dsp);
1198 1201 mutex_exit(&dsp->ds_lock);
1199 1202
1200 1203 addr_length = dsp->ds_mip->mi_addr_length;
1201 1204
1202 1205 off = dlp->dl_dest_addr_offset;
1203 1206 len = dlp->dl_dest_addr_length;
1204 1207
1205 1208 if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
1206 1209 dl_err = DL_BADPRIM;
1207 1210 goto failed;
1208 1211 }
1209 1212
1210 1213 if (len != addr_length + sizeof (uint16_t)) {
1211 1214 dl_err = DL_BADADDR;
1212 1215 goto failed;
1213 1216 }
1214 1217
1215 1218 addr = mp->b_rptr + off;
1216 1219 sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
1217 1220
1218 1221 /*
1219 1222 * Check the length of the packet and the block types.
1220 1223 */
1221 1224 size = 0;
1222 1225 payload = mp->b_cont;
1223 1226 for (bp = payload; bp != NULL; bp = bp->b_cont) {
1224 1227 if (DB_TYPE(bp) != M_DATA)
1225 1228 goto baddata;
1226 1229
1227 1230 size += MBLKL(bp);
1228 1231 }
1229 1232
1230 1233 mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
1231 1234 if (size > max_sdu)
1232 1235 goto baddata;
1233 1236
1234 1237 /*
1235 1238 * Build a packet header.
1236 1239 */
1237 1240 if ((bp = dls_header(dsp, addr, sap, dlp->dl_priority.dl_max,
1238 1241 &payload)) == NULL) {
1239 1242 dl_err = DL_BADADDR;
1240 1243 goto failed;
1241 1244 }
1242 1245
1243 1246 /*
1244 1247 * We no longer need the M_PROTO header, so free it.
1245 1248 */
1246 1249 freeb(mp);
1247 1250
1248 1251 /*
1249 1252 * Transfer the checksum offload information if it is present.
1250 1253 */
1251 1254 hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value,
1252 1255 &flags);
1253 1256 (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0);
1254 1257
1255 1258 /*
1256 1259 * Link the payload onto the new header.
1257 1260 */
1258 1261 ASSERT(bp->b_cont == NULL);
1259 1262 bp->b_cont = payload;
1260 1263
1261 1264 /*
1262 1265 * No lock can be held across modules and putnext()'s,
1263 1266 * which can happen here with the call from DLD_TX().
1264 1267 */
1265 1268 if (DLD_TX(dsp, bp, 0, 0) != NULL) {
1266 1269 /* flow-controlled */
1267 1270 DLD_SETQFULL(dsp);
1268 1271 }
1269 1272 DLD_DATATHR_DCR(dsp);
1270 1273 return;
1271 1274
1272 1275 failed:
1273 1276 dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0);
1274 1277 DLD_DATATHR_DCR(dsp);
1275 1278 return;
1276 1279
1277 1280 baddata:
1278 1281 dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1279 1282 DLD_DATATHR_DCR(dsp);
1280 1283 }
1281 1284
1282 1285 /*
1283 1286 * DL_PASSIVE_REQ
1284 1287 */
1285 1288 static void
1286 1289 proto_passive_req(dld_str_t *dsp, mblk_t *mp)
1287 1290 {
1288 1291 t_uscalar_t dl_err;
1289 1292
1290 1293 /*
1291 1294 * If we've already become active by issuing an active primitive,
1292 1295 * then it's too late to try to become passive.
1293 1296 */
1294 1297 if (dsp->ds_passivestate == DLD_ACTIVE) {
1295 1298 dl_err = DL_OUTSTATE;
1296 1299 goto failed;
1297 1300 }
1298 1301
1299 1302 if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1300 1303 dl_err = DL_BADPRIM;
1301 1304 goto failed;
1302 1305 }
1303 1306
1304 1307 dsp->ds_passivestate = DLD_PASSIVE;
1305 1308 dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1306 1309 return;
1307 1310 failed:
1308 1311 dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0);
1309 1312 }
1310 1313
1311 1314
1312 1315 /*
1313 1316 * Catch-all handler.
1314 1317 */
1315 1318 static void
1316 1319 proto_req(dld_str_t *dsp, mblk_t *mp)
1317 1320 {
1318 1321 union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
1319 1322
1320 1323 dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
1321 1324 }
1322 1325
1323 1326 static int
1324 1327 dld_capab_perim(dld_str_t *dsp, void *data, uint_t flags)
1325 1328 {
1326 1329 switch (flags) {
1327 1330 case DLD_ENABLE:
1328 1331 mac_perim_enter_by_mh(dsp->ds_mh, (mac_perim_handle_t *)data);
1329 1332 return (0);
1330 1333
1331 1334 case DLD_DISABLE:
1332 1335 mac_perim_exit((mac_perim_handle_t)data);
1333 1336 return (0);
1334 1337
1335 1338 case DLD_QUERY:
1336 1339 return (mac_perim_held(dsp->ds_mh));
1337 1340 }
1338 1341 return (0);
1339 1342 }
1340 1343
1341 1344 static int
1342 1345 dld_capab_direct(dld_str_t *dsp, void *data, uint_t flags)
1343 1346 {
1344 1347 dld_capab_direct_t *direct = data;
1345 1348
1346 1349 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1347 1350
1348 1351 switch (flags) {
1349 1352 case DLD_ENABLE:
1350 1353 dls_rx_set(dsp, (dls_rx_t)direct->di_rx_cf,
1351 1354 direct->di_rx_ch);
1352 1355
1353 1356 direct->di_tx_df = (uintptr_t)str_mdata_fastpath_put;
1354 1357 direct->di_tx_dh = dsp;
1355 1358 direct->di_tx_cb_df = (uintptr_t)mac_client_tx_notify;
1356 1359 direct->di_tx_cb_dh = dsp->ds_mch;
1357 1360 direct->di_tx_fctl_df = (uintptr_t)mac_tx_is_flow_blocked;
1358 1361 direct->di_tx_fctl_dh = dsp->ds_mch;
1359 1362
1360 1363 dsp->ds_direct = B_TRUE;
1361 1364
1362 1365 return (0);
1363 1366
1364 1367 case DLD_DISABLE:
1365 1368 dls_rx_set(dsp, (dsp->ds_mode == DLD_FASTPATH) ?
1366 1369 dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1367 1370 dsp->ds_direct = B_FALSE;
1368 1371
1369 1372 return (0);
1370 1373 }
1371 1374 return (ENOTSUP);
1372 1375 }
1373 1376
1374 1377 /*
1375 1378 * dld_capab_poll_enable()
1376 1379 *
1377 1380 * This function is misnamed. All polling and fanouts are run out of the
1378 1381 * lower mac (in case of VNIC and the only mac in case of NICs). The
1379 1382 * availability of Rx ring and promiscous mode is all taken care between
1380 1383 * the soft ring set (mac_srs), the Rx ring, and S/W classifier. Any
1381 1384 * fanout necessary is done by the soft rings that are part of the
1382 1385 * mac_srs (by default mac_srs sends the packets up via a TCP and
1383 1386 * non TCP soft ring).
1384 1387 *
1385 1388 * The mac_srs (or its associated soft rings) always store the ill_rx_ring
1386 1389 * (the cookie returned when they registered with IP during plumb) as their
1387 1390 * 2nd argument which is passed up as mac_resource_handle_t. The upcall
1388 1391 * function and 1st argument is what the caller registered when they
1389 1392 * called mac_rx_classify_flow_add() to register the flow. For VNIC,
1390 1393 * the function is vnic_rx and argument is vnic_t. For regular NIC
1391 1394 * case, it mac_rx_default and mac_handle_t. As explained above, the
1392 1395 * mac_srs (or its soft ring) will add the ill_rx_ring (mac_resource_handle_t)
1393 1396 * from its stored 2nd argument.
1394 1397 */
1395 1398 static int
1396 1399 dld_capab_poll_enable(dld_str_t *dsp, dld_capab_poll_t *poll)
1397 1400 {
1398 1401 if (dsp->ds_polling)
1399 1402 return (EINVAL);
1400 1403
1401 1404 if ((dld_opt & DLD_OPT_NO_POLL) != 0 || dsp->ds_mode == DLD_RAW)
1402 1405 return (ENOTSUP);
1403 1406
1404 1407 /*
1405 1408 * Enable client polling if and only if DLS bypass is possible.
1406 1409 * Special cases like VLANs need DLS processing in the Rx data path.
1407 1410 * In such a case we can neither allow the client (IP) to directly
1408 1411 * poll the softring (since DLS processing hasn't been done) nor can
1409 1412 * we allow DLS bypass.
1410 1413 */
1411 1414 if (!mac_rx_bypass_set(dsp->ds_mch, dsp->ds_rx, dsp->ds_rx_arg))
1412 1415 return (ENOTSUP);
1413 1416
1414 1417 /*
1415 1418 * Register soft ring resources. This will come in handy later if
1416 1419 * the user decides to modify CPU bindings to use more CPUs for the
1417 1420 * device in which case we will switch to fanout using soft rings.
1418 1421 */
1419 1422 mac_resource_set_common(dsp->ds_mch,
1420 1423 (mac_resource_add_t)poll->poll_ring_add_cf,
1421 1424 (mac_resource_remove_t)poll->poll_ring_remove_cf,
1422 1425 (mac_resource_quiesce_t)poll->poll_ring_quiesce_cf,
1423 1426 (mac_resource_restart_t)poll->poll_ring_restart_cf,
1424 1427 (mac_resource_bind_t)poll->poll_ring_bind_cf,
1425 1428 poll->poll_ring_ch);
1426 1429
1427 1430 mac_client_poll_enable(dsp->ds_mch);
1428 1431
1429 1432 dsp->ds_polling = B_TRUE;
1430 1433 return (0);
1431 1434 }
1432 1435
1433 1436 /* ARGSUSED */
1434 1437 static int
1435 1438 dld_capab_poll_disable(dld_str_t *dsp, dld_capab_poll_t *poll)
1436 1439 {
1437 1440 if (!dsp->ds_polling)
1438 1441 return (EINVAL);
1439 1442
1440 1443 mac_client_poll_disable(dsp->ds_mch);
1441 1444 mac_resource_set(dsp->ds_mch, NULL, NULL);
1442 1445
1443 1446 dsp->ds_polling = B_FALSE;
1444 1447 return (0);
1445 1448 }
1446 1449
1447 1450 static int
1448 1451 dld_capab_poll(dld_str_t *dsp, void *data, uint_t flags)
1449 1452 {
1450 1453 dld_capab_poll_t *poll = data;
1451 1454
1452 1455 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1453 1456
1454 1457 switch (flags) {
1455 1458 case DLD_ENABLE:
1456 1459 return (dld_capab_poll_enable(dsp, poll));
1457 1460 case DLD_DISABLE:
1458 1461 return (dld_capab_poll_disable(dsp, poll));
1459 1462 }
1460 1463 return (ENOTSUP);
1461 1464 }
1462 1465
1463 1466 static int
1464 1467 dld_capab_lso(dld_str_t *dsp, void *data, uint_t flags)
1465 1468 {
1466 1469 dld_capab_lso_t *lso = data;
1467 1470
1468 1471 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1469 1472
1470 1473 switch (flags) {
1471 1474 case DLD_ENABLE: {
1472 1475 mac_capab_lso_t mac_lso;
1473 1476
1474 1477 /*
1475 1478 * Check if LSO is supported on this MAC & enable LSO
1476 1479 * accordingly.
1477 1480 */
1478 1481 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) {
1479 1482 lso->lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max;
1480 1483 lso->lso_flags = 0;
1481 1484 /* translate the flag for mac clients */
1482 1485 if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV4) != 0)
1483 1486 lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV4;
1484 1487 dsp->ds_lso = B_TRUE;
1485 1488 dsp->ds_lso_max = lso->lso_max;
1486 1489 } else {
1487 1490 dsp->ds_lso = B_FALSE;
1488 1491 dsp->ds_lso_max = 0;
1489 1492 return (ENOTSUP);
1490 1493 }
1491 1494 return (0);
1492 1495 }
1493 1496 case DLD_DISABLE: {
1494 1497 dsp->ds_lso = B_FALSE;
1495 1498 dsp->ds_lso_max = 0;
1496 1499 return (0);
1497 1500 }
1498 1501 }
1499 1502 return (ENOTSUP);
1500 1503 }
1501 1504
1502 1505 static int
1503 1506 dld_capab(dld_str_t *dsp, uint_t type, void *data, uint_t flags)
1504 1507 {
1505 1508 int err;
1506 1509
1507 1510 /*
1508 1511 * Don't enable direct callback capabilities unless the caller is
1509 1512 * the IP client. When a module is inserted in a stream (_I_INSERT)
1510 1513 * the stack initiates capability disable, but due to races, the
1511 1514 * module insertion may complete before the capability disable
1512 1515 * completes. So we limit the check to DLD_ENABLE case.
1513 1516 */
1514 1517 if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
1515 1518 (dsp->ds_sap != ETHERTYPE_IP ||
1516 1519 !check_mod_above(dsp->ds_rq, "ip"))) {
1517 1520 return (ENOTSUP);
1518 1521 }
1519 1522
1520 1523 switch (type) {
1521 1524 case DLD_CAPAB_DIRECT:
1522 1525 err = dld_capab_direct(dsp, data, flags);
1523 1526 break;
1524 1527
1525 1528 case DLD_CAPAB_POLL:
1526 1529 err = dld_capab_poll(dsp, data, flags);
1527 1530 break;
1528 1531
1529 1532 case DLD_CAPAB_PERIM:
1530 1533 err = dld_capab_perim(dsp, data, flags);
1531 1534 break;
1532 1535
1533 1536 case DLD_CAPAB_LSO:
1534 1537 err = dld_capab_lso(dsp, data, flags);
1535 1538 break;
1536 1539
1537 1540 default:
1538 1541 err = ENOTSUP;
1539 1542 break;
1540 1543 }
1541 1544
1542 1545 return (err);
1543 1546 }
1544 1547
1545 1548 /*
1546 1549 * DL_CAPABILITY_ACK/DL_ERROR_ACK
1547 1550 */
1548 1551 static void
1549 1552 proto_capability_advertise(dld_str_t *dsp, mblk_t *mp)
1550 1553 {
1551 1554 dl_capability_ack_t *dlap;
1552 1555 dl_capability_sub_t *dlsp;
1553 1556 size_t subsize;
1554 1557 dl_capab_dld_t dld;
1555 1558 dl_capab_hcksum_t hcksum;
1556 1559 dl_capab_zerocopy_t zcopy;
1557 1560 dl_capab_vrrp_t vrrp;
1558 1561 mac_capab_vrrp_t vrrp_capab;
1559 1562 uint8_t *ptr;
1560 1563 queue_t *q = dsp->ds_wq;
1561 1564 mblk_t *mp1;
1562 1565 boolean_t hcksum_capable = B_FALSE;
1563 1566 boolean_t zcopy_capable = B_FALSE;
1564 1567 boolean_t dld_capable = B_FALSE;
1565 1568 boolean_t vrrp_capable = B_FALSE;
1566 1569
1567 1570 /*
1568 1571 * Initially assume no capabilities.
1569 1572 */
1570 1573 subsize = 0;
1571 1574
1572 1575 /*
1573 1576 * Check if checksum offload is supported on this MAC.
1574 1577 */
1575 1578 bzero(&hcksum, sizeof (dl_capab_hcksum_t));
1576 1579 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM,
1577 1580 &hcksum.hcksum_txflags)) {
1578 1581 if (hcksum.hcksum_txflags != 0) {
1579 1582 hcksum_capable = B_TRUE;
1580 1583 subsize += sizeof (dl_capability_sub_t) +
1581 1584 sizeof (dl_capab_hcksum_t);
1582 1585 }
1583 1586 }
1584 1587
1585 1588 /*
1586 1589 * Check if zerocopy is supported on this interface.
1587 1590 * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled
1588 1591 * then reserve space for that capability.
1589 1592 */
1590 1593 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) &&
1591 1594 !(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1592 1595 zcopy_capable = B_TRUE;
1593 1596 subsize += sizeof (dl_capability_sub_t) +
1594 1597 sizeof (dl_capab_zerocopy_t);
1595 1598 }
1596 1599
1597 1600 /*
1598 1601 * Direct capability negotiation interface between IP and DLD
1599 1602 */
1600 1603 if (dsp->ds_sap == ETHERTYPE_IP && check_mod_above(dsp->ds_rq, "ip")) {
1601 1604 dld_capable = B_TRUE;
1602 1605 subsize += sizeof (dl_capability_sub_t) +
1603 1606 sizeof (dl_capab_dld_t);
1604 1607 }
1605 1608
1606 1609 /*
1607 1610 * Check if vrrp is supported on this interface. If so, reserve
1608 1611 * space for that capability.
1609 1612 */
1610 1613 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_VRRP, &vrrp_capab)) {
1611 1614 vrrp_capable = B_TRUE;
1612 1615 subsize += sizeof (dl_capability_sub_t) +
1613 1616 sizeof (dl_capab_vrrp_t);
1614 1617 }
1615 1618
1616 1619 /*
1617 1620 * If there are no capabilities to advertise or if we
1618 1621 * can't allocate a response, send a DL_ERROR_ACK.
1619 1622 */
1620 1623 if ((mp1 = reallocb(mp,
1621 1624 sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
1622 1625 dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
1623 1626 return;
1624 1627 }
1625 1628
1626 1629 mp = mp1;
1627 1630 DB_TYPE(mp) = M_PROTO;
1628 1631 mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
1629 1632 bzero(mp->b_rptr, MBLKL(mp));
1630 1633 dlap = (dl_capability_ack_t *)mp->b_rptr;
1631 1634 dlap->dl_primitive = DL_CAPABILITY_ACK;
1632 1635 dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
1633 1636 dlap->dl_sub_length = subsize;
1634 1637 ptr = (uint8_t *)&dlap[1];
1635 1638
1636 1639 /*
1637 1640 * TCP/IP checksum offload.
1638 1641 */
1639 1642 if (hcksum_capable) {
1640 1643 dlsp = (dl_capability_sub_t *)ptr;
1641 1644
1642 1645 dlsp->dl_cap = DL_CAPAB_HCKSUM;
1643 1646 dlsp->dl_length = sizeof (dl_capab_hcksum_t);
1644 1647 ptr += sizeof (dl_capability_sub_t);
1645 1648
1646 1649 hcksum.hcksum_version = HCKSUM_VERSION_1;
1647 1650 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1648 1651 bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
1649 1652 ptr += sizeof (dl_capab_hcksum_t);
1650 1653 }
1651 1654
1652 1655 /*
1653 1656 * Zero copy
1654 1657 */
1655 1658 if (zcopy_capable) {
1656 1659 dlsp = (dl_capability_sub_t *)ptr;
1657 1660
1658 1661 dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
1659 1662 dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
1660 1663 ptr += sizeof (dl_capability_sub_t);
1661 1664
1662 1665 bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
1663 1666 zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
1664 1667 zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
1665 1668
1666 1669 dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
1667 1670 bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
1668 1671 ptr += sizeof (dl_capab_zerocopy_t);
1669 1672 }
1670 1673
1671 1674 /*
1672 1675 * VRRP capability negotiation
1673 1676 */
1674 1677 if (vrrp_capable) {
1675 1678 dlsp = (dl_capability_sub_t *)ptr;
1676 1679 dlsp->dl_cap = DL_CAPAB_VRRP;
1677 1680 dlsp->dl_length = sizeof (dl_capab_vrrp_t);
1678 1681 ptr += sizeof (dl_capability_sub_t);
1679 1682
1680 1683 bzero(&vrrp, sizeof (dl_capab_vrrp_t));
1681 1684 vrrp.vrrp_af = vrrp_capab.mcv_af;
1682 1685 bcopy(&vrrp, ptr, sizeof (dl_capab_vrrp_t));
1683 1686 ptr += sizeof (dl_capab_vrrp_t);
1684 1687 }
1685 1688
1686 1689 /*
1687 1690 * Direct capability negotiation interface between IP and DLD.
1688 1691 * Refer to dld.h for details.
1689 1692 */
1690 1693 if (dld_capable) {
1691 1694 dlsp = (dl_capability_sub_t *)ptr;
1692 1695 dlsp->dl_cap = DL_CAPAB_DLD;
1693 1696 dlsp->dl_length = sizeof (dl_capab_dld_t);
1694 1697 ptr += sizeof (dl_capability_sub_t);
1695 1698
1696 1699 bzero(&dld, sizeof (dl_capab_dld_t));
1697 1700 dld.dld_version = DLD_CURRENT_VERSION;
1698 1701 dld.dld_capab = (uintptr_t)dld_capab;
1699 1702 dld.dld_capab_handle = (uintptr_t)dsp;
1700 1703
1701 1704 dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1702 1705 bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
1703 1706 ptr += sizeof (dl_capab_dld_t);
1704 1707 }
1705 1708
1706 1709 ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1707 1710 qreply(q, mp);
1708 1711 }
1709 1712
1710 1713 /*
1711 1714 * Disable any enabled capabilities.
1712 1715 */
1713 1716 void
1714 1717 dld_capabilities_disable(dld_str_t *dsp)
1715 1718 {
1716 1719 if (dsp->ds_polling)
1717 1720 (void) dld_capab_poll_disable(dsp, NULL);
1718 1721 }
|
↓ open down ↓ |
1000 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX