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