1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * Data-Link Provider Interface (Version 2)
28 */
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <poll.h>
37#include <stropts.h>
38#include <sys/dlpi.h>
39#include <errno.h>
40#include <alloca.h>
41#include <sys/sysmacros.h>
42#include <ctype.h>
43#include <net/if_types.h>
44#include <netinet/arp.h>
45#include <libdladm.h>
46#include <libdllink.h>
47#include <libdlpi.h>
48#include <libintl.h>
49#include <libinetutil.h>
50#include <dirent.h>
51
52#include "libdlpi_impl.h"
53
54static int i_dlpi_open(const char *, int *, uint_t, boolean_t);
55static int i_dlpi_style1_open(dlpi_impl_t *);
56static int i_dlpi_style2_open(dlpi_impl_t *);
57static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t);
58static int i_dlpi_attach(dlpi_impl_t *);
59static void i_dlpi_passive(dlpi_impl_t *);
60
61static int i_dlpi_strputmsg(dlpi_impl_t *, const dlpi_msg_t *, const void *,
62    size_t, int);
63static int i_dlpi_strgetmsg(dlpi_impl_t *, int, dlpi_msg_t *, t_uscalar_t,
64    t_uscalar_t, size_t, void *, size_t *, size_t *);
65static int i_dlpi_msg_common(dlpi_impl_t *, const dlpi_msg_t *, dlpi_msg_t *,
66    size_t, int);
67
68static size_t i_dlpi_getprimsize(t_uscalar_t);
69static int i_dlpi_multi(dlpi_handle_t, t_uscalar_t, const uint8_t *, size_t);
70static int i_dlpi_promisc(dlpi_handle_t, t_uscalar_t, uint_t);
71static uint_t i_dlpi_buildsap(uint8_t *, uint_t);
72static void i_dlpi_writesap(void *, uint_t, uint_t);
73static int i_dlpi_notifyind_process(dlpi_impl_t *, dl_notify_ind_t *);
74static boolean_t i_dlpi_notifyidexists(dlpi_impl_t *, dlpi_notifyent_t *);
75static void i_dlpi_deletenotifyid(dlpi_impl_t *);
76
77struct i_dlpi_walklink_arg {
78	dlpi_walkfunc_t *fn;
79	void *arg;
80};
81
82static int
83i_dlpi_walk_link(const char *name, void *arg)
84{
85	struct i_dlpi_walklink_arg *warg = arg;
86
87	return ((warg->fn(name, warg->arg)) ? DLADM_WALK_TERMINATE :
88	    DLADM_WALK_CONTINUE);
89}
90
91/*ARGSUSED*/
92void
93dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags)
94{
95	struct i_dlpi_walklink_arg warg;
96	struct dirent *d;
97	DIR *dp;
98	dladm_handle_t handle;
99
100	warg.fn = fn;
101	warg.arg = arg;
102
103	if (flags & DLPI_DEVIPNET) {
104		if ((dp = opendir("/dev/ipnet")) == NULL)
105			return;
106
107		while ((d = readdir(dp)) != NULL) {
108			if (d->d_name[0] == '.')
109				continue;
110
111			if (warg.fn(d->d_name, warg.arg))
112				break;
113		}
114
115		(void) closedir(dp);
116	} else {
117		/*
118		 * Rather than have libdlpi take the libdladm handle,
119		 * open the handle here.
120		 */
121		if (dladm_open(&handle) != DLADM_STATUS_OK)
122			return;
123
124		(void) dladm_walk(i_dlpi_walk_link, handle, &warg,
125		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
126		    DLADM_OPT_ACTIVE);
127
128		dladm_close(handle);
129	}
130}
131
132int
133dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
134{
135	int		retval, on = 1;
136	ifspec_t	ifsp;
137	dlpi_impl_t  	*dip;
138
139	/*
140	 * Validate linkname, fail if logical unit number (lun) is specified,
141	 * otherwise decompose the contents into ifsp.
142	 */
143	if (linkname == NULL || (strchr(linkname, ':') != NULL) ||
144	    !ifparse_ifspec(linkname, &ifsp))
145		return (DLPI_ELINKNAMEINVAL);
146
147	/*
148	 * Ensure flags values are sane.
149	 */
150	if ((flags & (DLPI_DEVIPNET|DLPI_DEVONLY)) ==
151	    (DLPI_DEVIPNET|DLPI_DEVONLY))
152		return (DLPI_EINVAL);
153
154	/* Allocate a new dlpi_impl_t. */
155	if ((dip = calloc(1, sizeof (dlpi_impl_t))) == NULL)
156		return (DL_SYSERR);
157
158	/* Fill in known/default libdlpi handle values. */
159	dip->dli_timeout = DLPI_DEF_TIMEOUT;
160	dip->dli_ppa = ifsp.ifsp_ppa;
161	dip->dli_oflags = flags;
162	dip->dli_notifylistp = NULL;
163	dip->dli_note_processing = B_FALSE;
164	if (getenv("DLPI_DEVONLY") != NULL)
165		dip->dli_oflags |= DLPI_DEVONLY;
166
167	/* Copy linkname provided to the function. */
168	if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >=
169	    sizeof (dip->dli_linkname)) {
170		free(dip);
171		return (DLPI_ELINKNAMEINVAL);
172	}
173
174	/* Copy provider name. */
175	(void) strlcpy(dip->dli_provider, ifsp.ifsp_devnm,
176	    sizeof (dip->dli_provider));
177
178	/*
179	 * Special case: DLPI_SERIAL flag is set to indicate a synchronous
180	 * serial line interface (see syncinit(1M), syncstat(1M),
181	 * syncloop(1M)), which is not a DLPI link.
182	 */
183	if (dip->dli_oflags & DLPI_SERIAL) {
184		if ((retval = i_dlpi_style2_open(dip)) != DLPI_SUCCESS) {
185			free(dip);
186			return (retval);
187		}
188
189		*dhp = (dlpi_handle_t)dip;
190		return (retval);
191	}
192
193	if ((retval = i_dlpi_style1_open(dip)) != DLPI_SUCCESS) {
194		if (retval == DLPI_ENOTSTYLE2) {
195			/*
196			 * The error code indicates not to continue the
197			 * style-2 open. Change the error code back to
198			 * DL_SYSERR, so that one would know the cause
199			 * of failure from errno.
200			 */
201			retval = DL_SYSERR;
202		} else if (!(dip->dli_oflags & DLPI_DEVIPNET)) {
203			retval = i_dlpi_style2_open(dip);
204		}
205		if (retval != DLPI_SUCCESS) {
206			free(dip);
207			return (retval);
208		}
209	}
210
211	if (dip->dli_oflags & DLPI_PASSIVE)
212		i_dlpi_passive(dip);
213
214	if ((dip->dli_oflags & DLPI_RAW) &&
215	    ioctl(dip->dli_fd, DLIOCRAW, 0) < 0) {
216		dlpi_close((dlpi_handle_t)dip);
217		return (DLPI_ERAWNOTSUP);
218	}
219
220	if ((dip->dli_oflags & DLPI_IPNETINFO) &&
221	    ioctl(dip->dli_fd, DLIOCIPNETINFO, &on) < 0) {
222		dlpi_close((dlpi_handle_t)dip);
223		return (DLPI_EIPNETINFONOTSUP);
224	}
225
226	/*
227	 * We intentionally do not care if this request fails, as this
228	 * indicates the underlying DLPI device does not support Native mode
229	 * (pre-GLDV3 device drivers).
230	 */
231	if (dip->dli_oflags & DLPI_NATIVE) {
232		if ((retval = ioctl(dip->dli_fd, DLIOCNATIVE, 0)) > 0)
233			dip->dli_mactype = retval;
234	}
235
236	*dhp = (dlpi_handle_t)dip;
237	return (DLPI_SUCCESS);
238}
239
240void
241dlpi_close(dlpi_handle_t dh)
242{
243	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
244	dlpi_notifyent_t *next, *dnp;
245
246	if (dip != NULL) {
247		for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = next) {
248			next = dnp->dln_next;
249			free(dnp);
250		}
251
252		(void) close(dip->dli_fd);
253		free(dip);
254	}
255}
256
257/*
258 * NOTE: The opt argument must be zero and is reserved for future use to extend
259 * fields to the dlpi_info_t structure (see dlpi_info(3DLPI)).
260 */
261int
262dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt)
263{
264	int 		retval;
265	dlpi_msg_t	req, ack;
266	dl_info_ack_t	*infoackp;
267	uint8_t		*sapp, *addrp;
268	caddr_t		ackendp, datap;
269	t_uscalar_t	dataoff, datalen;
270	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
271
272	if (dip == NULL)
273		return (DLPI_EINHANDLE);
274
275	if (infop == NULL || opt != 0)
276		return (DLPI_EINVAL);
277
278	(void) memset(infop, 0, sizeof (dlpi_info_t));
279
280	/* Set QoS range parameters to default unsupported value. */
281	infop->di_qos_range.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
282	infop->di_qos_range.dl_trans_delay.dl_target_value = DL_UNKNOWN;
283	infop->di_qos_range.dl_trans_delay.dl_accept_value = DL_UNKNOWN;
284	infop->di_qos_range.dl_priority.dl_min = DL_UNKNOWN;
285	infop->di_qos_range.dl_priority.dl_max = DL_UNKNOWN;
286	infop->di_qos_range.dl_protection.dl_min = DL_UNKNOWN;
287	infop->di_qos_range.dl_protection.dl_max = DL_UNKNOWN;
288	infop->di_qos_range.dl_residual_error = DL_UNKNOWN;
289
290	/* Set QoS parameters to default unsupported value. */
291	infop->di_qos_sel.dl_qos_type = (t_uscalar_t)DL_UNKNOWN;
292	infop->di_qos_sel.dl_trans_delay = DL_UNKNOWN;
293	infop->di_qos_sel.dl_priority = DL_UNKNOWN;
294	infop->di_qos_sel.dl_protection = DL_UNKNOWN;
295	infop->di_qos_sel.dl_residual_error = DL_UNKNOWN;
296
297	DLPI_MSG_CREATE(req, DL_INFO_REQ);
298	DLPI_MSG_CREATE(ack, DL_INFO_ACK);
299
300	retval = i_dlpi_msg_common(dip, &req, &ack, DL_INFO_ACK_SIZE, RS_HIPRI);
301	if (retval != DLPI_SUCCESS)
302		return (retval);
303
304	infoackp = &(ack.dlm_msg->info_ack);
305	if (infoackp->dl_version != DL_VERSION_2)
306		return (DLPI_EVERNOTSUP);
307
308	if (infoackp->dl_service_mode != DL_CLDLS)
309		return (DLPI_EMODENOTSUP);
310
311	dip->dli_style = infoackp->dl_provider_style;
312	dip->dli_mactype = infoackp->dl_mac_type;
313
314	ackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
315
316	/* Check and save QoS selection information, if any. */
317	datalen = infoackp->dl_qos_length;
318	dataoff = infoackp->dl_qos_offset;
319	if (dataoff != 0 && datalen != 0) {
320		datap = (caddr_t)infoackp + dataoff;
321		if (datalen > sizeof (dl_qos_cl_sel1_t) ||
322		    dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
323			return (DLPI_EBADMSG);
324
325		(void) memcpy(&infop->di_qos_sel, datap, datalen);
326		if (infop->di_qos_sel.dl_qos_type != DL_QOS_CL_SEL1)
327			return (DLPI_EMODENOTSUP);
328	}
329
330	/* Check and save QoS range information, if any. */
331	datalen = infoackp->dl_qos_range_length;
332	dataoff = infoackp->dl_qos_range_offset;
333	if (dataoff != 0 && datalen != 0) {
334		datap = (caddr_t)infoackp + dataoff;
335		if (datalen > sizeof (dl_qos_cl_range1_t) ||
336		    dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
337			return (DLPI_EBADMSG);
338
339		(void) memcpy(&infop->di_qos_range, datap, datalen);
340		if (infop->di_qos_range.dl_qos_type != DL_QOS_CL_RANGE1)
341			return (DLPI_EMODENOTSUP);
342	}
343
344	/* Check and save physical address and SAP information. */
345	dip->dli_saplen = abs(infoackp->dl_sap_length);
346	dip->dli_sapbefore = (infoackp->dl_sap_length > 0);
347	infop->di_physaddrlen = infoackp->dl_addr_length - dip->dli_saplen;
348
349	if (infop->di_physaddrlen > DLPI_PHYSADDR_MAX ||
350	    dip->dli_saplen > DLPI_SAPLEN_MAX)
351		return (DL_BADADDR);
352
353	dataoff = infoackp->dl_addr_offset;
354	datalen = infoackp->dl_addr_length;
355	if (dataoff != 0 && datalen != 0) {
356		datap = (caddr_t)infoackp + dataoff;
357		if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
358			return (DLPI_EBADMSG);
359
360		sapp = addrp = (uint8_t *)datap;
361		if (dip->dli_sapbefore)
362			addrp += dip->dli_saplen;
363		else
364			sapp += infop->di_physaddrlen;
365
366		(void) memcpy(infop->di_physaddr, addrp, infop->di_physaddrlen);
367		infop->di_sap = i_dlpi_buildsap(sapp, dip->dli_saplen);
368	}
369
370	/* Check and save broadcast address information, if any. */
371	datalen = infoackp->dl_brdcst_addr_length;
372	dataoff = infoackp->dl_brdcst_addr_offset;
373	if (dataoff != 0 && datalen != 0) {
374		datap = (caddr_t)infoackp + dataoff;
375		if (dataoff < DL_INFO_ACK_SIZE || datap + datalen > ackendp)
376			return (DLPI_EBADMSG);
377		if (datalen != infop->di_physaddrlen)
378			return (DL_BADADDR);
379
380		infop->di_bcastaddrlen = datalen;
381		(void) memcpy(infop->di_bcastaddr, datap, datalen);
382	}
383
384	infop->di_max_sdu = infoackp->dl_max_sdu;
385	infop->di_min_sdu = infoackp->dl_min_sdu;
386	infop->di_state = infoackp->dl_current_state;
387	infop->di_mactype = infoackp->dl_mac_type;
388
389	/* Information retrieved from the handle. */
390	(void) strlcpy(infop->di_linkname, dip->dli_linkname,
391	    sizeof (infop->di_linkname));
392	infop->di_timeout = dip->dli_timeout;
393
394	return (DLPI_SUCCESS);
395}
396
397/*
398 * This function parses 'linkname' and stores the 'provider' name and 'PPA'.
399 */
400int
401dlpi_parselink(const char *linkname, char *provider, uint_t *ppa)
402{
403	dladm_status_t status;
404
405	status = dladm_parselink(linkname, provider, ppa);
406
407	if (status != DLADM_STATUS_OK)
408		return (DLPI_ELINKNAMEINVAL);
409
410	return (DLPI_SUCCESS);
411}
412
413/*
414 * This function takes a provider name and a PPA and stores a full linkname
415 * as 'linkname'. If 'provider' already is a full linkname 'provider' name
416 * is stored in 'linkname'.
417 */
418int
419dlpi_makelink(char *linkname, const char *provider, uint_t ppa)
420{
421	int provlen = strlen(provider);
422
423	if (linkname == NULL || provlen == 0 || provlen >= DLPI_LINKNAME_MAX)
424		return (DLPI_ELINKNAMEINVAL);
425
426	if (!isdigit(provider[provlen - 1])) {
427		(void) snprintf(linkname, DLPI_LINKNAME_MAX, "%s%d", provider,
428		    ppa);
429	} else {
430		(void) strlcpy(linkname, provider, DLPI_LINKNAME_MAX);
431	}
432
433	return (DLPI_SUCCESS);
434}
435
436int
437dlpi_bind(dlpi_handle_t dh, uint_t sap, uint_t *boundsap)
438{
439	int		retval;
440	dlpi_msg_t	req, ack;
441	dl_bind_req_t	*bindreqp;
442	dl_bind_ack_t	*bindackp;
443	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
444
445	if (dip == NULL)
446		return (DLPI_EINHANDLE);
447
448	DLPI_MSG_CREATE(req, DL_BIND_REQ);
449	DLPI_MSG_CREATE(ack, DL_BIND_ACK);
450	bindreqp = &(req.dlm_msg->bind_req);
451
452	/*
453	 * If 'sap' is DLPI_ANY_SAP, bind to SAP 2 on token ring, else 0 on
454	 * other interface types (SAP 0 has special significance on token ring).
455	 */
456	if (sap == DLPI_ANY_SAP)
457		bindreqp->dl_sap = ((dip->dli_mactype == DL_TPR) ? 2 : 0);
458	else
459		bindreqp->dl_sap = sap;
460
461	bindreqp->dl_service_mode = DL_CLDLS;
462	bindreqp->dl_conn_mgmt = 0;
463	bindreqp->dl_max_conind = 0;
464	bindreqp->dl_xidtest_flg = 0;
465
466	retval = i_dlpi_msg_common(dip, &req, &ack, DL_BIND_ACK_SIZE, 0);
467	if (retval != DLPI_SUCCESS)
468		return (retval);
469
470	bindackp = &(ack.dlm_msg->bind_ack);
471	/*
472	 * Received a DLPI_BIND_ACK, now verify that the bound SAP
473	 * is equal to the SAP requested. Some DLPI MAC type may bind
474	 * to a different SAP than requested, in this case 'boundsap'
475	 * returns the actual bound SAP. For the case where 'boundsap'
476	 * is NULL and 'sap' is not DLPI_ANY_SAP, dlpi_bind fails.
477	 */
478	if (boundsap != NULL) {
479		*boundsap = bindackp->dl_sap;
480	} else if (sap != DLPI_ANY_SAP && bindackp->dl_sap != sap) {
481		if (dlpi_unbind(dh) != DLPI_SUCCESS)
482			return (DLPI_FAILURE);
483		else
484			return (DLPI_EUNAVAILSAP);
485	}
486
487	dip->dli_sap = bindackp->dl_sap;	/* save sap value in handle */
488	return (DLPI_SUCCESS);
489}
490
491int
492dlpi_unbind(dlpi_handle_t dh)
493{
494	dlpi_msg_t	req, ack;
495	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
496
497	if (dip == NULL)
498		return (DLPI_EINHANDLE);
499
500	DLPI_MSG_CREATE(req, DL_UNBIND_REQ);
501	DLPI_MSG_CREATE(ack, DL_OK_ACK);
502
503	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
504}
505
506/*
507 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and
508 * based on the "op" value, multicast address is enabled/disabled.
509 */
510static int
511i_dlpi_multi(dlpi_handle_t dh, t_uscalar_t op, const uint8_t *addrp,
512    size_t addrlen)
513{
514	dlpi_msg_t		req, ack;
515	dl_enabmulti_req_t	*multireqp;
516	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
517
518	if (dip == NULL)
519		return (DLPI_EINHANDLE);
520
521	if (addrlen > DLPI_PHYSADDR_MAX)
522		return (DLPI_EINVAL);
523
524	DLPI_MSG_CREATE(req, op);
525	DLPI_MSG_CREATE(ack, DL_OK_ACK);
526
527	multireqp = &(req.dlm_msg->enabmulti_req);
528	multireqp->dl_addr_length = addrlen;
529	multireqp->dl_addr_offset = sizeof (dl_enabmulti_req_t);
530	(void) memcpy(&multireqp[1], addrp, addrlen);
531
532	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
533}
534
535int
536dlpi_enabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
537{
538	return (i_dlpi_multi(dh, DL_ENABMULTI_REQ, addrp, addrlen));
539}
540
541int
542dlpi_disabmulti(dlpi_handle_t dh, const void *addrp, size_t addrlen)
543{
544	return (i_dlpi_multi(dh, DL_DISABMULTI_REQ, addrp, addrlen));
545}
546
547/*
548 * This function is invoked by dlpi_promiscon() or dlpi_promiscoff(). Based
549 * on the value of 'op', promiscuous mode is turned on/off at the specified
550 * 'level'.
551 */
552static int
553i_dlpi_promisc(dlpi_handle_t dh, t_uscalar_t op, uint_t level)
554{
555	dlpi_msg_t		req, ack;
556	dl_promiscon_req_t	*promiscreqp;
557	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
558
559	if (dip == NULL)
560		return (DLPI_EINHANDLE);
561
562	DLPI_MSG_CREATE(req, op);
563	DLPI_MSG_CREATE(ack, DL_OK_ACK);
564
565	promiscreqp = &(req.dlm_msg->promiscon_req);
566	promiscreqp->dl_level = level;
567
568	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
569}
570
571int
572dlpi_promiscon(dlpi_handle_t dh, uint_t level)
573{
574	return (i_dlpi_promisc(dh, DL_PROMISCON_REQ, level));
575}
576
577int
578dlpi_promiscoff(dlpi_handle_t dh, uint_t level)
579{
580	return (i_dlpi_promisc(dh, DL_PROMISCOFF_REQ, level));
581}
582
583int
584dlpi_get_physaddr(dlpi_handle_t dh, uint_t type, void *addrp, size_t *addrlenp)
585{
586	int			retval;
587	dlpi_msg_t  		req, ack;
588	dl_phys_addr_req_t	*physreqp;
589	dl_phys_addr_ack_t	*physackp;
590	t_uscalar_t		dataoff, datalen;
591	caddr_t			datap, physackendp;
592	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
593
594	if (dip == NULL)
595		return (DLPI_EINHANDLE);
596
597	if (addrlenp == NULL || addrp == NULL || *addrlenp < DLPI_PHYSADDR_MAX)
598		return (DLPI_EINVAL);
599
600	DLPI_MSG_CREATE(req, DL_PHYS_ADDR_REQ);
601	DLPI_MSG_CREATE(ack, DL_PHYS_ADDR_ACK);
602
603	physreqp = &(req.dlm_msg->physaddr_req);
604	physreqp->dl_addr_type = type;
605
606	retval = i_dlpi_msg_common(dip, &req, &ack, DL_PHYS_ADDR_ACK_SIZE, 0);
607	if (retval != DLPI_SUCCESS)
608		return (retval);
609
610	/* Received DL_PHYS_ADDR_ACK, store the physical address and length. */
611	physackp = &(ack.dlm_msg->physaddr_ack);
612	physackendp = (caddr_t)ack.dlm_msg + ack.dlm_msgsz;
613	dataoff = physackp->dl_addr_offset;
614	datalen = physackp->dl_addr_length;
615	if (dataoff != 0 && datalen != 0) {
616		datap = (caddr_t)physackp + dataoff;
617		if (datalen > DLPI_PHYSADDR_MAX)
618			return (DL_BADADDR);
619		if (dataoff < DL_PHYS_ADDR_ACK_SIZE ||
620		    datap + datalen > physackendp)
621			return (DLPI_EBADMSG);
622
623		*addrlenp = physackp->dl_addr_length;
624		(void) memcpy(addrp, datap, datalen);
625	} else {
626		*addrlenp = datalen;
627	}
628
629	return (DLPI_SUCCESS);
630}
631
632int
633dlpi_set_physaddr(dlpi_handle_t dh, uint_t type, const void *addrp,
634    size_t addrlen)
635{
636	dlpi_msg_t  		req, ack;
637	dl_set_phys_addr_req_t	*setphysreqp;
638	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
639
640	if (dip == NULL)
641		return (DLPI_EINHANDLE);
642
643	if (addrp == NULL || type != DL_CURR_PHYS_ADDR ||
644	    addrlen > DLPI_PHYSADDR_MAX)
645		return (DLPI_EINVAL);
646
647	DLPI_MSG_CREATE(req, DL_SET_PHYS_ADDR_REQ);
648	DLPI_MSG_CREATE(ack, DL_OK_ACK);
649
650	setphysreqp = &(req.dlm_msg->set_physaddr_req);
651	setphysreqp->dl_addr_length = addrlen;
652	setphysreqp->dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
653	(void) memcpy(&setphysreqp[1], addrp, addrlen);
654
655	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
656}
657
658int
659dlpi_send(dlpi_handle_t dh, const void *daddrp, size_t daddrlen,
660    const void *msgbuf, size_t msglen, const dlpi_sendinfo_t *sendp)
661{
662	dlpi_msg_t		req;
663	dl_unitdata_req_t	*udatareqp;
664	uint_t			sap;
665	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
666
667	if (dip == NULL)
668		return (DLPI_EINHANDLE);
669
670	if (dip->dli_oflags & DLPI_RAW)
671		return (i_dlpi_strputmsg(dip, NULL, msgbuf, msglen, 0));
672
673	if ((daddrlen > 0 && daddrp == NULL) || daddrlen > DLPI_PHYSADDR_MAX)
674		return (DLPI_EINVAL);
675
676	DLPI_MSG_CREATE(req, DL_UNITDATA_REQ);
677	udatareqp = &(req.dlm_msg->unitdata_req);
678
679	/* Set priority to default priority range. */
680	udatareqp->dl_priority.dl_min = 0;
681	udatareqp->dl_priority.dl_max = 0;
682
683	/* Use SAP value if specified otherwise use bound SAP value. */
684	if (sendp != NULL) {
685		sap = sendp->dsi_sap;
686		if (sendp->dsi_prio.dl_min != DL_QOS_DONT_CARE)
687			udatareqp->dl_priority.dl_min = sendp->dsi_prio.dl_min;
688		if (sendp->dsi_prio.dl_max != DL_QOS_DONT_CARE)
689			udatareqp->dl_priority.dl_max = sendp->dsi_prio.dl_max;
690	} else {
691		sap = dip->dli_sap;
692	}
693
694	udatareqp->dl_dest_addr_length = daddrlen + dip->dli_saplen;
695	udatareqp->dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
696
697	/*
698	 * Since `daddrp' only has the link-layer destination address,
699	 * we must prepend or append the SAP (according to dli_sapbefore)
700	 * to make a full DLPI address.
701	 */
702	if (dip->dli_sapbefore) {
703		i_dlpi_writesap(&udatareqp[1], sap, dip->dli_saplen);
704		(void) memcpy((caddr_t)&udatareqp[1] + dip->dli_saplen,
705		    daddrp, daddrlen);
706	} else {
707		(void) memcpy(&udatareqp[1], daddrp, daddrlen);
708		i_dlpi_writesap((caddr_t)&udatareqp[1] + daddrlen, sap,
709		    dip->dli_saplen);
710	}
711
712	return (i_dlpi_strputmsg(dip, &req, msgbuf, msglen, 0));
713}
714
715int
716dlpi_recv(dlpi_handle_t dh, void *saddrp, size_t *saddrlenp, void *msgbuf,
717    size_t *msglenp, int msec, dlpi_recvinfo_t *recvp)
718{
719	int			retval;
720	dlpi_msg_t		ind;
721	size_t			totmsglen;
722	dl_unitdata_ind_t	*udatap;
723	t_uscalar_t		dataoff, datalen;
724	caddr_t			datap, indendp;
725	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
726
727	if (dip == NULL)
728		return (DLPI_EINHANDLE);
729	/*
730	 * If handle is in raw mode ignore everything except total message
731	 * length.
732	 */
733	if (dip->dli_oflags & DLPI_RAW) {
734		retval = i_dlpi_strgetmsg(dip, msec, NULL, 0, 0, 0, msgbuf,
735		    msglenp, &totmsglen);
736
737		if (retval == DLPI_SUCCESS && recvp != NULL)
738			recvp->dri_totmsglen = totmsglen;
739		return (retval);
740	}
741
742	DLPI_MSG_CREATE(ind, DL_UNITDATA_IND);
743	udatap = &(ind.dlm_msg->unitdata_ind);
744	indendp = (caddr_t)ind.dlm_msg + ind.dlm_msgsz;
745
746	if ((retval = i_dlpi_strgetmsg(dip, msec, &ind, DL_UNITDATA_IND,
747	    DL_UNITDATA_IND, DL_UNITDATA_IND_SIZE, msgbuf,
748	    msglenp, &totmsglen)) != DLPI_SUCCESS)
749		return (retval);
750
751	/*
752	 * If DLPI link provides source address, store source address in
753	 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0.
754	 */
755	if (saddrp != NULL && saddrlenp != NULL)  {
756		if (*saddrlenp < DLPI_PHYSADDR_MAX)
757			return (DLPI_EINVAL);
758
759		dataoff = udatap->dl_src_addr_offset;
760		datalen = udatap->dl_src_addr_length;
761		if (dataoff != 0 && datalen != 0) {
762			datap = (caddr_t)udatap + dataoff;
763			if (dataoff < DL_UNITDATA_IND_SIZE ||
764			    datap + datalen > indendp)
765				return (DLPI_EBADMSG);
766
767			*saddrlenp = datalen - dip->dli_saplen;
768			if (*saddrlenp > DLPI_PHYSADDR_MAX)
769				return (DL_BADADDR);
770
771			if (dip->dli_sapbefore)
772				datap += dip->dli_saplen;
773			(void) memcpy(saddrp, datap, *saddrlenp);
774		} else {
775			*saddrlenp = 0;
776		}
777	}
778
779	/*
780	 * If destination address requested, check and save destination
781	 * address, if any.
782	 */
783	if (recvp != NULL) {
784		dataoff = udatap->dl_dest_addr_offset;
785		datalen = udatap->dl_dest_addr_length;
786		if (dataoff != 0 && datalen != 0) {
787			datap = (caddr_t)udatap + dataoff;
788			if (dataoff < DL_UNITDATA_IND_SIZE ||
789			    datap + datalen > indendp)
790				return (DLPI_EBADMSG);
791
792			recvp->dri_destaddrlen = datalen - dip->dli_saplen;
793			if (recvp->dri_destaddrlen > DLPI_PHYSADDR_MAX)
794				return (DL_BADADDR);
795
796			if (dip->dli_sapbefore)
797				datap += dip->dli_saplen;
798			(void) memcpy(recvp->dri_destaddr, datap,
799			    recvp->dri_destaddrlen);
800		} else {
801			recvp->dri_destaddrlen = 0;
802		}
803
804		recvp->dri_destaddrtype = udatap->dl_group_address;
805		recvp->dri_totmsglen = totmsglen;
806	}
807
808	return (DLPI_SUCCESS);
809}
810
811int
812dlpi_enabnotify(dlpi_handle_t dh, uint_t notes, dlpi_notifyfunc_t *funcp,
813    void *arg, dlpi_notifyid_t *id)
814{
815	int			retval;
816	dlpi_msg_t		req, ack;
817	dl_notify_req_t		*notifyreqp;
818	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
819	dlpi_notifyent_t	*newnotifp;
820	dlpi_info_t 		dlinfo;
821
822	if (dip == NULL)
823		return (DLPI_EINHANDLE);
824
825	retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
826	if (retval != DLPI_SUCCESS)
827		return (retval);
828
829	if (dip->dli_note_processing)
830		return (DLPI_FAILURE);
831
832	if (funcp == NULL || id == NULL)
833		return (DLPI_EINVAL);
834
835	if ((~DLPI_NOTIFICATION_TYPES & notes) ||
836	    !(notes & DLPI_NOTIFICATION_TYPES))
837		return (DLPI_ENOTEINVAL);
838
839	DLPI_MSG_CREATE(req, DL_NOTIFY_REQ);
840	DLPI_MSG_CREATE(ack, DL_NOTIFY_ACK);
841
842	notifyreqp = &(req.dlm_msg->notify_req);
843	notifyreqp->dl_notifications = notes;
844	notifyreqp->dl_timelimit = 0;
845
846	retval = i_dlpi_msg_common(dip, &req, &ack, DL_NOTIFY_ACK_SIZE, 0);
847	if (retval == DL_NOTSUPPORTED)
848		return (DLPI_ENOTENOTSUP);
849
850	if (retval != DLPI_SUCCESS)
851		return (retval);
852
853	if ((newnotifp = calloc(1, sizeof (dlpi_notifyent_t))) == NULL)
854		return (DL_SYSERR);
855
856	/* Register notification information. */
857	newnotifp->dln_fnp = funcp;
858	newnotifp->dln_notes = notes;
859	newnotifp->arg = arg;
860	newnotifp->dln_rm = B_FALSE;
861
862	/* Insert notification node at head */
863	newnotifp->dln_next = dip->dli_notifylistp;
864	dip->dli_notifylistp = newnotifp;
865
866	*id = (dlpi_notifyid_t)newnotifp;
867	return (DLPI_SUCCESS);
868}
869
870int
871dlpi_disabnotify(dlpi_handle_t dh, dlpi_notifyid_t id, void **argp)
872{
873	dlpi_impl_t		*dip = (dlpi_impl_t *)dh;
874	dlpi_notifyent_t	*remid = (dlpi_notifyent_t *)id;
875
876	if (dip == NULL)
877		return (DLPI_EINHANDLE);
878
879	/* Walk the notifyentry list to find matching id. */
880	if (!(i_dlpi_notifyidexists(dip, remid)))
881		return (DLPI_ENOTEIDINVAL);
882
883	if (argp != NULL)
884		*argp = remid->arg;
885
886	remid->dln_rm = B_TRUE;
887	/* Delete node if callbacks are not being processed. */
888	if (!dip->dli_note_processing)
889		i_dlpi_deletenotifyid(dip);
890
891	return (DLPI_SUCCESS);
892}
893
894int
895dlpi_fd(dlpi_handle_t dh)
896{
897	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
898
899	return (dip != NULL ? dip->dli_fd : -1);
900}
901
902int
903dlpi_set_timeout(dlpi_handle_t dh, int sec)
904{
905	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
906
907	if (dip == NULL)
908		return (DLPI_EINHANDLE);
909
910	dip->dli_timeout = sec;
911	return (DLPI_SUCCESS);
912}
913
914const char *
915dlpi_linkname(dlpi_handle_t dh)
916{
917	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
918
919	return (dip != NULL ? dip->dli_linkname : NULL);
920}
921
922/*
923 * Returns DLPI style stored in the handle.
924 * Note: This function is used for test purposes only. Do not remove without
925 * fixing the DLPI testsuite.
926 */
927uint_t
928dlpi_style(dlpi_handle_t dh)
929{
930	dlpi_impl_t	*dip = (dlpi_impl_t *)dh;
931
932	return (dip->dli_style);
933}
934
935uint_t
936dlpi_arptype(uint_t dlpitype)
937{
938	switch (dlpitype) {
939
940	case DL_ETHER:
941		return (ARPHRD_ETHER);
942
943	case DL_FRAME:
944		return (ARPHRD_FRAME);
945
946	case DL_ATM:
947		return (ARPHRD_ATM);
948
949	case DL_IPATM:
950		return (ARPHRD_IPATM);
951
952	case DL_HDLC:
953		return (ARPHRD_HDLC);
954
955	case DL_FC:
956		return (ARPHRD_FC);
957
958	case DL_CSMACD:				/* ieee 802 networks */
959	case DL_TPB:
960	case DL_TPR:
961	case DL_METRO:
962	case DL_FDDI:
963		return (ARPHRD_IEEE802);
964
965	case DL_IB:
966		return (ARPHRD_IB);
967
968	case DL_IPV4:
969	case DL_IPV6:
970		return (ARPHRD_TUNNEL);
971	}
972
973	return (0);
974}
975
976uint_t
977dlpi_iftype(uint_t dlpitype)
978{
979	switch (dlpitype) {
980
981	case DL_ETHER:
982		return (IFT_ETHER);
983
984	case DL_ATM:
985		return (IFT_ATM);
986
987	case DL_CSMACD:
988		return (IFT_ISO88023);
989
990	case DL_TPB:
991		return (IFT_ISO88024);
992
993	case DL_TPR:
994		return (IFT_ISO88025);
995
996	case DL_FDDI:
997		return (IFT_FDDI);
998
999	case DL_IB:
1000		return (IFT_IB);
1001
1002	case DL_OTHER:
1003		return (IFT_OTHER);
1004	}
1005
1006	return (0);
1007}
1008
1009/*
1010 * This function attempts to open a device under the following namespaces:
1011 *	/dev/ipnet	- if DLPI_DEVIPNET is specified
1012 *      /dev/net	- if a data-link with the specified name exists
1013 *	/dev		- if DLPI_DEVONLY is specified, or if there is no
1014 *			  data-link with the specified name (could be /dev/ip)
1015 *
1016 * In particular, if DLPI_DEVIPNET is not specified, this function is used to
1017 * open a data-link node, or "/dev/ip" node. It is usually be called firstly
1018 * with style1 being B_TRUE, and if that fails and the return value is not
1019 * DLPI_ENOTSTYLE2, the function will again be called with style1 being
1020 * B_FALSE (style-1 open attempt first, then style-2 open attempt).
1021 *
1022 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node
1023 * directly.
1024 *
1025 * Otherwise, for style-1 attempt, the function will try to open the style-1
1026 * /dev/net node, and perhaps fallback to open the style-1 /dev node if the
1027 * give name is not a data-link name (e.g., it is /dev/ip). Note that the
1028 * fallback and the subsequent style-2 attempt will not happen if:
1029 * 1. style-1 opening of the /dev/net node succeeds;
1030 * 2. style-1 opening of the /dev/net node fails with errno other than ENOENT,
1031 *    which means that the specific /dev/net node exist, but the attempt fails
1032 *    for some other reason;
1033 * 3. style-1 openning of the /dev/net fails with ENOENT, but the name is
1034 *    a known device name or its VLAN PPA hack name. (for example, assuming
1035 *    device bge0 is renamed to net0, opening /dev/net/bge1000 would return
1036 *    ENOENT, but we should not fallback to open /dev/bge1000 in this case,
1037 *    as VLAN 1 over the bge0 device should be named as net1000.
1038 *
1039 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed
1040 * the second style-2 open attempt.
1041 */
1042static int
1043i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
1044{
1045	char		path[MAXPATHLEN];
1046	int		oflags;
1047
1048	errno = ENOENT;
1049	oflags = O_RDWR;
1050	if (flags & DLPI_EXCL)
1051		oflags |= O_EXCL;
1052
1053	if (flags & DLPI_DEVIPNET) {
1054		(void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider);
1055		if ((*fd = open(path, oflags)) != -1)
1056			return (DLPI_SUCCESS);
1057		else
1058			return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1059	} else if (style1 && !(flags & DLPI_DEVONLY)) {
1060		char		driver[DLPI_LINKNAME_MAX];
1061		char		device[DLPI_LINKNAME_MAX];
1062		datalink_id_t	linkid;
1063		uint_t		ppa;
1064		dladm_handle_t	handle;
1065
1066		/*
1067		 * This is not a valid style-1 name. It could be "ip" module
1068		 * for example. Fallback to open the /dev node.
1069		 */
1070		if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS)
1071			goto fallback;
1072
1073		(void) snprintf(path, sizeof (path), "/dev/net/%s", provider);
1074		if ((*fd = open(path, oflags)) != -1)
1075			return (DLPI_SUCCESS);
1076
1077		/*
1078		 * We don't fallback to open the /dev node when it returns
1079		 * error codes other than ENOENT. In that case, DLPI_ENOTSTYLE2
1080		 * is returned to indicate not to continue the style-2 open.
1081		 */
1082		if (errno != ENOENT)
1083			return (DLPI_ENOTSTYLE2);
1084
1085		/*
1086		 * We didn't find the /dev/net node. Then we check whether
1087		 * the given name is a device name or its VLAN PPA hack name
1088		 * of a known link. If the answer is yes, and this link
1089		 * supports vanity naming, then the link (or the VLAN) should
1090		 * also have its /dev/net node but perhaps with another vanity
1091		 * name (for example, when bge0 is renamed to net0). In this
1092		 * case, although attempt to open the /dev/net/<devname> fails,
1093		 * we should not fallback to open the /dev/<devname> node.
1094		 */
1095		(void) snprintf(device, DLPI_LINKNAME_MAX, "%s%d", driver,
1096		    ppa >= 1000 ? ppa % 1000 : ppa);
1097
1098		/* open libdladm handle rather than taking it as input */
1099		if (dladm_open(&handle) != DLADM_STATUS_OK)
1100			goto fallback;
1101
1102		if (dladm_dev2linkid(handle, device, &linkid) ==
1103		    DLADM_STATUS_OK) {
1104			dladm_phys_attr_t dpa;
1105
1106			if ((dladm_phys_info(handle, linkid, &dpa,
1107			    DLADM_OPT_ACTIVE)) == DLADM_STATUS_OK &&
1108			    !dpa.dp_novanity) {
1109				dladm_close(handle);
1110				return (DLPI_ENOTSTYLE2);
1111			}
1112		}
1113		dladm_close(handle);
1114	}
1115
1116fallback:
1117	(void) snprintf(path, sizeof (path), "/dev/%s", provider);
1118	if ((*fd = open(path, oflags)) != -1)
1119		return (DLPI_SUCCESS);
1120
1121	return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
1122}
1123
1124/*
1125 * Open a style 1 link. PPA is implicitly attached.
1126 */
1127static int
1128i_dlpi_style1_open(dlpi_impl_t *dip)
1129{
1130	int		retval, save_errno;
1131	int		fd;
1132
1133	retval = i_dlpi_open(dip->dli_linkname, &fd, dip->dli_oflags, B_TRUE);
1134	if (retval != DLPI_SUCCESS)
1135		return (retval);
1136	dip->dli_fd = fd;
1137
1138	if ((retval = i_dlpi_checkstyle(dip, DL_STYLE1)) != DLPI_SUCCESS) {
1139		save_errno = errno;
1140		(void) close(dip->dli_fd);
1141		errno = save_errno;
1142	}
1143
1144	return (retval);
1145}
1146
1147/*
1148 * Open a style 2 link. PPA must be explicitly attached.
1149 */
1150static int
1151i_dlpi_style2_open(dlpi_impl_t *dip)
1152{
1153	int 		fd;
1154	int 		retval, save_errno;
1155
1156	retval = i_dlpi_open(dip->dli_provider, &fd, dip->dli_oflags, B_FALSE);
1157	if (retval != DLPI_SUCCESS)
1158		return (retval);
1159	dip->dli_fd = fd;
1160
1161	/*
1162	 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a
1163	 * DLPI link so attach and ignore rest.
1164	 */
1165	if (dip->dli_oflags & DLPI_SERIAL)
1166		goto attach;
1167
1168	if ((retval = i_dlpi_checkstyle(dip, DL_STYLE2)) != DLPI_SUCCESS)
1169		goto failure;
1170
1171	/*
1172	 * Succeeded opening the link and verified it is style2. Now attach to
1173	 * PPA only if DLPI_NOATTACH is not set.
1174	 */
1175	if (dip->dli_oflags & DLPI_NOATTACH)
1176		return (DLPI_SUCCESS);
1177
1178attach:
1179	if ((retval = i_dlpi_attach(dip)) == DLPI_SUCCESS)
1180		return (DLPI_SUCCESS);
1181
1182failure:
1183	save_errno = errno;
1184	(void) close(dip->dli_fd);
1185	errno = save_errno;
1186	return (retval);
1187}
1188
1189/*
1190 * Verify with DLPI that the link is the expected DLPI 'style' device,
1191 * dlpi_info sets the DLPI style in the DLPI handle.
1192 */
1193static int
1194i_dlpi_checkstyle(dlpi_impl_t *dip, t_uscalar_t style)
1195{
1196	int retval;
1197	dlpi_info_t dlinfo;
1198
1199	retval = dlpi_info((dlpi_handle_t)dip, &dlinfo, 0);
1200	if (retval == DLPI_SUCCESS && dip->dli_style != style)
1201		retval = DLPI_EBADLINK;
1202
1203	return (retval);
1204}
1205
1206/*
1207 * For DLPI style 2 providers, an explicit attach of PPA is required.
1208 */
1209static int
1210i_dlpi_attach(dlpi_impl_t *dip)
1211{
1212	dlpi_msg_t		req, ack;
1213	dl_attach_req_t		*attachreqp;
1214
1215	/*
1216	 * Special case: DLPI_SERIAL flag (synchronous serial lines)
1217	 * is not a DLPI link so ignore DLPI style.
1218	 */
1219	if (dip->dli_style != DL_STYLE2 && !(dip->dli_oflags & DLPI_SERIAL))
1220		return (DLPI_ENOTSTYLE2);
1221
1222	DLPI_MSG_CREATE(req, DL_ATTACH_REQ);
1223	DLPI_MSG_CREATE(ack, DL_OK_ACK);
1224
1225	attachreqp = &(req.dlm_msg->attach_req);
1226	attachreqp->dl_ppa = dip->dli_ppa;
1227
1228	return (i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0));
1229}
1230
1231/*
1232 * Enable DLPI passive mode on a DLPI handle. We intentionally do not care
1233 * if this request fails, as this indicates the underlying DLPI device does
1234 * not support link aggregation (pre-GLDV3 device drivers), and thus will
1235 * see the expected behavior without failing with DL_SYSERR/EBUSY when issuing
1236 * DLPI primitives like DL_BIND_REQ. For further info see dlpi(7p).
1237 */
1238static void
1239i_dlpi_passive(dlpi_impl_t *dip)
1240{
1241	dlpi_msg_t		req, ack;
1242
1243	DLPI_MSG_CREATE(req, DL_PASSIVE_REQ);
1244	DLPI_MSG_CREATE(ack, DL_OK_ACK);
1245
1246	(void) i_dlpi_msg_common(dip, &req, &ack, DL_OK_ACK_SIZE, 0);
1247}
1248
1249/*
1250 * Send a dlpi control message and/or data message on a stream. The inputs
1251 * for this function are:
1252 * 	dlpi_impl_t *dip: internal dlpi handle to open stream
1253 *	const dlpi_msg_t *dlreqp: request message structure
1254 *	void *databuf:	data buffer
1255 *	size_t datalen:	data buffer len
1256 *	int flags:	flags to set for putmsg()
1257 * Returns DLPI_SUCCESS if putmsg() succeeds, otherwise DL_SYSERR on failure.
1258 */
1259static int
1260i_dlpi_strputmsg(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1261    const void *databuf, size_t datalen, int flags)
1262{
1263	int		retval;
1264	int		fd = dip->dli_fd;
1265	struct strbuf	ctl;
1266	struct strbuf   data;
1267
1268	if (dlreqp != NULL) {
1269		ctl.buf = (void *)dlreqp->dlm_msg;
1270		ctl.len = dlreqp->dlm_msgsz;
1271	}
1272
1273	data.buf = (void *)databuf;
1274	data.len = datalen;
1275
1276	retval = putmsg(fd, (dlreqp == NULL ? NULL: &ctl),
1277	    (databuf == NULL ? NULL : &data), flags);
1278
1279	return ((retval == 0) ? DLPI_SUCCESS : DL_SYSERR);
1280}
1281
1282/*
1283 * Get a DLPI control message and/or data message from a stream. The inputs
1284 * for this function are:
1285 * 	dlpi_impl_t *dip: 	internal dlpi handle
1286 * 	int msec: 		timeout to wait for message
1287 *	dlpi_msg_t *dlreplyp:	reply message structure, the message size
1288 *				member on return stores actual size received
1289 *	t_uscalar_t dlreqprim: 	requested primitive
1290 *	t_uscalar_t dlreplyprim:acknowledged primitive in response to request
1291 *	size_t dlreplyminsz:	minimum size of acknowledged primitive size
1292 *	void *databuf: 		data buffer
1293 *	size_t *datalenp:	data buffer len
1294 *	size_t *totdatalenp: 	total data received. Greater than 'datalenp' if
1295 *				actual data received is larger than 'databuf'
1296 * Function returns DLPI_SUCCESS if requested message is retrieved
1297 * otherwise returns error code or timeouts. If a notification arrives on
1298 * the stream the callback is notified. However, error returned during the
1299 * handling of notification is ignored as it would be confusing to actual caller
1300 * of this function.
1301 */
1302static int
1303i_dlpi_strgetmsg(dlpi_impl_t *dip, int msec, dlpi_msg_t *dlreplyp,
1304    t_uscalar_t dlreqprim, t_uscalar_t dlreplyprim, size_t dlreplyminsz,
1305    void *databuf, size_t *datalenp, size_t *totdatalenp)
1306{
1307	int			retval;
1308	int			flags;
1309	int			fd = dip->dli_fd;
1310	struct strbuf		ctl, data;
1311	struct pollfd		pfd;
1312	hrtime_t		start, current;
1313	long			bufc[DLPI_CHUNKSIZE / sizeof (long)];
1314	long			bufd[DLPI_CHUNKSIZE / sizeof (long)];
1315	union DL_primitives	*dlprim;
1316	dl_notify_ind_t		*dlnotif;
1317	boolean_t		infinite = (msec < 0);	/* infinite timeout */
1318
1319	/*
1320	 * dlreplyp and databuf can be NULL at the same time, to force a check
1321	 * for pending events on the DLPI link instance; dlpi_enabnotify(3DLPI).
1322	 * this will be true more so for DLPI_RAW mode with notifications
1323	 * enabled.
1324	 */
1325	if ((databuf == NULL && datalenp != NULL) ||
1326	    (databuf != NULL && datalenp == NULL))
1327		return (DLPI_EINVAL);
1328
1329	pfd.fd = fd;
1330	pfd.events = POLLIN | POLLPRI;
1331
1332	ctl.buf = (dlreplyp == NULL) ? bufc : (void *)dlreplyp->dlm_msg;
1333	ctl.len = 0;
1334	ctl.maxlen = (dlreplyp == NULL) ? sizeof (bufc) : dlreplyp->dlm_msgsz;
1335
1336	data.buf = (databuf == NULL) ? bufd : databuf;
1337	data.len = 0;
1338	data.maxlen = (databuf == NULL) ? sizeof (bufd): *datalenp;
1339
1340	for (;;) {
1341		if (!infinite)
1342			start = NSEC2MSEC(gethrtime());
1343
1344		switch (poll(&pfd, 1, msec)) {
1345		default:
1346			if (pfd.revents & POLLHUP)
1347				return (DL_SYSERR);
1348			break;
1349		case 0:
1350			return (DLPI_ETIMEDOUT);
1351		case -1:
1352			return (DL_SYSERR);
1353		}
1354
1355		flags = 0;
1356		if ((retval = getmsg(fd, &ctl, &data, &flags)) < 0)
1357			return (DL_SYSERR);
1358
1359		if (totdatalenp != NULL)
1360			*totdatalenp = data.len;
1361
1362		/*
1363		 * The supplied DLPI_CHUNKSIZE sized buffers are large enough
1364		 * to retrieve all valid DLPI responses in one iteration.
1365		 * If MORECTL or MOREDATA is set, we are not interested in the
1366		 * remainder of the message. Temporary buffers are used to
1367		 * drain the remainder of this message.
1368		 * The special case we have to account for is if
1369		 * a higher priority messages is enqueued  whilst handling
1370		 * this condition. We use a change in the flags parameter
1371		 * returned by getmsg() to indicate the message has changed.
1372		 */
1373		while (retval & (MORECTL | MOREDATA)) {
1374			struct strbuf   cscratch, dscratch;
1375			int		oflags = flags;
1376
1377			cscratch.buf = (char *)bufc;
1378			dscratch.buf = (char *)bufd;
1379			cscratch.len = dscratch.len = 0;
1380			cscratch.maxlen = dscratch.maxlen =
1381			    sizeof (bufc);
1382
1383			if ((retval = getmsg(fd, &cscratch, &dscratch,
1384			    &flags)) < 0)
1385				return (DL_SYSERR);
1386
1387			if (totdatalenp != NULL)
1388				*totdatalenp += dscratch.len;
1389			/*
1390			 * In the special case of higher priority
1391			 * message received, the low priority message
1392			 * received earlier is discarded, if no data
1393			 * or control message is left.
1394			 */
1395			if ((flags != oflags) &&
1396			    !(retval & (MORECTL | MOREDATA)) &&
1397			    (cscratch.len != 0)) {
1398				ctl.len = MIN(cscratch.len, DLPI_CHUNKSIZE);
1399				if (dlreplyp != NULL)
1400					(void) memcpy(dlreplyp->dlm_msg, bufc,
1401					    ctl.len);
1402				break;
1403			}
1404		}
1405
1406		/*
1407		 * Check if DL_NOTIFY_IND message received. If there is one,
1408		 * notify the callback function(s) and continue processing the
1409		 * requested message.
1410		 */
1411		if (dip->dli_notifylistp != NULL &&
1412		    ctl.len >= (int)(sizeof (t_uscalar_t)) &&
1413		    *(t_uscalar_t *)(void *)ctl.buf == DL_NOTIFY_IND) {
1414			/* process properly-formed DL_NOTIFY_IND messages */
1415			if (ctl.len >= DL_NOTIFY_IND_SIZE) {
1416				dlnotif = (dl_notify_ind_t *)(void *)ctl.buf;
1417				(void) i_dlpi_notifyind_process(dip, dlnotif);
1418			}
1419			goto update_timer;
1420		}
1421
1422		/*
1423		 * If we were expecting a data message, and we got one, set
1424		 * *datalenp.  If we aren't waiting on a control message, then
1425		 * we're done.
1426		 */
1427		if (databuf != NULL && data.len >= 0) {
1428			*datalenp = data.len;
1429			if (dlreplyp == NULL)
1430				break;
1431		}
1432
1433		/*
1434		 * If we were expecting a control message, and the message
1435		 * we received is at least big enough to be a DLPI message,
1436		 * then verify it's a reply to something we sent.  If it
1437		 * is a reply to something we sent, also verify its size.
1438		 */
1439		if (dlreplyp != NULL && ctl.len >= sizeof (t_uscalar_t)) {
1440			dlprim = dlreplyp->dlm_msg;
1441			if (dlprim->dl_primitive == dlreplyprim) {
1442				if (ctl.len < dlreplyminsz)
1443					return (DLPI_EBADMSG);
1444				dlreplyp->dlm_msgsz = ctl.len;
1445				break;
1446			} else if (dlprim->dl_primitive == DL_ERROR_ACK) {
1447				if (ctl.len < DL_ERROR_ACK_SIZE)
1448					return (DLPI_EBADMSG);
1449
1450				/* Is it ours? */
1451				if (dlprim->error_ack.dl_error_primitive ==
1452				    dlreqprim)
1453					break;
1454			}
1455		}
1456update_timer:
1457		if (!infinite) {
1458			current = NSEC2MSEC(gethrtime());
1459			msec -= (current - start);
1460
1461			if (msec <= 0)
1462				return (DLPI_ETIMEDOUT);
1463		}
1464	}
1465
1466	return (DLPI_SUCCESS);
1467}
1468
1469/*
1470 * Common routine invoked by all DLPI control routines. The inputs for this
1471 * function are:
1472 * 	dlpi_impl_t *dip: internal dlpi handle
1473 *	const dlpi_msg_t *dlreqp: request message structure
1474 *	dlpi_msg_t *dlreplyp: reply message structure
1475 *	size_t dlreplyminsz: minimum size of reply primitive
1476 *	int flags: flags to be set to send a message
1477 * This routine succeeds if the message is an expected request/acknowledged
1478 * message. However, if DLPI notification has been enabled via
1479 * dlpi_enabnotify(), DL_NOTIFY_IND messages are handled before handling
1480 * expected messages. Otherwise, any other unexpected asynchronous messages will
1481 * be discarded.
1482 */
1483static int
1484i_dlpi_msg_common(dlpi_impl_t *dip, const dlpi_msg_t *dlreqp,
1485    dlpi_msg_t *dlreplyp, size_t dlreplyminsz, int flags)
1486{
1487	int		retval;
1488	t_uscalar_t	dlreqprim = dlreqp->dlm_msg->dl_primitive;
1489	t_uscalar_t 	dlreplyprim = dlreplyp->dlm_msg->dl_primitive;
1490
1491	/* Put the requested primitive on the stream. */
1492	retval = i_dlpi_strputmsg(dip, dlreqp, NULL, 0, flags);
1493	if (retval != DLPI_SUCCESS)
1494		return (retval);
1495
1496	/* Retrieve acknowledged message for requested primitive. */
1497	retval = i_dlpi_strgetmsg(dip, (dip->dli_timeout * MILLISEC),
1498	    dlreplyp, dlreqprim, dlreplyprim, dlreplyminsz, NULL, NULL, NULL);
1499	if (retval != DLPI_SUCCESS)
1500		return (retval);
1501
1502	/*
1503	 * If primitive is DL_ERROR_ACK, set errno.
1504	 */
1505	if (dlreplyp->dlm_msg->dl_primitive == DL_ERROR_ACK) {
1506		errno = dlreplyp->dlm_msg->error_ack.dl_unix_errno;
1507		retval = dlreplyp->dlm_msg->error_ack.dl_errno;
1508	}
1509
1510	return (retval);
1511}
1512
1513/*
1514 * DLPI error codes.
1515 */
1516static const char *dlpi_errlist[] = {
1517	"bad LSAP selector",				/* DL_BADSAP  0x00 */
1518	"DLSAP address in improper format or invalid",	/* DL_BADADDR 0x01 */
1519	"improper permissions for request",		/* DL_ACCESS  0x02 */
1520	"primitive issued in improper state",		/* DL_OUTSTATE 0x03 */
1521	NULL,						/* DL_SYSERR  0x04 */
1522	"sequence number not from outstanding DL_CONN_IND",
1523							/* DL_BADCORR 0x05 */
1524	"user data exceeded provider limit",		/* DL_BADDATA 0x06 */
1525	"requested service not supplied by provider",
1526						/* DL_UNSUPPORTED 0x07 */
1527	"specified PPA was invalid", 			/* DL_BADPPA 0x08 */
1528	"primitive received not known by provider",	/* DL_BADPRIM 0x09 */
1529	"QoS parameters contained invalid values",
1530						/* DL_BADQOSPARAM 0x0a */
1531	"QoS structure type is unknown/unsupported",	/* DL_BADQOSTYPE 0x0b */
1532	"token used not an active stream", 		/* DL_BADTOKEN 0x0c */
1533	"attempted second bind with dl_max_conind",	/* DL_BOUND 0x0d */
1534	"physical link initialization failed",		/* DL_INITFAILED 0x0e */
1535	"provider couldn't allocate alternate address",	/* DL_NOADDR 0x0f */
1536	"physical link not initialized",		/* DL_NOTINIT 0x10 */
1537	"previous data unit could not be delivered",
1538						/* DL_UNDELIVERABLE 0x11 */
1539	"primitive is known but unsupported",
1540						/* DL_NOTSUPPORTED 0x12 */
1541	"limit exceeded",				/* DL_TOOMANY 0x13 */
1542	"promiscuous mode not enabled",			/* DL_NOTENAB 0x14 */
1543	"other streams for PPA in post-attached",	/* DL_BUSY 0x15 */
1544	"automatic handling XID&TEST unsupported",	/* DL_NOAUTO 0x16 */
1545	"automatic handling of XID unsupported",	/* DL_NOXIDAUTO 0x17 */
1546	"automatic handling of TEST unsupported",	/* DL_NOTESTAUTO 0x18 */
1547	"automatic handling of XID response",		/* DL_XIDAUTO 0x19 */
1548	"automatic handling of TEST response", 		/* DL_TESTAUTO 0x1a */
1549	"pending outstanding connect indications"	/* DL_PENDING 0x1b */
1550};
1551
1552/*
1553 * libdlpi error codes.
1554 */
1555static const char *libdlpi_errlist[] = {
1556	"DLPI operation succeeded",		/* DLPI_SUCCESS */
1557	"invalid argument",			/* DLPI_EINVAL */
1558	"invalid DLPI linkname",		/* DLPI_ELINKNAMEINVAL */
1559	"DLPI link does not exist",		/* DLPI_ENOLINK */
1560	"bad DLPI link",			/* DLPI_EBADLINK */
1561	"invalid DLPI handle",			/* DLPI_EINHANDLE */
1562	"DLPI operation timed out",		/* DLPI_ETIMEDOUT */
1563	"unsupported DLPI version",		/* DLPI_EVERNOTSUP */
1564	"unsupported DLPI connection mode",	/* DLPI_EMODENOTSUP */
1565	"unavailable DLPI SAP",			/* DLPI_EUNAVAILSAP */
1566	"DLPI operation failed",		/* DLPI_FAILURE */
1567	"DLPI style-2 node reports style-1",	/* DLPI_ENOTSTYLE2 */
1568	"bad DLPI message",			/* DLPI_EBADMSG */
1569	"DLPI raw mode not supported",		/* DLPI_ERAWNOTSUP */
1570	"DLPI notification not supported by link",
1571						/* DLPI_ENOTENOTSUP */
1572	"invalid DLPI notification type",	/* DLPI_ENOTEINVAL */
1573	"invalid DLPI notification id",		/* DLPI_ENOTEIDINVAL */
1574	"DLPI_IPNETINFO not supported"		/* DLPI_EIPNETINFONOTSUP */
1575};
1576
1577const char *
1578dlpi_strerror(int err)
1579{
1580	if (err == DL_SYSERR)
1581		return (strerror(errno));
1582	else if (err >= 0 && err < NELEMS(dlpi_errlist))
1583		return (dgettext(TEXT_DOMAIN, dlpi_errlist[err]));
1584	else if (err >= DLPI_SUCCESS && err < DLPI_ERRMAX)
1585		return (dgettext(TEXT_DOMAIN, libdlpi_errlist[err -
1586		    DLPI_SUCCESS]));
1587	else
1588		return (dgettext(TEXT_DOMAIN, "Unknown DLPI error"));
1589}
1590
1591/*
1592 * Each table entry comprises a DLPI/Private mactype and the description.
1593 */
1594static const dlpi_mactype_t dlpi_mactypes[] = {
1595	{ DL_CSMACD,		"CSMA/CD"		},
1596	{ DL_TPB,		"Token Bus"		},
1597	{ DL_TPR,		"Token Ring"		},
1598	{ DL_METRO,		"Metro Net"		},
1599	{ DL_ETHER,		"Ethernet"		},
1600	{ DL_HDLC,		"HDLC"			},
1601	{ DL_CHAR,		"Sync Character"	},
1602	{ DL_CTCA,		"CTCA"			},
1603	{ DL_FDDI,		"FDDI"			},
1604	{ DL_FRAME,		"Frame Relay (LAPF)"	},
1605	{ DL_MPFRAME,		"MP Frame Relay"	},
1606	{ DL_ASYNC,		"Async Character"	},
1607	{ DL_IPX25,		"X.25 (Classic IP)"	},
1608	{ DL_LOOP,		"Software Loopback"	},
1609	{ DL_FC,		"Fiber Channel"		},
1610	{ DL_ATM,		"ATM"			},
1611	{ DL_IPATM,		"ATM (Classic IP)"	},
1612	{ DL_X25,		"X.25 (LAPB)"		},
1613	{ DL_ISDN,		"ISDN"			},
1614	{ DL_HIPPI,		"HIPPI"			},
1615	{ DL_100VG,		"100BaseVG Ethernet"	},
1616	{ DL_100VGTPR,		"100BaseVG Token Ring"	},
1617	{ DL_ETH_CSMA,		"Ethernet/IEEE 802.3"	},
1618	{ DL_100BT,		"100BaseT"		},
1619	{ DL_IB,		"Infiniband"		},
1620	{ DL_IPV4,		"IPv4 Tunnel"		},
1621	{ DL_IPV6,		"IPv6 Tunnel"		},
1622	{ DL_WIFI,		"IEEE 802.11"		},
1623	{ DL_IPNET,		"IPNET"			}
1624};
1625
1626const char *
1627dlpi_mactype(uint_t mactype)
1628{
1629	int i;
1630
1631	for (i = 0; i < NELEMS(dlpi_mactypes); i++) {
1632		if (dlpi_mactypes[i].dm_mactype == mactype)
1633			return (dlpi_mactypes[i].dm_desc);
1634	}
1635
1636	return ("Unknown MAC Type");
1637}
1638
1639/*
1640 * Each table entry comprises a DLPI primitive and the maximum buffer
1641 * size needed, in bytes, for the DLPI message (see <sys/dlpi.h> for details).
1642 */
1643static const dlpi_primsz_t dlpi_primsizes[] = {
1644{ DL_INFO_REQ,		DL_INFO_REQ_SIZE				},
1645{ DL_INFO_ACK,		DL_INFO_ACK_SIZE + (2 * DLPI_PHYSADDR_MAX) +
1646			DLPI_SAPLEN_MAX + (2 * sizeof (union DL_qos_types))},
1647{ DL_ATTACH_REQ,	DL_ATTACH_REQ_SIZE				},
1648{ DL_BIND_REQ,		DL_BIND_REQ_SIZE				},
1649{ DL_BIND_ACK, 		DL_BIND_ACK_SIZE + DLPI_PHYSADDR_MAX +
1650			DLPI_SAPLEN_MAX					},
1651{ DL_UNBIND_REQ, 	DL_UNBIND_REQ_SIZE				},
1652{ DL_ENABMULTI_REQ, 	DL_ENABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX	},
1653{ DL_DISABMULTI_REQ, 	DL_DISABMULTI_REQ_SIZE + DLPI_PHYSADDR_MAX	},
1654{ DL_PROMISCON_REQ, 	DL_PROMISCON_REQ_SIZE				},
1655{ DL_PROMISCOFF_REQ,	DL_PROMISCOFF_REQ_SIZE				},
1656{ DL_PASSIVE_REQ, 	DL_PASSIVE_REQ_SIZE				},
1657{ DL_UNITDATA_REQ, 	DL_UNITDATA_REQ_SIZE + DLPI_PHYSADDR_MAX +
1658			DLPI_SAPLEN_MAX					},
1659{ DL_UNITDATA_IND, 	DL_UNITDATA_IND_SIZE + (2 * (DLPI_PHYSADDR_MAX +
1660			DLPI_SAPLEN_MAX))				},
1661{ DL_PHYS_ADDR_REQ, 	DL_PHYS_ADDR_REQ_SIZE				},
1662{ DL_PHYS_ADDR_ACK, 	DL_PHYS_ADDR_ACK_SIZE + DLPI_PHYSADDR_MAX	},
1663{ DL_SET_PHYS_ADDR_REQ, DL_SET_PHYS_ADDR_REQ_SIZE + DLPI_PHYSADDR_MAX	},
1664{ DL_OK_ACK,		MAX(DL_ERROR_ACK_SIZE, DL_OK_ACK_SIZE)		},
1665{ DL_NOTIFY_REQ,	DL_NOTIFY_REQ_SIZE				},
1666{ DL_NOTIFY_ACK,	MAX(DL_ERROR_ACK_SIZE, DL_NOTIFY_ACK_SIZE)	},
1667{ DL_NOTIFY_IND,	DL_NOTIFY_IND_SIZE + DLPI_PHYSADDR_MAX +
1668			DLPI_SAPLEN_MAX					}
1669};
1670
1671/*
1672 * Refers to the dlpi_primsizes[] table to return corresponding maximum
1673 * buffer size.
1674 */
1675static size_t
1676i_dlpi_getprimsize(t_uscalar_t prim)
1677{
1678	int	i;
1679
1680	for (i = 0; i < NELEMS(dlpi_primsizes); i++) {
1681		if (dlpi_primsizes[i].dp_prim == prim)
1682			return (dlpi_primsizes[i].dp_primsz);
1683	}
1684
1685	return (sizeof (t_uscalar_t));
1686}
1687
1688/*
1689 * sap values vary in length and are in host byte order, build sap value
1690 * by writing saplen bytes, so that the sap value is left aligned.
1691 */
1692static uint_t
1693i_dlpi_buildsap(uint8_t *sapp, uint_t saplen)
1694{
1695	int i;
1696	uint_t sap = 0;
1697
1698#ifdef _LITTLE_ENDIAN
1699	for (i = saplen - 1; i >= 0; i--) {
1700#else
1701	for (i = 0; i < saplen; i++) {
1702#endif
1703		sap <<= 8;
1704		sap |= sapp[i];
1705	}
1706
1707	return (sap);
1708}
1709
1710/*
1711 * Copy sap value to a buffer in host byte order. saplen is the number of
1712 * bytes to copy.
1713 */
1714static void
1715i_dlpi_writesap(void *dstbuf, uint_t sap, uint_t saplen)
1716{
1717	uint8_t *sapp;
1718
1719#ifdef _LITTLE_ENDIAN
1720	sapp = (uint8_t *)&sap;
1721#else
1722	sapp = (uint8_t *)&sap + (sizeof (sap) - saplen);
1723#endif
1724
1725	(void) memcpy(dstbuf, sapp, saplen);
1726}
1727
1728/*
1729 * Fill notification payload and callback each registered functions.
1730 * Delete nodes if any was called while processing.
1731 */
1732static int
1733i_dlpi_notifyind_process(dlpi_impl_t *dip, dl_notify_ind_t *dlnotifyindp)
1734{
1735	dlpi_notifyinfo_t	notifinfo;
1736	t_uscalar_t		dataoff, datalen;
1737	caddr_t			datap;
1738	dlpi_notifyent_t	*dnp;
1739	uint_t			note = dlnotifyindp->dl_notification;
1740	uint_t			deletenode = B_FALSE;
1741
1742	notifinfo.dni_note = note;
1743
1744	switch (note) {
1745	case DL_NOTE_SPEED:
1746		notifinfo.dni_speed = dlnotifyindp->dl_data;
1747		break;
1748	case DL_NOTE_SDU_SIZE:
1749		notifinfo.dni_size = dlnotifyindp->dl_data;
1750		break;
1751	case DL_NOTE_PHYS_ADDR:
1752		/*
1753		 * libdlpi currently only supports notifications for
1754		 * DL_CURR_PHYS_ADDR.
1755		 */
1756		if (dlnotifyindp->dl_data != DL_CURR_PHYS_ADDR)
1757			return (DLPI_ENOTENOTSUP);
1758
1759		dataoff = dlnotifyindp->dl_addr_offset;
1760		datalen = dlnotifyindp->dl_addr_length;
1761
1762		if (dataoff == 0 || datalen == 0)
1763			return (DLPI_EBADMSG);
1764
1765		datap = (caddr_t)dlnotifyindp + dataoff;
1766		if (dataoff < DL_NOTIFY_IND_SIZE)
1767			return (DLPI_EBADMSG);
1768
1769		notifinfo.dni_physaddrlen = datalen - dip->dli_saplen;
1770
1771		if (notifinfo.dni_physaddrlen > DLPI_PHYSADDR_MAX)
1772			return (DL_BADADDR);
1773
1774		(void) memcpy(notifinfo.dni_physaddr, datap,
1775		    notifinfo.dni_physaddrlen);
1776		break;
1777	}
1778
1779	dip->dli_note_processing = B_TRUE;
1780
1781	for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
1782		if (note & dnp->dln_notes)
1783			dnp->dln_fnp((dlpi_handle_t)dip, &notifinfo, dnp->arg);
1784		if (dnp->dln_rm)
1785			deletenode = B_TRUE;
1786	}
1787
1788	dip->dli_note_processing = B_FALSE;
1789
1790	/* Walk the notifyentry list to unregister marked entries. */
1791	if (deletenode)
1792		i_dlpi_deletenotifyid(dip);
1793
1794	return (DLPI_SUCCESS);
1795}
1796/*
1797 * Find registered notification.
1798 */
1799static boolean_t
1800i_dlpi_notifyidexists(dlpi_impl_t *dip, dlpi_notifyent_t *id)
1801{
1802	dlpi_notifyent_t	*dnp;
1803
1804	for (dnp = dip->dli_notifylistp; dnp != NULL; dnp = dnp->dln_next) {
1805		if (id == dnp)
1806			return (B_TRUE);
1807	}
1808
1809	return (B_FALSE);
1810}
1811
1812/*
1813 * Walk the list of notifications and deleted nodes marked to be deleted.
1814 */
1815static void
1816i_dlpi_deletenotifyid(dlpi_impl_t *dip)
1817{
1818	dlpi_notifyent_t	 *prev, *dnp;
1819
1820	prev = NULL;
1821	dnp = dip->dli_notifylistp;
1822	while (dnp != NULL) {
1823		if (!dnp->dln_rm) {
1824			prev = dnp;
1825			dnp = dnp->dln_next;
1826		} else if (prev == NULL) {
1827			dip->dli_notifylistp = dnp->dln_next;
1828			free(dnp);
1829			dnp = dip->dli_notifylistp;
1830		} else {
1831			prev->dln_next = dnp->dln_next;
1832			free(dnp);
1833			dnp = prev->dln_next;
1834		}
1835	}
1836}
1837