1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Data-Link Provider Interface (Version 2) 28 */ 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <poll.h> 37 #include <stropts.h> 38 #include <sys/dlpi.h> 39 #include <errno.h> 40 #include <alloca.h> 41 #include <sys/sysmacros.h> 42 #include <ctype.h> 43 #include <net/if_types.h> 44 #include <netinet/arp.h> 45 #include <libdladm.h> 46 #include <libdllink.h> 47 #include <libdlpi.h> 48 #include <libintl.h> 49 #include <libinetutil.h> 50 #include <dirent.h> 51 52 #include "libdlpi_impl.h" 53 54 static int i_dlpi_open(const char *, int *, uint_t, boolean_t); 55 static int i_dlpi_style1_open(dlpi_impl_t *); 56 static int i_dlpi_style2_open(dlpi_impl_t *); 57 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t); 58 static int i_dlpi_remove_ppa(char *); 59 static int i_dlpi_attach(dlpi_impl_t *); 60 static void i_dlpi_passive(dlpi_impl_t *); 61 62 static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *, 63 size_t, int); 64 static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t, 65 t_uscalar_t, size_t, void *, size_t *, size_t *); 66 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *, 67 size_t, int); 68 69 static size_t i_dlpi_getprimsize(t_uscalar_t); 70 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t); 71 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t); 72 static uint_t i_dlpi_buildsap(uint8_t *, uint_t); 73 static void i_dlpi_writesap(void *, uint_t, uint_t); 74 static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *); 75 static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *); 76 static void i_dlpi_deletenotifyid(dlpi_impl_t *); 77 78 struct i_dlpi_walklink_arg { 79 dlpi_walkfunc_t *fn; 80 void *arg; 81 }; 82 83 static int 84 i_dlpi_walk_link(const char *name, void *arg) 85 { 86 struct i_dlpi_walklink_arg *warg = arg; 87 88 return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE : 89 DLADM_WALK_CONTINUE); 90 } 91 92 /*ARGSUSED*/ 93 void 94 dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags) 95 { 96 struct i_dlpi_walklink_arg warg; 97 struct dirent *d; 98 DIR *dp; 99 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 if (dlinfo.di_state != DL_IDLE) 839 return (DL_OUTSTATE); 840 841 if (dip->dli_note_processing) 842 return (DLPI_FAILURE); 843 844 if (funcp == NULL || id == NULL) 845 return (DLPI_EINVAL); 846 847 if ((~DLPI_NOTIFICATION_TYPES & notes) || 848 !(notes & DLPI_NOTIFICATION_TYPES)) 849 return (DLPI_ENOTEINVAL); 850 851 DLPI_MSG_CREATE(req, DL_NOTIFY_REQ); 852 DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK); 853 854 notifyreqp = &(req.dlm_msg->notify_req); 855 notifyreqp->dl_notifications = notes; 856 notifyreqp->dl_timelimit = 0; 857 858 retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0); 859 if (retval == DL_NOTSUPPORTED) 860 return (DLPI_ENOTENOTSUP); 861 862 if (retval != DLPI_SUCCESS) 863 return (retval); 864 865 if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL) 866 return (DL_SYSERR); 867 868 /* Register notification information. */ 869 newnotifp->dln_fnp = funcp; 870 newnotifp->dln_notes = notes; 871 newnotifp->arg = arg; 872 newnotifp->dln_rm = B_FALSE; 873 874 /* Insert notification node at head */ 875 newnotifp->dln_next = dip->dli_notifylistp; 876 dip->dli_notifylistp = newnotifp; 877 878 *id = (dlpi_notifyid_t)newnotifp; 879 return (DLPI_SUCCESS); 880 } 881 882 int 883 dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp) 884 { 885 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 886 dlpi_notifyent_t *remid = (dlpi_notifyent_t *)id; 887 888 if (dip == NULL) 889 return (DLPI_EINHANDLE); 890 891 /* Walk the notifyentry list to find matching id. */ 892 if (!(i_dlpi_notifyidexists(dip, remid))) 893 return (DLPI_ENOTEIDINVAL); 894 895 if (argp != NULL) 896 *argp = remid->arg; 897 898 remid->dln_rm = B_TRUE; 899 /* Delete node if callbacks are not being processed. */ 900 if (!dip->dli_note_processing) 901 i_dlpi_deletenotifyid(dip); 902 903 return (DLPI_SUCCESS); 904 } 905 906 int 907 dlpi_fd(dlpi_handle_t dh) 908 { 909 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 910 911 return (dip != NULL ? dip->dli_fd : -1); 912 } 913 914 int 915 dlpi_set_timeout(dlpi_handle_t dh, int sec) 916 { 917 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 918 919 if (dip == NULL) 920 return (DLPI_EINHANDLE); 921 922 dip->dli_timeout = sec; 923 return (DLPI_SUCCESS); 924 } 925 926 const char * 927 dlpi_linkname(dlpi_handle_t dh) 928 { 929 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 930 931 return (dip != NULL ? dip->dli_linkname : NULL); 932 } 933 934 /* 935 * Returns DLPI style stored in the handle. 936 * Note: This function is used for test purposes only. Do not remove without 937 * fixing the DLPI testsuite. 938 */ 939 uint_t 940 dlpi_style(dlpi_handle_t dh) 941 { 942 dlpi_impl_t *dip = (dlpi_impl_t *)dh; 943 944 return (dip->dli_style); 945 } 946 947 uint_t 948 dlpi_arptype(uint_t dlpitype) 949 { 950 switch (dlpitype) { 951 952 case DL_ETHER: 953 return (ARPHRD_ETHER); 954 955 case DL_FRAME: 956 return (ARPHRD_FRAME); 957 958 case DL_ATM: 959 return (ARPHRD_ATM); 960 961 case DL_IPATM: 962 return (ARPHRD_IPATM); 963 964 case DL_HDLC: 965 return (ARPHRD_HDLC); 966 967 case DL_FC: 968 return (ARPHRD_FC); 969 970 case DL_CSMACD: /* ieee 802 networks */ 971 case DL_TPB: 972 case DL_TPR: 973 case DL_METRO: 974 case DL_FDDI: 975 return (ARPHRD_IEEE802); 976 977 case DL_IB: 978 return (ARPHRD_IB); 979 980 case DL_IPV4: 981 case DL_IPV6: 982 return (ARPHRD_TUNNEL); 983 } 984 985 return (0); 986 } 987 988 uint_t 989 dlpi_iftype(uint_t dlpitype) 990 { 991 switch (dlpitype) { 992 993 case DL_ETHER: 994 return (IFT_ETHER); 995 996 case DL_ATM: 997 return (IFT_ATM); 998 999 case DL_CSMACD: 1000 return (IFT_ISO88023); 1001 1002 case DL_TPB: 1003 return (IFT_ISO88024); 1004 1005 case DL_TPR: 1006 return (IFT_ISO88025); 1007 1008 case DL_FDDI: 1009 return (IFT_FDDI); 1010 1011 case DL_IB: 1012 return (IFT_IB); 1013 1014 case DL_OTHER: 1015 return (IFT_OTHER); 1016 } 1017 1018 return (0); 1019 } 1020 1021 /* 1022 * This function attempts to open a device under the following namespaces: 1023 * /dev/ipnet - if DLPI_DEVIPNET is specified 1024 * /dev/net - if a data-link with the specified name exists 1025 * /dev - if DLPI_DEVONLY is specified, or if there is no 1026 * data-link with the specified name (could be /dev/ip) 1027 * 1028 * In particular, if DLPI_DEVIPNET is not specified, this function is used to 1029 * open a data-link node, or "/dev/ip" node. It is usually be called firstly 1030 * with style1 being B_TRUE, and if that fails and the return value is not 1031 * DLPI_ENOTSTYLE2, the function will again be called with style1 being 1032 * B_FALSE (style-1 open attempt first, then style-2 open attempt). 1033 * 1034 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node 1035 * directly. 1036 * 1037 * Otherwise, for style-1 attempt, the function will try to open the style-1 1038 * /dev/net node, and perhaps fallback to open the style-1 /dev node if the 1039 * give name is not a data-link name (e.g., it is /dev/ip). Note that the 1040 * fallback and the subsequent style-2 attempt will not happen if: 1041 * 1. style-1 opening of the /dev/net node succeeds; 1042 * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT, 1043 * which means that the specific /dev/net node exist, but the attempt fails 1044 * for some other reason; 1045 * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is 1046 * a known device name or its VLAN PPA hack name. (for example, assuming 1047 * device bge0 is renamed to net0, opening /dev/net/bge1000 would return 1048 * ENOENT, but we should not fallback to open /dev/bge1000 in this case, 1049 * as VLAN 1 over the bge0 device should be named as net1000. 1050 * 1051 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed 1052 * the second style-2 open attempt. 1053 */ 1054 static int 1055 i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1) 1056 { 1057 char path[MAXPATHLEN]; 1058 int oflags; 1059 1060 errno = ENOENT; 1061 oflags = O_RDWR; 1062 if (flags & DLPI_EXCL) 1063 oflags |= O_EXCL; 1064 1065 if (flags & DLPI_DEVIPNET) { 1066 (void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider); 1067 if ((*fd = open(path, oflags)) != -1) 1068 return (DLPI_SUCCESS); 1069 else 1070 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 1071 } else if (style1 && !(flags & DLPI_DEVONLY)) { 1072 char driver[DLPI_LINKNAME_MAX]; 1073 char device[DLPI_LINKNAME_MAX]; 1074 datalink_id_t linkid; 1075 uint_t ppa; 1076 dladm_handle_t handle; 1077 1078 /* 1079 * This is not a valid style-1 name. It could be "ip" module 1080 * for example. Fallback to open the /dev node. 1081 */ 1082 if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS) 1083 goto fallback; 1084 1085 (void) snprintf(path, sizeof (path), "/dev/net/%s", provider); 1086 if ((*fd = open(path, oflags)) != -1) 1087 return (DLPI_SUCCESS); 1088 1089 /* 1090 * We don't fallback to open the /dev node when it returns 1091 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2 1092 * is returned to indicate not to continue the style-2 open. 1093 */ 1094 if (errno != ENOENT) 1095 return (DLPI_ENOTSTYLE2); 1096 1097 /* 1098 * We didn't find the /dev/net node. Then we check whether 1099 * the given name is a device name or its VLAN PPA hack name 1100 * of a known link. If the answer is yes, and this link 1101 * supports vanity naming, then the link (or the VLAN) should 1102 * also have its /dev/net node but perhaps with another vanity 1103 * name (for example, when bge0 is renamed to net0). In this 1104 * case, although attempt to open the /dev/net/<devname> fails, 1105 * we should not fallback to open the /dev/<devname> node. 1106 */ 1107 (void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver, 1108 ppa >= 1000 ? ppa % 1000 : ppa); 1109 1110 /* open libdladm handle rather than taking it as input */ 1111 if (dladm_open(&handle) != DLADM_STATUS_OK) 1112 return (DLPI_FAILURE); 1113 1114 if (dladm_dev2linkid(handle, device, &linkid) == 1115 DLADM_STATUS_OK) { 1116 dladm_phys_attr_t dpa; 1117 1118 if ((dladm_phys_info(handle, linkid, &dpa, 1119 DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK && 1120 !dpa.dp_novanity) { 1121 dladm_close(handle); 1122 return (DLPI_ENOTSTYLE2); 1123 } 1124 } 1125 dladm_close(handle); 1126 } 1127 1128 fallback: 1129 (void) snprintf(path, sizeof (path), "/dev/%s", provider); 1130 if ((*fd = open(path, oflags)) != -1) 1131 return (DLPI_SUCCESS); 1132 1133 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR); 1134 } 1135 1136 /* 1137 * Open a style 1 link. PPA is implicitly attached. 1138 */ 1139 static int 1140 i_dlpi_style1_open(dlpi_impl_t *dip) 1141 { 1142 int retval, save_errno; 1143 int fd; 1144 1145 /* 1146 * In order to support open of syntax like device[.module[.module...]] 1147 * where modules need to be pushed onto the device stream, open only 1148 * device name, otherwise open the full linkname. 1149 */ 1150 retval = i_dlpi_open((dip->dli_mod_cnt != 0) ? 1151 dip->dli_provider : dip->dli_linkname, &fd, 1152 dip->dli_oflags, B_TRUE); 1153 1154 if (retval != DLPI_SUCCESS) { 1155 dip->dli_mod_pushed = 0; 1156 return (retval); 1157 } 1158 dip->dli_fd = fd; 1159 1160 /* 1161 * Try to push modules (if any) onto the device stream. If I_PUSH 1162 * fails, we increment count of modules pushed (dli_mod_pushed) 1163 * expecting it is last module to be pushed and thus will be pushed 1164 * in i_dlpi_style2_open(). 1165 */ 1166 for (dip->dli_mod_pushed = 0; dip->dli_mod_pushed < dip->dli_mod_cnt; 1167 dip->dli_mod_pushed++) { 1168 if (ioctl(fd, I_PUSH, 1169 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 1170 dip->dli_mod_pushed++; 1171 return (DLPI_FAILURE); 1172 } 1173 } 1174 1175 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) { 1176 save_errno = errno; 1177 (void) close(dip->dli_fd); 1178 errno = save_errno; 1179 dip->dli_mod_pushed = 0; 1180 return (retval); 1181 } 1182 1183 return (DLPI_SUCCESS); 1184 } 1185 1186 /* 1187 * Open a style 2 link. PPA must be explicitly attached. 1188 */ 1189 static int 1190 i_dlpi_style2_open(dlpi_impl_t *dip) 1191 { 1192 int fd; 1193 int retval, save_errno; 1194 1195 /* 1196 * If style 1 open failed, we need to determine how far it got and 1197 * finish up the open() call as a style 2 open. 1198 * 1199 * If no modules were pushed (mod_pushed == 0), then we need to 1200 * open it as a style 2 link. 1201 * 1202 * If the pushing of the last module failed, we need to 1203 * try pushing it as a style 2 module. Decrement dli_mod_pushed 1204 * count so it can be pushed onto the stream. 1205 * 1206 * Otherwise we failed during the push of an intermediate module and 1207 * must fail out and close the link. 1208 */ 1209 if (dip->dli_mod_pushed == 0) { 1210 if ((retval = i_dlpi_open(dip->dli_provider, &fd, 1211 dip->dli_oflags, B_FALSE)) != DLPI_SUCCESS) { 1212 return (retval); 1213 } 1214 dip->dli_fd = fd; 1215 } else if (dip->dli_mod_pushed == dip->dli_mod_cnt) { 1216 if (i_dlpi_remove_ppa(dip->dli_modlist[dip->dli_mod_cnt - 1]) 1217 != DLPI_SUCCESS) 1218 return (DLPI_ELINKNAMEINVAL); 1219 1220 dip->dli_mod_pushed--; 1221 fd = dip->dli_fd; 1222 } else { 1223 return (DLPI_ELINKNAMEINVAL); 1224 } 1225 1226 /* Try and push modules (if any) onto the device stream. */ 1227 for (; dip->dli_mod_pushed < dip->dli_mod_cnt; dip->dli_mod_pushed++) { 1228 if (ioctl(fd, I_PUSH, 1229 dip->dli_modlist[dip->dli_mod_pushed]) == -1) { 1230 retval = DL_SYSERR; 1231 goto failure; 1232 } 1233 } 1234 1235 /* 1236 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a 1237 * DLPI link so attach and ignore rest. 1238 */ 1239 if (dip->dli_oflags & DLPI_SERIAL) 1240 goto attach; 1241 1242 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS) 1243 goto failure; 1244 1245 /* 1246 * Succeeded opening the link and verified it is style2. Now attach to 1247 * PPA only if DLPI_NOATTACH is not set. 1248 */ 1249 if (dip->dli_oflags & DLPI_NOATTACH) 1250 return (DLPI_SUCCESS); 1251 1252 attach: 1253 if ((retval = i_dlpi_attach(dip)) != DLPI_SUCCESS) 1254 goto failure; 1255 1256 return (DLPI_SUCCESS); 1257 1258 failure: 1259 save_errno = errno; 1260 (void) close(dip->dli_fd); 1261 errno = save_errno; 1262 return (retval); 1263 } 1264 1265 /* 1266 * Verify with DLPI that the link is the expected DLPI 'style' device, 1267 * dlpi_info sets the DLPI style in the DLPI handle. 1268 */ 1269 static int 1270 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style) 1271 { 1272 int retval; 1273 dlpi_info_t dlinfo; 1274 1275 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0); 1276 if (retval == DLPI_SUCCESS && dip->dli_style != style) 1277 retval = DLPI_EBADLINK; 1278 1279 return (retval); 1280 } 1281 1282 /* 1283 * Remove PPA from end of linkname. 1284 * Return DLPI_SUCCESS if found, else return DLPI_FAILURE. 1285 */ 1286 static int 1287 i_dlpi_remove_ppa(char *linkname) 1288 { 1289 int i = strlen(linkname) - 1; 1290 1291 if (i == -1 || !isdigit(linkname[i--])) 1292 return (DLPI_FAILURE); 1293 1294 while (i >= 0 && isdigit(linkname[i])) 1295 i--; 1296 1297 linkname[i + 1] = '\0'; 1298 return (DLPI_SUCCESS); 1299 } 1300 1301 /* 1302 * For DLPI style 2 providers, an explicit attach of PPA is required. 1303 */ 1304 static int 1305 i_dlpi_attach(dlpi_impl_t *dip) 1306 { 1307 dlpi_msg_t req, ack; 1308 dl_attach_req_t *attachreqp; 1309 1310 /* 1311 * Special case: DLPI_SERIAL flag (synchronous serial lines) 1312 * is not a DLPI link so ignore DLPI style. 1313 */ 1314 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL)) 1315 return (DLPI_ENOTSTYLE2); 1316 1317 DLPI_MSG_CREATE(req, DL_ATTACH_REQ); 1318 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1319 1320 attachreqp = &(req.dlm_msg->attach_req); 1321 attachreqp->dl_ppa = dip->dli_ppa; 1322 1323 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0)); 1324 } 1325 1326 /* 1327 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care 1328 * if this request fails, as this indicates the underlying DLPI device does 1329 * not support link aggregation (pre-GLDV3 device drivers), and thus will 1330 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing 1331 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p). 1332 */ 1333 static void 1334 i_dlpi_passive(dlpi_impl_t *dip) 1335 { 1336 dlpi_msg_t req, ack; 1337 1338 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ); 1339 DLPI_MSG_CREATE(ack, DL_OK_ACK); 1340 1341 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0); 1342 } 1343 1344 /* 1345 * Send a dlpi control message and/or data message on a stream. The inputs 1346 * for this function are: 1347 * dlpi_impl_t *dip: internal dlpi handle to open stream 1348 * const dlpi_msg_t *dlreqp: request message structure 1349 * void *databuf: data buffer 1350 * size_t datalen: data buffer len 1351 * int flags: flags to set for putmsg() 1352 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure. 1353 */ 1354 static int 1355 i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1356 const void *databuf, size_t datalen, int flags) 1357 { 1358 int retval; 1359 int fd = dip->dli_fd; 1360 struct strbuf ctl; 1361 struct strbuf data; 1362 1363 if (dlreqp != NULL) { 1364 ctl.buf = (void *)dlreqp->dlm_msg; 1365 ctl.len = dlreqp->dlm_msgsz; 1366 } 1367 1368 data.buf = (void *)databuf; 1369 data.len = datalen; 1370 1371 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl), 1372 (databuf == NULL ? NULL : &data), flags); 1373 1374 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR); 1375 } 1376 1377 /* 1378 * Get a DLPI control message and/or data message from a stream. The inputs 1379 * for this function are: 1380 * dlpi_impl_t *dip: internal dlpi handle 1381 * int msec: timeout to wait for message 1382 * dlpi_msg_t *dlreplyp: reply message structure, the message size 1383 * member on return stores actual size received 1384 * t_uscalar_t dlreqprim: requested primitive 1385 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request 1386 * size_t dlreplyminsz: minimum size of acknowledged primitive size 1387 * void *databuf: data buffer 1388 * size_t *datalenp: data buffer len 1389 * size_t *totdatalenp: total data received. Greater than 'datalenp' if 1390 * actual data received is larger than 'databuf' 1391 * Function returns DLPI_SUCCESS if requested message is retrieved 1392 * otherwise returns error code or timeouts. If a notification arrives on 1393 * the stream the callback is notified. However, error returned during the 1394 * handling of notification is ignored as it would be confusing to actual caller 1395 * of this function. 1396 */ 1397 static int 1398 i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp, 1399 t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz, 1400 void *databuf, size_t *datalenp, size_t *totdatalenp) 1401 { 1402 int retval; 1403 int flags = 0; 1404 int fd = dip->dli_fd; 1405 struct strbuf ctl, data; 1406 struct pollfd pfd; 1407 hrtime_t start, current; 1408 long bufc[DLPI_CHUNKSIZE / sizeof (long)]; 1409 long bufd[DLPI_CHUNKSIZE / sizeof (long)]; 1410 union DL_primitives *dlprim; 1411 dl_notify_ind_t *dlnotif; 1412 boolean_t infinite = (msec < 0); /* infinite timeout */ 1413 1414 /* 1415 * dlreplyp and databuf can be NULL at the same time, to force a check 1416 * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI). 1417 * this will be true more so for DLPI_RAW mode with notifications 1418 * enabled. 1419 */ 1420 if ((databuf == NULL && datalenp != NULL) || 1421 (databuf != NULL && datalenp == NULL)) 1422 return (DLPI_EINVAL); 1423 1424 pfd.fd = fd; 1425 pfd.events = POLLIN | POLLPRI; 1426 1427 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg; 1428 ctl.len = 0; 1429 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz; 1430 1431 data.buf = (databuf == NULL) ? bufd : databuf; 1432 data.len = 0; 1433 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp; 1434 1435 for (;;) { 1436 if (!infinite) 1437 start = gethrtime() / (NANOSEC / MILLISEC); 1438 1439 switch (poll(&pfd, 1, msec)) { 1440 default: 1441 if (pfd.revents & POLLHUP) 1442 return (DL_SYSERR); 1443 break; 1444 case 0: 1445 return (DLPI_ETIMEDOUT); 1446 case -1: 1447 return (DL_SYSERR); 1448 } 1449 1450 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0) 1451 return (DL_SYSERR); 1452 1453 if (totdatalenp != NULL) 1454 *totdatalenp = data.len; 1455 1456 /* 1457 * The supplied DLPI_CHUNKSIZE sized buffers are large enough 1458 * to retrieve all valid DLPI responses in one iteration. 1459 * If MORECTL or MOREDATA is set, we are not interested in the 1460 * remainder of the message. Temporary buffers are used to 1461 * drain the remainder of this message. 1462 * The special case we have to account for is if 1463 * a higher priority messages is enqueued whilst handling 1464 * this condition. We use a change in the flags parameter 1465 * returned by getmsg() to indicate the message has changed. 1466 */ 1467 while (retval & (MORECTL | MOREDATA)) { 1468 struct strbuf cscratch, dscratch; 1469 int oflags = flags; 1470 1471 cscratch.buf = (char *)bufc; 1472 dscratch.buf = (char *)bufd; 1473 cscratch.len = dscratch.len = 0; 1474 cscratch.maxlen = dscratch.maxlen = 1475 sizeof (bufc); 1476 1477 if ((retval = getmsg(fd, &cscratch, &dscratch, 1478 &flags)) < 0) 1479 return (DL_SYSERR); 1480 1481 if (totdatalenp != NULL) 1482 *totdatalenp += dscratch.len; 1483 /* 1484 * In the special case of higher priority 1485 * message received, the low priority message 1486 * received earlier is discarded, if no data 1487 * or control message is left. 1488 */ 1489 if ((flags != oflags) && 1490 !(retval & (MORECTL | MOREDATA)) && 1491 (cscratch.len != 0)) { 1492 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE); 1493 if (dlreplyp != NULL) 1494 (void) memcpy(dlreplyp->dlm_msg, bufc, 1495 ctl.len); 1496 break; 1497 } 1498 } 1499 1500 /* 1501 * Check if DL_NOTIFY_IND message received. If there is one, 1502 * notify the callback function(s) and continue processing the 1503 * requested message. 1504 */ 1505 if (dip->dli_notifylistp != NULL && 1506 ctl.len >= (int)(sizeof (t_uscalar_t)) && 1507 *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) { 1508 /* process properly-formed DL_NOTIFY_IND messages */ 1509 if (ctl.len >= DL_NOTIFY_IND_SIZE) { 1510 dlnotif = (dl_notify_ind_t *)(void *)ctl.buf; 1511 (void) i_dlpi_notifyind_process(dip, dlnotif); 1512 } 1513 goto update_timer; 1514 } 1515 1516 /* 1517 * If we were expecting a data message, and we got one, set 1518 * *datalenp. If we aren't waiting on a control message, then 1519 * we're done. 1520 */ 1521 if (databuf != NULL && data.len >= 0) { 1522 *datalenp = data.len; 1523 if (dlreplyp == NULL) 1524 break; 1525 } 1526 1527 /* 1528 * If we were expecting a control message, and the message 1529 * we received is at least big enough to be a DLPI message, 1530 * then verify it's a reply to something we sent. If it 1531 * is a reply to something we sent, also verify its size. 1532 */ 1533 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) { 1534 dlprim = dlreplyp->dlm_msg; 1535 if (dlprim->dl_primitive == dlreplyprim) { 1536 if (ctl.len < dlreplyminsz) 1537 return (DLPI_EBADMSG); 1538 dlreplyp->dlm_msgsz = ctl.len; 1539 break; 1540 } else if (dlprim->dl_primitive == DL_ERROR_ACK) { 1541 if (ctl.len < DL_ERROR_ACK_SIZE) 1542 return (DLPI_EBADMSG); 1543 1544 /* Is it ours? */ 1545 if (dlprim->error_ack.dl_error_primitive == 1546 dlreqprim) 1547 break; 1548 } 1549 } 1550 update_timer: 1551 if (!infinite) { 1552 current = gethrtime() / (NANOSEC / MILLISEC); 1553 msec -= (current - start); 1554 1555 if (msec <= 0) 1556 return (DLPI_ETIMEDOUT); 1557 } 1558 } 1559 1560 return (DLPI_SUCCESS); 1561 } 1562 1563 /* 1564 * Common routine invoked by all DLPI control routines. The inputs for this 1565 * function are: 1566 * dlpi_impl_t *dip: internal dlpi handle 1567 * const dlpi_msg_t *dlreqp: request message structure 1568 * dlpi_msg_t *dlreplyp: reply message structure 1569 * size_t dlreplyminsz: minimum size of reply primitive 1570 * int flags: flags to be set to send a message 1571 * This routine succeeds if the message is an expected request/acknowledged 1572 * message. However, if DLPI notification has been enabled via 1573 * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling 1574 * expected messages. Otherwise, any other unexpected asynchronous messages will 1575 * be discarded. 1576 */ 1577 static int 1578 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp, 1579 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags) 1580 { 1581 int retval; 1582 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive; 1583 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive; 1584 1585 /* Put the requested primitive on the stream. */ 1586 retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags); 1587 if (retval != DLPI_SUCCESS) 1588 return (retval); 1589 1590 /* Retrieve acknowledged message for requested primitive. */ 1591 retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC), 1592 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL); 1593 if (retval != DLPI_SUCCESS) 1594 return (retval); 1595 1596 /* 1597 * If primitive is DL_ERROR_ACK, set errno. 1598 */ 1599 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) { 1600 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno; 1601 retval = dlreplyp->dlm_msg->error_ack.dl_errno; 1602 } 1603 1604 return (retval); 1605 } 1606 1607 /* 1608 * DLPI error codes. 1609 */ 1610 static const char *dlpi_errlist[] = { 1611 "bad LSAP selector", /* DL_BADSAP 0x00 */ 1612 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */ 1613 "improper permissions for request", /* DL_ACCESS 0x02 */ 1614 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */ 1615 NULL, /* DL_SYSERR 0x04 */ 1616 "sequence number not from outstanding DL_CONN_IND", 1617 /* DL_BADCORR 0x05 */ 1618 "user data exceeded provider limit", /* DL_BADDATA 0x06 */ 1619 "requested service not supplied by provider", 1620 /* DL_UNSUPPORTED 0x07 */ 1621 "specified PPA was invalid", /* DL_BADPPA 0x08 */ 1622 "primitive received not known by provider", /* DL_BADPRIM 0x09 */ 1623 "QoS parameters contained invalid values", 1624 /* DL_BADQOSPARAM 0x0a */ 1625 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */ 1626 "token used not an active stream", /* DL_BADTOKEN 0x0c */ 1627 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */ 1628 "physical link initialization failed", /* DL_INITFAILED 0x0e */ 1629 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */ 1630 "physical link not initialized", /* DL_NOTINIT 0x10 */ 1631 "previous data unit could not be delivered", 1632 /* DL_UNDELIVERABLE 0x11 */ 1633 "primitive is known but unsupported", 1634 /* DL_NOTSUPPORTED 0x12 */ 1635 "limit exceeded", /* DL_TOOMANY 0x13 */ 1636 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */ 1637 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */ 1638 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */ 1639 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */ 1640 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */ 1641 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */ 1642 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */ 1643 "pending outstanding connect indications" /* DL_PENDING 0x1b */ 1644 }; 1645 1646 /* 1647 * libdlpi error codes. 1648 */ 1649 static const char *libdlpi_errlist[] = { 1650 "DLPI operation succeeded", /* DLPI_SUCCESS */ 1651 "invalid argument", /* DLPI_EINVAL */ 1652 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */ 1653 "DLPI link does not exist", /* DLPI_ENOLINK */ 1654 "bad DLPI link", /* DLPI_EBADLINK */ 1655 "invalid DLPI handle", /* DLPI_EINHANDLE */ 1656 "DLPI operation timed out", /* DLPI_ETIMEDOUT */ 1657 "unsupported DLPI version", /* DLPI_EVERNOTSUP */ 1658 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */ 1659 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */ 1660 "DLPI operation failed", /* DLPI_FAILURE */ 1661 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */ 1662 "bad DLPI message", /* DLPI_EBADMSG */ 1663 "DLPI raw mode not supported", /* DLPI_ERAWNOTSUP */ 1664 "DLPI notification not supported by link", 1665 /* DLPI_ENOTENOTSUP */ 1666 "invalid DLPI notification type", /* DLPI_ENOTEINVAL */ 1667 "invalid DLPI notification id", /* DLPI_ENOTEIDINVAL */ 1668 "DLPI_IPNETINFO not supported" /* DLPI_EIPNETINFONOTSUP */ 1669 }; 1670 1671 const char * 1672 dlpi_strerror(int err) 1673 { 1674 if (err == DL_SYSERR) 1675 return (strerror(errno)); 1676 else if (err >= 0 && err < NELEMS(dlpi_errlist)) 1677 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err])); 1678 else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX) 1679 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err - 1680 DLPI_SUCCESS])); 1681 else 1682 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error")); 1683 } 1684 1685 /* 1686 * Each table entry comprises a DLPI/Private mactype and the description. 1687 */ 1688 static const dlpi_mactype_t dlpi_mactypes[] = { 1689 { DL_CSMACD, "CSMA/CD" }, 1690 { DL_TPB, "Token Bus" }, 1691 { DL_TPR, "Token Ring" }, 1692 { DL_METRO, "Metro Net" }, 1693 { DL_ETHER, "Ethernet" }, 1694 { DL_HDLC, "HDLC" }, 1695 { DL_CHAR, "Sync Character" }, 1696 { DL_CTCA, "CTCA" }, 1697 { DL_FDDI, "FDDI" }, 1698 { DL_FRAME, "Frame Relay (LAPF)" }, 1699 { DL_MPFRAME, "MP Frame Relay" }, 1700 { DL_ASYNC, "Async Character" }, 1701 { DL_IPX25, "X.25 (Classic IP)" }, 1702 { DL_LOOP, "Software Loopback" }, 1703 { DL_FC, "Fiber Channel" }, 1704 { DL_ATM, "ATM" }, 1705 { DL_IPATM, "ATM (Classic IP)" }, 1706 { DL_X25, "X.25 (LAPB)" }, 1707 { DL_ISDN, "ISDN" }, 1708 { DL_HIPPI, "HIPPI" }, 1709 { DL_100VG, "100BaseVG Ethernet" }, 1710 { DL_100VGTPR, "100BaseVG Token Ring" }, 1711 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" }, 1712 { DL_100BT, "100BaseT" }, 1713 { DL_IB, "Infiniband" }, 1714 { DL_IPV4, "IPv4 Tunnel" }, 1715 { DL_IPV6, "IPv6 Tunnel" }, 1716 { DL_WIFI, "IEEE 802.11" }, 1717 { DL_IPNET, "IPNET" } 1718 }; 1719 1720 const char * 1721 dlpi_mactype(uint_t mactype) 1722 { 1723 int i; 1724 1725 for (i = 0; i < NELEMS(dlpi_mactypes); i++) { 1726 if (dlpi_mactypes[i].dm_mactype == mactype) 1727 return (dlpi_mactypes[i].dm_desc); 1728 } 1729 1730 return ("Unknown MAC Type"); 1731 } 1732 1733 /* 1734 * Each table entry comprises a DLPI primitive and the maximum buffer 1735 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details). 1736 */ 1737 static const dlpi_primsz_t dlpi_primsizes[] = { 1738 { DL_INFO_REQ, DL_INFO_REQ_SIZE }, 1739 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) + 1740 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))}, 1741 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE }, 1742 { DL_BIND_REQ, DL_BIND_REQ_SIZE }, 1743 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX + 1744 DLPI_SAPLEN_MAX }, 1745 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE }, 1746 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1747 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1748 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE }, 1749 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE }, 1750 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE }, 1751 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX + 1752 DLPI_SAPLEN_MAX }, 1753 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX + 1754 DLPI_SAPLEN_MAX)) }, 1755 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE }, 1756 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX }, 1757 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX }, 1758 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) }, 1759 { DL_NOTIFY_REQ, DL_NOTIFY_REQ_SIZE }, 1760 { DL_NOTIFY_ACK, MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE) }, 1761 { DL_NOTIFY_IND, DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX + 1762 DLPI_SAPLEN_MAX } 1763 }; 1764 1765 /* 1766 * Refers to the dlpi_primsizes[] table to return corresponding maximum 1767 * buffer size. 1768 */ 1769 static size_t 1770 i_dlpi_getprimsize(t_uscalar_t prim) 1771 { 1772 int i; 1773 1774 for (i = 0; i < NELEMS(dlpi_primsizes); i++) { 1775 if (dlpi_primsizes[i].dp_prim == prim) 1776 return (dlpi_primsizes[i].dp_primsz); 1777 } 1778 1779 return (sizeof (t_uscalar_t)); 1780 } 1781 1782 /* 1783 * sap values vary in length and are in host byte order, build sap value 1784 * by writing saplen bytes, so that the sap value is left aligned. 1785 */ 1786 static uint_t 1787 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen) 1788 { 1789 int i; 1790 uint_t sap = 0; 1791 1792 #ifdef _LITTLE_ENDIAN 1793 for (i = saplen - 1; i >= 0; i--) { 1794 #else 1795 for (i = 0; i < saplen; i++) { 1796 #endif 1797 sap <<= 8; 1798 sap |= sapp[i]; 1799 } 1800 1801 return (sap); 1802 } 1803 1804 /* 1805 * Copy sap value to a buffer in host byte order. saplen is the number of 1806 * bytes to copy. 1807 */ 1808 static void 1809 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen) 1810 { 1811 uint8_t *sapp; 1812 1813 #ifdef _LITTLE_ENDIAN 1814 sapp = (uint8_t *)&sap; 1815 #else 1816 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen); 1817 #endif 1818 1819 (void) memcpy(dstbuf, sapp, saplen); 1820 } 1821 1822 /* 1823 * Fill notification payload and callback each registered functions. 1824 * Delete nodes if any was called while processing. 1825 */ 1826 static int 1827 i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp) 1828 { 1829 dlpi_notifyinfo_t notifinfo; 1830 t_uscalar_t dataoff, datalen; 1831 caddr_t datap; 1832 dlpi_notifyent_t *dnp; 1833 uint_t note = dlnotifyindp->dl_notification; 1834 uint_t deletenode = B_FALSE; 1835 1836 notifinfo.dni_note = note; 1837 1838 switch (note) { 1839 case DL_NOTE_SPEED: 1840 notifinfo.dni_speed = dlnotifyindp->dl_data; 1841 break; 1842 case DL_NOTE_SDU_SIZE: 1843 notifinfo.dni_size = dlnotifyindp->dl_data; 1844 break; 1845 case DL_NOTE_PHYS_ADDR: 1846 dataoff = dlnotifyindp->dl_addr_offset; 1847 datalen = dlnotifyindp->dl_addr_length; 1848 1849 if (dataoff == 0 || datalen == 0) 1850 return (DLPI_EBADMSG); 1851 1852 datap = (caddr_t)dlnotifyindp + dataoff; 1853 if (dataoff < DL_NOTIFY_IND_SIZE) 1854 return (DLPI_EBADMSG); 1855 1856 notifinfo.dni_physaddrlen = datalen - dip->dli_saplen; 1857 1858 if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX) 1859 return (DL_BADADDR); 1860 1861 (void) memcpy(notifinfo.dni_physaddr, datap, 1862 notifinfo.dni_physaddrlen); 1863 break; 1864 } 1865 1866 dip->dli_note_processing = B_TRUE; 1867 1868 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) { 1869 if (note & dnp->dln_notes) 1870 dnp->dln_fnp((dlpi_handle_t)dip, ¬ifinfo, dnp->arg); 1871 if (dnp->dln_rm) 1872 deletenode = B_TRUE; 1873 } 1874 1875 dip->dli_note_processing = B_FALSE; 1876 1877 /* Walk the notifyentry list to unregister marked entries. */ 1878 if (deletenode) 1879 i_dlpi_deletenotifyid(dip); 1880 1881 return (DLPI_SUCCESS); 1882 } 1883 /* 1884 * Find registered notification. 1885 */ 1886 static boolean_t 1887 i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id) 1888 { 1889 dlpi_notifyent_t *dnp; 1890 1891 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) { 1892 if (id == dnp) 1893 return (B_TRUE); 1894 } 1895 1896 return (B_FALSE); 1897 } 1898 1899 /* 1900 * Walk the list of notifications and deleted nodes marked to be deleted. 1901 */ 1902 static void 1903 i_dlpi_deletenotifyid(dlpi_impl_t *dip) 1904 { 1905 dlpi_notifyent_t *prev, *dnp; 1906 1907 prev = NULL; 1908 dnp = dip->dli_notifylistp; 1909 while (dnp != NULL) { 1910 if (!dnp->dln_rm) { 1911 prev = dnp; 1912 dnp = dnp->dln_next; 1913 } else if (prev == NULL) { 1914 dip->dli_notifylistp = dnp->dln_next; 1915 free(dnp); 1916 dnp = dip->dli_notifylistp; 1917 } else { 1918 prev->dln_next = dnp->dln_next; 1919 free(dnp); 1920 dnp = prev->dln_next; 1921 } 1922 } 1923 } 1924