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