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