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