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