1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Data-Link Driver 31 */ 32 33 #include <sys/types.h> 34 #include <sys/debug.h> 35 #include <sys/sysmacros.h> 36 #include <sys/stream.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 #include <sys/strsun.h> 40 #include <sys/dlpi.h> 41 #include <netinet/in.h> 42 #include <sys/sdt.h> 43 #include <sys/strsubr.h> 44 #include <sys/vlan.h> 45 #include <sys/mac.h> 46 #include <sys/dls.h> 47 #include <sys/dld.h> 48 #include <sys/dld_impl.h> 49 50 typedef boolean_t proto_reqfunc_t(dld_str_t *, union DL_primitives *, mblk_t *); 51 52 static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req, 53 proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req, 54 proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req, 55 proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req, 56 proto_notify_req, proto_unitdata_req, proto_passive_req; 57 58 static void proto_excl(queue_t *, mblk_t *); 59 static void proto_info_ack(dld_str_t *, mblk_t *); 60 static void proto_attach_ack(dld_str_t *, mblk_t *, int); 61 static void proto_detach_ack(dld_str_t *, mblk_t *); 62 static void proto_bind_ack(dld_str_t *, mblk_t *, int); 63 static void proto_unbind_ack(dld_str_t *, mblk_t *); 64 static void proto_promiscon_ack(dld_str_t *, mblk_t *, int); 65 static void proto_promiscoff_ack(dld_str_t *, mblk_t *, int); 66 static void proto_enabmulti_ack(dld_str_t *, mblk_t *, int); 67 static void proto_disabmulti_ack(dld_str_t *, mblk_t *, int); 68 static void proto_setphysaddr_ack(dld_str_t *, mblk_t *, int); 69 static void proto_physaddr_ack(dld_str_t *, mblk_t *, t_uscalar_t); 70 static void proto_udqos_ack(dld_str_t *, mblk_t *); 71 static void proto_poll_disable(dld_str_t *); 72 static boolean_t proto_poll_enable(dld_str_t *, dl_capab_poll_t *); 73 static void proto_capability_ack(dld_str_t *, mblk_t *); 74 static void proto_capability_enable(dld_str_t *, mblk_t *); 75 static void proto_notify_ack(dld_str_t *, mblk_t *, uint_t, 76 uint_t); 77 78 #define DL_SOLARIS 0x100 79 80 /* 81 * M_PROTO/M_PCPROTO request handlers 82 */ 83 84 typedef struct proto_req_info { 85 t_uscalar_t pri_prim; 86 const char *pri_txt; 87 boolean_t pri_needexcl; 88 boolean_t pri_active; 89 proto_reqfunc_t *pri_fn; 90 } proto_req_info_t; 91 92 static proto_req_info_t proto_ri[] = { 93 { DL_INFO_REQ, "DL_INFO_REQ", B_FALSE, B_FALSE, proto_info_req }, 94 { DL_BIND_REQ, "DL_BIND_REQ", B_TRUE, B_TRUE, proto_bind_req }, 95 { DL_UNBIND_REQ, "DL_UNBIND_REQ", B_TRUE, B_FALSE, proto_unbind_req }, 96 { DL_INFO_ACK, "DL_INFO_ACK", B_FALSE, B_FALSE, proto_req }, 97 { DL_BIND_ACK, "DL_BIND_ACK", B_FALSE, B_FALSE, proto_req }, 98 { DL_ERROR_ACK, "DL_ERROR_ACK", B_FALSE, B_FALSE, proto_req }, 99 { DL_OK_ACK, "DL_OK_ACK", B_FALSE, B_FALSE, proto_req }, 100 { DL_UNITDATA_REQ, "DL_UNITDATA_REQ", B_FALSE, B_FALSE, 101 proto_unitdata_req }, 102 { DL_UNITDATA_IND, "DL_UNITDATA_IND", B_FALSE, B_FALSE, proto_req }, 103 { DL_UDERROR_IND, "DL_UDERROR_IND", B_FALSE, B_FALSE, proto_req }, 104 { DL_UDQOS_REQ, "DL_UDQOS_REQ", B_TRUE, B_FALSE, proto_udqos_req }, 105 { DL_ATTACH_REQ, "DL_ATTACH_REQ", B_TRUE, B_FALSE, proto_attach_req }, 106 { DL_DETACH_REQ, "DL_DETACH_REQ", B_TRUE, B_FALSE, proto_detach_req }, 107 { DL_CONNECT_REQ, "DL_CONNECT_REQ", B_FALSE, B_FALSE, proto_req }, 108 { DL_CONNECT_IND, "DL_CONNECT_IND", B_FALSE, B_FALSE, proto_req }, 109 { DL_CONNECT_RES, "DL_CONNECT_RES", B_FALSE, B_FALSE, proto_req }, 110 { DL_CONNECT_CON, "DL_CONNECT_CON", B_FALSE, B_FALSE, proto_req }, 111 { DL_TOKEN_REQ, "DL_TOKEN_REQ", B_FALSE, B_FALSE, proto_req }, 112 { DL_TOKEN_ACK, "DL_TOKEN_ACK", B_FALSE, B_FALSE, proto_req }, 113 { DL_DISCONNECT_REQ, "DL_DISCONNECT_REQ", B_FALSE, B_FALSE, proto_req }, 114 { DL_DISCONNECT_IND, "DL_DISCONNECT_IND", B_FALSE, B_FALSE, proto_req }, 115 { DL_SUBS_UNBIND_REQ, "DL_SUBS_UNBIND_REQ", B_FALSE, B_FALSE, 116 proto_req }, 117 { 0x16, "undefined", B_FALSE, B_FALSE, proto_req }, 118 { DL_RESET_REQ, "DL_RESET_REQ", B_FALSE, B_FALSE, proto_req }, 119 { DL_RESET_IND, "DL_RESET_IND", B_FALSE, B_FALSE, proto_req }, 120 { DL_RESET_RES, "DL_RESET_RES", B_FALSE, B_FALSE, proto_req }, 121 { DL_RESET_CON, "DL_RESET_CON", B_FALSE, B_FALSE, proto_req }, 122 { DL_SUBS_BIND_REQ, "DL_SUBS_BIND_REQ", B_FALSE, B_FALSE, proto_req }, 123 { DL_SUBS_BIND_ACK, "DL_SUBS_BIND_ACK", B_FALSE, B_FALSE, proto_req }, 124 { DL_ENABMULTI_REQ, "DL_ENABMULTI_REQ", B_TRUE, B_TRUE, 125 proto_enabmulti_req }, 126 { DL_DISABMULTI_REQ, "DL_DISABMULTI_REQ", B_TRUE, B_FALSE, 127 proto_disabmulti_req }, 128 { DL_PROMISCON_REQ, "DL_PROMISCON_REQ", B_TRUE, B_TRUE, 129 proto_promiscon_req }, 130 { DL_PROMISCOFF_REQ, "DL_PROMISCOFF_REQ", B_TRUE, B_FALSE, 131 proto_promiscoff_req }, 132 { DL_DATA_ACK_REQ, "DL_DATA_ACK_REQ", B_FALSE, B_FALSE, proto_req }, 133 { DL_DATA_ACK_IND, "DL_DATA_ACK_IND", B_FALSE, B_FALSE, proto_req }, 134 { DL_DATA_ACK_STATUS_IND, "DL_DATA_ACK_STATUS_IND", B_FALSE, B_FALSE, 135 proto_req }, 136 { DL_REPLY_REQ, "DL_REPLY_REQ", B_FALSE, B_FALSE, proto_req }, 137 { DL_REPLY_IND, "DL_REPLY_IND", B_FALSE, B_FALSE, proto_req }, 138 { DL_REPLY_STATUS_IND, "DL_REPLY_STATUS_IND", B_FALSE, B_FALSE, 139 proto_req }, 140 { DL_REPLY_UPDATE_REQ, "DL_REPLY_UPDATE_REQ", B_FALSE, B_FALSE, 141 proto_req }, 142 { DL_REPLY_UPDATE_STATUS_IND, "DL_REPLY_UPDATE_STATUS_IND", B_FALSE, 143 B_FALSE, proto_req }, 144 { DL_XID_REQ, "DL_XID_REQ", B_FALSE, B_FALSE, proto_req }, 145 { DL_XID_IND, "DL_XID_IND", B_FALSE, B_FALSE, proto_req }, 146 { DL_XID_RES, "DL_XID_RES", B_FALSE, B_FALSE, proto_req }, 147 { DL_XID_CON, "DL_XID_CON", B_FALSE, B_FALSE, proto_req }, 148 { DL_TEST_REQ, "DL_TEST_REQ", B_FALSE, B_FALSE, proto_req }, 149 { DL_TEST_IND, "DL_TEST_IND", B_FALSE, B_FALSE, proto_req }, 150 { DL_TEST_RES, "DL_TEST_RES", B_FALSE, B_FALSE, proto_req }, 151 { DL_TEST_CON, "DL_TEST_CON", B_FALSE, B_FALSE, proto_req }, 152 { DL_PHYS_ADDR_REQ, "DL_PHYS_ADDR_REQ", B_FALSE, B_FALSE, 153 proto_physaddr_req }, 154 { DL_PHYS_ADDR_ACK, "DL_PHYS_ADDR_ACK", B_FALSE, B_FALSE, proto_req }, 155 { DL_SET_PHYS_ADDR_REQ, "DL_SET_PHYS_ADDR_REQ", B_TRUE, B_TRUE, 156 proto_setphysaddr_req }, 157 { DL_GET_STATISTICS_REQ, "DL_GET_STATISTICS_REQ", B_FALSE, B_FALSE, 158 proto_req }, 159 { DL_GET_STATISTICS_ACK, "DL_GET_STATISTICS_ACK", B_FALSE, B_FALSE, 160 proto_req } 161 }; 162 163 #define PROTO_RI_COUNT (sizeof (proto_ri) / sizeof (proto_ri[0])) 164 165 static proto_req_info_t proto_sri[] = { 166 { DL_NOTIFY_REQ, "DL_NOTIFY_REQ", B_FALSE, B_FALSE, proto_notify_req }, 167 { DL_NOTIFY_ACK, "DL_NOTIFY_ACK", B_FALSE, B_FALSE, proto_req }, 168 { DL_NOTIFY_IND, "DL_NOTIFY_IND", B_FALSE, B_FALSE, proto_req }, 169 { DL_AGGR_REQ, "DL_AGGR_REQ", B_FALSE, B_TRUE, proto_req }, 170 { DL_AGGR_IND, "DL_AGGR_IND", B_FALSE, B_FALSE, proto_req }, 171 { DL_UNAGGR_REQ, "DL_UNAGGR_REQ", B_FALSE, B_TRUE, proto_req }, 172 { 0x106, "undefined", B_FALSE, B_FALSE, proto_req }, 173 { 0x107, "undefined", B_FALSE, B_FALSE, proto_req }, 174 { 0x108, "undefined", B_FALSE, B_FALSE, proto_req }, 175 { 0x109, "undefined", B_FALSE, B_FALSE, proto_req }, 176 { 0x10a, "undefined", B_FALSE, B_FALSE, proto_req }, 177 { 0x10b, "undefined", B_FALSE, B_FALSE, proto_req }, 178 { 0x10c, "undefined", B_FALSE, B_FALSE, proto_req }, 179 { 0x10d, "undefined", B_FALSE, B_FALSE, proto_req }, 180 { 0x10e, "undefined", B_FALSE, B_FALSE, proto_req }, 181 { 0x10f, "undefined", B_FALSE, B_FALSE, proto_req }, 182 { DL_CAPABILITY_REQ, "DL_CAPABILITY_REQ", B_FALSE, B_FALSE, 183 proto_capability_req }, 184 { DL_CAPABILITY_ACK, "DL_CAPABILITY_ACK", B_FALSE, B_FALSE, proto_req }, 185 { DL_CONTROL_REQ, "DL_CONTROL_REQ", B_FALSE, B_TRUE, proto_req }, 186 { DL_CONTROL_ACK, "DL_CONTROL_ACK", B_FALSE, B_FALSE, proto_req }, 187 { DL_PASSIVE_REQ, "DL_PASSIVE_REQ", B_TRUE, B_FALSE, proto_passive_req } 188 }; 189 190 #define PROTO_SRI_COUNT (sizeof (proto_sri) / sizeof (proto_sri[0])) 191 192 #define DL_ACK_PENDING(state) \ 193 ((state) == DL_ATTACH_PENDING || \ 194 (state) == DL_DETACH_PENDING || \ 195 (state) == DL_BIND_PENDING || \ 196 (state) == DL_UNBIND_PENDING) 197 198 /* 199 * Process a DLPI protocol message. (Only ever called from put(9e)). 200 */ 201 void 202 dld_proto(dld_str_t *dsp, mblk_t *mp) 203 { 204 union DL_primitives *udlp; 205 t_uscalar_t prim; 206 proto_req_info_t *prip; 207 boolean_t success; 208 209 if (MBLKL(mp) < sizeof (t_uscalar_t)) { 210 freemsg(mp); 211 return; 212 } 213 214 udlp = (union DL_primitives *)mp->b_rptr; 215 prim = udlp->dl_primitive; 216 217 /* 218 * Select the correct jump table. 219 */ 220 if (prim & DL_SOLARIS) { 221 /* 222 * Entries in the 'solaris extensions' jump table 223 * have an extra bit in the primitive value. Clear it 224 * to do the lookup. 225 */ 226 prim &= ~DL_SOLARIS; 227 228 /* 229 * Check the primitive is in range. 230 */ 231 if (prim >= PROTO_SRI_COUNT) 232 goto unsupported; 233 234 /* 235 * Grab the jump table entry. 236 */ 237 prip = &proto_sri[prim]; 238 239 /* 240 * OR the cleared bit back in to make the primitive valid 241 * again. 242 */ 243 prim |= DL_SOLARIS; 244 } else { 245 /* 246 * Check the primitive is in range. 247 */ 248 if (prim >= PROTO_RI_COUNT) 249 goto unsupported; 250 251 /* 252 * Grab the jump table entry. 253 */ 254 prip = &proto_ri[prim]; 255 } 256 257 ASSERT(prip->pri_prim == prim); 258 259 /* 260 * If this primitive causes the data-link channel used by this 261 * object to become active, then we need to notify dls. Note that 262 * if we're already passive by having succesfully processed a 263 * DL_PASSIVE_REQ, then active primitives do not cause us to become 264 * active. 265 */ 266 if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { 267 if (!dls_active_set(dsp->ds_dc)) { 268 dlerrorack(dsp->ds_wq, mp, prim, DL_SYSERR, EBUSY); 269 return; 270 } 271 } 272 273 /* 274 * Check whether we need, and whether we have, exclusive access to 275 * the stream. 276 */ 277 if (prip->pri_needexcl) { 278 /* 279 * We only have shared access and we need exclusive access. 280 */ 281 ASSERT(!PERIM_EXCL(dsp->ds_wq)); 282 283 /* 284 * Process via qwriter(9f). 285 */ 286 qwriter(dsp->ds_wq, mp, proto_excl, PERIM_INNER); 287 return; 288 } 289 290 success = prip->pri_fn(dsp, udlp, mp); 291 if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { 292 if (success) 293 dsp->ds_passivestate = DLD_ACTIVE; 294 else 295 dls_active_clear(dsp->ds_dc); 296 } 297 298 return; 299 300 unsupported: 301 (void) proto_req(dsp, udlp, mp); 302 } 303 304 /* 305 * Called via qwriter(9f). 306 */ 307 static void 308 proto_excl(queue_t *q, mblk_t *mp) 309 { 310 dld_str_t *dsp = q->q_ptr; 311 union DL_primitives *udlp; 312 t_uscalar_t prim; 313 proto_req_info_t *prip; 314 boolean_t success; 315 316 ASSERT(MBLKL(mp) >= sizeof (t_uscalar_t)); 317 318 udlp = (union DL_primitives *)mp->b_rptr; 319 prim = udlp->dl_primitive; 320 321 /* 322 * Select the correct jump table. 323 */ 324 if (prim & DL_SOLARIS) { 325 /* 326 * Entries in the 'solaris extensions' jump table 327 * have an extra bit in the primitive value. Clear it 328 * to do the lookup. 329 */ 330 prim &= ~DL_SOLARIS; 331 332 /* 333 * Grab the jump table entry. 334 */ 335 ASSERT(prim < PROTO_SRI_COUNT); 336 prip = &proto_sri[prim]; 337 338 /* 339 * OR the cleared bit back in to make the primitive valid 340 * again. 341 */ 342 prim |= DL_SOLARIS; 343 } else { 344 /* 345 * Grab the jump table entry. 346 */ 347 ASSERT(prim < PROTO_RI_COUNT); 348 prip = &proto_ri[prim]; 349 } 350 351 ASSERT(prip->pri_prim == prim); 352 353 success = prip->pri_fn(dsp, udlp, mp); 354 if (prip->pri_active && dsp->ds_passivestate == DLD_UNINITIALIZED) { 355 if (success) 356 dsp->ds_passivestate = DLD_ACTIVE; 357 else 358 dls_active_clear(dsp->ds_dc); 359 } 360 } 361 362 /* 363 * DL_INFO_REQ 364 */ 365 /*ARGSUSED*/ 366 static boolean_t 367 proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 368 { 369 proto_info_ack(dsp, mp); 370 return (B_TRUE); 371 } 372 373 /* 374 * DL_ATTACH_REQ 375 */ 376 static boolean_t 377 proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 378 { 379 dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; 380 t_scalar_t index; 381 dld_node_t *dnp; 382 dld_ppa_t *dpp; 383 int err; 384 385 ASSERT(PERIM_EXCL(dsp->ds_wq)); 386 387 if (dsp->ds_dlstate != DL_UNATTACHED) { 388 dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_OUTSTATE, 0); 389 return (B_FALSE); 390 } 391 392 if (MBLKL(mp) < sizeof (dl_attach_req_t)) { 393 dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPRIM, 0); 394 return (B_FALSE); 395 } 396 397 index = dlp->dl_ppa; 398 399 dnp = dsp->ds_dnp; 400 ASSERT(dnp->dn_style == DL_STYLE2); 401 402 if ((dpp = dld_node_ppa_find(dnp, index)) == NULL) { 403 dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, DL_BADPPA, 0); 404 return (B_FALSE); 405 } 406 407 dsp->ds_dlstate = DL_ATTACH_PENDING; 408 409 err = dld_str_attach(dsp, dpp); 410 proto_attach_ack(dsp, mp, err); 411 return (err == 0); 412 } 413 414 /* 415 * DL_DETACH_REQ 416 */ 417 /*ARGSUSED*/ 418 static boolean_t 419 proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 420 { 421 ASSERT(PERIM_EXCL(dsp->ds_wq)); 422 423 if (dsp->ds_dlstate != DL_UNBOUND) { 424 dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0); 425 return (B_FALSE); 426 } 427 428 if (MBLKL(mp) < sizeof (dl_detach_req_t)) { 429 dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); 430 return (B_FALSE); 431 } 432 433 if ((dsp->ds_dnp)->dn_style == DL_STYLE1) { 434 dlerrorack(dsp->ds_wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); 435 return (B_FALSE); 436 } 437 438 dsp->ds_dlstate = DL_DETACH_PENDING; 439 440 dld_str_detach(dsp); 441 proto_detach_ack(dsp, mp); 442 return (B_TRUE); 443 } 444 445 /* 446 * DL_BIND_REQ 447 */ 448 static boolean_t 449 proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 450 { 451 dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; 452 int err; 453 454 ASSERT(PERIM_EXCL(dsp->ds_wq)); 455 456 if (dsp->ds_dlstate != DL_UNBOUND) { 457 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0); 458 return (B_FALSE); 459 } 460 461 if (MBLKL(mp) < sizeof (dl_bind_req_t)) { 462 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); 463 return (B_FALSE); 464 } 465 466 if (dlp->dl_xidtest_flg != 0) { 467 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_NOAUTO, 0); 468 return (B_FALSE); 469 } 470 471 if (dlp->dl_service_mode != DL_CLDLS) { 472 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); 473 return (B_FALSE); 474 } 475 476 dsp->ds_dlstate = DL_BIND_PENDING; 477 478 /* 479 * Set the receive callback. 480 */ 481 dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_RAW) ? 482 dld_str_rx_raw : dld_str_rx_unitdata, dsp); 483 484 /* 485 * Set the M_DATA handler. 486 */ 487 if (dsp->ds_mode == DLD_RAW) 488 dld_str_tx_raw(dsp); 489 490 /* 491 * Bind the channel such that it can receive packets. 492 */ 493 dsp->ds_sap = dlp->dl_sap; 494 err = dls_bind(dsp->ds_dc, dlp->dl_sap); 495 496 proto_bind_ack(dsp, mp, err); 497 return (err == 0); 498 } 499 500 /* 501 * DL_UNBIND_REQ 502 */ 503 /*ARGSUSED*/ 504 static boolean_t 505 proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 506 { 507 ASSERT(PERIM_EXCL(dsp->ds_wq)); 508 509 if (dsp->ds_dlstate != DL_IDLE) { 510 dlerrorack(dsp->ds_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); 511 return (B_FALSE); 512 } 513 514 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { 515 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); 516 return (B_FALSE); 517 } 518 519 dsp->ds_dlstate = DL_UNBIND_PENDING; 520 521 /* 522 * Flush any remaining packets scheduled for transmission. 523 */ 524 flushq(dsp->ds_wq, FLUSHALL); 525 526 /* 527 * Reset the M_DATA handler. 528 */ 529 dld_str_tx_drop(dsp); 530 531 /* 532 * Unbind the channel to stop packets being received. 533 */ 534 dls_unbind(dsp->ds_dc); 535 536 /* 537 * Disable polling mode, if it is enabled. 538 */ 539 proto_poll_disable(dsp); 540 541 /* 542 * Clear the receive callback. 543 */ 544 dls_rx_set(dsp->ds_dc, NULL, NULL); 545 546 /* 547 * Set the mode back to the default (unitdata). 548 */ 549 dsp->ds_mode = DLD_UNITDATA; 550 551 proto_unbind_ack(dsp, mp); 552 return (B_TRUE); 553 } 554 555 /* 556 * DL_PROMISCON_REQ 557 */ 558 static boolean_t 559 proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 560 { 561 dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; 562 int err; 563 564 ASSERT(PERIM_EXCL(dsp->ds_wq)); 565 566 if (dsp->ds_dlstate == DL_UNATTACHED || 567 DL_ACK_PENDING(dsp->ds_dlstate)) { 568 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_OUTSTATE, 0); 569 return (B_FALSE); 570 } 571 572 if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { 573 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); 574 return (B_FALSE); 575 } 576 577 switch (dlp->dl_level) { 578 case DL_PROMISC_SAP: 579 dsp->ds_promisc |= DLS_PROMISC_SAP; 580 break; 581 582 case DL_PROMISC_MULTI: 583 dsp->ds_promisc |= DLS_PROMISC_MULTI; 584 break; 585 586 case DL_PROMISC_PHYS: 587 dsp->ds_promisc |= DLS_PROMISC_PHYS; 588 break; 589 590 default: 591 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 592 0); 593 return (B_FALSE); 594 } 595 596 /* 597 * Adjust channel promiscuity. 598 */ 599 err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 600 proto_promiscon_ack(dsp, mp, err); 601 return (err == 0); 602 } 603 604 /* 605 * DL_PROMISCOFF_REQ 606 */ 607 static boolean_t 608 proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 609 { 610 dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; 611 int err; 612 613 ASSERT(PERIM_EXCL(dsp->ds_wq)); 614 615 if (dsp->ds_dlstate == DL_UNATTACHED || 616 DL_ACK_PENDING(dsp->ds_dlstate)) { 617 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_OUTSTATE, 0); 618 return (B_FALSE); 619 } 620 621 if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { 622 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); 623 return (B_FALSE); 624 } 625 626 switch (dlp->dl_level) { 627 case DL_PROMISC_SAP: 628 if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) 629 goto notenab; 630 631 dsp->ds_promisc &= ~DLS_PROMISC_SAP; 632 break; 633 634 case DL_PROMISC_MULTI: 635 if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) 636 goto notenab; 637 638 dsp->ds_promisc &= ~DLS_PROMISC_MULTI; 639 break; 640 641 case DL_PROMISC_PHYS: 642 if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) 643 goto notenab; 644 645 dsp->ds_promisc &= ~DLS_PROMISC_PHYS; 646 break; 647 648 default: 649 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 650 0); 651 return (B_FALSE); 652 } 653 654 /* 655 * Adjust channel promiscuity. 656 */ 657 err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 658 659 proto_promiscoff_ack(dsp, mp, err); 660 return (err == 0); 661 662 notenab: 663 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); 664 return (B_FALSE); 665 } 666 667 /* 668 * DL_ENABMULTI_REQ 669 */ 670 static boolean_t 671 proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 672 { 673 dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; 674 int err; 675 676 ASSERT(PERIM_EXCL(dsp->ds_wq)); 677 678 if (dsp->ds_dlstate == DL_UNATTACHED || 679 DL_ACK_PENDING(dsp->ds_dlstate)) { 680 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); 681 return (B_FALSE); 682 } 683 684 if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || 685 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 686 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 687 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); 688 return (B_FALSE); 689 } 690 691 err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 692 proto_enabmulti_ack(dsp, mp, err); 693 return (err == 0); 694 } 695 696 /* 697 * DL_DISABMULTI_REQ 698 */ 699 static boolean_t 700 proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 701 { 702 dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; 703 int err; 704 705 ASSERT(PERIM_EXCL(dsp->ds_wq)); 706 707 if (dsp->ds_dlstate == DL_UNATTACHED || 708 DL_ACK_PENDING(dsp->ds_dlstate)) { 709 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0); 710 return (B_FALSE); 711 } 712 713 if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || 714 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 715 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 716 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); 717 return (B_FALSE); 718 } 719 720 err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 721 proto_disabmulti_ack(dsp, mp, err); 722 return (err == 0); 723 } 724 725 /* 726 * DL_PHYS_ADDR_REQ 727 */ 728 static boolean_t 729 proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 730 { 731 dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; 732 733 if (dsp->ds_dlstate == DL_UNATTACHED || 734 DL_ACK_PENDING(dsp->ds_dlstate)) { 735 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 736 return (B_FALSE); 737 } 738 739 if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { 740 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); 741 return (B_FALSE); 742 } 743 744 if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && 745 dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { 746 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_UNSUPPORTED, 0); 747 return (B_FALSE); 748 } 749 750 proto_physaddr_ack(dsp, mp, dlp->dl_addr_type); 751 return (B_TRUE); 752 } 753 754 /* 755 * DL_SET_PHYS_ADDR_REQ 756 */ 757 static boolean_t 758 proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 759 { 760 dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; 761 int err; 762 763 ASSERT(PERIM_EXCL(dsp->ds_wq)); 764 765 if (dsp->ds_dlstate == DL_UNATTACHED || 766 DL_ACK_PENDING(dsp->ds_dlstate)) { 767 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 768 0); 769 return (B_FALSE); 770 } 771 772 if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || 773 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 774 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 775 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 776 0); 777 return (B_FALSE); 778 } 779 780 err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); 781 proto_setphysaddr_ack(dsp, mp, err); 782 return (err == 0); 783 } 784 785 /* 786 * DL_UDQOS_REQ 787 */ 788 static boolean_t 789 proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 790 { 791 dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; 792 dl_qos_cl_sel1_t *selp; 793 int off, len; 794 795 ASSERT(PERIM_EXCL(dsp->ds_wq)); 796 797 off = dlp->dl_qos_offset; 798 len = dlp->dl_qos_length; 799 800 if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { 801 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADPRIM, 0); 802 return (B_FALSE); 803 } 804 805 selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); 806 if (selp->dl_qos_type != DL_QOS_CL_SEL1) { 807 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSTYPE, 0); 808 return (B_FALSE); 809 } 810 811 if (dsp->ds_vid == VLAN_ID_NONE || 812 selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || 813 selp->dl_priority < 0) { 814 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSPARAM, 0); 815 return (B_FALSE); 816 } 817 818 dsp->ds_pri = selp->dl_priority; 819 proto_udqos_ack(dsp, mp); 820 return (B_TRUE); 821 } 822 823 /* 824 * DL_CAPABILITY_REQ 825 */ 826 /*ARGSUSED*/ 827 static boolean_t 828 proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 829 { 830 dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; 831 832 if (dsp->ds_dlstate == DL_UNATTACHED || 833 DL_ACK_PENDING(dsp->ds_dlstate)) { 834 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_OUTSTATE, 835 0); 836 return (B_FALSE); 837 } 838 839 if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 840 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); 841 return (B_FALSE); 842 } 843 844 /* 845 * This request is overloaded. If there are no requested capabilities 846 * then we just want to acknowledge with all the capabilities we 847 * support. Otherwise we enable the set of capabilities requested. 848 */ 849 if (dlp->dl_sub_length == 0) { 850 proto_capability_ack(dsp, mp); 851 return (B_TRUE); 852 } 853 854 if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 855 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); 856 return (B_FALSE); 857 } 858 859 proto_capability_enable(dsp, mp); 860 return (B_TRUE); 861 } 862 863 /* 864 * DL_NOTIFY_REQ 865 */ 866 static boolean_t 867 proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 868 { 869 dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; 870 uint_t notifications = 871 DL_NOTE_PROMISC_ON_PHYS | 872 DL_NOTE_PROMISC_OFF_PHYS | 873 DL_NOTE_PHYS_ADDR | 874 DL_NOTE_LINK_UP | 875 DL_NOTE_LINK_DOWN | 876 DL_NOTE_CAPAB_RENEG; 877 878 if (dsp->ds_dlstate == DL_UNATTACHED || 879 DL_ACK_PENDING(dsp->ds_dlstate)) { 880 dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_OUTSTATE, 881 0); 882 return (B_FALSE); 883 } 884 885 if (MBLKL(mp) < sizeof (dl_notify_req_t)) { 886 dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_BADPRIM, 0); 887 return (B_FALSE); 888 } 889 890 if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) 891 notifications |= DL_NOTE_SPEED; 892 893 proto_notify_ack(dsp, mp, dlp->dl_notifications & notifications, 894 notifications); 895 return (B_TRUE); 896 } 897 898 /* 899 * DL_UINTDATA_REQ 900 */ 901 static boolean_t 902 proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 903 { 904 queue_t *q = dsp->ds_wq; 905 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)udlp; 906 off_t off; 907 size_t len; 908 size_t size; 909 const uint8_t *addr; 910 uint16_t sap; 911 uint_t addr_length; 912 mblk_t *bp; 913 mblk_t *cont; 914 uint32_t start; 915 uint32_t stuff; 916 uint32_t end; 917 uint32_t value; 918 uint32_t flags; 919 920 if (dsp->ds_dlstate != DL_IDLE) { 921 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); 922 return (B_FALSE); 923 } 924 925 if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { 926 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); 927 return (B_FALSE); 928 } 929 930 off = dlp->dl_dest_addr_offset; 931 len = dlp->dl_dest_addr_length; 932 933 if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { 934 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); 935 return (B_FALSE); 936 } 937 938 addr_length = dsp->ds_mip->mi_addr_length; 939 if (len != addr_length + sizeof (uint16_t)) 940 goto badaddr; 941 942 addr = mp->b_rptr + off; 943 sap = *(uint16_t *)(mp->b_rptr + off + addr_length); 944 945 /* 946 * Check the length of the packet and the block types. 947 */ 948 size = 0; 949 cont = mp->b_cont; 950 for (bp = cont; bp != NULL; bp = bp->b_cont) { 951 if (DB_TYPE(bp) != M_DATA) 952 goto baddata; 953 954 size += MBLKL(bp); 955 } 956 957 if (size > dsp->ds_mip->mi_sdu_max) 958 goto baddata; 959 960 /* 961 * Build a packet header. 962 */ 963 if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) 964 goto badaddr; 965 966 /* 967 * We no longer need the M_PROTO header, so free it. 968 */ 969 freeb(mp); 970 971 /* 972 * Transfer the checksum offload information if it is present. 973 */ 974 hcksum_retrieve(cont, NULL, NULL, &start, &stuff, &end, &value, 975 &flags); 976 (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 977 0); 978 979 /* 980 * Link the payload onto the new header. 981 */ 982 ASSERT(bp->b_cont == NULL); 983 bp->b_cont = cont; 984 985 /* 986 * If something is already queued then we must queue to avoid 987 * re-ordering. 988 */ 989 if (q->q_first != NULL) { 990 (void) putq(q, bp); 991 return (B_TRUE); 992 } 993 994 /* 995 * Attempt to transmit the packet. 996 */ 997 if ((mp = dls_tx(dsp->ds_dc, bp)) != NULL) { 998 noenable(q); 999 while ((bp = mp) != NULL) { 1000 mp = mp->b_next; 1001 bp->b_next = NULL; 1002 (void) putq(q, bp); 1003 } 1004 } 1005 return (B_TRUE); 1006 1007 badaddr: 1008 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADADDR, 0); 1009 return (B_FALSE); 1010 1011 baddata: 1012 dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); 1013 return (B_FALSE); 1014 } 1015 1016 /* 1017 * DL_PASSIVE_REQ 1018 */ 1019 /* ARGSUSED */ 1020 static boolean_t 1021 proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1022 { 1023 ASSERT(PERIM_EXCL(dsp->ds_wq)); 1024 1025 /* 1026 * If we've already become active by issuing an active primitive, 1027 * then it's too late to try to become passive. 1028 */ 1029 if (dsp->ds_passivestate == DLD_ACTIVE) { 1030 dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_OUTSTATE, 0); 1031 return (B_FALSE); 1032 } 1033 1034 if (MBLKL(mp) < sizeof (dl_passive_req_t)) { 1035 dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_BADPRIM, 0); 1036 return (B_FALSE); 1037 } 1038 1039 dsp->ds_passivestate = DLD_PASSIVE; 1040 dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); 1041 return (B_TRUE); 1042 } 1043 1044 /* 1045 * Catch-all handler. 1046 */ 1047 static boolean_t 1048 proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) 1049 { 1050 dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 1051 return (B_FALSE); 1052 } 1053 1054 typedef struct dl_info_ack_wrapper { 1055 dl_info_ack_t dl_info; 1056 uint8_t dl_addr[MAXADDRLEN + sizeof (uint16_t)]; 1057 uint8_t dl_brdcst_addr[MAXADDRLEN]; 1058 dl_qos_cl_range1_t dl_qos_range1; 1059 dl_qos_cl_sel1_t dl_qos_sel1; 1060 } dl_info_ack_wrapper_t; 1061 1062 #define NEG(x) -(x) 1063 1064 /* 1065 * DL_INFO_ACK 1066 */ 1067 static void 1068 proto_info_ack(dld_str_t *dsp, mblk_t *mp) 1069 { 1070 dl_info_ack_wrapper_t *dlwp; 1071 dl_info_ack_t *dlp; 1072 dl_qos_cl_sel1_t *selp; 1073 dl_qos_cl_range1_t *rangep; 1074 uint8_t *addr; 1075 uint8_t *brdcst_addr; 1076 dld_node_t *dnp; 1077 uint_t addr_length; 1078 uint_t sap_length; 1079 1080 /* 1081 * Swap the request message for one large enough to contain the 1082 * wrapper structure defined above. 1083 */ 1084 if ((mp = mexchange(dsp->ds_wq, mp, sizeof (dl_info_ack_wrapper_t), 1085 M_PCPROTO, 0)) == NULL) 1086 return; 1087 1088 bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); 1089 dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; 1090 1091 dlp = &(dlwp->dl_info); 1092 ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); 1093 1094 dlp->dl_primitive = DL_INFO_ACK; 1095 1096 /* 1097 * Set up the sub-structure pointers. 1098 */ 1099 addr = dlwp->dl_addr; 1100 brdcst_addr = dlwp->dl_brdcst_addr; 1101 rangep = &(dlwp->dl_qos_range1); 1102 selp = &(dlwp->dl_qos_sel1); 1103 1104 /* 1105 * This driver supports only version 2 connectionless DLPI provider 1106 * nodes. 1107 */ 1108 dlp->dl_service_mode = DL_CLDLS; 1109 dlp->dl_version = DL_VERSION_2; 1110 1111 /* 1112 * Set the style of the provider from the dld_node_t structure 1113 * representing the dev_t that was opened. 1114 */ 1115 dnp = dsp->ds_dnp; 1116 dlp->dl_provider_style = dnp->dn_style; 1117 ASSERT(dlp->dl_provider_style == DL_STYLE1 || 1118 dlp->dl_provider_style == DL_STYLE2); 1119 1120 /* 1121 * Set the current DLPI state. 1122 */ 1123 dlp->dl_current_state = dsp->ds_dlstate; 1124 1125 /* 1126 * Gratuitously set the media type. This is because the Cisco VPN 3000 1127 * module assumes that the media type is known prior to DL_ATTACH_REQ 1128 * being completed. 1129 */ 1130 dlp->dl_mac_type = DL_ETHER; 1131 1132 /* 1133 * If the stream is not at least attached then we're done. 1134 */ 1135 if (dsp->ds_dlstate == DL_UNATTACHED || 1136 dsp->ds_dlstate == DL_ATTACH_PENDING || 1137 dsp->ds_dlstate == DL_DETACH_PENDING) 1138 goto done; 1139 1140 /* 1141 * Set the media type (properly this time). 1142 */ 1143 dlp->dl_mac_type = dsp->ds_mip->mi_media; 1144 1145 /* 1146 * Set the DLSAP length. We only support 16 bit values and they 1147 * appear after the MAC address portion of DLSAP addresses. 1148 */ 1149 sap_length = sizeof (uint16_t); 1150 dlp->dl_sap_length = NEG(sap_length); 1151 1152 /* 1153 * Set the minimum and maximum payload sizes. 1154 */ 1155 dlp->dl_min_sdu = dsp->ds_mip->mi_sdu_min; 1156 dlp->dl_max_sdu = dsp->ds_mip->mi_sdu_max; 1157 1158 addr_length = dsp->ds_mip->mi_addr_length; 1159 ASSERT(addr_length != 0); 1160 1161 /* 1162 * Copy in the media broadcast address. 1163 */ 1164 dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; 1165 bcopy(dsp->ds_mip->mi_brdcst_addr, brdcst_addr, addr_length); 1166 dlp->dl_brdcst_addr_length = addr_length; 1167 1168 /* 1169 * We only support QoS information for VLAN interfaces. 1170 */ 1171 if (dsp->ds_vid != VLAN_ID_NONE) { 1172 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; 1173 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); 1174 1175 rangep->dl_qos_type = DL_QOS_CL_RANGE1; 1176 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; 1177 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; 1178 rangep->dl_protection.dl_min = DL_UNKNOWN; 1179 rangep->dl_protection.dl_max = DL_UNKNOWN; 1180 rangep->dl_residual_error = DL_UNKNOWN; 1181 1182 /* 1183 * Specify the supported range of priorities. 1184 */ 1185 rangep->dl_priority.dl_min = 0; 1186 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; 1187 1188 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; 1189 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); 1190 1191 selp->dl_qos_type = DL_QOS_CL_SEL1; 1192 selp->dl_trans_delay = DL_UNKNOWN; 1193 selp->dl_protection = DL_UNKNOWN; 1194 selp->dl_residual_error = DL_UNKNOWN; 1195 1196 /* 1197 * Specify the current priority (which can be changed by 1198 * the DL_UDQOS_REQ primitive). 1199 */ 1200 selp->dl_priority = dsp->ds_pri; 1201 } else { 1202 /* 1203 * Shorten the buffer to lose the unused QoS information 1204 * structures. This is to work around a bug in the Cisco VPN 1205 * 3000 module. 1206 */ 1207 mp->b_wptr = (uint8_t *)rangep; 1208 } 1209 1210 dlp->dl_addr_length = addr_length + sizeof (uint16_t); 1211 if (dsp->ds_dlstate == DL_IDLE) { 1212 /* 1213 * The stream is bound. Therefore we can formulate a valid 1214 * DLSAP address. 1215 */ 1216 dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; 1217 bcopy(dsp->ds_curr_addr, addr, addr_length); 1218 *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 1219 } 1220 1221 done: 1222 ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); 1223 ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, 1224 dlp->dl_qos_range_length != 0)); 1225 ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); 1226 ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, 1227 dlp->dl_brdcst_addr_length != 0)); 1228 1229 qreply(dsp->ds_wq, mp); 1230 } 1231 1232 /* 1233 * DL_OK_ACK/DL_ERROR_ACK 1234 */ 1235 static void 1236 proto_attach_ack(dld_str_t *dsp, mblk_t *mp, int err) 1237 { 1238 int dl_err; 1239 1240 if (err != 0) 1241 goto failed; 1242 1243 dsp->ds_dlstate = DL_UNBOUND; 1244 dlokack(dsp->ds_wq, mp, DL_ATTACH_REQ); 1245 return; 1246 1247 failed: 1248 switch (err) { 1249 case ENOENT: 1250 dl_err = DL_BADPPA; 1251 err = 0; 1252 break; 1253 1254 default: 1255 dl_err = DL_SYSERR; 1256 break; 1257 } 1258 1259 dsp->ds_dlstate = DL_UNATTACHED; 1260 dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, dl_err, err); 1261 } 1262 1263 /* 1264 * DL_OK_ACK 1265 */ 1266 static void 1267 proto_detach_ack(dld_str_t *dsp, mblk_t *mp) 1268 { 1269 dsp->ds_dlstate = DL_UNATTACHED; 1270 dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); 1271 } 1272 1273 /* 1274 * DL_BIND_ACK/DL_ERROR_ACK 1275 */ 1276 static void 1277 proto_bind_ack(dld_str_t *dsp, mblk_t *mp, int err) 1278 { 1279 uint8_t addr[MAXADDRLEN]; 1280 uint_t addr_length; 1281 int dl_err; 1282 1283 if (err != 0) 1284 goto failed; 1285 1286 /* 1287 * Copy in MAC address. 1288 */ 1289 addr_length = dsp->ds_mip->mi_addr_length; 1290 bcopy(dsp->ds_curr_addr, addr, addr_length); 1291 1292 /* 1293 * Copy in the DLSAP. 1294 */ 1295 *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 1296 addr_length += sizeof (uint16_t); 1297 1298 dsp->ds_dlstate = DL_IDLE; 1299 dlbindack(dsp->ds_wq, mp, dsp->ds_sap, (void *)addr, addr_length, 0, 1300 0); 1301 return; 1302 1303 failed: 1304 switch (err) { 1305 case EINVAL: 1306 dl_err = DL_BADADDR; 1307 err = 0; 1308 break; 1309 1310 default: 1311 dl_err = DL_SYSERR; 1312 break; 1313 } 1314 1315 dsp->ds_dlstate = DL_UNBOUND; 1316 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, dl_err, err); 1317 } 1318 1319 /* 1320 * DL_OK_ACK 1321 */ 1322 static void 1323 proto_unbind_ack(dld_str_t *dsp, mblk_t *mp) 1324 { 1325 dsp->ds_dlstate = DL_UNBOUND; 1326 dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ); 1327 } 1328 1329 /* 1330 * DL_OK_ACK/DL_ERROR_ACK 1331 */ 1332 static void 1333 proto_promiscon_ack(dld_str_t *dsp, mblk_t *mp, int err) 1334 { 1335 if (err != 0) 1336 goto failed; 1337 1338 dlokack(dsp->ds_wq, mp, DL_PROMISCON_REQ); 1339 return; 1340 1341 failed: 1342 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_SYSERR, err); 1343 } 1344 1345 /* 1346 * DL_OK_ACK/DL_ERROR_ACK 1347 */ 1348 static void 1349 proto_promiscoff_ack(dld_str_t *dsp, mblk_t *mp, int err) 1350 { 1351 if (err != 0) 1352 goto failed; 1353 1354 dlokack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ); 1355 return; 1356 1357 failed: 1358 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, err); 1359 } 1360 1361 /* 1362 * DL_OK_ACK/DL_ERROR_ACK 1363 */ 1364 static void 1365 proto_enabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) 1366 { 1367 int dl_err; 1368 1369 if (err != 0) 1370 goto failed; 1371 1372 dlokack(dsp->ds_wq, mp, DL_ENABMULTI_REQ); 1373 return; 1374 1375 failed: 1376 switch (err) { 1377 case EINVAL: 1378 dl_err = DL_BADADDR; 1379 err = 0; 1380 break; 1381 1382 case ENOSPC: 1383 dl_err = DL_TOOMANY; 1384 err = 0; 1385 break; 1386 1387 default: 1388 dl_err = DL_SYSERR; 1389 break; 1390 } 1391 1392 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, dl_err, err); 1393 } 1394 1395 /* 1396 * DL_OK_ACK/DL_ERROR_ACK 1397 */ 1398 static void 1399 proto_disabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) 1400 { 1401 int dl_err; 1402 1403 if (err != 0) 1404 goto failed; 1405 1406 dlokack(dsp->ds_wq, mp, DL_DISABMULTI_REQ); 1407 return; 1408 1409 failed: 1410 switch (err) { 1411 case EINVAL: 1412 dl_err = DL_BADADDR; 1413 err = 0; 1414 break; 1415 1416 case ENOENT: 1417 dl_err = DL_NOTENAB; 1418 err = 0; 1419 break; 1420 1421 default: 1422 dl_err = DL_SYSERR; 1423 break; 1424 } 1425 1426 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, dl_err, err); 1427 } 1428 1429 /* 1430 * DL_PHYS_ADDR_ACK 1431 */ 1432 static void 1433 proto_physaddr_ack(dld_str_t *dsp, mblk_t *mp, t_uscalar_t type) 1434 { 1435 uint_t addr_length; 1436 1437 /* 1438 * Copy in the address. 1439 */ 1440 addr_length = dsp->ds_mip->mi_addr_length; 1441 dlphysaddrack(dsp->ds_wq, mp, (type == DL_CURR_PHYS_ADDR) ? 1442 dsp->ds_curr_addr : dsp->ds_fact_addr, addr_length); 1443 } 1444 1445 /* 1446 * DL_OK_ACK/DL_ERROR_ACK 1447 */ 1448 static void 1449 proto_setphysaddr_ack(dld_str_t *dsp, mblk_t *mp, int err) 1450 { 1451 int dl_err; 1452 1453 if (err != 0) 1454 goto failed; 1455 1456 dlokack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ); 1457 return; 1458 1459 failed: 1460 switch (err) { 1461 case EINVAL: 1462 dl_err = DL_BADADDR; 1463 err = 0; 1464 break; 1465 1466 default: 1467 dl_err = DL_SYSERR; 1468 break; 1469 } 1470 1471 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, dl_err, err); 1472 } 1473 1474 /* 1475 * DL_OK_ACK 1476 */ 1477 static void 1478 proto_udqos_ack(dld_str_t *dsp, mblk_t *mp) 1479 { 1480 dlokack(dsp->ds_wq, mp, DL_UDQOS_REQ); 1481 } 1482 1483 static void 1484 proto_poll_disable(dld_str_t *dsp) 1485 { 1486 mac_handle_t mh; 1487 1488 if (!dsp->ds_polling) 1489 return; 1490 1491 /* 1492 * It should be impossible to enable raw mode if polling is turned on. 1493 */ 1494 ASSERT(dsp->ds_mode != DLD_RAW); 1495 1496 /* 1497 * Reset the resource_add callback. 1498 */ 1499 mh = dls_mac(dsp->ds_dc); 1500 mac_resource_set(mh, NULL, NULL); 1501 1502 /* 1503 * Set receive function back to default. 1504 */ 1505 dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? 1506 dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp); 1507 1508 /* 1509 * Note that polling is disabled. 1510 */ 1511 dsp->ds_polling = B_FALSE; 1512 } 1513 1514 static boolean_t 1515 proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp) 1516 { 1517 mac_handle_t mh; 1518 1519 ASSERT(!dsp->ds_polling); 1520 1521 /* 1522 * We cannot enable polling if raw mode 1523 * has been enabled. 1524 */ 1525 if (dsp->ds_mode == DLD_RAW) 1526 return (B_FALSE); 1527 1528 mh = dls_mac(dsp->ds_dc); 1529 1530 /* 1531 * Register resources. 1532 */ 1533 mac_resource_set(mh, (mac_resource_add_t)pollp->poll_ring_add, 1534 (void *)pollp->poll_rx_handle); 1535 mac_resources(mh); 1536 1537 /* 1538 * Set the receive function. 1539 */ 1540 dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->poll_rx, 1541 (void *)pollp->poll_rx_handle); 1542 1543 /* 1544 * Note that polling is enabled. This prevents further DLIOCHDRINFO 1545 * ioctls from overwriting the receive function pointer. 1546 */ 1547 dsp->ds_polling = B_TRUE; 1548 return (B_TRUE); 1549 } 1550 1551 /* 1552 * DL_CAPABILITY_ACK/DL_ERROR_ACK 1553 */ 1554 static void 1555 proto_capability_ack(dld_str_t *dsp, mblk_t *mp) 1556 { 1557 dl_capability_ack_t *dlap; 1558 dl_capability_sub_t *dlsp; 1559 size_t subsize; 1560 dl_capab_poll_t poll; 1561 dl_capab_hcksum_t hcksum; 1562 dl_capab_zerocopy_t zcopy; 1563 uint8_t *ptr; 1564 uint32_t cksum; 1565 boolean_t poll_cap; 1566 1567 /* 1568 * Initially assume no capabilities. 1569 */ 1570 subsize = 0; 1571 1572 /* 1573 * Check if polling can be enabled on this interface. 1574 * If advertising DL_CAPAB_POLL has not been explicitly disabled 1575 * then reserve space for that capability. 1576 */ 1577 poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) && 1578 !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE)); 1579 if (poll_cap) { 1580 subsize += sizeof (dl_capability_sub_t) + 1581 sizeof (dl_capab_poll_t); 1582 } 1583 1584 /* 1585 * If the MAC interface supports checksum offload then reserve 1586 * space for the DL_CAPAB_HCKSUM capability. 1587 */ 1588 if ((cksum = dsp->ds_mip->mi_cksum) != 0) { 1589 subsize += sizeof (dl_capability_sub_t) + 1590 sizeof (dl_capab_hcksum_t); 1591 } 1592 1593 /* 1594 * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then 1595 * reserve space for it. 1596 */ 1597 if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 1598 subsize += sizeof (dl_capability_sub_t) + 1599 sizeof (dl_capab_zerocopy_t); 1600 } 1601 1602 /* 1603 * If there are no capabilities to advertise, send a DL_ERROR_ACK. 1604 */ 1605 if (subsize == 0) { 1606 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 1607 0); 1608 return; 1609 } 1610 1611 if ((mp = mexchange(dsp->ds_wq, mp, 1612 sizeof (dl_capability_ack_t) + subsize, M_PROTO, 0)) == NULL) 1613 return; 1614 1615 bzero(mp->b_rptr, sizeof (dl_capability_ack_t)); 1616 dlap = (dl_capability_ack_t *)mp->b_rptr; 1617 dlap->dl_primitive = DL_CAPABILITY_ACK; 1618 dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 1619 dlap->dl_sub_length = subsize; 1620 ptr = (uint8_t *)&dlap[1]; 1621 1622 /* 1623 * IP polling interface. 1624 */ 1625 if (poll_cap) { 1626 /* 1627 * Attempt to disable just in case this is a re-negotiation. 1628 */ 1629 proto_poll_disable(dsp); 1630 1631 dlsp = (dl_capability_sub_t *)ptr; 1632 1633 dlsp->dl_cap = DL_CAPAB_POLL; 1634 dlsp->dl_length = sizeof (dl_capab_poll_t); 1635 ptr += sizeof (dl_capability_sub_t); 1636 1637 bzero(&poll, sizeof (dl_capab_poll_t)); 1638 poll.poll_version = POLL_VERSION_1; 1639 poll.poll_flags = POLL_CAPABLE; 1640 poll.poll_tx_handle = (uintptr_t)dsp->ds_dc; 1641 poll.poll_tx = (uintptr_t)dls_tx; 1642 1643 dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); 1644 bcopy(&poll, ptr, sizeof (dl_capab_poll_t)); 1645 ptr += sizeof (dl_capab_poll_t); 1646 } 1647 1648 /* 1649 * TCP/IP checksum offload. 1650 */ 1651 if (cksum != 0) { 1652 dlsp = (dl_capability_sub_t *)ptr; 1653 1654 dlsp->dl_cap = DL_CAPAB_HCKSUM; 1655 dlsp->dl_length = sizeof (dl_capab_hcksum_t); 1656 ptr += sizeof (dl_capability_sub_t); 1657 1658 bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 1659 hcksum.hcksum_version = HCKSUM_VERSION_1; 1660 hcksum.hcksum_txflags = cksum; 1661 1662 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1663 bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 1664 ptr += sizeof (dl_capab_hcksum_t); 1665 } 1666 1667 /* 1668 * Zero copy 1669 */ 1670 if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 1671 dlsp = (dl_capability_sub_t *)ptr; 1672 1673 dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 1674 dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 1675 ptr += sizeof (dl_capability_sub_t); 1676 1677 bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 1678 zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 1679 zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 1680 1681 dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); 1682 bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 1683 ptr += sizeof (dl_capab_zerocopy_t); 1684 } 1685 1686 ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 1687 qreply(dsp->ds_wq, mp); 1688 } 1689 1690 /* 1691 * DL_CAPABILITY_ACK/DL_ERROR_ACK 1692 */ 1693 static void 1694 proto_capability_enable(dld_str_t *dsp, mblk_t *mp) 1695 { 1696 dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr; 1697 dl_capability_sub_t *sp; 1698 size_t size; 1699 offset_t off; 1700 size_t len; 1701 offset_t end; 1702 1703 dlp->dl_primitive = DL_CAPABILITY_ACK; 1704 1705 off = dlp->dl_sub_offset; 1706 len = dlp->dl_sub_length; 1707 1708 /* 1709 * Walk the list of capabilities to be enabled. 1710 */ 1711 for (end = off + len; off < end; ) { 1712 sp = (dl_capability_sub_t *)(mp->b_rptr + off); 1713 size = sizeof (dl_capability_sub_t) + sp->dl_length; 1714 1715 if (off + size > end || 1716 !IS_P2ALIGNED(off, sizeof (uint32_t))) { 1717 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, 1718 DL_BADPRIM, 0); 1719 return; 1720 } 1721 1722 switch (sp->dl_cap) { 1723 1724 /* 1725 * TCP/IP checksum offload to hardware. 1726 */ 1727 case DL_CAPAB_HCKSUM: { 1728 dl_capab_hcksum_t *hcksump; 1729 dl_capab_hcksum_t hcksum; 1730 1731 ASSERT(dsp->ds_mip->mi_cksum != 0); 1732 1733 hcksump = (dl_capab_hcksum_t *)&sp[1]; 1734 1735 /* 1736 * Copy for alignment. 1737 */ 1738 bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 1739 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1740 bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 1741 break; 1742 } 1743 1744 /* 1745 * IP polling interface. 1746 */ 1747 case DL_CAPAB_POLL: { 1748 dl_capab_poll_t *pollp; 1749 dl_capab_poll_t poll; 1750 1751 pollp = (dl_capab_poll_t *)&sp[1]; 1752 1753 /* 1754 * Copy for alignment. 1755 */ 1756 bcopy(pollp, &poll, sizeof (dl_capab_poll_t)); 1757 1758 switch (poll.poll_flags) { 1759 default: 1760 /*FALLTHRU*/ 1761 case POLL_DISABLE: 1762 proto_poll_disable(dsp); 1763 break; 1764 1765 case POLL_ENABLE: 1766 ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); 1767 1768 /* 1769 * Make sure polling is disabled. 1770 */ 1771 proto_poll_disable(dsp); 1772 1773 /* 1774 * Now attempt enable it. 1775 */ 1776 if (!proto_poll_enable(dsp, &poll)) 1777 break; 1778 1779 bzero(&poll, sizeof (dl_capab_poll_t)); 1780 poll.poll_flags = POLL_ENABLE; 1781 break; 1782 } 1783 1784 dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); 1785 bcopy(&poll, pollp, sizeof (dl_capab_poll_t)); 1786 break; 1787 } 1788 default: 1789 break; 1790 } 1791 1792 off += size; 1793 } 1794 1795 qreply(dsp->ds_wq, mp); 1796 } 1797 1798 /* 1799 * DL_NOTIFY_ACK 1800 */ 1801 static void 1802 proto_notify_ack(dld_str_t *dsp, mblk_t *mp, uint_t enable_set, uint_t ack_set) 1803 { 1804 /* 1805 * Cache the notifications that are being enabled. 1806 */ 1807 dsp->ds_notifications = enable_set; 1808 1809 /* 1810 * The ACK carries all notifications regardless of which set is 1811 * being enabled. 1812 */ 1813 dlnotifyack(dsp->ds_wq, mp, ack_set); 1814 1815 /* 1816 * Solicit DL_NOTIFY_IND messages for each enabled notification. 1817 */ 1818 if (dsp->ds_notifications != 0) 1819 dld_str_notify_ind(dsp); 1820 } 1821