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