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