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