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