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