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, dld_str_rx_unitdata, (void *)dsp); 482 483 /* 484 * Bind the channel such that it can receive packets. 485 */ 486 dsp->ds_sap = dlp->dl_sap; 487 err = dls_bind(dsp->ds_dc, dlp->dl_sap); 488 489 proto_bind_ack(dsp, mp, err); 490 return (err == 0); 491 } 492 493 /* 494 * DL_UNBIND_REQ 495 */ 496 /*ARGSUSED*/ 497 static boolean_t 498 proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 499 { 500 ASSERT(PERIM_EXCL(dsp->ds_wq)); 501 502 if (dsp->ds_dlstate != DL_IDLE) { 503 dlerrorack(dsp->ds_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); 504 return (B_FALSE); 505 } 506 507 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { 508 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); 509 return (B_FALSE); 510 } 511 512 dsp->ds_dlstate = DL_UNBIND_PENDING; 513 514 /* 515 * Flush any remaining packets scheduled for transmission. 516 */ 517 flushq(dsp->ds_wq, FLUSHALL); 518 519 /* 520 * Reset the M_DATA handler. 521 */ 522 dld_str_tx_drop(dsp); 523 524 /* 525 * Unbind the channel to stop packets being received. 526 */ 527 dls_unbind(dsp->ds_dc); 528 529 /* 530 * Disable polling mode, if it is enabled. 531 */ 532 proto_poll_disable(dsp); 533 534 /* 535 * Clear the receive callback. 536 */ 537 dls_rx_set(dsp->ds_dc, NULL, NULL); 538 539 /* 540 * Set the mode back to the default (unitdata). 541 */ 542 dsp->ds_mode = DLD_UNITDATA; 543 544 proto_unbind_ack(dsp, mp); 545 return (B_TRUE); 546 } 547 548 /* 549 * DL_PROMISCON_REQ 550 */ 551 static boolean_t 552 proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 553 { 554 dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; 555 int err; 556 557 ASSERT(PERIM_EXCL(dsp->ds_wq)); 558 559 if (dsp->ds_dlstate == DL_UNATTACHED || 560 DL_ACK_PENDING(dsp->ds_dlstate)) { 561 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_OUTSTATE, 0); 562 return (B_FALSE); 563 } 564 565 if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { 566 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); 567 return (B_FALSE); 568 } 569 570 switch (dlp->dl_level) { 571 case DL_PROMISC_SAP: 572 dsp->ds_promisc |= DLS_PROMISC_SAP; 573 break; 574 575 case DL_PROMISC_MULTI: 576 dsp->ds_promisc |= DLS_PROMISC_MULTI; 577 break; 578 579 case DL_PROMISC_PHYS: 580 dsp->ds_promisc |= DLS_PROMISC_PHYS; 581 break; 582 583 default: 584 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 585 0); 586 return (B_FALSE); 587 } 588 589 /* 590 * Adjust channel promiscuity. 591 */ 592 err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 593 proto_promiscon_ack(dsp, mp, err); 594 return (err == 0); 595 } 596 597 /* 598 * DL_PROMISCOFF_REQ 599 */ 600 static boolean_t 601 proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 602 { 603 dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; 604 int err; 605 606 ASSERT(PERIM_EXCL(dsp->ds_wq)); 607 608 if (dsp->ds_dlstate == DL_UNATTACHED || 609 DL_ACK_PENDING(dsp->ds_dlstate)) { 610 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_OUTSTATE, 0); 611 return (B_FALSE); 612 } 613 614 if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { 615 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); 616 return (B_FALSE); 617 } 618 619 switch (dlp->dl_level) { 620 case DL_PROMISC_SAP: 621 if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) 622 goto notenab; 623 624 dsp->ds_promisc &= ~DLS_PROMISC_SAP; 625 break; 626 627 case DL_PROMISC_MULTI: 628 if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) 629 goto notenab; 630 631 dsp->ds_promisc &= ~DLS_PROMISC_MULTI; 632 break; 633 634 case DL_PROMISC_PHYS: 635 if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) 636 goto notenab; 637 638 dsp->ds_promisc &= ~DLS_PROMISC_PHYS; 639 break; 640 641 default: 642 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 643 0); 644 return (B_FALSE); 645 } 646 647 /* 648 * Adjust channel promiscuity. 649 */ 650 err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 651 652 proto_promiscoff_ack(dsp, mp, err); 653 return (err == 0); 654 655 notenab: 656 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); 657 return (B_FALSE); 658 } 659 660 /* 661 * DL_ENABMULTI_REQ 662 */ 663 static boolean_t 664 proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 665 { 666 dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; 667 int err; 668 669 ASSERT(PERIM_EXCL(dsp->ds_wq)); 670 671 if (dsp->ds_dlstate == DL_UNATTACHED || 672 DL_ACK_PENDING(dsp->ds_dlstate)) { 673 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); 674 return (B_FALSE); 675 } 676 677 if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || 678 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 679 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 680 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); 681 return (B_FALSE); 682 } 683 684 err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 685 proto_enabmulti_ack(dsp, mp, err); 686 return (err == 0); 687 } 688 689 /* 690 * DL_DISABMULTI_REQ 691 */ 692 static boolean_t 693 proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 694 { 695 dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; 696 int err; 697 698 ASSERT(PERIM_EXCL(dsp->ds_wq)); 699 700 if (dsp->ds_dlstate == DL_UNATTACHED || 701 DL_ACK_PENDING(dsp->ds_dlstate)) { 702 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_OUTSTATE, 0); 703 return (B_FALSE); 704 } 705 706 if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || 707 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 708 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 709 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); 710 return (B_FALSE); 711 } 712 713 err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 714 proto_disabmulti_ack(dsp, mp, err); 715 return (err == 0); 716 } 717 718 /* 719 * DL_PHYS_ADDR_REQ 720 */ 721 static boolean_t 722 proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 723 { 724 dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; 725 726 if (dsp->ds_dlstate == DL_UNATTACHED || 727 DL_ACK_PENDING(dsp->ds_dlstate)) { 728 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 729 return (B_FALSE); 730 } 731 732 if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { 733 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); 734 return (B_FALSE); 735 } 736 737 if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && 738 dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { 739 dlerrorack(dsp->ds_wq, mp, DL_PHYS_ADDR_REQ, DL_UNSUPPORTED, 0); 740 return (B_FALSE); 741 } 742 743 proto_physaddr_ack(dsp, mp, dlp->dl_addr_type); 744 return (B_TRUE); 745 } 746 747 /* 748 * DL_SET_PHYS_ADDR_REQ 749 */ 750 static boolean_t 751 proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 752 { 753 dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; 754 int err; 755 756 ASSERT(PERIM_EXCL(dsp->ds_wq)); 757 758 if (dsp->ds_dlstate == DL_UNATTACHED || 759 DL_ACK_PENDING(dsp->ds_dlstate)) { 760 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 761 0); 762 return (B_FALSE); 763 } 764 765 if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || 766 !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 767 dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 768 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 769 0); 770 return (B_FALSE); 771 } 772 773 err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); 774 proto_setphysaddr_ack(dsp, mp, err); 775 return (err == 0); 776 } 777 778 /* 779 * DL_UDQOS_REQ 780 */ 781 static boolean_t 782 proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 783 { 784 dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; 785 dl_qos_cl_sel1_t *selp; 786 int off, len; 787 788 ASSERT(PERIM_EXCL(dsp->ds_wq)); 789 790 off = dlp->dl_qos_offset; 791 len = dlp->dl_qos_length; 792 793 if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { 794 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADPRIM, 0); 795 return (B_FALSE); 796 } 797 798 selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); 799 if (selp->dl_qos_type != DL_QOS_CL_SEL1) { 800 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSTYPE, 0); 801 return (B_FALSE); 802 } 803 804 if (dsp->ds_vid == VLAN_ID_NONE || 805 selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || 806 selp->dl_priority < 0) { 807 dlerrorack(dsp->ds_wq, mp, DL_UDQOS_REQ, DL_BADQOSPARAM, 0); 808 return (B_FALSE); 809 } 810 811 dsp->ds_pri = selp->dl_priority; 812 proto_udqos_ack(dsp, mp); 813 return (B_TRUE); 814 } 815 816 /* 817 * DL_CAPABILITY_REQ 818 */ 819 /*ARGSUSED*/ 820 static boolean_t 821 proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 822 { 823 dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; 824 825 if (dsp->ds_dlstate == DL_UNATTACHED || 826 DL_ACK_PENDING(dsp->ds_dlstate)) { 827 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_OUTSTATE, 828 0); 829 return (B_FALSE); 830 } 831 832 if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 833 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); 834 return (B_FALSE); 835 } 836 837 /* 838 * This request is overloaded. If there are no requested capabilities 839 * then we just want to acknowledge with all the capabilities we 840 * support. Otherwise we enable the set of capabilities requested. 841 */ 842 if (dlp->dl_sub_length == 0) { 843 proto_capability_ack(dsp, mp); 844 return (B_TRUE); 845 } 846 847 if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 848 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_BADPRIM, 0); 849 return (B_FALSE); 850 } 851 852 proto_capability_enable(dsp, mp); 853 return (B_TRUE); 854 } 855 856 /* 857 * DL_NOTIFY_REQ 858 */ 859 static boolean_t 860 proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 861 { 862 dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; 863 uint_t notifications = 864 DL_NOTE_PROMISC_ON_PHYS | 865 DL_NOTE_PROMISC_OFF_PHYS | 866 DL_NOTE_PHYS_ADDR | 867 DL_NOTE_LINK_UP | 868 DL_NOTE_LINK_DOWN | 869 DL_NOTE_CAPAB_RENEG; 870 871 if (dsp->ds_dlstate == DL_UNATTACHED || 872 DL_ACK_PENDING(dsp->ds_dlstate)) { 873 dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_OUTSTATE, 874 0); 875 return (B_FALSE); 876 } 877 878 if (MBLKL(mp) < sizeof (dl_notify_req_t)) { 879 dlerrorack(dsp->ds_wq, mp, DL_NOTIFY_REQ, DL_BADPRIM, 0); 880 return (B_FALSE); 881 } 882 883 if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) 884 notifications |= DL_NOTE_SPEED; 885 886 proto_notify_ack(dsp, mp, dlp->dl_notifications & notifications, 887 notifications); 888 return (B_TRUE); 889 } 890 891 /* 892 * DL_UINTDATA_REQ 893 */ 894 static boolean_t 895 proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 896 { 897 queue_t *q = dsp->ds_wq; 898 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)udlp; 899 off_t off; 900 size_t len; 901 size_t size; 902 const uint8_t *addr; 903 uint16_t sap; 904 uint_t addr_length; 905 mblk_t *bp; 906 mblk_t *cont; 907 uint32_t start; 908 uint32_t stuff; 909 uint32_t end; 910 uint32_t value; 911 uint32_t flags; 912 913 if (dsp->ds_dlstate != DL_IDLE) { 914 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); 915 return (B_FALSE); 916 } 917 918 if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { 919 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); 920 return (B_FALSE); 921 } 922 923 off = dlp->dl_dest_addr_offset; 924 len = dlp->dl_dest_addr_length; 925 926 if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { 927 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0); 928 return (B_FALSE); 929 } 930 931 addr_length = dsp->ds_mip->mi_addr_length; 932 if (len != addr_length + sizeof (uint16_t)) 933 goto badaddr; 934 935 addr = mp->b_rptr + off; 936 sap = *(uint16_t *)(mp->b_rptr + off + addr_length); 937 938 /* 939 * Check the length of the packet and the block types. 940 */ 941 size = 0; 942 cont = mp->b_cont; 943 for (bp = cont; bp != NULL; bp = bp->b_cont) { 944 if (DB_TYPE(bp) != M_DATA) 945 goto baddata; 946 947 size += MBLKL(bp); 948 } 949 950 if (size > dsp->ds_mip->mi_sdu_max) 951 goto baddata; 952 953 /* 954 * Build a packet header. 955 */ 956 if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) 957 goto badaddr; 958 959 /* 960 * We no longer need the M_PROTO header, so free it. 961 */ 962 freeb(mp); 963 964 /* 965 * Transfer the checksum offload information if it is present. 966 */ 967 hcksum_retrieve(cont, NULL, NULL, &start, &stuff, &end, &value, 968 &flags); 969 (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 970 0); 971 972 /* 973 * Link the payload onto the new header. 974 */ 975 ASSERT(bp->b_cont == NULL); 976 bp->b_cont = cont; 977 978 /* 979 * If something is already queued then we must queue to avoid 980 * re-ordering. 981 */ 982 if (q->q_first != NULL) { 983 (void) putq(q, bp); 984 return (B_TRUE); 985 } 986 987 /* 988 * Attempt to transmit the packet. 989 */ 990 if ((mp = dls_tx(dsp->ds_dc, bp)) != NULL) { 991 noenable(q); 992 while ((bp = mp) != NULL) { 993 mp = mp->b_next; 994 bp->b_next = NULL; 995 (void) putq(q, bp); 996 } 997 } 998 return (B_TRUE); 999 1000 badaddr: 1001 dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADADDR, 0); 1002 return (B_FALSE); 1003 1004 baddata: 1005 dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); 1006 return (B_FALSE); 1007 } 1008 1009 /* 1010 * DL_PASSIVE_REQ 1011 */ 1012 /* ARGSUSED */ 1013 static boolean_t 1014 proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1015 { 1016 ASSERT(PERIM_EXCL(dsp->ds_wq)); 1017 1018 /* 1019 * If we've already become active by issuing an active primitive, 1020 * then it's too late to try to become passive. 1021 */ 1022 if (dsp->ds_passivestate == DLD_ACTIVE) { 1023 dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_OUTSTATE, 0); 1024 return (B_FALSE); 1025 } 1026 1027 if (MBLKL(mp) < sizeof (dl_passive_req_t)) { 1028 dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, DL_BADPRIM, 0); 1029 return (B_FALSE); 1030 } 1031 1032 dsp->ds_passivestate = DLD_PASSIVE; 1033 dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); 1034 return (B_TRUE); 1035 } 1036 1037 /* 1038 * Catch-all handler. 1039 */ 1040 static boolean_t 1041 proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) 1042 { 1043 dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 1044 return (B_FALSE); 1045 } 1046 1047 typedef struct dl_info_ack_wrapper { 1048 dl_info_ack_t dl_info; 1049 uint8_t dl_addr[MAXADDRLEN + sizeof (uint16_t)]; 1050 uint8_t dl_brdcst_addr[MAXADDRLEN]; 1051 dl_qos_cl_range1_t dl_qos_range1; 1052 dl_qos_cl_sel1_t dl_qos_sel1; 1053 } dl_info_ack_wrapper_t; 1054 1055 #define NEG(x) -(x) 1056 1057 /* 1058 * DL_INFO_ACK 1059 */ 1060 static void 1061 proto_info_ack(dld_str_t *dsp, mblk_t *mp) 1062 { 1063 dl_info_ack_wrapper_t *dlwp; 1064 dl_info_ack_t *dlp; 1065 dl_qos_cl_sel1_t *selp; 1066 dl_qos_cl_range1_t *rangep; 1067 uint8_t *addr; 1068 uint8_t *brdcst_addr; 1069 dld_node_t *dnp; 1070 uint_t addr_length; 1071 uint_t sap_length; 1072 1073 /* 1074 * Swap the request message for one large enough to contain the 1075 * wrapper structure defined above. 1076 */ 1077 if ((mp = mexchange(dsp->ds_wq, mp, sizeof (dl_info_ack_wrapper_t), 1078 M_PCPROTO, 0)) == NULL) 1079 return; 1080 1081 bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); 1082 dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; 1083 1084 dlp = &(dlwp->dl_info); 1085 ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); 1086 1087 dlp->dl_primitive = DL_INFO_ACK; 1088 1089 /* 1090 * Set up the sub-structure pointers. 1091 */ 1092 addr = dlwp->dl_addr; 1093 brdcst_addr = dlwp->dl_brdcst_addr; 1094 rangep = &(dlwp->dl_qos_range1); 1095 selp = &(dlwp->dl_qos_sel1); 1096 1097 /* 1098 * This driver supports only version 2 connectionless DLPI provider 1099 * nodes. 1100 */ 1101 dlp->dl_service_mode = DL_CLDLS; 1102 dlp->dl_version = DL_VERSION_2; 1103 1104 /* 1105 * Set the style of the provider from the dld_node_t structure 1106 * representing the dev_t that was opened. 1107 */ 1108 dnp = dsp->ds_dnp; 1109 dlp->dl_provider_style = dnp->dn_style; 1110 ASSERT(dlp->dl_provider_style == DL_STYLE1 || 1111 dlp->dl_provider_style == DL_STYLE2); 1112 1113 /* 1114 * Set the current DLPI state. 1115 */ 1116 dlp->dl_current_state = dsp->ds_dlstate; 1117 1118 /* 1119 * Gratuitously set the media type. This is because the Cisco VPN 3000 1120 * module assumes that the media type is known prior to DL_ATTACH_REQ 1121 * being completed. 1122 */ 1123 dlp->dl_mac_type = DL_ETHER; 1124 1125 /* 1126 * If the stream is not at least attached then we're done. 1127 */ 1128 if (dsp->ds_dlstate == DL_UNATTACHED || 1129 dsp->ds_dlstate == DL_ATTACH_PENDING || 1130 dsp->ds_dlstate == DL_DETACH_PENDING) 1131 goto done; 1132 1133 /* 1134 * Set the media type (properly this time). 1135 */ 1136 dlp->dl_mac_type = dsp->ds_mip->mi_media; 1137 1138 /* 1139 * Set the DLSAP length. We only support 16 bit values and they 1140 * appear after the MAC address portion of DLSAP addresses. 1141 */ 1142 sap_length = sizeof (uint16_t); 1143 dlp->dl_sap_length = NEG(sap_length); 1144 1145 /* 1146 * Set the minimum and maximum payload sizes. 1147 */ 1148 dlp->dl_min_sdu = dsp->ds_mip->mi_sdu_min; 1149 dlp->dl_max_sdu = dsp->ds_mip->mi_sdu_max; 1150 1151 addr_length = dsp->ds_mip->mi_addr_length; 1152 ASSERT(addr_length != 0); 1153 1154 /* 1155 * Copy in the media broadcast address. 1156 */ 1157 dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; 1158 bcopy(dsp->ds_mip->mi_brdcst_addr, brdcst_addr, addr_length); 1159 dlp->dl_brdcst_addr_length = addr_length; 1160 1161 /* 1162 * We only support QoS information for VLAN interfaces. 1163 */ 1164 if (dsp->ds_vid != VLAN_ID_NONE) { 1165 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; 1166 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); 1167 1168 rangep->dl_qos_type = DL_QOS_CL_RANGE1; 1169 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; 1170 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; 1171 rangep->dl_protection.dl_min = DL_UNKNOWN; 1172 rangep->dl_protection.dl_max = DL_UNKNOWN; 1173 rangep->dl_residual_error = DL_UNKNOWN; 1174 1175 /* 1176 * Specify the supported range of priorities. 1177 */ 1178 rangep->dl_priority.dl_min = 0; 1179 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; 1180 1181 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; 1182 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); 1183 1184 selp->dl_qos_type = DL_QOS_CL_SEL1; 1185 selp->dl_trans_delay = DL_UNKNOWN; 1186 selp->dl_protection = DL_UNKNOWN; 1187 selp->dl_residual_error = DL_UNKNOWN; 1188 1189 /* 1190 * Specify the current priority (which can be changed by 1191 * the DL_UDQOS_REQ primitive). 1192 */ 1193 selp->dl_priority = dsp->ds_pri; 1194 } else { 1195 /* 1196 * Shorten the buffer to lose the unused QoS information 1197 * structures. This is to work around a bug in the Cisco VPN 1198 * 3000 module. 1199 */ 1200 mp->b_wptr = (uint8_t *)rangep; 1201 } 1202 1203 dlp->dl_addr_length = addr_length + sizeof (uint16_t); 1204 if (dsp->ds_dlstate == DL_IDLE) { 1205 /* 1206 * The stream is bound. Therefore we can formulate a valid 1207 * DLSAP address. 1208 */ 1209 dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; 1210 bcopy(dsp->ds_curr_addr, addr, addr_length); 1211 *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 1212 } 1213 1214 done: 1215 ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); 1216 ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, 1217 dlp->dl_qos_range_length != 0)); 1218 ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); 1219 ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, 1220 dlp->dl_brdcst_addr_length != 0)); 1221 1222 qreply(dsp->ds_wq, mp); 1223 } 1224 1225 /* 1226 * DL_OK_ACK/DL_ERROR_ACK 1227 */ 1228 static void 1229 proto_attach_ack(dld_str_t *dsp, mblk_t *mp, int err) 1230 { 1231 int dl_err; 1232 1233 if (err != 0) 1234 goto failed; 1235 1236 dsp->ds_dlstate = DL_UNBOUND; 1237 dlokack(dsp->ds_wq, mp, DL_ATTACH_REQ); 1238 return; 1239 1240 failed: 1241 switch (err) { 1242 case ENOENT: 1243 dl_err = DL_BADPPA; 1244 err = 0; 1245 break; 1246 1247 default: 1248 dl_err = DL_SYSERR; 1249 break; 1250 } 1251 1252 dsp->ds_dlstate = DL_UNATTACHED; 1253 dlerrorack(dsp->ds_wq, mp, DL_ATTACH_REQ, dl_err, err); 1254 } 1255 1256 /* 1257 * DL_OK_ACK 1258 */ 1259 static void 1260 proto_detach_ack(dld_str_t *dsp, mblk_t *mp) 1261 { 1262 dsp->ds_dlstate = DL_UNATTACHED; 1263 dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); 1264 } 1265 1266 /* 1267 * DL_BIND_ACK/DL_ERROR_ACK 1268 */ 1269 static void 1270 proto_bind_ack(dld_str_t *dsp, mblk_t *mp, int err) 1271 { 1272 uint8_t addr[MAXADDRLEN]; 1273 uint_t addr_length; 1274 int dl_err; 1275 1276 if (err != 0) 1277 goto failed; 1278 1279 /* 1280 * Copy in MAC address. 1281 */ 1282 addr_length = dsp->ds_mip->mi_addr_length; 1283 bcopy(dsp->ds_curr_addr, addr, addr_length); 1284 1285 /* 1286 * Copy in the DLSAP. 1287 */ 1288 *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 1289 addr_length += sizeof (uint16_t); 1290 1291 dsp->ds_dlstate = DL_IDLE; 1292 dlbindack(dsp->ds_wq, mp, dsp->ds_sap, (void *)addr, addr_length, 0, 1293 0); 1294 return; 1295 1296 failed: 1297 switch (err) { 1298 case EINVAL: 1299 dl_err = DL_BADADDR; 1300 err = 0; 1301 break; 1302 1303 default: 1304 dl_err = DL_SYSERR; 1305 break; 1306 } 1307 1308 dsp->ds_dlstate = DL_UNBOUND; 1309 dlerrorack(dsp->ds_wq, mp, DL_BIND_REQ, dl_err, err); 1310 } 1311 1312 /* 1313 * DL_OK_ACK 1314 */ 1315 static void 1316 proto_unbind_ack(dld_str_t *dsp, mblk_t *mp) 1317 { 1318 dsp->ds_dlstate = DL_UNBOUND; 1319 dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ); 1320 } 1321 1322 /* 1323 * DL_OK_ACK/DL_ERROR_ACK 1324 */ 1325 static void 1326 proto_promiscon_ack(dld_str_t *dsp, mblk_t *mp, int err) 1327 { 1328 if (err != 0) 1329 goto failed; 1330 1331 dlokack(dsp->ds_wq, mp, DL_PROMISCON_REQ); 1332 return; 1333 1334 failed: 1335 dlerrorack(dsp->ds_wq, mp, DL_PROMISCON_REQ, DL_SYSERR, err); 1336 } 1337 1338 /* 1339 * DL_OK_ACK/DL_ERROR_ACK 1340 */ 1341 static void 1342 proto_promiscoff_ack(dld_str_t *dsp, mblk_t *mp, int err) 1343 { 1344 if (err != 0) 1345 goto failed; 1346 1347 dlokack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ); 1348 return; 1349 1350 failed: 1351 dlerrorack(dsp->ds_wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, err); 1352 } 1353 1354 /* 1355 * DL_OK_ACK/DL_ERROR_ACK 1356 */ 1357 static void 1358 proto_enabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) 1359 { 1360 int dl_err; 1361 1362 if (err != 0) 1363 goto failed; 1364 1365 dlokack(dsp->ds_wq, mp, DL_ENABMULTI_REQ); 1366 return; 1367 1368 failed: 1369 switch (err) { 1370 case EINVAL: 1371 dl_err = DL_BADADDR; 1372 err = 0; 1373 break; 1374 1375 case ENOSPC: 1376 dl_err = DL_TOOMANY; 1377 err = 0; 1378 break; 1379 1380 default: 1381 dl_err = DL_SYSERR; 1382 break; 1383 } 1384 1385 dlerrorack(dsp->ds_wq, mp, DL_ENABMULTI_REQ, dl_err, err); 1386 } 1387 1388 /* 1389 * DL_OK_ACK/DL_ERROR_ACK 1390 */ 1391 static void 1392 proto_disabmulti_ack(dld_str_t *dsp, mblk_t *mp, int err) 1393 { 1394 int dl_err; 1395 1396 if (err != 0) 1397 goto failed; 1398 1399 dlokack(dsp->ds_wq, mp, DL_DISABMULTI_REQ); 1400 return; 1401 1402 failed: 1403 switch (err) { 1404 case EINVAL: 1405 dl_err = DL_BADADDR; 1406 err = 0; 1407 break; 1408 1409 case ENOENT: 1410 dl_err = DL_NOTENAB; 1411 err = 0; 1412 break; 1413 1414 default: 1415 dl_err = DL_SYSERR; 1416 break; 1417 } 1418 1419 dlerrorack(dsp->ds_wq, mp, DL_DISABMULTI_REQ, dl_err, err); 1420 } 1421 1422 /* 1423 * DL_PHYS_ADDR_ACK 1424 */ 1425 static void 1426 proto_physaddr_ack(dld_str_t *dsp, mblk_t *mp, t_uscalar_t type) 1427 { 1428 uint_t addr_length; 1429 1430 /* 1431 * Copy in the address. 1432 */ 1433 addr_length = dsp->ds_mip->mi_addr_length; 1434 dlphysaddrack(dsp->ds_wq, mp, (type == DL_CURR_PHYS_ADDR) ? 1435 dsp->ds_curr_addr : dsp->ds_fact_addr, addr_length); 1436 } 1437 1438 /* 1439 * DL_OK_ACK/DL_ERROR_ACK 1440 */ 1441 static void 1442 proto_setphysaddr_ack(dld_str_t *dsp, mblk_t *mp, int err) 1443 { 1444 int dl_err; 1445 1446 if (err != 0) 1447 goto failed; 1448 1449 dlokack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ); 1450 return; 1451 1452 failed: 1453 switch (err) { 1454 case EINVAL: 1455 dl_err = DL_BADADDR; 1456 err = 0; 1457 break; 1458 1459 default: 1460 dl_err = DL_SYSERR; 1461 break; 1462 } 1463 1464 dlerrorack(dsp->ds_wq, mp, DL_SET_PHYS_ADDR_REQ, dl_err, err); 1465 } 1466 1467 /* 1468 * DL_OK_ACK 1469 */ 1470 static void 1471 proto_udqos_ack(dld_str_t *dsp, mblk_t *mp) 1472 { 1473 dlokack(dsp->ds_wq, mp, DL_UDQOS_REQ); 1474 } 1475 1476 static void 1477 proto_poll_disable(dld_str_t *dsp) 1478 { 1479 mac_handle_t mh; 1480 1481 if (!dsp->ds_polling) 1482 return; 1483 1484 /* 1485 * It should be impossible to enable raw mode if polling is turned on. 1486 */ 1487 ASSERT(dsp->ds_mode != DLD_RAW); 1488 1489 /* 1490 * Reset the resource_add callback. 1491 */ 1492 mh = dls_mac(dsp->ds_dc); 1493 mac_resource_set(mh, NULL, NULL); 1494 1495 /* 1496 * Set receive function back to default. 1497 */ 1498 dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? 1499 dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp); 1500 1501 /* 1502 * Note that polling is disabled. 1503 */ 1504 dsp->ds_polling = B_FALSE; 1505 } 1506 1507 static boolean_t 1508 proto_poll_enable(dld_str_t *dsp, dl_capab_poll_t *pollp) 1509 { 1510 mac_handle_t mh; 1511 1512 ASSERT(!dsp->ds_polling); 1513 1514 /* 1515 * We cannot enable polling if raw mode 1516 * has been enabled. 1517 */ 1518 if (dsp->ds_mode == DLD_RAW) 1519 return (B_FALSE); 1520 1521 mh = dls_mac(dsp->ds_dc); 1522 1523 /* 1524 * Register resources. 1525 */ 1526 mac_resource_set(mh, (mac_resource_add_t)pollp->poll_ring_add, 1527 (void *)pollp->poll_rx_handle); 1528 mac_resources(mh); 1529 1530 /* 1531 * Set the receive function. 1532 */ 1533 dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->poll_rx, 1534 (void *)pollp->poll_rx_handle); 1535 1536 /* 1537 * Note that polling is enabled. This prevents further DLIOCHDRINFO 1538 * ioctls from overwriting the receive function pointer. 1539 */ 1540 dsp->ds_polling = B_TRUE; 1541 return (B_TRUE); 1542 } 1543 1544 /* 1545 * DL_CAPABILITY_ACK/DL_ERROR_ACK 1546 */ 1547 static void 1548 proto_capability_ack(dld_str_t *dsp, mblk_t *mp) 1549 { 1550 dl_capability_ack_t *dlap; 1551 dl_capability_sub_t *dlsp; 1552 size_t subsize; 1553 dl_capab_poll_t poll; 1554 dl_capab_hcksum_t hcksum; 1555 dl_capab_zerocopy_t zcopy; 1556 uint8_t *ptr; 1557 uint32_t cksum; 1558 boolean_t poll_cap; 1559 1560 /* 1561 * Initially assume no capabilities. 1562 */ 1563 subsize = 0; 1564 1565 /* 1566 * Check if polling can be enabled on this interface. 1567 * If advertising DL_CAPAB_POLL has not been explicitly disabled 1568 * then reserve space for that capability. 1569 */ 1570 poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) && 1571 !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE)); 1572 if (poll_cap) { 1573 subsize += sizeof (dl_capability_sub_t) + 1574 sizeof (dl_capab_poll_t); 1575 } 1576 1577 /* 1578 * If the MAC interface supports checksum offload then reserve 1579 * space for the DL_CAPAB_HCKSUM capability. 1580 */ 1581 if ((cksum = dsp->ds_mip->mi_cksum) != 0) { 1582 subsize += sizeof (dl_capability_sub_t) + 1583 sizeof (dl_capab_hcksum_t); 1584 } 1585 1586 /* 1587 * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then 1588 * reserve space for it. 1589 */ 1590 if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 1591 subsize += sizeof (dl_capability_sub_t) + 1592 sizeof (dl_capab_zerocopy_t); 1593 } 1594 1595 /* 1596 * If there are no capabilities to advertise, send a DL_ERROR_ACK. 1597 */ 1598 if (subsize == 0) { 1599 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 1600 0); 1601 return; 1602 } 1603 1604 if ((mp = mexchange(dsp->ds_wq, mp, 1605 sizeof (dl_capability_ack_t) + subsize, M_PROTO, 0)) == NULL) 1606 return; 1607 1608 bzero(mp->b_rptr, sizeof (dl_capability_ack_t)); 1609 dlap = (dl_capability_ack_t *)mp->b_rptr; 1610 dlap->dl_primitive = DL_CAPABILITY_ACK; 1611 dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 1612 dlap->dl_sub_length = subsize; 1613 ptr = (uint8_t *)&dlap[1]; 1614 1615 /* 1616 * IP polling interface. 1617 */ 1618 if (poll_cap) { 1619 /* 1620 * Attempt to disable just in case this is a re-negotiation. 1621 */ 1622 proto_poll_disable(dsp); 1623 1624 dlsp = (dl_capability_sub_t *)ptr; 1625 1626 dlsp->dl_cap = DL_CAPAB_POLL; 1627 dlsp->dl_length = sizeof (dl_capab_poll_t); 1628 ptr += sizeof (dl_capability_sub_t); 1629 1630 bzero(&poll, sizeof (dl_capab_poll_t)); 1631 poll.poll_version = POLL_VERSION_1; 1632 poll.poll_flags = POLL_CAPABLE; 1633 poll.poll_tx_handle = (uintptr_t)dsp->ds_dc; 1634 poll.poll_tx = (uintptr_t)dls_tx; 1635 1636 dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); 1637 bcopy(&poll, ptr, sizeof (dl_capab_poll_t)); 1638 ptr += sizeof (dl_capab_poll_t); 1639 } 1640 1641 /* 1642 * TCP/IP checksum offload. 1643 */ 1644 if (cksum != 0) { 1645 dlsp = (dl_capability_sub_t *)ptr; 1646 1647 dlsp->dl_cap = DL_CAPAB_HCKSUM; 1648 dlsp->dl_length = sizeof (dl_capab_hcksum_t); 1649 ptr += sizeof (dl_capability_sub_t); 1650 1651 bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 1652 hcksum.hcksum_version = HCKSUM_VERSION_1; 1653 hcksum.hcksum_txflags = cksum; 1654 1655 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1656 bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 1657 ptr += sizeof (dl_capab_hcksum_t); 1658 } 1659 1660 /* 1661 * Zero copy 1662 */ 1663 if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 1664 dlsp = (dl_capability_sub_t *)ptr; 1665 1666 dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 1667 dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 1668 ptr += sizeof (dl_capability_sub_t); 1669 1670 bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 1671 zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 1672 zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 1673 1674 dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); 1675 bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 1676 ptr += sizeof (dl_capab_zerocopy_t); 1677 } 1678 1679 ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 1680 qreply(dsp->ds_wq, mp); 1681 } 1682 1683 /* 1684 * DL_CAPABILITY_ACK/DL_ERROR_ACK 1685 */ 1686 static void 1687 proto_capability_enable(dld_str_t *dsp, mblk_t *mp) 1688 { 1689 dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr; 1690 dl_capability_sub_t *sp; 1691 size_t size; 1692 offset_t off; 1693 size_t len; 1694 offset_t end; 1695 1696 dlp->dl_primitive = DL_CAPABILITY_ACK; 1697 1698 off = dlp->dl_sub_offset; 1699 len = dlp->dl_sub_length; 1700 1701 /* 1702 * Walk the list of capabilities to be enabled. 1703 */ 1704 for (end = off + len; off < end; ) { 1705 sp = (dl_capability_sub_t *)(mp->b_rptr + off); 1706 size = sizeof (dl_capability_sub_t) + sp->dl_length; 1707 1708 if (off + size > end || 1709 !IS_P2ALIGNED(off, sizeof (uint32_t))) { 1710 dlerrorack(dsp->ds_wq, mp, DL_CAPABILITY_REQ, 1711 DL_BADPRIM, 0); 1712 return; 1713 } 1714 1715 switch (sp->dl_cap) { 1716 1717 /* 1718 * TCP/IP checksum offload to hardware. 1719 */ 1720 case DL_CAPAB_HCKSUM: { 1721 dl_capab_hcksum_t *hcksump; 1722 dl_capab_hcksum_t hcksum; 1723 1724 ASSERT(dsp->ds_mip->mi_cksum != 0); 1725 1726 hcksump = (dl_capab_hcksum_t *)&sp[1]; 1727 1728 /* 1729 * Copy for alignment. 1730 */ 1731 bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 1732 dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1733 bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 1734 break; 1735 } 1736 1737 /* 1738 * IP polling interface. 1739 */ 1740 case DL_CAPAB_POLL: { 1741 dl_capab_poll_t *pollp; 1742 dl_capab_poll_t poll; 1743 1744 pollp = (dl_capab_poll_t *)&sp[1]; 1745 1746 /* 1747 * Copy for alignment. 1748 */ 1749 bcopy(pollp, &poll, sizeof (dl_capab_poll_t)); 1750 1751 switch (poll.poll_flags) { 1752 default: 1753 /*FALLTHRU*/ 1754 case POLL_DISABLE: 1755 proto_poll_disable(dsp); 1756 break; 1757 1758 case POLL_ENABLE: 1759 ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); 1760 1761 /* 1762 * Make sure polling is disabled. 1763 */ 1764 proto_poll_disable(dsp); 1765 1766 /* 1767 * Now attempt enable it. 1768 */ 1769 if (!proto_poll_enable(dsp, &poll)) 1770 break; 1771 1772 bzero(&poll, sizeof (dl_capab_poll_t)); 1773 poll.poll_flags = POLL_ENABLE; 1774 break; 1775 } 1776 1777 dlcapabsetqid(&(poll.poll_mid), dsp->ds_rq); 1778 bcopy(&poll, pollp, sizeof (dl_capab_poll_t)); 1779 break; 1780 } 1781 default: 1782 break; 1783 } 1784 1785 off += size; 1786 } 1787 1788 qreply(dsp->ds_wq, mp); 1789 } 1790 1791 /* 1792 * DL_NOTIFY_ACK 1793 */ 1794 static void 1795 proto_notify_ack(dld_str_t *dsp, mblk_t *mp, uint_t enable_set, uint_t ack_set) 1796 { 1797 /* 1798 * Cache the notifications that are being enabled. 1799 */ 1800 dsp->ds_notifications = enable_set; 1801 1802 /* 1803 * The ACK carries all notifications regardless of which set is 1804 * being enabled. 1805 */ 1806 dlnotifyack(dsp->ds_wq, mp, ack_set); 1807 1808 /* 1809 * Solicit DL_NOTIFY_IND messages for each enabled notification. 1810 */ 1811 if (dsp->ds_notifications != 0) 1812 dld_str_notify_ind(dsp); 1813 } 1814