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