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