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