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