Home | History | Annotate | Download | only in io
      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  *  Common Sun DLPI routines.
     28  */
     29 
     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>
     35 #include <sys/dlpi.h>
     36 #include <sys/ddi.h>
     37 #include <sys/sunddi.h>
     38 #include <sys/sunldi.h>
     39 #include <sys/cmn_err.h>
     40 
     41 void
     42 dlbindack(
     43 	queue_t		*wq,
     44 	mblk_t		*mp,
     45 	t_scalar_t	sap,
     46 	const void	*addrp,
     47 	t_uscalar_t	addrlen,
     48 	t_uscalar_t	maxconind,
     49 	t_uscalar_t	xidtest)
     50 {
     51 	union DL_primitives	*dlp;
     52 	size_t			size;
     53 
     54 	size = sizeof (dl_bind_ack_t) + addrlen;
     55 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
     56 		return;
     57 
     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;
     64 	if (addrlen != 0)
     65 		bcopy(addrp, mp->b_rptr + sizeof (dl_bind_ack_t), addrlen);
     66 	qreply(wq, mp);
     67 }
     68 
     69 void
     70 dlokack(
     71 	queue_t		*wq,
     72 	mblk_t		*mp,
     73 	t_uscalar_t	correct_primitive)
     74 {
     75 	union DL_primitives	*dlp;
     76 
     77 	if ((mp = mexchange(wq, mp, sizeof (dl_ok_ack_t), M_PCPROTO,
     78 	    DL_OK_ACK)) == NULL)
     79 		return;
     80 	dlp = (union DL_primitives *)mp->b_rptr;
     81 	dlp->ok_ack.dl_correct_primitive = correct_primitive;
     82 	qreply(wq, mp);
     83 }
     84 
     85 void
     86 dlerrorack(
     87 	queue_t		*wq,
     88 	mblk_t		*mp,
     89 	t_uscalar_t	error_primitive,
     90 	t_uscalar_t	error,
     91 	t_uscalar_t	unix_errno)
     92 {
     93 	union DL_primitives	*dlp;
     94 
     95 	if ((mp = mexchange(wq, mp, sizeof (dl_error_ack_t), M_PCPROTO,
     96 	    DL_ERROR_ACK)) == NULL)
     97 		return;
     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;
    102 	qreply(wq, mp);
    103 }
    104 
    105 void
    106 dluderrorind(
    107 	queue_t		*wq,
    108 	mblk_t		*mp,
    109 	const void	*addrp,
    110 	t_uscalar_t	addrlen,
    111 	t_uscalar_t	error,
    112 	t_uscalar_t	unix_errno)
    113 {
    114 	union DL_primitives	*dlp;
    115 	size_t			size;
    116 
    117 	size = sizeof (dl_uderror_ind_t) + addrlen;
    118 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_UDERROR_IND)) == NULL)
    119 		return;
    120 
    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;
    126 	if (addrlen != 0)
    127 		bcopy(addrp, mp->b_rptr + sizeof (dl_uderror_ind_t), addrlen);
    128 	qreply(wq, mp);
    129 }
    130 
    131 void
    132 dlphysaddrack(
    133 	queue_t		*wq,
    134 	mblk_t		*mp,
    135 	const void	*addrp,
    136 	t_uscalar_t	len)
    137 {
    138 	union DL_primitives	*dlp;
    139 	size_t			size;
    140 
    141 	size = sizeof (dl_phys_addr_ack_t) + len;
    142 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_PHYS_ADDR_ACK)) == NULL)
    143 		return;
    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);
    147 	if (len != 0)
    148 		bcopy(addrp, mp->b_rptr + sizeof (dl_phys_addr_ack_t), len);
    149 	qreply(wq, mp);
    150 }
    151 
    152 void
    153 dlcapabsetqid(dl_mid_t *idp, const queue_t *q)
    154 {
    155 #ifndef _LP64
    156 	idp->mid[0] = (t_uscalar_t)q;
    157 #else
    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);
    160 #endif
    161 }
    162 
    163 boolean_t
    164 dlcapabcheckqid(const dl_mid_t *idp, const queue_t *q)
    165 {
    166 #ifndef _LP64
    167 	return ((queue_t *)(idp->mid[0]) == q);
    168 #else
    169 	return ((queue_t *)
    170 	    ((uint64_t)idp->mid[0] | ((uint64_t)idp->mid[1] << 32)) == q);
    171 #endif
    172 }
    173 
    174 void
    175 dlnotifyack(
    176 	queue_t		*wq,
    177 	mblk_t		*mp,
    178 	uint32_t	notifications)
    179 {
    180 	union DL_primitives	*dlp;
    181 
    182 	if ((mp = mexchange(wq, mp, sizeof (dl_notify_ack_t), M_PROTO,
    183 	    DL_NOTIFY_ACK)) == NULL)
    184 		return;
    185 	dlp = (union DL_primitives *)mp->b_rptr;
    186 	dlp->notify_ack.dl_notifications = notifications;
    187 	qreply(wq, mp);
    188 }
    189 
    190 static int
    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)
    193 {
    194 	int		err;
    195 	size_t		len;
    196 	mblk_t		*mp = *mpp;
    197 	t_uscalar_t	reqprim, ackprim, ackreqprim;
    198 	union DL_primitives *dlp;
    199 
    200 	reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
    201 
    202 	(void) ldi_putmsg(lh, mp);
    203 
    204 	switch (err = ldi_getmsg(lh, &mp, tvp)) {
    205 	case 0:
    206 		break;
    207 	case ETIME:
    208 		cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s",
    209 		    dl_primstr(reqprim), dl_primstr(expprim));
    210 		return (ETIME);
    211 	default:
    212 		cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d",
    213 		    dl_primstr(expprim), err);
    214 		return (err);
    215 	}
    216 
    217 	len = MBLKL(mp);
    218 	if (len < sizeof (t_uscalar_t)) {
    219 		cmn_err(CE_NOTE, "!dl_op: received runt DLPI message");
    220 		freemsg(mp);
    221 		return (EBADMSG);
    222 	}
    223 
    224 	dlp = (union DL_primitives *)mp->b_rptr;
    225 	ackprim = dlp->dl_primitive;
    226 
    227 	if (ackprim == expprim) {
    228 		if (len < minlen)
    229 			goto runt;
    230 
    231 		if (ackprim == DL_OK_ACK) {
    232 			if (dlp->ok_ack.dl_correct_primitive != reqprim) {
    233 				ackreqprim = dlp->ok_ack.dl_correct_primitive;
    234 				goto mixup;
    235 			}
    236 		}
    237 		*mpp = mp;
    238 		return (0);
    239 	}
    240 
    241 	if (ackprim == DL_ERROR_ACK) {
    242 		if (len < DL_ERROR_ACK_SIZE)
    243 			goto runt;
    244 
    245 		if (dlp->error_ack.dl_error_primitive != reqprim) {
    246 			ackreqprim = dlp->error_ack.dl_error_primitive;
    247 			goto mixup;
    248 		}
    249 
    250 		/*
    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.
    254 		 */
    255 		if (dleap != NULL)
    256 			*dleap = dlp->error_ack;
    257 
    258 		freemsg(mp);
    259 		return (ENOTSUP);
    260 	}
    261 
    262 	cmn_err(CE_NOTE, "!dl_op: expected %s but received %s",
    263 	    dl_primstr(expprim), dl_primstr(ackprim));
    264 	freemsg(mp);
    265 	return (EBADMSG);
    266 runt:
    267 	cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim));
    268 	freemsg(mp);
    269 	return (EBADMSG);
    270 mixup:
    271 	cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s",
    272 	    dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim));
    273 	freemsg(mp);
    274 	return (EBADMSG);
    275 }
    276 
    277 /*
    278  * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response.
    279  *
    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').
    282  */
    283 int
    284 dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap)
    285 {
    286 	mblk_t	*mp;
    287 	int	err;
    288 
    289 	mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ);
    290 	if (mp == NULL)
    291 		return (ENOMEM);
    292 
    293 	((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa;
    294 
    295 	err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL);
    296 	if (err == 0)
    297 		freemsg(mp);
    298 	return (err);
    299 }
    300 
    301 /*
    302  * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response.
    303  *
    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').
    306  */
    307 int
    308 dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap)
    309 {
    310 	dl_bind_req_t	*dlbrp;
    311 	dl_bind_ack_t	*dlbap;
    312 	mblk_t 		*mp;
    313 	int		err;
    314 
    315 	mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
    316 	if (mp == NULL)
    317 		return (ENOMEM);
    318 
    319 	dlbrp = (dl_bind_req_t *)mp->b_rptr;
    320 	dlbrp->dl_sap = sap;
    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;
    325 
    326 	err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL);
    327 	if (err == 0) {
    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",
    331 			    dlbap->dl_sap);
    332 			err = EPROTO;
    333 		}
    334 		freemsg(mp);
    335 	}
    336 	return (err);
    337 }
    338 
    339 /*
    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.
    344  *
    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').
    347  */
    348 int
    349 dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp,
    350     dl_error_ack_t *dleap)
    351 {
    352 	dl_phys_addr_ack_t *dlpap;
    353 	mblk_t		*mp;
    354 	int		err;
    355 	t_uscalar_t	paddrlen, paddroff;
    356 	timestruc_t	tv;
    357 
    358 	mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO,
    359 	    DL_PHYS_ADDR_REQ);
    360 	if (mp == NULL)
    361 		return (ENOMEM);
    362 
    363 	((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR;
    364 
    365 	/*
    366 	 * In case some provider doesn't implement or NAK the
    367 	 * request, just wait for 15 seconds.
    368 	 */
    369 	tv.tv_sec = 15;
    370 	tv.tv_nsec = 0;
    371 
    372 	err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap,
    373 	    &tv);
    374 	if (err == 0) {
    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);
    382 			err = EBADMSG;
    383 		} else {
    384 			bcopy(mp->b_rptr + paddroff, physaddr, paddrlen);
    385 			*physlenp = paddrlen;
    386 		}
    387 		freemsg(mp);
    388 	}
    389 	return (err);
    390 }
    391 
    392 /*
    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.
    399  *
    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').
    402  */
    403 int
    404 dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr,
    405     size_t *physlenp, dl_error_ack_t *dleap)
    406 {
    407 	mblk_t	*mp;
    408 	int	err;
    409 	int	addrlen, addroff;
    410 
    411 	mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ);
    412 	if (mp == NULL)
    413 		return (ENOMEM);
    414 
    415 	err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL);
    416 	if (err != 0)
    417 		return (err);
    418 
    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);
    427 			freemsg(mp);
    428 			return (EBADMSG);
    429 		}
    430 
    431 		if (dliap->dl_sap_length > 0)
    432 			addroff += dliap->dl_sap_length;
    433 		bcopy(mp->b_rptr + addroff, physaddr, addrlen);
    434 		*physlenp = addrlen;
    435 	}
    436 	freemsg(mp);
    437 	return (err);
    438 }
    439 
    440 /*
    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.
    444  *
    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').
    447  */
    448 int
    449 dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap)
    450 {
    451 	mblk_t	*mp;
    452 	int	err;
    453 
    454 	mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
    455 	if (mp == NULL)
    456 		return (ENOMEM);
    457 
    458 	((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp;
    459 
    460 	err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL);
    461 	if (err == 0) {
    462 		*notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications;
    463 		freemsg(mp);
    464 	}
    465 	return (err);
    466 }
    467 
    468 const char *
    469 dl_primstr(t_uscalar_t prim)
    470 {
    471 	switch (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>");
    503 	}
    504 }
    505 
    506 const char *
    507 dl_errstr(t_uscalar_t err)
    508 {
    509 	switch (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>");
    539 	}
    540 }
    541 
    542 const char *
    543 dl_mactypestr(t_uscalar_t mactype)
    544 {
    545 	switch (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>");
    576 	}
    577 }
    578