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