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