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 * Common Sun DLPI routines.
30 #include <sys/types.h>
31 #include <sys/sysmacros.h>
32 #include <sys/byteorder.h>
33 #include <sys/stream.h>
34 #include <sys/strsun.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunldi.h>
39 #include <sys/cmn_err.h>
48 t_uscalar_t maxconind
,
51 union DL_primitives
*dlp
;
54 size
= sizeof (dl_bind_ack_t
) + addrlen
;
55 if ((mp
= mexchange(wq
, mp
, size
, M_PCPROTO
, DL_BIND_ACK
)) == NULL
)
58 dlp
= (union DL_primitives
*)mp
->b_rptr
;
59 dlp
->bind_ack
.dl_sap
= sap
;
60 dlp
->bind_ack
.dl_addr_length
= addrlen
;
61 dlp
->bind_ack
.dl_addr_offset
= sizeof (dl_bind_ack_t
);
62 dlp
->bind_ack
.dl_max_conind
= maxconind
;
63 dlp
->bind_ack
.dl_xidtest_flg
= xidtest
;
65 bcopy(addrp
, mp
->b_rptr
+ sizeof (dl_bind_ack_t
), addrlen
);
73 t_uscalar_t correct_primitive
)
75 union DL_primitives
*dlp
;
77 if ((mp
= mexchange(wq
, mp
, sizeof (dl_ok_ack_t
), M_PCPROTO
,
80 dlp
= (union DL_primitives
*)mp
->b_rptr
;
81 dlp
->ok_ack
.dl_correct_primitive
= correct_primitive
;
89 t_uscalar_t error_primitive
,
91 t_uscalar_t unix_errno
)
93 union DL_primitives
*dlp
;
95 if ((mp
= mexchange(wq
, mp
, sizeof (dl_error_ack_t
), M_PCPROTO
,
96 DL_ERROR_ACK
)) == NULL
)
98 dlp
= (union DL_primitives
*)mp
->b_rptr
;
99 dlp
->error_ack
.dl_error_primitive
= error_primitive
;
100 dlp
->error_ack
.dl_errno
= error
;
101 dlp
->error_ack
.dl_unix_errno
= unix_errno
;
112 t_uscalar_t unix_errno
)
114 union DL_primitives
*dlp
;
117 size
= sizeof (dl_uderror_ind_t
) + addrlen
;
118 if ((mp
= mexchange(wq
, mp
, size
, M_PCPROTO
, DL_UDERROR_IND
)) == NULL
)
121 dlp
= (union DL_primitives
*)mp
->b_rptr
;
122 dlp
->uderror_ind
.dl_dest_addr_length
= addrlen
;
123 dlp
->uderror_ind
.dl_dest_addr_offset
= sizeof (dl_uderror_ind_t
);
124 dlp
->uderror_ind
.dl_unix_errno
= unix_errno
;
125 dlp
->uderror_ind
.dl_errno
= error
;
127 bcopy(addrp
, mp
->b_rptr
+ sizeof (dl_uderror_ind_t
), addrlen
);
138 union DL_primitives
*dlp
;
141 size
= sizeof (dl_phys_addr_ack_t
) + len
;
142 if ((mp
= mexchange(wq
, mp
, size
, M_PCPROTO
, DL_PHYS_ADDR_ACK
)) == NULL
)
144 dlp
= (union DL_primitives
*)mp
->b_rptr
;
145 dlp
->physaddr_ack
.dl_addr_length
= len
;
146 dlp
->physaddr_ack
.dl_addr_offset
= sizeof (dl_phys_addr_ack_t
);
148 bcopy(addrp
, mp
->b_rptr
+ sizeof (dl_phys_addr_ack_t
), len
);
153 dlcapabsetqid(dl_mid_t
*idp
, const queue_t
*q
)
156 idp
->mid
[0] = (t_uscalar_t
)q
;
158 idp
->mid
[0] = (t_uscalar_t
)BMASK_32((uint64_t)q
);
159 idp
->mid
[1] = (t_uscalar_t
)BMASK_32(((uint64_t)q
) >> 32);
164 dlcapabcheckqid(const dl_mid_t
*idp
, const queue_t
*q
)
167 return ((queue_t
*)(idp
->mid
[0]) == q
);
170 ((uint64_t)idp
->mid
[0] | ((uint64_t)idp
->mid
[1] << 32)) == q
);
178 uint32_t notifications
)
180 union DL_primitives
*dlp
;
182 if ((mp
= mexchange(wq
, mp
, sizeof (dl_notify_ack_t
), M_PROTO
,
183 DL_NOTIFY_ACK
)) == NULL
)
185 dlp
= (union DL_primitives
*)mp
->b_rptr
;
186 dlp
->notify_ack
.dl_notifications
= notifications
;
191 dl_op(ldi_handle_t lh
, mblk_t
**mpp
, t_uscalar_t expprim
, size_t minlen
,
192 dl_error_ack_t
*dleap
, timestruc_t
*tvp
)
197 t_uscalar_t reqprim
, ackprim
, ackreqprim
;
198 union DL_primitives
*dlp
;
200 reqprim
= ((union DL_primitives
*)mp
->b_rptr
)->dl_primitive
;
202 (void) ldi_putmsg(lh
, mp
);
204 switch (err
= ldi_getmsg(lh
, &mp
, tvp
)) {
208 cmn_err(CE_NOTE
, "!dl_op: timed out waiting for %s to %s",
209 dl_primstr(reqprim
), dl_primstr(expprim
));
212 cmn_err(CE_NOTE
, "!dl_op: ldi_getmsg() for %s failed: %d",
213 dl_primstr(expprim
), err
);
218 if (len
< sizeof (t_uscalar_t
)) {
219 cmn_err(CE_NOTE
, "!dl_op: received runt DLPI message");
224 dlp
= (union DL_primitives
*)mp
->b_rptr
;
225 ackprim
= dlp
->dl_primitive
;
227 if (ackprim
== expprim
) {
231 if (ackprim
== DL_OK_ACK
) {
232 if (dlp
->ok_ack
.dl_correct_primitive
!= reqprim
) {
233 ackreqprim
= dlp
->ok_ack
.dl_correct_primitive
;
241 if (ackprim
== DL_ERROR_ACK
) {
242 if (len
< DL_ERROR_ACK_SIZE
)
245 if (dlp
->error_ack
.dl_error_primitive
!= reqprim
) {
246 ackreqprim
= dlp
->error_ack
.dl_error_primitive
;
251 * Return a special error code (ENOTSUP) indicating that the
252 * caller has returned DL_ERROR_ACK. Callers that want more
253 * details an pass a non-NULL dleap.
256 *dleap
= dlp
->error_ack
;
262 cmn_err(CE_NOTE
, "!dl_op: expected %s but received %s",
263 dl_primstr(expprim
), dl_primstr(ackprim
));
267 cmn_err(CE_NOTE
, "!dl_op: received runt %s", dl_primstr(ackprim
));
271 cmn_err(CE_NOTE
, "!dl_op: received %s for %s instead of %s",
272 dl_primstr(ackprim
), dl_primstr(ackreqprim
), dl_primstr(reqprim
));
278 * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response.
280 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
281 * caller can get the contents by passing a non-NULL `dleap').
284 dl_attach(ldi_handle_t lh
, int ppa
, dl_error_ack_t
*dleap
)
289 mp
= mexchange(NULL
, NULL
, DL_ATTACH_REQ_SIZE
, M_PROTO
, DL_ATTACH_REQ
);
293 ((dl_attach_req_t
*)mp
->b_rptr
)->dl_ppa
= ppa
;
295 err
= dl_op(lh
, &mp
, DL_OK_ACK
, DL_OK_ACK_SIZE
, dleap
, NULL
);
302 * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response.
304 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
305 * caller can get the contents by passing a non-NULL `dleap').
308 dl_bind(ldi_handle_t lh
, uint_t sap
, dl_error_ack_t
*dleap
)
310 dl_bind_req_t
*dlbrp
;
311 dl_bind_ack_t
*dlbap
;
315 mp
= mexchange(NULL
, NULL
, DL_BIND_REQ_SIZE
, M_PROTO
, DL_BIND_REQ
);
319 dlbrp
= (dl_bind_req_t
*)mp
->b_rptr
;
321 dlbrp
->dl_conn_mgmt
= 0;
322 dlbrp
->dl_max_conind
= 0;
323 dlbrp
->dl_xidtest_flg
= 0;
324 dlbrp
->dl_service_mode
= DL_CLDLS
;
326 err
= dl_op(lh
, &mp
, DL_BIND_ACK
, DL_BIND_ACK_SIZE
, dleap
, NULL
);
328 dlbap
= (dl_bind_ack_t
*)mp
->b_rptr
;
329 if (dlbap
->dl_sap
!= sap
) {
330 cmn_err(CE_NOTE
, "!dl_bind: DL_BIND_ACK: bad sap %u",
340 * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response. The caller
341 * must set `*physlenp' to the size of `physaddr' (both of which must be
342 * non-NULL); upon success they will be updated to contain the actual physical
343 * address and length.
345 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
346 * caller can get the contents by passing a non-NULL `dleap').
349 dl_phys_addr(ldi_handle_t lh
, uchar_t
*physaddr
, size_t *physlenp
,
350 dl_error_ack_t
*dleap
)
352 dl_phys_addr_ack_t
*dlpap
;
355 t_uscalar_t paddrlen
, paddroff
;
358 mp
= mexchange(NULL
, NULL
, DL_PHYS_ADDR_REQ_SIZE
, M_PROTO
,
363 ((dl_phys_addr_req_t
*)mp
->b_rptr
)->dl_addr_type
= DL_CURR_PHYS_ADDR
;
366 * In case some provider doesn't implement or NAK the
367 * request, just wait for 15 seconds.
372 err
= dl_op(lh
, &mp
, DL_PHYS_ADDR_ACK
, DL_PHYS_ADDR_ACK_SIZE
, dleap
,
375 dlpap
= (dl_phys_addr_ack_t
*)mp
->b_rptr
;
376 paddrlen
= dlpap
->dl_addr_length
;
377 paddroff
= dlpap
->dl_addr_offset
;
378 if (paddroff
== 0 || paddrlen
== 0 || paddrlen
> *physlenp
||
379 !MBLKIN(mp
, paddroff
, paddrlen
)) {
380 cmn_err(CE_NOTE
, "!dl_phys_addr: DL_PHYS_ADDR_ACK: "
381 "bad length/offset %d/%d", paddrlen
, paddroff
);
384 bcopy(mp
->b_rptr
+ paddroff
, physaddr
, paddrlen
);
385 *physlenp
= paddrlen
;
393 * Send a DL_INFO_REQ over `lh' and wait for the response. The caller must
394 * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t
395 * from the provider. The caller may optionally get the provider's physical
396 * address by passing a non-NULL `physaddr' and setting `*physlenp' to its
397 * size; upon success they will be updated to contain the actual physical
398 * address and its length.
400 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
401 * caller can get the contents by passing a non-NULL `dleap').
404 dl_info(ldi_handle_t lh
, dl_info_ack_t
*dliap
, uchar_t
*physaddr
,
405 size_t *physlenp
, dl_error_ack_t
*dleap
)
409 int addrlen
, addroff
;
411 mp
= mexchange(NULL
, NULL
, DL_INFO_REQ_SIZE
, M_PCPROTO
, DL_INFO_REQ
);
415 err
= dl_op(lh
, &mp
, DL_INFO_ACK
, DL_INFO_ACK_SIZE
, dleap
, NULL
);
419 *dliap
= *(dl_info_ack_t
*)mp
->b_rptr
;
420 if (physaddr
!= NULL
) {
421 addrlen
= dliap
->dl_addr_length
- ABS(dliap
->dl_sap_length
);
422 addroff
= dliap
->dl_addr_offset
;
423 if (addroff
== 0 || addrlen
<= 0 || addrlen
> *physlenp
||
424 !MBLKIN(mp
, addroff
, dliap
->dl_addr_length
)) {
425 cmn_err(CE_NOTE
, "!dl_info: DL_INFO_ACK: "
426 "bad length/offset %d/%d", addrlen
, addroff
);
431 if (dliap
->dl_sap_length
> 0)
432 addroff
+= dliap
->dl_sap_length
;
433 bcopy(mp
->b_rptr
+ addroff
, physaddr
, addrlen
);
441 * Send a DL_NOTIFY_REQ over `lh' and wait for the response. The caller
442 * should set `notesp' to the set of notifications they wish to enable;
443 * upon success it will contain the notifications enabled by the provider.
445 * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
446 * caller can get the contents by passing a non-NULL `dleap').
449 dl_notify(ldi_handle_t lh
, uint32_t *notesp
, dl_error_ack_t
*dleap
)
454 mp
= mexchange(NULL
, NULL
, DL_NOTIFY_REQ_SIZE
, M_PROTO
, DL_NOTIFY_REQ
);
458 ((dl_notify_req_t
*)mp
->b_rptr
)->dl_notifications
= *notesp
;
460 err
= dl_op(lh
, &mp
, DL_NOTIFY_ACK
, DL_NOTIFY_ACK_SIZE
, dleap
, NULL
);
462 *notesp
= ((dl_notify_ack_t
*)mp
->b_rptr
)->dl_notifications
;
469 dl_primstr(t_uscalar_t prim
)
472 case DL_INFO_REQ
: return ("DL_INFO_REQ");
473 case DL_INFO_ACK
: return ("DL_INFO_ACK");
474 case DL_ATTACH_REQ
: return ("DL_ATTACH_REQ");
475 case DL_DETACH_REQ
: return ("DL_DETACH_REQ");
476 case DL_BIND_REQ
: return ("DL_BIND_REQ");
477 case DL_BIND_ACK
: return ("DL_BIND_ACK");
478 case DL_UNBIND_REQ
: return ("DL_UNBIND_REQ");
479 case DL_OK_ACK
: return ("DL_OK_ACK");
480 case DL_ERROR_ACK
: return ("DL_ERROR_ACK");
481 case DL_ENABMULTI_REQ
: return ("DL_ENABMULTI_REQ");
482 case DL_DISABMULTI_REQ
: return ("DL_DISABMULTI_REQ");
483 case DL_PROMISCON_REQ
: return ("DL_PROMISCON_REQ");
484 case DL_PROMISCOFF_REQ
: return ("DL_PROMISCOFF_REQ");
485 case DL_UNITDATA_REQ
: return ("DL_UNITDATA_REQ");
486 case DL_UNITDATA_IND
: return ("DL_UNITDATA_IND");
487 case DL_UDERROR_IND
: return ("DL_UDERROR_IND");
488 case DL_PHYS_ADDR_REQ
: return ("DL_PHYS_ADDR_REQ");
489 case DL_PHYS_ADDR_ACK
: return ("DL_PHYS_ADDR_ACK");
490 case DL_SET_PHYS_ADDR_REQ
: return ("DL_SET_PHYS_ADDR_REQ");
491 case DL_NOTIFY_REQ
: return ("DL_NOTIFY_REQ");
492 case DL_NOTIFY_ACK
: return ("DL_NOTIFY_ACK");
493 case DL_NOTIFY_IND
: return ("DL_NOTIFY_IND");
494 case DL_NOTIFY_CONF
: return ("DL_NOTIFY_CONF");
495 case DL_CAPABILITY_REQ
: return ("DL_CAPABILITY_REQ");
496 case DL_CAPABILITY_ACK
: return ("DL_CAPABILITY_ACK");
497 case DL_CONTROL_REQ
: return ("DL_CONTROL_REQ");
498 case DL_CONTROL_ACK
: return ("DL_CONTROL_ACK");
499 case DL_PASSIVE_REQ
: return ("DL_PASSIVE_REQ");
500 case DL_INTR_MODE_REQ
: return ("DL_INTR_MODE_REQ");
501 case DL_UDQOS_REQ
: return ("DL_UDQOS_REQ");
502 default: return ("<unknown primitive>");
507 dl_errstr(t_uscalar_t err
)
510 case DL_ACCESS
: return ("DL_ACCESS");
511 case DL_BADADDR
: return ("DL_BADADDR");
512 case DL_BADCORR
: return ("DL_BADCORR");
513 case DL_BADDATA
: return ("DL_BADDATA");
514 case DL_BADPPA
: return ("DL_BADPPA");
515 case DL_BADPRIM
: return ("DL_BADPRIM");
516 case DL_BADQOSPARAM
: return ("DL_BADQOSPARAM");
517 case DL_BADQOSTYPE
: return ("DL_BADQOSTYPE");
518 case DL_BADSAP
: return ("DL_BADSAP");
519 case DL_BADTOKEN
: return ("DL_BADTOKEN");
520 case DL_BOUND
: return ("DL_BOUND");
521 case DL_INITFAILED
: return ("DL_INITFAILED");
522 case DL_NOADDR
: return ("DL_NOADDR");
523 case DL_NOTINIT
: return ("DL_NOTINIT");
524 case DL_OUTSTATE
: return ("DL_OUTSTATE");
525 case DL_SYSERR
: return ("DL_SYSERR");
526 case DL_UNSUPPORTED
: return ("DL_UNSUPPORTED");
527 case DL_UNDELIVERABLE
: return ("DL_UNDELIVERABLE");
528 case DL_NOTSUPPORTED
: return ("DL_NOTSUPPORTED ");
529 case DL_TOOMANY
: return ("DL_TOOMANY");
530 case DL_NOTENAB
: return ("DL_NOTENAB");
531 case DL_BUSY
: return ("DL_BUSY");
532 case DL_NOAUTO
: return ("DL_NOAUTO");
533 case DL_NOXIDAUTO
: return ("DL_NOXIDAUTO");
534 case DL_NOTESTAUTO
: return ("DL_NOTESTAUTO");
535 case DL_XIDAUTO
: return ("DL_XIDAUTO");
536 case DL_TESTAUTO
: return ("DL_TESTAUTO");
537 case DL_PENDING
: return ("DL_PENDING");
538 default: return ("<unknown error>");
543 dl_mactypestr(t_uscalar_t mactype
)
546 case DL_CSMACD
: return ("CSMA/CD");
547 case DL_TPB
: return ("Token Bus");
548 case DL_TPR
: return ("Token Ring");
549 case DL_METRO
: return ("Metro Net");
550 case DL_ETHER
: return ("Ethernet");
551 case DL_HDLC
: return ("HDLC");
552 case DL_CHAR
: return ("Sync Character");
553 case DL_CTCA
: return ("CTCA");
554 case DL_FDDI
: return ("FDDI");
555 case DL_FRAME
: return ("Frame Relay (LAPF)");
556 case DL_MPFRAME
: return ("MP Frame Relay");
557 case DL_ASYNC
: return ("Async Character");
558 case DL_IPX25
: return ("X.25 (Classic IP)");
559 case DL_LOOP
: return ("Software Loopback");
560 case DL_FC
: return ("Fiber Channel");
561 case DL_ATM
: return ("ATM");
562 case DL_IPATM
: return ("ATM (Classic IP)");
563 case DL_X25
: return ("X.25 (LAPB)");
564 case DL_ISDN
: return ("ISDN");
565 case DL_HIPPI
: return ("HIPPI");
566 case DL_100VG
: return ("100BaseVG Ethernet");
567 case DL_100VGTPR
: return ("100BaseVG Token Ring");
568 case DL_ETH_CSMA
: return ("Ethernet/IEEE 802.3");
569 case DL_100BT
: return ("100BaseT");
570 case DL_IB
: return ("Infiniband");
571 case DL_IPV4
: return ("IPv4 Tunnel");
572 case DL_IPV6
: return ("IPv6 Tunnel");
573 case DL_WIFI
: return ("IEEE 802.11");
574 case DL_IPNET
: return ("IPNET");
575 default: return ("<unknown mactype>");