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