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 /*
22e11c3f44Smeem * 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_attach(dlpi_impl_t *);
59c7e4935fSss150715 static void i_dlpi_passive(dlpi_impl_t *);
607c478bd9Sstevel@tonic-gate
613ab45760Sss150715 static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *,
623ab45760Sss150715 size_t, int);
633ab45760Sss150715 static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t,
643ab45760Sss150715 t_uscalar_t, size_t, void *, size_t *, size_t *);
65c7e4935fSss150715 static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *,
66c7e4935fSss150715 size_t, int);
677c478bd9Sstevel@tonic-gate
68c7e4935fSss150715 static size_t i_dlpi_getprimsize(t_uscalar_t);
69c7e4935fSss150715 static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t);
70c7e4935fSss150715 static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t);
71c7e4935fSss150715 static uint_t i_dlpi_buildsap(uint8_t *, uint_t);
72c7e4935fSss150715 static void i_dlpi_writesap(void *, uint_t, uint_t);
733ab45760Sss150715 static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *);
743ab45760Sss150715 static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *);
753ab45760Sss150715 static void i_dlpi_deletenotifyid(dlpi_impl_t *);
76c7e4935fSss150715
77d62bc4baSyz147064 struct i_dlpi_walklink_arg {
78d62bc4baSyz147064 dlpi_walkfunc_t *fn;
79d62bc4baSyz147064 void *arg;
80d62bc4baSyz147064 };
81d62bc4baSyz147064
82d62bc4baSyz147064 static int
i_dlpi_walk_link(const char * name,void * arg)83d62bc4baSyz147064 i_dlpi_walk_link(const char *name, void *arg)
84d62bc4baSyz147064 {
85d62bc4baSyz147064 struct i_dlpi_walklink_arg *warg = arg;
86d62bc4baSyz147064
87d62bc4baSyz147064 return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE :
88d62bc4baSyz147064 DLADM_WALK_CONTINUE);
89d62bc4baSyz147064 }
90d62bc4baSyz147064
91d62bc4baSyz147064 /*ARGSUSED*/
92d62bc4baSyz147064 void
dlpi_walk(dlpi_walkfunc_t * fn,void * arg,uint_t flags)93d62bc4baSyz147064 dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags)
94d62bc4baSyz147064 {
95d62bc4baSyz147064 struct i_dlpi_walklink_arg warg;
96b127ac41SPhilip Kirk struct dirent *d;
97b127ac41SPhilip Kirk DIR *dp;
984ac67f02SAnurag S. Maskey dladm_handle_t handle;
99d62bc4baSyz147064
100d62bc4baSyz147064 warg.fn = fn;
101d62bc4baSyz147064 warg.arg = arg;
102d62bc4baSyz147064
103b127ac41SPhilip Kirk if (flags & DLPI_DEVIPNET) {
104b127ac41SPhilip Kirk if ((dp = opendir("/dev/ipnet")) == NULL)
105b127ac41SPhilip Kirk return;
106b127ac41SPhilip Kirk
107b127ac41SPhilip Kirk while ((d = readdir(dp)) != NULL) {
108b127ac41SPhilip Kirk if (d->d_name[0] == '.')
109b127ac41SPhilip Kirk continue;
110b127ac41SPhilip Kirk
111b127ac41SPhilip Kirk if (warg.fn(d->d_name, warg.arg))
112b127ac41SPhilip Kirk break;
113b127ac41SPhilip Kirk }
114b127ac41SPhilip Kirk
115b127ac41SPhilip Kirk (void) closedir(dp);
116b127ac41SPhilip Kirk } else {
1174ac67f02SAnurag S. Maskey /*
1184ac67f02SAnurag S. Maskey * Rather than have libdlpi take the libdladm handle,
1194ac67f02SAnurag S. Maskey * open the handle here.
1204ac67f02SAnurag S. Maskey */
1214ac67f02SAnurag S. Maskey if (dladm_open(&handle) != DLADM_STATUS_OK)
1224ac67f02SAnurag S. Maskey return;
1234ac67f02SAnurag S. Maskey
1244ac67f02SAnurag S. Maskey (void) dladm_walk(i_dlpi_walk_link, handle, &warg,
1254ac67f02SAnurag S. Maskey DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1264ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE);
1274ac67f02SAnurag S. Maskey
1284ac67f02SAnurag S. Maskey dladm_close(handle);
129d62bc4baSyz147064 }
130b127ac41SPhilip Kirk }
131d62bc4baSyz147064
132c7e4935fSss150715 int
dlpi_open(const char * linkname,dlpi_handle_t * dhp,uint_t flags)133c7e4935fSss150715 dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
134c7e4935fSss150715 {
135b127ac41SPhilip Kirk int retval, on = 1;
136c7e4935fSss150715 ifspec_t ifsp;
137c7e4935fSss150715 dlpi_impl_t *dip;
138c7e4935fSss150715
139c7e4935fSss150715 /*
140c7e4935fSss150715 * Validate linkname, fail if logical unit number (lun) is specified,
141c7e4935fSss150715 * otherwise decompose the contents into ifsp.
142c7e4935fSss150715 */
143c7e4935fSss150715 if (linkname == NULL || (strchr(linkname, ':') != NULL) ||
144c7e4935fSss150715 !ifparse_ifspec(linkname, &ifsp))
145c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL);
146c7e4935fSss150715
147b127ac41SPhilip Kirk /*
148b127ac41SPhilip Kirk * Ensure flags values are sane.
149b127ac41SPhilip Kirk */
150b127ac41SPhilip Kirk if ((flags & (DLPI_DEVIPNET|DLPI_DEVONLY)) ==
151b127ac41SPhilip Kirk (DLPI_DEVIPNET|DLPI_DEVONLY))
152b127ac41SPhilip Kirk return (DLPI_EINVAL);
153b127ac41SPhilip Kirk
154c7e4935fSss150715 /* Allocate a new dlpi_impl_t. */
155c7e4935fSss150715 if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL)
156c7e4935fSss150715 return (DL_SYSERR);
157c7e4935fSss150715
158c7e4935fSss150715 /* Fill in known/default libdlpi handle values. */
159c7e4935fSss150715 dip->dli_timeout = DLPI_DEF_TIMEOUT;
160c7e4935fSss150715 dip->dli_ppa = ifsp.ifsp_ppa;
161c7e4935fSss150715 dip->dli_oflags = flags;
1623ab45760Sss150715 dip->dli_notifylistp = NULL;
1633ab45760Sss150715 dip->dli_note_processing = B_FALSE;
164d62bc4baSyz147064 if (getenv("DLPI_DEVONLY") != NULL)
165d62bc4baSyz147064 dip->dli_oflags |= DLPI_DEVONLY;
166c7e4935fSss150715
167c7e4935fSss150715 /* Copy linkname provided to the function. */
168c7e4935fSss150715 if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >=
169c7e4935fSss150715 sizeof (dip->dli_linkname)) {
170c7e4935fSss150715 free(dip);
171c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL);
172c7e4935fSss150715 }
173c7e4935fSss150715
174c7e4935fSss150715 /* Copy provider name. */
175c7e4935fSss150715 (void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm,
176c7e4935fSss150715 sizeof (dip->dli_provider));
177c7e4935fSss150715
178c7e4935fSss150715 /*
179c7e4935fSss150715 * Special case: DLPI_SERIAL flag is set to indicate a synchronous
180c7e4935fSss150715 * serial line interface (see syncinit(1M), syncstat(1M),
181c7e4935fSss150715 * syncloop(1M)), which is not a DLPI link.
182c7e4935fSss150715 */
183c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL) {
184c7e4935fSss150715 if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) {
185c7e4935fSss150715 free(dip);
186c7e4935fSss150715 return (retval);
187c7e4935fSss150715 }
188c7e4935fSss150715
189c7e4935fSss150715 *dhp = (dlpi_handle_t)dip;
190c7e4935fSss150715 return (retval);
191c7e4935fSss150715 }
192c7e4935fSss150715
193d62bc4baSyz147064 if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) {
194d62bc4baSyz147064 if (retval == DLPI_ENOTSTYLE2) {
195d62bc4baSyz147064 /*
196d62bc4baSyz147064 * The error code indicates not to continue the
197d62bc4baSyz147064 * style-2 open. Change the error code back to
198d62bc4baSyz147064 * DL_SYSERR, so that one would know the cause
199d62bc4baSyz147064 * of failure from errno.
200d62bc4baSyz147064 */
201d62bc4baSyz147064 retval = DL_SYSERR;
202b127ac41SPhilip Kirk } else if (!(dip->dli_oflags & DLPI_DEVIPNET)) {
203d62bc4baSyz147064 retval = i_dlpi_style2_open(dip);
204d62bc4baSyz147064 }
205d62bc4baSyz147064 if (retval != DLPI_SUCCESS) {
206c7e4935fSss150715 free(dip);
207c7e4935fSss150715 return (retval);
208c7e4935fSss150715 }
209c7e4935fSss150715 }
210c7e4935fSss150715
211c7e4935fSss150715 if (dip->dli_oflags & DLPI_PASSIVE)
212c7e4935fSss150715 i_dlpi_passive(dip);
213c7e4935fSss150715
214c7e4935fSss150715 if ((dip->dli_oflags & DLPI_RAW) &&
215c7e4935fSss150715 ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) {
216c7e4935fSss150715 dlpi_close((dlpi_handle_t)dip);
217c7e4935fSss150715 return (DLPI_ERAWNOTSUP);
218c7e4935fSss150715 }
219c7e4935fSss150715
220b127ac41SPhilip Kirk if ((dip->dli_oflags & DLPI_IPNETINFO) &&
221b127ac41SPhilip Kirk ioctl(dip->dli_fd, DLIOCIPNETINFO, &on) < 0) {
222b127ac41SPhilip Kirk dlpi_close((dlpi_handle_t)dip);
223b127ac41SPhilip Kirk return (DLPI_EIPNETINFONOTSUP);
224b127ac41SPhilip Kirk }
225b127ac41SPhilip Kirk
226c7e4935fSss150715 /*
227c7e4935fSss150715 * We intentionally do not care if this request fails, as this
228c7e4935fSss150715 * indicates the underlying DLPI device does not support Native mode
229c7e4935fSss150715 * (pre-GLDV3 device drivers).
230c7e4935fSss150715 */
231c7e4935fSss150715 if (dip->dli_oflags & DLPI_NATIVE) {
232c7e4935fSss150715 if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0)
233c7e4935fSss150715 dip->dli_mactype = retval;
234c7e4935fSss150715 }
235c7e4935fSss150715
236c7e4935fSss150715 *dhp = (dlpi_handle_t)dip;
237c7e4935fSss150715 return (DLPI_SUCCESS);
238c7e4935fSss150715 }
239c7e4935fSss150715
240c7e4935fSss150715 void
dlpi_close(dlpi_handle_t dh)241c7e4935fSss150715 dlpi_close(dlpi_handle_t dh)
242c7e4935fSss150715 {
243c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
2443ab45760Sss150715 dlpi_notifyent_t *next, *dnp;
245c7e4935fSss150715
246c7e4935fSss150715 if (dip != NULL) {
2473ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = next) {
2483ab45760Sss150715 next = dnp->dln_next;
2493ab45760Sss150715 free(dnp);
2503ab45760Sss150715 }
2513ab45760Sss150715
252c7e4935fSss150715 (void) close(dip->dli_fd);
253c7e4935fSss150715 free(dip);
254c7e4935fSss150715 }
255c7e4935fSss150715 }
256c7e4935fSss150715
257c7e4935fSss150715 /*
258c7e4935fSss150715 * NOTE: The opt argument must be zero and is reserved for future use to extend
259c7e4935fSss150715 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)).
260c7e4935fSss150715 */
261c7e4935fSss150715 int
dlpi_info(dlpi_handle_t dh,dlpi_info_t * infop,uint_t opt)262c7e4935fSss150715 dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt)
263c7e4935fSss150715 {
264c7e4935fSss150715 int retval;
265c7e4935fSss150715 dlpi_msg_t req, ack;
266c7e4935fSss150715 dl_info_ack_t *infoackp;
267c7e4935fSss150715 uint8_t *sapp, *addrp;
268c7e4935fSss150715 caddr_t ackendp, datap;
269c7e4935fSss150715 t_uscalar_t dataoff, datalen;
270c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
271c7e4935fSss150715
272c7e4935fSss150715 if (dip == NULL)
273c7e4935fSss150715 return (DLPI_EINHANDLE);
274c7e4935fSss150715
275c7e4935fSss150715 if (infop == NULL || opt != 0)
276c7e4935fSss150715 return (DLPI_EINVAL);
277c7e4935fSss150715
278c7e4935fSss150715 (void) memset(infop, 0, sizeof (dlpi_info_t));
279c7e4935fSss150715
280c7e4935fSss150715 /* Set QoS range parameters to default unsupported value. */
281c7e4935fSss150715 infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
282c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN;
283c7e4935fSss150715 infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN;
284c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN;
285c7e4935fSss150715 infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN;
286c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN;
287c7e4935fSss150715 infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN;
288c7e4935fSss150715 infop->di_qos_range.dl_residual_error = DL_UNKNOWN;
289c7e4935fSss150715
290c7e4935fSss150715 /* Set QoS parameters to default unsupported value. */
291c7e4935fSss150715 infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
292c7e4935fSss150715 infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN;
293c7e4935fSss150715 infop->di_qos_sel.dl_priority = DL_UNKNOWN;
294c7e4935fSss150715 infop->di_qos_sel.dl_protection = DL_UNKNOWN;
295c7e4935fSss150715 infop->di_qos_sel.dl_residual_error = DL_UNKNOWN;
296c7e4935fSss150715
297c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_INFO_REQ);
298c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_INFO_ACK);
299c7e4935fSss150715
300c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI);
301c7e4935fSss150715 if (retval != DLPI_SUCCESS)
302c7e4935fSss150715 return (retval);
303c7e4935fSss150715
304c7e4935fSss150715 infoackp = &(ack.dlm_msg->info_ack);
305c7e4935fSss150715 if (infoackp->dl_version != DL_VERSION_2)
306c7e4935fSss150715 return (DLPI_EVERNOTSUP);
307c7e4935fSss150715
308c7e4935fSss150715 if (infoackp->dl_service_mode != DL_CLDLS)
309c7e4935fSss150715 return (DLPI_EMODENOTSUP);
310c7e4935fSss150715
311c7e4935fSss150715 dip->dli_style = infoackp->dl_provider_style;
312c7e4935fSss150715 dip->dli_mactype = infoackp->dl_mac_type;
313c7e4935fSss150715
314c7e4935fSss150715 ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
315c7e4935fSss150715
316c7e4935fSss150715 /* Check and save QoS selection information, if any. */
317c7e4935fSss150715 datalen = infoackp->dl_qos_length;
318c7e4935fSss150715 dataoff = infoackp->dl_qos_offset;
319c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
320c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff;
321c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_sel1_t) ||
322c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
323c7e4935fSss150715 return (DLPI_EBADMSG);
324c7e4935fSss150715
325c7e4935fSss150715 (void) memcpy(&infop->di_qos_sel, datap, datalen);
326c7e4935fSss150715 if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1)
327c7e4935fSss150715 return (DLPI_EMODENOTSUP);
328c7e4935fSss150715 }
329c7e4935fSss150715
330c7e4935fSss150715 /* Check and save QoS range information, if any. */
331c7e4935fSss150715 datalen = infoackp->dl_qos_range_length;
332c7e4935fSss150715 dataoff = infoackp->dl_qos_range_offset;
333c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
334c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff;
335c7e4935fSss150715 if (datalen > sizeof (dl_qos_cl_range1_t) ||
336c7e4935fSss150715 dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
337c7e4935fSss150715 return (DLPI_EBADMSG);
338c7e4935fSss150715
339c7e4935fSss150715 (void) memcpy(&infop->di_qos_range, datap, datalen);
340c7e4935fSss150715 if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1)
341c7e4935fSss150715 return (DLPI_EMODENOTSUP);
342c7e4935fSss150715 }
343c7e4935fSss150715
344c7e4935fSss150715 /* Check and save physical address and SAP information. */
345c7e4935fSss150715 dip->dli_saplen = abs(infoackp->dl_sap_length);
346c7e4935fSss150715 dip->dli_sapbefore = (infoackp->dl_sap_length > 0);
347c7e4935fSss150715 infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen;
348c7e4935fSss150715
349c7e4935fSss150715 if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX ||
350c7e4935fSss150715 dip->dli_saplen > DLPI_SAPLEN_MAX)
351c7e4935fSss150715 return (DL_BADADDR);
352c7e4935fSss150715
353c7e4935fSss150715 dataoff = infoackp->dl_addr_offset;
354c7e4935fSss150715 datalen = infoackp->dl_addr_length;
355c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
356c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff;
357c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
358c7e4935fSss150715 return (DLPI_EBADMSG);
359c7e4935fSss150715
360c7e4935fSss150715 sapp = addrp = (uint8_t *)datap;
361c7e4935fSss150715 if (dip->dli_sapbefore)
362c7e4935fSss150715 addrp += dip->dli_saplen;
363c7e4935fSss150715 else
364c7e4935fSss150715 sapp += infop->di_physaddrlen;
365c7e4935fSss150715
366c7e4935fSss150715 (void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen);
367c7e4935fSss150715 infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen);
368c7e4935fSss150715 }
369c7e4935fSss150715
370c7e4935fSss150715 /* Check and save broadcast address information, if any. */
371c7e4935fSss150715 datalen = infoackp->dl_brdcst_addr_length;
372c7e4935fSss150715 dataoff = infoackp->dl_brdcst_addr_offset;
373c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
374c7e4935fSss150715 datap = (caddr_t)infoackp + dataoff;
375c7e4935fSss150715 if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
376c7e4935fSss150715 return (DLPI_EBADMSG);
377c7e4935fSss150715 if (datalen != infop->di_physaddrlen)
378c7e4935fSss150715 return (DL_BADADDR);
379c7e4935fSss150715
380c7e4935fSss150715 infop->di_bcastaddrlen = datalen;
381c7e4935fSss150715 (void) memcpy(infop->di_bcastaddr, datap, datalen);
382c7e4935fSss150715 }
383c7e4935fSss150715
384c7e4935fSss150715 infop->di_max_sdu = infoackp->dl_max_sdu;
385c7e4935fSss150715 infop->di_min_sdu = infoackp->dl_min_sdu;
386c7e4935fSss150715 infop->di_state = infoackp->dl_current_state;
387c7e4935fSss150715 infop->di_mactype = infoackp->dl_mac_type;
388c7e4935fSss150715
389c7e4935fSss150715 /* Information retrieved from the handle. */
390c7e4935fSss150715 (void) strlcpy(infop->di_linkname, dip->dli_linkname,
391c7e4935fSss150715 sizeof (infop->di_linkname));
392c7e4935fSss150715 infop->di_timeout = dip->dli_timeout;
393c7e4935fSss150715
394c7e4935fSss150715 return (DLPI_SUCCESS);
395c7e4935fSss150715 }
396c7e4935fSss150715
397c7e4935fSss150715 /*
398c7e4935fSss150715 * This function parses 'linkname' and stores the 'provider' name and 'PPA'.
399c7e4935fSss150715 */
400c7e4935fSss150715 int
dlpi_parselink(const char * linkname,char * provider,uint_t * ppa)401c7e4935fSss150715 dlpi_parselink(const char *linkname, char *provider, uint_t *ppa)
402c7e4935fSss150715 {
403e7801d59Ssowmini dladm_status_t status;
404c7e4935fSss150715
405e7801d59Ssowmini status = dladm_parselink(linkname, provider, ppa);
406e7801d59Ssowmini
407e7801d59Ssowmini if (status != DLADM_STATUS_OK)
408c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL);
409c7e4935fSss150715
410c7e4935fSss150715 return (DLPI_SUCCESS);
411c7e4935fSss150715 }
412c7e4935fSss150715
413c7e4935fSss150715 /*
414c7e4935fSss150715 * This function takes a provider name and a PPA and stores a full linkname
415c7e4935fSss150715 * as 'linkname'. If 'provider' already is a full linkname 'provider' name
416c7e4935fSss150715 * is stored in 'linkname'.
417c7e4935fSss150715 */
418c7e4935fSss150715 int
dlpi_makelink(char * linkname,const char * provider,uint_t ppa)419c7e4935fSss150715 dlpi_makelink(char *linkname, const char *provider, uint_t ppa)
420c7e4935fSss150715 {
421c7e4935fSss150715 int provlen = strlen(provider);
422c7e4935fSss150715
423c7e4935fSss150715 if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX)
424c7e4935fSss150715 return (DLPI_ELINKNAMEINVAL);
425c7e4935fSss150715
426c7e4935fSss150715 if (!isdigit(provider[provlen - 1])) {
427c7e4935fSss150715 (void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider,
428c7e4935fSss150715 ppa);
429c7e4935fSss150715 } else {
430c7e4935fSss150715 (void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX);
431c7e4935fSss150715 }
432c7e4935fSss150715
433c7e4935fSss150715 return (DLPI_SUCCESS);
434c7e4935fSss150715 }
435c7e4935fSss150715
436c7e4935fSss150715 int
dlpi_bind(dlpi_handle_t dh,uint_t sap,uint_t * boundsap)437c7e4935fSss150715 dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap)
438c7e4935fSss150715 {
439c7e4935fSss150715 int retval;
440c7e4935fSss150715 dlpi_msg_t req, ack;
441c7e4935fSss150715 dl_bind_req_t *bindreqp;
442c7e4935fSss150715 dl_bind_ack_t *bindackp;
443c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
444c7e4935fSss150715
445c7e4935fSss150715 if (dip == NULL)
446c7e4935fSss150715 return (DLPI_EINHANDLE);
447c7e4935fSss150715
448c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_BIND_REQ);
449c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_BIND_ACK);
450c7e4935fSss150715 bindreqp = &(req.dlm_msg->bind_req);
451c7e4935fSss150715
452c7e4935fSss150715 /*
453c7e4935fSss150715 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on
454c7e4935fSss150715 * other interface types (SAP 0 has special significance on token ring).
455c7e4935fSss150715 */
456c7e4935fSss150715 if (sap == DLPI_ANY_SAP)
457c7e4935fSss150715 bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0);
458c7e4935fSss150715 else
459c7e4935fSss150715 bindreqp->dl_sap = sap;
460c7e4935fSss150715
461c7e4935fSss150715 bindreqp->dl_service_mode = DL_CLDLS;
462c7e4935fSss150715 bindreqp->dl_conn_mgmt = 0;
463c7e4935fSss150715 bindreqp->dl_max_conind = 0;
464c7e4935fSss150715 bindreqp->dl_xidtest_flg = 0;
465c7e4935fSss150715
466c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0);
467c7e4935fSss150715 if (retval != DLPI_SUCCESS)
468c7e4935fSss150715 return (retval);
469c7e4935fSss150715
470c7e4935fSss150715 bindackp = &(ack.dlm_msg->bind_ack);
471c7e4935fSss150715 /*
472c7e4935fSss150715 * Received a DLPI_BIND_ACK, now verify that the bound SAP
473c7e4935fSss150715 * is equal to the SAP requested. Some DLPI MAC type may bind
474c7e4935fSss150715 * to a different SAP than requested, in this case 'boundsap'
475c7e4935fSss150715 * returns the actual bound SAP. For the case where 'boundsap'
476c7e4935fSss150715 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails.
477c7e4935fSss150715 */
478c7e4935fSss150715 if (boundsap != NULL) {
479c7e4935fSss150715 *boundsap = bindackp->dl_sap;
480c7e4935fSss150715 } else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) {
481c7e4935fSss150715 if (dlpi_unbind(dh) != DLPI_SUCCESS)
482c7e4935fSss150715 return (DLPI_FAILURE);
483c7e4935fSss150715 else
484c7e4935fSss150715 return (DLPI_EUNAVAILSAP);
485c7e4935fSss150715 }
486c7e4935fSss150715
487c7e4935fSss150715 dip->dli_sap = bindackp->dl_sap; /* save sap value in handle */
488c7e4935fSss150715 return (DLPI_SUCCESS);
489c7e4935fSss150715 }
490c7e4935fSss150715
491c7e4935fSss150715 int
dlpi_unbind(dlpi_handle_t dh)492c7e4935fSss150715 dlpi_unbind(dlpi_handle_t dh)
493c7e4935fSss150715 {
494c7e4935fSss150715 dlpi_msg_t req, ack;
495c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
496c7e4935fSss150715
497c7e4935fSss150715 if (dip == NULL)
498c7e4935fSss150715 return (DLPI_EINHANDLE);
499c7e4935fSss150715
500c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNBIND_REQ);
501c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
502c7e4935fSss150715
503c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
504c7e4935fSss150715 }
505c7e4935fSss150715
506c7e4935fSss150715 /*
507c7e4935fSss150715 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and
508c7e4935fSss150715 * based on the "op" value, multicast address is enabled/disabled.
509c7e4935fSss150715 */
510c7e4935fSss150715 static int
i_dlpi_multi(dlpi_handle_t dh,t_uscalar_t op,const uint8_t * addrp,size_t addrlen)511c7e4935fSss150715 i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp,
512c7e4935fSss150715 size_t addrlen)
513c7e4935fSss150715 {
514c7e4935fSss150715 dlpi_msg_t req, ack;
515c7e4935fSss150715 dl_enabmulti_req_t *multireqp;
516c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
517c7e4935fSss150715
518c7e4935fSss150715 if (dip == NULL)
519c7e4935fSss150715 return (DLPI_EINHANDLE);
520c7e4935fSss150715
521c7e4935fSss150715 if (addrlen > DLPI_PHYSADDR_MAX)
522c7e4935fSss150715 return (DLPI_EINVAL);
523c7e4935fSss150715
524c7e4935fSss150715 DLPI_MSG_CREATE(req, op);
525c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
526c7e4935fSss150715
527c7e4935fSss150715 multireqp = &(req.dlm_msg->enabmulti_req);
528c7e4935fSss150715 multireqp->dl_addr_length = addrlen;
529c7e4935fSss150715 multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
530c7e4935fSss150715 (void) memcpy(&multireqp[1], addrp, addrlen);
531c7e4935fSss150715
532c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
533c7e4935fSss150715 }
534c7e4935fSss150715
535c7e4935fSss150715 int
dlpi_enabmulti(dlpi_handle_t dh,const void * addrp,size_t addrlen)536c7e4935fSss150715 dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
537c7e4935fSss150715 {
538c7e4935fSss150715 return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen));
539c7e4935fSss150715 }
540c7e4935fSss150715
541c7e4935fSss150715 int
dlpi_disabmulti(dlpi_handle_t dh,const void * addrp,size_t addrlen)542c7e4935fSss150715 dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
543c7e4935fSss150715 {
544c7e4935fSss150715 return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen));
545c7e4935fSss150715 }
546c7e4935fSss150715
547c7e4935fSss150715 /*
548c7e4935fSss150715 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based
549c7e4935fSss150715 * on the value of 'op', promiscuous mode is turned on/off at the specified
550c7e4935fSss150715 * 'level'.
551c7e4935fSss150715 */
552c7e4935fSss150715 static int
i_dlpi_promisc(dlpi_handle_t dh,t_uscalar_t op,uint_t level)553c7e4935fSss150715 i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level)
554c7e4935fSss150715 {
555c7e4935fSss150715 dlpi_msg_t req, ack;
556c7e4935fSss150715 dl_promiscon_req_t *promiscreqp;
557c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
558c7e4935fSss150715
559c7e4935fSss150715 if (dip == NULL)
560c7e4935fSss150715 return (DLPI_EINHANDLE);
561c7e4935fSss150715
562c7e4935fSss150715 DLPI_MSG_CREATE(req, op);
563c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
564c7e4935fSss150715
565c7e4935fSss150715 promiscreqp = &(req.dlm_msg->promiscon_req);
566c7e4935fSss150715 promiscreqp->dl_level = level;
567c7e4935fSss150715
568c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
569c7e4935fSss150715 }
570c7e4935fSss150715
571c7e4935fSss150715 int
dlpi_promiscon(dlpi_handle_t dh,uint_t level)572c7e4935fSss150715 dlpi_promiscon(dlpi_handle_t dh, uint_t level)
573c7e4935fSss150715 {
574c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level));
575c7e4935fSss150715 }
576c7e4935fSss150715
577c7e4935fSss150715 int
dlpi_promiscoff(dlpi_handle_t dh,uint_t level)578c7e4935fSss150715 dlpi_promiscoff(dlpi_handle_t dh, uint_t level)
579c7e4935fSss150715 {
580c7e4935fSss150715 return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level));
581c7e4935fSss150715 }
582c7e4935fSss150715
583c7e4935fSss150715 int
dlpi_get_physaddr(dlpi_handle_t dh,uint_t type,void * addrp,size_t * addrlenp)584c7e4935fSss150715 dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp)
585c7e4935fSss150715 {
586c7e4935fSss150715 int retval;
587c7e4935fSss150715 dlpi_msg_t req, ack;
588c7e4935fSss150715 dl_phys_addr_req_t *physreqp;
589c7e4935fSss150715 dl_phys_addr_ack_t *physackp;
590c7e4935fSss150715 t_uscalar_t dataoff, datalen;
591c7e4935fSss150715 caddr_t datap, physackendp;
592c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
593c7e4935fSss150715
594c7e4935fSss150715 if (dip == NULL)
595c7e4935fSss150715 return (DLPI_EINHANDLE);
596c7e4935fSss150715
597c7e4935fSss150715 if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX)
598c7e4935fSss150715 return (DLPI_EINVAL);
599c7e4935fSss150715
600c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ);
601c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK);
602c7e4935fSss150715
603c7e4935fSss150715 physreqp = &(req.dlm_msg->physaddr_req);
604c7e4935fSss150715 physreqp->dl_addr_type = type;
605c7e4935fSss150715
606c7e4935fSss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0);
607c7e4935fSss150715 if (retval != DLPI_SUCCESS)
608c7e4935fSss150715 return (retval);
609c7e4935fSss150715
610c7e4935fSss150715 /* Received DL_PHYS_ADDR_ACK, store the physical address and length. */
611c7e4935fSss150715 physackp = &(ack.dlm_msg->physaddr_ack);
612c7e4935fSss150715 physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
613c7e4935fSss150715 dataoff = physackp->dl_addr_offset;
614c7e4935fSss150715 datalen = physackp->dl_addr_length;
615c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
616c7e4935fSss150715 datap = (caddr_t)physackp + dataoff;
617c7e4935fSss150715 if (datalen > DLPI_PHYSADDR_MAX)
618c7e4935fSss150715 return (DL_BADADDR);
619c7e4935fSss150715 if (dataoff < DL_PHYS_ADDR_ACK_SIZE ||
620c7e4935fSss150715 datap + datalen > physackendp)
621c7e4935fSss150715 return (DLPI_EBADMSG);
622c7e4935fSss150715
623c7e4935fSss150715 *addrlenp = physackp->dl_addr_length;
624c7e4935fSss150715 (void) memcpy(addrp, datap, datalen);
625c7e4935fSss150715 } else {
626c7e4935fSss150715 *addrlenp = datalen;
627c7e4935fSss150715 }
628c7e4935fSss150715
629c7e4935fSss150715 return (DLPI_SUCCESS);
630c7e4935fSss150715 }
631c7e4935fSss150715
632c7e4935fSss150715 int
dlpi_set_physaddr(dlpi_handle_t dh,uint_t type,const void * addrp,size_t addrlen)633c7e4935fSss150715 dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp,
634c7e4935fSss150715 size_t addrlen)
635c7e4935fSss150715 {
636c7e4935fSss150715 dlpi_msg_t req, ack;
637c7e4935fSss150715 dl_set_phys_addr_req_t *setphysreqp;
638c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
639c7e4935fSss150715
640c7e4935fSss150715 if (dip == NULL)
641c7e4935fSss150715 return (DLPI_EINHANDLE);
642c7e4935fSss150715
643c7e4935fSss150715 if (addrp == NULL || type != DL_CURR_PHYS_ADDR ||
644c7e4935fSss150715 addrlen > DLPI_PHYSADDR_MAX)
645c7e4935fSss150715 return (DLPI_EINVAL);
646c7e4935fSss150715
647c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ);
648c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
649c7e4935fSss150715
650c7e4935fSss150715 setphysreqp = &(req.dlm_msg->set_physaddr_req);
651c7e4935fSss150715 setphysreqp->dl_addr_length = addrlen;
652c7e4935fSss150715 setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
653c7e4935fSss150715 (void) memcpy(&setphysreqp[1], addrp, addrlen);
654c7e4935fSss150715
655c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
656c7e4935fSss150715 }
657c7e4935fSss150715
658c7e4935fSss150715 int
dlpi_send(dlpi_handle_t dh,const void * daddrp,size_t daddrlen,const void * msgbuf,size_t msglen,const dlpi_sendinfo_t * sendp)659c7e4935fSss150715 dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen,
660c7e4935fSss150715 const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp)
661c7e4935fSss150715 {
662c7e4935fSss150715 dlpi_msg_t req;
663c7e4935fSss150715 dl_unitdata_req_t *udatareqp;
664c7e4935fSss150715 uint_t sap;
665c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
666c7e4935fSss150715
667c7e4935fSss150715 if (dip == NULL)
668c7e4935fSss150715 return (DLPI_EINHANDLE);
669c7e4935fSss150715
670c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW)
6713ab45760Sss150715 return (i_dlpi_strputmsg(dip, NULL, msgbuf, msglen, 0));
672c7e4935fSss150715
673948f2876Sss150715 if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX)
674c7e4935fSss150715 return (DLPI_EINVAL);
675c7e4935fSss150715
676c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_UNITDATA_REQ);
677c7e4935fSss150715 udatareqp = &(req.dlm_msg->unitdata_req);
678c7e4935fSss150715
679c7e4935fSss150715 /* Set priority to default priority range. */
680c7e4935fSss150715 udatareqp->dl_priority.dl_min = 0;
681c7e4935fSss150715 udatareqp->dl_priority.dl_max = 0;
682c7e4935fSss150715
683c7e4935fSss150715 /* Use SAP value if specified otherwise use bound SAP value. */
684c7e4935fSss150715 if (sendp != NULL) {
685c7e4935fSss150715 sap = sendp->dsi_sap;
686c7e4935fSss150715 if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE)
687c7e4935fSss150715 udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min;
688c7e4935fSss150715 if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE)
689c7e4935fSss150715 udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max;
690c7e4935fSss150715 } else {
691c7e4935fSss150715 sap = dip->dli_sap;
692c7e4935fSss150715 }
693c7e4935fSss150715
694c7e4935fSss150715 udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen;
695c7e4935fSss150715 udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
696c7e4935fSss150715
697c7e4935fSss150715 /*
698c7e4935fSss150715 * Since `daddrp' only has the link-layer destination address,
699c7e4935fSss150715 * we must prepend or append the SAP (according to dli_sapbefore)
700c7e4935fSss150715 * to make a full DLPI address.
701c7e4935fSss150715 */
702c7e4935fSss150715 if (dip->dli_sapbefore) {
703c7e4935fSss150715 i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen);
704c7e4935fSss150715 (void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen,
705c7e4935fSss150715 daddrp, daddrlen);
706c7e4935fSss150715 } else {
707c7e4935fSss150715 (void) memcpy(&udatareqp[1], daddrp, daddrlen);
708c7e4935fSss150715 i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap,
709c7e4935fSss150715 dip->dli_saplen);
710c7e4935fSss150715 }
711c7e4935fSss150715
7123ab45760Sss150715 return (i_dlpi_strputmsg(dip, &req, msgbuf, msglen, 0));
713c7e4935fSss150715 }
714c7e4935fSss150715
715c7e4935fSss150715 int
dlpi_recv(dlpi_handle_t dh,void * saddrp,size_t * saddrlenp,void * msgbuf,size_t * msglenp,int msec,dlpi_recvinfo_t * recvp)716c7e4935fSss150715 dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf,
717c7e4935fSss150715 size_t *msglenp, int msec, dlpi_recvinfo_t *recvp)
718c7e4935fSss150715 {
719c7e4935fSss150715 int retval;
720c7e4935fSss150715 dlpi_msg_t ind;
721c7e4935fSss150715 size_t totmsglen;
722c7e4935fSss150715 dl_unitdata_ind_t *udatap;
723c7e4935fSss150715 t_uscalar_t dataoff, datalen;
724c7e4935fSss150715 caddr_t datap, indendp;
725c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
726c7e4935fSss150715
727c7e4935fSss150715 if (dip == NULL)
728c7e4935fSss150715 return (DLPI_EINHANDLE);
729c7e4935fSss150715 /*
730c7e4935fSss150715 * If handle is in raw mode ignore everything except total message
731c7e4935fSss150715 * length.
732c7e4935fSss150715 */
733c7e4935fSss150715 if (dip->dli_oflags & DLPI_RAW) {
7343ab45760Sss150715 retval = i_dlpi_strgetmsg(dip, msec, NULL, 0, 0, 0, msgbuf,
7353ab45760Sss150715 msglenp, &totmsglen);
736c7e4935fSss150715
737c7e4935fSss150715 if (retval == DLPI_SUCCESS && recvp != NULL)
738c7e4935fSss150715 recvp->dri_totmsglen = totmsglen;
739c7e4935fSss150715 return (retval);
740c7e4935fSss150715 }
741c7e4935fSss150715
742c7e4935fSss150715 DLPI_MSG_CREATE(ind, DL_UNITDATA_IND);
743c7e4935fSss150715 udatap = &(ind.dlm_msg->unitdata_ind);
744c7e4935fSss150715 indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz;
745c7e4935fSss150715
7463ab45760Sss150715 if ((retval = i_dlpi_strgetmsg(dip, msec, &ind, DL_UNITDATA_IND,
7473ab45760Sss150715 DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, msgbuf,
7483ab45760Sss150715 msglenp, &totmsglen)) != DLPI_SUCCESS)
749c7e4935fSss150715 return (retval);
750c7e4935fSss150715
751c7e4935fSss150715 /*
752c7e4935fSss150715 * If DLPI link provides source address, store source address in
753c7e4935fSss150715 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0.
754c7e4935fSss150715 */
755c7e4935fSss150715 if (saddrp != NULL && saddrlenp != NULL) {
756c7e4935fSss150715 if (*saddrlenp < DLPI_PHYSADDR_MAX)
757c7e4935fSss150715 return (DLPI_EINVAL);
758c7e4935fSss150715
759c7e4935fSss150715 dataoff = udatap->dl_src_addr_offset;
760c7e4935fSss150715 datalen = udatap->dl_src_addr_length;
761c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
762c7e4935fSss150715 datap = (caddr_t)udatap + dataoff;
763c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE ||
764c7e4935fSss150715 datap + datalen > indendp)
765c7e4935fSss150715 return (DLPI_EBADMSG);
766c7e4935fSss150715
767c7e4935fSss150715 *saddrlenp = datalen - dip->dli_saplen;
768c7e4935fSss150715 if (*saddrlenp > DLPI_PHYSADDR_MAX)
769c7e4935fSss150715 return (DL_BADADDR);
770c7e4935fSss150715
771c7e4935fSss150715 if (dip->dli_sapbefore)
772c7e4935fSss150715 datap += dip->dli_saplen;
773c7e4935fSss150715 (void) memcpy(saddrp, datap, *saddrlenp);
774c7e4935fSss150715 } else {
775c7e4935fSss150715 *saddrlenp = 0;
776c7e4935fSss150715 }
777c7e4935fSss150715 }
778c7e4935fSss150715
779c7e4935fSss150715 /*
780c7e4935fSss150715 * If destination address requested, check and save destination
781c7e4935fSss150715 * address, if any.
782c7e4935fSss150715 */
783c7e4935fSss150715 if (recvp != NULL) {
784c7e4935fSss150715 dataoff = udatap->dl_dest_addr_offset;
785c7e4935fSss150715 datalen = udatap->dl_dest_addr_length;
786c7e4935fSss150715 if (dataoff != 0 && datalen != 0) {
787c7e4935fSss150715 datap = (caddr_t)udatap + dataoff;
788c7e4935fSss150715 if (dataoff < DL_UNITDATA_IND_SIZE ||
789c7e4935fSss150715 datap + datalen > indendp)
790c7e4935fSss150715 return (DLPI_EBADMSG);
791c7e4935fSss150715
792c7e4935fSss150715 recvp->dri_destaddrlen = datalen - dip->dli_saplen;
793c7e4935fSss150715 if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX)
794c7e4935fSss150715 return (DL_BADADDR);
795c7e4935fSss150715
796c7e4935fSss150715 if (dip->dli_sapbefore)
797c7e4935fSss150715 datap += dip->dli_saplen;
798c7e4935fSss150715 (void) memcpy(recvp->dri_destaddr, datap,
799c7e4935fSss150715 recvp->dri_destaddrlen);
800c7e4935fSss150715 } else {
801c7e4935fSss150715 recvp->dri_destaddrlen = 0;
802c7e4935fSss150715 }
803c7e4935fSss150715
8045494fa53Sss150715 recvp->dri_destaddrtype = udatap->dl_group_address;
805c7e4935fSss150715 recvp->dri_totmsglen = totmsglen;
806c7e4935fSss150715 }
807c7e4935fSss150715
808c7e4935fSss150715 return (DLPI_SUCCESS);
809c7e4935fSss150715 }
810c7e4935fSss150715
811c7e4935fSss150715 int
dlpi_enabnotify(dlpi_handle_t dh,uint_t notes,dlpi_notifyfunc_t * funcp,void * arg,dlpi_notifyid_t * id)8123ab45760Sss150715 dlpi_enabnotify(dlpi_handle_t dh, uint_t notes, dlpi_notifyfunc_t *funcp,
8133ab45760Sss150715 void *arg, dlpi_notifyid_t *id)
8143ab45760Sss150715 {
8153ab45760Sss150715 int retval;
8163ab45760Sss150715 dlpi_msg_t req, ack;
8173ab45760Sss150715 dl_notify_req_t *notifyreqp;
8183ab45760Sss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
8193ab45760Sss150715 dlpi_notifyent_t *newnotifp;
8203ab45760Sss150715 dlpi_info_t dlinfo;
8213ab45760Sss150715
8223ab45760Sss150715 if (dip == NULL)
8233ab45760Sss150715 return (DLPI_EINHANDLE);
8243ab45760Sss150715
8253ab45760Sss150715 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
8263ab45760Sss150715 if (retval != DLPI_SUCCESS)
8273ab45760Sss150715 return (retval);
8283ab45760Sss150715
8293ab45760Sss150715 if (dip->dli_note_processing)
8303ab45760Sss150715 return (DLPI_FAILURE);
8313ab45760Sss150715
8323ab45760Sss150715 if (funcp == NULL || id == NULL)
8333ab45760Sss150715 return (DLPI_EINVAL);
8343ab45760Sss150715
8353ab45760Sss150715 if ((~DLPI_NOTIFICATION_TYPES & notes) ||
8363ab45760Sss150715 !(notes & DLPI_NOTIFICATION_TYPES))
8373ab45760Sss150715 return (DLPI_ENOTEINVAL);
8383ab45760Sss150715
8393ab45760Sss150715 DLPI_MSG_CREATE(req, DL_NOTIFY_REQ);
8403ab45760Sss150715 DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK);
8413ab45760Sss150715
8423ab45760Sss150715 notifyreqp = &(req.dlm_msg->notify_req);
8433ab45760Sss150715 notifyreqp->dl_notifications = notes;
8443ab45760Sss150715 notifyreqp->dl_timelimit = 0;
8453ab45760Sss150715
8463ab45760Sss150715 retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0);
8473ab45760Sss150715 if (retval == DL_NOTSUPPORTED)
8483ab45760Sss150715 return (DLPI_ENOTENOTSUP);
8493ab45760Sss150715
8503ab45760Sss150715 if (retval != DLPI_SUCCESS)
8513ab45760Sss150715 return (retval);
8523ab45760Sss150715
8533ab45760Sss150715 if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL)
8543ab45760Sss150715 return (DL_SYSERR);
8553ab45760Sss150715
8563ab45760Sss150715 /* Register notification information. */
8573ab45760Sss150715 newnotifp->dln_fnp = funcp;
8583ab45760Sss150715 newnotifp->dln_notes = notes;
8593ab45760Sss150715 newnotifp->arg = arg;
8603ab45760Sss150715 newnotifp->dln_rm = B_FALSE;
8613ab45760Sss150715
8623ab45760Sss150715 /* Insert notification node at head */
8633ab45760Sss150715 newnotifp->dln_next = dip->dli_notifylistp;
8643ab45760Sss150715 dip->dli_notifylistp = newnotifp;
8653ab45760Sss150715
8663ab45760Sss150715 *id = (dlpi_notifyid_t)newnotifp;
8673ab45760Sss150715 return (DLPI_SUCCESS);
8683ab45760Sss150715 }
8693ab45760Sss150715
8703ab45760Sss150715 int
dlpi_disabnotify(dlpi_handle_t dh,dlpi_notifyid_t id,void ** argp)8713ab45760Sss150715 dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp)
8723ab45760Sss150715 {
8733ab45760Sss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
8743ab45760Sss150715 dlpi_notifyent_t *remid = (dlpi_notifyent_t *)id;
8753ab45760Sss150715
8763ab45760Sss150715 if (dip == NULL)
8773ab45760Sss150715 return (DLPI_EINHANDLE);
8783ab45760Sss150715
8793ab45760Sss150715 /* Walk the notifyentry list to find matching id. */
8803ab45760Sss150715 if (!(i_dlpi_notifyidexists(dip, remid)))
8813ab45760Sss150715 return (DLPI_ENOTEIDINVAL);
8823ab45760Sss150715
8833ab45760Sss150715 if (argp != NULL)
8843ab45760Sss150715 *argp = remid->arg;
8853ab45760Sss150715
8863ab45760Sss150715 remid->dln_rm = B_TRUE;
8873ab45760Sss150715 /* Delete node if callbacks are not being processed. */
8883ab45760Sss150715 if (!dip->dli_note_processing)
8893ab45760Sss150715 i_dlpi_deletenotifyid(dip);
8903ab45760Sss150715
8913ab45760Sss150715 return (DLPI_SUCCESS);
8923ab45760Sss150715 }
8933ab45760Sss150715
8943ab45760Sss150715 int
dlpi_fd(dlpi_handle_t dh)895c7e4935fSss150715 dlpi_fd(dlpi_handle_t dh)
896c7e4935fSss150715 {
897c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
898c7e4935fSss150715
899c7e4935fSss150715 return (dip != NULL ? dip->dli_fd : -1);
900c7e4935fSss150715 }
901c7e4935fSss150715
902c7e4935fSss150715 int
dlpi_set_timeout(dlpi_handle_t dh,int sec)903c7e4935fSss150715 dlpi_set_timeout(dlpi_handle_t dh, int sec)
904c7e4935fSss150715 {
905c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
906c7e4935fSss150715
907c7e4935fSss150715 if (dip == NULL)
908c7e4935fSss150715 return (DLPI_EINHANDLE);
909c7e4935fSss150715
910c7e4935fSss150715 dip->dli_timeout = sec;
911c7e4935fSss150715 return (DLPI_SUCCESS);
912c7e4935fSss150715 }
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate const char *
dlpi_linkname(dlpi_handle_t dh)915c7e4935fSss150715 dlpi_linkname(dlpi_handle_t dh)
9167c478bd9Sstevel@tonic-gate {
917c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
9187c478bd9Sstevel@tonic-gate
919c7e4935fSss150715 return (dip != NULL ? dip->dli_linkname : NULL);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate
922c7e4935fSss150715 /*
923c7e4935fSss150715 * Returns DLPI style stored in the handle.
924c7e4935fSss150715 * Note: This function is used for test purposes only. Do not remove without
925c7e4935fSss150715 * fixing the DLPI testsuite.
926c7e4935fSss150715 */
927c7e4935fSss150715 uint_t
dlpi_style(dlpi_handle_t dh)928c7e4935fSss150715 dlpi_style(dlpi_handle_t dh)
9297c478bd9Sstevel@tonic-gate {
930c7e4935fSss150715 dlpi_impl_t *dip = (dlpi_impl_t *)dh;
9317c478bd9Sstevel@tonic-gate
932c7e4935fSss150715 return (dip->dli_style);
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate
935948f2876Sss150715 uint_t
dlpi_arptype(uint_t dlpitype)936948f2876Sss150715 dlpi_arptype(uint_t dlpitype)
937948f2876Sss150715 {
938948f2876Sss150715 switch (dlpitype) {
939948f2876Sss150715
940948f2876Sss150715 case DL_ETHER:
941948f2876Sss150715 return (ARPHRD_ETHER);
942948f2876Sss150715
943948f2876Sss150715 case DL_FRAME:
944948f2876Sss150715 return (ARPHRD_FRAME);
945948f2876Sss150715
946948f2876Sss150715 case DL_ATM:
947948f2876Sss150715 return (ARPHRD_ATM);
948948f2876Sss150715
949948f2876Sss150715 case DL_IPATM:
950948f2876Sss150715 return (ARPHRD_IPATM);
951948f2876Sss150715
952948f2876Sss150715 case DL_HDLC:
953948f2876Sss150715 return (ARPHRD_HDLC);
954948f2876Sss150715
955948f2876Sss150715 case DL_FC:
956948f2876Sss150715 return (ARPHRD_FC);
957948f2876Sss150715
958948f2876Sss150715 case DL_CSMACD: /* ieee 802 networks */
959948f2876Sss150715 case DL_TPB:
960948f2876Sss150715 case DL_TPR:
961948f2876Sss150715 case DL_METRO:
962948f2876Sss150715 case DL_FDDI:
963948f2876Sss150715 return (ARPHRD_IEEE802);
964948f2876Sss150715
965948f2876Sss150715 case DL_IB:
966948f2876Sss150715 return (ARPHRD_IB);
967948f2876Sss150715
968948f2876Sss150715 case DL_IPV4:
969948f2876Sss150715 case DL_IPV6:
970948f2876Sss150715 return (ARPHRD_TUNNEL);
971948f2876Sss150715 }
972948f2876Sss150715
973948f2876Sss150715 return (0);
974948f2876Sss150715 }
975948f2876Sss150715
976948f2876Sss150715 uint_t
dlpi_iftype(uint_t dlpitype)977948f2876Sss150715 dlpi_iftype(uint_t dlpitype)
978948f2876Sss150715 {
979948f2876Sss150715 switch (dlpitype) {
980948f2876Sss150715
981948f2876Sss150715 case DL_ETHER:
982948f2876Sss150715 return (IFT_ETHER);
983948f2876Sss150715
984948f2876Sss150715 case DL_ATM:
985948f2876Sss150715 return (IFT_ATM);
986948f2876Sss150715
987948f2876Sss150715 case DL_CSMACD:
988948f2876Sss150715 return (IFT_ISO88023);
989948f2876Sss150715
990948f2876Sss150715 case DL_TPB:
991948f2876Sss150715 return (IFT_ISO88024);
992948f2876Sss150715
993948f2876Sss150715 case DL_TPR:
994948f2876Sss150715 return (IFT_ISO88025);
995948f2876Sss150715
996948f2876Sss150715 case DL_FDDI:
997948f2876Sss150715 return (IFT_FDDI);
998948f2876Sss150715
999948f2876Sss150715 case DL_IB:
1000948f2876Sss150715 return (IFT_IB);
1001948f2876Sss150715
1002948f2876Sss150715 case DL_OTHER:
1003948f2876Sss150715 return (IFT_OTHER);
1004948f2876Sss150715 }
1005948f2876Sss150715
1006948f2876Sss150715 return (0);
1007948f2876Sss150715 }
1008948f2876Sss150715
1009c7e4935fSss150715 /*
1010d62bc4baSyz147064 * This function attempts to open a device under the following namespaces:
1011b127ac41SPhilip Kirk * /dev/ipnet - if DLPI_DEVIPNET is specified
1012d62bc4baSyz147064 * /dev/net - if a data-link with the specified name exists
1013d62bc4baSyz147064 * /dev - if DLPI_DEVONLY is specified, or if there is no
1014d62bc4baSyz147064 * data-link with the specified name (could be /dev/ip)
1015d62bc4baSyz147064 *
1016b127ac41SPhilip Kirk * In particular, if DLPI_DEVIPNET is not specified, this function is used to
1017b127ac41SPhilip Kirk * open a data-link node, or "/dev/ip" node. It is usually be called firstly
1018d62bc4baSyz147064 * with style1 being B_TRUE, and if that fails and the return value is not
1019d62bc4baSyz147064 * DLPI_ENOTSTYLE2, the function will again be called with style1 being
1020d62bc4baSyz147064 * B_FALSE (style-1 open attempt first, then style-2 open attempt).
1021d62bc4baSyz147064 *
1022d62bc4baSyz147064 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node
1023d62bc4baSyz147064 * directly.
1024d62bc4baSyz147064 *
1025d62bc4baSyz147064 * Otherwise, for style-1 attempt, the function will try to open the style-1
1026d62bc4baSyz147064 * /dev/net node, and perhaps fallback to open the style-1 /dev node if the
1027d62bc4baSyz147064 * give name is not a data-link name (e.g., it is /dev/ip). Note that the
1028d62bc4baSyz147064 * fallback and the subsequent style-2 attempt will not happen if:
1029d62bc4baSyz147064 * 1. style-1 opening of the /dev/net node succeeds;
1030d62bc4baSyz147064 * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT,
1031d62bc4baSyz147064 * which means that the specific /dev/net node exist, but the attempt fails
1032d62bc4baSyz147064 * for some other reason;
1033d62bc4baSyz147064 * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is
1034d62bc4baSyz147064 * a known device name or its VLAN PPA hack name. (for example, assuming
1035d62bc4baSyz147064 * device bge0 is renamed to net0, opening /dev/net/bge1000 would return
1036d62bc4baSyz147064 * ENOENT, but we should not fallback to open /dev/bge1000 in this case,
1037d62bc4baSyz147064 * as VLAN 1 over the bge0 device should be named as net1000.
1038d62bc4baSyz147064 *
1039d62bc4baSyz147064 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed
1040d62bc4baSyz147064 * the second style-2 open attempt.
1041c7e4935fSss150715 */
10427c478bd9Sstevel@tonic-gate static int
i_dlpi_open(const char * provider,int * fd,uint_t flags,boolean_t style1)1043d62bc4baSyz147064 i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
10447c478bd9Sstevel@tonic-gate {
1045c7e4935fSss150715 char path[MAXPATHLEN];
1046c7e4935fSss150715 int oflags;
1047c7e4935fSss150715
1048d62bc4baSyz147064 errno = ENOENT;
1049c7e4935fSss150715 oflags = O_RDWR;
1050c7e4935fSss150715 if (flags & DLPI_EXCL)
1051c7e4935fSss150715 oflags |= O_EXCL;
1052c7e4935fSss150715
1053b127ac41SPhilip Kirk if (flags & DLPI_DEVIPNET) {
1054b127ac41SPhilip Kirk (void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider);
1055b127ac41SPhilip Kirk if ((*fd = open(path, oflags)) != -1)
1056b127ac41SPhilip Kirk return (DLPI_SUCCESS);
1057b127ac41SPhilip Kirk else
1058b127ac41SPhilip Kirk return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1059b127ac41SPhilip Kirk } else if (style1 && !(flags & DLPI_DEVONLY)) {
1060d62bc4baSyz147064 char driver[DLPI_LINKNAME_MAX];
1061d62bc4baSyz147064 char device[DLPI_LINKNAME_MAX];
1062d62bc4baSyz147064 datalink_id_t linkid;
1063d62bc4baSyz147064 uint_t ppa;
10644ac67f02SAnurag S. Maskey dladm_handle_t handle;
1065c7e4935fSss150715
1066d62bc4baSyz147064 /*
1067d62bc4baSyz147064 * This is not a valid style-1 name. It could be "ip" module
1068d62bc4baSyz147064 * for example. Fallback to open the /dev node.
1069d62bc4baSyz147064 */
1070d62bc4baSyz147064 if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS)
1071d62bc4baSyz147064 goto fallback;
1072d62bc4baSyz147064
1073d62bc4baSyz147064 (void) snprintf(path, sizeof (path), "/dev/net/%s", provider);
1074c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1)
1075c7e4935fSss150715 return (DLPI_SUCCESS);
1076c7e4935fSss150715
1077c7e4935fSss150715 /*
1078d62bc4baSyz147064 * We don't fallback to open the /dev node when it returns
1079d62bc4baSyz147064 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2
1080d62bc4baSyz147064 * is returned to indicate not to continue the style-2 open.
1081c7e4935fSss150715 */
1082d62bc4baSyz147064 if (errno != ENOENT)
1083d62bc4baSyz147064 return (DLPI_ENOTSTYLE2);
1084c7e4935fSss150715
1085d62bc4baSyz147064 /*
1086d62bc4baSyz147064 * We didn't find the /dev/net node. Then we check whether
1087d62bc4baSyz147064 * the given name is a device name or its VLAN PPA hack name
1088d62bc4baSyz147064 * of a known link. If the answer is yes, and this link
1089d62bc4baSyz147064 * supports vanity naming, then the link (or the VLAN) should
1090d62bc4baSyz147064 * also have its /dev/net node but perhaps with another vanity
1091d62bc4baSyz147064 * name (for example, when bge0 is renamed to net0). In this
1092d62bc4baSyz147064 * case, although attempt to open the /dev/net/<devname> fails,
1093d62bc4baSyz147064 * we should not fallback to open the /dev/<devname> node.
1094d62bc4baSyz147064 */
1095d62bc4baSyz147064 (void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver,
1096d62bc4baSyz147064 ppa >= 1000 ? ppa % 1000 : ppa);
1097d62bc4baSyz147064
10984ac67f02SAnurag S. Maskey /* open libdladm handle rather than taking it as input */
10994ac67f02SAnurag S. Maskey if (dladm_open(&handle) != DLADM_STATUS_OK)
1100e11c3f44Smeem goto fallback;
11014ac67f02SAnurag S. Maskey
11024ac67f02SAnurag S. Maskey if (dladm_dev2linkid(handle, device, &linkid) ==
11034ac67f02SAnurag S. Maskey DLADM_STATUS_OK) {
1104d62bc4baSyz147064 dladm_phys_attr_t dpa;
1105d62bc4baSyz147064
11064ac67f02SAnurag S. Maskey if ((dladm_phys_info(handle, linkid, &dpa,
11074ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK &&
11084ac67f02SAnurag S. Maskey !dpa.dp_novanity) {
11094ac67f02SAnurag S. Maskey dladm_close(handle);
1110d62bc4baSyz147064 return (DLPI_ENOTSTYLE2);
1111d62bc4baSyz147064 }
1112d62bc4baSyz147064 }
11134ac67f02SAnurag S. Maskey dladm_close(handle);
1114d62bc4baSyz147064 }
1115d62bc4baSyz147064
1116d62bc4baSyz147064 fallback:
1117d62bc4baSyz147064 (void) snprintf(path, sizeof (path), "/dev/%s", provider);
1118c7e4935fSss150715 if ((*fd = open(path, oflags)) != -1)
1119c7e4935fSss150715 return (DLPI_SUCCESS);
1120c7e4935fSss150715
1121c7e4935fSss150715 return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1122c7e4935fSss150715 }
1123c7e4935fSss150715
1124c7e4935fSss150715 /*
1125c7e4935fSss150715 * Open a style 1 link. PPA is implicitly attached.
1126c7e4935fSss150715 */
1127c7e4935fSss150715 static int
i_dlpi_style1_open(dlpi_impl_t * dip)1128c7e4935fSss150715 i_dlpi_style1_open(dlpi_impl_t *dip)
1129c7e4935fSss150715 {
1130c7e4935fSss150715 int retval, save_errno;
1131c7e4935fSss150715 int fd;
1132c7e4935fSss150715
11332b24ab6bSSebastien Roy retval = i_dlpi_open(dip->dli_linkname, &fd, dip->dli_oflags, B_TRUE);
11342b24ab6bSSebastien Roy if (retval != DLPI_SUCCESS)
1135c7e4935fSss150715 return (retval);
1136c7e4935fSss150715 dip->dli_fd = fd;
1137c7e4935fSss150715
1138c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) {
1139c7e4935fSss150715 save_errno = errno;
1140c7e4935fSss150715 (void) close(dip->dli_fd);
1141c7e4935fSss150715 errno = save_errno;
1142c7e4935fSss150715 }
1143c7e4935fSss150715
11442b24ab6bSSebastien Roy return (retval);
1145c7e4935fSss150715 }
1146c7e4935fSss150715
1147c7e4935fSss150715 /*
1148c7e4935fSss150715 * Open a style 2 link. PPA must be explicitly attached.
1149c7e4935fSss150715 */
1150c7e4935fSss150715 static int
i_dlpi_style2_open(dlpi_impl_t * dip)1151c7e4935fSss150715 i_dlpi_style2_open(dlpi_impl_t *dip)
1152c7e4935fSss150715 {
1153c7e4935fSss150715 int fd;
1154c7e4935fSss150715 int retval, save_errno;
1155c7e4935fSss150715
11562b24ab6bSSebastien Roy retval = i_dlpi_open(dip->dli_provider, &fd, dip->dli_oflags, B_FALSE);
11572b24ab6bSSebastien Roy if (retval != DLPI_SUCCESS)
1158c7e4935fSss150715 return (retval);
1159c7e4935fSss150715 dip->dli_fd = fd;
1160c7e4935fSss150715
1161c7e4935fSss150715 /*
1162c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a
1163c7e4935fSss150715 * DLPI link so attach and ignore rest.
1164c7e4935fSss150715 */
1165c7e4935fSss150715 if (dip->dli_oflags & DLPI_SERIAL)
1166c7e4935fSss150715 goto attach;
1167c7e4935fSss150715
1168c7e4935fSss150715 if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS)
1169c7e4935fSss150715 goto failure;
1170c7e4935fSss150715
1171c7e4935fSss150715 /*
1172c7e4935fSss150715 * Succeeded opening the link and verified it is style2. Now attach to
1173c7e4935fSss150715 * PPA only if DLPI_NOATTACH is not set.
1174c7e4935fSss150715 */
1175c7e4935fSss150715 if (dip->dli_oflags & DLPI_NOATTACH)
1176c7e4935fSss150715 return (DLPI_SUCCESS);
1177c7e4935fSss150715
1178c7e4935fSss150715 attach:
11792b24ab6bSSebastien Roy if ((retval = i_dlpi_attach(dip)) == DLPI_SUCCESS)
1180c7e4935fSss150715 return (DLPI_SUCCESS);
1181c7e4935fSss150715
1182c7e4935fSss150715 failure:
1183c7e4935fSss150715 save_errno = errno;
1184c7e4935fSss150715 (void) close(dip->dli_fd);
1185c7e4935fSss150715 errno = save_errno;
1186c7e4935fSss150715 return (retval);
1187c7e4935fSss150715 }
1188c7e4935fSss150715
1189c7e4935fSss150715 /*
1190c7e4935fSss150715 * Verify with DLPI that the link is the expected DLPI 'style' device,
1191c7e4935fSss150715 * dlpi_info sets the DLPI style in the DLPI handle.
1192c7e4935fSss150715 */
1193c7e4935fSss150715 static int
i_dlpi_checkstyle(dlpi_impl_t * dip,t_uscalar_t style)1194c7e4935fSss150715 i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style)
1195c7e4935fSss150715 {
1196c7e4935fSss150715 int retval;
1197c7e4935fSss150715 dlpi_info_t dlinfo;
1198c7e4935fSss150715
1199c7e4935fSss150715 retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
1200c7e4935fSss150715 if (retval == DLPI_SUCCESS && dip->dli_style != style)
1201c7e4935fSss150715 retval = DLPI_EBADLINK;
1202c7e4935fSss150715
1203c7e4935fSss150715 return (retval);
1204c7e4935fSss150715 }
1205c7e4935fSss150715
1206c7e4935fSss150715 /*
1207c7e4935fSss150715 * For DLPI style 2 providers, an explicit attach of PPA is required.
1208c7e4935fSss150715 */
1209c7e4935fSss150715 static int
i_dlpi_attach(dlpi_impl_t * dip)1210c7e4935fSss150715 i_dlpi_attach(dlpi_impl_t *dip)
1211c7e4935fSss150715 {
1212c7e4935fSss150715 dlpi_msg_t req, ack;
1213c7e4935fSss150715 dl_attach_req_t *attachreqp;
1214c7e4935fSss150715
1215c7e4935fSss150715 /*
1216c7e4935fSss150715 * Special case: DLPI_SERIAL flag (synchronous serial lines)
1217c7e4935fSss150715 * is not a DLPI link so ignore DLPI style.
1218c7e4935fSss150715 */
1219c7e4935fSss150715 if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL))
1220c7e4935fSss150715 return (DLPI_ENOTSTYLE2);
1221c7e4935fSss150715
1222c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_ATTACH_REQ);
1223c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
1224c7e4935fSss150715
1225c7e4935fSss150715 attachreqp = &(req.dlm_msg->attach_req);
1226c7e4935fSss150715 attachreqp->dl_ppa = dip->dli_ppa;
1227c7e4935fSss150715
1228c7e4935fSss150715 return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
1229c7e4935fSss150715 }
1230c7e4935fSss150715
1231c7e4935fSss150715 /*
1232c7e4935fSss150715 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care
1233c7e4935fSss150715 * if this request fails, as this indicates the underlying DLPI device does
1234c7e4935fSss150715 * not support link aggregation (pre-GLDV3 device drivers), and thus will
1235c7e4935fSss150715 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing
1236c7e4935fSss150715 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p).
1237c7e4935fSss150715 */
1238c7e4935fSss150715 static void
i_dlpi_passive(dlpi_impl_t * dip)1239c7e4935fSss150715 i_dlpi_passive(dlpi_impl_t *dip)
1240c7e4935fSss150715 {
1241c7e4935fSss150715 dlpi_msg_t req, ack;
1242c7e4935fSss150715
1243c7e4935fSss150715 DLPI_MSG_CREATE(req, DL_PASSIVE_REQ);
1244c7e4935fSss150715 DLPI_MSG_CREATE(ack, DL_OK_ACK);
1245c7e4935fSss150715
1246c7e4935fSss150715 (void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0);
1247c7e4935fSss150715 }
1248c7e4935fSss150715
1249c7e4935fSss150715 /*
1250c7e4935fSss150715 * Send a dlpi control message and/or data message on a stream. The inputs
1251c7e4935fSss150715 * for this function are:
12523ab45760Sss150715 * dlpi_impl_t *dip: internal dlpi handle to open stream
1253c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure
1254c7e4935fSss150715 * void *databuf: data buffer
1255c7e4935fSss150715 * size_t datalen: data buffer len
1256c7e4935fSss150715 * int flags: flags to set for putmsg()
1257c7e4935fSss150715 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure.
1258c7e4935fSss150715 */
1259c7e4935fSss150715 static int
i_dlpi_strputmsg(dlpi_impl_t * dip,const dlpi_msg_t * dlreqp,const void * databuf,size_t datalen,int flags)12603ab45760Sss150715 i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1261c7e4935fSss150715 const void *databuf, size_t datalen, int flags)
1262c7e4935fSss150715 {
1263c7e4935fSss150715 int retval;
12643ab45760Sss150715 int fd = dip->dli_fd;
12657c478bd9Sstevel@tonic-gate struct strbuf ctl;
12667c478bd9Sstevel@tonic-gate struct strbuf data;
1267c7e4935fSss150715
1268c7e4935fSss150715 if (dlreqp != NULL) {
1269c7e4935fSss150715 ctl.buf = (void *)dlreqp->dlm_msg;
1270c7e4935fSss150715 ctl.len = dlreqp->dlm_msgsz;
1271c7e4935fSss150715 }
1272c7e4935fSss150715
1273c7e4935fSss150715 data.buf = (void *)databuf;
1274c7e4935fSss150715 data.len = datalen;
1275c7e4935fSss150715
1276c7e4935fSss150715 retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl),
1277c7e4935fSss150715 (databuf == NULL ? NULL : &data), flags);
1278c7e4935fSss150715
1279c7e4935fSss150715 return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR);
1280c7e4935fSss150715 }
1281c7e4935fSss150715
1282c7e4935fSss150715 /*
1283c7e4935fSss150715 * Get a DLPI control message and/or data message from a stream. The inputs
1284c7e4935fSss150715 * for this function are:
12853ab45760Sss150715 * dlpi_impl_t *dip: internal dlpi handle
1286c7e4935fSss150715 * int msec: timeout to wait for message
1287c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure, the message size
1288c7e4935fSss150715 * member on return stores actual size received
1289c7e4935fSss150715 * t_uscalar_t dlreqprim: requested primitive
1290c7e4935fSss150715 * t_uscalar_t dlreplyprim:acknowledged primitive in response to request
1291c7e4935fSss150715 * size_t dlreplyminsz: minimum size of acknowledged primitive size
1292c7e4935fSss150715 * void *databuf: data buffer
1293c7e4935fSss150715 * size_t *datalenp: data buffer len
1294c7e4935fSss150715 * size_t *totdatalenp: total data received. Greater than 'datalenp' if
1295c7e4935fSss150715 * actual data received is larger than 'databuf'
1296c7e4935fSss150715 * Function returns DLPI_SUCCESS if requested message is retrieved
12973ab45760Sss150715 * otherwise returns error code or timeouts. If a notification arrives on
12983ab45760Sss150715 * the stream the callback is notified. However, error returned during the
12993ab45760Sss150715 * handling of notification is ignored as it would be confusing to actual caller
13003ab45760Sss150715 * of this function.
1301c7e4935fSss150715 */
1302c7e4935fSss150715 static int
i_dlpi_strgetmsg(dlpi_impl_t * dip,int msec,dlpi_msg_t * dlreplyp,t_uscalar_t dlreqprim,t_uscalar_t dlreplyprim,size_t dlreplyminsz,void * databuf,size_t * datalenp,size_t * totdatalenp)13033ab45760Sss150715 i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp,
13043ab45760Sss150715 t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz,
13053ab45760Sss150715 void *databuf, size_t *datalenp, size_t *totdatalenp)
1306c7e4935fSss150715 {
1307c7e4935fSss150715 int retval;
1308e11c3f44Smeem int flags;
13093ab45760Sss150715 int fd = dip->dli_fd;
1310c7e4935fSss150715 struct strbuf ctl, data;
1311c7e4935fSss150715 struct pollfd pfd;
1312c7e4935fSss150715 hrtime_t start, current;
1313c7e4935fSss150715 long bufc[DLPI_CHUNKSIZE / sizeof (long)];
1314c7e4935fSss150715 long bufd[DLPI_CHUNKSIZE / sizeof (long)];
1315c7e4935fSss150715 union DL_primitives *dlprim;
13163ab45760Sss150715 dl_notify_ind_t *dlnotif;
1317c7e4935fSss150715 boolean_t infinite = (msec < 0); /* infinite timeout */
1318c7e4935fSss150715
1319c623edd3SGirish Moodalbail /*
1320c623edd3SGirish Moodalbail * dlreplyp and databuf can be NULL at the same time, to force a check
1321c623edd3SGirish Moodalbail * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI).
1322c623edd3SGirish Moodalbail * this will be true more so for DLPI_RAW mode with notifications
1323c623edd3SGirish Moodalbail * enabled.
1324c623edd3SGirish Moodalbail */
1325c623edd3SGirish Moodalbail if ((databuf == NULL && datalenp != NULL) ||
1326c7e4935fSss150715 (databuf != NULL && datalenp == NULL))
1327c7e4935fSss150715 return (DLPI_EINVAL);
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate pfd.fd = fd;
13307c478bd9Sstevel@tonic-gate pfd.events = POLLIN | POLLPRI;
13317c478bd9Sstevel@tonic-gate
1332c7e4935fSss150715 ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg;
13337c478bd9Sstevel@tonic-gate ctl.len = 0;
1334c7e4935fSss150715 ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz;
13357c478bd9Sstevel@tonic-gate
1336c7e4935fSss150715 data.buf = (databuf == NULL) ? bufd : databuf;
13377c478bd9Sstevel@tonic-gate data.len = 0;
1338c7e4935fSss150715 data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp;
13397c478bd9Sstevel@tonic-gate
1340c7e4935fSss150715 for (;;) {
1341c7e4935fSss150715 if (!infinite)
1342*19449258SJosef 'Jeff' Sipek start = NSEC2MSEC(gethrtime());
13437c478bd9Sstevel@tonic-gate
1344c7e4935fSss150715 switch (poll(&pfd, 1, msec)) {
1345c7e4935fSss150715 default:
1346948f2876Sss150715 if (pfd.revents & POLLHUP)
1347948f2876Sss150715 return (DL_SYSERR);
13487c478bd9Sstevel@tonic-gate break;
13497c478bd9Sstevel@tonic-gate case 0:
1350c7e4935fSss150715 return (DLPI_ETIMEDOUT);
13517c478bd9Sstevel@tonic-gate case -1:
1352c7e4935fSss150715 return (DL_SYSERR);
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate
1355e11c3f44Smeem flags = 0;
1356c7e4935fSss150715 if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0)
1357c7e4935fSss150715 return (DL_SYSERR);
13587c478bd9Sstevel@tonic-gate
1359c7e4935fSss150715 if (totdatalenp != NULL)
1360c7e4935fSss150715 *totdatalenp = data.len;
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate /*
1363c7e4935fSss150715 * The supplied DLPI_CHUNKSIZE sized buffers are large enough
1364c7e4935fSss150715 * to retrieve all valid DLPI responses in one iteration.
1365c7e4935fSss150715 * If MORECTL or MOREDATA is set, we are not interested in the
1366c7e4935fSss150715 * remainder of the message. Temporary buffers are used to
1367c7e4935fSss150715 * drain the remainder of this message.
1368c7e4935fSss150715 * The special case we have to account for is if
1369c7e4935fSss150715 * a higher priority messages is enqueued whilst handling
1370c7e4935fSss150715 * this condition. We use a change in the flags parameter
1371c7e4935fSss150715 * returned by getmsg() to indicate the message has changed.
13727c478bd9Sstevel@tonic-gate */
1373c7e4935fSss150715 while (retval & (MORECTL | MOREDATA)) {
1374c7e4935fSss150715 struct strbuf cscratch, dscratch;
1375c7e4935fSss150715 int oflags = flags;
1376c7e4935fSss150715
1377c7e4935fSss150715 cscratch.buf = (char *)bufc;
1378c7e4935fSss150715 dscratch.buf = (char *)bufd;
1379c7e4935fSss150715 cscratch.len = dscratch.len = 0;
1380c7e4935fSss150715 cscratch.maxlen = dscratch.maxlen =
1381c7e4935fSss150715 sizeof (bufc);
1382c7e4935fSss150715
1383c7e4935fSss150715 if ((retval = getmsg(fd, &cscratch, &dscratch,
1384c7e4935fSss150715 &flags)) < 0)
1385c7e4935fSss150715 return (DL_SYSERR);
1386c7e4935fSss150715
1387c7e4935fSss150715 if (totdatalenp != NULL)
1388c7e4935fSss150715 *totdatalenp += dscratch.len;
1389c7e4935fSss150715 /*
1390c7e4935fSss150715 * In the special case of higher priority
1391c7e4935fSss150715 * message received, the low priority message
1392c7e4935fSss150715 * received earlier is discarded, if no data
1393c7e4935fSss150715 * or control message is left.
1394c7e4935fSss150715 */
1395c7e4935fSss150715 if ((flags != oflags) &&
1396c7e4935fSss150715 !(retval & (MORECTL | MOREDATA)) &&
1397c7e4935fSss150715 (cscratch.len != 0)) {
1398c7e4935fSss150715 ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE);
1399c7e4935fSss150715 if (dlreplyp != NULL)
1400c7e4935fSss150715 (void) memcpy(dlreplyp->dlm_msg, bufc,
1401c7e4935fSss150715 ctl.len);
1402c7e4935fSss150715 break;
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate
14067c478bd9Sstevel@tonic-gate /*
14073ab45760Sss150715 * Check if DL_NOTIFY_IND message received. If there is one,
14083ab45760Sss150715 * notify the callback function(s) and continue processing the
14093ab45760Sss150715 * requested message.
14103ab45760Sss150715 */
14113ab45760Sss150715 if (dip->dli_notifylistp != NULL &&
1412c623edd3SGirish Moodalbail ctl.len >= (int)(sizeof (t_uscalar_t)) &&
1413c623edd3SGirish Moodalbail *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) {
1414c623edd3SGirish Moodalbail /* process properly-formed DL_NOTIFY_IND messages */
1415c623edd3SGirish Moodalbail if (ctl.len >= DL_NOTIFY_IND_SIZE) {
1416c623edd3SGirish Moodalbail dlnotif = (dl_notify_ind_t *)(void *)ctl.buf;
14173ab45760Sss150715 (void) i_dlpi_notifyind_process(dip, dlnotif);
1418c623edd3SGirish Moodalbail }
1419c623edd3SGirish Moodalbail goto update_timer;
14203ab45760Sss150715 }
14213ab45760Sss150715
14223ab45760Sss150715 /*
1423c7e4935fSss150715 * If we were expecting a data message, and we got one, set
1424c7e4935fSss150715 * *datalenp. If we aren't waiting on a control message, then
1425c7e4935fSss150715 * we're done.
14267c478bd9Sstevel@tonic-gate */
1427c7e4935fSss150715 if (databuf != NULL && data.len >= 0) {
1428c7e4935fSss150715 *datalenp = data.len;
1429c7e4935fSss150715 if (dlreplyp == NULL)
1430c7e4935fSss150715 break;
14317c478bd9Sstevel@tonic-gate }
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate /*
1434c7e4935fSss150715 * If we were expecting a control message, and the message
1435c7e4935fSss150715 * we received is at least big enough to be a DLPI message,
1436c7e4935fSss150715 * then verify it's a reply to something we sent. If it
1437c7e4935fSss150715 * is a reply to something we sent, also verify its size.
14387c478bd9Sstevel@tonic-gate */
1439c7e4935fSss150715 if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) {
1440c7e4935fSss150715 dlprim = dlreplyp->dlm_msg;
1441c7e4935fSss150715 if (dlprim->dl_primitive == dlreplyprim) {
1442c7e4935fSss150715 if (ctl.len < dlreplyminsz)
1443c7e4935fSss150715 return (DLPI_EBADMSG);
1444c7e4935fSss150715 dlreplyp->dlm_msgsz = ctl.len;
1445c7e4935fSss150715 break;
1446c7e4935fSss150715 } else if (dlprim->dl_primitive == DL_ERROR_ACK) {
1447c7e4935fSss150715 if (ctl.len < DL_ERROR_ACK_SIZE)
1448c7e4935fSss150715 return (DLPI_EBADMSG);
14497c478bd9Sstevel@tonic-gate
1450c7e4935fSss150715 /* Is it ours? */
1451c7e4935fSss150715 if (dlprim->error_ack.dl_error_primitive ==
1452c7e4935fSss150715 dlreqprim)
14537c478bd9Sstevel@tonic-gate break;
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate }
1456c623edd3SGirish Moodalbail update_timer:
1457c7e4935fSss150715 if (!infinite) {
1458*19449258SJosef 'Jeff' Sipek current = NSEC2MSEC(gethrtime());
1459c7e4935fSss150715 msec -= (current - start);
14607c478bd9Sstevel@tonic-gate
1461c7e4935fSss150715 if (msec <= 0)
1462c7e4935fSss150715 return (DLPI_ETIMEDOUT);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate
1466c7e4935fSss150715 return (DLPI_SUCCESS);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate /*
1470c7e4935fSss150715 * Common routine invoked by all DLPI control routines. The inputs for this
1471c7e4935fSss150715 * function are:
1472c7e4935fSss150715 * dlpi_impl_t *dip: internal dlpi handle
1473c7e4935fSss150715 * const dlpi_msg_t *dlreqp: request message structure
1474c7e4935fSss150715 * dlpi_msg_t *dlreplyp: reply message structure
1475c7e4935fSss150715 * size_t dlreplyminsz: minimum size of reply primitive
1476c7e4935fSss150715 * int flags: flags to be set to send a message
1477c7e4935fSss150715 * This routine succeeds if the message is an expected request/acknowledged
14783ab45760Sss150715 * message. However, if DLPI notification has been enabled via
14793ab45760Sss150715 * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling
14803ab45760Sss150715 * expected messages. Otherwise, any other unexpected asynchronous messages will
14813ab45760Sss150715 * be discarded.
14827c478bd9Sstevel@tonic-gate */
14837c478bd9Sstevel@tonic-gate static int
i_dlpi_msg_common(dlpi_impl_t * dip,const dlpi_msg_t * dlreqp,dlpi_msg_t * dlreplyp,size_t dlreplyminsz,int flags)1484c7e4935fSss150715 i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1485c7e4935fSss150715 dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags)
1486c7e4935fSss150715 {
1487c7e4935fSss150715 int retval;
1488c7e4935fSss150715 t_uscalar_t dlreqprim = dlreqp->dlm_msg->dl_primitive;
1489c7e4935fSss150715 t_uscalar_t dlreplyprim = dlreplyp->dlm_msg->dl_primitive;
1490c7e4935fSss150715
1491c7e4935fSss150715 /* Put the requested primitive on the stream. */
14923ab45760Sss150715 retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags);
1493c7e4935fSss150715 if (retval != DLPI_SUCCESS)
1494c7e4935fSss150715 return (retval);
1495c7e4935fSss150715
1496c7e4935fSss150715 /* Retrieve acknowledged message for requested primitive. */
14973ab45760Sss150715 retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC),
1498c7e4935fSss150715 dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL);
1499c7e4935fSss150715 if (retval != DLPI_SUCCESS)
1500c7e4935fSss150715 return (retval);
1501c7e4935fSss150715
1502c7e4935fSss150715 /*
1503c7e4935fSss150715 * If primitive is DL_ERROR_ACK, set errno.
1504c7e4935fSss150715 */
1505c7e4935fSss150715 if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) {
1506c7e4935fSss150715 errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno;
1507c7e4935fSss150715 retval = dlreplyp->dlm_msg->error_ack.dl_errno;
1508c7e4935fSss150715 }
1509c7e4935fSss150715
1510c7e4935fSss150715 return (retval);
1511c7e4935fSss150715 }
1512c7e4935fSss150715
1513c7e4935fSss150715 /*
1514c7e4935fSss150715 * DLPI error codes.
1515c7e4935fSss150715 */
1516c7e4935fSss150715 static const char *dlpi_errlist[] = {
1517c7e4935fSss150715 "bad LSAP selector", /* DL_BADSAP 0x00 */
1518c7e4935fSss150715 "DLSAP address in improper format or invalid", /* DL_BADADDR 0x01 */
1519c7e4935fSss150715 "improper permissions for request", /* DL_ACCESS 0x02 */
1520c7e4935fSss150715 "primitive issued in improper state", /* DL_OUTSTATE 0x03 */
1521c7e4935fSss150715 NULL, /* DL_SYSERR 0x04 */
1522c7e4935fSss150715 "sequence number not from outstanding DL_CONN_IND",
1523c7e4935fSss150715 /* DL_BADCORR 0x05 */
1524c7e4935fSss150715 "user data exceeded provider limit", /* DL_BADDATA 0x06 */
1525c7e4935fSss150715 "requested service not supplied by provider",
1526c7e4935fSss150715 /* DL_UNSUPPORTED 0x07 */
1527c7e4935fSss150715 "specified PPA was invalid", /* DL_BADPPA 0x08 */
1528c7e4935fSss150715 "primitive received not known by provider", /* DL_BADPRIM 0x09 */
1529c7e4935fSss150715 "QoS parameters contained invalid values",
1530c7e4935fSss150715 /* DL_BADQOSPARAM 0x0a */
1531c7e4935fSss150715 "QoS structure type is unknown/unsupported", /* DL_BADQOSTYPE 0x0b */
1532c7e4935fSss150715 "token used not an active stream", /* DL_BADTOKEN 0x0c */
1533c7e4935fSss150715 "attempted second bind with dl_max_conind", /* DL_BOUND 0x0d */
1534c7e4935fSss150715 "physical link initialization failed", /* DL_INITFAILED 0x0e */
1535c7e4935fSss150715 "provider couldn't allocate alternate address", /* DL_NOADDR 0x0f */
1536c7e4935fSss150715 "physical link not initialized", /* DL_NOTINIT 0x10 */
1537c7e4935fSss150715 "previous data unit could not be delivered",
1538c7e4935fSss150715 /* DL_UNDELIVERABLE 0x11 */
1539c7e4935fSss150715 "primitive is known but unsupported",
1540c7e4935fSss150715 /* DL_NOTSUPPORTED 0x12 */
1541c7e4935fSss150715 "limit exceeded", /* DL_TOOMANY 0x13 */
1542c7e4935fSss150715 "promiscuous mode not enabled", /* DL_NOTENAB 0x14 */
1543c7e4935fSss150715 "other streams for PPA in post-attached", /* DL_BUSY 0x15 */
1544c7e4935fSss150715 "automatic handling XID&TEST unsupported", /* DL_NOAUTO 0x16 */
1545c7e4935fSss150715 "automatic handling of XID unsupported", /* DL_NOXIDAUTO 0x17 */
1546c7e4935fSss150715 "automatic handling of TEST unsupported", /* DL_NOTESTAUTO 0x18 */
1547c7e4935fSss150715 "automatic handling of XID response", /* DL_XIDAUTO 0x19 */
1548c7e4935fSss150715 "automatic handling of TEST response", /* DL_TESTAUTO 0x1a */
1549c7e4935fSss150715 "pending outstanding connect indications" /* DL_PENDING 0x1b */
1550c7e4935fSss150715 };
1551c7e4935fSss150715
1552c7e4935fSss150715 /*
1553c7e4935fSss150715 * libdlpi error codes.
1554c7e4935fSss150715 */
1555c7e4935fSss150715 static const char *libdlpi_errlist[] = {
1556c7e4935fSss150715 "DLPI operation succeeded", /* DLPI_SUCCESS */
1557c7e4935fSss150715 "invalid argument", /* DLPI_EINVAL */
1558c7e4935fSss150715 "invalid DLPI linkname", /* DLPI_ELINKNAMEINVAL */
1559c7e4935fSss150715 "DLPI link does not exist", /* DLPI_ENOLINK */
1560c7e4935fSss150715 "bad DLPI link", /* DLPI_EBADLINK */
1561c7e4935fSss150715 "invalid DLPI handle", /* DLPI_EINHANDLE */
1562c7e4935fSss150715 "DLPI operation timed out", /* DLPI_ETIMEDOUT */
1563c7e4935fSss150715 "unsupported DLPI version", /* DLPI_EVERNOTSUP */
1564c7e4935fSss150715 "unsupported DLPI connection mode", /* DLPI_EMODENOTSUP */
1565c7e4935fSss150715 "unavailable DLPI SAP", /* DLPI_EUNAVAILSAP */
1566c7e4935fSss150715 "DLPI operation failed", /* DLPI_FAILURE */
1567c7e4935fSss150715 "DLPI style-2 node reports style-1", /* DLPI_ENOTSTYLE2 */
1568c7e4935fSss150715 "bad DLPI message", /* DLPI_EBADMSG */
15693ab45760Sss150715 "DLPI raw mode not supported", /* DLPI_ERAWNOTSUP */
15703ab45760Sss150715 "DLPI notification not supported by link",
15713ab45760Sss150715 /* DLPI_ENOTENOTSUP */
15723ab45760Sss150715 "invalid DLPI notification type", /* DLPI_ENOTEINVAL */
1573b127ac41SPhilip Kirk "invalid DLPI notification id", /* DLPI_ENOTEIDINVAL */
1574b127ac41SPhilip Kirk "DLPI_IPNETINFO not supported" /* DLPI_EIPNETINFONOTSUP */
1575c7e4935fSss150715 };
1576c7e4935fSss150715
1577c7e4935fSss150715 const char *
dlpi_strerror(int err)1578c7e4935fSss150715 dlpi_strerror(int err)
1579c7e4935fSss150715 {
1580c7e4935fSss150715 if (err == DL_SYSERR)
1581c7e4935fSss150715 return (strerror(errno));
1582c7e4935fSss150715 else if (err >= 0 && err < NELEMS(dlpi_errlist))
1583c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, dlpi_errlist[err]));
15843ab45760Sss150715 else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX)
1585c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err -
1586c7e4935fSss150715 DLPI_SUCCESS]));
1587c7e4935fSss150715 else
1588c7e4935fSss150715 return (dgettext(TEXT_DOMAIN, "Unknown DLPI error"));
1589c7e4935fSss150715 }
1590c7e4935fSss150715
1591c7e4935fSss150715 /*
1592c7e4935fSss150715 * Each table entry comprises a DLPI/Private mactype and the description.
1593c7e4935fSss150715 */
1594c7e4935fSss150715 static const dlpi_mactype_t dlpi_mactypes[] = {
1595c7e4935fSss150715 { DL_CSMACD, "CSMA/CD" },
1596c7e4935fSss150715 { DL_TPB, "Token Bus" },
1597c7e4935fSss150715 { DL_TPR, "Token Ring" },
1598c7e4935fSss150715 { DL_METRO, "Metro Net" },
1599c7e4935fSss150715 { DL_ETHER, "Ethernet" },
1600c7e4935fSss150715 { DL_HDLC, "HDLC" },
1601c7e4935fSss150715 { DL_CHAR, "Sync Character" },
1602c7e4935fSss150715 { DL_CTCA, "CTCA" },
1603c7e4935fSss150715 { DL_FDDI, "FDDI" },
1604c7e4935fSss150715 { DL_FRAME, "Frame Relay (LAPF)" },
1605c7e4935fSss150715 { DL_MPFRAME, "MP Frame Relay" },
1606c7e4935fSss150715 { DL_ASYNC, "Async Character" },
1607c7e4935fSss150715 { DL_IPX25, "X.25 (Classic IP)" },
1608c7e4935fSss150715 { DL_LOOP, "Software Loopback" },
1609c7e4935fSss150715 { DL_FC, "Fiber Channel" },
1610c7e4935fSss150715 { DL_ATM, "ATM" },
1611c7e4935fSss150715 { DL_IPATM, "ATM (Classic IP)" },
1612c7e4935fSss150715 { DL_X25, "X.25 (LAPB)" },
1613c7e4935fSss150715 { DL_ISDN, "ISDN" },
1614c7e4935fSss150715 { DL_HIPPI, "HIPPI" },
1615c7e4935fSss150715 { DL_100VG, "100BaseVG Ethernet" },
1616c7e4935fSss150715 { DL_100VGTPR, "100BaseVG Token Ring" },
1617c7e4935fSss150715 { DL_ETH_CSMA, "Ethernet/IEEE 802.3" },
1618c7e4935fSss150715 { DL_100BT, "100BaseT" },
1619c7e4935fSss150715 { DL_IB, "Infiniband" },
1620c7e4935fSss150715 { DL_IPV4, "IPv4 Tunnel" },
1621c7e4935fSss150715 { DL_IPV6, "IPv6 Tunnel" },
1622b127ac41SPhilip Kirk { DL_WIFI, "IEEE 802.11" },
1623b127ac41SPhilip Kirk { DL_IPNET, "IPNET" }
1624c7e4935fSss150715 };
1625c7e4935fSss150715
1626c7e4935fSss150715 const char *
dlpi_mactype(uint_t mactype)1627c7e4935fSss150715 dlpi_mactype(uint_t mactype)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate int i;
16307c478bd9Sstevel@tonic-gate
1631c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_mactypes); i++) {
1632c7e4935fSss150715 if (dlpi_mactypes[i].dm_mactype == mactype)
1633c7e4935fSss150715 return (dlpi_mactypes[i].dm_desc);
16347c478bd9Sstevel@tonic-gate }
16357c478bd9Sstevel@tonic-gate
1636c7e4935fSss150715 return ("Unknown MAC Type");
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
1639c7e4935fSss150715 /*
1640c7e4935fSss150715 * Each table entry comprises a DLPI primitive and the maximum buffer
1641c7e4935fSss150715 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details).
1642c7e4935fSss150715 */
1643c7e4935fSss150715 static const dlpi_primsz_t dlpi_primsizes[] = {
1644c7e4935fSss150715 { DL_INFO_REQ, DL_INFO_REQ_SIZE },
1645c7e4935fSss150715 { DL_INFO_ACK, DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) +
1646c7e4935fSss150715 DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))},
1647c7e4935fSss150715 { DL_ATTACH_REQ, DL_ATTACH_REQ_SIZE },
1648c7e4935fSss150715 { DL_BIND_REQ, DL_BIND_REQ_SIZE },
1649c7e4935fSss150715 { DL_BIND_ACK, DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX +
1650c7e4935fSss150715 DLPI_SAPLEN_MAX },
1651c7e4935fSss150715 { DL_UNBIND_REQ, DL_UNBIND_REQ_SIZE },
1652c7e4935fSss150715 { DL_ENABMULTI_REQ, DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX },
1653c7e4935fSss150715 { DL_DISABMULTI_REQ, DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX },
1654c7e4935fSss150715 { DL_PROMISCON_REQ, DL_PROMISCON_REQ_SIZE },
1655c7e4935fSss150715 { DL_PROMISCOFF_REQ, DL_PROMISCOFF_REQ_SIZE },
1656c7e4935fSss150715 { DL_PASSIVE_REQ, DL_PASSIVE_REQ_SIZE },
1657c7e4935fSss150715 { DL_UNITDATA_REQ, DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX +
1658c7e4935fSss150715 DLPI_SAPLEN_MAX },
1659c7e4935fSss150715 { DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX +
1660c7e4935fSss150715 DLPI_SAPLEN_MAX)) },
1661c7e4935fSss150715 { DL_PHYS_ADDR_REQ, DL_PHYS_ADDR_REQ_SIZE },
1662c7e4935fSss150715 { DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX },
1663c7e4935fSss150715 { DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX },
16643ab45760Sss150715 { DL_OK_ACK, MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE) },
16653ab45760Sss150715 { DL_NOTIFY_REQ, DL_NOTIFY_REQ_SIZE },
16663ab45760Sss150715 { DL_NOTIFY_ACK, MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE) },
16673ab45760Sss150715 { DL_NOTIFY_IND, DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX +
16683ab45760Sss150715 DLPI_SAPLEN_MAX }
1669c7e4935fSss150715 };
1670c7e4935fSss150715
1671c7e4935fSss150715 /*
1672c7e4935fSss150715 * Refers to the dlpi_primsizes[] table to return corresponding maximum
1673c7e4935fSss150715 * buffer size.
1674c7e4935fSss150715 */
1675c7e4935fSss150715 static size_t
i_dlpi_getprimsize(t_uscalar_t prim)1676c7e4935fSss150715 i_dlpi_getprimsize(t_uscalar_t prim)
1677c7e4935fSss150715 {
1678c7e4935fSss150715 int i;
1679c7e4935fSss150715
1680c7e4935fSss150715 for (i = 0; i < NELEMS(dlpi_primsizes); i++) {
1681c7e4935fSss150715 if (dlpi_primsizes[i].dp_prim == prim)
1682c7e4935fSss150715 return (dlpi_primsizes[i].dp_primsz);
1683c7e4935fSss150715 }
1684c7e4935fSss150715
1685c7e4935fSss150715 return (sizeof (t_uscalar_t));
1686c7e4935fSss150715 }
1687c7e4935fSss150715
1688c7e4935fSss150715 /*
1689c7e4935fSss150715 * sap values vary in length and are in host byte order, build sap value
1690c7e4935fSss150715 * by writing saplen bytes, so that the sap value is left aligned.
1691c7e4935fSss150715 */
1692c7e4935fSss150715 static uint_t
i_dlpi_buildsap(uint8_t * sapp,uint_t saplen)1693c7e4935fSss150715 i_dlpi_buildsap(uint8_t *sapp, uint_t saplen)
1694c7e4935fSss150715 {
1695c7e4935fSss150715 int i;
1696c7e4935fSss150715 uint_t sap = 0;
1697c7e4935fSss150715
1698c7e4935fSss150715 #ifdef _LITTLE_ENDIAN
1699c7e4935fSss150715 for (i = saplen - 1; i >= 0; i--) {
1700c7e4935fSss150715 #else
1701c7e4935fSss150715 for (i = 0; i < saplen; i++) {
1702c7e4935fSss150715 #endif
1703c7e4935fSss150715 sap <<= 8;
1704c7e4935fSss150715 sap |= sapp[i];
1705c7e4935fSss150715 }
1706c7e4935fSss150715
1707c7e4935fSss150715 return (sap);
1708c7e4935fSss150715 }
1709c7e4935fSss150715
1710c7e4935fSss150715 /*
1711c7e4935fSss150715 * Copy sap value to a buffer in host byte order. saplen is the number of
1712c7e4935fSss150715 * bytes to copy.
1713c7e4935fSss150715 */
1714c7e4935fSss150715 static void
1715c7e4935fSss150715 i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen)
1716c7e4935fSss150715 {
1717c7e4935fSss150715 uint8_t *sapp;
1718c7e4935fSss150715
1719c7e4935fSss150715 #ifdef _LITTLE_ENDIAN
1720c7e4935fSss150715 sapp = (uint8_t *)&sap;
1721c7e4935fSss150715 #else
1722c7e4935fSss150715 sapp = (uint8_t *)&sap + (sizeof (sap) - saplen);
1723c7e4935fSss150715 #endif
1724c7e4935fSss150715
1725c7e4935fSss150715 (void) memcpy(dstbuf, sapp, saplen);
17267c478bd9Sstevel@tonic-gate }
17273ab45760Sss150715
17283ab45760Sss150715 /*
17293ab45760Sss150715 * Fill notification payload and callback each registered functions.
17303ab45760Sss150715 * Delete nodes if any was called while processing.
17313ab45760Sss150715 */
17323ab45760Sss150715 static int
17333ab45760Sss150715 i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp)
17343ab45760Sss150715 {
17353ab45760Sss150715 dlpi_notifyinfo_t notifinfo;
17363ab45760Sss150715 t_uscalar_t dataoff, datalen;
17373ab45760Sss150715 caddr_t datap;
17383ab45760Sss150715 dlpi_notifyent_t *dnp;
17393ab45760Sss150715 uint_t note = dlnotifyindp->dl_notification;
17403ab45760Sss150715 uint_t deletenode = B_FALSE;
17413ab45760Sss150715
17423ab45760Sss150715 notifinfo.dni_note = note;
17433ab45760Sss150715
17443ab45760Sss150715 switch (note) {
17453ab45760Sss150715 case DL_NOTE_SPEED:
17463ab45760Sss150715 notifinfo.dni_speed = dlnotifyindp->dl_data;
17473ab45760Sss150715 break;
17483ab45760Sss150715 case DL_NOTE_SDU_SIZE:
17493ab45760Sss150715 notifinfo.dni_size = dlnotifyindp->dl_data;
17503ab45760Sss150715 break;
17513ab45760Sss150715 case DL_NOTE_PHYS_ADDR:
17522b24ab6bSSebastien Roy /*
17532b24ab6bSSebastien Roy * libdlpi currently only supports notifications for
17542b24ab6bSSebastien Roy * DL_CURR_PHYS_ADDR.
17552b24ab6bSSebastien Roy */
17562b24ab6bSSebastien Roy if (dlnotifyindp->dl_data != DL_CURR_PHYS_ADDR)
17572b24ab6bSSebastien Roy return (DLPI_ENOTENOTSUP);
17582b24ab6bSSebastien Roy
17593ab45760Sss150715 dataoff = dlnotifyindp->dl_addr_offset;
17603ab45760Sss150715 datalen = dlnotifyindp->dl_addr_length;
17613ab45760Sss150715
17623ab45760Sss150715 if (dataoff == 0 || datalen == 0)
17633ab45760Sss150715 return (DLPI_EBADMSG);
17643ab45760Sss150715
17653ab45760Sss150715 datap = (caddr_t)dlnotifyindp + dataoff;
17663ab45760Sss150715 if (dataoff < DL_NOTIFY_IND_SIZE)
17673ab45760Sss150715 return (DLPI_EBADMSG);
17683ab45760Sss150715
17693ab45760Sss150715 notifinfo.dni_physaddrlen = datalen - dip->dli_saplen;
17703ab45760Sss150715
17713ab45760Sss150715 if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX)
17723ab45760Sss150715 return (DL_BADADDR);
17733ab45760Sss150715
17743ab45760Sss150715 (void) memcpy(notifinfo.dni_physaddr, datap,
17753ab45760Sss150715 notifinfo.dni_physaddrlen);
17763ab45760Sss150715 break;
17773ab45760Sss150715 }
17783ab45760Sss150715
17793ab45760Sss150715 dip->dli_note_processing = B_TRUE;
17803ab45760Sss150715
17813ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
17823ab45760Sss150715 if (note & dnp->dln_notes)
17833ab45760Sss150715 dnp->dln_fnp((dlpi_handle_t)dip, ¬ifinfo, dnp->arg);
17843ab45760Sss150715 if (dnp->dln_rm)
17853ab45760Sss150715 deletenode = B_TRUE;
17863ab45760Sss150715 }
17873ab45760Sss150715
17883ab45760Sss150715 dip->dli_note_processing = B_FALSE;
17893ab45760Sss150715
17903ab45760Sss150715 /* Walk the notifyentry list to unregister marked entries. */
17913ab45760Sss150715 if (deletenode)
17923ab45760Sss150715 i_dlpi_deletenotifyid(dip);
17933ab45760Sss150715
17943ab45760Sss150715 return (DLPI_SUCCESS);
17953ab45760Sss150715 }
17963ab45760Sss150715 /*
17973ab45760Sss150715 * Find registered notification.
17983ab45760Sss150715 */
17993ab45760Sss150715 static boolean_t
18003ab45760Sss150715 i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id)
18013ab45760Sss150715 {
18023ab45760Sss150715 dlpi_notifyent_t *dnp;
18033ab45760Sss150715
18043ab45760Sss150715 for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
18053ab45760Sss150715 if (id == dnp)
18063ab45760Sss150715 return (B_TRUE);
18073ab45760Sss150715 }
18083ab45760Sss150715
18093ab45760Sss150715 return (B_FALSE);
18103ab45760Sss150715 }
18113ab45760Sss150715
18123ab45760Sss150715 /*
18133ab45760Sss150715 * Walk the list of notifications and deleted nodes marked to be deleted.
18143ab45760Sss150715 */
18153ab45760Sss150715 static void
18163ab45760Sss150715 i_dlpi_deletenotifyid(dlpi_impl_t *dip)
18173ab45760Sss150715 {
18183ab45760Sss150715 dlpi_notifyent_t *prev, *dnp;
18193ab45760Sss150715
18203ab45760Sss150715 prev = NULL;
18213ab45760Sss150715 dnp = dip->dli_notifylistp;
18223ab45760Sss150715 while (dnp != NULL) {
18233ab45760Sss150715 if (!dnp->dln_rm) {
18243ab45760Sss150715 prev = dnp;
18253ab45760Sss150715 dnp = dnp->dln_next;
18263ab45760Sss150715 } else if (prev == NULL) {
18273ab45760Sss150715 dip->dli_notifylistp = dnp->dln_next;
18283ab45760Sss150715 free(dnp);
18293ab45760Sss150715 dnp = dip->dli_notifylistp;
18303ab45760Sss150715 } else {
18313ab45760Sss150715 prev->dln_next = dnp->dln_next;
18323ab45760Sss150715 free(dnp);
18333ab45760Sss150715 dnp = prev->dln_next;
18343ab45760Sss150715 }
18353ab45760Sss150715 }
18363ab45760Sss150715 }
1837