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