Home | History | Annotate | Download | only in common
      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 = gethrtime() / (NANOSEC / MILLISEC);
   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 = gethrtime() / (NANOSEC / MILLISEC);
   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 }
   1837