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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Data-Link Provider Interface (Version 2)
32 #include <sys/types.h>
41 #include <sys/sysmacros.h>
43 #include <net/if_types.h>
44 #include <netinet/arp.h>
46 #include <libdllink.h>
49 #include <libinetutil.h>
52 #include "libdlpi_impl.h"
54 static int i_dlpi_open(const char *, int *, uint_t
, boolean_t
);
55 static int i_dlpi_style1_open(dlpi_impl_t
*);
56 static int i_dlpi_style2_open(dlpi_impl_t
*);
57 static int i_dlpi_checkstyle(dlpi_impl_t
*, t_uscalar_t
);
58 static int i_dlpi_attach(dlpi_impl_t
*);
59 static void i_dlpi_passive(dlpi_impl_t
*);
61 static int i_dlpi_strputmsg(dlpi_impl_t
*, const dlpi_msg_t
*, const void *,
63 static 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 *);
65 static int i_dlpi_msg_common(dlpi_impl_t
*, const dlpi_msg_t
*, dlpi_msg_t
*,
68 static size_t i_dlpi_getprimsize(t_uscalar_t
);
69 static int i_dlpi_multi(dlpi_handle_t
, t_uscalar_t
, const uint8_t *, size_t);
70 static int i_dlpi_promisc(dlpi_handle_t
, t_uscalar_t
, uint_t
);
71 static uint_t
i_dlpi_buildsap(uint8_t *, uint_t
);
72 static void i_dlpi_writesap(void *, uint_t
, uint_t
);
73 static int i_dlpi_notifyind_process(dlpi_impl_t
*, dl_notify_ind_t
*);
74 static boolean_t
i_dlpi_notifyidexists(dlpi_impl_t
*, dlpi_notifyent_t
*);
75 static void i_dlpi_deletenotifyid(dlpi_impl_t
*);
77 struct i_dlpi_walklink_arg
{
83 i_dlpi_walk_link(const char *name
, void *arg
)
85 struct i_dlpi_walklink_arg
*warg
= arg
;
87 return ((warg
->fn(name
, warg
->arg
)) ? DLADM_WALK_TERMINATE
:
93 dlpi_walk(dlpi_walkfunc_t
*fn
, void *arg
, uint_t flags
)
95 struct i_dlpi_walklink_arg warg
;
98 dladm_handle_t handle
;
103 if (flags
& DLPI_DEVIPNET
) {
104 if ((dp
= opendir("/dev/ipnet")) == NULL
)
107 while ((d
= readdir(dp
)) != NULL
) {
108 if (d
->d_name
[0] == '.')
111 if (warg
.fn(d
->d_name
, warg
.arg
))
118 * Rather than have libdlpi take the libdladm handle,
119 * open the handle here.
121 if (dladm_open(&handle
) != DLADM_STATUS_OK
)
124 (void) dladm_walk(i_dlpi_walk_link
, handle
, &warg
,
125 DATALINK_CLASS_ALL
, DATALINK_ANY_MEDIATYPE
,
133 dlpi_open(const char *linkname
, dlpi_handle_t
*dhp
, uint_t flags
)
140 * Validate linkname, fail if logical unit number (lun) is specified,
141 * otherwise decompose the contents into ifsp.
143 if (linkname
== NULL
|| (strchr(linkname
, ':') != NULL
) ||
144 !ifparse_ifspec(linkname
, &ifsp
))
145 return (DLPI_ELINKNAMEINVAL
);
148 * Ensure flags values are sane.
150 if ((flags
& (DLPI_DEVIPNET
|DLPI_DEVONLY
)) ==
151 (DLPI_DEVIPNET
|DLPI_DEVONLY
))
152 return (DLPI_EINVAL
);
154 /* Allocate a new dlpi_impl_t. */
155 if ((dip
= calloc(1, sizeof (dlpi_impl_t
))) == NULL
)
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
;
167 /* Copy linkname provided to the function. */
168 if (strlcpy(dip
->dli_linkname
, linkname
, sizeof (dip
->dli_linkname
)) >=
169 sizeof (dip
->dli_linkname
)) {
171 return (DLPI_ELINKNAMEINVAL
);
174 /* Copy provider name. */
175 (void) strlcpy(dip
->dli_provider
, ifsp
.ifsp_devnm
,
176 sizeof (dip
->dli_provider
));
179 * Special case: DLPI_SERIAL flag is set to indicate a synchronous
180 * serial line interface (see syncinit(8), syncstat(8),
181 * syncloop(8)), which is not a DLPI link.
183 if (dip
->dli_oflags
& DLPI_SERIAL
) {
184 if ((retval
= i_dlpi_style2_open(dip
)) != DLPI_SUCCESS
) {
189 *dhp
= (dlpi_handle_t
)dip
;
193 if ((retval
= i_dlpi_style1_open(dip
)) != DLPI_SUCCESS
) {
194 if (retval
== DLPI_ENOTSTYLE2
) {
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.
202 } else if (!(dip
->dli_oflags
& DLPI_DEVIPNET
)) {
203 retval
= i_dlpi_style2_open(dip
);
205 if (retval
!= DLPI_SUCCESS
) {
211 if (dip
->dli_oflags
& DLPI_PASSIVE
)
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
);
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
);
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).
231 if (dip
->dli_oflags
& DLPI_NATIVE
) {
232 if ((retval
= ioctl(dip
->dli_fd
, DLIOCNATIVE
, 0)) > 0)
233 dip
->dli_mactype
= retval
;
236 *dhp
= (dlpi_handle_t
)dip
;
237 return (DLPI_SUCCESS
);
241 dlpi_close(dlpi_handle_t dh
)
243 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
244 dlpi_notifyent_t
*next
, *dnp
;
247 for (dnp
= dip
->dli_notifylistp
; dnp
!= NULL
; dnp
= next
) {
248 next
= dnp
->dln_next
;
252 (void) close(dip
->dli_fd
);
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)).
262 dlpi_info(dlpi_handle_t dh
, dlpi_info_t
*infop
, uint_t opt
)
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
;
273 return (DLPI_EINHANDLE
);
275 if (infop
== NULL
|| opt
!= 0)
276 return (DLPI_EINVAL
);
278 (void) memset(infop
, 0, sizeof (dlpi_info_t
));
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
;
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
;
297 DLPI_MSG_CREATE(req
, DL_INFO_REQ
);
298 DLPI_MSG_CREATE(ack
, DL_INFO_ACK
);
300 retval
= i_dlpi_msg_common(dip
, &req
, &ack
, DL_INFO_ACK_SIZE
, RS_HIPRI
);
301 if (retval
!= DLPI_SUCCESS
)
304 infoackp
= &(ack
.dlm_msg
->info_ack
);
305 if (infoackp
->dl_version
!= DL_VERSION_2
)
306 return (DLPI_EVERNOTSUP
);
308 if (infoackp
->dl_service_mode
!= DL_CLDLS
)
309 return (DLPI_EMODENOTSUP
);
311 dip
->dli_style
= infoackp
->dl_provider_style
;
312 dip
->dli_mactype
= infoackp
->dl_mac_type
;
314 ackendp
= (caddr_t
)ack
.dlm_msg
+ ack
.dlm_msgsz
;
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
);
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
);
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
);
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
);
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
;
349 if (infop
->di_physaddrlen
> DLPI_PHYSADDR_MAX
||
350 dip
->dli_saplen
> DLPI_SAPLEN_MAX
)
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
);
360 sapp
= addrp
= (uint8_t *)datap
;
361 if (dip
->dli_sapbefore
)
362 addrp
+= dip
->dli_saplen
;
364 sapp
+= infop
->di_physaddrlen
;
366 (void) memcpy(infop
->di_physaddr
, addrp
, infop
->di_physaddrlen
);
367 infop
->di_sap
= i_dlpi_buildsap(sapp
, dip
->dli_saplen
);
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
)
380 infop
->di_bcastaddrlen
= datalen
;
381 (void) memcpy(infop
->di_bcastaddr
, datap
, datalen
);
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
;
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
;
394 return (DLPI_SUCCESS
);
398 * This function parses 'linkname' and stores the 'provider' name and 'PPA'.
401 dlpi_parselink(const char *linkname
, char *provider
, uint_t
*ppa
)
403 dladm_status_t status
;
405 status
= dladm_parselink(linkname
, provider
, ppa
);
407 if (status
!= DLADM_STATUS_OK
)
408 return (DLPI_ELINKNAMEINVAL
);
410 return (DLPI_SUCCESS
);
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'.
419 dlpi_makelink(char *linkname
, const char *provider
, uint_t ppa
)
421 int provlen
= strlen(provider
);
423 if (linkname
== NULL
|| provlen
== 0 || provlen
>= DLPI_LINKNAME_MAX
)
424 return (DLPI_ELINKNAMEINVAL
);
426 if (!isdigit(provider
[provlen
- 1])) {
427 (void) snprintf(linkname
, DLPI_LINKNAME_MAX
, "%s%d", provider
,
430 (void) strlcpy(linkname
, provider
, DLPI_LINKNAME_MAX
);
433 return (DLPI_SUCCESS
);
437 dlpi_bind(dlpi_handle_t dh
, uint_t sap
, uint_t
*boundsap
)
441 dl_bind_req_t
*bindreqp
;
442 dl_bind_ack_t
*bindackp
;
443 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
446 return (DLPI_EINHANDLE
);
448 DLPI_MSG_CREATE(req
, DL_BIND_REQ
);
449 DLPI_MSG_CREATE(ack
, DL_BIND_ACK
);
450 bindreqp
= &(req
.dlm_msg
->bind_req
);
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).
456 if (sap
== DLPI_ANY_SAP
)
457 bindreqp
->dl_sap
= ((dip
->dli_mactype
== DL_TPR
) ? 2 : 0);
459 bindreqp
->dl_sap
= sap
;
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;
466 retval
= i_dlpi_msg_common(dip
, &req
, &ack
, DL_BIND_ACK_SIZE
, 0);
467 if (retval
!= DLPI_SUCCESS
)
470 bindackp
= &(ack
.dlm_msg
->bind_ack
);
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.
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
);
484 return (DLPI_EUNAVAILSAP
);
487 dip
->dli_sap
= bindackp
->dl_sap
; /* save sap value in handle */
488 return (DLPI_SUCCESS
);
492 dlpi_unbind(dlpi_handle_t dh
)
495 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
498 return (DLPI_EINHANDLE
);
500 DLPI_MSG_CREATE(req
, DL_UNBIND_REQ
);
501 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
503 return (i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0));
507 * This function is invoked by dlpi_enabmulti() or dlpi_disabmulti() and
508 * based on the "op" value, multicast address is enabled/disabled.
511 i_dlpi_multi(dlpi_handle_t dh
, t_uscalar_t op
, const uint8_t *addrp
,
515 dl_enabmulti_req_t
*multireqp
;
516 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
519 return (DLPI_EINHANDLE
);
521 if (addrlen
> DLPI_PHYSADDR_MAX
)
522 return (DLPI_EINVAL
);
524 DLPI_MSG_CREATE(req
, op
);
525 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
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
);
532 return (i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0));
536 dlpi_enabmulti(dlpi_handle_t dh
, const void *addrp
, size_t addrlen
)
538 return (i_dlpi_multi(dh
, DL_ENABMULTI_REQ
, addrp
, addrlen
));
542 dlpi_disabmulti(dlpi_handle_t dh
, const void *addrp
, size_t addrlen
)
544 return (i_dlpi_multi(dh
, DL_DISABMULTI_REQ
, addrp
, addrlen
));
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
553 i_dlpi_promisc(dlpi_handle_t dh
, t_uscalar_t op
, uint_t level
)
556 dl_promiscon_req_t
*promiscreqp
;
557 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
560 return (DLPI_EINHANDLE
);
562 DLPI_MSG_CREATE(req
, op
);
563 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
565 promiscreqp
= &(req
.dlm_msg
->promiscon_req
);
566 promiscreqp
->dl_level
= level
;
568 return (i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0));
572 dlpi_promiscon(dlpi_handle_t dh
, uint_t level
)
574 return (i_dlpi_promisc(dh
, DL_PROMISCON_REQ
, level
));
578 dlpi_promiscoff(dlpi_handle_t dh
, uint_t level
)
580 return (i_dlpi_promisc(dh
, DL_PROMISCOFF_REQ
, level
));
584 dlpi_get_physaddr(dlpi_handle_t dh
, uint_t type
, void *addrp
, size_t *addrlenp
)
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
;
595 return (DLPI_EINHANDLE
);
597 if (addrlenp
== NULL
|| addrp
== NULL
|| *addrlenp
< DLPI_PHYSADDR_MAX
)
598 return (DLPI_EINVAL
);
600 DLPI_MSG_CREATE(req
, DL_PHYS_ADDR_REQ
);
601 DLPI_MSG_CREATE(ack
, DL_PHYS_ADDR_ACK
);
603 physreqp
= &(req
.dlm_msg
->physaddr_req
);
604 physreqp
->dl_addr_type
= type
;
606 retval
= i_dlpi_msg_common(dip
, &req
, &ack
, DL_PHYS_ADDR_ACK_SIZE
, 0);
607 if (retval
!= DLPI_SUCCESS
)
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
)
619 if (dataoff
< DL_PHYS_ADDR_ACK_SIZE
||
620 datap
+ datalen
> physackendp
)
621 return (DLPI_EBADMSG
);
623 *addrlenp
= physackp
->dl_addr_length
;
624 (void) memcpy(addrp
, datap
, datalen
);
629 return (DLPI_SUCCESS
);
633 dlpi_set_physaddr(dlpi_handle_t dh
, uint_t type
, const void *addrp
,
637 dl_set_phys_addr_req_t
*setphysreqp
;
638 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
641 return (DLPI_EINHANDLE
);
643 if (addrp
== NULL
|| type
!= DL_CURR_PHYS_ADDR
||
644 addrlen
> DLPI_PHYSADDR_MAX
)
645 return (DLPI_EINVAL
);
647 DLPI_MSG_CREATE(req
, DL_SET_PHYS_ADDR_REQ
);
648 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
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
);
655 return (i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0));
659 dlpi_send(dlpi_handle_t dh
, const void *daddrp
, size_t daddrlen
,
660 const void *msgbuf
, size_t msglen
, const dlpi_sendinfo_t
*sendp
)
663 dl_unitdata_req_t
*udatareqp
;
665 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
668 return (DLPI_EINHANDLE
);
670 if (dip
->dli_oflags
& DLPI_RAW
)
671 return (i_dlpi_strputmsg(dip
, NULL
, msgbuf
, msglen
, 0));
673 if ((daddrlen
> 0 && daddrp
== NULL
) || daddrlen
> DLPI_PHYSADDR_MAX
)
674 return (DLPI_EINVAL
);
676 DLPI_MSG_CREATE(req
, DL_UNITDATA_REQ
);
677 udatareqp
= &(req
.dlm_msg
->unitdata_req
);
679 /* Set priority to default priority range. */
680 udatareqp
->dl_priority
.dl_min
= 0;
681 udatareqp
->dl_priority
.dl_max
= 0;
683 /* Use SAP value if specified otherwise use bound SAP value. */
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
;
694 udatareqp
->dl_dest_addr_length
= daddrlen
+ dip
->dli_saplen
;
695 udatareqp
->dl_dest_addr_offset
= DL_UNITDATA_REQ_SIZE
;
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.
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
,
707 (void) memcpy(&udatareqp
[1], daddrp
, daddrlen
);
708 i_dlpi_writesap((caddr_t
)&udatareqp
[1] + daddrlen
, sap
,
712 return (i_dlpi_strputmsg(dip
, &req
, msgbuf
, msglen
, 0));
716 dlpi_recv(dlpi_handle_t dh
, void *saddrp
, size_t *saddrlenp
, void *msgbuf
,
717 size_t *msglenp
, int msec
, dlpi_recvinfo_t
*recvp
)
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
;
728 return (DLPI_EINHANDLE
);
730 * If handle is in raw mode ignore everything except total message
733 if (dip
->dli_oflags
& DLPI_RAW
) {
734 retval
= i_dlpi_strgetmsg(dip
, msec
, NULL
, 0, 0, 0, msgbuf
,
735 msglenp
, &totmsglen
);
737 if (retval
== DLPI_SUCCESS
&& recvp
!= NULL
)
738 recvp
->dri_totmsglen
= totmsglen
;
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
;
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
)
752 * If DLPI link provides source address, store source address in
753 * 'saddrp' and source length in 'saddrlenp', else set saddrlenp to 0.
755 if (saddrp
!= NULL
&& saddrlenp
!= NULL
) {
756 if (*saddrlenp
< DLPI_PHYSADDR_MAX
)
757 return (DLPI_EINVAL
);
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
);
767 *saddrlenp
= datalen
- dip
->dli_saplen
;
768 if (*saddrlenp
> DLPI_PHYSADDR_MAX
)
771 if (dip
->dli_sapbefore
)
772 datap
+= dip
->dli_saplen
;
773 (void) memcpy(saddrp
, datap
, *saddrlenp
);
780 * If destination address requested, check and save destination
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
);
792 recvp
->dri_destaddrlen
= datalen
- dip
->dli_saplen
;
793 if (recvp
->dri_destaddrlen
> DLPI_PHYSADDR_MAX
)
796 if (dip
->dli_sapbefore
)
797 datap
+= dip
->dli_saplen
;
798 (void) memcpy(recvp
->dri_destaddr
, datap
,
799 recvp
->dri_destaddrlen
);
801 recvp
->dri_destaddrlen
= 0;
804 recvp
->dri_destaddrtype
= udatap
->dl_group_address
;
805 recvp
->dri_totmsglen
= totmsglen
;
808 return (DLPI_SUCCESS
);
812 dlpi_enabnotify(dlpi_handle_t dh
, uint_t notes
, dlpi_notifyfunc_t
*funcp
,
813 void *arg
, dlpi_notifyid_t
*id
)
817 dl_notify_req_t
*notifyreqp
;
818 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
819 dlpi_notifyent_t
*newnotifp
;
823 return (DLPI_EINHANDLE
);
825 retval
= dlpi_info((dlpi_handle_t
)dip
, &dlinfo
, 0);
826 if (retval
!= DLPI_SUCCESS
)
829 if (dip
->dli_note_processing
)
830 return (DLPI_FAILURE
);
832 if (funcp
== NULL
|| id
== NULL
)
833 return (DLPI_EINVAL
);
835 if ((~DLPI_NOTIFICATION_TYPES
& notes
) ||
836 !(notes
& DLPI_NOTIFICATION_TYPES
))
837 return (DLPI_ENOTEINVAL
);
839 DLPI_MSG_CREATE(req
, DL_NOTIFY_REQ
);
840 DLPI_MSG_CREATE(ack
, DL_NOTIFY_ACK
);
842 notifyreqp
= &(req
.dlm_msg
->notify_req
);
843 notifyreqp
->dl_notifications
= notes
;
844 notifyreqp
->dl_timelimit
= 0;
846 retval
= i_dlpi_msg_common(dip
, &req
, &ack
, DL_NOTIFY_ACK_SIZE
, 0);
847 if (retval
== DL_NOTSUPPORTED
)
848 return (DLPI_ENOTENOTSUP
);
850 if (retval
!= DLPI_SUCCESS
)
853 if ((newnotifp
= calloc(1, sizeof (dlpi_notifyent_t
))) == NULL
)
856 /* Register notification information. */
857 newnotifp
->dln_fnp
= funcp
;
858 newnotifp
->dln_notes
= notes
;
859 newnotifp
->arg
= arg
;
860 newnotifp
->dln_rm
= B_FALSE
;
862 /* Insert notification node at head */
863 newnotifp
->dln_next
= dip
->dli_notifylistp
;
864 dip
->dli_notifylistp
= newnotifp
;
866 *id
= (dlpi_notifyid_t
)newnotifp
;
867 return (DLPI_SUCCESS
);
871 dlpi_disabnotify(dlpi_handle_t dh
, dlpi_notifyid_t id
, void **argp
)
873 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
874 dlpi_notifyent_t
*remid
= (dlpi_notifyent_t
*)id
;
877 return (DLPI_EINHANDLE
);
879 /* Walk the notifyentry list to find matching id. */
880 if (!(i_dlpi_notifyidexists(dip
, remid
)))
881 return (DLPI_ENOTEIDINVAL
);
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
);
891 return (DLPI_SUCCESS
);
895 dlpi_fd(dlpi_handle_t dh
)
897 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
899 return (dip
!= NULL
? dip
->dli_fd
: -1);
903 dlpi_set_timeout(dlpi_handle_t dh
, int sec
)
905 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
908 return (DLPI_EINHANDLE
);
910 dip
->dli_timeout
= sec
;
911 return (DLPI_SUCCESS
);
915 dlpi_linkname(dlpi_handle_t dh
)
917 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
919 return (dip
!= NULL
? dip
->dli_linkname
: NULL
);
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.
928 dlpi_style(dlpi_handle_t dh
)
930 dlpi_impl_t
*dip
= (dlpi_impl_t
*)dh
;
932 return (dip
->dli_style
);
936 dlpi_arptype(uint_t dlpitype
)
941 return (ARPHRD_ETHER
);
944 return (ARPHRD_FRAME
);
950 return (ARPHRD_IPATM
);
953 return (ARPHRD_HDLC
);
958 case DL_CSMACD
: /* ieee 802 networks */
963 return (ARPHRD_IEEE802
);
970 return (ARPHRD_TUNNEL
);
977 dlpi_iftype(uint_t dlpitype
)
988 return (IFT_ISO88023
);
991 return (IFT_ISO88024
);
994 return (IFT_ISO88025
);
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)
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).
1022 * If DLPI_DEVONLY is specified, both attempt will try to open the /dev node
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.
1039 * DLPI_ENOTSTYLE2 will be returned in case 2 and 3 to indicate not to proceed
1040 * the second style-2 open attempt.
1043 i_dlpi_open(const char *provider
, int *fd
, uint_t flags
, boolean_t style1
)
1045 char path
[MAXPATHLEN
];
1050 if (flags
& DLPI_EXCL
)
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
);
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
;
1064 dladm_handle_t handle
;
1067 * This is not a valid style-1 name. It could be "ip" module
1068 * for example. Fallback to open the /dev node.
1070 if (dlpi_parselink(provider
, driver
, &ppa
) != DLPI_SUCCESS
)
1073 (void) snprintf(path
, sizeof (path
), "/dev/net/%s", provider
);
1074 if ((*fd
= open(path
, oflags
)) != -1)
1075 return (DLPI_SUCCESS
);
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.
1082 if (errno
!= ENOENT
)
1083 return (DLPI_ENOTSTYLE2
);
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.
1095 (void) snprintf(device
, DLPI_LINKNAME_MAX
, "%s%d", driver
,
1096 ppa
>= 1000 ? ppa
% 1000 : ppa
);
1098 /* open libdladm handle rather than taking it as input */
1099 if (dladm_open(&handle
) != DLADM_STATUS_OK
)
1102 if (dladm_dev2linkid(handle
, device
, &linkid
) ==
1104 dladm_phys_attr_t dpa
;
1106 if ((dladm_phys_info(handle
, linkid
, &dpa
,
1107 DLADM_OPT_ACTIVE
)) == DLADM_STATUS_OK
&&
1109 dladm_close(handle
);
1110 return (DLPI_ENOTSTYLE2
);
1113 dladm_close(handle
);
1117 (void) snprintf(path
, sizeof (path
), "/dev/%s", provider
);
1118 if ((*fd
= open(path
, oflags
)) != -1)
1119 return (DLPI_SUCCESS
);
1121 return (errno
== ENOENT
? DLPI_ENOLINK
: DL_SYSERR
);
1125 * Open a style 1 link. PPA is implicitly attached.
1128 i_dlpi_style1_open(dlpi_impl_t
*dip
)
1130 int retval
, save_errno
;
1133 retval
= i_dlpi_open(dip
->dli_linkname
, &fd
, dip
->dli_oflags
, B_TRUE
);
1134 if (retval
!= DLPI_SUCCESS
)
1138 if ((retval
= i_dlpi_checkstyle(dip
, DL_STYLE1
)) != DLPI_SUCCESS
) {
1140 (void) close(dip
->dli_fd
);
1148 * Open a style 2 link. PPA must be explicitly attached.
1151 i_dlpi_style2_open(dlpi_impl_t
*dip
)
1154 int retval
, save_errno
;
1156 retval
= i_dlpi_open(dip
->dli_provider
, &fd
, dip
->dli_oflags
, B_FALSE
);
1157 if (retval
!= DLPI_SUCCESS
)
1162 * Special case: DLPI_SERIAL flag (synchronous serial lines) is not a
1163 * DLPI link so attach and ignore rest.
1165 if (dip
->dli_oflags
& DLPI_SERIAL
)
1168 if ((retval
= i_dlpi_checkstyle(dip
, DL_STYLE2
)) != DLPI_SUCCESS
)
1172 * Succeeded opening the link and verified it is style2. Now attach to
1173 * PPA only if DLPI_NOATTACH is not set.
1175 if (dip
->dli_oflags
& DLPI_NOATTACH
)
1176 return (DLPI_SUCCESS
);
1179 if ((retval
= i_dlpi_attach(dip
)) == DLPI_SUCCESS
)
1180 return (DLPI_SUCCESS
);
1184 (void) close(dip
->dli_fd
);
1190 * Verify with DLPI that the link is the expected DLPI 'style' device,
1191 * dlpi_info sets the DLPI style in the DLPI handle.
1194 i_dlpi_checkstyle(dlpi_impl_t
*dip
, t_uscalar_t style
)
1199 retval
= dlpi_info((dlpi_handle_t
)dip
, &dlinfo
, 0);
1200 if (retval
== DLPI_SUCCESS
&& dip
->dli_style
!= style
)
1201 retval
= DLPI_EBADLINK
;
1207 * For DLPI style 2 providers, an explicit attach of PPA is required.
1210 i_dlpi_attach(dlpi_impl_t
*dip
)
1212 dlpi_msg_t req
, ack
;
1213 dl_attach_req_t
*attachreqp
;
1216 * Special case: DLPI_SERIAL flag (synchronous serial lines)
1217 * is not a DLPI link so ignore DLPI style.
1219 if (dip
->dli_style
!= DL_STYLE2
&& !(dip
->dli_oflags
& DLPI_SERIAL
))
1220 return (DLPI_ENOTSTYLE2
);
1222 DLPI_MSG_CREATE(req
, DL_ATTACH_REQ
);
1223 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
1225 attachreqp
= &(req
.dlm_msg
->attach_req
);
1226 attachreqp
->dl_ppa
= dip
->dli_ppa
;
1228 return (i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0));
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).
1239 i_dlpi_passive(dlpi_impl_t
*dip
)
1241 dlpi_msg_t req
, ack
;
1243 DLPI_MSG_CREATE(req
, DL_PASSIVE_REQ
);
1244 DLPI_MSG_CREATE(ack
, DL_OK_ACK
);
1246 (void) i_dlpi_msg_common(dip
, &req
, &ack
, DL_OK_ACK_SIZE
, 0);
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.
1260 i_dlpi_strputmsg(dlpi_impl_t
*dip
, const dlpi_msg_t
*dlreqp
,
1261 const void *databuf
, size_t datalen
, int flags
)
1264 int fd
= dip
->dli_fd
;
1268 if (dlreqp
!= NULL
) {
1269 ctl
.buf
= (void *)dlreqp
->dlm_msg
;
1270 ctl
.len
= dlreqp
->dlm_msgsz
;
1273 data
.buf
= (void *)databuf
;
1276 retval
= putmsg(fd
, (dlreqp
== NULL
? NULL
: &ctl
),
1277 (databuf
== NULL
? NULL
: &data
), flags
);
1279 return ((retval
== 0) ? DLPI_SUCCESS
: DL_SYSERR
);
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
1303 i_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
)
1309 int fd
= dip
->dli_fd
;
1310 struct strbuf ctl
, data
;
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 */
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
1325 if ((databuf
== NULL
&& datalenp
!= NULL
) ||
1326 (databuf
!= NULL
&& datalenp
== NULL
))
1327 return (DLPI_EINVAL
);
1330 pfd
.events
= POLLIN
| POLLPRI
;
1332 ctl
.buf
= (dlreplyp
== NULL
) ? bufc
: (void *)dlreplyp
->dlm_msg
;
1334 ctl
.maxlen
= (dlreplyp
== NULL
) ? sizeof (bufc
) : dlreplyp
->dlm_msgsz
;
1336 data
.buf
= (databuf
== NULL
) ? bufd
: databuf
;
1338 data
.maxlen
= (databuf
== NULL
) ? sizeof (bufd
): *datalenp
;
1342 start
= NSEC2MSEC(gethrtime());
1344 switch (poll(&pfd
, 1, msec
)) {
1346 if (pfd
.revents
& POLLHUP
)
1350 return (DLPI_ETIMEDOUT
);
1356 if ((retval
= getmsg(fd
, &ctl
, &data
, &flags
)) < 0)
1359 if (totdatalenp
!= NULL
)
1360 *totdatalenp
= data
.len
;
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.
1373 while (retval
& (MORECTL
| MOREDATA
)) {
1374 struct strbuf cscratch
, dscratch
;
1377 cscratch
.buf
= (char *)bufc
;
1378 dscratch
.buf
= (char *)bufd
;
1379 cscratch
.len
= dscratch
.len
= 0;
1380 cscratch
.maxlen
= dscratch
.maxlen
=
1383 if ((retval
= getmsg(fd
, &cscratch
, &dscratch
,
1387 if (totdatalenp
!= NULL
)
1388 *totdatalenp
+= dscratch
.len
;
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.
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
,
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.
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
);
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
1427 if (databuf
!= NULL
&& data
.len
>= 0) {
1428 *datalenp
= data
.len
;
1429 if (dlreplyp
== NULL
)
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.
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
;
1446 } else if (dlprim
->dl_primitive
== DL_ERROR_ACK
) {
1447 if (ctl
.len
< DL_ERROR_ACK_SIZE
)
1448 return (DLPI_EBADMSG
);
1451 if (dlprim
->error_ack
.dl_error_primitive
==
1458 current
= NSEC2MSEC(gethrtime());
1459 msec
-= (current
- start
);
1462 return (DLPI_ETIMEDOUT
);
1466 return (DLPI_SUCCESS
);
1470 * Common routine invoked by all DLPI control routines. The inputs for this
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
1484 i_dlpi_msg_common(dlpi_impl_t
*dip
, const dlpi_msg_t
*dlreqp
,
1485 dlpi_msg_t
*dlreplyp
, size_t dlreplyminsz
, int flags
)
1488 t_uscalar_t dlreqprim
= dlreqp
->dlm_msg
->dl_primitive
;
1489 t_uscalar_t dlreplyprim
= dlreplyp
->dlm_msg
->dl_primitive
;
1491 /* Put the requested primitive on the stream. */
1492 retval
= i_dlpi_strputmsg(dip
, dlreqp
, NULL
, 0, flags
);
1493 if (retval
!= DLPI_SUCCESS
)
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
)
1503 * If primitive is DL_ERROR_ACK, set errno.
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
;
1516 static 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 */
1553 * libdlpi error codes.
1555 static 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 */
1578 dlpi_strerror(int err
)
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
-
1588 return (dgettext(TEXT_DOMAIN
, "Unknown DLPI error"));
1592 * Each table entry comprises a DLPI/Private mactype and the description.
1594 static 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" },
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" }
1627 dlpi_mactype(uint_t mactype
)
1631 for (i
= 0; i
< NELEMS(dlpi_mactypes
); i
++) {
1632 if (dlpi_mactypes
[i
].dm_mactype
== mactype
)
1633 return (dlpi_mactypes
[i
].dm_desc
);
1636 return ("Unknown MAC Type");
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).
1643 static 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
+
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
+
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
+
1672 * Refers to the dlpi_primsizes[] table to return corresponding maximum
1676 i_dlpi_getprimsize(t_uscalar_t prim
)
1680 for (i
= 0; i
< NELEMS(dlpi_primsizes
); i
++) {
1681 if (dlpi_primsizes
[i
].dp_prim
== prim
)
1682 return (dlpi_primsizes
[i
].dp_primsz
);
1685 return (sizeof (t_uscalar_t
));
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.
1693 i_dlpi_buildsap(uint8_t *sapp
, uint_t saplen
)
1698 #ifdef _LITTLE_ENDIAN
1699 for (i
= saplen
- 1; i
>= 0; i
--) {
1701 for (i
= 0; i
< saplen
; i
++) {
1711 * Copy sap value to a buffer in host byte order. saplen is the number of
1715 i_dlpi_writesap(void *dstbuf
, uint_t sap
, uint_t saplen
)
1719 #ifdef _LITTLE_ENDIAN
1720 sapp
= (uint8_t *)&sap
;
1722 sapp
= (uint8_t *)&sap
+ (sizeof (sap
) - saplen
);
1725 (void) memcpy(dstbuf
, sapp
, saplen
);
1729 * Fill notification payload and callback each registered functions.
1730 * Delete nodes if any was called while processing.
1733 i_dlpi_notifyind_process(dlpi_impl_t
*dip
, dl_notify_ind_t
*dlnotifyindp
)
1735 dlpi_notifyinfo_t notifinfo
;
1736 t_uscalar_t dataoff
, datalen
;
1738 dlpi_notifyent_t
*dnp
;
1739 uint_t note
= dlnotifyindp
->dl_notification
;
1740 uint_t deletenode
= B_FALSE
;
1742 notifinfo
.dni_note
= note
;
1746 notifinfo
.dni_speed
= dlnotifyindp
->dl_data
;
1748 case DL_NOTE_SDU_SIZE
:
1749 notifinfo
.dni_size
= dlnotifyindp
->dl_data
;
1751 case DL_NOTE_PHYS_ADDR
:
1753 * libdlpi currently only supports notifications for
1754 * DL_CURR_PHYS_ADDR.
1756 if (dlnotifyindp
->dl_data
!= DL_CURR_PHYS_ADDR
)
1757 return (DLPI_ENOTENOTSUP
);
1759 dataoff
= dlnotifyindp
->dl_addr_offset
;
1760 datalen
= dlnotifyindp
->dl_addr_length
;
1762 if (dataoff
== 0 || datalen
== 0)
1763 return (DLPI_EBADMSG
);
1765 datap
= (caddr_t
)dlnotifyindp
+ dataoff
;
1766 if (dataoff
< DL_NOTIFY_IND_SIZE
)
1767 return (DLPI_EBADMSG
);
1769 notifinfo
.dni_physaddrlen
= datalen
- dip
->dli_saplen
;
1771 if (notifinfo
.dni_physaddrlen
> DLPI_PHYSADDR_MAX
)
1772 return (DL_BADADDR
);
1774 (void) memcpy(notifinfo
.dni_physaddr
, datap
,
1775 notifinfo
.dni_physaddrlen
);
1779 dip
->dli_note_processing
= B_TRUE
;
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
, ¬ifinfo
, dnp
->arg
);
1785 deletenode
= B_TRUE
;
1788 dip
->dli_note_processing
= B_FALSE
;
1790 /* Walk the notifyentry list to unregister marked entries. */
1792 i_dlpi_deletenotifyid(dip
);
1794 return (DLPI_SUCCESS
);
1797 * Find registered notification.
1800 i_dlpi_notifyidexists(dlpi_impl_t
*dip
, dlpi_notifyent_t
*id
)
1802 dlpi_notifyent_t
*dnp
;
1804 for (dnp
= dip
->dli_notifylistp
; dnp
!= NULL
; dnp
= dnp
->dln_next
) {
1813 * Walk the list of notifications and deleted nodes marked to be deleted.
1816 i_dlpi_deletenotifyid(dlpi_impl_t
*dip
)
1818 dlpi_notifyent_t
*prev
, *dnp
;
1821 dnp
= dip
->dli_notifylistp
;
1822 while (dnp
!= NULL
) {
1825 dnp
= dnp
->dln_next
;
1826 } else if (prev
== NULL
) {
1827 dip
->dli_notifylistp
= dnp
->dln_next
;
1829 dnp
= dip
->dli_notifylistp
;
1831 prev
->dln_next
= dnp
->dln_next
;
1833 dnp
= prev
->dln_next
;