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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Data-Link Provider Interface (Version 2) 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #include <poll.h> 40 #include <stropts.h> 41 #include <sys/dlpi.h> 42 #include <errno.h> 43 #include <sys/sysmacros.h> 44 #include <ctype.h> 45 #include <libdlpi.h> 46 #include <libdladm.h> 47 48 typedef enum dlpi_multi_op { 49 DLPI_MULTI_DISABLE = 0, 50 DLPI_MULTI_ENABLE 51 } dlpi_multi_op_t; 52 53 typedef enum dlpi_promisc_op { 54 DLPI_PROMISC_OFF = 0, 55 DLPI_PROMISC_ON 56 } dlpi_promisc_op_t; 57 58 const char *i_dlpi_mac_type[] = { 59 "CSMA/CD", /* 0x00 */ 60 "Token Bus", /* 0x01 */ 61 "Token Ring", /* 0x02 */ 62 "Metro Net", /* 0x03 */ 63 "Ethernet", /* 0x04 */ 64 "HDLC", /* 0x05 */ 65 "Sync Character", /* 0x06 */ 66 "CTCA", /* 0x07 */ 67 "FDDI", /* 0x08 */ 68 "unknown", /* 0x09 */ 69 "Frame Relay (LAPF)", /* 0x0a */ 70 "MP Frame Relay", /* 0x0b */ 71 "Async Character", /* 0x0c */ 72 "X.25 (Classic IP)", /* 0x0d */ 73 "Software Loopback", /* 0x0e */ 74 "undefined", /* 0x0f */ 75 "Fiber Channel", /* 0x10 */ 76 "ATM", /* 0x11 */ 77 "ATM (Classic IP)", /* 0x12 */ 78 "X.25 (LAPB)", /* 0x13 */ 79 "ISDN", /* 0x14 */ 80 "HIPPI", /* 0x15 */ 81 "100BaseVG Ethernet", /* 0x16 */ 82 "100BaseVG Token Ring", /* 0x17 */ 83 "Ethernet/IEEE 802.3", /* 0x18 */ 84 "100BaseT", /* 0x19 */ 85 "Infiniband" /* 0x1a */ 86 }; 87 88 static int i_dlpi_ifrm_num(char *, unsigned int *); 89 90 const char * 91 dlpi_mac_type(uint_t type) 92 { 93 if (type >= sizeof (i_dlpi_mac_type) / sizeof (i_dlpi_mac_type[0])) 94 return ("ERROR"); 95 96 return (i_dlpi_mac_type[type]); 97 } 98 99 static int 100 strputmsg(int fd, uint8_t *ctl_buf, size_t ctl_len, int flags) 101 { 102 struct strbuf ctl; 103 104 ctl.buf = (char *)ctl_buf; 105 ctl.len = ctl_len; 106 107 return (putmsg(fd, &ctl, NULL, flags)); 108 } 109 110 static int 111 strgetmsg(int fd, int timeout, char *ctl_buf, 112 size_t *ctl_lenp, char *data_buf, size_t *data_lenp) 113 { 114 struct strbuf ctl; 115 struct strbuf data; 116 int res; 117 struct pollfd pfd; 118 int flags = 0; 119 120 pfd.fd = fd; 121 pfd.events = POLLIN | POLLPRI; 122 123 switch (poll(&pfd, 1, timeout)) { 124 default: 125 ctl.buf = ctl_buf; 126 ctl.len = 0; 127 ctl.maxlen = (ctl_lenp != NULL) ? *ctl_lenp : 0; 128 129 data.buf = data_buf; 130 data.len = 0; 131 data.maxlen = (data_lenp != NULL) ? *data_lenp : 0; 132 133 if ((res = getmsg(fd, &ctl, &data, &flags)) < 0) 134 goto failed; 135 136 if (ctl_buf != NULL) { 137 if (res & MORECTL) { 138 errno = E2BIG; 139 goto failed; 140 } 141 142 *ctl_lenp = ctl.len; 143 } 144 145 if (data_buf != NULL) { 146 if (res & MOREDATA) { 147 errno = E2BIG; 148 goto failed; 149 } 150 151 *data_lenp = data.len; 152 } 153 154 break; 155 case 0: 156 errno = ETIME; 157 /*FALLTHRU*/ 158 case -1: 159 goto failed; 160 } 161 162 return (0); 163 failed: 164 return (-1); 165 } 166 167 int 168 dlpi_open(const char *provider) 169 { 170 char devname[MAXPATHLEN]; 171 char path[MAXPATHLEN]; 172 int fd; 173 struct stat st; 174 175 (void) snprintf(devname, MAXPATHLEN, "/dev/%s", provider); 176 177 if ((fd = open(devname, O_RDWR)) != -1) 178 return (fd); 179 180 (void) snprintf(path, MAXPATHLEN, "/devices/pseudo/clone@0:%s", 181 provider); 182 183 if (stat(path, &st) == 0) { 184 (void) strlcpy(devname, path, sizeof (devname)); 185 if ((fd = open(devname, O_RDWR)) != -1) 186 return (fd); 187 } 188 189 return (-1); 190 } 191 192 int 193 dlpi_close(int fd) 194 { 195 return (close(fd)); 196 } 197 198 int 199 dlpi_info(int fd, int timeout, dl_info_ack_t *ackp, 200 union DL_qos_types *selp, union DL_qos_types *rangep, 201 uint8_t *addrp, size_t *addrlenp, uint8_t *brdcst_addrp, 202 size_t *brdcst_addrlenp) 203 { 204 int rc = -1; 205 size_t size; 206 dl_info_ack_t *buf; 207 dl_info_req_t dlir; 208 dl_info_ack_t *dliap; 209 union DL_qos_types *uqtp; 210 211 size = sizeof (dl_info_ack_t); /* DL_INFO_ACK */ 212 size += sizeof (union DL_qos_types); /* QoS selections */ 213 size += sizeof (union DL_qos_types); /* QoS ranges */ 214 size += MAXADDRLEN + MAXSAPLEN; /* DLSAP Address */ 215 size += MAXADDRLEN; /* Broadcast Address */ 216 217 if ((buf = malloc(size)) == NULL) 218 return (-1); 219 220 dlir.dl_primitive = DL_INFO_REQ; 221 222 if (strputmsg(fd, (uint8_t *)&dlir, DL_INFO_REQ_SIZE, RS_HIPRI) == -1) 223 goto done; 224 225 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 226 goto done; 227 228 if (size < DL_INFO_ACK_SIZE) { 229 errno = EBADMSG; 230 goto done; 231 } 232 233 dliap = (dl_info_ack_t *)buf; 234 if (dliap->dl_primitive != DL_INFO_ACK || 235 dliap->dl_version != DL_VERSION_2) { 236 errno = EPROTO; 237 goto done; 238 } 239 240 (void) memcpy(ackp, buf, DL_INFO_ACK_SIZE); 241 242 if (dliap->dl_qos_offset != 0) { 243 if (dliap->dl_qos_length < sizeof (t_uscalar_t)) { 244 errno = EPROTO; 245 goto done; 246 } 247 248 uqtp = (union DL_qos_types *) 249 ((uintptr_t)buf + dliap->dl_qos_offset); 250 if (uqtp->dl_qos_type != DL_QOS_CO_SEL1 && 251 uqtp->dl_qos_type != DL_QOS_CL_SEL1) { 252 errno = EPROTO; 253 goto done; 254 } 255 256 if (selp != NULL) 257 (void) memcpy(selp, (char *)buf + dliap->dl_qos_offset, 258 dliap->dl_qos_length); 259 } 260 261 if (dliap->dl_qos_range_offset != 0) { 262 if (dliap->dl_qos_range_length < sizeof (t_uscalar_t)) { 263 errno = EPROTO; 264 goto done; 265 } 266 267 uqtp = (union DL_qos_types *) 268 ((uintptr_t)buf + dliap->dl_qos_range_offset); 269 if (uqtp->dl_qos_type != DL_QOS_CO_RANGE1 && 270 uqtp->dl_qos_type != DL_QOS_CL_RANGE1) { 271 errno = EPROTO; 272 goto done; 273 } 274 275 if (rangep != NULL) 276 (void) memcpy(rangep, 277 (char *)buf + dliap->dl_qos_range_offset, 278 dliap->dl_qos_range_length); 279 } 280 281 if (dliap->dl_addr_offset != 0) { 282 if (dliap->dl_addr_length == 0) { 283 errno = EPROTO; 284 goto done; 285 } 286 287 if (addrlenp != NULL) 288 *addrlenp = dliap->dl_addr_length; 289 if (addrp != NULL) 290 (void) memcpy(addrp, 291 (char *)buf + dliap->dl_addr_offset, 292 dliap->dl_addr_length); 293 } 294 295 if (dliap->dl_brdcst_addr_offset != 0) { 296 if (dliap->dl_brdcst_addr_length == 0) { 297 errno = EPROTO; 298 goto done; 299 } 300 301 if (brdcst_addrlenp != NULL) 302 *brdcst_addrlenp = dliap->dl_brdcst_addr_length; 303 if (brdcst_addrp != NULL) 304 (void) memcpy(brdcst_addrp, 305 (char *)buf + dliap->dl_brdcst_addr_offset, 306 dliap->dl_brdcst_addr_length); 307 } 308 309 rc = 0; /* success */ 310 done: 311 free(buf); 312 return (rc); 313 } 314 315 int 316 dlpi_attach(int fd, int timeout, uint_t ppa) 317 { 318 int rc = -1; 319 size_t size; 320 dl_attach_req_t dlar; 321 dl_error_ack_t *dleap; 322 union DL_primitives *buf; 323 union DL_primitives *udlp; 324 325 size = 0; 326 size = MAX(sizeof (dl_ok_ack_t), size); 327 size = MAX(sizeof (dl_error_ack_t), size); 328 329 if ((buf = malloc(size)) == NULL) 330 return (-1); 331 332 dlar.dl_primitive = DL_ATTACH_REQ; 333 dlar.dl_ppa = ppa; 334 335 if (strputmsg(fd, (uint8_t *)&dlar, DL_ATTACH_REQ_SIZE, 0) == -1) 336 goto done; 337 338 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 339 goto done; 340 341 if (size < sizeof (t_uscalar_t)) { 342 errno = EBADMSG; 343 goto done; 344 } 345 346 udlp = (union DL_primitives *)buf; 347 switch (udlp->dl_primitive) { 348 case DL_OK_ACK: 349 if (size < DL_OK_ACK_SIZE) { 350 errno = EBADMSG; 351 goto done; 352 } 353 break; 354 355 case DL_ERROR_ACK: 356 if (size < DL_ERROR_ACK_SIZE) { 357 errno = EBADMSG; 358 goto done; 359 } 360 361 dleap = (dl_error_ack_t *)buf; 362 switch (dleap->dl_errno) { 363 case DL_BADPPA: 364 errno = EINVAL; 365 break; 366 367 case DL_ACCESS: 368 errno = EPERM; 369 break; 370 371 case DL_SYSERR: 372 errno = dleap->dl_unix_errno; 373 break; 374 375 default: 376 errno = EPROTO; 377 break; 378 } 379 380 goto done; 381 382 default: 383 errno = EBADMSG; 384 goto done; 385 } 386 387 rc = 0; /* success */ 388 done: 389 free(buf); 390 return (rc); 391 } 392 393 int 394 dlpi_detach(int fd, int timeout) 395 { 396 int rc = -1; 397 size_t size; 398 dl_detach_req_t dldr; 399 dl_error_ack_t *dleap; 400 union DL_primitives *buf; 401 union DL_primitives *udlp; 402 403 size = 0; 404 size = MAX(sizeof (dl_ok_ack_t), size); 405 size = MAX(sizeof (dl_error_ack_t), size); 406 407 if ((buf = malloc(size)) == NULL) 408 return (-1); 409 410 dldr.dl_primitive = DL_DETACH_REQ; 411 412 if (strputmsg(fd, (uint8_t *)&dldr, DL_DETACH_REQ_SIZE, 0) == -1) 413 goto done; 414 415 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 416 goto done; 417 418 if (size < sizeof (t_uscalar_t)) { 419 errno = EBADMSG; 420 goto done; 421 } 422 423 udlp = (union DL_primitives *)buf; 424 switch (udlp->dl_primitive) { 425 case DL_OK_ACK: 426 if (size < DL_OK_ACK_SIZE) { 427 errno = EBADMSG; 428 goto done; 429 } 430 break; 431 432 case DL_ERROR_ACK: 433 if (size < DL_ERROR_ACK_SIZE) { 434 errno = EBADMSG; 435 goto done; 436 } 437 438 dleap = (dl_error_ack_t *)buf; 439 switch (dleap->dl_errno) { 440 case DL_SYSERR: 441 errno = dleap->dl_unix_errno; 442 break; 443 444 default: 445 errno = EPROTO; 446 break; 447 } 448 goto done; 449 450 default: 451 errno = EBADMSG; 452 goto done; 453 } 454 455 rc = 0; /* success */ 456 done: 457 free(buf); 458 return (rc); 459 } 460 461 int 462 dlpi_bind(int fd, int timeout, uint_t sap, uint16_t mode, 463 boolean_t conn_mgmt, uint32_t *max_conn_ind, 464 uint32_t *xid_test, uint8_t *addrp, size_t *addrlenp) 465 { 466 int rc = -1; 467 size_t size; 468 dl_bind_req_t dlbr; 469 dl_bind_ack_t *dlbap; 470 dl_error_ack_t *dleap; 471 union DL_primitives *buf; 472 union DL_primitives *udlp; 473 474 size = 0; 475 size = MAX(sizeof (dl_bind_ack_t) + MAXADDRLEN + MAXSAPLEN, size); 476 size = MAX(sizeof (dl_error_ack_t), size); 477 478 if ((buf = malloc(size)) == NULL) 479 return (-1); 480 481 dlbr.dl_primitive = DL_BIND_REQ; 482 dlbr.dl_sap = sap; 483 dlbr.dl_service_mode = mode; 484 dlbr.dl_conn_mgmt = (conn_mgmt) ? 1 : 0; 485 dlbr.dl_max_conind = (max_conn_ind != NULL) ? *max_conn_ind : 0; 486 dlbr.dl_xidtest_flg = (xid_test != NULL) ? *xid_test : 0; 487 488 if (strputmsg(fd, (uint8_t *)&dlbr, DL_BIND_REQ_SIZE, 0) == -1) 489 goto done; 490 491 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 492 goto done; 493 494 if (size < sizeof (t_uscalar_t)) { 495 errno = EBADMSG; 496 goto done; 497 } 498 499 udlp = (union DL_primitives *)buf; 500 switch (udlp->dl_primitive) { 501 case DL_BIND_ACK: 502 if (size < DL_BIND_ACK_SIZE) { 503 errno = EBADMSG; 504 goto done; 505 } 506 507 dlbap = (dl_bind_ack_t *)buf; 508 if (max_conn_ind != NULL) 509 *max_conn_ind = dlbap->dl_max_conind; 510 if (xid_test != NULL) 511 *xid_test = dlbap->dl_xidtest_flg; 512 513 if (dlbap->dl_addr_offset != 0) { 514 if (dlbap->dl_addr_length == 0) { 515 errno = EPROTO; 516 goto done; 517 } 518 519 if (addrlenp != NULL) 520 *addrlenp = dlbap->dl_addr_length; 521 if (addrp != NULL) 522 (void) memcpy(addrp, 523 (char *)buf + dlbap->dl_addr_offset, 524 dlbap->dl_addr_length); 525 } 526 527 break; 528 529 case DL_ERROR_ACK: 530 if (size < DL_ERROR_ACK_SIZE) { 531 errno = EBADMSG; 532 goto done; 533 } 534 535 dleap = (dl_error_ack_t *)buf; 536 switch (dleap->dl_errno) { 537 case DL_BADADDR: 538 errno = EINVAL; 539 break; 540 541 case DL_INITFAILED: 542 case DL_NOTINIT: 543 errno = EIO; 544 break; 545 546 case DL_ACCESS: 547 errno = EACCES; 548 break; 549 550 case DL_NOADDR: 551 errno = EFAULT; 552 break; 553 554 case DL_UNSUPPORTED: 555 case DL_NOAUTO: 556 case DL_NOXIDAUTO: 557 case DL_NOTESTAUTO: 558 errno = ENOTSUP; 559 break; 560 561 case DL_SYSERR: 562 errno = dleap->dl_unix_errno; 563 break; 564 565 default: 566 errno = EPROTO; 567 break; 568 } 569 goto done; 570 571 default: 572 errno = EBADMSG; 573 goto done; 574 } 575 576 rc = 0; /* success */ 577 done: 578 free(buf); 579 return (rc); 580 } 581 582 int 583 dlpi_unbind(int fd, int timeout) 584 { 585 int rc = -1; 586 size_t size; 587 dl_unbind_req_t dlubr; 588 dl_error_ack_t *dleap; 589 union DL_primitives *buf; 590 union DL_primitives *udlp; 591 592 size = 0; 593 size = MAX(sizeof (dl_ok_ack_t), size); 594 size = MAX(sizeof (dl_error_ack_t), size); 595 596 if ((buf = malloc(size)) == NULL) 597 return (-1); 598 599 dlubr.dl_primitive = DL_UNBIND_REQ; 600 601 if (strputmsg(fd, (uint8_t *)&dlubr, DL_UNBIND_REQ_SIZE, 0) == -1) 602 goto done; 603 604 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 605 goto done; 606 607 if (size < sizeof (t_uscalar_t)) { 608 errno = EBADMSG; 609 goto done; 610 } 611 612 udlp = (union DL_primitives *)buf; 613 switch (udlp->dl_primitive) { 614 case DL_OK_ACK: 615 if (size < DL_OK_ACK_SIZE) { 616 errno = EBADMSG; 617 goto done; 618 } 619 break; 620 621 case DL_ERROR_ACK: 622 if (size < DL_ERROR_ACK_SIZE) { 623 errno = EBADMSG; 624 goto done; 625 } 626 627 dleap = (dl_error_ack_t *)buf; 628 switch (dleap->dl_errno) { 629 case DL_SYSERR: 630 errno = dleap->dl_unix_errno; 631 break; 632 633 default: 634 errno = EPROTO; 635 break; 636 } 637 goto done; 638 639 default: 640 errno = EBADMSG; 641 goto done; 642 } 643 644 rc = 0; /* success */ 645 done: 646 free(buf); 647 return (rc); 648 } 649 650 static int 651 i_dlpi_multi(int fd, int timeout, dlpi_multi_op_t op, 652 uint8_t *addrp, size_t addr_length) 653 { 654 int rc = -1; 655 size_t opsize; 656 size_t size; 657 dl_enabmulti_req_t *dlemrp; 658 dl_disabmulti_req_t *dldmrp; 659 dl_error_ack_t *dleap; 660 union DL_primitives *buf; 661 union DL_primitives *udlp; 662 663 opsize = (op == DLPI_MULTI_ENABLE) ? sizeof (dl_enabmulti_req_t) : 664 sizeof (dl_disabmulti_req_t); 665 opsize += addr_length; 666 667 size = 0; 668 size = MAX(opsize, size); 669 size = MAX(sizeof (dl_ok_ack_t), size); 670 size = MAX(sizeof (dl_error_ack_t), size); 671 672 if ((buf = malloc(size)) == NULL) 673 return (-1); 674 675 if (op == DLPI_MULTI_ENABLE) { 676 dlemrp = (dl_enabmulti_req_t *)buf; 677 dlemrp->dl_primitive = DL_ENABMULTI_REQ; 678 dlemrp->dl_addr_length = addr_length; 679 dlemrp->dl_addr_offset = sizeof (dl_enabmulti_req_t); 680 (void) memcpy(&dlemrp[1], addrp, addr_length); 681 } else { 682 dldmrp = (dl_disabmulti_req_t *)buf; 683 dldmrp->dl_primitive = DL_DISABMULTI_REQ; 684 dldmrp->dl_addr_length = addr_length; 685 dldmrp->dl_addr_offset = sizeof (dl_disabmulti_req_t); 686 (void) memcpy(&dldmrp[1], addrp, addr_length); 687 } 688 689 if (strputmsg(fd, (uint8_t *)buf, opsize, 0) == -1) 690 goto done; 691 692 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 693 goto done; 694 695 if (size < sizeof (t_uscalar_t)) { 696 errno = EBADMSG; 697 goto done; 698 } 699 700 udlp = (union DL_primitives *)buf; 701 switch (udlp->dl_primitive) { 702 case DL_OK_ACK: 703 if (size < DL_OK_ACK_SIZE) { 704 errno = EBADMSG; 705 goto done; 706 } 707 break; 708 709 case DL_ERROR_ACK: 710 if (size < DL_ERROR_ACK_SIZE) { 711 errno = EBADMSG; 712 goto done; 713 } 714 715 dleap = (dl_error_ack_t *)buf; 716 switch (dleap->dl_errno) { 717 case DL_BADADDR: 718 errno = EINVAL; 719 break; 720 721 case DL_TOOMANY: 722 errno = ENOSPC; 723 break; 724 725 case DL_NOTSUPPORTED: 726 errno = ENOTSUP; 727 break; 728 729 case DL_NOTENAB: 730 errno = EINVAL; 731 break; 732 733 case DL_SYSERR: 734 errno = dleap->dl_unix_errno; 735 break; 736 737 default: 738 errno = EPROTO; 739 break; 740 } 741 goto done; 742 743 default: 744 errno = EBADMSG; 745 goto done; 746 } 747 748 rc = 0; /* success */ 749 done: 750 free(buf); 751 return (rc); 752 } 753 754 int 755 dlpi_enabmulti(int fd, int timeout, uint8_t *addrp, 756 size_t addr_length) 757 { 758 return (i_dlpi_multi(fd, timeout, DLPI_MULTI_ENABLE, addrp, 759 addr_length)); 760 } 761 762 int 763 dlpi_disabmulti(int fd, int timeout, uint8_t *addrp, 764 size_t addr_length) 765 { 766 return (i_dlpi_multi(fd, timeout, DLPI_MULTI_DISABLE, addrp, 767 addr_length)); 768 } 769 770 static int 771 i_dlpi_promisc(int fd, int timeout, dlpi_promisc_op_t op, 772 uint_t level) 773 { 774 int rc = -1; 775 size_t opsize; 776 size_t size; 777 dl_promiscon_req_t *dlpnrp; 778 dl_promiscoff_req_t *dlpfrp; 779 dl_error_ack_t *dleap; 780 union DL_primitives *buf; 781 union DL_primitives *udlp; 782 783 opsize = (op == DLPI_PROMISC_ON) ? sizeof (dl_promiscon_req_t) : 784 sizeof (dl_promiscoff_req_t); 785 786 size = 0; 787 size = MAX(opsize, size); 788 size = MAX(sizeof (dl_ok_ack_t), size); 789 size = MAX(sizeof (dl_error_ack_t), size); 790 791 if ((buf = malloc(size)) == NULL) 792 return (-1); 793 794 if (op == DLPI_PROMISC_ON) { 795 dlpnrp = (dl_promiscon_req_t *)buf; 796 dlpnrp->dl_primitive = DL_PROMISCON_REQ; 797 dlpnrp->dl_level = level; 798 799 if (strputmsg(fd, (uint8_t *)dlpnrp, opsize, 0) == -1) 800 goto done; 801 } else { 802 dlpfrp = (dl_promiscoff_req_t *)buf; 803 dlpfrp->dl_primitive = DL_PROMISCOFF_REQ; 804 dlpfrp->dl_level = level; 805 806 if (strputmsg(fd, (uint8_t *)dlpfrp, opsize, 0) == -1) 807 goto done; 808 } 809 810 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 811 goto done; 812 813 if (size < sizeof (t_uscalar_t)) { 814 errno = EBADMSG; 815 goto done; 816 } 817 818 udlp = (union DL_primitives *)buf; 819 switch (udlp->dl_primitive) { 820 case DL_OK_ACK: 821 if (size < DL_OK_ACK_SIZE) { 822 errno = EBADMSG; 823 goto done; 824 } 825 break; 826 827 case DL_ERROR_ACK: 828 if (size < DL_ERROR_ACK_SIZE) { 829 errno = EBADMSG; 830 goto done; 831 } 832 833 dleap = (dl_error_ack_t *)buf; 834 switch (dleap->dl_errno) { 835 case DL_NOTSUPPORTED: 836 case DL_UNSUPPORTED: 837 errno = ENOTSUP; 838 break; 839 840 case DL_NOTENAB: 841 errno = EINVAL; 842 break; 843 844 case DL_SYSERR: 845 errno = dleap->dl_unix_errno; 846 break; 847 848 default: 849 errno = EPROTO; 850 break; 851 } 852 goto done; 853 854 default: 855 errno = EBADMSG; 856 goto done; 857 } 858 859 rc = 0; /* success */ 860 done: 861 free(buf); 862 return (rc); 863 } 864 865 int 866 dlpi_promiscon(int fd, int timeout, uint_t level) 867 { 868 return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_ON, level)); 869 } 870 871 int 872 dlpi_promiscoff(int fd, int timeout, uint_t level) 873 { 874 return (i_dlpi_promisc(fd, timeout, DLPI_PROMISC_OFF, level)); 875 } 876 877 int 878 dlpi_phys_addr(int fd, int timeout, uint_t type, uint8_t *addrp, 879 size_t *addrlenp) 880 { 881 int rc = -1; 882 size_t size; 883 dl_phys_addr_req_t dlpar; 884 dl_phys_addr_ack_t *dlpaap; 885 dl_error_ack_t *dleap; 886 union DL_primitives *buf; 887 union DL_primitives *udlp; 888 889 size = 0; 890 size = MAX(sizeof (dl_phys_addr_ack_t) + MAXADDRLEN, size); 891 size = MAX(sizeof (dl_error_ack_t), size); 892 893 if ((buf = malloc(size)) == NULL) 894 return (-1); 895 896 dlpar.dl_primitive = DL_PHYS_ADDR_REQ; 897 dlpar.dl_addr_type = type; 898 899 if (strputmsg(fd, (uint8_t *)&dlpar, DL_PHYS_ADDR_REQ_SIZE, 0) == -1) 900 goto done; 901 902 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 903 goto done; 904 905 if (size < sizeof (t_uscalar_t)) { 906 errno = EBADMSG; 907 goto done; 908 } 909 910 udlp = (union DL_primitives *)buf; 911 switch (udlp->dl_primitive) { 912 case DL_PHYS_ADDR_ACK: 913 if (size < DL_PHYS_ADDR_ACK_SIZE) { 914 errno = EBADMSG; 915 goto done; 916 } 917 918 dlpaap = (dl_phys_addr_ack_t *)buf; 919 if (dlpaap->dl_addr_offset != 0) { 920 if (dlpaap->dl_addr_length == 0) { 921 errno = EPROTO; 922 goto done; 923 } 924 925 if (addrlenp != NULL) 926 *addrlenp = dlpaap->dl_addr_length; 927 928 if (addrp != NULL) 929 (void) memcpy(addrp, 930 (char *)buf + dlpaap->dl_addr_offset, 931 dlpaap->dl_addr_length); 932 } 933 break; 934 935 case DL_ERROR_ACK: 936 if (size < DL_ERROR_ACK_SIZE) { 937 errno = EBADMSG; 938 goto done; 939 } 940 941 dleap = (dl_error_ack_t *)buf; 942 switch (dleap->dl_errno) { 943 case DL_SYSERR: 944 errno = dleap->dl_unix_errno; 945 break; 946 947 default: 948 errno = EPROTO; 949 break; 950 } 951 goto done; 952 953 default: 954 errno = EBADMSG; 955 goto done; 956 } 957 958 rc = 0; /* success */ 959 done: 960 free(buf); 961 return (rc); 962 } 963 964 int 965 dlpi_set_phys_addr(int fd, int timeout, uint8_t *addrp, 966 size_t addr_length) 967 { 968 int rc = -1; 969 size_t opsize; 970 size_t size; 971 dl_set_phys_addr_req_t *dlspap; 972 dl_error_ack_t *dleap; 973 union DL_primitives *buf; 974 union DL_primitives *udlp; 975 976 opsize = sizeof (dl_set_phys_addr_req_t) + addr_length; 977 978 size = 0; 979 size = MAX(opsize, size); 980 size = MAX(sizeof (dl_ok_ack_t), size); 981 size = MAX(sizeof (dl_error_ack_t), size); 982 983 if ((buf = malloc(size)) == NULL) 984 return (-1); 985 986 dlspap = (dl_set_phys_addr_req_t *)buf; 987 dlspap->dl_primitive = DL_SET_PHYS_ADDR_REQ; 988 dlspap->dl_addr_length = addr_length; 989 dlspap->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 990 (void) memcpy(&dlspap[1], addrp, addr_length); 991 992 if (strputmsg(fd, (uint8_t *)dlspap, opsize, 0) == -1) 993 goto done; 994 995 if (strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL) == -1) 996 goto done; 997 998 if (size < sizeof (t_uscalar_t)) { 999 errno = EBADMSG; 1000 goto done; 1001 } 1002 1003 udlp = (union DL_primitives *)buf; 1004 switch (udlp->dl_primitive) { 1005 case DL_OK_ACK: 1006 if (size < DL_OK_ACK_SIZE) { 1007 errno = EBADMSG; 1008 goto done; 1009 } 1010 break; 1011 1012 case DL_ERROR_ACK: 1013 if (size < DL_ERROR_ACK_SIZE) { 1014 errno = EBADMSG; 1015 goto done; 1016 } 1017 1018 dleap = (dl_error_ack_t *)buf; 1019 switch (dleap->dl_errno) { 1020 case DL_BADADDR: 1021 errno = EINVAL; 1022 break; 1023 1024 case DL_NOTSUPPORTED: 1025 errno = ENOTSUP; 1026 break; 1027 1028 case DL_SYSERR: 1029 errno = dleap->dl_unix_errno; 1030 break; 1031 1032 default: 1033 errno = EPROTO; 1034 break; 1035 } 1036 goto done; 1037 1038 default: 1039 errno = EBADMSG; 1040 goto done; 1041 } 1042 1043 rc = 0; /* success */ 1044 done: 1045 free(buf); 1046 return (rc); 1047 } 1048 1049 void 1050 dlpi_passive(int fd, int timeout) 1051 { 1052 size_t size; 1053 dl_passive_req_t dlpr; 1054 union DL_primitives *buf; 1055 1056 size = MAX(sizeof (dl_ok_ack_t), sizeof (dl_error_ack_t)); 1057 1058 if ((buf = malloc(size)) == NULL) 1059 return; 1060 1061 dlpr.dl_primitive = DL_PASSIVE_REQ; 1062 1063 /* 1064 * We don't care about the outcome of this operation. We at least 1065 * don't want to return until the operation completes or the 1066 * timeout expires. 1067 */ 1068 if (strputmsg(fd, (uint8_t *)&dlpr, DL_PASSIVE_REQ_SIZE, 0) == 0) 1069 (void) strgetmsg(fd, timeout, (char *)buf, &size, NULL, NULL); 1070 free(buf); 1071 } 1072 1073 static int 1074 i_dlpi_style1_open(dlpi_if_attr_t *diap) 1075 { 1076 int fd; 1077 int cnt; 1078 dl_info_ack_t dlia; 1079 1080 /* Open device */ 1081 if ((fd = dlpi_open(diap->devname)) == -1) { 1082 diap->style1_failed = B_TRUE; 1083 diap->mod_pushed = 0; 1084 return (-1); 1085 } else { 1086 diap->style1_fd = fd; 1087 } 1088 1089 /* 1090 * Try to push modules (if any) onto the device stream 1091 */ 1092 for (cnt = 0; cnt < diap->mod_cnt; cnt++) { 1093 if (ioctl(fd, I_PUSH, diap->modlist[cnt]) == -1) { 1094 diap->mod_pushed = cnt+1; 1095 return (-1); 1096 } 1097 } 1098 1099 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) == -1) 1100 goto failed; 1101 1102 if (dlia.dl_provider_style != DL_STYLE1) 1103 goto failed; 1104 1105 diap->style = DL_STYLE1; 1106 diap->style1_failed = B_FALSE; 1107 1108 return (fd); 1109 failed: 1110 diap->style1_failed = B_TRUE; 1111 (void) dlpi_close(fd); 1112 return (-1); 1113 } 1114 1115 static int 1116 i_dlpi_style2_open(dlpi_if_attr_t *diap) 1117 { 1118 int fd; 1119 uint_t ppa; 1120 dl_info_ack_t dlia; 1121 1122 /* 1123 * If style 1 open failed, we need to determine how far it got and 1124 * finish up the open() call as a style 2 open 1125 * 1126 * If no modules were pushed (mod_pushed == 0), then we need to 1127 * strip off the ppa off the device name and open it as a style 2 1128 * device 1129 * 1130 * If the pushing of the last module failed, we need to strip off the 1131 * ppa from that module and try pushing it as a style 2 module 1132 * 1133 * Otherwise we failed during the push of an intermediate module and 1134 * must fail out and close the device. 1135 * 1136 * And if style1 did not fail (i.e. we called style2 open directly), 1137 * just open the device 1138 */ 1139 if (diap->style1_failed) { 1140 if (!diap->mod_pushed) { 1141 if (i_dlpi_ifrm_num(diap->devname, &ppa) < 0) 1142 return (-1); 1143 if ((fd = dlpi_open(diap->devname)) == -1) 1144 return (-1); 1145 } else if (diap->mod_pushed == diap->mod_cnt) { 1146 if (i_dlpi_ifrm_num( 1147 diap->modlist[diap->mod_cnt - 1], &ppa) < 0) 1148 return (-1); 1149 diap->mod_pushed--; 1150 fd = diap->style1_fd; 1151 } else { 1152 return (-1); 1153 } 1154 } else { 1155 if ((fd = dlpi_open(diap->devname)) == -1) 1156 return (-1); 1157 } 1158 1159 /* 1160 * Try and push modules (if any) onto the device stream 1161 */ 1162 for (; diap->mod_pushed < diap->mod_cnt; diap->mod_pushed++) { 1163 if (ioctl(fd, I_PUSH, 1164 diap->modlist[diap->mod_pushed]) == -1) 1165 goto failed; 1166 } 1167 1168 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, 1169 NULL) == -1) 1170 goto failed; 1171 1172 if (dlia.dl_provider_style != DL_STYLE2) 1173 goto failed; 1174 1175 diap->style = DL_STYLE2; 1176 1177 if (dlpi_attach(fd, -1, diap->ppa) < 0) 1178 goto failed; 1179 1180 return (fd); 1181 failed: 1182 (void) dlpi_close(fd); 1183 return (-1); 1184 } 1185 1186 static int 1187 i_dlpi_ifname_parse(const char *ifname, dlpi_if_attr_t *diap) 1188 { 1189 char *modlist = NULL; /* list of modules to push */ 1190 int cnt = 0; /* number of modules to push */ 1191 char modbuf[LIFNAMSIZ + 32]; 1192 char *nxtmod; 1193 char *p; 1194 int len; 1195 1196 /* if lun is specified fail (backwards compat) */ 1197 if (strchr(ifname, ':') != NULL) 1198 return (-1); 1199 1200 /* save copy of original device name */ 1201 if (strlcpy(diap->ifname, ifname, sizeof (diap->ifname)) >= 1202 sizeof (diap->ifname)) 1203 return (-1); 1204 1205 /* initialize ppa */ 1206 diap->ppa = -1; 1207 1208 /* get provider name and ppa from ifname */ 1209 len = strlen(ifname); 1210 for (p = (char *)ifname + len; --p != ifname; len--) { 1211 if (!isdigit(*p)) { 1212 (void) strlcpy(diap->provider, ifname, len + 1); 1213 diap->ppa = atoi(p + 1); 1214 break; 1215 } 1216 } 1217 1218 if (strlcpy(modbuf, diap->ifname, sizeof (modbuf)) >= 1219 sizeof (modbuf)) 1220 return (-1); 1221 1222 /* parse '.' delimited module list */ 1223 modlist = strchr(modbuf, '.'); 1224 if (modlist != NULL) { 1225 /* null-terminate interface name (device) */ 1226 *modlist = '\0'; 1227 modlist++; 1228 while (modlist && cnt < MAX_MODS) { 1229 if (*modlist == '\0') 1230 return (-1); 1231 1232 nxtmod = strchr(modlist, '.'); 1233 if (nxtmod) { 1234 *nxtmod = '\0'; 1235 nxtmod++; 1236 } 1237 if (strlcpy(diap->modlist[cnt], modlist, 1238 sizeof (diap->modlist[cnt])) >= 1239 sizeof (diap->modlist[cnt])) 1240 return (-1); 1241 cnt++; 1242 modlist = nxtmod; 1243 } 1244 } 1245 diap->mod_cnt = cnt; 1246 1247 if (strlcpy(diap->devname, modbuf, sizeof (diap->devname)) >= 1248 sizeof (diap->devname)) 1249 return (-1); 1250 1251 return (0); 1252 } 1253 1254 int 1255 dlpi_if_open(const char *ifname, dlpi_if_attr_t *diap, 1256 boolean_t force_style2) 1257 { 1258 int fd; 1259 1260 if (i_dlpi_ifname_parse(ifname, diap) == -1) { 1261 errno = EINVAL; 1262 return (-1); 1263 } 1264 1265 diap->style1_failed = B_TRUE; 1266 1267 if (!force_style2) { 1268 if ((fd = i_dlpi_style1_open(diap)) != -1) 1269 return (fd); 1270 } 1271 1272 if ((fd = i_dlpi_style2_open(diap)) == -1) 1273 return (-1); 1274 1275 return (fd); 1276 } 1277 1278 int 1279 dlpi_if_parse(const char *ifname, char *provider, int *ppap) 1280 { 1281 dlpi_if_attr_t diap; 1282 1283 if (i_dlpi_ifname_parse(ifname, &diap) == -1) { 1284 errno = EINVAL; 1285 return (-1); 1286 } 1287 1288 if (strlcpy(provider, diap.provider, LIFNAMSIZ) > LIFNAMSIZ) 1289 return (-1); 1290 1291 if (ppap != NULL) 1292 *ppap = diap.ppa; 1293 1294 return (0); 1295 } 1296 1297 /* 1298 * attempt to remove ppa from end of file name 1299 * return -1 if none found 1300 * return ppa if found and remove the ppa from the filename 1301 */ 1302 static int 1303 i_dlpi_ifrm_num(char *fname, unsigned int *ppa) 1304 { 1305 int i; 1306 uint_t p = 0; 1307 unsigned int m = 1; 1308 1309 i = strlen(fname) - 1; 1310 1311 while (i >= 0 && isdigit(fname[i])) { 1312 p += (fname[i] - '0')*m; 1313 m *= 10; 1314 i--; 1315 } 1316 1317 if (m == 1) { 1318 return (-1); 1319 } 1320 1321 fname[i + 1] = '\0'; 1322 *ppa = p; 1323 return (0); 1324 } 1325