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 2007 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 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <fcntl.h> 37 #include <unistd.h> 38 #include <poll.h> 39 #include <stropts.h> 40 #include <sys/dlpi.h> 41 #include <errno.h> 42 #include <alloca.h> 43 #include <sys/sysmacros.h> 44 #include <ctype.h> 45 #include <net/if_types.h> 46 #include <netinet/arp.h> 47 #include <libdlpi.h> 48 #include <libintl.h> 49 #include <libinetutil.h> 50 51 #include "libdlpi_impl.h" 52 53 static int i_dlpi_open(const char *, int *, uint_t); 54 static int i_dlpi_style1_open(dlpi_impl_t *); 55 static int i_dlpi_style2_open(dlpi_impl_t *); 56 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t); 57 static int i_dlpi_remove_ppa(char *); 58 static int i_dlpi_attach(dlpi_impl_t *); 59 static void i_dlpi_passive(dlpi_impl_t *); 60 61 static int i_dlpi_strputmsg(int, const dlpi_msg_t *, const void *, size_t, int); 62 static int i_dlpi_strgetmsg(int, int, dlpi_msg_t *, t_uscalar_t, t_uscalar_t, 63 size_t, void *, size_t *, size_t *); 64 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *, 65 size_t, int); 66 67 static size_t i_dlpi_getprimsize(t_uscalar_t); 68 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t); 69 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t); 70 static uint_t i_dlpi_buildsap(uint8_t *, uint_t); 71 static void i_dlpi_writesap(void *, uint_t, uint_t); 72 73 int 74 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags) 75 { 76 int retval; 77 int cnt; 78 ifspec_t ifsp; 79 dlpi_impl_t *dip; 80 81 /* 82 * Validate linkname, fail if logical unit number (lun) is specified, 83 * otherwise decompose the contents into ifsp. 84 */ 85 if (linkname == NULL || (strchr(linkname, ':') != NULL) || 86 !ifparse_ifspec(linkname, &ifsp)) 87 return (DLPI_ELINKNAMEINVAL); 88 89 /* Allocate a new dlpi_impl_t. */ 90 if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL) 91 return (DL_SYSERR); 92 93 /* Fill in known/default libdlpi handle values. */ 94 dip->dli_timeout = DLPI_DEF_TIMEOUT; 95 dip->dli_ppa = ifsp.ifsp_ppa; 96 dip->dli_mod_cnt = ifsp.ifsp_modcnt; 97 dip->dli_oflags = flags; 98 99 for (cnt = 0; cnt != dip->dli_mod_cnt; cnt++) { 100 (void) strlcpy(dip->dli_modlist[cnt], ifsp.ifsp_mods[cnt], 101 DLPI_LINKNAME_MAX); 102 } 103 104 /* Copy linkname provided to the function. */ 105 if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >= 106 sizeof (dip->dli_linkname)) { 107 free(dip); 108 return (DLPI_ELINKNAMEINVAL); 109 } 110 111 /* Copy provider name. */ 112 (void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm, 113 sizeof (dip->dli_provider)); 114 115 /* 116 * Special case: DLPI_SERIAL flag is set to indicate a synchronous 117 * serial line interface (see syncinit(1M), syncstat(1M), 118 * syncloop(1M)), which is not a DLPI link. 119 */ 120 if (dip->dli_oflags & DLPI_SERIAL) { 121 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { 122 free(dip); 123 return (retval); 124 } 125 126 *dhp = (dlpi_handle_t)dip; 127 return (retval); 128 } 129 130 if (i_dlpi_style1_open(dip) != DLPI_SUCCESS) { 131 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) { 132 free(dip); 133 return (retval); 134 } 135 } 136 137 if (dip->dli_oflags & DLPI_PASSIVE) 138 i_dlpi_passive(dip); 139 140 if ((dip->dli_oflags & DLPI_RAW) && 141 ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) { 142 dlpi_close((dlpi_handle_t)dip); 143 return (DLPI_ERAWNOTSUP); 144 } 145 146 /* 147 * We intentionally do not care if this request fails, as this 148 * indicates the underlying DLPI device does not support Native mode 149 * (pre-GLDV3 device drivers). 150 */ 151 if (dip->dli_oflags & DLPI_NATIVE) { 152 if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0) 153 dip->dli_mactype = retval; 154 } 155 156 *dhp = (dlpi_handle_t)dip; 157 return (DLPI_SUCCESS); 158 } 159 160 void 161 dlpi_close(dlpi_handle_t dh) 162 { 163 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 164 165 if (dip != NULL) { 166 (void) close(dip->dli_fd); 167 free(dip); 168 } 169 } 170 171 /* 172 * NOTE: The opt argument must be zero and is reserved for future use to extend 173 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)). 174 */ 175 int 176 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt) 177 { 178 int retval; 179 dlpi_msg_t req, ack; 180 dl_info_ack_t *infoackp; 181 uint8_t *sapp, *addrp; 182 caddr_t ackendp, datap; 183 t_uscalar_t dataoff, datalen; 184 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 185 186 if (dip == NULL) 187 return (DLPI_EINHANDLE); 188 189 if (infop == NULL || opt != 0) 190 return (DLPI_EINVAL); 191 192 (void) memset(infop, 0, sizeof (dlpi_info_t)); 193 194 /* Set QoS range parameters to default unsupported value. */ 195 infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 196 infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN; 197 infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN; 198 infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN; 199 infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN; 200 infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN; 201 infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN; 202 infop->di_qos_range.dl_residual_error = DL_UNKNOWN; 203 204 /* Set QoS parameters to default unsupported value. */ 205 infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN; 206 infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN; 207 infop->di_qos_sel.dl_priority = DL_UNKNOWN; 208 infop->di_qos_sel.dl_protection = DL_UNKNOWN; 209 infop->di_qos_sel.dl_residual_error = DL_UNKNOWN; 210 211 DLPI_MSG_CREATE(req, DL_INFO_REQ); 212 DLPI_MSG_CREATE(ack, DL_INFO_ACK); 213 214 retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI); 215 if (retval != DLPI_SUCCESS) 216 return (retval); 217 218 infoackp = &(ack.dlm_msg->info_ack); 219 if (infoackp->dl_version != DL_VERSION_2) 220 return (DLPI_EVERNOTSUP); 221 222 if (infoackp->dl_service_mode != DL_CLDLS) 223 return (DLPI_EMODENOTSUP); 224 225 dip->dli_style = infoackp->dl_provider_style; 226 dip->dli_mactype = infoackp->dl_mac_type; 227 228 ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 229 230 /* Check and save QoS selection information, if any. */ 231 datalen = infoackp->dl_qos_length; 232 dataoff = infoackp->dl_qos_offset; 233 if (dataoff != 0 && datalen != 0) { 234 datap = (caddr_t)infoackp + dataoff; 235 if (datalen > sizeof (dl_qos_cl_sel1_t) || 236 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 237 return (DLPI_EBADMSG); 238 239 (void) memcpy(&infop->di_qos_sel, datap, datalen); 240 if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1) 241 return (DLPI_EMODENOTSUP); 242 } 243 244 /* Check and save QoS range information, if any. */ 245 datalen = infoackp->dl_qos_range_length; 246 dataoff = infoackp->dl_qos_range_offset; 247 if (dataoff != 0 && datalen != 0) { 248 datap = (caddr_t)infoackp + dataoff; 249 if (datalen > sizeof (dl_qos_cl_range1_t) || 250 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 251 return (DLPI_EBADMSG); 252 253 (void) memcpy(&infop->di_qos_range, datap, datalen); 254 if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1) 255 return (DLPI_EMODENOTSUP); 256 } 257 258 /* Check and save physical address and SAP information. */ 259 dip->dli_saplen = abs(infoackp->dl_sap_length); 260 dip->dli_sapbefore = (infoackp->dl_sap_length > 0); 261 infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen; 262 263 if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX || 264 dip->dli_saplen > DLPI_SAPLEN_MAX) 265 return (DL_BADADDR); 266 267 dataoff = infoackp->dl_addr_offset; 268 datalen = infoackp->dl_addr_length; 269 if (dataoff != 0 && datalen != 0) { 270 datap = (caddr_t)infoackp + dataoff; 271 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 272 return (DLPI_EBADMSG); 273 274 sapp = addrp = (uint8_t *)datap; 275 if (dip->dli_sapbefore) 276 addrp += dip->dli_saplen; 277 else 278 sapp += infop->di_physaddrlen; 279 280 (void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen); 281 infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen); 282 } 283 284 /* Check and save broadcast address information, if any. */ 285 datalen = infoackp->dl_brdcst_addr_length; 286 dataoff = infoackp->dl_brdcst_addr_offset; 287 if (dataoff != 0 && datalen != 0) { 288 datap = (caddr_t)infoackp + dataoff; 289 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp) 290 return (DLPI_EBADMSG); 291 if (datalen != infop->di_physaddrlen) 292 return (DL_BADADDR); 293 294 infop->di_bcastaddrlen = datalen; 295 (void) memcpy(infop->di_bcastaddr, datap, datalen); 296 } 297 298 infop->di_max_sdu = infoackp->dl_max_sdu; 299 infop->di_min_sdu = infoackp->dl_min_sdu; 300 infop->di_state = infoackp->dl_current_state; 301 infop->di_mactype = infoackp->dl_mac_type; 302 303 /* Information retrieved from the handle. */ 304 (void) strlcpy(infop->di_linkname, dip->dli_linkname, 305 sizeof (infop->di_linkname)); 306 infop->di_timeout = dip->dli_timeout; 307 308 return (DLPI_SUCCESS); 309 } 310 311 /* 312 * This function parses 'linkname' and stores the 'provider' name and 'PPA'. 313 */ 314 int 315 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa) 316 { 317 ifspec_t ifsp; 318 319 if (linkname == NULL || !ifparse_ifspec(linkname, &ifsp)) 320 return (DLPI_ELINKNAMEINVAL); 321 322 if (provider != NULL) 323 (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 324 325 if (ppa != NULL) 326 *ppa = ifsp.ifsp_ppa; 327 328 return (DLPI_SUCCESS); 329 } 330 331 /* 332 * This function takes a provider name and a PPA and stores a full linkname 333 * as 'linkname'. If 'provider' already is a full linkname 'provider' name 334 * is stored in 'linkname'. 335 */ 336 int 337 dlpi_makelink(char *linkname, const char *provider, uint_t ppa) 338 { 339 int provlen = strlen(provider); 340 341 if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX) 342 return (DLPI_ELINKNAMEINVAL); 343 344 if (!isdigit(provider[provlen - 1])) { 345 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider, 346 ppa); 347 } else { 348 (void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX); 349 } 350 351 return (DLPI_SUCCESS); 352 } 353 354 int 355 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap) 356 { 357 int retval; 358 dlpi_msg_t req, ack; 359 dl_bind_req_t *bindreqp; 360 dl_bind_ack_t *bindackp; 361 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 362 363 if (dip == NULL) 364 return (DLPI_EINHANDLE); 365 366 DLPI_MSG_CREATE(req, DL_BIND_REQ); 367 DLPI_MSG_CREATE(ack, DL_BIND_ACK); 368 bindreqp = &(req.dlm_msg->bind_req); 369 370 /* 371 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on 372 * other interface types (SAP 0 has special significance on token ring). 373 */ 374 if (sap == DLPI_ANY_SAP) 375 bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0); 376 else 377 bindreqp->dl_sap = sap; 378 379 bindreqp->dl_service_mode = DL_CLDLS; 380 bindreqp->dl_conn_mgmt = 0; 381 bindreqp->dl_max_conind = 0; 382 bindreqp->dl_xidtest_flg = 0; 383 384 retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0); 385 if (retval != DLPI_SUCCESS) 386 return (retval); 387 388 bindackp = &(ack.dlm_msg->bind_ack); 389 /* 390 * Received a DLPI_BIND_ACK, now verify that the bound SAP 391 * is equal to the SAP requested. Some DLPI MAC type may bind 392 * to a different SAP than requested, in this case 'boundsap' 393 * returns the actual bound SAP. For the case where 'boundsap' 394 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails. 395 */ 396 if (boundsap != NULL) { 397 *boundsap = bindackp->dl_sap; 398 } else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) { 399 if (dlpi_unbind(dh) != DLPI_SUCCESS) 400 return (DLPI_FAILURE); 401 else 402 return (DLPI_EUNAVAILSAP); 403 } 404 405 dip->dli_sap = bindackp->dl_sap; /* save sap value in handle */ 406 return (DLPI_SUCCESS); 407 } 408 409 int 410 dlpi_unbind(dlpi_handle_t dh) 411 { 412 dlpi_msg_t req, ack; 413 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 414 415 if (dip == NULL) 416 return (DLPI_EINHANDLE); 417 418 DLPI_MSG_CREATE(req, DL_UNBIND_REQ); 419 DLPI_MSG_CREATE(ack, DL_OK_ACK); 420 421 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 422 } 423 424 /* 425 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and 426 * based on the "op" value, multicast address is enabled/disabled. 427 */ 428 static int 429 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp, 430 size_t addrlen) 431 { 432 dlpi_msg_t req, ack; 433 dl_enabmulti_req_t *multireqp; 434 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 435 436 if (dip == NULL) 437 return (DLPI_EINHANDLE); 438 439 if (addrlen > DLPI_PHYSADDR_MAX) 440 return (DLPI_EINVAL); 441 442 DLPI_MSG_CREATE(req, op); 443 DLPI_MSG_CREATE(ack, DL_OK_ACK); 444 445 multireqp = &(req.dlm_msg->enabmulti_req); 446 multireqp->dl_addr_length = addrlen; 447 multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t); 448 (void) memcpy(&multireqp[1], addrp, addrlen); 449 450 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 451 } 452 453 int 454 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 455 { 456 return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen)); 457 } 458 459 int 460 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen) 461 { 462 return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen)); 463 } 464 465 /* 466 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based 467 * on the value of 'op', promiscuous mode is turned on/off at the specified 468 * 'level'. 469 */ 470 static int 471 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level) 472 { 473 dlpi_msg_t req, ack; 474 dl_promiscon_req_t *promiscreqp; 475 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 476 477 if (dip == NULL) 478 return (DLPI_EINHANDLE); 479 480 DLPI_MSG_CREATE(req, op); 481 DLPI_MSG_CREATE(ack, DL_OK_ACK); 482 483 promiscreqp = &(req.dlm_msg->promiscon_req); 484 promiscreqp->dl_level = level; 485 486 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 487 } 488 489 int 490 dlpi_promiscon(dlpi_handle_t dh, uint_t level) 491 { 492 return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level)); 493 } 494 495 int 496 dlpi_promiscoff(dlpi_handle_t dh, uint_t level) 497 { 498 return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level)); 499 } 500 501 int 502 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp) 503 { 504 int retval; 505 dlpi_msg_t req, ack; 506 dl_phys_addr_req_t *physreqp; 507 dl_phys_addr_ack_t *physackp; 508 t_uscalar_t dataoff, datalen; 509 caddr_t datap, physackendp; 510 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 511 512 if (dip == NULL) 513 return (DLPI_EINHANDLE); 514 515 if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX) 516 return (DLPI_EINVAL); 517 518 DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ); 519 DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK); 520 521 physreqp = &(req.dlm_msg->physaddr_req); 522 physreqp->dl_addr_type = type; 523 524 retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0); 525 if (retval != DLPI_SUCCESS) 526 return (retval); 527 528 /* Received DL_PHYS_ADDR_ACK, store the physical address and length. */ 529 physackp = &(ack.dlm_msg->physaddr_ack); 530 physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz; 531 dataoff = physackp->dl_addr_offset; 532 datalen = physackp->dl_addr_length; 533 if (dataoff != 0 && datalen != 0) { 534 datap = (caddr_t)physackp + dataoff; 535 if (datalen > DLPI_PHYSADDR_MAX) 536 return (DL_BADADDR); 537 if (dataoff < DL_PHYS_ADDR_ACK_SIZE || 538 datap + datalen > physackendp) 539 return (DLPI_EBADMSG); 540 541 *addrlenp = physackp->dl_addr_length; 542 (void) memcpy(addrp, datap, datalen); 543 } else { 544 *addrlenp = datalen; 545 } 546 547 return (DLPI_SUCCESS); 548 } 549 550 int 551 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp, 552 size_t addrlen) 553 { 554 dlpi_msg_t req, ack; 555 dl_set_phys_addr_req_t *setphysreqp; 556 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 557 558 if (dip == NULL) 559 return (DLPI_EINHANDLE); 560 561 if (addrp == NULL || type != DL_CURR_PHYS_ADDR || 562 addrlen > DLPI_PHYSADDR_MAX) 563 return (DLPI_EINVAL); 564 565 DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ); 566 DLPI_MSG_CREATE(ack, DL_OK_ACK); 567 568 setphysreqp = &(req.dlm_msg->set_physaddr_req); 569 setphysreqp->dl_addr_length = addrlen; 570 setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 571 (void) memcpy(&setphysreqp[1], addrp, addrlen); 572 573 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 574 } 575 576 int 577 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen, 578 const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp) 579 { 580 dlpi_msg_t req; 581 dl_unitdata_req_t *udatareqp; 582 uint_t sap; 583 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 584 585 if (dip == NULL) 586 return (DLPI_EINHANDLE); 587 588 if (dip->dli_oflags & DLPI_RAW) 589 return (i_dlpi_strputmsg(dip->dli_fd, NULL, msgbuf, msglen, 0)); 590 591 if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX) 592 return (DLPI_EINVAL); 593 594 DLPI_MSG_CREATE(req, DL_UNITDATA_REQ); 595 udatareqp = &(req.dlm_msg->unitdata_req); 596 597 /* Set priority to default priority range. */ 598 udatareqp->dl_priority.dl_min = 0; 599 udatareqp->dl_priority.dl_max = 0; 600 601 /* Use SAP value if specified otherwise use bound SAP value. */ 602 if (sendp != NULL) { 603 sap = sendp->dsi_sap; 604 if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE) 605 udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min; 606 if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE) 607 udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max; 608 } else { 609 sap = dip->dli_sap; 610 } 611 612 udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen; 613 udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE; 614 615 /* 616 * Since `daddrp' only has the link-layer destination address, 617 * we must prepend or append the SAP (according to dli_sapbefore) 618 * to make a full DLPI address. 619 */ 620 if (dip->dli_sapbefore) { 621 i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen); 622 (void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen, 623 daddrp, daddrlen); 624 } else { 625 (void) memcpy(&udatareqp[1], daddrp, daddrlen); 626 i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap, 627 dip->dli_saplen); 628 } 629 630 return (i_dlpi_strputmsg(dip->dli_fd, &req, msgbuf, msglen, 0)); 631 } 632 633 int 634 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf, 635 size_t *msglenp, int msec, dlpi_recvinfo_t *recvp) 636 { 637 int retval; 638 dlpi_msg_t ind; 639 size_t totmsglen; 640 dl_unitdata_ind_t *udatap; 641 t_uscalar_t dataoff, datalen; 642 caddr_t datap, indendp; 643 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 644 645 if (dip == NULL) 646 return (DLPI_EINHANDLE); 647 /* 648 * If handle is in raw mode ignore everything except total message 649 * length. 650 */ 651 if (dip->dli_oflags & DLPI_RAW) { 652 retval = i_dlpi_strgetmsg(dip->dli_fd, msec, NULL, 0, 0, 0, 653 msgbuf, msglenp, &totmsglen); 654 655 if (retval == DLPI_SUCCESS && recvp != NULL) 656 recvp->dri_totmsglen = totmsglen; 657 return (retval); 658 } 659 660 DLPI_MSG_CREATE(ind, DL_UNITDATA_IND); 661 udatap = &(ind.dlm_msg->unitdata_ind); 662 indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz; 663 664 if ((retval = i_dlpi_strgetmsg(dip->dli_fd, msec, &ind, 665 DL_UNITDATA_IND, DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, 666 msgbuf, msglenp, &totmsglen)) != DLPI_SUCCESS) 667 return (retval); 668 669 /* 670 * If DLPI link provides source address, store source address in 671 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0. 672 */ 673 if (saddrp != NULL && saddrlenp != NULL) { 674 if (*saddrlenp < DLPI_PHYSADDR_MAX) 675 return (DLPI_EINVAL); 676 677 dataoff = udatap->dl_src_addr_offset; 678 datalen = udatap->dl_src_addr_length; 679 if (dataoff != 0 && datalen != 0) { 680 datap = (caddr_t)udatap + dataoff; 681 if (dataoff < DL_UNITDATA_IND_SIZE || 682 datap + datalen > indendp) 683 return (DLPI_EBADMSG); 684 685 *saddrlenp = datalen - dip->dli_saplen; 686 if (*saddrlenp > DLPI_PHYSADDR_MAX) 687 return (DL_BADADDR); 688 689 if (dip->dli_sapbefore) 690 datap += dip->dli_saplen; 691 (void) memcpy(saddrp, datap, *saddrlenp); 692 } else { 693 *saddrlenp = 0; 694 } 695 } 696 697 /* 698 * If destination address requested, check and save destination 699 * address, if any. 700 */ 701 if (recvp != NULL) { 702 dataoff = udatap->dl_dest_addr_offset; 703 datalen = udatap->dl_dest_addr_length; 704 if (dataoff != 0 && datalen != 0) { 705 datap = (caddr_t)udatap + dataoff; 706 if (dataoff < DL_UNITDATA_IND_SIZE || 707 datap + datalen > indendp) 708 return (DLPI_EBADMSG); 709 710 recvp->dri_destaddrlen = datalen - dip->dli_saplen; 711 if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX) 712 return (DL_BADADDR); 713 714 if (dip->dli_sapbefore) 715 datap += dip->dli_saplen; 716 (void) memcpy(recvp->dri_destaddr, datap, 717 recvp->dri_destaddrlen); 718 } else { 719 recvp->dri_destaddrlen = 0; 720 } 721 722 recvp->dri_destaddrtype = udatap->dl_group_address; 723 recvp->dri_totmsglen = totmsglen; 724 } 725 726 return (DLPI_SUCCESS); 727 } 728 729 int 730 dlpi_fd(dlpi_handle_t dh) 731 { 732 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 733 734 return (dip != NULL ? dip->dli_fd : -1); 735 } 736 737 int 738 dlpi_set_timeout(dlpi_handle_t dh, int sec) 739 { 740 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 741 742 if (dip == NULL) 743 return (DLPI_EINHANDLE); 744 745 dip->dli_timeout = sec; 746 return (DLPI_SUCCESS); 747 } 748 749 const char * 750 dlpi_linkname(dlpi_handle_t dh) 751 { 752 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 753 754 return (dip != NULL ? dip->dli_linkname : NULL); 755 } 756 757 /* 758 * Returns DLPI style stored in the handle. 759 * Note: This function is used for test purposes only. Do not remove without 760 * fixing the DLPI testsuite. 761 */ 762 uint_t 763 dlpi_style(dlpi_handle_t dh) 764 { 765 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 766 767 return (dip->dli_style); 768 } 769 770 uint_t 771 dlpi_arptype(uint_t dlpitype) 772 { 773 switch (dlpitype) { 774 775 case DL_ETHER: 776 return (ARPHRD_ETHER); 777 778 case DL_FRAME: 779 return (ARPHRD_FRAME); 780 781 case DL_ATM: 782 return (ARPHRD_ATM); 783 784 case DL_IPATM: 785 return (ARPHRD_IPATM); 786 787 case DL_HDLC: 788 return (ARPHRD_HDLC); 789 790 case DL_FC: 791 return (ARPHRD_FC); 792 793 case DL_CSMACD: /* ieee 802 networks */ 794 case DL_TPB: 795 case DL_TPR: 796 case DL_METRO: 797 case DL_FDDI: 798 return (ARPHRD_IEEE802); 799 800 case DL_IB: 801 return (ARPHRD_IB); 802 803 case DL_IPV4: 804 case DL_IPV6: 805 return (ARPHRD_TUNNEL); 806 } 807 808 return (0); 809 } 810 811 uint_t 812 dlpi_iftype(uint_t dlpitype) 813 { 814 switch (dlpitype) { 815 816 case DL_ETHER: 817 return (IFT_ETHER); 818 819 case DL_ATM: 820 return (IFT_ATM); 821 822 case DL_CSMACD: 823 return (IFT_ISO88023); 824 825 case DL_TPB: 826 return (IFT_ISO88024); 827 828 case DL_TPR: 829 return (IFT_ISO88025); 830 831 case DL_FDDI: 832 return (IFT_FDDI); 833 834 case DL_IB: 835 return (IFT_IB); 836 837 case DL_OTHER: 838 return (IFT_OTHER); 839 } 840 841 return (0); 842 } 843 844 /* 845 * This function attempts to open linkname under the following namespaces: 846 * - /dev 847 * - /devices 848 * If open doesn't succeed and link doesn't exist (ENOENT), this function 849 * returns DLPI_ENOLINK, otherwise returns DL_SYSERR. 850 */ 851 static int 852 i_dlpi_open(const char *provider, int *fd, uint_t flags) 853 { 854 char path[MAXPATHLEN]; 855 int oflags; 856 857 oflags = O_RDWR; 858 if (flags & DLPI_EXCL) 859 oflags |= O_EXCL; 860 861 (void) snprintf(path, sizeof (path), "/dev/%s", provider); 862 863 if ((*fd = open(path, oflags)) != -1) 864 return (DLPI_SUCCESS); 865 866 /* 867 * On diskless boot, it's possible the /dev links have not yet 868 * been created; fallback to /devices. When /dev links are 869 * created on demand, this code can be removed. 870 */ 871 (void) snprintf(path, sizeof (path), "/devices/pseudo/clone@0:%s", 872 provider); 873 874 if ((*fd = open(path, oflags)) != -1) 875 return (DLPI_SUCCESS); 876 877 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 878 } 879 880 /* 881 * Open a style 1 link. PPA is implicitly attached. 882 */ 883 static int 884 i_dlpi_style1_open(dlpi_impl_t *dip) 885 { 886 int retval, save_errno; 887 int fd; 888 889 /* 890 * In order to support open of syntax like device[.module[.module...]] 891 * where modules need to be pushed onto the device stream, open only 892 * device name, otherwise open the full linkname. 893 */ 894 retval = i_dlpi_open((dip->dli_mod_cnt != 0) ? dip->dli_provider : 895 dip->dli_linkname, &fd, dip->dli_oflags); 896 897 if (retval != DLPI_SUCCESS) { 898 dip->dli_mod_pushed = 0; 899 return (retval); 900 } 901 dip->dli_fd = fd; 902 903 /* 904 * Try to push modules (if any) onto the device stream. If I_PUSH 905 * fails, we increment count of modules pushed (dli_mod_pushed) 906 * expecting it is last module to be pushed and thus will be pushed 907 * in i_dlpi_style2_open(). 908 */ 909 for (dip->dli_mod_pushed = 0; dip->dli_mod_pushed < dip->dli_mod_cnt; 910 dip->dli_mod_pushed++) { 911 if (ioctl(fd, I_PUSH, 912 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 913 dip->dli_mod_pushed++; 914 return (DLPI_FAILURE); 915 } 916 } 917 918 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) { 919 save_errno = errno; 920 (void) close(dip->dli_fd); 921 errno = save_errno; 922 dip->dli_mod_pushed = 0; 923 return (retval); 924 } 925 926 return (DLPI_SUCCESS); 927 } 928 929 /* 930 * Open a style 2 link. PPA must be explicitly attached. 931 */ 932 static int 933 i_dlpi_style2_open(dlpi_impl_t *dip) 934 { 935 int fd; 936 int retval, save_errno; 937 938 /* 939 * If style 1 open failed, we need to determine how far it got and 940 * finish up the open() call as a style 2 open. 941 * 942 * If no modules were pushed (mod_pushed == 0), then we need to 943 * open it as a style 2 link. 944 * 945 * If the pushing of the last module failed, we need to 946 * try pushing it as a style 2 module. Decrement dli_mod_pushed 947 * count so it can be pushed onto the stream. 948 * 949 * Otherwise we failed during the push of an intermediate module and 950 * must fail out and close the link. 951 */ 952 if (dip->dli_mod_pushed == 0) { 953 if ((retval = i_dlpi_open(dip->dli_provider, &fd, 954 dip->dli_oflags)) != DLPI_SUCCESS) 955 return (retval); 956 957 dip->dli_fd = fd; 958 } else if (dip->dli_mod_pushed == dip->dli_mod_cnt) { 959 if (i_dlpi_remove_ppa(dip->dli_modlist[dip->dli_mod_cnt - 1]) 960 != DLPI_SUCCESS) 961 return (DLPI_ELINKNAMEINVAL); 962 963 dip->dli_mod_pushed--; 964 fd = dip->dli_fd; 965 } else { 966 return (DLPI_ELINKNAMEINVAL); 967 } 968 969 /* Try and push modules (if any) onto the device stream. */ 970 for (; dip->dli_mod_pushed < dip->dli_mod_cnt; dip->dli_mod_pushed++) { 971 if (ioctl(fd, I_PUSH, 972 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 973 retval = DL_SYSERR; 974 goto failure; 975 } 976 } 977 978 /* 979 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a 980 * DLPI link so attach and ignore rest. 981 */ 982 if (dip->dli_oflags & DLPI_SERIAL) 983 goto attach; 984 985 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS) 986 goto failure; 987 988 /* 989 * Succeeded opening the link and verified it is style2. Now attach to 990 * PPA only if DLPI_NOATTACH is not set. 991 */ 992 if (dip->dli_oflags & DLPI_NOATTACH) 993 return (DLPI_SUCCESS); 994 995 attach: 996 if ((retval = i_dlpi_attach(dip)) != DLPI_SUCCESS) 997 goto failure; 998 999 return (DLPI_SUCCESS); 1000 1001 failure: 1002 save_errno = errno; 1003 (void) close(dip->dli_fd); 1004 errno = save_errno; 1005 return (retval); 1006 } 1007 1008 /* 1009 * Verify with DLPI that the link is the expected DLPI 'style' device, 1010 * dlpi_info sets the DLPI style in the DLPI handle. 1011 */ 1012 static int 1013 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style) 1014 { 1015 int retval; 1016 dlpi_info_t dlinfo; 1017 1018 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0); 1019 if (retval == DLPI_SUCCESS && dip->dli_style != style) 1020 retval = DLPI_EBADLINK; 1021 1022 return (retval); 1023 } 1024 1025 /* 1026 * Remove PPA from end of linkname. 1027 * Return DLPI_SUCCESS if found, else return DLPI_FAILURE. 1028 */ 1029 static int 1030 i_dlpi_remove_ppa(char *linkname) 1031 { 1032 int i = strlen(linkname) - 1; 1033 1034 if (i == -1 || !isdigit(linkname[i--])) 1035 return (DLPI_FAILURE); 1036 1037 while (i >= 0 && isdigit(linkname[i])) 1038 i--; 1039 1040 linkname[i + 1] = '\0'; 1041 return (DLPI_SUCCESS); 1042 } 1043 1044 /* 1045 * For DLPI style 2 providers, an explicit attach of PPA is required. 1046 */ 1047 static int 1048 i_dlpi_attach(dlpi_impl_t *dip) 1049 { 1050 dlpi_msg_t req, ack; 1051 dl_attach_req_t *attachreqp; 1052 1053 /* 1054 * Special case: DLPI_SERIAL flag (synchronous serial lines) 1055 * is not a DLPI link so ignore DLPI style. 1056 */ 1057 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL)) 1058 return (DLPI_ENOTSTYLE2); 1059 1060 DLPI_MSG_CREATE(req, DL_ATTACH_REQ); 1061 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1062 1063 attachreqp = &(req.dlm_msg->attach_req); 1064 attachreqp->dl_ppa = dip->dli_ppa; 1065 1066 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 1067 } 1068 1069 /* 1070 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care 1071 * if this request fails, as this indicates the underlying DLPI device does 1072 * not support link aggregation (pre-GLDV3 device drivers), and thus will 1073 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing 1074 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p). 1075 */ 1076 static void 1077 i_dlpi_passive(dlpi_impl_t *dip) 1078 { 1079 dlpi_msg_t req, ack; 1080 1081 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ); 1082 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1083 1084 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0); 1085 } 1086 1087 /* 1088 * Send a dlpi control message and/or data message on a stream. The inputs 1089 * for this function are: 1090 * int fd: file descriptor of open stream to send message 1091 * const dlpi_msg_t *dlreqp: request message structure 1092 * void *databuf: data buffer 1093 * size_t datalen: data buffer len 1094 * int flags: flags to set for putmsg() 1095 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure. 1096 */ 1097 static int 1098 i_dlpi_strputmsg(int fd, const dlpi_msg_t *dlreqp, 1099 const void *databuf, size_t datalen, int flags) 1100 { 1101 int retval; 1102 struct strbuf ctl; 1103 struct strbuf data; 1104 1105 if (dlreqp != NULL) { 1106 ctl.buf = (void *)dlreqp->dlm_msg; 1107 ctl.len = dlreqp->dlm_msgsz; 1108 } 1109 1110 data.buf = (void *)databuf; 1111 data.len = datalen; 1112 1113 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl), 1114 (databuf == NULL ? NULL : &data), flags); 1115 1116 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR); 1117 } 1118 1119 /* 1120 * Get a DLPI control message and/or data message from a stream. The inputs 1121 * for this function are: 1122 * int fd: file descriptor of open stream 1123 * int msec: timeout to wait for message 1124 * dlpi_msg_t *dlreplyp: reply message structure, the message size 1125 * member on return stores actual size received 1126 * t_uscalar_t dlreqprim: requested primitive 1127 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request 1128 * size_t dlreplyminsz: minimum size of acknowledged primitive size 1129 * void *databuf: data buffer 1130 * size_t *datalenp: data buffer len 1131 * size_t *totdatalenp: total data received. Greater than 'datalenp' if 1132 * actual data received is larger than 'databuf' 1133 * Function returns DLPI_SUCCESS if requested message is retrieved 1134 * otherwise returns error code or timeouts. 1135 */ 1136 static int 1137 i_dlpi_strgetmsg(int fd, int msec, dlpi_msg_t *dlreplyp, t_uscalar_t dlreqprim, 1138 t_uscalar_t dlreplyprim, size_t dlreplyminsz, void *databuf, 1139 size_t *datalenp, size_t *totdatalenp) 1140 { 1141 int retval; 1142 int flags = 0; 1143 struct strbuf ctl, data; 1144 struct pollfd pfd; 1145 hrtime_t start, current; 1146 long bufc[DLPI_CHUNKSIZE / sizeof (long)]; 1147 long bufd[DLPI_CHUNKSIZE / sizeof (long)]; 1148 union DL_primitives *dlprim; 1149 boolean_t infinite = (msec < 0); /* infinite timeout */ 1150 1151 if ((dlreplyp == NULL && databuf == NULL) || 1152 (databuf == NULL && datalenp != NULL) || 1153 (databuf != NULL && datalenp == NULL)) 1154 return (DLPI_EINVAL); 1155 1156 pfd.fd = fd; 1157 pfd.events = POLLIN | POLLPRI; 1158 1159 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg; 1160 ctl.len = 0; 1161 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz; 1162 1163 data.buf = (databuf == NULL) ? bufd : databuf; 1164 data.len = 0; 1165 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp; 1166 1167 for (;;) { 1168 if (!infinite) 1169 start = gethrtime() / (NANOSEC / MILLISEC); 1170 1171 switch (poll(&pfd, 1, msec)) { 1172 default: 1173 if (pfd.revents & POLLHUP) 1174 return (DL_SYSERR); 1175 break; 1176 case 0: 1177 return (DLPI_ETIMEDOUT); 1178 case -1: 1179 return (DL_SYSERR); 1180 } 1181 1182 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0) 1183 return (DL_SYSERR); 1184 1185 if (totdatalenp != NULL) 1186 *totdatalenp = data.len; 1187 1188 /* 1189 * The supplied DLPI_CHUNKSIZE sized buffers are large enough 1190 * to retrieve all valid DLPI responses in one iteration. 1191 * If MORECTL or MOREDATA is set, we are not interested in the 1192 * remainder of the message. Temporary buffers are used to 1193 * drain the remainder of this message. 1194 * The special case we have to account for is if 1195 * a higher priority messages is enqueued whilst handling 1196 * this condition. We use a change in the flags parameter 1197 * returned by getmsg() to indicate the message has changed. 1198 */ 1199 while (retval & (MORECTL | MOREDATA)) { 1200 struct strbuf cscratch, dscratch; 1201 int oflags = flags; 1202 1203 cscratch.buf = (char *)bufc; 1204 dscratch.buf = (char *)bufd; 1205 cscratch.len = dscratch.len = 0; 1206 cscratch.maxlen = dscratch.maxlen = 1207 sizeof (bufc); 1208 1209 if ((retval = getmsg(fd, &cscratch, &dscratch, 1210 &flags)) < 0) 1211 return (DL_SYSERR); 1212 1213 if (totdatalenp != NULL) 1214 *totdatalenp += dscratch.len; 1215 /* 1216 * In the special case of higher priority 1217 * message received, the low priority message 1218 * received earlier is discarded, if no data 1219 * or control message is left. 1220 */ 1221 if ((flags != oflags) && 1222 !(retval & (MORECTL | MOREDATA)) && 1223 (cscratch.len != 0)) { 1224 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE); 1225 if (dlreplyp != NULL) 1226 (void) memcpy(dlreplyp->dlm_msg, bufc, 1227 ctl.len); 1228 break; 1229 } 1230 } 1231 1232 /* 1233 * If we were expecting a data message, and we got one, set 1234 * *datalenp. If we aren't waiting on a control message, then 1235 * we're done. 1236 */ 1237 if (databuf != NULL && data.len >= 0) { 1238 *datalenp = data.len; 1239 if (dlreplyp == NULL) 1240 break; 1241 } 1242 1243 /* 1244 * If we were expecting a control message, and the message 1245 * we received is at least big enough to be a DLPI message, 1246 * then verify it's a reply to something we sent. If it 1247 * is a reply to something we sent, also verify its size. 1248 */ 1249 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) { 1250 dlprim = dlreplyp->dlm_msg; 1251 if (dlprim->dl_primitive == dlreplyprim) { 1252 if (ctl.len < dlreplyminsz) 1253 return (DLPI_EBADMSG); 1254 dlreplyp->dlm_msgsz = ctl.len; 1255 break; 1256 } else if (dlprim->dl_primitive == DL_ERROR_ACK) { 1257 if (ctl.len < DL_ERROR_ACK_SIZE) 1258 return (DLPI_EBADMSG); 1259 1260 /* Is it ours? */ 1261 if (dlprim->error_ack.dl_error_primitive == 1262 dlreqprim) 1263 break; 1264 } 1265 } 1266 1267 if (!infinite) { 1268 current = gethrtime() / (NANOSEC / MILLISEC); 1269 msec -= (current - start); 1270 1271 if (msec <= 0) 1272 return (DLPI_ETIMEDOUT); 1273 } 1274 } 1275 1276 return (DLPI_SUCCESS); 1277 } 1278 1279 /* 1280 * Common routine invoked by all DLPI control routines. The inputs for this 1281 * function are: 1282 * dlpi_impl_t *dip: internal dlpi handle 1283 * const dlpi_msg_t *dlreqp: request message structure 1284 * dlpi_msg_t *dlreplyp: reply message structure 1285 * size_t dlreplyminsz: minimum size of reply primitive 1286 * int flags: flags to be set to send a message 1287 * This routine succeeds if the message is an expected request/acknowledged 1288 * message. Unexpected asynchronous messages (e.g. unexpected DL_NOTIFY_IND 1289 * messages) will be discarded. 1290 */ 1291 static int 1292 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1293 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags) 1294 { 1295 int retval; 1296 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive; 1297 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive; 1298 1299 /* Put the requested primitive on the stream. */ 1300 retval = i_dlpi_strputmsg(dip->dli_fd, dlreqp, NULL, 0, flags); 1301 if (retval != DLPI_SUCCESS) 1302 return (retval); 1303 1304 /* Retrieve acknowledged message for requested primitive. */ 1305 retval = i_dlpi_strgetmsg(dip->dli_fd, (dip->dli_timeout * MILLISEC), 1306 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL); 1307 if (retval != DLPI_SUCCESS) 1308 return (retval); 1309 1310 /* 1311 * If primitive is DL_ERROR_ACK, set errno. 1312 */ 1313 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) { 1314 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno; 1315 retval = dlreplyp->dlm_msg->error_ack.dl_errno; 1316 } 1317 1318 return (retval); 1319 } 1320 1321 /* 1322 * DLPI error codes. 1323 */ 1324 static const char *dlpi_errlist[] = { 1325 "bad LSAP selector", /* DL_BADSAP 0x00 */ 1326 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */ 1327 "improper permissions for request", /* DL_ACCESS 0x02 */ 1328 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */ 1329 NULL, /* DL_SYSERR 0x04 */ 1330 "sequence number not from outstanding DL_CONN_IND", 1331 /* DL_BADCORR 0x05 */ 1332 "user data exceeded provider limit", /* DL_BADDATA 0x06 */ 1333 "requested service not supplied by provider", 1334 /* DL_UNSUPPORTED 0x07 */ 1335 "specified PPA was invalid", /* DL_BADPPA 0x08 */ 1336 "primitive received not known by provider", /* DL_BADPRIM 0x09 */ 1337 "QoS parameters contained invalid values", 1338 /* DL_BADQOSPARAM 0x0a */ 1339 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */ 1340 "token used not an active stream", /* DL_BADTOKEN 0x0c */ 1341 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */ 1342 "physical link initialization failed", /* DL_INITFAILED 0x0e */ 1343 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */ 1344 "physical link not initialized", /* DL_NOTINIT 0x10 */ 1345 "previous data unit could not be delivered", 1346 /* DL_UNDELIVERABLE 0x11 */ 1347 "primitive is known but unsupported", 1348 /* DL_NOTSUPPORTED 0x12 */ 1349 "limit exceeded", /* DL_TOOMANY 0x13 */ 1350 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */ 1351 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */ 1352 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */ 1353 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */ 1354 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */ 1355 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */ 1356 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */ 1357 "pending outstanding connect indications" /* DL_PENDING 0x1b */ 1358 }; 1359 1360 /* 1361 * libdlpi error codes. 1362 */ 1363 static const char *libdlpi_errlist[] = { 1364 "DLPI operation succeeded", /* DLPI_SUCCESS */ 1365 "invalid argument", /* DLPI_EINVAL */ 1366 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */ 1367 "DLPI link does not exist", /* DLPI_ENOLINK */ 1368 "bad DLPI link", /* DLPI_EBADLINK */ 1369 "invalid DLPI handle", /* DLPI_EINHANDLE */ 1370 "DLPI operation timed out", /* DLPI_ETIMEDOUT */ 1371 "unsupported DLPI version", /* DLPI_EVERNOTSUP */ 1372 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */ 1373 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */ 1374 "DLPI operation failed", /* DLPI_FAILURE */ 1375 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */ 1376 "bad DLPI message", /* DLPI_EBADMSG */ 1377 "DLPI raw mode not supported" /* DLPI_ERAWNOTSUP */ 1378 }; 1379 1380 const char * 1381 dlpi_strerror(int err) 1382 { 1383 if (err == DL_SYSERR) 1384 return (strerror(errno)); 1385 else if (err >= 0 && err < NELEMS(dlpi_errlist)) 1386 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err])); 1387 else if (err > DLPI_SUCCESS && err < DLPI_ERRMAX) 1388 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err - 1389 DLPI_SUCCESS])); 1390 else 1391 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error")); 1392 } 1393 1394 /* 1395 * Each table entry comprises a DLPI/Private mactype and the description. 1396 */ 1397 static const dlpi_mactype_t dlpi_mactypes[] = { 1398 { DL_CSMACD, "CSMA/CD" }, 1399 { DL_TPB, "Token Bus" }, 1400 { DL_TPR, "Token Ring" }, 1401 { DL_METRO, "Metro Net" }, 1402 { DL_ETHER, "Ethernet" }, 1403 { DL_HDLC, "HDLC" }, 1404 { DL_CHAR, "Sync Character" }, 1405 { DL_CTCA, "CTCA" }, 1406 { DL_FDDI, "FDDI" }, 1407 { DL_FRAME, "Frame Relay (LAPF)" }, 1408 { DL_MPFRAME, "MP Frame Relay" }, 1409 { DL_ASYNC, "Async Character" }, 1410 { DL_IPX25, "X.25 (Classic IP)" }, 1411 { DL_LOOP, "Software Loopback" }, 1412 { DL_FC, "Fiber Channel" }, 1413 { DL_ATM, "ATM" }, 1414 { DL_IPATM, "ATM (Classic IP)" }, 1415 { DL_X25, "X.25 (LAPB)" }, 1416 { DL_ISDN, "ISDN" }, 1417 { DL_HIPPI, "HIPPI" }, 1418 { DL_100VG, "100BaseVG Ethernet" }, 1419 { DL_100VGTPR, "100BaseVG Token Ring" }, 1420 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" }, 1421 { DL_100BT, "100BaseT" }, 1422 { DL_IB, "Infiniband" }, 1423 { DL_IPV4, "IPv4 Tunnel" }, 1424 { DL_IPV6, "IPv6 Tunnel" }, 1425 { DL_WIFI, "IEEE 802.11" } 1426 }; 1427 1428 const char * 1429 dlpi_mactype(uint_t mactype) 1430 { 1431 int i; 1432 1433 for (i = 0; i < NELEMS(dlpi_mactypes); i++) { 1434 if (dlpi_mactypes[i].dm_mactype == mactype) 1435 return (dlpi_mactypes[i].dm_desc); 1436 } 1437 1438 return ("Unknown MAC Type"); 1439 } 1440 1441 /* 1442 * Each table entry comprises a DLPI primitive and the maximum buffer 1443 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details). 1444 */ 1445 static const dlpi_primsz_t dlpi_primsizes[] = { 1446 { DL_INFO_REQ, DL_INFO_REQ_SIZE }, 1447 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) + 1448 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))}, 1449 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE }, 1450 { DL_BIND_REQ, DL_BIND_REQ_SIZE }, 1451 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX + 1452 DLPI_SAPLEN_MAX }, 1453 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE }, 1454 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1455 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1456 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE }, 1457 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE }, 1458 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE }, 1459 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX + 1460 DLPI_SAPLEN_MAX }, 1461 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX + 1462 DLPI_SAPLEN_MAX)) }, 1463 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE }, 1464 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX }, 1465 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1466 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) } 1467 }; 1468 1469 /* 1470 * Refers to the dlpi_primsizes[] table to return corresponding maximum 1471 * buffer size. 1472 */ 1473 static size_t 1474 i_dlpi_getprimsize(t_uscalar_t prim) 1475 { 1476 int i; 1477 1478 for (i = 0; i < NELEMS(dlpi_primsizes); i++) { 1479 if (dlpi_primsizes[i].dp_prim == prim) 1480 return (dlpi_primsizes[i].dp_primsz); 1481 } 1482 1483 return (sizeof (t_uscalar_t)); 1484 } 1485 1486 /* 1487 * sap values vary in length and are in host byte order, build sap value 1488 * by writing saplen bytes, so that the sap value is left aligned. 1489 */ 1490 static uint_t 1491 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen) 1492 { 1493 int i; 1494 uint_t sap = 0; 1495 1496 #ifdef _LITTLE_ENDIAN 1497 for (i = saplen - 1; i >= 0; i--) { 1498 #else 1499 for (i = 0; i < saplen; i++) { 1500 #endif 1501 sap <<= 8; 1502 sap |= sapp[i]; 1503 } 1504 1505 return (sap); 1506 } 1507 1508 /* 1509 * Copy sap value to a buffer in host byte order. saplen is the number of 1510 * bytes to copy. 1511 */ 1512 static void 1513 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen) 1514 { 1515 uint8_t *sapp; 1516 1517 #ifdef _LITTLE_ENDIAN 1518 sapp = (uint8_t *)&sap; 1519 #else 1520 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen); 1521 #endif 1522 1523 (void) memcpy(dstbuf, sapp, saplen); 1524 } 1525