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