xref: /titanic_44/usr/src/lib/libdlpi/common/libdlpi.c (revision e11c3f44f531fdff80941ce57c065d2ae861cefc)
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*e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Data-Link Provider Interface (Version 2)
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <poll.h>
377c478bd9Sstevel@tonic-gate #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
397c478bd9Sstevel@tonic-gate #include <errno.h>
40c7e4935fSss150715 #include <alloca.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <ctype.h>
43948f2876Sss150715 #include <net/if_types.h>
44948f2876Sss150715 #include <netinet/arp.h>
45d62bc4baSyz147064 #include <libdladm.h>
46d62bc4baSyz147064 #include <libdllink.h>
477c478bd9Sstevel@tonic-gate #include <libdlpi.h>
48c7e4935fSss150715 #include <libintl.h>
49c7e4935fSss150715 #include <libinetutil.h>
50b127ac41SPhilip Kirk #include <dirent.h>
517c478bd9Sstevel@tonic-gate 
52c7e4935fSss150715 #include "libdlpi_impl.h"
537c478bd9Sstevel@tonic-gate 
54d62bc4baSyz147064 static int i_dlpi_open(const char *, int *, uint_t, boolean_t);
55c7e4935fSss150715 static int i_dlpi_style1_open(dlpi_impl_t *);
56c7e4935fSss150715 static int i_dlpi_style2_open(dlpi_impl_t *);
57c7e4935fSss150715 static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t);
58c7e4935fSss150715 static int i_dlpi_remove_ppa(char *);
59c7e4935fSss150715 static int i_dlpi_attach(dlpi_impl_t *);
60c7e4935fSss150715 static void i_dlpi_passive(dlpi_impl_t *);
617c478bd9Sstevel@tonic-gate 
623ab45760Sss150715 static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *,
633ab45760Sss150715     size_t, int);
643ab45760Sss150715 static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t,
653ab45760Sss150715     t_uscalar_t, size_t, void *, size_t *, size_t *);
66c7e4935fSss150715 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *,
67c7e4935fSss150715     size_t, int);
687c478bd9Sstevel@tonic-gate 
69c7e4935fSss150715 static size_t i_dlpi_getprimsize(t_uscalar_t);
70c7e4935fSss150715 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t);
71c7e4935fSss150715 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t);
72c7e4935fSss150715 static uint_t i_dlpi_buildsap(uint8_t *, uint_t);
73c7e4935fSss150715 static void i_dlpi_writesap(void *, uint_t, uint_t);
743ab45760Sss150715 static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *);
753ab45760Sss150715 static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *);
763ab45760Sss150715 static void i_dlpi_deletenotifyid(dlpi_impl_t *);
77c7e4935fSss150715 
78d62bc4baSyz147064 struct i_dlpi_walklink_arg {
79d62bc4baSyz147064 	dlpi_walkfunc_t *fn;
80d62bc4baSyz147064 	void *arg;
81d62bc4baSyz147064 };
82d62bc4baSyz147064 
83d62bc4baSyz147064 static int
84d62bc4baSyz147064 i_dlpi_walk_link(const char *name, void *arg)
85d62bc4baSyz147064 {
86d62bc4baSyz147064 	struct i_dlpi_walklink_arg *warg = arg;
87d62bc4baSyz147064 
88d62bc4baSyz147064 	return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE :
89d62bc4baSyz147064 	    DLADM_WALK_CONTINUE);
90d62bc4baSyz147064 }
91d62bc4baSyz147064 
92d62bc4baSyz147064 /*ARGSUSED*/
93d62bc4baSyz147064 void
94d62bc4baSyz147064 dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags)
95d62bc4baSyz147064 {
96d62bc4baSyz147064 	struct i_dlpi_walklink_arg warg;
97b127ac41SPhilip Kirk 	struct dirent *d;
98b127ac41SPhilip Kirk 	DIR *dp;
994ac67f02SAnurag S. Maskey 	dladm_handle_t handle;
100d62bc4baSyz147064 
101d62bc4baSyz147064 	warg.fn = fn;
102d62bc4baSyz147064 	warg.arg = arg;
103d62bc4baSyz147064 
104b127ac41SPhilip Kirk 	if (flags & DLPI_DEVIPNET) {
105b127ac41SPhilip Kirk 		if ((dp = opendir("/dev/ipnet")) == NULL)
106b127ac41SPhilip Kirk 			return;
107b127ac41SPhilip Kirk 
108b127ac41SPhilip Kirk 		while ((d = readdir(dp)) != NULL) {
109b127ac41SPhilip Kirk 			if (d->d_name[0] == '.')
110b127ac41SPhilip Kirk 				continue;
111b127ac41SPhilip Kirk 
112b127ac41SPhilip Kirk 			if (warg.fn(d->d_name, warg.arg))
113b127ac41SPhilip Kirk 				break;
114b127ac41SPhilip Kirk 		}
115b127ac41SPhilip Kirk 
116b127ac41SPhilip Kirk 		(void) closedir(dp);
117b127ac41SPhilip Kirk 	} else {
1184ac67f02SAnurag S. Maskey 		/*
1194ac67f02SAnurag S. Maskey 		 * Rather than have libdlpi take the libdladm handle,
1204ac67f02SAnurag S. Maskey 		 * open the handle here.
1214ac67f02SAnurag S. Maskey 		 */
1224ac67f02SAnurag S. Maskey 		if (dladm_open(&handle) != DLADM_STATUS_OK)
1234ac67f02SAnurag S. Maskey 			return;
1244ac67f02SAnurag S. Maskey 
1254ac67f02SAnurag S. Maskey 		(void) dladm_walk(i_dlpi_walk_link, handle, &warg,
1264ac67f02SAnurag S. Maskey 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1274ac67f02SAnurag S. Maskey 		    DLADM_OPT_ACTIVE);
1284ac67f02SAnurag S. Maskey 
1294ac67f02SAnurag S. Maskey 		dladm_close(handle);
130d62bc4baSyz147064 	}
131b127ac41SPhilip Kirk }
132d62bc4baSyz147064 
133c7e4935fSss150715 int
134c7e4935fSss150715 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
135c7e4935fSss150715 {
136b127ac41SPhilip Kirk 	int		retval, on = 1;
137c7e4935fSss150715 	int		cnt;
138c7e4935fSss150715 	ifspec_t	ifsp;
139c7e4935fSss150715 	dlpi_impl_t  	*dip;
140c7e4935fSss150715 
141c7e4935fSss150715 	/*
142c7e4935fSss150715 	 * Validate linkname, fail if logical unit number (lun) is specified,
143c7e4935fSss150715 	 * otherwise decompose the contents into ifsp.
144c7e4935fSss150715 	 */
145c7e4935fSss150715 	if (linkname == NULL || (strchr(linkname, ':') != NULL) ||
146c7e4935fSss150715 	    !ifparse_ifspec(linkname, &ifsp))
147c7e4935fSss150715 		return (DLPI_ELINKNAMEINVAL);
148c7e4935fSss150715 
149b127ac41SPhilip Kirk 	/*
150b127ac41SPhilip Kirk 	 * Ensure flags values are sane.
151b127ac41SPhilip Kirk 	 */
152b127ac41SPhilip Kirk 	if ((flags & (DLPI_DEVIPNET|DLPI_DEVONLY)) ==
153b127ac41SPhilip Kirk 	    (DLPI_DEVIPNET|DLPI_DEVONLY))
154b127ac41SPhilip Kirk 		return (DLPI_EINVAL);
155b127ac41SPhilip Kirk 
156c7e4935fSss150715 	/* Allocate a new dlpi_impl_t. */
157c7e4935fSss150715 	if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL)
158c7e4935fSss150715 		return (DL_SYSERR);
159c7e4935fSss150715 
160c7e4935fSss150715 	/* Fill in known/default libdlpi handle values. */
161c7e4935fSss150715 	dip->dli_timeout = DLPI_DEF_TIMEOUT;
162c7e4935fSss150715 	dip->dli_ppa = ifsp.ifsp_ppa;
163c7e4935fSss150715 	dip->dli_oflags = flags;
1643ab45760Sss150715 	dip->dli_notifylistp = NULL;
1653ab45760Sss150715 	dip->dli_note_processing = B_FALSE;
166d62bc4baSyz147064 	if (getenv("DLPI_DEVONLY") != NULL)
167d62bc4baSyz147064 		dip->dli_oflags |= DLPI_DEVONLY;
168c7e4935fSss150715 
169b127ac41SPhilip Kirk 	if (!(flags & DLPI_DEVIPNET)) {
170b127ac41SPhilip Kirk 		dip->dli_mod_cnt = ifsp.ifsp_modcnt;
171c7e4935fSss150715 		for (cnt = 0; cnt != dip->dli_mod_cnt; cnt++) {
172b127ac41SPhilip Kirk 			(void) strlcpy(dip->dli_modlist[cnt],
173b127ac41SPhilip Kirk 			    ifsp.ifsp_mods[cnt], DLPI_LINKNAME_MAX);
174b127ac41SPhilip Kirk 		}
175c7e4935fSss150715 	}
176c7e4935fSss150715 
177c7e4935fSss150715 	/* Copy linkname provided to the function. */
178c7e4935fSss150715 	if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >=
179c7e4935fSss150715 	    sizeof (dip->dli_linkname)) {
180c7e4935fSss150715 		free(dip);
181c7e4935fSss150715 		return (DLPI_ELINKNAMEINVAL);
182c7e4935fSss150715 	}
183c7e4935fSss150715 
184c7e4935fSss150715 	/* Copy provider name. */
185c7e4935fSss150715 	(void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm,
186c7e4935fSss150715 	    sizeof (dip->dli_provider));
187c7e4935fSss150715 
188c7e4935fSss150715 	/*
189c7e4935fSss150715 	 * Special case: DLPI_SERIAL flag is set to indicate a synchronous
190c7e4935fSss150715 	 * serial line interface (see syncinit(1M), syncstat(1M),
191c7e4935fSss150715 	 * syncloop(1M)), which is not a DLPI link.
192c7e4935fSss150715 	 */
193c7e4935fSss150715 	if (dip->dli_oflags & DLPI_SERIAL) {
194c7e4935fSss150715 		if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) {
195c7e4935fSss150715 			free(dip);
196c7e4935fSss150715 			return (retval);
197c7e4935fSss150715 		}
198c7e4935fSss150715 
199c7e4935fSss150715 		*dhp = (dlpi_handle_t)dip;
200c7e4935fSss150715 		return (retval);
201c7e4935fSss150715 	}
202c7e4935fSss150715 
203d62bc4baSyz147064 	if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) {
204d62bc4baSyz147064 		if (retval == DLPI_ENOTSTYLE2) {
205d62bc4baSyz147064 			/*
206d62bc4baSyz147064 			 * The error code indicates not to continue the
207d62bc4baSyz147064 			 * style-2 open. Change the error code back to
208d62bc4baSyz147064 			 * DL_SYSERR, so that one would know the cause
209d62bc4baSyz147064 			 * of failure from errno.
210d62bc4baSyz147064 			 */
211d62bc4baSyz147064 			retval = DL_SYSERR;
212b127ac41SPhilip Kirk 		} else if (!(dip->dli_oflags & DLPI_DEVIPNET)) {
213d62bc4baSyz147064 			retval = i_dlpi_style2_open(dip);
214d62bc4baSyz147064 		}
215d62bc4baSyz147064 		if (retval != DLPI_SUCCESS) {
216c7e4935fSss150715 			free(dip);
217c7e4935fSss150715 			return (retval);
218c7e4935fSss150715 		}
219c7e4935fSss150715 	}
220c7e4935fSss150715 
221c7e4935fSss150715 	if (dip->dli_oflags & DLPI_PASSIVE)
222c7e4935fSss150715 		i_dlpi_passive(dip);
223c7e4935fSss150715 
224c7e4935fSss150715 	if ((dip->dli_oflags & DLPI_RAW) &&
225c7e4935fSss150715 	    ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) {
226c7e4935fSss150715 		dlpi_close((dlpi_handle_t)dip);
227c7e4935fSss150715 		return (DLPI_ERAWNOTSUP);
228c7e4935fSss150715 	}
229c7e4935fSss150715 
230b127ac41SPhilip Kirk 	if ((dip->dli_oflags & DLPI_IPNETINFO) &&
231b127ac41SPhilip Kirk 	    ioctl(dip->dli_fd, DLIOCIPNETINFO, &on) < 0) {
232b127ac41SPhilip Kirk 		dlpi_close((dlpi_handle_t)dip);
233b127ac41SPhilip Kirk 		return (DLPI_EIPNETINFONOTSUP);
234b127ac41SPhilip Kirk 	}
235b127ac41SPhilip Kirk 
236c7e4935fSss150715 	/*
237c7e4935fSss150715 	 * We intentionally do not care if this request fails, as this
238c7e4935fSss150715 	 * indicates the underlying DLPI device does not support Native mode
239c7e4935fSss150715 	 * (pre-GLDV3 device drivers).
240c7e4935fSss150715 	 */
241c7e4935fSss150715 	if (dip->dli_oflags & DLPI_NATIVE) {
242c7e4935fSss150715 		if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0)
243c7e4935fSss150715 			dip->dli_mactype = retval;
244c7e4935fSss150715 	}
245c7e4935fSss150715 
246c7e4935fSss150715 	*dhp = (dlpi_handle_t)dip;
247c7e4935fSss150715 	return (DLPI_SUCCESS);
248c7e4935fSss150715 }
249c7e4935fSss150715 
250c7e4935fSss150715 void
251c7e4935fSss150715 dlpi_close(dlpi_handle_t dh)
252c7e4935fSss150715 {
253c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
2543ab45760Sss150715 	dlpi_notifyent_t *next, *dnp;
255c7e4935fSss150715 
256c7e4935fSss150715 	if (dip != NULL) {
2573ab45760Sss150715 		for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = next) {
2583ab45760Sss150715 			next = dnp->dln_next;
2593ab45760Sss150715 			free(dnp);
2603ab45760Sss150715 		}
2613ab45760Sss150715 
262c7e4935fSss150715 		(void) close(dip->dli_fd);
263c7e4935fSss150715 		free(dip);
264c7e4935fSss150715 	}
265c7e4935fSss150715 }
266c7e4935fSss150715 
267c7e4935fSss150715 /*
268c7e4935fSss150715  * NOTE: The opt argument must be zero and is reserved for future use to extend
269c7e4935fSss150715  * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)).
270c7e4935fSss150715  */
271c7e4935fSss150715 int
272c7e4935fSss150715 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt)
273c7e4935fSss150715 {
274c7e4935fSss150715 	int 		retval;
275c7e4935fSss150715 	dlpi_msg_t	req, ack;
276c7e4935fSss150715 	dl_info_ack_t	*infoackp;
277c7e4935fSss150715 	uint8_t		*sapp, *addrp;
278c7e4935fSss150715 	caddr_t		ackendp, datap;
279c7e4935fSss150715 	t_uscalar_t	dataoff, datalen;
280c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
281c7e4935fSss150715 
282c7e4935fSss150715 	if (dip == NULL)
283c7e4935fSss150715 		return (DLPI_EINHANDLE);
284c7e4935fSss150715 
285c7e4935fSss150715 	if (infop == NULL || opt != 0)
286c7e4935fSss150715 		return (DLPI_EINVAL);
287c7e4935fSss150715 
288c7e4935fSss150715 	(void) memset(infop, 0, sizeof (dlpi_info_t));
289c7e4935fSss150715 
290c7e4935fSss150715 	/* Set QoS range parameters to default unsupported value. */
291c7e4935fSss150715 	infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
292c7e4935fSss150715 	infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN;
293c7e4935fSss150715 	infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN;
294c7e4935fSss150715 	infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN;
295c7e4935fSss150715 	infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN;
296c7e4935fSss150715 	infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN;
297c7e4935fSss150715 	infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN;
298c7e4935fSss150715 	infop->di_qos_range.dl_residual_error = DL_UNKNOWN;
299c7e4935fSss150715 
300c7e4935fSss150715 	/* Set QoS parameters to default unsupported value. */
301c7e4935fSss150715 	infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
302c7e4935fSss150715 	infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN;
303c7e4935fSss150715 	infop->di_qos_sel.dl_priority = DL_UNKNOWN;
304c7e4935fSss150715 	infop->di_qos_sel.dl_protection = DL_UNKNOWN;
305c7e4935fSss150715 	infop->di_qos_sel.dl_residual_error = DL_UNKNOWN;
306c7e4935fSss150715 
307c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_INFO_REQ);
308c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_INFO_ACK);
309c7e4935fSss150715 
310c7e4935fSss150715 	retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI);
311c7e4935fSss150715 	if (retval != DLPI_SUCCESS)
312c7e4935fSss150715 		return (retval);
313c7e4935fSss150715 
314c7e4935fSss150715 	infoackp = &(ack.dlm_msg->info_ack);
315c7e4935fSss150715 	if (infoackp->dl_version != DL_VERSION_2)
316c7e4935fSss150715 		return (DLPI_EVERNOTSUP);
317c7e4935fSss150715 
318c7e4935fSss150715 	if (infoackp->dl_service_mode != DL_CLDLS)
319c7e4935fSss150715 		return (DLPI_EMODENOTSUP);
320c7e4935fSss150715 
321c7e4935fSss150715 	dip->dli_style = infoackp->dl_provider_style;
322c7e4935fSss150715 	dip->dli_mactype = infoackp->dl_mac_type;
323c7e4935fSss150715 
324c7e4935fSss150715 	ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
325c7e4935fSss150715 
326c7e4935fSss150715 	/* Check and save QoS selection information, if any. */
327c7e4935fSss150715 	datalen = infoackp->dl_qos_length;
328c7e4935fSss150715 	dataoff = infoackp->dl_qos_offset;
329c7e4935fSss150715 	if (dataoff != 0 && datalen != 0) {
330c7e4935fSss150715 		datap = (caddr_t)infoackp + dataoff;
331c7e4935fSss150715 		if (datalen > sizeof (dl_qos_cl_sel1_t) ||
332c7e4935fSss150715 		    dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
333c7e4935fSss150715 			return (DLPI_EBADMSG);
334c7e4935fSss150715 
335c7e4935fSss150715 		(void) memcpy(&infop->di_qos_sel, datap, datalen);
336c7e4935fSss150715 		if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1)
337c7e4935fSss150715 			return (DLPI_EMODENOTSUP);
338c7e4935fSss150715 	}
339c7e4935fSss150715 
340c7e4935fSss150715 	/* Check and save QoS range information, if any. */
341c7e4935fSss150715 	datalen = infoackp->dl_qos_range_length;
342c7e4935fSss150715 	dataoff = infoackp->dl_qos_range_offset;
343c7e4935fSss150715 	if (dataoff != 0 && datalen != 0) {
344c7e4935fSss150715 		datap = (caddr_t)infoackp + dataoff;
345c7e4935fSss150715 		if (datalen > sizeof (dl_qos_cl_range1_t) ||
346c7e4935fSss150715 		    dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
347c7e4935fSss150715 			return (DLPI_EBADMSG);
348c7e4935fSss150715 
349c7e4935fSss150715 		(void) memcpy(&infop->di_qos_range, datap, datalen);
350c7e4935fSss150715 		if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1)
351c7e4935fSss150715 			return (DLPI_EMODENOTSUP);
352c7e4935fSss150715 	}
353c7e4935fSss150715 
354c7e4935fSss150715 	/* Check and save physical address and SAP information. */
355c7e4935fSss150715 	dip->dli_saplen = abs(infoackp->dl_sap_length);
356c7e4935fSss150715 	dip->dli_sapbefore = (infoackp->dl_sap_length > 0);
357c7e4935fSss150715 	infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen;
358c7e4935fSss150715 
359c7e4935fSss150715 	if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX ||
360c7e4935fSss150715 	    dip->dli_saplen > DLPI_SAPLEN_MAX)
361c7e4935fSss150715 		return (DL_BADADDR);
362c7e4935fSss150715 
363c7e4935fSss150715 	dataoff = infoackp->dl_addr_offset;
364c7e4935fSss150715 	datalen = infoackp->dl_addr_length;
365c7e4935fSss150715 	if (dataoff != 0 && datalen != 0) {
366c7e4935fSss150715 		datap = (caddr_t)infoackp + dataoff;
367c7e4935fSss150715 		if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
368c7e4935fSss150715 			return (DLPI_EBADMSG);
369c7e4935fSss150715 
370c7e4935fSss150715 		sapp = addrp = (uint8_t *)datap;
371c7e4935fSss150715 		if (dip->dli_sapbefore)
372c7e4935fSss150715 			addrp += dip->dli_saplen;
373c7e4935fSss150715 		else
374c7e4935fSss150715 			sapp += infop->di_physaddrlen;
375c7e4935fSss150715 
376c7e4935fSss150715 		(void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen);
377c7e4935fSss150715 		infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen);
378c7e4935fSss150715 	}
379c7e4935fSss150715 
380c7e4935fSss150715 	/* Check and save broadcast address information, if any. */
381c7e4935fSss150715 	datalen = infoackp->dl_brdcst_addr_length;
382c7e4935fSss150715 	dataoff = infoackp->dl_brdcst_addr_offset;
383c7e4935fSss150715 	if (dataoff != 0 && datalen != 0) {
384c7e4935fSss150715 		datap = (caddr_t)infoackp + dataoff;
385c7e4935fSss150715 		if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
386c7e4935fSss150715 			return (DLPI_EBADMSG);
387c7e4935fSss150715 		if (datalen != infop->di_physaddrlen)
388c7e4935fSss150715 			return (DL_BADADDR);
389c7e4935fSss150715 
390c7e4935fSss150715 		infop->di_bcastaddrlen = datalen;
391c7e4935fSss150715 		(void) memcpy(infop->di_bcastaddr, datap, datalen);
392c7e4935fSss150715 	}
393c7e4935fSss150715 
394c7e4935fSss150715 	infop->di_max_sdu = infoackp->dl_max_sdu;
395c7e4935fSss150715 	infop->di_min_sdu = infoackp->dl_min_sdu;
396c7e4935fSss150715 	infop->di_state = infoackp->dl_current_state;
397c7e4935fSss150715 	infop->di_mactype = infoackp->dl_mac_type;
398c7e4935fSss150715 
399c7e4935fSss150715 	/* Information retrieved from the handle. */
400c7e4935fSss150715 	(void) strlcpy(infop->di_linkname, dip->dli_linkname,
401c7e4935fSss150715 	    sizeof (infop->di_linkname));
402c7e4935fSss150715 	infop->di_timeout = dip->dli_timeout;
403c7e4935fSss150715 
404c7e4935fSss150715 	return (DLPI_SUCCESS);
405c7e4935fSss150715 }
406c7e4935fSss150715 
407c7e4935fSss150715 /*
408c7e4935fSss150715  * This function parses 'linkname' and stores the 'provider' name and 'PPA'.
409c7e4935fSss150715  */
410c7e4935fSss150715 int
411c7e4935fSss150715 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa)
412c7e4935fSss150715 {
413e7801d59Ssowmini 	dladm_status_t status;
414c7e4935fSss150715 
415e7801d59Ssowmini 	status = dladm_parselink(linkname, provider, ppa);
416e7801d59Ssowmini 
417e7801d59Ssowmini 	if (status != DLADM_STATUS_OK)
418c7e4935fSss150715 		return (DLPI_ELINKNAMEINVAL);
419c7e4935fSss150715 
420c7e4935fSss150715 	return (DLPI_SUCCESS);
421c7e4935fSss150715 }
422c7e4935fSss150715 
423c7e4935fSss150715 /*
424c7e4935fSss150715  * This function takes a provider name and a PPA and stores a full linkname
425c7e4935fSss150715  * as 'linkname'. If 'provider' already is a full linkname 'provider' name
426c7e4935fSss150715  * is stored in 'linkname'.
427c7e4935fSss150715  */
428c7e4935fSss150715 int
429c7e4935fSss150715 dlpi_makelink(char *linkname, const char *provider, uint_t ppa)
430c7e4935fSss150715 {
431c7e4935fSss150715 	int provlen = strlen(provider);
432c7e4935fSss150715 
433c7e4935fSss150715 	if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX)
434c7e4935fSss150715 		return (DLPI_ELINKNAMEINVAL);
435c7e4935fSss150715 
436c7e4935fSss150715 	if (!isdigit(provider[provlen - 1])) {
437c7e4935fSss150715 		(void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider,
438c7e4935fSss150715 		    ppa);
439c7e4935fSss150715 	} else {
440c7e4935fSss150715 		(void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX);
441c7e4935fSss150715 	}
442c7e4935fSss150715 
443c7e4935fSss150715 	return (DLPI_SUCCESS);
444c7e4935fSss150715 }
445c7e4935fSss150715 
446c7e4935fSss150715 int
447c7e4935fSss150715 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap)
448c7e4935fSss150715 {
449c7e4935fSss150715 	int		retval;
450c7e4935fSss150715 	dlpi_msg_t	req, ack;
451c7e4935fSss150715 	dl_bind_req_t	*bindreqp;
452c7e4935fSss150715 	dl_bind_ack_t	*bindackp;
453c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
454c7e4935fSss150715 
455c7e4935fSss150715 	if (dip == NULL)
456c7e4935fSss150715 		return (DLPI_EINHANDLE);
457c7e4935fSss150715 
458c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_BIND_REQ);
459c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_BIND_ACK);
460c7e4935fSss150715 	bindreqp = &(req.dlm_msg->bind_req);
461c7e4935fSss150715 
462c7e4935fSss150715 	/*
463c7e4935fSss150715 	 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on
464c7e4935fSss150715 	 * other interface types (SAP 0 has special significance on token ring).
465c7e4935fSss150715 	 */
466c7e4935fSss150715 	if (sap == DLPI_ANY_SAP)
467c7e4935fSss150715 		bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0);
468c7e4935fSss150715 	else
469c7e4935fSss150715 		bindreqp->dl_sap = sap;
470c7e4935fSss150715 
471c7e4935fSss150715 	bindreqp->dl_service_mode = DL_CLDLS;
472c7e4935fSss150715 	bindreqp->dl_conn_mgmt = 0;
473c7e4935fSss150715 	bindreqp->dl_max_conind = 0;
474c7e4935fSss150715 	bindreqp->dl_xidtest_flg = 0;
475c7e4935fSss150715 
476c7e4935fSss150715 	retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0);
477c7e4935fSss150715 	if (retval != DLPI_SUCCESS)
478c7e4935fSss150715 		return (retval);
479c7e4935fSss150715 
480c7e4935fSss150715 	bindackp = &(ack.dlm_msg->bind_ack);
481c7e4935fSss150715 	/*
482c7e4935fSss150715 	 * Received a DLPI_BIND_ACK, now verify that the bound SAP
483c7e4935fSss150715 	 * is equal to the SAP requested. Some DLPI MAC type may bind
484c7e4935fSss150715 	 * to a different SAP than requested, in this case 'boundsap'
485c7e4935fSss150715 	 * returns the actual bound SAP. For the case where 'boundsap'
486c7e4935fSss150715 	 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails.
487c7e4935fSss150715 	 */
488c7e4935fSss150715 	if (boundsap != NULL) {
489c7e4935fSss150715 		*boundsap = bindackp->dl_sap;
490c7e4935fSss150715 	} else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) {
491c7e4935fSss150715 		if (dlpi_unbind(dh) != DLPI_SUCCESS)
492c7e4935fSss150715 			return (DLPI_FAILURE);
493c7e4935fSss150715 		else
494c7e4935fSss150715 			return (DLPI_EUNAVAILSAP);
495c7e4935fSss150715 	}
496c7e4935fSss150715 
497c7e4935fSss150715 	dip->dli_sap = bindackp->dl_sap;	/* save sap value in handle */
498c7e4935fSss150715 	return (DLPI_SUCCESS);
499c7e4935fSss150715 }
500c7e4935fSss150715 
501c7e4935fSss150715 int
502c7e4935fSss150715 dlpi_unbind(dlpi_handle_t dh)
503c7e4935fSss150715 {
504c7e4935fSss150715 	dlpi_msg_t	req, ack;
505c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
506c7e4935fSss150715 
507c7e4935fSss150715 	if (dip == NULL)
508c7e4935fSss150715 		return (DLPI_EINHANDLE);
509c7e4935fSss150715 
510c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_UNBIND_REQ);
511c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
512c7e4935fSss150715 
513c7e4935fSss150715 	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
514c7e4935fSss150715 }
515c7e4935fSss150715 
516c7e4935fSss150715 /*
517c7e4935fSss150715  * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and
518c7e4935fSss150715  * based on the "op" value, multicast address is enabled/disabled.
519c7e4935fSss150715  */
520c7e4935fSss150715 static int
521c7e4935fSss150715 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp,
522c7e4935fSss150715     size_t addrlen)
523c7e4935fSss150715 {
524c7e4935fSss150715 	dlpi_msg_t		req, ack;
525c7e4935fSss150715 	dl_enabmulti_req_t	*multireqp;
526c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
527c7e4935fSss150715 
528c7e4935fSss150715 	if (dip == NULL)
529c7e4935fSss150715 		return (DLPI_EINHANDLE);
530c7e4935fSss150715 
531c7e4935fSss150715 	if (addrlen > DLPI_PHYSADDR_MAX)
532c7e4935fSss150715 		return (DLPI_EINVAL);
533c7e4935fSss150715 
534c7e4935fSss150715 	DLPI_MSG_CREATE(req, op);
535c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
536c7e4935fSss150715 
537c7e4935fSss150715 	multireqp = &(req.dlm_msg->enabmulti_req);
538c7e4935fSss150715 	multireqp->dl_addr_length = addrlen;
539c7e4935fSss150715 	multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
540c7e4935fSss150715 	(void) memcpy(&multireqp[1], addrp, addrlen);
541c7e4935fSss150715 
542c7e4935fSss150715 	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
543c7e4935fSss150715 }
544c7e4935fSss150715 
545c7e4935fSss150715 int
546c7e4935fSss150715 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
547c7e4935fSss150715 {
548c7e4935fSss150715 	return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen));
549c7e4935fSss150715 }
550c7e4935fSss150715 
551c7e4935fSss150715 int
552c7e4935fSss150715 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
553c7e4935fSss150715 {
554c7e4935fSss150715 	return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen));
555c7e4935fSss150715 }
556c7e4935fSss150715 
557c7e4935fSss150715 /*
558c7e4935fSss150715  * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based
559c7e4935fSss150715  * on the value of 'op', promiscuous mode is turned on/off at the specified
560c7e4935fSss150715  * 'level'.
561c7e4935fSss150715  */
562c7e4935fSss150715 static int
563c7e4935fSss150715 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level)
564c7e4935fSss150715 {
565c7e4935fSss150715 	dlpi_msg_t		req, ack;
566c7e4935fSss150715 	dl_promiscon_req_t	*promiscreqp;
567c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
568c7e4935fSss150715 
569c7e4935fSss150715 	if (dip == NULL)
570c7e4935fSss150715 		return (DLPI_EINHANDLE);
571c7e4935fSss150715 
572c7e4935fSss150715 	DLPI_MSG_CREATE(req, op);
573c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
574c7e4935fSss150715 
575c7e4935fSss150715 	promiscreqp = &(req.dlm_msg->promiscon_req);
576c7e4935fSss150715 	promiscreqp->dl_level = level;
577c7e4935fSss150715 
578c7e4935fSss150715 	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
579c7e4935fSss150715 }
580c7e4935fSss150715 
581c7e4935fSss150715 int
582c7e4935fSss150715 dlpi_promiscon(dlpi_handle_t dh, uint_t level)
583c7e4935fSss150715 {
584c7e4935fSss150715 	return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level));
585c7e4935fSss150715 }
586c7e4935fSss150715 
587c7e4935fSss150715 int
588c7e4935fSss150715 dlpi_promiscoff(dlpi_handle_t dh, uint_t level)
589c7e4935fSss150715 {
590c7e4935fSss150715 	return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level));
591c7e4935fSss150715 }
592c7e4935fSss150715 
593c7e4935fSss150715 int
594c7e4935fSss150715 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp)
595c7e4935fSss150715 {
596c7e4935fSss150715 	int			retval;
597c7e4935fSss150715 	dlpi_msg_t  		req, ack;
598c7e4935fSss150715 	dl_phys_addr_req_t	*physreqp;
599c7e4935fSss150715 	dl_phys_addr_ack_t	*physackp;
600c7e4935fSss150715 	t_uscalar_t		dataoff, datalen;
601c7e4935fSss150715 	caddr_t			datap, physackendp;
602c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
603c7e4935fSss150715 
604c7e4935fSss150715 	if (dip == NULL)
605c7e4935fSss150715 		return (DLPI_EINHANDLE);
606c7e4935fSss150715 
607c7e4935fSss150715 	if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX)
608c7e4935fSss150715 		return (DLPI_EINVAL);
609c7e4935fSss150715 
610c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ);
611c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK);
612c7e4935fSss150715 
613c7e4935fSss150715 	physreqp = &(req.dlm_msg->physaddr_req);
614c7e4935fSss150715 	physreqp->dl_addr_type = type;
615c7e4935fSss150715 
616c7e4935fSss150715 	retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0);
617c7e4935fSss150715 	if (retval != DLPI_SUCCESS)
618c7e4935fSss150715 		return (retval);
619c7e4935fSss150715 
620c7e4935fSss150715 	/* Received DL_PHYS_ADDR_ACK, store the physical address and length. */
621c7e4935fSss150715 	physackp = &(ack.dlm_msg->physaddr_ack);
622c7e4935fSss150715 	physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
623c7e4935fSss150715 	dataoff = physackp->dl_addr_offset;
624c7e4935fSss150715 	datalen = physackp->dl_addr_length;
625c7e4935fSss150715 	if (dataoff != 0 && datalen != 0) {
626c7e4935fSss150715 		datap = (caddr_t)physackp + dataoff;
627c7e4935fSss150715 		if (datalen > DLPI_PHYSADDR_MAX)
628c7e4935fSss150715 			return (DL_BADADDR);
629c7e4935fSss150715 		if (dataoff < DL_PHYS_ADDR_ACK_SIZE ||
630c7e4935fSss150715 		    datap + datalen > physackendp)
631c7e4935fSss150715 			return (DLPI_EBADMSG);
632c7e4935fSss150715 
633c7e4935fSss150715 		*addrlenp = physackp->dl_addr_length;
634c7e4935fSss150715 		(void) memcpy(addrp, datap, datalen);
635c7e4935fSss150715 	} else {
636c7e4935fSss150715 		*addrlenp = datalen;
637c7e4935fSss150715 	}
638c7e4935fSss150715 
639c7e4935fSss150715 	return (DLPI_SUCCESS);
640c7e4935fSss150715 }
641c7e4935fSss150715 
642c7e4935fSss150715 int
643c7e4935fSss150715 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp,
644c7e4935fSss150715     size_t addrlen)
645c7e4935fSss150715 {
646c7e4935fSss150715 	dlpi_msg_t  		req, ack;
647c7e4935fSss150715 	dl_set_phys_addr_req_t	*setphysreqp;
648c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
649c7e4935fSss150715 
650c7e4935fSss150715 	if (dip == NULL)
651c7e4935fSss150715 		return (DLPI_EINHANDLE);
652c7e4935fSss150715 
653c7e4935fSss150715 	if (addrp == NULL || type != DL_CURR_PHYS_ADDR ||
654c7e4935fSss150715 	    addrlen > DLPI_PHYSADDR_MAX)
655c7e4935fSss150715 		return (DLPI_EINVAL);
656c7e4935fSss150715 
657c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ);
658c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
659c7e4935fSss150715 
660c7e4935fSss150715 	setphysreqp = &(req.dlm_msg->set_physaddr_req);
661c7e4935fSss150715 	setphysreqp->dl_addr_length = addrlen;
662c7e4935fSss150715 	setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
663c7e4935fSss150715 	(void) memcpy(&setphysreqp[1], addrp, addrlen);
664c7e4935fSss150715 
665c7e4935fSss150715 	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
666c7e4935fSss150715 }
667c7e4935fSss150715 
668c7e4935fSss150715 int
669c7e4935fSss150715 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen,
670c7e4935fSss150715     const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp)
671c7e4935fSss150715 {
672c7e4935fSss150715 	dlpi_msg_t		req;
673c7e4935fSss150715 	dl_unitdata_req_t	*udatareqp;
674c7e4935fSss150715 	uint_t			sap;
675c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
676c7e4935fSss150715 
677c7e4935fSss150715 	if (dip == NULL)
678c7e4935fSss150715 		return (DLPI_EINHANDLE);
679c7e4935fSss150715 
680c7e4935fSss150715 	if (dip->dli_oflags & DLPI_RAW)
6813ab45760Sss150715 		return (i_dlpi_strputmsg(dip, NULL, msgbuf, msglen, 0));
682c7e4935fSss150715 
683948f2876Sss150715 	if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX)
684c7e4935fSss150715 		return (DLPI_EINVAL);
685c7e4935fSss150715 
686c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_UNITDATA_REQ);
687c7e4935fSss150715 	udatareqp = &(req.dlm_msg->unitdata_req);
688c7e4935fSss150715 
689c7e4935fSss150715 	/* Set priority to default priority range. */
690c7e4935fSss150715 	udatareqp->dl_priority.dl_min = 0;
691c7e4935fSss150715 	udatareqp->dl_priority.dl_max = 0;
692c7e4935fSss150715 
693c7e4935fSss150715 	/* Use SAP value if specified otherwise use bound SAP value. */
694c7e4935fSss150715 	if (sendp != NULL) {
695c7e4935fSss150715 		sap = sendp->dsi_sap;
696c7e4935fSss150715 		if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE)
697c7e4935fSss150715 			udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min;
698c7e4935fSss150715 		if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE)
699c7e4935fSss150715 			udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max;
700c7e4935fSss150715 	} else {
701c7e4935fSss150715 		sap = dip->dli_sap;
702c7e4935fSss150715 	}
703c7e4935fSss150715 
704c7e4935fSss150715 	udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen;
705c7e4935fSss150715 	udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
706c7e4935fSss150715 
707c7e4935fSss150715 	/*
708c7e4935fSss150715 	 * Since `daddrp' only has the link-layer destination address,
709c7e4935fSss150715 	 * we must prepend or append the SAP (according to dli_sapbefore)
710c7e4935fSss150715 	 * to make a full DLPI address.
711c7e4935fSss150715 	 */
712c7e4935fSss150715 	if (dip->dli_sapbefore) {
713c7e4935fSss150715 		i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen);
714c7e4935fSss150715 		(void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen,
715c7e4935fSss150715 		    daddrp, daddrlen);
716c7e4935fSss150715 	} else {
717c7e4935fSss150715 		(void) memcpy(&udatareqp[1], daddrp, daddrlen);
718c7e4935fSss150715 		i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap,
719c7e4935fSss150715 		    dip->dli_saplen);
720c7e4935fSss150715 	}
721c7e4935fSss150715 
7223ab45760Sss150715 	return (i_dlpi_strputmsg(dip, &req, msgbuf, msglen, 0));
723c7e4935fSss150715 }
724c7e4935fSss150715 
725c7e4935fSss150715 int
726c7e4935fSss150715 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf,
727c7e4935fSss150715     size_t *msglenp, int msec, dlpi_recvinfo_t *recvp)
728c7e4935fSss150715 {
729c7e4935fSss150715 	int			retval;
730c7e4935fSss150715 	dlpi_msg_t		ind;
731c7e4935fSss150715 	size_t			totmsglen;
732c7e4935fSss150715 	dl_unitdata_ind_t	*udatap;
733c7e4935fSss150715 	t_uscalar_t		dataoff, datalen;
734c7e4935fSss150715 	caddr_t			datap, indendp;
735c7e4935fSss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
736c7e4935fSss150715 
737c7e4935fSss150715 	if (dip == NULL)
738c7e4935fSss150715 		return (DLPI_EINHANDLE);
739c7e4935fSss150715 	/*
740c7e4935fSss150715 	 * If handle is in raw mode ignore everything except total message
741c7e4935fSss150715 	 * length.
742c7e4935fSss150715 	 */
743c7e4935fSss150715 	if (dip->dli_oflags & DLPI_RAW) {
7443ab45760Sss150715 		retval = i_dlpi_strgetmsg(dip, msec, NULL, 0, 0, 0, msgbuf,
7453ab45760Sss150715 		    msglenp, &totmsglen);
746c7e4935fSss150715 
747c7e4935fSss150715 		if (retval == DLPI_SUCCESS && recvp != NULL)
748c7e4935fSss150715 			recvp->dri_totmsglen = totmsglen;
749c7e4935fSss150715 		return (retval);
750c7e4935fSss150715 	}
751c7e4935fSss150715 
752c7e4935fSss150715 	DLPI_MSG_CREATE(ind, DL_UNITDATA_IND);
753c7e4935fSss150715 	udatap = &(ind.dlm_msg->unitdata_ind);
754c7e4935fSss150715 	indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz;
755c7e4935fSss150715 
7563ab45760Sss150715 	if ((retval = i_dlpi_strgetmsg(dip, msec, &ind, DL_UNITDATA_IND,
7573ab45760Sss150715 	    DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, msgbuf,
7583ab45760Sss150715 	    msglenp, &totmsglen)) != DLPI_SUCCESS)
759c7e4935fSss150715 		return (retval);
760c7e4935fSss150715 
761c7e4935fSss150715 	/*
762c7e4935fSss150715 	 * If DLPI link provides source address, store source address in
763c7e4935fSss150715 	 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0.
764c7e4935fSss150715 	 */
765c7e4935fSss150715 	if (saddrp != NULL && saddrlenp != NULL)  {
766c7e4935fSss150715 		if (*saddrlenp < DLPI_PHYSADDR_MAX)
767c7e4935fSss150715 			return (DLPI_EINVAL);
768c7e4935fSss150715 
769c7e4935fSss150715 		dataoff = udatap->dl_src_addr_offset;
770c7e4935fSss150715 		datalen = udatap->dl_src_addr_length;
771c7e4935fSss150715 		if (dataoff != 0 && datalen != 0) {
772c7e4935fSss150715 			datap = (caddr_t)udatap + dataoff;
773c7e4935fSss150715 			if (dataoff < DL_UNITDATA_IND_SIZE ||
774c7e4935fSss150715 			    datap + datalen > indendp)
775c7e4935fSss150715 				return (DLPI_EBADMSG);
776c7e4935fSss150715 
777c7e4935fSss150715 			*saddrlenp = datalen - dip->dli_saplen;
778c7e4935fSss150715 			if (*saddrlenp > DLPI_PHYSADDR_MAX)
779c7e4935fSss150715 				return (DL_BADADDR);
780c7e4935fSss150715 
781c7e4935fSss150715 			if (dip->dli_sapbefore)
782c7e4935fSss150715 				datap += dip->dli_saplen;
783c7e4935fSss150715 			(void) memcpy(saddrp, datap, *saddrlenp);
784c7e4935fSss150715 		} else {
785c7e4935fSss150715 			*saddrlenp = 0;
786c7e4935fSss150715 		}
787c7e4935fSss150715 	}
788c7e4935fSss150715 
789c7e4935fSss150715 	/*
790c7e4935fSss150715 	 * If destination address requested, check and save destination
791c7e4935fSss150715 	 * address, if any.
792c7e4935fSss150715 	 */
793c7e4935fSss150715 	if (recvp != NULL) {
794c7e4935fSss150715 		dataoff = udatap->dl_dest_addr_offset;
795c7e4935fSss150715 		datalen = udatap->dl_dest_addr_length;
796c7e4935fSss150715 		if (dataoff != 0 && datalen != 0) {
797c7e4935fSss150715 			datap = (caddr_t)udatap + dataoff;
798c7e4935fSss150715 			if (dataoff < DL_UNITDATA_IND_SIZE ||
799c7e4935fSss150715 			    datap + datalen > indendp)
800c7e4935fSss150715 				return (DLPI_EBADMSG);
801c7e4935fSss150715 
802c7e4935fSss150715 			recvp->dri_destaddrlen = datalen - dip->dli_saplen;
803c7e4935fSss150715 			if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX)
804c7e4935fSss150715 				return (DL_BADADDR);
805c7e4935fSss150715 
806c7e4935fSss150715 			if (dip->dli_sapbefore)
807c7e4935fSss150715 				datap += dip->dli_saplen;
808c7e4935fSss150715 			(void) memcpy(recvp->dri_destaddr, datap,
809c7e4935fSss150715 			    recvp->dri_destaddrlen);
810c7e4935fSss150715 		} else {
811c7e4935fSss150715 			recvp->dri_destaddrlen = 0;
812c7e4935fSss150715 		}
813c7e4935fSss150715 
8145494fa53Sss150715 		recvp->dri_destaddrtype = udatap->dl_group_address;
815c7e4935fSss150715 		recvp->dri_totmsglen = totmsglen;
816c7e4935fSss150715 	}
817c7e4935fSss150715 
818c7e4935fSss150715 	return (DLPI_SUCCESS);
819c7e4935fSss150715 }
820c7e4935fSss150715 
821c7e4935fSss150715 int
8223ab45760Sss150715 dlpi_enabnotify(dlpi_handle_t dh, uint_t notes, dlpi_notifyfunc_t *funcp,
8233ab45760Sss150715     void *arg, dlpi_notifyid_t *id)
8243ab45760Sss150715 {
8253ab45760Sss150715 	int			retval;
8263ab45760Sss150715 	dlpi_msg_t		req, ack;
8273ab45760Sss150715 	dl_notify_req_t		*notifyreqp;
8283ab45760Sss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
8293ab45760Sss150715 	dlpi_notifyent_t	*newnotifp;
8303ab45760Sss150715 	dlpi_info_t 		dlinfo;
8313ab45760Sss150715 
8323ab45760Sss150715 	if (dip == NULL)
8333ab45760Sss150715 		return (DLPI_EINHANDLE);
8343ab45760Sss150715 
8353ab45760Sss150715 	retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
8363ab45760Sss150715 	if (retval != DLPI_SUCCESS)
8373ab45760Sss150715 		return (retval);
8383ab45760Sss150715 	if (dlinfo.di_state != DL_IDLE)
8393ab45760Sss150715 		return (DL_OUTSTATE);
8403ab45760Sss150715 
8413ab45760Sss150715 	if (dip->dli_note_processing)
8423ab45760Sss150715 		return (DLPI_FAILURE);
8433ab45760Sss150715 
8443ab45760Sss150715 	if (funcp == NULL || id == NULL)
8453ab45760Sss150715 		return (DLPI_EINVAL);
8463ab45760Sss150715 
8473ab45760Sss150715 	if ((~DLPI_NOTIFICATION_TYPES & notes) ||
8483ab45760Sss150715 	    !(notes & DLPI_NOTIFICATION_TYPES))
8493ab45760Sss150715 		return (DLPI_ENOTEINVAL);
8503ab45760Sss150715 
8513ab45760Sss150715 	DLPI_MSG_CREATE(req, DL_NOTIFY_REQ);
8523ab45760Sss150715 	DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK);
8533ab45760Sss150715 
8543ab45760Sss150715 	notifyreqp = &(req.dlm_msg->notify_req);
8553ab45760Sss150715 	notifyreqp->dl_notifications = notes;
8563ab45760Sss150715 	notifyreqp->dl_timelimit = 0;
8573ab45760Sss150715 
8583ab45760Sss150715 	retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0);
8593ab45760Sss150715 	if (retval == DL_NOTSUPPORTED)
8603ab45760Sss150715 		return (DLPI_ENOTENOTSUP);
8613ab45760Sss150715 
8623ab45760Sss150715 	if (retval != DLPI_SUCCESS)
8633ab45760Sss150715 		return (retval);
8643ab45760Sss150715 
8653ab45760Sss150715 	if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL)
8663ab45760Sss150715 		return (DL_SYSERR);
8673ab45760Sss150715 
8683ab45760Sss150715 	/* Register notification information. */
8693ab45760Sss150715 	newnotifp->dln_fnp = funcp;
8703ab45760Sss150715 	newnotifp->dln_notes = notes;
8713ab45760Sss150715 	newnotifp->arg = arg;
8723ab45760Sss150715 	newnotifp->dln_rm = B_FALSE;
8733ab45760Sss150715 
8743ab45760Sss150715 	/* Insert notification node at head */
8753ab45760Sss150715 	newnotifp->dln_next = dip->dli_notifylistp;
8763ab45760Sss150715 	dip->dli_notifylistp = newnotifp;
8773ab45760Sss150715 
8783ab45760Sss150715 	*id = (dlpi_notifyid_t)newnotifp;
8793ab45760Sss150715 	return (DLPI_SUCCESS);
8803ab45760Sss150715 }
8813ab45760Sss150715 
8823ab45760Sss150715 int
8833ab45760Sss150715 dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp)
8843ab45760Sss150715 {
8853ab45760Sss150715 	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
8863ab45760Sss150715 	dlpi_notifyent_t	*remid = (dlpi_notifyent_t *)id;
8873ab45760Sss150715 
8883ab45760Sss150715 	if (dip == NULL)
8893ab45760Sss150715 		return (DLPI_EINHANDLE);
8903ab45760Sss150715 
8913ab45760Sss150715 	/* Walk the notifyentry list to find matching id. */
8923ab45760Sss150715 	if (!(i_dlpi_notifyidexists(dip, remid)))
8933ab45760Sss150715 		return (DLPI_ENOTEIDINVAL);
8943ab45760Sss150715 
8953ab45760Sss150715 	if (argp != NULL)
8963ab45760Sss150715 		*argp = remid->arg;
8973ab45760Sss150715 
8983ab45760Sss150715 	remid->dln_rm = B_TRUE;
8993ab45760Sss150715 	/* Delete node if callbacks are not being processed. */
9003ab45760Sss150715 	if (!dip->dli_note_processing)
9013ab45760Sss150715 		i_dlpi_deletenotifyid(dip);
9023ab45760Sss150715 
9033ab45760Sss150715 	return (DLPI_SUCCESS);
9043ab45760Sss150715 }
9053ab45760Sss150715 
9063ab45760Sss150715 int
907c7e4935fSss150715 dlpi_fd(dlpi_handle_t dh)
908c7e4935fSss150715 {
909c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
910c7e4935fSss150715 
911c7e4935fSss150715 	return (dip != NULL ? dip->dli_fd : -1);
912c7e4935fSss150715 }
913c7e4935fSss150715 
914c7e4935fSss150715 int
915c7e4935fSss150715 dlpi_set_timeout(dlpi_handle_t dh, int sec)
916c7e4935fSss150715 {
917c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
918c7e4935fSss150715 
919c7e4935fSss150715 	if (dip == NULL)
920c7e4935fSss150715 		return (DLPI_EINHANDLE);
921c7e4935fSss150715 
922c7e4935fSss150715 	dip->dli_timeout = sec;
923c7e4935fSss150715 	return (DLPI_SUCCESS);
924c7e4935fSss150715 }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate const char *
927c7e4935fSss150715 dlpi_linkname(dlpi_handle_t dh)
9287c478bd9Sstevel@tonic-gate {
929c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
9307c478bd9Sstevel@tonic-gate 
931c7e4935fSss150715 	return (dip != NULL ? dip->dli_linkname : NULL);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
934c7e4935fSss150715 /*
935c7e4935fSss150715  * Returns DLPI style stored in the handle.
936c7e4935fSss150715  * Note: This function is used for test purposes only. Do not remove without
937c7e4935fSss150715  * fixing the DLPI testsuite.
938c7e4935fSss150715  */
939c7e4935fSss150715 uint_t
940c7e4935fSss150715 dlpi_style(dlpi_handle_t dh)
9417c478bd9Sstevel@tonic-gate {
942c7e4935fSss150715 	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
9437c478bd9Sstevel@tonic-gate 
944c7e4935fSss150715 	return (dip->dli_style);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
947948f2876Sss150715 uint_t
948948f2876Sss150715 dlpi_arptype(uint_t dlpitype)
949948f2876Sss150715 {
950948f2876Sss150715 	switch (dlpitype) {
951948f2876Sss150715 
952948f2876Sss150715 	case DL_ETHER:
953948f2876Sss150715 		return (ARPHRD_ETHER);
954948f2876Sss150715 
955948f2876Sss150715 	case DL_FRAME:
956948f2876Sss150715 		return (ARPHRD_FRAME);
957948f2876Sss150715 
958948f2876Sss150715 	case DL_ATM:
959948f2876Sss150715 		return (ARPHRD_ATM);
960948f2876Sss150715 
961948f2876Sss150715 	case DL_IPATM:
962948f2876Sss150715 		return (ARPHRD_IPATM);
963948f2876Sss150715 
964948f2876Sss150715 	case DL_HDLC:
965948f2876Sss150715 		return (ARPHRD_HDLC);
966948f2876Sss150715 
967948f2876Sss150715 	case DL_FC:
968948f2876Sss150715 		return (ARPHRD_FC);
969948f2876Sss150715 
970948f2876Sss150715 	case DL_CSMACD:				/* ieee 802 networks */
971948f2876Sss150715 	case DL_TPB:
972948f2876Sss150715 	case DL_TPR:
973948f2876Sss150715 	case DL_METRO:
974948f2876Sss150715 	case DL_FDDI:
975948f2876Sss150715 		return (ARPHRD_IEEE802);
976948f2876Sss150715 
977948f2876Sss150715 	case DL_IB:
978948f2876Sss150715 		return (ARPHRD_IB);
979948f2876Sss150715 
980948f2876Sss150715 	case DL_IPV4:
981948f2876Sss150715 	case DL_IPV6:
982948f2876Sss150715 		return (ARPHRD_TUNNEL);
983948f2876Sss150715 	}
984948f2876Sss150715 
985948f2876Sss150715 	return (0);
986948f2876Sss150715 }
987948f2876Sss150715 
988948f2876Sss150715 uint_t
989948f2876Sss150715 dlpi_iftype(uint_t dlpitype)
990948f2876Sss150715 {
991948f2876Sss150715 	switch (dlpitype) {
992948f2876Sss150715 
993948f2876Sss150715 	case DL_ETHER:
994948f2876Sss150715 		return (IFT_ETHER);
995948f2876Sss150715 
996948f2876Sss150715 	case DL_ATM:
997948f2876Sss150715 		return (IFT_ATM);
998948f2876Sss150715 
999948f2876Sss150715 	case DL_CSMACD:
1000948f2876Sss150715 		return (IFT_ISO88023);
1001948f2876Sss150715 
1002948f2876Sss150715 	case DL_TPB:
1003948f2876Sss150715 		return (IFT_ISO88024);
1004948f2876Sss150715 
1005948f2876Sss150715 	case DL_TPR:
1006948f2876Sss150715 		return (IFT_ISO88025);
1007948f2876Sss150715 
1008948f2876Sss150715 	case DL_FDDI:
1009948f2876Sss150715 		return (IFT_FDDI);
1010948f2876Sss150715 
1011948f2876Sss150715 	case DL_IB:
1012948f2876Sss150715 		return (IFT_IB);
1013948f2876Sss150715 
1014948f2876Sss150715 	case DL_OTHER:
1015948f2876Sss150715 		return (IFT_OTHER);
1016948f2876Sss150715 	}
1017948f2876Sss150715 
1018948f2876Sss150715 	return (0);
1019948f2876Sss150715 }
1020948f2876Sss150715 
1021c7e4935fSss150715 /*
1022d62bc4baSyz147064  * This function attempts to open a device under the following namespaces:
1023b127ac41SPhilip Kirk  *	/dev/ipnet	- if DLPI_DEVIPNET is specified
1024d62bc4baSyz147064  *      /dev/net	- if a data-link with the specified name exists
1025d62bc4baSyz147064  *	/dev		- if DLPI_DEVONLY is specified, or if there is no
1026d62bc4baSyz147064  *			  data-link with the specified name (could be /dev/ip)
1027d62bc4baSyz147064  *
1028b127ac41SPhilip Kirk  * In particular, if DLPI_DEVIPNET is not specified, this function is used to
1029b127ac41SPhilip Kirk  * open a data-link node, or "/dev/ip" node. It is usually be called firstly
1030d62bc4baSyz147064  * with style1 being B_TRUE, and if that fails and the return value is not
1031d62bc4baSyz147064  * DLPI_ENOTSTYLE2, the function will again be called with style1 being
1032d62bc4baSyz147064  * B_FALSE (style-1 open attempt first, then style-2 open attempt).
1033d62bc4baSyz147064  *
1034d62bc4baSyz147064  * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node
1035d62bc4baSyz147064  * directly.
1036d62bc4baSyz147064  *
1037d62bc4baSyz147064  * Otherwise, for style-1 attempt, the function will try to open the style-1
1038d62bc4baSyz147064  * /dev/net node, and perhaps fallback to open the style-1 /dev node if the
1039d62bc4baSyz147064  * give name is not a data-link name (e.g., it is /dev/ip). Note that the
1040d62bc4baSyz147064  * fallback and the subsequent style-2 attempt will not happen if:
1041d62bc4baSyz147064  * 1. style-1 opening of the /dev/net node succeeds;
1042d62bc4baSyz147064  * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT,
1043d62bc4baSyz147064  *    which means that the specific /dev/net node exist, but the attempt fails
1044d62bc4baSyz147064  *    for some other reason;
1045d62bc4baSyz147064  * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is
1046d62bc4baSyz147064  *    a known device name or its VLAN PPA hack name. (for example, assuming
1047d62bc4baSyz147064  *    device bge0 is renamed to net0, opening /dev/net/bge1000 would return
1048d62bc4baSyz147064  *    ENOENT, but we should not fallback to open /dev/bge1000 in this case,
1049d62bc4baSyz147064  *    as VLAN 1 over the bge0 device should be named as net1000.
1050d62bc4baSyz147064  *
1051d62bc4baSyz147064  * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed
1052d62bc4baSyz147064  * the second style-2 open attempt.
1053c7e4935fSss150715  */
10547c478bd9Sstevel@tonic-gate static int
1055d62bc4baSyz147064 i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
10567c478bd9Sstevel@tonic-gate {
1057c7e4935fSss150715 	char		path[MAXPATHLEN];
1058c7e4935fSss150715 	int		oflags;
1059c7e4935fSss150715 
1060d62bc4baSyz147064 	errno = ENOENT;
1061c7e4935fSss150715 	oflags = O_RDWR;
1062c7e4935fSss150715 	if (flags & DLPI_EXCL)
1063c7e4935fSss150715 		oflags |= O_EXCL;
1064c7e4935fSss150715 
1065b127ac41SPhilip Kirk 	if (flags & DLPI_DEVIPNET) {
1066b127ac41SPhilip Kirk 		(void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider);
1067b127ac41SPhilip Kirk 		if ((*fd = open(path, oflags)) != -1)
1068b127ac41SPhilip Kirk 			return (DLPI_SUCCESS);
1069b127ac41SPhilip Kirk 		else
1070b127ac41SPhilip Kirk 			return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1071b127ac41SPhilip Kirk 	} else if (style1 && !(flags & DLPI_DEVONLY)) {
1072d62bc4baSyz147064 		char		driver[DLPI_LINKNAME_MAX];
1073d62bc4baSyz147064 		char		device[DLPI_LINKNAME_MAX];
1074d62bc4baSyz147064 		datalink_id_t	linkid;
1075d62bc4baSyz147064 		uint_t		ppa;
10764ac67f02SAnurag S. Maskey 		dladm_handle_t	handle;
1077c7e4935fSss150715 
1078d62bc4baSyz147064 		/*
1079d62bc4baSyz147064 		 * This is not a valid style-1 name. It could be "ip" module
1080d62bc4baSyz147064 		 * for example. Fallback to open the /dev node.
1081d62bc4baSyz147064 		 */
1082d62bc4baSyz147064 		if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS)
1083d62bc4baSyz147064 			goto fallback;
1084d62bc4baSyz147064 
1085d62bc4baSyz147064 		(void) snprintf(path, sizeof (path), "/dev/net/%s", provider);
1086c7e4935fSss150715 		if ((*fd = open(path, oflags)) != -1)
1087c7e4935fSss150715 			return (DLPI_SUCCESS);
1088c7e4935fSss150715 
1089c7e4935fSss150715 		/*
1090d62bc4baSyz147064 		 * We don't fallback to open the /dev node when it returns
1091d62bc4baSyz147064 		 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2
1092d62bc4baSyz147064 		 * is returned to indicate not to continue the style-2 open.
1093c7e4935fSss150715 		 */
1094d62bc4baSyz147064 		if (errno != ENOENT)
1095d62bc4baSyz147064 			return (DLPI_ENOTSTYLE2);
1096c7e4935fSss150715 
1097d62bc4baSyz147064 		/*
1098d62bc4baSyz147064 		 * We didn't find the /dev/net node. Then we check whether
1099d62bc4baSyz147064 		 * the given name is a device name or its VLAN PPA hack name
1100d62bc4baSyz147064 		 * of a known link. If the answer is yes, and this link
1101d62bc4baSyz147064 		 * supports vanity naming, then the link (or the VLAN) should
1102d62bc4baSyz147064 		 * also have its /dev/net node but perhaps with another vanity
1103d62bc4baSyz147064 		 * name (for example, when bge0 is renamed to net0). In this
1104d62bc4baSyz147064 		 * case, although attempt to open the /dev/net/<devname> fails,
1105d62bc4baSyz147064 		 * we should not fallback to open the /dev/<devname> node.
1106d62bc4baSyz147064 		 */
1107d62bc4baSyz147064 		(void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver,
1108d62bc4baSyz147064 		    ppa >= 1000 ? ppa % 1000 : ppa);
1109d62bc4baSyz147064 
11104ac67f02SAnurag S. Maskey 		/* open libdladm handle rather than taking it as input */
11114ac67f02SAnurag S. Maskey 		if (dladm_open(&handle) != DLADM_STATUS_OK)
1112*e11c3f44Smeem 			goto fallback;
11134ac67f02SAnurag S. Maskey 
11144ac67f02SAnurag S. Maskey 		if (dladm_dev2linkid(handle, device, &linkid) ==
11154ac67f02SAnurag S. Maskey 		    DLADM_STATUS_OK) {
1116d62bc4baSyz147064 			dladm_phys_attr_t dpa;
1117d62bc4baSyz147064 
11184ac67f02SAnurag S. Maskey 			if ((dladm_phys_info(handle, linkid, &dpa,
11194ac67f02SAnurag S. Maskey 			    DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK &&
11204ac67f02SAnurag S. Maskey 			    !dpa.dp_novanity) {
11214ac67f02SAnurag S. Maskey 				dladm_close(handle);
1122d62bc4baSyz147064 				return (DLPI_ENOTSTYLE2);
1123d62bc4baSyz147064 			}
1124d62bc4baSyz147064 		}
11254ac67f02SAnurag S. Maskey 		dladm_close(handle);
1126d62bc4baSyz147064 	}
1127d62bc4baSyz147064 
1128d62bc4baSyz147064 fallback:
1129d62bc4baSyz147064 	(void) snprintf(path, sizeof (path), "/dev/%s", provider);
1130c7e4935fSss150715 	if ((*fd = open(path, oflags)) != -1)
1131c7e4935fSss150715 		return (DLPI_SUCCESS);
1132c7e4935fSss150715 
1133c7e4935fSss150715 	return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1134c7e4935fSss150715 }
1135c7e4935fSss150715 
1136c7e4935fSss150715 /*
1137c7e4935fSss150715  * Open a style 1 link. PPA is implicitly attached.
1138c7e4935fSss150715  */
1139c7e4935fSss150715 static int
1140c7e4935fSss150715 i_dlpi_style1_open(dlpi_impl_t *dip)
1141c7e4935fSss150715 {
1142c7e4935fSss150715 	int		retval, save_errno;
1143c7e4935fSss150715 	int		fd;
1144c7e4935fSss150715 
1145c7e4935fSss150715 	/*
1146c7e4935fSss150715 	 * In order to support open of syntax like device[.module[.module...]]
1147c7e4935fSss150715 	 * where modules need to be pushed onto the device stream, open only
1148c7e4935fSss150715 	 * device name, otherwise open the full linkname.
1149c7e4935fSss150715 	 */
1150d62bc4baSyz147064 	retval = i_dlpi_open((dip->dli_mod_cnt != 0) ?
1151d62bc4baSyz147064 	    dip->dli_provider : dip->dli_linkname, &fd,
1152d62bc4baSyz147064 	    dip->dli_oflags, B_TRUE);
1153c7e4935fSss150715 
1154c7e4935fSss150715 	if (retval != DLPI_SUCCESS) {
1155c7e4935fSss150715 		dip->dli_mod_pushed = 0;
1156c7e4935fSss150715 		return (retval);
1157c7e4935fSss150715 	}
1158c7e4935fSss150715 	dip->dli_fd = fd;
1159c7e4935fSss150715 
1160c7e4935fSss150715 	/*
1161c7e4935fSss150715 	 * Try to push modules (if any) onto the device stream. If I_PUSH
1162c7e4935fSss150715 	 * fails, we increment count of modules pushed (dli_mod_pushed)
1163c7e4935fSss150715 	 * expecting it is last module to be pushed and thus will be pushed
1164c7e4935fSss150715 	 * in i_dlpi_style2_open().
1165c7e4935fSss150715 	 */
1166c7e4935fSss150715 	for (dip->dli_mod_pushed = 0; dip->dli_mod_pushed < dip->dli_mod_cnt;
1167c7e4935fSss150715 	    dip->dli_mod_pushed++) {
1168c7e4935fSss150715 		if (ioctl(fd, I_PUSH,
1169c7e4935fSss150715 		    dip->dli_modlist[dip->dli_mod_pushed]) == -1) {
1170c7e4935fSss150715 			dip->dli_mod_pushed++;
1171c7e4935fSss150715 			return (DLPI_FAILURE);
1172c7e4935fSss150715 		}
1173c7e4935fSss150715 	}
1174c7e4935fSss150715 
1175c7e4935fSss150715 	if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) {
1176c7e4935fSss150715 		save_errno = errno;
1177c7e4935fSss150715 		(void) close(dip->dli_fd);
1178c7e4935fSss150715 		errno = save_errno;
1179c7e4935fSss150715 		dip->dli_mod_pushed = 0;
1180c7e4935fSss150715 		return (retval);
1181c7e4935fSss150715 	}
1182c7e4935fSss150715 
1183c7e4935fSss150715 	return (DLPI_SUCCESS);
1184c7e4935fSss150715 }
1185c7e4935fSss150715 
1186c7e4935fSss150715 /*
1187c7e4935fSss150715  * Open a style 2 link. PPA must be explicitly attached.
1188c7e4935fSss150715  */
1189c7e4935fSss150715 static int
1190c7e4935fSss150715 i_dlpi_style2_open(dlpi_impl_t *dip)
1191c7e4935fSss150715 {
1192c7e4935fSss150715 	int 		fd;
1193c7e4935fSss150715 	int 		retval, save_errno;
1194c7e4935fSss150715 
1195c7e4935fSss150715 	/*
1196c7e4935fSss150715 	 * If style 1 open failed, we need to determine how far it got and
1197c7e4935fSss150715 	 * finish up the open() call as a style 2 open.
1198c7e4935fSss150715 	 *
1199c7e4935fSss150715 	 * If no modules were pushed (mod_pushed == 0), then we need to
1200c7e4935fSss150715 	 * open it as a style 2 link.
1201c7e4935fSss150715 	 *
1202c7e4935fSss150715 	 * If the pushing of the last module failed, we need to
1203c7e4935fSss150715 	 * try pushing it as a style 2 module. Decrement dli_mod_pushed
1204c7e4935fSss150715 	 * count so it can be pushed onto the stream.
1205c7e4935fSss150715 	 *
1206c7e4935fSss150715 	 * Otherwise we failed during the push of an intermediate module and
1207c7e4935fSss150715 	 * must fail out and close the link.
1208c7e4935fSss150715 	 */
1209c7e4935fSss150715 	if (dip->dli_mod_pushed == 0) {
1210c7e4935fSss150715 		if ((retval = i_dlpi_open(dip->dli_provider, &fd,
1211d62bc4baSyz147064 		    dip->dli_oflags, B_FALSE)) != DLPI_SUCCESS) {
1212c7e4935fSss150715 			return (retval);
1213d62bc4baSyz147064 		}
1214c7e4935fSss150715 		dip->dli_fd = fd;
1215c7e4935fSss150715 	} else if (dip->dli_mod_pushed == dip->dli_mod_cnt) {
1216c7e4935fSss150715 		if (i_dlpi_remove_ppa(dip->dli_modlist[dip->dli_mod_cnt - 1])
1217c7e4935fSss150715 		    != DLPI_SUCCESS)
1218c7e4935fSss150715 			return (DLPI_ELINKNAMEINVAL);
1219c7e4935fSss150715 
1220c7e4935fSss150715 		dip->dli_mod_pushed--;
1221c7e4935fSss150715 		fd = dip->dli_fd;
1222c7e4935fSss150715 	} else {
1223c7e4935fSss150715 		return (DLPI_ELINKNAMEINVAL);
1224c7e4935fSss150715 	}
1225c7e4935fSss150715 
1226c7e4935fSss150715 	/* Try and push modules (if any) onto the device stream. */
1227c7e4935fSss150715 	for (; dip->dli_mod_pushed < dip->dli_mod_cnt; dip->dli_mod_pushed++) {
1228c7e4935fSss150715 		if (ioctl(fd, I_PUSH,
1229c7e4935fSss150715 		    dip->dli_modlist[dip->dli_mod_pushed]) == -1) {
1230c7e4935fSss150715 			retval = DL_SYSERR;
1231c7e4935fSss150715 			goto failure;
1232c7e4935fSss150715 		}
1233c7e4935fSss150715 	}
1234c7e4935fSss150715 
1235c7e4935fSss150715 	/*
1236c7e4935fSss150715 	 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a
1237c7e4935fSss150715 	 * DLPI link so attach and ignore rest.
1238c7e4935fSss150715 	 */
1239c7e4935fSss150715 	if (dip->dli_oflags & DLPI_SERIAL)
1240c7e4935fSss150715 		goto attach;
1241c7e4935fSss150715 
1242c7e4935fSss150715 	if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS)
1243c7e4935fSss150715 		goto failure;
1244c7e4935fSss150715 
1245c7e4935fSss150715 	/*
1246c7e4935fSss150715 	 * Succeeded opening the link and verified it is style2. Now attach to
1247c7e4935fSss150715 	 * PPA only if DLPI_NOATTACH is not set.
1248c7e4935fSss150715 	 */
1249c7e4935fSss150715 	if (dip->dli_oflags & DLPI_NOATTACH)
1250c7e4935fSss150715 		return (DLPI_SUCCESS);
1251c7e4935fSss150715 
1252c7e4935fSss150715 attach:
1253c7e4935fSss150715 	if ((retval = i_dlpi_attach(dip)) != DLPI_SUCCESS)
1254c7e4935fSss150715 		goto failure;
1255c7e4935fSss150715 
1256c7e4935fSss150715 	return (DLPI_SUCCESS);
1257c7e4935fSss150715 
1258c7e4935fSss150715 failure:
1259c7e4935fSss150715 	save_errno = errno;
1260c7e4935fSss150715 	(void) close(dip->dli_fd);
1261c7e4935fSss150715 	errno = save_errno;
1262c7e4935fSss150715 	return (retval);
1263c7e4935fSss150715 }
1264c7e4935fSss150715 
1265c7e4935fSss150715 /*
1266c7e4935fSss150715  * Verify with DLPI that the link is the expected DLPI 'style' device,
1267c7e4935fSss150715  * dlpi_info sets the DLPI style in the DLPI handle.
1268c7e4935fSss150715  */
1269c7e4935fSss150715 static int
1270c7e4935fSss150715 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style)
1271c7e4935fSss150715 {
1272c7e4935fSss150715 	int retval;
1273c7e4935fSss150715 	dlpi_info_t dlinfo;
1274c7e4935fSss150715 
1275c7e4935fSss150715 	retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
1276c7e4935fSss150715 	if (retval == DLPI_SUCCESS && dip->dli_style != style)
1277c7e4935fSss150715 		retval = DLPI_EBADLINK;
1278c7e4935fSss150715 
1279c7e4935fSss150715 	return (retval);
1280c7e4935fSss150715 }
1281c7e4935fSss150715 
1282c7e4935fSss150715 /*
1283c7e4935fSss150715  * Remove PPA from end of linkname.
1284c7e4935fSss150715  * Return DLPI_SUCCESS if found, else return DLPI_FAILURE.
1285c7e4935fSss150715  */
1286c7e4935fSss150715 static int
1287c7e4935fSss150715 i_dlpi_remove_ppa(char *linkname)
1288c7e4935fSss150715 {
1289c7e4935fSss150715 	int i = strlen(linkname) - 1;
1290c7e4935fSss150715 
1291c7e4935fSss150715 	if (i == -1 || !isdigit(linkname[i--]))
1292c7e4935fSss150715 		return (DLPI_FAILURE);
1293c7e4935fSss150715 
1294c7e4935fSss150715 	while (i >= 0 && isdigit(linkname[i]))
1295c7e4935fSss150715 		i--;
1296c7e4935fSss150715 
1297c7e4935fSss150715 	linkname[i + 1] = '\0';
1298c7e4935fSss150715 	return (DLPI_SUCCESS);
1299c7e4935fSss150715 }
1300c7e4935fSss150715 
1301c7e4935fSss150715 /*
1302c7e4935fSss150715  * For DLPI style 2 providers, an explicit attach of PPA is required.
1303c7e4935fSss150715  */
1304c7e4935fSss150715 static int
1305c7e4935fSss150715 i_dlpi_attach(dlpi_impl_t *dip)
1306c7e4935fSss150715 {
1307c7e4935fSss150715 	dlpi_msg_t		req, ack;
1308c7e4935fSss150715 	dl_attach_req_t		*attachreqp;
1309c7e4935fSss150715 
1310c7e4935fSss150715 	/*
1311c7e4935fSss150715 	 * Special case: DLPI_SERIAL flag (synchronous serial lines)
1312c7e4935fSss150715 	 * is not a DLPI link so ignore DLPI style.
1313c7e4935fSss150715 	 */
1314c7e4935fSss150715 	if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL))
1315c7e4935fSss150715 		return (DLPI_ENOTSTYLE2);
1316c7e4935fSss150715 
1317c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_ATTACH_REQ);
1318c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
1319c7e4935fSss150715 
1320c7e4935fSss150715 	attachreqp = &(req.dlm_msg->attach_req);
1321c7e4935fSss150715 	attachreqp->dl_ppa = dip->dli_ppa;
1322c7e4935fSss150715 
1323c7e4935fSss150715 	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
1324c7e4935fSss150715 }
1325c7e4935fSss150715 
1326c7e4935fSss150715 /*
1327c7e4935fSss150715  * Enable DLPI passive mode on a DLPI handle. We intentionally do not care
1328c7e4935fSss150715  * if this request fails, as this indicates the underlying DLPI device does
1329c7e4935fSss150715  * not support link aggregation (pre-GLDV3 device drivers), and thus will
1330c7e4935fSss150715  * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing
1331c7e4935fSss150715  * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p).
1332c7e4935fSss150715  */
1333c7e4935fSss150715 static void
1334c7e4935fSss150715 i_dlpi_passive(dlpi_impl_t *dip)
1335c7e4935fSss150715 {
1336c7e4935fSss150715 	dlpi_msg_t		req, ack;
1337c7e4935fSss150715 
1338c7e4935fSss150715 	DLPI_MSG_CREATE(req, DL_PASSIVE_REQ);
1339c7e4935fSss150715 	DLPI_MSG_CREATE(ack, DL_OK_ACK);
1340c7e4935fSss150715 
1341c7e4935fSss150715 	(void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0);
1342c7e4935fSss150715 }
1343c7e4935fSss150715 
1344c7e4935fSss150715 /*
1345c7e4935fSss150715  * Send a dlpi control message and/or data message on a stream. The inputs
1346c7e4935fSss150715  * for this function are:
13473ab45760Sss150715  * 	dlpi_impl_t *dip: internal dlpi handle to open stream
1348c7e4935fSss150715  *	const dlpi_msg_t *dlreqp: request message structure
1349c7e4935fSss150715  *	void *databuf:	data buffer
1350c7e4935fSss150715  *	size_t datalen:	data buffer len
1351c7e4935fSss150715  *	int flags:	flags to set for putmsg()
1352c7e4935fSss150715  * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure.
1353c7e4935fSss150715  */
1354c7e4935fSss150715 static int
13553ab45760Sss150715 i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1356c7e4935fSss150715     const void *databuf, size_t datalen, int flags)
1357c7e4935fSss150715 {
1358c7e4935fSss150715 	int		retval;
13593ab45760Sss150715 	int		fd = dip->dli_fd;
13607c478bd9Sstevel@tonic-gate 	struct strbuf	ctl;
13617c478bd9Sstevel@tonic-gate 	struct strbuf   data;
1362c7e4935fSss150715 
1363c7e4935fSss150715 	if (dlreqp != NULL) {
1364c7e4935fSss150715 		ctl.buf = (void *)dlreqp->dlm_msg;
1365c7e4935fSss150715 		ctl.len = dlreqp->dlm_msgsz;
1366c7e4935fSss150715 	}
1367c7e4935fSss150715 
1368c7e4935fSss150715 	data.buf = (void *)databuf;
1369c7e4935fSss150715 	data.len = datalen;
1370c7e4935fSss150715 
1371c7e4935fSss150715 	retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl),
1372c7e4935fSss150715 	    (databuf == NULL ? NULL : &data), flags);
1373c7e4935fSss150715 
1374c7e4935fSss150715 	return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR);
1375c7e4935fSss150715 }
1376c7e4935fSss150715 
1377c7e4935fSss150715 /*
1378c7e4935fSss150715  * Get a DLPI control message and/or data message from a stream. The inputs
1379c7e4935fSss150715  * for this function are:
13803ab45760Sss150715  * 	dlpi_impl_t *dip: 	internal dlpi handle
1381c7e4935fSss150715  * 	int msec: 		timeout to wait for message
1382c7e4935fSss150715  *	dlpi_msg_t *dlreplyp:	reply message structure, the message size
1383c7e4935fSss150715  *				member on return stores actual size received
1384c7e4935fSss150715  *	t_uscalar_t dlreqprim: 	requested primitive
1385c7e4935fSss150715  *	t_uscalar_t dlreplyprim:acknowledged primitive in response to request
1386c7e4935fSss150715  *	size_t dlreplyminsz:	minimum size of acknowledged primitive size
1387c7e4935fSss150715  *	void *databuf: 		data buffer
1388c7e4935fSss150715  *	size_t *datalenp:	data buffer len
1389c7e4935fSss150715  *	size_t *totdatalenp: 	total data received. Greater than 'datalenp' if
1390c7e4935fSss150715  *				actual data received is larger than 'databuf'
1391c7e4935fSss150715  * Function returns DLPI_SUCCESS if requested message is retrieved
13923ab45760Sss150715  * otherwise returns error code or timeouts. If a notification arrives on
13933ab45760Sss150715  * the stream the callback is notified. However, error returned during the
13943ab45760Sss150715  * handling of notification is ignored as it would be confusing to actual caller
13953ab45760Sss150715  * of this function.
1396c7e4935fSss150715  */
1397c7e4935fSss150715 static int
13983ab45760Sss150715 i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp,
13993ab45760Sss150715     t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz,
14003ab45760Sss150715     void *databuf, size_t *datalenp, size_t *totdatalenp)
1401c7e4935fSss150715 {
1402c7e4935fSss150715 	int			retval;
1403*e11c3f44Smeem 	int			flags;
14043ab45760Sss150715 	int			fd = dip->dli_fd;
1405c7e4935fSss150715 	struct strbuf		ctl, data;
1406c7e4935fSss150715 	struct pollfd		pfd;
1407c7e4935fSss150715 	hrtime_t		start, current;
1408c7e4935fSss150715 	long			bufc[DLPI_CHUNKSIZE / sizeof (long)];
1409c7e4935fSss150715 	long			bufd[DLPI_CHUNKSIZE / sizeof (long)];
1410c7e4935fSss150715 	union DL_primitives	*dlprim;
14113ab45760Sss150715 	dl_notify_ind_t		*dlnotif;
1412c7e4935fSss150715 	boolean_t		infinite = (msec < 0);	/* infinite timeout */
1413c7e4935fSss150715 
1414c623edd3SGirish Moodalbail 	/*
1415c623edd3SGirish Moodalbail 	 * dlreplyp and databuf can be NULL at the same time, to force a check
1416c623edd3SGirish Moodalbail 	 * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI).
1417c623edd3SGirish Moodalbail 	 * this will be true more so for DLPI_RAW mode with notifications
1418c623edd3SGirish Moodalbail 	 * enabled.
1419c623edd3SGirish Moodalbail 	 */
1420c623edd3SGirish Moodalbail 	if ((databuf == NULL && datalenp != NULL) ||
1421c7e4935fSss150715 	    (databuf != NULL && datalenp == NULL))
1422c7e4935fSss150715 		return (DLPI_EINVAL);
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	pfd.fd = fd;
14257c478bd9Sstevel@tonic-gate 	pfd.events = POLLIN | POLLPRI;
14267c478bd9Sstevel@tonic-gate 
1427c7e4935fSss150715 	ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg;
14287c478bd9Sstevel@tonic-gate 	ctl.len = 0;
1429c7e4935fSss150715 	ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz;
14307c478bd9Sstevel@tonic-gate 
1431c7e4935fSss150715 	data.buf = (databuf == NULL) ? bufd : databuf;
14327c478bd9Sstevel@tonic-gate 	data.len = 0;
1433c7e4935fSss150715 	data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp;
14347c478bd9Sstevel@tonic-gate 
1435c7e4935fSss150715 	for (;;) {
1436c7e4935fSss150715 		if (!infinite)
1437c7e4935fSss150715 			start = gethrtime() / (NANOSEC / MILLISEC);
14387c478bd9Sstevel@tonic-gate 
1439c7e4935fSss150715 		switch (poll(&pfd, 1, msec)) {
1440c7e4935fSss150715 		default:
1441948f2876Sss150715 			if (pfd.revents & POLLHUP)
1442948f2876Sss150715 				return (DL_SYSERR);
14437c478bd9Sstevel@tonic-gate 			break;
14447c478bd9Sstevel@tonic-gate 		case 0:
1445c7e4935fSss150715 			return (DLPI_ETIMEDOUT);
14467c478bd9Sstevel@tonic-gate 		case -1:
1447c7e4935fSss150715 			return (DL_SYSERR);
14487c478bd9Sstevel@tonic-gate 		}
14497c478bd9Sstevel@tonic-gate 
1450*e11c3f44Smeem 		flags = 0;
1451c7e4935fSss150715 		if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0)
1452c7e4935fSss150715 			return (DL_SYSERR);
14537c478bd9Sstevel@tonic-gate 
1454c7e4935fSss150715 		if (totdatalenp != NULL)
1455c7e4935fSss150715 			*totdatalenp = data.len;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 		/*
1458c7e4935fSss150715 		 * The supplied DLPI_CHUNKSIZE sized buffers are large enough
1459c7e4935fSss150715 		 * to retrieve all valid DLPI responses in one iteration.
1460c7e4935fSss150715 		 * If MORECTL or MOREDATA is set, we are not interested in the
1461c7e4935fSss150715 		 * remainder of the message. Temporary buffers are used to
1462c7e4935fSss150715 		 * drain the remainder of this message.
1463c7e4935fSss150715 		 * The special case we have to account for is if
1464c7e4935fSss150715 		 * a higher priority messages is enqueued  whilst handling
1465c7e4935fSss150715 		 * this condition. We use a change in the flags parameter
1466c7e4935fSss150715 		 * returned by getmsg() to indicate the message has changed.
14677c478bd9Sstevel@tonic-gate 		 */
1468c7e4935fSss150715 		while (retval & (MORECTL | MOREDATA)) {
1469c7e4935fSss150715 			struct strbuf   cscratch, dscratch;
1470c7e4935fSss150715 			int		oflags = flags;
1471c7e4935fSss150715 
1472c7e4935fSss150715 			cscratch.buf = (char *)bufc;
1473c7e4935fSss150715 			dscratch.buf = (char *)bufd;
1474c7e4935fSss150715 			cscratch.len = dscratch.len = 0;
1475c7e4935fSss150715 			cscratch.maxlen = dscratch.maxlen =
1476c7e4935fSss150715 			    sizeof (bufc);
1477c7e4935fSss150715 
1478c7e4935fSss150715 			if ((retval = getmsg(fd, &cscratch, &dscratch,
1479c7e4935fSss150715 			    &flags)) < 0)
1480c7e4935fSss150715 				return (DL_SYSERR);
1481c7e4935fSss150715 
1482c7e4935fSss150715 			if (totdatalenp != NULL)
1483c7e4935fSss150715 				*totdatalenp += dscratch.len;
1484c7e4935fSss150715 			/*
1485c7e4935fSss150715 			 * In the special case of higher priority
1486c7e4935fSss150715 			 * message received, the low priority message
1487c7e4935fSss150715 			 * received earlier is discarded, if no data
1488c7e4935fSss150715 			 * or control message is left.
1489c7e4935fSss150715 			 */
1490c7e4935fSss150715 			if ((flags != oflags) &&
1491c7e4935fSss150715 			    !(retval & (MORECTL | MOREDATA)) &&
1492c7e4935fSss150715 			    (cscratch.len != 0)) {
1493c7e4935fSss150715 				ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE);
1494c7e4935fSss150715 				if (dlreplyp != NULL)
1495c7e4935fSss150715 					(void) memcpy(dlreplyp->dlm_msg, bufc,
1496c7e4935fSss150715 					    ctl.len);
1497c7e4935fSss150715 				break;
14987c478bd9Sstevel@tonic-gate 			}
14997c478bd9Sstevel@tonic-gate 		}
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 		/*
15023ab45760Sss150715 		 * Check if DL_NOTIFY_IND message received. If there is one,
15033ab45760Sss150715 		 * notify the callback function(s) and continue processing the
15043ab45760Sss150715 		 * requested message.
15053ab45760Sss150715 		 */
15063ab45760Sss150715 		if (dip->dli_notifylistp != NULL &&
1507c623edd3SGirish Moodalbail 		    ctl.len >= (int)(sizeof (t_uscalar_t)) &&
1508c623edd3SGirish Moodalbail 		    *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) {
1509c623edd3SGirish Moodalbail 			/* process properly-formed DL_NOTIFY_IND messages */
1510c623edd3SGirish Moodalbail 			if (ctl.len >= DL_NOTIFY_IND_SIZE) {
1511c623edd3SGirish Moodalbail 				dlnotif = (dl_notify_ind_t *)(void *)ctl.buf;
15123ab45760Sss150715 				(void) i_dlpi_notifyind_process(dip, dlnotif);
1513c623edd3SGirish Moodalbail 			}
1514c623edd3SGirish Moodalbail 			goto update_timer;
15153ab45760Sss150715 		}
15163ab45760Sss150715 
15173ab45760Sss150715 		/*
1518c7e4935fSss150715 		 * If we were expecting a data message, and we got one, set
1519c7e4935fSss150715 		 * *datalenp.  If we aren't waiting on a control message, then
1520c7e4935fSss150715 		 * we're done.
15217c478bd9Sstevel@tonic-gate 		 */
1522c7e4935fSss150715 		if (databuf != NULL && data.len >= 0) {
1523c7e4935fSss150715 			*datalenp = data.len;
1524c7e4935fSss150715 			if (dlreplyp == NULL)
1525c7e4935fSss150715 				break;
15267c478bd9Sstevel@tonic-gate 		}
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 		/*
1529c7e4935fSss150715 		 * If we were expecting a control message, and the message
1530c7e4935fSss150715 		 * we received is at least big enough to be a DLPI message,
1531c7e4935fSss150715 		 * then verify it's a reply to something we sent.  If it
1532c7e4935fSss150715 		 * is a reply to something we sent, also verify its size.
15337c478bd9Sstevel@tonic-gate 		 */
1534c7e4935fSss150715 		if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) {
1535c7e4935fSss150715 			dlprim = dlreplyp->dlm_msg;
1536c7e4935fSss150715 			if (dlprim->dl_primitive == dlreplyprim) {
1537c7e4935fSss150715 				if (ctl.len < dlreplyminsz)
1538c7e4935fSss150715 					return (DLPI_EBADMSG);
1539c7e4935fSss150715 				dlreplyp->dlm_msgsz = ctl.len;
1540c7e4935fSss150715 				break;
1541c7e4935fSss150715 			} else if (dlprim->dl_primitive == DL_ERROR_ACK) {
1542c7e4935fSss150715 				if (ctl.len < DL_ERROR_ACK_SIZE)
1543c7e4935fSss150715 					return (DLPI_EBADMSG);
15447c478bd9Sstevel@tonic-gate 
1545c7e4935fSss150715 				/* Is it ours? */
1546c7e4935fSss150715 				if (dlprim->error_ack.dl_error_primitive ==
1547c7e4935fSss150715 				    dlreqprim)
15487c478bd9Sstevel@tonic-gate 					break;
15497c478bd9Sstevel@tonic-gate 			}
15507c478bd9Sstevel@tonic-gate 		}
1551c623edd3SGirish Moodalbail update_timer:
1552c7e4935fSss150715 		if (!infinite) {
1553c7e4935fSss150715 			current = gethrtime() / (NANOSEC / MILLISEC);
1554c7e4935fSss150715 			msec -= (current - start);
15557c478bd9Sstevel@tonic-gate 
1556c7e4935fSss150715 			if (msec <= 0)
1557c7e4935fSss150715 				return (DLPI_ETIMEDOUT);
15587c478bd9Sstevel@tonic-gate 		}
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate 
1561c7e4935fSss150715 	return (DLPI_SUCCESS);
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate /*
1565c7e4935fSss150715  * Common routine invoked by all DLPI control routines. The inputs for this
1566c7e4935fSss150715  * function are:
1567c7e4935fSss150715  * 	dlpi_impl_t *dip: internal dlpi handle
1568c7e4935fSss150715  *	const dlpi_msg_t *dlreqp: request message structure
1569c7e4935fSss150715  *	dlpi_msg_t *dlreplyp: reply message structure
1570c7e4935fSss150715  *	size_t dlreplyminsz: minimum size of reply primitive
1571c7e4935fSss150715  *	int flags: flags to be set to send a message
1572c7e4935fSss150715  * This routine succeeds if the message is an expected request/acknowledged
15733ab45760Sss150715  * message. However, if DLPI notification has been enabled via
15743ab45760Sss150715  * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling
15753ab45760Sss150715  * expected messages. Otherwise, any other unexpected asynchronous messages will
15763ab45760Sss150715  * be discarded.
15777c478bd9Sstevel@tonic-gate  */
15787c478bd9Sstevel@tonic-gate static int
1579c7e4935fSss150715 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1580c7e4935fSss150715     dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags)
1581c7e4935fSss150715 {
1582c7e4935fSss150715 	int		retval;
1583c7e4935fSss150715 	t_uscalar_t	dlreqprim = dlreqp->dlm_msg->dl_primitive;
1584c7e4935fSss150715 	t_uscalar_t 	dlreplyprim = dlreplyp->dlm_msg->dl_primitive;
1585c7e4935fSss150715 
1586c7e4935fSss150715 	/* Put the requested primitive on the stream. */
15873ab45760Sss150715 	retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags);
1588c7e4935fSss150715 	if (retval != DLPI_SUCCESS)
1589c7e4935fSss150715 		return (retval);
1590c7e4935fSss150715 
1591c7e4935fSss150715 	/* Retrieve acknowledged message for requested primitive. */
15923ab45760Sss150715 	retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC),
1593c7e4935fSss150715 	    dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL);
1594c7e4935fSss150715 	if (retval != DLPI_SUCCESS)
1595c7e4935fSss150715 		return (retval);
1596c7e4935fSss150715 
1597c7e4935fSss150715 	/*
1598c7e4935fSss150715 	 * If primitive is DL_ERROR_ACK, set errno.
1599c7e4935fSss150715 	 */
1600c7e4935fSss150715 	if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) {
1601c7e4935fSss150715 		errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno;
1602c7e4935fSss150715 		retval = dlreplyp->dlm_msg->error_ack.dl_errno;
1603c7e4935fSss150715 	}
1604c7e4935fSss150715 
1605c7e4935fSss150715 	return (retval);
1606c7e4935fSss150715 }
1607c7e4935fSss150715 
1608c7e4935fSss150715 /*
1609c7e4935fSss150715  * DLPI error codes.
1610c7e4935fSss150715  */
1611c7e4935fSss150715 static const char *dlpi_errlist[] = {
1612c7e4935fSss150715 	"bad LSAP selector",				/* DL_BADSAP  0x00 */
1613c7e4935fSss150715 	"DLSAP address in improper format or invalid",	/* DL_BADADDR 0x01 */
1614c7e4935fSss150715 	"improper permissions for request",		/* DL_ACCESS  0x02 */
1615c7e4935fSss150715 	"primitive issued in improper state",		/* DL_OUTSTATE 0x03 */
1616c7e4935fSss150715 	NULL,						/* DL_SYSERR  0x04 */
1617c7e4935fSss150715 	"sequence number not from outstanding DL_CONN_IND",
1618c7e4935fSss150715 							/* DL_BADCORR 0x05 */
1619c7e4935fSss150715 	"user data exceeded provider limit",		/* DL_BADDATA 0x06 */
1620c7e4935fSss150715 	"requested service not supplied by provider",
1621c7e4935fSss150715 						/* DL_UNSUPPORTED 0x07 */
1622c7e4935fSss150715 	"specified PPA was invalid", 			/* DL_BADPPA 0x08 */
1623c7e4935fSss150715 	"primitive received not known by provider",	/* DL_BADPRIM 0x09 */
1624c7e4935fSss150715 	"QoS parameters contained invalid values",
1625c7e4935fSss150715 						/* DL_BADQOSPARAM 0x0a */
1626c7e4935fSss150715 	"QoS structure type is unknown/unsupported",	/* DL_BADQOSTYPE 0x0b */
1627c7e4935fSss150715 	"token used not an active stream", 		/* DL_BADTOKEN 0x0c */
1628c7e4935fSss150715 	"attempted second bind with dl_max_conind",	/* DL_BOUND 0x0d */
1629c7e4935fSss150715 	"physical link initialization failed",		/* DL_INITFAILED 0x0e */
1630c7e4935fSss150715 	"provider couldn't allocate alternate address",	/* DL_NOADDR 0x0f */
1631c7e4935fSss150715 	"physical link not initialized",		/* DL_NOTINIT 0x10 */
1632c7e4935fSss150715 	"previous data unit could not be delivered",
1633c7e4935fSss150715 						/* DL_UNDELIVERABLE 0x11 */
1634c7e4935fSss150715 	"primitive is known but unsupported",
1635c7e4935fSss150715 						/* DL_NOTSUPPORTED 0x12 */
1636c7e4935fSss150715 	"limit exceeded",				/* DL_TOOMANY 0x13 */
1637c7e4935fSss150715 	"promiscuous mode not enabled",			/* DL_NOTENAB 0x14 */
1638c7e4935fSss150715 	"other streams for PPA in post-attached",	/* DL_BUSY 0x15 */
1639c7e4935fSss150715 	"automatic handling XID&TEST unsupported",	/* DL_NOAUTO 0x16 */
1640c7e4935fSss150715 	"automatic handling of XID unsupported",	/* DL_NOXIDAUTO 0x17 */
1641c7e4935fSss150715 	"automatic handling of TEST unsupported",	/* DL_NOTESTAUTO 0x18 */
1642c7e4935fSss150715 	"automatic handling of XID response",		/* DL_XIDAUTO 0x19 */
1643c7e4935fSss150715 	"automatic handling of TEST response", 		/* DL_TESTAUTO 0x1a */
1644c7e4935fSss150715 	"pending outstanding connect indications"	/* DL_PENDING 0x1b */
1645c7e4935fSss150715 };
1646c7e4935fSss150715 
1647c7e4935fSss150715 /*
1648c7e4935fSss150715  * libdlpi error codes.
1649c7e4935fSss150715  */
1650c7e4935fSss150715 static const char *libdlpi_errlist[] = {
1651c7e4935fSss150715 	"DLPI operation succeeded",		/* DLPI_SUCCESS */
1652c7e4935fSss150715 	"invalid argument",			/* DLPI_EINVAL */
1653c7e4935fSss150715 	"invalid DLPI linkname",		/* DLPI_ELINKNAMEINVAL */
1654c7e4935fSss150715 	"DLPI link does not exist",		/* DLPI_ENOLINK */
1655c7e4935fSss150715 	"bad DLPI link",			/* DLPI_EBADLINK */
1656c7e4935fSss150715 	"invalid DLPI handle",			/* DLPI_EINHANDLE */
1657c7e4935fSss150715 	"DLPI operation timed out",		/* DLPI_ETIMEDOUT */
1658c7e4935fSss150715 	"unsupported DLPI version",		/* DLPI_EVERNOTSUP */
1659c7e4935fSss150715 	"unsupported DLPI connection mode",	/* DLPI_EMODENOTSUP */
1660c7e4935fSss150715 	"unavailable DLPI SAP",			/* DLPI_EUNAVAILSAP */
1661c7e4935fSss150715 	"DLPI operation failed",		/* DLPI_FAILURE */
1662c7e4935fSss150715 	"DLPI style-2 node reports style-1",	/* DLPI_ENOTSTYLE2 */
1663c7e4935fSss150715 	"bad DLPI message",			/* DLPI_EBADMSG */
16643ab45760Sss150715 	"DLPI raw mode not supported",		/* DLPI_ERAWNOTSUP */
16653ab45760Sss150715 	"DLPI notification not supported by link",
16663ab45760Sss150715 						/* DLPI_ENOTENOTSUP */
16673ab45760Sss150715 	"invalid DLPI notification type",	/* DLPI_ENOTEINVAL */
1668b127ac41SPhilip Kirk 	"invalid DLPI notification id",		/* DLPI_ENOTEIDINVAL */
1669b127ac41SPhilip Kirk 	"DLPI_IPNETINFO not supported"		/* DLPI_EIPNETINFONOTSUP */
1670c7e4935fSss150715 };
1671c7e4935fSss150715 
1672c7e4935fSss150715 const char *
1673c7e4935fSss150715 dlpi_strerror(int err)
1674c7e4935fSss150715 {
1675c7e4935fSss150715 	if (err == DL_SYSERR)
1676c7e4935fSss150715 		return (strerror(errno));
1677c7e4935fSss150715 	else if (err >= 0 && err < NELEMS(dlpi_errlist))
1678c7e4935fSss150715 		return (dgettext(TEXT_DOMAIN, dlpi_errlist[err]));
16793ab45760Sss150715 	else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX)
1680c7e4935fSss150715 		return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err -
1681c7e4935fSss150715 		    DLPI_SUCCESS]));
1682c7e4935fSss150715 	else
1683c7e4935fSss150715 		return (dgettext(TEXT_DOMAIN, "Unknown DLPI error"));
1684c7e4935fSss150715 }
1685c7e4935fSss150715 
1686c7e4935fSss150715 /*
1687c7e4935fSss150715  * Each table entry comprises a DLPI/Private mactype and the description.
1688c7e4935fSss150715  */
1689c7e4935fSss150715 static const dlpi_mactype_t dlpi_mactypes[] = {
1690c7e4935fSss150715 	{ DL_CSMACD,		"CSMA/CD"		},
1691c7e4935fSss150715 	{ DL_TPB,		"Token Bus"		},
1692c7e4935fSss150715 	{ DL_TPR,		"Token Ring"		},
1693c7e4935fSss150715 	{ DL_METRO,		"Metro Net"		},
1694c7e4935fSss150715 	{ DL_ETHER,		"Ethernet"		},
1695c7e4935fSss150715 	{ DL_HDLC,		"HDLC"			},
1696c7e4935fSss150715 	{ DL_CHAR,		"Sync Character"	},
1697c7e4935fSss150715 	{ DL_CTCA,		"CTCA"			},
1698c7e4935fSss150715 	{ DL_FDDI,		"FDDI"			},
1699c7e4935fSss150715 	{ DL_FRAME,		"Frame Relay (LAPF)"	},
1700c7e4935fSss150715 	{ DL_MPFRAME,		"MP Frame Relay"	},
1701c7e4935fSss150715 	{ DL_ASYNC,		"Async Character"	},
1702c7e4935fSss150715 	{ DL_IPX25,		"X.25 (Classic IP)"	},
1703c7e4935fSss150715 	{ DL_LOOP,		"Software Loopback"	},
1704c7e4935fSss150715 	{ DL_FC,		"Fiber Channel"		},
1705c7e4935fSss150715 	{ DL_ATM,		"ATM"			},
1706c7e4935fSss150715 	{ DL_IPATM,		"ATM (Classic IP)"	},
1707c7e4935fSss150715 	{ DL_X25,		"X.25 (LAPB)"		},
1708c7e4935fSss150715 	{ DL_ISDN,		"ISDN"			},
1709c7e4935fSss150715 	{ DL_HIPPI,		"HIPPI"			},
1710c7e4935fSss150715 	{ DL_100VG,		"100BaseVG Ethernet"	},
1711c7e4935fSss150715 	{ DL_100VGTPR,		"100BaseVG Token Ring"	},
1712c7e4935fSss150715 	{ DL_ETH_CSMA,		"Ethernet/IEEE 802.3"	},
1713c7e4935fSss150715 	{ DL_100BT,		"100BaseT"		},
1714c7e4935fSss150715 	{ DL_IB,		"Infiniband"		},
1715c7e4935fSss150715 	{ DL_IPV4,		"IPv4 Tunnel"		},
1716c7e4935fSss150715 	{ DL_IPV6,		"IPv6 Tunnel"		},
1717b127ac41SPhilip Kirk 	{ DL_WIFI,		"IEEE 802.11"		},
1718b127ac41SPhilip Kirk 	{ DL_IPNET,		"IPNET"			}
1719c7e4935fSss150715 };
1720c7e4935fSss150715 
1721c7e4935fSss150715 const char *
1722c7e4935fSss150715 dlpi_mactype(uint_t mactype)
17237c478bd9Sstevel@tonic-gate {
17247c478bd9Sstevel@tonic-gate 	int i;
17257c478bd9Sstevel@tonic-gate 
1726c7e4935fSss150715 	for (i = 0; i < NELEMS(dlpi_mactypes); i++) {
1727c7e4935fSss150715 		if (dlpi_mactypes[i].dm_mactype == mactype)
1728c7e4935fSss150715 			return (dlpi_mactypes[i].dm_desc);
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
1731c7e4935fSss150715 	return ("Unknown MAC Type");
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
1734c7e4935fSss150715 /*
1735c7e4935fSss150715  * Each table entry comprises a DLPI primitive and the maximum buffer
1736c7e4935fSss150715  * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details).
1737c7e4935fSss150715  */
1738c7e4935fSss150715 static const dlpi_primsz_t dlpi_primsizes[] = {
1739c7e4935fSss150715 { DL_INFO_REQ,		DL_INFO_REQ_SIZE				},
1740c7e4935fSss150715 { DL_INFO_ACK,		DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) +
1741c7e4935fSss150715 			DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))},
1742c7e4935fSss150715 { DL_ATTACH_REQ,	DL_ATTACH_REQ_SIZE				},
1743c7e4935fSss150715 { DL_BIND_REQ,		DL_BIND_REQ_SIZE				},
1744c7e4935fSss150715 { DL_BIND_ACK, 		DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX +
1745c7e4935fSss150715 			DLPI_SAPLEN_MAX					},
1746c7e4935fSss150715 { DL_UNBIND_REQ, 	DL_UNBIND_REQ_SIZE				},
1747c7e4935fSss150715 { DL_ENABMULTI_REQ, 	DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX	},
1748c7e4935fSss150715 { DL_DISABMULTI_REQ, 	DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX	},
1749c7e4935fSss150715 { DL_PROMISCON_REQ, 	DL_PROMISCON_REQ_SIZE				},
1750c7e4935fSss150715 { DL_PROMISCOFF_REQ,	DL_PROMISCOFF_REQ_SIZE				},
1751c7e4935fSss150715 { DL_PASSIVE_REQ, 	DL_PASSIVE_REQ_SIZE				},
1752c7e4935fSss150715 { DL_UNITDATA_REQ, 	DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX +
1753c7e4935fSss150715 			DLPI_SAPLEN_MAX					},
1754c7e4935fSss150715 { DL_UNITDATA_IND, 	DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX +
1755c7e4935fSss150715 			DLPI_SAPLEN_MAX))				},
1756c7e4935fSss150715 { DL_PHYS_ADDR_REQ, 	DL_PHYS_ADDR_REQ_SIZE				},
1757c7e4935fSss150715 { DL_PHYS_ADDR_ACK, 	DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX	},
1758c7e4935fSss150715 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX	},
17593ab45760Sss150715 { DL_OK_ACK,		MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE)		},
17603ab45760Sss150715 { DL_NOTIFY_REQ,	DL_NOTIFY_REQ_SIZE				},
17613ab45760Sss150715 { DL_NOTIFY_ACK,	MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE)	},
17623ab45760Sss150715 { DL_NOTIFY_IND,	DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX +
17633ab45760Sss150715 			DLPI_SAPLEN_MAX					}
1764c7e4935fSss150715 };
1765c7e4935fSss150715 
1766c7e4935fSss150715 /*
1767c7e4935fSss150715  * Refers to the dlpi_primsizes[] table to return corresponding maximum
1768c7e4935fSss150715  * buffer size.
1769c7e4935fSss150715  */
1770c7e4935fSss150715 static size_t
1771c7e4935fSss150715 i_dlpi_getprimsize(t_uscalar_t prim)
1772c7e4935fSss150715 {
1773c7e4935fSss150715 	int	i;
1774c7e4935fSss150715 
1775c7e4935fSss150715 	for (i = 0; i < NELEMS(dlpi_primsizes); i++) {
1776c7e4935fSss150715 		if (dlpi_primsizes[i].dp_prim == prim)
1777c7e4935fSss150715 			return (dlpi_primsizes[i].dp_primsz);
1778c7e4935fSss150715 	}
1779c7e4935fSss150715 
1780c7e4935fSss150715 	return (sizeof (t_uscalar_t));
1781c7e4935fSss150715 }
1782c7e4935fSss150715 
1783c7e4935fSss150715 /*
1784c7e4935fSss150715  * sap values vary in length and are in host byte order, build sap value
1785c7e4935fSss150715  * by writing saplen bytes, so that the sap value is left aligned.
1786c7e4935fSss150715  */
1787c7e4935fSss150715 static uint_t
1788c7e4935fSss150715 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen)
1789c7e4935fSss150715 {
1790c7e4935fSss150715 	int i;
1791c7e4935fSss150715 	uint_t sap = 0;
1792c7e4935fSss150715 
1793c7e4935fSss150715 #ifdef _LITTLE_ENDIAN
1794c7e4935fSss150715 	for (i = saplen - 1; i >= 0; i--) {
1795c7e4935fSss150715 #else
1796c7e4935fSss150715 	for (i = 0; i < saplen; i++) {
1797c7e4935fSss150715 #endif
1798c7e4935fSss150715 		sap <<= 8;
1799c7e4935fSss150715 		sap |= sapp[i];
1800c7e4935fSss150715 	}
1801c7e4935fSss150715 
1802c7e4935fSss150715 	return (sap);
1803c7e4935fSss150715 }
1804c7e4935fSss150715 
1805c7e4935fSss150715 /*
1806c7e4935fSss150715  * Copy sap value to a buffer in host byte order. saplen is the number of
1807c7e4935fSss150715  * bytes to copy.
1808c7e4935fSss150715  */
1809c7e4935fSss150715 static void
1810c7e4935fSss150715 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen)
1811c7e4935fSss150715 {
1812c7e4935fSss150715 	uint8_t *sapp;
1813c7e4935fSss150715 
1814c7e4935fSss150715 #ifdef _LITTLE_ENDIAN
1815c7e4935fSss150715 	sapp = (uint8_t *)&sap;
1816c7e4935fSss150715 #else
1817c7e4935fSss150715 	sapp = (uint8_t *)&sap + (sizeof (sap) - saplen);
1818c7e4935fSss150715 #endif
1819c7e4935fSss150715 
1820c7e4935fSss150715 	(void) memcpy(dstbuf, sapp, saplen);
18217c478bd9Sstevel@tonic-gate }
18223ab45760Sss150715 
18233ab45760Sss150715 /*
18243ab45760Sss150715  * Fill notification payload and callback each registered functions.
18253ab45760Sss150715  * Delete nodes if any was called while processing.
18263ab45760Sss150715  */
18273ab45760Sss150715 static int
18283ab45760Sss150715 i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp)
18293ab45760Sss150715 {
18303ab45760Sss150715 	dlpi_notifyinfo_t	notifinfo;
18313ab45760Sss150715 	t_uscalar_t		dataoff, datalen;
18323ab45760Sss150715 	caddr_t			datap;
18333ab45760Sss150715 	dlpi_notifyent_t	*dnp;
18343ab45760Sss150715 	uint_t			note = dlnotifyindp->dl_notification;
18353ab45760Sss150715 	uint_t			deletenode = B_FALSE;
18363ab45760Sss150715 
18373ab45760Sss150715 	notifinfo.dni_note = note;
18383ab45760Sss150715 
18393ab45760Sss150715 	switch (note) {
18403ab45760Sss150715 	case DL_NOTE_SPEED:
18413ab45760Sss150715 		notifinfo.dni_speed = dlnotifyindp->dl_data;
18423ab45760Sss150715 		break;
18433ab45760Sss150715 	case DL_NOTE_SDU_SIZE:
18443ab45760Sss150715 		notifinfo.dni_size = dlnotifyindp->dl_data;
18453ab45760Sss150715 		break;
18463ab45760Sss150715 	case DL_NOTE_PHYS_ADDR:
18473ab45760Sss150715 		dataoff = dlnotifyindp->dl_addr_offset;
18483ab45760Sss150715 		datalen = dlnotifyindp->dl_addr_length;
18493ab45760Sss150715 
18503ab45760Sss150715 		if (dataoff == 0 || datalen == 0)
18513ab45760Sss150715 			return (DLPI_EBADMSG);
18523ab45760Sss150715 
18533ab45760Sss150715 		datap = (caddr_t)dlnotifyindp + dataoff;
18543ab45760Sss150715 		if (dataoff < DL_NOTIFY_IND_SIZE)
18553ab45760Sss150715 			return (DLPI_EBADMSG);
18563ab45760Sss150715 
18573ab45760Sss150715 		notifinfo.dni_physaddrlen = datalen - dip->dli_saplen;
18583ab45760Sss150715 
18593ab45760Sss150715 		if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX)
18603ab45760Sss150715 			return (DL_BADADDR);
18613ab45760Sss150715 
18623ab45760Sss150715 		(void) memcpy(notifinfo.dni_physaddr, datap,
18633ab45760Sss150715 		    notifinfo.dni_physaddrlen);
18643ab45760Sss150715 		break;
18653ab45760Sss150715 	}
18663ab45760Sss150715 
18673ab45760Sss150715 	dip->dli_note_processing = B_TRUE;
18683ab45760Sss150715 
18693ab45760Sss150715 	for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
18703ab45760Sss150715 		if (note & dnp->dln_notes)
18713ab45760Sss150715 			dnp->dln_fnp((dlpi_handle_t)dip, &notifinfo, dnp->arg);
18723ab45760Sss150715 		if (dnp->dln_rm)
18733ab45760Sss150715 			deletenode = B_TRUE;
18743ab45760Sss150715 	}
18753ab45760Sss150715 
18763ab45760Sss150715 	dip->dli_note_processing = B_FALSE;
18773ab45760Sss150715 
18783ab45760Sss150715 	/* Walk the notifyentry list to unregister marked entries. */
18793ab45760Sss150715 	if (deletenode)
18803ab45760Sss150715 		i_dlpi_deletenotifyid(dip);
18813ab45760Sss150715 
18823ab45760Sss150715 	return (DLPI_SUCCESS);
18833ab45760Sss150715 }
18843ab45760Sss150715 /*
18853ab45760Sss150715  * Find registered notification.
18863ab45760Sss150715  */
18873ab45760Sss150715 static boolean_t
18883ab45760Sss150715 i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id)
18893ab45760Sss150715 {
18903ab45760Sss150715 	dlpi_notifyent_t	*dnp;
18913ab45760Sss150715 
18923ab45760Sss150715 	for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
18933ab45760Sss150715 		if (id == dnp)
18943ab45760Sss150715 			return (B_TRUE);
18953ab45760Sss150715 	}
18963ab45760Sss150715 
18973ab45760Sss150715 	return (B_FALSE);
18983ab45760Sss150715 }
18993ab45760Sss150715 
19003ab45760Sss150715 /*
19013ab45760Sss150715  * Walk the list of notifications and deleted nodes marked to be deleted.
19023ab45760Sss150715  */
19033ab45760Sss150715 static void
19043ab45760Sss150715 i_dlpi_deletenotifyid(dlpi_impl_t *dip)
19053ab45760Sss150715 {
19063ab45760Sss150715 	dlpi_notifyent_t	 *prev, *dnp;
19073ab45760Sss150715 
19083ab45760Sss150715 	prev = NULL;
19093ab45760Sss150715 	dnp = dip->dli_notifylistp;
19103ab45760Sss150715 	while (dnp != NULL) {
19113ab45760Sss150715 		if (!dnp->dln_rm) {
19123ab45760Sss150715 			prev = dnp;
19133ab45760Sss150715 			dnp = dnp->dln_next;
19143ab45760Sss150715 		} else if (prev == NULL) {
19153ab45760Sss150715 			dip->dli_notifylistp = dnp->dln_next;
19163ab45760Sss150715 			free(dnp);
19173ab45760Sss150715 			dnp = dip->dli_notifylistp;
19183ab45760Sss150715 		} else {
19193ab45760Sss150715 			prev->dln_next = dnp->dln_next;
19203ab45760Sss150715 			free(dnp);
19213ab45760Sss150715 			dnp = prev->dln_next;
19223ab45760Sss150715 		}
19233ab45760Sss150715 	}
19243ab45760Sss150715 }
1925