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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Common Sun DLPI routines. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/sysmacros.h> 32 #include <sys/byteorder.h> 33 #include <sys/stream.h> 34 #include <sys/strsun.h> 35 #include <sys/dlpi.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/sunldi.h> 39 #include <sys/cmn_err.h> 40 41 void 42 dlbindack( 43 queue_t *wq, 44 mblk_t *mp, 45 t_scalar_t sap, 46 const void *addrp, 47 t_uscalar_t addrlen, 48 t_uscalar_t maxconind, 49 t_uscalar_t xidtest) 50 { 51 union DL_primitives *dlp; 52 size_t size; 53 54 size = sizeof (dl_bind_ack_t) + addrlen; 55 if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL) 56 return; 57 58 dlp = (union DL_primitives *)mp->b_rptr; 59 dlp->bind_ack.dl_sap = sap; 60 dlp->bind_ack.dl_addr_length = addrlen; 61 dlp->bind_ack.dl_addr_offset = sizeof (dl_bind_ack_t); 62 dlp->bind_ack.dl_max_conind = maxconind; 63 dlp->bind_ack.dl_xidtest_flg = xidtest; 64 if (addrlen != 0) 65 bcopy(addrp, mp->b_rptr + sizeof (dl_bind_ack_t), addrlen); 66 qreply(wq, mp); 67 } 68 69 void 70 dlokack( 71 queue_t *wq, 72 mblk_t *mp, 73 t_uscalar_t correct_primitive) 74 { 75 union DL_primitives *dlp; 76 77 if ((mp = mexchange(wq, mp, sizeof (dl_ok_ack_t), M_PCPROTO, 78 DL_OK_ACK)) == NULL) 79 return; 80 dlp = (union DL_primitives *)mp->b_rptr; 81 dlp->ok_ack.dl_correct_primitive = correct_primitive; 82 qreply(wq, mp); 83 } 84 85 void 86 dlerrorack( 87 queue_t *wq, 88 mblk_t *mp, 89 t_uscalar_t error_primitive, 90 t_uscalar_t error, 91 t_uscalar_t unix_errno) 92 { 93 union DL_primitives *dlp; 94 95 if ((mp = mexchange(wq, mp, sizeof (dl_error_ack_t), M_PCPROTO, 96 DL_ERROR_ACK)) == NULL) 97 return; 98 dlp = (union DL_primitives *)mp->b_rptr; 99 dlp->error_ack.dl_error_primitive = error_primitive; 100 dlp->error_ack.dl_errno = error; 101 dlp->error_ack.dl_unix_errno = unix_errno; 102 qreply(wq, mp); 103 } 104 105 void 106 dluderrorind( 107 queue_t *wq, 108 mblk_t *mp, 109 const void *addrp, 110 t_uscalar_t addrlen, 111 t_uscalar_t error, 112 t_uscalar_t unix_errno) 113 { 114 union DL_primitives *dlp; 115 size_t size; 116 117 size = sizeof (dl_uderror_ind_t) + addrlen; 118 if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_UDERROR_IND)) == NULL) 119 return; 120 121 dlp = (union DL_primitives *)mp->b_rptr; 122 dlp->uderror_ind.dl_dest_addr_length = addrlen; 123 dlp->uderror_ind.dl_dest_addr_offset = sizeof (dl_uderror_ind_t); 124 dlp->uderror_ind.dl_unix_errno = unix_errno; 125 dlp->uderror_ind.dl_errno = error; 126 if (addrlen != 0) 127 bcopy(addrp, mp->b_rptr + sizeof (dl_uderror_ind_t), addrlen); 128 qreply(wq, mp); 129 } 130 131 void 132 dlphysaddrack( 133 queue_t *wq, 134 mblk_t *mp, 135 const void *addrp, 136 t_uscalar_t len) 137 { 138 union DL_primitives *dlp; 139 size_t size; 140 141 size = sizeof (dl_phys_addr_ack_t) + len; 142 if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_PHYS_ADDR_ACK)) == NULL) 143 return; 144 dlp = (union DL_primitives *)mp->b_rptr; 145 dlp->physaddr_ack.dl_addr_length = len; 146 dlp->physaddr_ack.dl_addr_offset = sizeof (dl_phys_addr_ack_t); 147 if (len != 0) 148 bcopy(addrp, mp->b_rptr + sizeof (dl_phys_addr_ack_t), len); 149 qreply(wq, mp); 150 } 151 152 void 153 dlcapabsetqid(dl_mid_t *idp, const queue_t *q) 154 { 155 #ifndef _LP64 156 idp->mid[0] = (t_uscalar_t)q; 157 #else 158 idp->mid[0] = (t_uscalar_t)BMASK_32((uint64_t)q); 159 idp->mid[1] = (t_uscalar_t)BMASK_32(((uint64_t)q) >> 32); 160 #endif 161 } 162 163 boolean_t 164 dlcapabcheckqid(const dl_mid_t *idp, const queue_t *q) 165 { 166 #ifndef _LP64 167 return ((queue_t *)(idp->mid[0]) == q); 168 #else 169 return ((queue_t *) 170 ((uint64_t)idp->mid[0] | ((uint64_t)idp->mid[1] << 32)) == q); 171 #endif 172 } 173 174 void 175 dlnotifyack( 176 queue_t *wq, 177 mblk_t *mp, 178 uint32_t notifications) 179 { 180 union DL_primitives *dlp; 181 182 if ((mp = mexchange(wq, mp, sizeof (dl_notify_ack_t), M_PROTO, 183 DL_NOTIFY_ACK)) == NULL) 184 return; 185 dlp = (union DL_primitives *)mp->b_rptr; 186 dlp->notify_ack.dl_notifications = notifications; 187 qreply(wq, mp); 188 } 189 190 static int 191 dl_op(ldi_handle_t lh, mblk_t **mpp, t_uscalar_t expprim, size_t minlen, 192 dl_error_ack_t *dleap, timestruc_t *tvp) 193 { 194 int err; 195 size_t len; 196 mblk_t *mp = *mpp; 197 t_uscalar_t reqprim, ackprim, ackreqprim; 198 union DL_primitives *dlp; 199 200 reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 201 202 (void) ldi_putmsg(lh, mp); 203 204 switch (err = ldi_getmsg(lh, &mp, tvp)) { 205 case 0: 206 break; 207 case ETIME: 208 cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s", 209 dl_primstr(reqprim), dl_primstr(expprim)); 210 return (ETIME); 211 default: 212 cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d", 213 dl_primstr(expprim), err); 214 return (err); 215 } 216 217 len = MBLKL(mp); 218 if (len < sizeof (t_uscalar_t)) { 219 cmn_err(CE_NOTE, "!dl_op: received runt DLPI message"); 220 freemsg(mp); 221 return (EBADMSG); 222 } 223 224 dlp = (union DL_primitives *)mp->b_rptr; 225 ackprim = dlp->dl_primitive; 226 227 if (ackprim == expprim) { 228 if (len < minlen) 229 goto runt; 230 231 if (ackprim == DL_OK_ACK) { 232 if (dlp->ok_ack.dl_correct_primitive != reqprim) { 233 ackreqprim = dlp->ok_ack.dl_correct_primitive; 234 goto mixup; 235 } 236 } 237 *mpp = mp; 238 return (0); 239 } 240 241 if (ackprim == DL_ERROR_ACK) { 242 if (len < DL_ERROR_ACK_SIZE) 243 goto runt; 244 245 if (dlp->error_ack.dl_error_primitive != reqprim) { 246 ackreqprim = dlp->error_ack.dl_error_primitive; 247 goto mixup; 248 } 249 250 /* 251 * Return a special error code (ENOTSUP) indicating that the 252 * caller has returned DL_ERROR_ACK. Callers that want more 253 * details an pass a non-NULL dleap. 254 */ 255 if (dleap != NULL) 256 *dleap = dlp->error_ack; 257 258 freemsg(mp); 259 return (ENOTSUP); 260 } 261 262 cmn_err(CE_NOTE, "!dl_op: expected %s but received %s", 263 dl_primstr(expprim), dl_primstr(ackprim)); 264 freemsg(mp); 265 return (EBADMSG); 266 runt: 267 cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim)); 268 freemsg(mp); 269 return (EBADMSG); 270 mixup: 271 cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s", 272 dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim)); 273 freemsg(mp); 274 return (EBADMSG); 275 } 276 277 /* 278 * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response. 279 * 280 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the 281 * caller can get the contents by passing a non-NULL `dleap'). 282 */ 283 int 284 dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap) 285 { 286 mblk_t *mp; 287 int err; 288 289 mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ); 290 if (mp == NULL) 291 return (ENOMEM); 292 293 ((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa; 294 295 err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL); 296 if (err == 0) 297 freemsg(mp); 298 return (err); 299 } 300 301 /* 302 * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response. 303 * 304 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the 305 * caller can get the contents by passing a non-NULL `dleap'). 306 */ 307 int 308 dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap) 309 { 310 dl_bind_req_t *dlbrp; 311 dl_bind_ack_t *dlbap; 312 mblk_t *mp; 313 int err; 314 315 mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ); 316 if (mp == NULL) 317 return (ENOMEM); 318 319 dlbrp = (dl_bind_req_t *)mp->b_rptr; 320 dlbrp->dl_sap = sap; 321 dlbrp->dl_conn_mgmt = 0; 322 dlbrp->dl_max_conind = 0; 323 dlbrp->dl_xidtest_flg = 0; 324 dlbrp->dl_service_mode = DL_CLDLS; 325 326 err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL); 327 if (err == 0) { 328 dlbap = (dl_bind_ack_t *)mp->b_rptr; 329 if (dlbap->dl_sap != sap) { 330 cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK: bad sap %u", 331 dlbap->dl_sap); 332 err = EPROTO; 333 } 334 freemsg(mp); 335 } 336 return (err); 337 } 338 339 /* 340 * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response. The caller 341 * must set `*physlenp' to the size of `physaddr' (both of which must be 342 * non-NULL); upon success they will be updated to contain the actual physical 343 * address and length. 344 * 345 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the 346 * caller can get the contents by passing a non-NULL `dleap'). 347 */ 348 int 349 dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp, 350 dl_error_ack_t *dleap) 351 { 352 dl_phys_addr_ack_t *dlpap; 353 mblk_t *mp; 354 int err; 355 t_uscalar_t paddrlen, paddroff; 356 timestruc_t tv; 357 358 mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO, 359 DL_PHYS_ADDR_REQ); 360 if (mp == NULL) 361 return (ENOMEM); 362 363 ((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR; 364 365 /* 366 * In case some provider doesn't implement or NAK the 367 * request, just wait for 15 seconds. 368 */ 369 tv.tv_sec = 15; 370 tv.tv_nsec = 0; 371 372 err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap, 373 &tv); 374 if (err == 0) { 375 dlpap = (dl_phys_addr_ack_t *)mp->b_rptr; 376 paddrlen = dlpap->dl_addr_length; 377 paddroff = dlpap->dl_addr_offset; 378 if (paddroff == 0 || paddrlen == 0 || paddrlen > *physlenp || 379 !MBLKIN(mp, paddroff, paddrlen)) { 380 cmn_err(CE_NOTE, "!dl_phys_addr: DL_PHYS_ADDR_ACK: " 381 "bad length/offset %d/%d", paddrlen, paddroff); 382 err = EBADMSG; 383 } else { 384 bcopy(mp->b_rptr + paddroff, physaddr, paddrlen); 385 *physlenp = paddrlen; 386 } 387 freemsg(mp); 388 } 389 return (err); 390 } 391 392 /* 393 * Send a DL_INFO_REQ over `lh' and wait for the response. The caller must 394 * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t 395 * from the provider. The caller may optionally get the provider's physical 396 * address by passing a non-NULL `physaddr' and setting `*physlenp' to its 397 * size; upon success they will be updated to contain the actual physical 398 * address and its length. 399 * 400 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the 401 * caller can get the contents by passing a non-NULL `dleap'). 402 */ 403 int 404 dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr, 405 size_t *physlenp, dl_error_ack_t *dleap) 406 { 407 mblk_t *mp; 408 int err; 409 int addrlen, addroff; 410 411 mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ); 412 if (mp == NULL) 413 return (ENOMEM); 414 415 err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL); 416 if (err != 0) 417 return (err); 418 419 *dliap = *(dl_info_ack_t *)mp->b_rptr; 420 if (physaddr != NULL) { 421 addrlen = dliap->dl_addr_length - ABS(dliap->dl_sap_length); 422 addroff = dliap->dl_addr_offset; 423 if (addroff == 0 || addrlen <= 0 || addrlen > *physlenp || 424 !MBLKIN(mp, addroff, dliap->dl_addr_length)) { 425 cmn_err(CE_NOTE, "!dl_info: DL_INFO_ACK: " 426 "bad length/offset %d/%d", addrlen, addroff); 427 freemsg(mp); 428 return (EBADMSG); 429 } 430 431 if (dliap->dl_sap_length > 0) 432 addroff += dliap->dl_sap_length; 433 bcopy(mp->b_rptr + addroff, physaddr, addrlen); 434 *physlenp = addrlen; 435 } 436 freemsg(mp); 437 return (err); 438 } 439 440 /* 441 * Send a DL_NOTIFY_REQ over `lh' and wait for the response. The caller 442 * should set `notesp' to the set of notifications they wish to enable; 443 * upon success it will contain the notifications enabled by the provider. 444 * 445 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the 446 * caller can get the contents by passing a non-NULL `dleap'). 447 */ 448 int 449 dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap) 450 { 451 mblk_t *mp; 452 int err; 453 454 mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ); 455 if (mp == NULL) 456 return (ENOMEM); 457 458 ((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp; 459 460 err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL); 461 if (err == 0) { 462 *notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications; 463 freemsg(mp); 464 } 465 return (err); 466 } 467 468 const char * 469 dl_primstr(t_uscalar_t prim) 470 { 471 switch (prim) { 472 case DL_INFO_REQ: return ("DL_INFO_REQ"); 473 case DL_INFO_ACK: return ("DL_INFO_ACK"); 474 case DL_ATTACH_REQ: return ("DL_ATTACH_REQ"); 475 case DL_DETACH_REQ: return ("DL_DETACH_REQ"); 476 case DL_BIND_REQ: return ("DL_BIND_REQ"); 477 case DL_BIND_ACK: return ("DL_BIND_ACK"); 478 case DL_UNBIND_REQ: return ("DL_UNBIND_REQ"); 479 case DL_OK_ACK: return ("DL_OK_ACK"); 480 case DL_ERROR_ACK: return ("DL_ERROR_ACK"); 481 case DL_ENABMULTI_REQ: return ("DL_ENABMULTI_REQ"); 482 case DL_DISABMULTI_REQ: return ("DL_DISABMULTI_REQ"); 483 case DL_PROMISCON_REQ: return ("DL_PROMISCON_REQ"); 484 case DL_PROMISCOFF_REQ: return ("DL_PROMISCOFF_REQ"); 485 case DL_UNITDATA_REQ: return ("DL_UNITDATA_REQ"); 486 case DL_UNITDATA_IND: return ("DL_UNITDATA_IND"); 487 case DL_UDERROR_IND: return ("DL_UDERROR_IND"); 488 case DL_PHYS_ADDR_REQ: return ("DL_PHYS_ADDR_REQ"); 489 case DL_PHYS_ADDR_ACK: return ("DL_PHYS_ADDR_ACK"); 490 case DL_SET_PHYS_ADDR_REQ: return ("DL_SET_PHYS_ADDR_REQ"); 491 case DL_NOTIFY_REQ: return ("DL_NOTIFY_REQ"); 492 case DL_NOTIFY_ACK: return ("DL_NOTIFY_ACK"); 493 case DL_NOTIFY_IND: return ("DL_NOTIFY_IND"); 494 case DL_CAPABILITY_REQ: return ("DL_CAPABILITY_REQ"); 495 case DL_CAPABILITY_ACK: return ("DL_CAPABILITY_ACK"); 496 case DL_CONTROL_REQ: return ("DL_CONTROL_REQ"); 497 case DL_CONTROL_ACK: return ("DL_CONTROL_ACK"); 498 case DL_PASSIVE_REQ: return ("DL_PASSIVE_REQ"); 499 case DL_INTR_MODE_REQ: return ("DL_INTR_MODE_REQ"); 500 case DL_UDQOS_REQ: return ("DL_UDQOS_REQ"); 501 default: return ("<unknown primitive>"); 502 } 503 } 504 505 const char * 506 dl_errstr(t_uscalar_t err) 507 { 508 switch (err) { 509 case DL_ACCESS: return ("DL_ACCESS"); 510 case DL_BADADDR: return ("DL_BADADDR"); 511 case DL_BADCORR: return ("DL_BADCORR"); 512 case DL_BADDATA: return ("DL_BADDATA"); 513 case DL_BADPPA: return ("DL_BADPPA"); 514 case DL_BADPRIM: return ("DL_BADPRIM"); 515 case DL_BADQOSPARAM: return ("DL_BADQOSPARAM"); 516 case DL_BADQOSTYPE: return ("DL_BADQOSTYPE"); 517 case DL_BADSAP: return ("DL_BADSAP"); 518 case DL_BADTOKEN: return ("DL_BADTOKEN"); 519 case DL_BOUND: return ("DL_BOUND"); 520 case DL_INITFAILED: return ("DL_INITFAILED"); 521 case DL_NOADDR: return ("DL_NOADDR"); 522 case DL_NOTINIT: return ("DL_NOTINIT"); 523 case DL_OUTSTATE: return ("DL_OUTSTATE"); 524 case DL_SYSERR: return ("DL_SYSERR"); 525 case DL_UNSUPPORTED: return ("DL_UNSUPPORTED"); 526 case DL_UNDELIVERABLE: return ("DL_UNDELIVERABLE"); 527 case DL_NOTSUPPORTED: return ("DL_NOTSUPPORTED "); 528 case DL_TOOMANY: return ("DL_TOOMANY"); 529 case DL_NOTENAB: return ("DL_NOTENAB"); 530 case DL_BUSY: return ("DL_BUSY"); 531 case DL_NOAUTO: return ("DL_NOAUTO"); 532 case DL_NOXIDAUTO: return ("DL_NOXIDAUTO"); 533 case DL_NOTESTAUTO: return ("DL_NOTESTAUTO"); 534 case DL_XIDAUTO: return ("DL_XIDAUTO"); 535 case DL_TESTAUTO: return ("DL_TESTAUTO"); 536 case DL_PENDING: return ("DL_PENDING"); 537 default: return ("<unknown error>"); 538 } 539 } 540 541 const char * 542 dl_mactypestr(t_uscalar_t mactype) 543 { 544 switch (mactype) { 545 case DL_CSMACD: return ("CSMA/CD"); 546 case DL_TPB: return ("Token Bus"); 547 case DL_TPR: return ("Token Ring"); 548 case DL_METRO: return ("Metro Net"); 549 case DL_ETHER: return ("Ethernet"); 550 case DL_HDLC: return ("HDLC"); 551 case DL_CHAR: return ("Sync Character"); 552 case DL_CTCA: return ("CTCA"); 553 case DL_FDDI: return ("FDDI"); 554 case DL_FRAME: return ("Frame Relay (LAPF)"); 555 case DL_MPFRAME: return ("MP Frame Relay"); 556 case DL_ASYNC: return ("Async Character"); 557 case DL_IPX25: return ("X.25 (Classic IP)"); 558 case DL_LOOP: return ("Software Loopback"); 559 case DL_FC: return ("Fiber Channel"); 560 case DL_ATM: return ("ATM"); 561 case DL_IPATM: return ("ATM (Classic IP)"); 562 case DL_X25: return ("X.25 (LAPB)"); 563 case DL_ISDN: return ("ISDN"); 564 case DL_HIPPI: return ("HIPPI"); 565 case DL_100VG: return ("100BaseVG Ethernet"); 566 case DL_100VGTPR: return ("100BaseVG Token Ring"); 567 case DL_ETH_CSMA: return ("Ethernet/IEEE 802.3"); 568 case DL_100BT: return ("100BaseT"); 569 case DL_IB: return ("Infiniband"); 570 case DL_IPV4: return ("IPv4 Tunnel"); 571 case DL_IPV6: return ("IPv6 Tunnel"); 572 case DL_WIFI: return ("IEEE 802.11"); 573 case DL_IPNET: return ("IPNET"); 574 default: return ("<unknown mactype>"); 575 } 576 } 577