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