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