Home | History | Annotate | Download | only in inet
      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 /* Copyright (c) 1990 Mentat Inc. */
     26 
     27 #include <sys/types.h>
     28 #include <inet/common.h>	/* for various inet/mi.h and inet/nd.h needs */
     29 #include <sys/stream.h>
     30 #include <sys/stropts.h>
     31 #include <sys/strsun.h>
     32 #include <sys/sysmacros.h>
     33 #include <inet/nd.h>
     34 #include <inet/mi.h>
     35 #define	_SUN_TPI_VERSION 2
     36 #include <sys/tihdr.h>
     37 #include <sys/timod.h>
     38 #include <sys/vtrace.h>
     39 #include <sys/kmem.h>
     40 #include <sys/mkdev.h>
     41 #include <sys/strlog.h>
     42 #include <sys/ddi.h>
     43 #include <sys/suntpi.h>
     44 #include <sys/cmn_err.h>
     45 #include <sys/debug.h>
     46 #include <sys/kobj.h>
     47 #include <sys/stropts.h>
     48 #include <sys/strsubr.h>
     49 #include <inet/proto_set.h>
     50 
     51 #define	ISDIGIT(ch)	((ch) >= '0' && (ch) <= '9')
     52 #define	ISUPPER(ch)	((ch) >= 'A' && (ch) <= 'Z')
     53 #define	tolower(ch)	('a' + ((ch) - 'A'))
     54 
     55 #define	MI_IS_TRANSPARENT(mp)	(mp->b_cont && \
     56 	(mp->b_cont->b_rptr != mp->b_cont->b_wptr))
     57 
     58 /*
     59  * NOTE: Whenever anything is allocated by mi_alloc or mi_alloc_sleep (below),
     60  * the size of the requested allocation is increased by one word.  This extra
     61  * word is used to store the size of the object being allocated, and is located
     62  * at the beginning of the allocated block.  The pointer returned to the caller
     63  * is a pointer to the *second* word in the newly-allocated block.  The IP
     64  * module of mdb is aware of this, and will need to be changed if this
     65  * allocation strategy is changed.
     66  */
     67 
     68 typedef	struct	stroptions *STROPTP;
     69 typedef union T_primitives *TPRIMP;
     70 
     71 /* Timer block states. */
     72 #define	TB_RUNNING	1
     73 #define	TB_IDLE		2
     74 /*
     75  * Could not stop/free before putq
     76  */
     77 #define	TB_RESCHED	3	/* mtb_time_left contains tick count */
     78 #define	TB_CANCELLED	4
     79 #define	TB_TO_BE_FREED	5
     80 
     81 typedef struct mtb_s {
     82 	int		mtb_state;
     83 	timeout_id_t	mtb_tid;
     84 	queue_t		*mtb_q;
     85 	MBLKP		mtb_mp;
     86 	clock_t		mtb_time_left;
     87 } MTB, *MTBP;
     88 
     89 static int mi_timer_fire(MTBP);
     90 static int mi_iprintf(char *, va_list, pfi_t, char *);
     91 static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t);
     92 static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t);
     93 
     94 /* ARGSUSED1 */
     95 void *
     96 mi_alloc(size_t size, uint_t pri)
     97 {
     98 	size_t *ptr;
     99 
    100 	size += sizeof (size);
    101 	if (ptr = kmem_alloc(size, KM_NOSLEEP)) {
    102 		*ptr = size;
    103 		return (ptr + 1);
    104 	}
    105 	return (NULL);
    106 }
    107 
    108 /* ARGSUSED1 */
    109 void *
    110 mi_alloc_sleep(size_t size, uint_t pri)
    111 {
    112 	size_t *ptr;
    113 
    114 	size += sizeof (size);
    115 	ptr = kmem_alloc(size, KM_SLEEP);
    116 	*ptr = size;
    117 	return (ptr + 1);
    118 }
    119 
    120 int
    121 mi_close_comm(void **mi_headp, queue_t *q)
    122 {
    123 	IDP ptr;
    124 
    125 	ptr = q->q_ptr;
    126 	mi_close_unlink(mi_headp, ptr);
    127 	mi_close_free(ptr);
    128 	q->q_ptr = WR(q)->q_ptr = NULL;
    129 	return (0);
    130 }
    131 
    132 void
    133 mi_close_unlink(void **mi_headp, IDP ptr)
    134 {
    135 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
    136 	MI_OP		mi_o;
    137 	dev_t		dev;
    138 
    139 	mi_o = (MI_OP)ptr;
    140 	if (!mi_o)
    141 		return;
    142 	mi_o--;
    143 
    144 	if (mi_o->mi_o_next == NULL) {
    145 		/* Not in list */
    146 		ASSERT(mi_o->mi_o_prev == NULL);
    147 		return;
    148 	}
    149 
    150 	/* Free minor number */
    151 	dev = mi_o->mi_o_dev;
    152 	if ((dev != OPENFAIL) && (dev != 0) && (dev <= MAXMIN))
    153 		inet_minor_free(mi_head->mh_arena, dev);
    154 
    155 	/* Unlink from list */
    156 	ASSERT(mi_o->mi_o_next != NULL);
    157 	ASSERT(mi_o->mi_o_prev != NULL);
    158 	ASSERT(mi_o->mi_o_next->mi_o_prev == mi_o);
    159 	ASSERT(mi_o->mi_o_prev->mi_o_next == mi_o);
    160 
    161 	mi_o->mi_o_next->mi_o_prev = mi_o->mi_o_prev;
    162 	mi_o->mi_o_prev->mi_o_next = mi_o->mi_o_next;
    163 	mi_o->mi_o_next = mi_o->mi_o_prev = NULL;
    164 
    165 	mi_o->mi_o_dev = (dev_t)OPENFAIL;
    166 
    167 	/* If list now empty free the list head */
    168 	if (mi_head->mh_o.mi_o_next == &mi_head->mh_o) {
    169 		ASSERT(mi_head->mh_o.mi_o_prev == &mi_head->mh_o);
    170 		if (mi_head->mh_arena != NULL)
    171 			inet_minor_destroy(mi_head->mh_arena);
    172 		mi_free((IDP)mi_head);
    173 		*mi_headp = NULL;
    174 	}
    175 }
    176 
    177 void
    178 mi_close_free(IDP ptr)
    179 {
    180 	MI_OP		mi_o;
    181 
    182 	mi_o = (MI_OP)ptr;
    183 	if (!mi_o)
    184 		return;
    185 	mi_o--;
    186 
    187 	ASSERT(mi_o->mi_o_next == NULL && mi_o->mi_o_prev == NULL);
    188 	mi_free((IDP)mi_o);
    189 }
    190 
    191 /*
    192  * mi_copyin - takes care of transparent or non-transparent ioctl for the
    193  * calling function so that they have to deal with just M_IOCDATA type
    194  * and not worry about M_COPYIN.
    195  *
    196  * mi_copyin checks to see if the ioctl is transparent or non transparent.
    197  * In case of a non_transparent ioctl, it packs the data into a M_IOCDATA
    198  * message and puts it back onto the current queue for further processing.
    199  * In case of transparent ioctl, it sends a M_COPYIN message up to the
    200  * streamhead so that a M_IOCDATA with the information comes back down.
    201  */
    202 void
    203 mi_copyin(queue_t *q, MBLKP mp, char *uaddr, size_t len)
    204 {
    205 	struct 	iocblk *iocp = (struct iocblk *)mp->b_rptr;
    206 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
    207 	struct 	copyresp *cp = (struct copyresp *)mp->b_rptr;
    208 	int    	err;
    209 	MBLKP	mp1;
    210 
    211 	ASSERT(mp->b_datap->db_type == M_IOCTL && !uaddr);
    212 
    213 	/* A transparent ioctl. Send a M_COPYIN message to the streamhead. */
    214 	if (iocp->ioc_count == TRANSPARENT) {
    215 		MI_COPY_COUNT(mp) = 1;
    216 		MI_COPY_DIRECTION(mp) = MI_COPY_IN;
    217 		cq->cq_private = mp->b_cont;
    218 		cq->cq_size = len;
    219 		cq->cq_flag = 0;
    220 		bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
    221 		mp->b_cont = NULL;
    222 		mp->b_datap->db_type = M_COPYIN;
    223 		qreply(q, mp);
    224 		return;
    225 	}
    226 
    227 	/*
    228 	 * A non-transparent ioctl. Need to convert into M_IOCDATA message.
    229 	 *
    230 	 * We allocate a 0 byte message block and put its address in
    231 	 * cp_private. It also makes the b_prev field = 1 and b_next
    232 	 * field = MI_COPY_IN for this 0 byte block. This is done to
    233 	 * maintain compatibility with old code in mi_copy_state
    234 	 * (which removes the empty block).
    235 	 */
    236 	err = miocpullup(mp, len);
    237 	if (err != 0)
    238 		goto err_ret;
    239 
    240 	mp1 = allocb(0, BPRI_MED);
    241 	if (mp1 == NULL) {
    242 		err = ENOMEM;
    243 		goto err_ret;
    244 	}
    245 
    246 	/*
    247 	 * Temporarily insert mp1 between the M_IOCTL and M_DATA blocks so
    248 	 * that we can use the MI_COPY_COUNT & MI_COPY_DIRECTION macros.
    249 	 */
    250 	mp1->b_cont = mp->b_cont;
    251 	mp->b_cont = mp1;
    252 	MI_COPY_COUNT(mp) = 1;
    253 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
    254 	mp->b_cont = mp1->b_cont;
    255 	mp1->b_cont = NULL;
    256 
    257 	/*
    258 	 * Leave a pointer to the 0 byte block in cp_private field for
    259 	 * future use by the mi_copy_* routines.
    260 	 */
    261 	mp->b_datap->db_type = M_IOCDATA;
    262 	cp->cp_private = mp1;
    263 	cp->cp_rval = NULL;
    264 	put(q, mp);
    265 	return;
    266 
    267 err_ret:
    268 	iocp->ioc_error = err;
    269 	iocp->ioc_count = 0;
    270 	if (mp->b_cont) {
    271 		freemsg(mp->b_cont);
    272 		mp->b_cont = NULL;
    273 	}
    274 	mp->b_datap->db_type = M_IOCACK;
    275 	qreply(q, mp);
    276 }
    277 
    278 /*
    279  * Allows transparent IOCTLs to have multiple copyins.  This is needed
    280  * for some variable-length structures, where the total size is only known
    281  * after the first part is copied in. Rather than setting MI_COPY_COUNT to
    282  * 1, as in mi_coypin(), it is simply incremented here.  This value can
    283  * then be checked in the returned IOCBLK.
    284  *
    285  * As this deals with copyins that follow the initial copyin, the byte
    286  * offset into the user buffer from which copying should begin must be
    287  * passed in in the offset parameter.
    288  *
    289  * Unlike mi_coypin(), this function expects to be passed an mblk chain
    290  * headed by an M_IOCBLK, as that's the chain that will be in use for
    291  * copies after the first one (copies where n != 1).
    292  */
    293 void
    294 mi_copyin_n(queue_t *q, MBLKP mp, size_t offset, size_t len)
    295 {
    296 	struct 	copyreq *cq = (struct copyreq *)mp->b_rptr;
    297 
    298 	ASSERT(mp->b_datap->db_type == M_IOCDATA);
    299 
    300 	MI_COPY_COUNT(mp)++;
    301 	MI_COPY_DIRECTION(mp) = MI_COPY_IN;
    302 	cq->cq_private = mp->b_cont;
    303 	cq->cq_size = len;
    304 	cq->cq_flag = 0;
    305 	bcopy(mp->b_cont->b_rptr, &cq->cq_addr, sizeof (cq->cq_addr));
    306 	cq->cq_addr += offset;
    307 	mp->b_cont = NULL;
    308 	mp->b_datap->db_type = M_COPYIN;
    309 	qreply(q, mp);
    310 }
    311 
    312 void
    313 mi_copyout(queue_t *q, MBLKP mp)
    314 {
    315 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
    316 	struct copyreq *cq = (struct copyreq *)iocp;
    317 	struct copyresp *cp = (struct copyresp *)cq;
    318 	MBLKP	mp1;
    319 	MBLKP	mp2;
    320 
    321 	if (mp->b_datap->db_type != M_IOCDATA || !mp->b_cont) {
    322 		mi_copy_done(q, mp, EPROTO);
    323 		return;
    324 	}
    325 	/* Check completion of previous copyout operation. */
    326 	mp1 = mp->b_cont;
    327 	if ((int)(uintptr_t)cp->cp_rval || !mp1->b_cont) {
    328 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
    329 		return;
    330 	}
    331 	if (!mp1->b_cont->b_cont && !MI_IS_TRANSPARENT(mp)) {
    332 		mp1->b_next = NULL;
    333 		mp1->b_prev = NULL;
    334 		mp->b_cont = mp1->b_cont;
    335 		freeb(mp1);
    336 		mp1 = mp->b_cont;
    337 		mp1->b_next = NULL;
    338 		mp1->b_prev = NULL;
    339 		iocp->ioc_count = mp1->b_wptr - mp1->b_rptr;
    340 		iocp->ioc_error = 0;
    341 		mp->b_datap->db_type = M_IOCACK;
    342 		qreply(q, mp);
    343 		return;
    344 	}
    345 	if (MI_COPY_DIRECTION(mp) == MI_COPY_IN) {
    346 		/* Set up for first copyout. */
    347 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
    348 		MI_COPY_COUNT(mp) = 1;
    349 	} else {
    350 		++MI_COPY_COUNT(mp);
    351 	}
    352 	cq->cq_private = mp1;
    353 	/* Find message preceding last. */
    354 	for (mp2 = mp1; mp2->b_cont->b_cont; mp2 = mp2->b_cont)
    355 		;
    356 	if (mp2 == mp1)
    357 		bcopy((char *)mp1->b_rptr, (char *)&cq->cq_addr,
    358 		    sizeof (cq->cq_addr));
    359 	else
    360 		cq->cq_addr = (char *)mp2->b_cont->b_next;
    361 	mp1 = mp2->b_cont;
    362 	mp->b_datap->db_type = M_COPYOUT;
    363 	mp->b_cont = mp1;
    364 	mp2->b_cont = NULL;
    365 	mp1->b_next = NULL;
    366 	cq->cq_size = mp1->b_wptr - mp1->b_rptr;
    367 	cq->cq_flag = 0;
    368 	qreply(q, mp);
    369 }
    370 
    371 MBLKP
    372 mi_copyout_alloc(queue_t *q, MBLKP mp, char *uaddr, size_t len,
    373     boolean_t free_on_error)
    374 {
    375 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
    376 	MBLKP	mp1;
    377 
    378 	if (mp->b_datap->db_type == M_IOCTL) {
    379 		if (iocp->ioc_count != TRANSPARENT) {
    380 			mp1 = allocb(0, BPRI_MED);
    381 			if (mp1 == NULL) {
    382 				if (free_on_error) {
    383 					iocp->ioc_error = ENOMEM;
    384 					iocp->ioc_count = 0;
    385 					freemsg(mp->b_cont);
    386 					mp->b_cont = NULL;
    387 					mp->b_datap->db_type = M_IOCACK;
    388 					qreply(q, mp);
    389 				}
    390 				return (NULL);
    391 			}
    392 			mp1->b_cont = mp->b_cont;
    393 			mp->b_cont = mp1;
    394 		}
    395 		MI_COPY_COUNT(mp) = 0;
    396 		MI_COPY_DIRECTION(mp) = MI_COPY_OUT;
    397 		/* Make sure it looks clean to mi_copyout. */
    398 		mp->b_datap->db_type = M_IOCDATA;
    399 		((struct copyresp *)iocp)->cp_rval = NULL;
    400 	}
    401 	mp1 = allocb(len, BPRI_MED);
    402 	if (mp1 == NULL) {
    403 		if (free_on_error)
    404 			mi_copy_done(q, mp, ENOMEM);
    405 		return (NULL);
    406 	}
    407 	linkb(mp, mp1);
    408 	mp1->b_next = (MBLKP)uaddr;
    409 	return (mp1);
    410 }
    411 
    412 void
    413 mi_copy_done(queue_t *q, MBLKP mp, int err)
    414 {
    415 	struct iocblk *iocp;
    416 	MBLKP	mp1;
    417 
    418 	if (!mp)
    419 		return;
    420 	if (!q || (mp->b_wptr - mp->b_rptr) < sizeof (struct iocblk)) {
    421 		freemsg(mp);
    422 		return;
    423 	}
    424 	iocp = (struct iocblk *)mp->b_rptr;
    425 	mp->b_datap->db_type = M_IOCACK;
    426 	iocp->ioc_error = err;
    427 
    428 	iocp->ioc_count = 0;
    429 	if ((mp1 = mp->b_cont) != NULL) {
    430 		for (; mp1; mp1 = mp1->b_cont) {
    431 			mp1->b_prev = NULL;
    432 			mp1->b_next = NULL;
    433 		}
    434 		freemsg(mp->b_cont);
    435 		mp->b_cont = NULL;
    436 	}
    437 	qreply(q, mp);
    438 }
    439 
    440 int
    441 mi_copy_state(queue_t *q, MBLKP mp, MBLKP *mpp)
    442 {
    443 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
    444 	struct copyresp *cp = (struct copyresp *)iocp;
    445 	MBLKP	mp1;
    446 
    447 	mp1 = mp->b_cont;
    448 	mp->b_cont = cp->cp_private;
    449 	if (mp1) {
    450 		if (mp1->b_cont && !pullupmsg(mp1, -1)) {
    451 			mi_copy_done(q, mp, ENOMEM);
    452 			return (-1);
    453 		}
    454 		linkb(mp->b_cont, mp1);
    455 	}
    456 	if ((int)(uintptr_t)cp->cp_rval) {
    457 		mi_copy_done(q, mp, (int)(uintptr_t)cp->cp_rval);
    458 		return (-1);
    459 	}
    460 	if (mpp && MI_COPY_DIRECTION(mp) == MI_COPY_IN)
    461 		*mpp = mp1;
    462 	return (MI_COPY_STATE(mp));
    463 }
    464 
    465 void
    466 mi_free(void *ptr)
    467 {
    468 	size_t	size;
    469 
    470 	if (!ptr)
    471 		return;
    472 	if ((size = ((size_t *)ptr)[-1]) <= 0)
    473 		cmn_err(CE_PANIC, "mi_free");
    474 
    475 	kmem_free((void *) ((size_t *)ptr - 1), size);
    476 }
    477 
    478 static int
    479 mi_iprintf(char *fmt, va_list ap, pfi_t putc_func, char *cookie)
    480 {
    481 	int	base;
    482 	char	buf[(sizeof (long) * 3) + 1];
    483 	static char	hex_val[] = "0123456789abcdef";
    484 	int	ch;
    485 	int	count;
    486 	char	*cp1;
    487 	int	digits;
    488 	char	*fcp;
    489 	boolean_t	is_long;
    490 	ulong_t	uval;
    491 	long	val;
    492 	boolean_t	zero_filled;
    493 
    494 	if (!fmt)
    495 		return (-1);
    496 	count = 0;
    497 	while (*fmt) {
    498 		if (*fmt != '%' || *++fmt == '%') {
    499 			count += (*putc_func)(cookie, *fmt++);
    500 			continue;
    501 		}
    502 		if (*fmt == '0') {
    503 			zero_filled = B_TRUE;
    504 			fmt++;
    505 			if (!*fmt)
    506 				break;
    507 		} else
    508 			zero_filled = B_FALSE;
    509 		base = 0;
    510 		for (digits = 0; ISDIGIT(*fmt); fmt++) {
    511 			digits *= 10;
    512 			digits += (*fmt - '0');
    513 		}
    514 		if (!*fmt)
    515 			break;
    516 		is_long = B_FALSE;
    517 		if (*fmt == 'l') {
    518 			is_long = B_TRUE;
    519 			fmt++;
    520 		}
    521 		if (!*fmt)
    522 			break;
    523 		ch = *fmt++;
    524 		if (ISUPPER(ch)) {
    525 			ch = tolower(ch);
    526 			is_long = B_TRUE;
    527 		}
    528 		switch (ch) {
    529 		case 'c':
    530 			count += (*putc_func)(cookie, va_arg(ap, int *));
    531 			continue;
    532 		case 'd':
    533 			base = 10;
    534 			break;
    535 		case 'm':	/* Print out memory, 2 hex chars per byte */
    536 			if (is_long)
    537 				fcp = va_arg(ap, char *);
    538 			else {
    539 				if ((cp1 = va_arg(ap, char *)) != NULL)
    540 					fcp = (char *)cp1;
    541 				else
    542 					fcp = NULL;
    543 			}
    544 			if (!fcp) {
    545 				for (fcp = (char *)"(NULL)"; *fcp; fcp++)
    546 					count += (*putc_func)(cookie, *fcp);
    547 			} else {
    548 				while (digits--) {
    549 					int u1 = *fcp++ & 0xFF;
    550 					count += (*putc_func)(cookie,
    551 					    hex_val[(u1>>4)& 0xF]);
    552 					count += (*putc_func)(cookie,
    553 					    hex_val[u1& 0xF]);
    554 				}
    555 			}
    556 			continue;
    557 		case 'o':
    558 			base = 8;
    559 			break;
    560 		case 'p':
    561 			is_long = B_TRUE;
    562 			/* FALLTHRU */
    563 		case 'x':
    564 			base = 16;
    565 			break;
    566 		case 's':
    567 			if (is_long)
    568 				fcp = va_arg(ap, char *);
    569 			else {
    570 				if ((cp1 = va_arg(ap, char *)) != NULL)
    571 					fcp = (char *)cp1;
    572 				else
    573 					fcp = NULL;
    574 			}
    575 			if (!fcp)
    576 				fcp = (char *)"(NULL)";
    577 			while (*fcp) {
    578 				count += (*putc_func)(cookie, *fcp++);
    579 				if (digits && --digits == 0)
    580 					break;
    581 			}
    582 			while (digits > 0) {
    583 				count += (*putc_func)(cookie, ' ');
    584 				digits--;
    585 			}
    586 			continue;
    587 		case 'u':
    588 			base = 10;
    589 			break;
    590 		default:
    591 			return (count);
    592 		}
    593 		if (is_long)
    594 			val = va_arg(ap, long);
    595 		else
    596 			val = va_arg(ap, int);
    597 		if (base == 10 && ch != 'u') {
    598 			if (val < 0) {
    599 				count += (*putc_func)(cookie, '-');
    600 				val = -val;
    601 			}
    602 			uval = val;
    603 		} else {
    604 			if (is_long)
    605 				uval = val;
    606 			else
    607 				uval = (uint_t)val;
    608 		}
    609 		/* Hand overload/restore the register variable 'fmt' */
    610 		cp1 = fmt;
    611 		fmt = A_END(buf);
    612 		*--fmt = '\0';
    613 		do {
    614 			if (fmt > buf)
    615 				*--fmt = hex_val[uval % base];
    616 			if (digits && --digits == 0)
    617 				break;
    618 		} while (uval /= base);
    619 		if (zero_filled) {
    620 			while (digits > 0 && fmt > buf) {
    621 				*--fmt = '0';
    622 				digits--;
    623 			}
    624 		}
    625 		while (*fmt)
    626 			count += (*putc_func)(cookie, *fmt++);
    627 		fmt = cp1;
    628 	}
    629 	return (count);
    630 }
    631 
    632 /* PRINTFLIKE2 */
    633 int
    634 mi_mpprintf(MBLKP mp, char *fmt, ...)
    635 {
    636 	va_list	ap;
    637 	int	count = -1;
    638 
    639 	va_start(ap, fmt);
    640 	if (mp) {
    641 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
    642 		    (char *)mp);
    643 		if (count != -1)
    644 			(void) mi_mpprintf_putc((char *)mp, '\0');
    645 	}
    646 	va_end(ap);
    647 	return (count);
    648 }
    649 
    650 /* PRINTFLIKE2 */
    651 int
    652 mi_mpprintf_nr(MBLKP mp, char *fmt, ...)
    653 {
    654 	va_list	ap;
    655 	int	count = -1;
    656 
    657 	va_start(ap, fmt);
    658 	if (mp) {
    659 		(void) adjmsg(mp, -1);
    660 		count = mi_iprintf(fmt, ap, (pfi_t)mi_mpprintf_putc,
    661 		    (char *)mp);
    662 		if (count != -1)
    663 			(void) mi_mpprintf_putc((char *)mp, '\0');
    664 	}
    665 	va_end(ap);
    666 	return (count);
    667 }
    668 
    669 int
    670 mi_mpprintf_putc(char *cookie, int ch)
    671 {
    672 	MBLKP	mp = (MBLKP)cookie;
    673 
    674 	while (mp->b_cont)
    675 		mp = mp->b_cont;
    676 	if (mp->b_wptr >= mp->b_datap->db_lim) {
    677 		mp->b_cont = allocb(1024, BPRI_HI);
    678 		mp = mp->b_cont;
    679 		if (!mp)
    680 			return (0);
    681 	}
    682 	*mp->b_wptr++ = (unsigned char)ch;
    683 	return (1);
    684 }
    685 
    686 IDP
    687 mi_first_ptr(void **mi_headp)
    688 {
    689 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
    690 	MI_OP	mi_op;
    691 
    692 	mi_op = mi_head->mh_o.mi_o_next;
    693 	if (mi_op && mi_op != &mi_head->mh_o)
    694 		return ((IDP)&mi_op[1]);
    695 	return (NULL);
    696 }
    697 
    698 /*
    699  * Clients can choose to have both module instances and device instances
    700  * in the same list. Return the first device instance in the list.
    701  */
    702 IDP
    703 mi_first_dev_ptr(void **mi_headp)
    704 {
    705 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
    706 	MI_OP	mi_op;
    707 
    708 	mi_op = mi_head->mh_o.mi_o_next;
    709 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
    710 		if (mi_op->mi_o_isdev)
    711 			return ((IDP)&mi_op[1]);
    712 		mi_op = mi_op->mi_o_next;
    713 	}
    714 	return (NULL);
    715 }
    716 
    717 IDP
    718 mi_next_ptr(void **mi_headp, IDP ptr)
    719 {
    720 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
    721 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
    722 
    723 	if ((mi_op = mi_op->mi_o_next) != NULL && mi_op != &mi_head->mh_o)
    724 		return ((IDP)&mi_op[1]);
    725 	return (NULL);
    726 }
    727 
    728 /*
    729  * Clients can choose to have both module instances and device instances
    730  * in the same list. Return the next device instance in the list.
    731  */
    732 IDP
    733 mi_next_dev_ptr(void **mi_headp, IDP ptr)
    734 {
    735 	mi_head_t *mi_head = *(mi_head_t **)mi_headp;
    736 	MI_OP	mi_op = ((MI_OP)ptr) - 1;
    737 
    738 	mi_op = mi_op->mi_o_next;
    739 	while ((mi_op != NULL) && (mi_op != &mi_head->mh_o)) {
    740 		if (mi_op->mi_o_isdev)
    741 			return ((IDP)&mi_op[1]);
    742 		mi_op = mi_op->mi_o_next;
    743 	}
    744 	return (NULL);
    745 }
    746 
    747 /*
    748  * Self clone the device
    749  * XXX - should we still support clone device
    750  */
    751 /* ARGSUSED4 */
    752 int
    753 mi_open_comm(void **mi_headp, size_t size, queue_t *q, dev_t *devp,
    754     int flag, int sflag, cred_t *credp)
    755 {
    756 	int error;
    757 	IDP ptr;
    758 
    759 	if (q->q_ptr != NULL)
    760 		return (0);
    761 
    762 	ptr = mi_open_alloc_sleep(size);
    763 	q->q_ptr = WR(q)->q_ptr = ptr;
    764 	error = mi_open_link(mi_headp, ptr, devp, flag, sflag, credp);
    765 	if (error != 0) {
    766 		q->q_ptr = WR(q)->q_ptr = NULL;
    767 		mi_close_free(ptr);
    768 	}
    769 	return (error);
    770 }
    771 
    772 IDP
    773 mi_open_alloc_sleep(size_t size)
    774 {
    775 	MI_OP		mi_o;
    776 
    777 	if (size > (UINT_MAX - sizeof (MI_O)))
    778 		return (NULL);
    779 
    780 	mi_o = (MI_OP)mi_zalloc_sleep(size + sizeof (MI_O));
    781 	mi_o++;
    782 	return ((IDP)mi_o);
    783 }
    784 
    785 IDP
    786 mi_open_alloc(size_t size)
    787 {
    788 	MI_OP		mi_o;
    789 
    790 	if (size > (UINT_MAX - sizeof (MI_O)))
    791 		return (NULL);
    792 
    793 	if ((mi_o = (MI_OP)mi_zalloc(size + sizeof (MI_O))) == NULL)
    794 		return (NULL);
    795 	mi_o++;
    796 	return ((IDP)mi_o);
    797 }
    798 
    799 /*
    800  * MODOPEN means just link in without respect of mi_o_dev.
    801  * A NULL devp can be used to create a detached instance
    802  * Otherwise self-clone the device.
    803  */
    804 /* ARGSUSED3 */
    805 int
    806 mi_open_link(void **mi_headp, IDP ptr, dev_t *devp, int flag, int sflag,
    807     cred_t *credp)
    808 {
    809 	mi_head_t	*mi_head = *(mi_head_t **)mi_headp;
    810 	MI_OP		insert;
    811 	MI_OP		mi_o;
    812 	dev_t		dev;
    813 
    814 	if (mi_head == NULL) {
    815 		char arena_name[50];
    816 		char *head_name;
    817 		ulong_t offset;
    818 
    819 		head_name = kobj_getsymname((uintptr_t)mi_headp, &offset);
    820 		if (head_name != NULL && offset == 0) {
    821 			(void) sprintf(arena_name, "%s_", head_name);
    822 		} else {
    823 			(void) sprintf(arena_name, "Hex0x%p_",
    824 			    (void *)mi_headp);
    825 		}
    826 		(void) sprintf(strchr(arena_name, '_') + 1, "minor");
    827 		mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t));
    828 		*mi_headp = (void *)mi_head;
    829 		/* Setup doubly linked list */
    830 		mi_head->mh_o.mi_o_next = &mi_head->mh_o;
    831 		mi_head->mh_o.mi_o_prev = &mi_head->mh_o;
    832 		mi_head->mh_o.mi_o_dev = 0;	/* For asserts only */
    833 		mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name,
    834 		    INET_MIN_DEV, MAXMIN, KM_SLEEP);
    835 	}
    836 	ASSERT(ptr != NULL);
    837 	mi_o = (MI_OP)ptr;
    838 	mi_o--;
    839 
    840 	if (sflag == MODOPEN) {
    841 		devp = NULL;
    842 		/*
    843 		 * Set device number to MAXMIN + incrementing number.
    844 		 */
    845 		dev = MAXMIN + ++mi_head->mh_module_dev;
    846 		/* check for wraparound */
    847 		if (dev <= MAXMIN) {
    848 			dev = MAXMIN + 1;
    849 			mi_head->mh_module_dev = 1;
    850 		}
    851 	} else if (devp == NULL) {
    852 		/* Detached open */
    853 		dev = (dev_t)OPENFAIL;
    854 	} else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) {
    855 		return (EBUSY);
    856 	}
    857 
    858 	mi_o->mi_o_dev = dev;
    859 	insert = (&mi_head->mh_o);
    860 	mi_o->mi_o_next = insert;
    861 	insert->mi_o_prev->mi_o_next = mi_o;
    862 	mi_o->mi_o_prev = insert->mi_o_prev;
    863 	insert->mi_o_prev = mi_o;
    864 
    865 	if (sflag == MODOPEN)
    866 		mi_o->mi_o_isdev = B_FALSE;
    867 	else
    868 		mi_o->mi_o_isdev = B_TRUE;
    869 
    870 	if (devp)
    871 		*devp = makedevice(getemajor(*devp), (minor_t)dev);
    872 	return (0);
    873 }
    874 
    875 uint8_t *
    876 mi_offset_param(mblk_t *mp, size_t offset, size_t len)
    877 {
    878 	size_t	msg_len;
    879 
    880 	if (!mp)
    881 		return (NULL);
    882 	msg_len = mp->b_wptr - mp->b_rptr;
    883 	if (msg_len == 0 || offset > msg_len || len > msg_len ||
    884 	    (offset + len) > msg_len || len == 0)
    885 		return (NULL);
    886 	return (&mp->b_rptr[offset]);
    887 }
    888 
    889 uint8_t *
    890 mi_offset_paramc(mblk_t *mp, size_t offset, size_t len)
    891 {
    892 	uint8_t	*param;
    893 
    894 	for (; mp; mp = mp->b_cont) {
    895 		int type = mp->b_datap->db_type;
    896 		if (datamsg(type)) {
    897 			if (param = mi_offset_param(mp, offset, len))
    898 				return (param);
    899 			if (offset < mp->b_wptr - mp->b_rptr)
    900 				break;
    901 			offset -= mp->b_wptr - mp->b_rptr;
    902 		}
    903 	}
    904 	return (NULL);
    905 }
    906 
    907 int
    908 mi_sprintf(char *buf, char *fmt, ...)
    909 {
    910 	va_list	ap;
    911 	int	count = -1;
    912 	va_start(ap, fmt);
    913 	if (buf) {
    914 		count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc,
    915 		    (char *)&buf);
    916 		if (count != -1)
    917 			(void) mi_sprintf_putc((char *)&buf, '\0');
    918 	}
    919 	va_end(ap);
    920 	return (count);
    921 }
    922 
    923 /* Used to count without writing data */
    924 /* ARGSUSED1 */
    925 static int
    926 mi_sprintf_noop(char *cookie, int ch)
    927 {
    928 	char	**cpp = (char **)cookie;
    929 
    930 	(*cpp)++;
    931 	return (1);
    932 }
    933 
    934 int
    935 mi_sprintf_putc(char *cookie, int ch)
    936 {
    937 	char	**cpp = (char **)cookie;
    938 
    939 	**cpp = (char)ch;
    940 	(*cpp)++;
    941 	return (1);
    942 }
    943 
    944 int
    945 mi_strcmp(const char *cp1, const char *cp2)
    946 {
    947 	while (*cp1++ == *cp2++) {
    948 		if (!cp2[-1])
    949 			return (0);
    950 	}
    951 	return ((uint_t)cp2[-1]  & 0xFF) - ((uint_t)cp1[-1] & 0xFF);
    952 }
    953 
    954 size_t
    955 mi_strlen(const char *str)
    956 {
    957 	const char *cp = str;
    958 
    959 	while (*cp != '\0')
    960 		cp++;
    961 	return ((int)(cp - str));
    962 }
    963 
    964 int
    965 mi_strlog(queue_t *q, char level, ushort_t flags, char *fmt, ...)
    966 {
    967 	va_list	ap;
    968 	char	buf[200];
    969 	char	*alloc_buf = buf;
    970 	int	count = -1;
    971 	char	*cp;
    972 	short	mid;
    973 	int	ret;
    974 	short	sid;
    975 
    976 	sid = 0;
    977 	mid = 0;
    978 	if (q != NULL) {
    979 		mid = q->q_qinfo->qi_minfo->mi_idnum;
    980 	}
    981 
    982 	/* Find out how many bytes we need and allocate if necesary */
    983 	va_start(ap, fmt);
    984 	cp = buf;
    985 	count = mi_iprintf(fmt, ap, mi_sprintf_noop, (char *)&cp);
    986 	if (count > sizeof (buf) &&
    987 	    !(alloc_buf = mi_alloc((uint_t)count + 2, BPRI_MED))) {
    988 		va_end(ap);
    989 		return (-1);
    990 	}
    991 	va_end(ap);
    992 
    993 	va_start(ap, fmt);
    994 	cp = alloc_buf;
    995 	count = mi_iprintf(fmt, ap, mi_sprintf_putc, (char *)&cp);
    996 	if (count != -1)
    997 		(void) mi_sprintf_putc((char *)&cp, '\0');
    998 	else
    999 		alloc_buf[0] = '\0';
   1000 	va_end(ap);
   1001 
   1002 	ret = strlog(mid, sid, level, flags, alloc_buf);
   1003 	if (alloc_buf != buf)
   1004 		mi_free(alloc_buf);
   1005 	return (ret);
   1006 }
   1007 
   1008 long
   1009 mi_strtol(const char *str, char **ptr, int base)
   1010 {
   1011 	const char *cp;
   1012 	int	digits;
   1013 	long	value;
   1014 	boolean_t	is_negative;
   1015 
   1016 	cp = str;
   1017 	while (*cp == ' ' || *cp == '\t' || *cp == '\n')
   1018 		cp++;
   1019 	is_negative = (*cp == '-');
   1020 	if (is_negative)
   1021 		cp++;
   1022 	if (base == 0) {
   1023 		base = 10;
   1024 		if (*cp == '0') {
   1025 			base = 8;
   1026 			cp++;
   1027 			if (*cp == 'x' || *cp == 'X') {
   1028 				base = 16;
   1029 				cp++;
   1030 			}
   1031 		}
   1032 	}
   1033 	value = 0;
   1034 	for (; *cp != '\0'; cp++) {
   1035 		if (*cp >= '0' && *cp <= '9')
   1036 			digits = *cp - '0';
   1037 		else if (*cp >= 'a' && *cp <= 'f')
   1038 			digits = *cp - 'a' + 10;
   1039 		else if (*cp >= 'A' && *cp <= 'F')
   1040 			digits = *cp - 'A' + 10;
   1041 		else
   1042 			break;
   1043 		if (digits >= base)
   1044 			break;
   1045 		value = (value * base) + digits;
   1046 	}
   1047 	/* Note: we cast away const here deliberately */
   1048 	if (ptr != NULL)
   1049 		*ptr = (char *)cp;
   1050 	if (is_negative)
   1051 		value = -value;
   1052 	return (value);
   1053 }
   1054 
   1055 /*
   1056  *		mi_timer mechanism.
   1057  *
   1058  * Each timer is represented by a timer mblk and a (streams) queue. When the
   1059  * timer fires the timer mblk will be put on the associated streams queue
   1060  * so that the streams module can process the timer even in its service
   1061  * procedure.
   1062  *
   1063  * The interface consists of 4 entry points:
   1064  *	mi_timer_alloc		- create a timer mblk
   1065  *	mi_timer_free		- free a timer mblk
   1066  *	mi_timer		- start, restart, stop, or move the
   1067  *				  timer to a different queue
   1068  *	mi_timer_valid		- called by streams module to verify that
   1069  *				  the timer did indeed fire.
   1070  */
   1071 
   1072 
   1073 
   1074 
   1075 /*
   1076  * Start, restart, stop, or move the timer to a new queue.
   1077  * If "tim" is -2 the timer is moved to a different queue.
   1078  * If "tim" is -1 the timer is stopped.
   1079  * Otherwise, the timer is stopped if it is already running, and
   1080  * set to fire tim milliseconds from now.
   1081  */
   1082 
   1083 void
   1084 mi_timer(queue_t *q, MBLKP mp, clock_t tim)
   1085 {
   1086 	MTBP	mtb;
   1087 	int	state;
   1088 
   1089 	ASSERT(tim >= -2);
   1090 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
   1091 		return;
   1092 	mtb = (MTBP)mp->b_datap->db_base;
   1093 	ASSERT(mp->b_datap->db_type == M_PCSIG);
   1094 	if (tim >= 0) {
   1095 		mtb->mtb_q = q;
   1096 		state = mtb->mtb_state;
   1097 		tim = MSEC_TO_TICK(tim);
   1098 		if (state == TB_RUNNING) {
   1099 			if (untimeout(mtb->mtb_tid) < 0) {
   1100 				/* Message has already been putq */
   1101 				ASSERT(mtb->mtb_q->q_first == mp ||
   1102 				    mp->b_prev || mp->b_next);
   1103 				mtb->mtb_state = TB_RESCHED;
   1104 				mtb->mtb_time_left = tim;
   1105 				/* mi_timer_valid will start timer */
   1106 				return;
   1107 			}
   1108 		} else if (state != TB_IDLE) {
   1109 			ASSERT(state != TB_TO_BE_FREED);
   1110 			if (state == TB_CANCELLED) {
   1111 				ASSERT(mtb->mtb_q->q_first == mp ||
   1112 				    mp->b_prev || mp->b_next);
   1113 				mtb->mtb_state = TB_RESCHED;
   1114 				mtb->mtb_time_left = tim;
   1115 				/* mi_timer_valid will start timer */
   1116 				return;
   1117 			}
   1118 			if (state == TB_RESCHED) {
   1119 				ASSERT(mtb->mtb_q->q_first == mp ||
   1120 				    mp->b_prev || mp->b_next);
   1121 				mtb->mtb_time_left = tim;
   1122 				/* mi_timer_valid will start timer */
   1123 				return;
   1124 			}
   1125 		}
   1126 		mtb->mtb_state = TB_RUNNING;
   1127 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
   1128 		return;
   1129 	}
   1130 	switch (tim) {
   1131 	case -1:
   1132 		mi_timer_stop(mp);
   1133 		break;
   1134 	case -2:
   1135 		mi_timer_move(q, mp);
   1136 		break;
   1137 	}
   1138 }
   1139 
   1140 /*
   1141  * Allocate an M_PCSIG timer message. The space between db_base and
   1142  * b_rptr is used by the mi_timer mechanism, and after b_rptr there are
   1143  * "size" bytes that the caller can use for its own purposes.
   1144  *
   1145  * Note that db_type has to be a priority message since otherwise
   1146  * the putq will not cause the service procedure to run when
   1147  * there is flow control.
   1148  */
   1149 MBLKP
   1150 mi_timer_alloc(size_t size)
   1151 {
   1152 	MBLKP	mp;
   1153 	MTBP	mtb;
   1154 
   1155 	if ((mp = allocb(size + sizeof (MTB), BPRI_HI)) != NULL) {
   1156 		mp->b_datap->db_type = M_PCSIG;
   1157 		mtb = (MTBP)mp->b_datap->db_base;
   1158 		mp->b_rptr = (uchar_t *)&mtb[1];
   1159 		mp->b_wptr = mp->b_rptr + size;
   1160 		mtb->mtb_state = TB_IDLE;
   1161 		mtb->mtb_mp = mp;
   1162 		mtb->mtb_q = NULL;
   1163 		return (mp);
   1164 	}
   1165 	return (NULL);
   1166 }
   1167 
   1168 /*
   1169  * timeout() callback function.
   1170  * Put the message on the current queue.
   1171  * If the timer is stopped or moved to a different queue after
   1172  * it has fired then mi_timer() and mi_timer_valid() will clean
   1173  * things up.
   1174  */
   1175 static int
   1176 mi_timer_fire(MTBP mtb)
   1177 {
   1178 	ASSERT(mtb == (MTBP)mtb->mtb_mp->b_datap->db_base);
   1179 	ASSERT(mtb->mtb_mp->b_datap->db_type == M_PCSIG);
   1180 	return (putq(mtb->mtb_q, mtb->mtb_mp));
   1181 }
   1182 
   1183 /*
   1184  * Logically free a timer mblk (that might have a pending timeout().)
   1185  * If the timer has fired and the mblk has been put on the queue then
   1186  * mi_timer_valid will free the mblk.
   1187  */
   1188 
   1189 void
   1190 mi_timer_free(MBLKP mp)
   1191 {
   1192 	MTBP	mtb;
   1193 	int	state;
   1194 
   1195 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
   1196 		return;
   1197 	mtb = (MTBP)mp->b_datap->db_base;
   1198 	state = mtb->mtb_state;
   1199 	if (state == TB_RUNNING) {
   1200 		if (untimeout(mtb->mtb_tid) < 0) {
   1201 			/* Message has already been putq */
   1202 			ASSERT(mtb->mtb_q->q_first == mp ||
   1203 			    mp->b_prev || mp->b_next);
   1204 			mtb->mtb_state = TB_TO_BE_FREED;
   1205 			/* mi_timer_valid will free the mblk */
   1206 			return;
   1207 		}
   1208 	} else if (state != TB_IDLE) {
   1209 		/* Message has already been putq */
   1210 		ASSERT(mtb->mtb_q->q_first == mp ||
   1211 		    mp->b_prev || mp->b_next);
   1212 		ASSERT(state != TB_TO_BE_FREED);
   1213 		mtb->mtb_state = TB_TO_BE_FREED;
   1214 		/* mi_timer_valid will free the mblk */
   1215 		return;
   1216 	}
   1217 	ASSERT(mtb->mtb_q ==  NULL || mtb->mtb_q->q_first != mp);
   1218 	freemsg(mp);
   1219 }
   1220 
   1221 /*
   1222  * Called from mi_timer(,,-2)
   1223  */
   1224 void
   1225 mi_timer_move(queue_t *q, MBLKP mp)
   1226 {
   1227 	MTBP	mtb;
   1228 	clock_t	tim;
   1229 
   1230 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
   1231 		return;
   1232 
   1233 	mtb = (MTBP)mp->b_datap->db_base;
   1234 	/*
   1235 	 * Need to untimeout and restart to make
   1236 	 * sure that the mblk is not about to be putq on the old queue
   1237 	 * by mi_timer_fire.
   1238 	 */
   1239 	if (mtb->mtb_state == TB_RUNNING) {
   1240 		if ((tim = untimeout(mtb->mtb_tid)) < 0) {
   1241 			/*
   1242 			 * Message has already been putq. Move from old queue
   1243 			 * to new queue.
   1244 			 */
   1245 			ASSERT(mtb->mtb_q->q_first == mp ||
   1246 			    mp->b_prev || mp->b_next);
   1247 			rmvq(mtb->mtb_q, mp);
   1248 			ASSERT(mtb->mtb_q->q_first != mp &&
   1249 			    mp->b_prev == NULL && mp->b_next == NULL);
   1250 			mtb->mtb_q = q;
   1251 			(void) putq(mtb->mtb_q, mp);
   1252 			return;
   1253 		}
   1254 		mtb->mtb_q = q;
   1255 		mtb->mtb_state = TB_RUNNING;
   1256 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
   1257 	} else if (mtb->mtb_state != TB_IDLE) {
   1258 		ASSERT(mtb->mtb_state != TB_TO_BE_FREED);
   1259 		/*
   1260 		 * Message is already sitting on queue. Move to new queue.
   1261 		 */
   1262 		ASSERT(mtb->mtb_q->q_first == mp ||
   1263 		    mp->b_prev || mp->b_next);
   1264 		rmvq(mtb->mtb_q, mp);
   1265 		ASSERT(mtb->mtb_q->q_first != mp &&
   1266 		    mp->b_prev == NULL && mp->b_next == NULL);
   1267 		mtb->mtb_q = q;
   1268 		(void) putq(mtb->mtb_q, mp);
   1269 	} else
   1270 		mtb->mtb_q = q;
   1271 }
   1272 
   1273 /*
   1274  * Called from mi_timer(,,-1)
   1275  */
   1276 void
   1277 mi_timer_stop(MBLKP mp)
   1278 {
   1279 	MTBP	mtb;
   1280 	int	state;
   1281 
   1282 	if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
   1283 		return;
   1284 
   1285 	mtb = (MTBP)mp->b_datap->db_base;
   1286 	state = mtb->mtb_state;
   1287 	if (state == TB_RUNNING) {
   1288 		if (untimeout(mtb->mtb_tid) < 0) {
   1289 			/* Message has already been putq */
   1290 			ASSERT(mtb->mtb_q->q_first == mp ||
   1291 			    mp->b_prev || mp->b_next);
   1292 			mtb->mtb_state = TB_CANCELLED;
   1293 		} else {
   1294 			mtb->mtb_state = TB_IDLE;
   1295 		}
   1296 	} else if (state == TB_RESCHED) {
   1297 		ASSERT(mtb->mtb_q->q_first == mp ||
   1298 		    mp->b_prev || mp->b_next);
   1299 		mtb->mtb_state = TB_CANCELLED;
   1300 	}
   1301 }
   1302 
   1303 /*
   1304  * The user of the mi_timer mechanism is required to call mi_timer_valid() for
   1305  * each M_PCSIG message processed in the service procedures.
   1306  * mi_timer_valid will return "true" if the timer actually did fire.
   1307  */
   1308 
   1309 boolean_t
   1310 mi_timer_valid(MBLKP mp)
   1311 {
   1312 	MTBP	mtb;
   1313 	int	state;
   1314 
   1315 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB) ||
   1316 	    mp->b_datap->db_type != M_PCSIG)
   1317 		return (B_FALSE);
   1318 	mtb = (MTBP)mp->b_datap->db_base;
   1319 	state = mtb->mtb_state;
   1320 	if (state != TB_RUNNING) {
   1321 		ASSERT(state != TB_IDLE);
   1322 		if (state == TB_TO_BE_FREED) {
   1323 			/*
   1324 			 * mi_timer_free was called after the message
   1325 			 * was putq'ed.
   1326 			 */
   1327 			freemsg(mp);
   1328 			return (B_FALSE);
   1329 		}
   1330 		if (state == TB_CANCELLED) {
   1331 			/* The timer was stopped after the mblk was putq'ed */
   1332 			mtb->mtb_state = TB_IDLE;
   1333 			return (B_FALSE);
   1334 		}
   1335 		if (state == TB_RESCHED) {
   1336 			/*
   1337 			 * The timer was stopped and then restarted after
   1338 			 * the mblk was putq'ed.
   1339 			 * mtb_time_left contains the number of ticks that
   1340 			 * the timer was restarted with.
   1341 			 */
   1342 			mtb->mtb_state = TB_RUNNING;
   1343 			mtb->mtb_tid = timeout((pfv_t)mi_timer_fire,
   1344 			    mtb, mtb->mtb_time_left);
   1345 			return (B_FALSE);
   1346 		}
   1347 	}
   1348 	mtb->mtb_state = TB_IDLE;
   1349 	return (B_TRUE);
   1350 }
   1351 
   1352 static void
   1353 mi_tpi_addr_and_opt(MBLKP mp, char *addr, t_scalar_t addr_length,
   1354     char *opt, t_scalar_t opt_length)
   1355 {
   1356 	struct T_unitdata_ind	*tudi;
   1357 
   1358 	/*
   1359 	 * This code is used more than just for unitdata ind
   1360 	 * (also for T_CONN_IND and T_CONN_CON) and
   1361 	 * relies on correct functioning on the happy
   1362 	 * coincidence that the address and option buffers
   1363 	 * represented by length/offset in all these primitives
   1364 	 * are isomorphic in terms of offset from start of data
   1365 	 * structure
   1366 	 */
   1367 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
   1368 	tudi->SRC_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
   1369 	tudi->SRC_length = addr_length;
   1370 	if (addr_length > 0) {
   1371 		bcopy(addr, (char *)mp->b_wptr, addr_length);
   1372 		mp->b_wptr += addr_length;
   1373 	}
   1374 	tudi->OPT_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
   1375 	tudi->OPT_length = opt_length;
   1376 	if (opt_length > 0) {
   1377 		bcopy(opt, (char *)mp->b_wptr, opt_length);
   1378 		mp->b_wptr += opt_length;
   1379 	}
   1380 }
   1381 
   1382 MBLKP
   1383 mi_tpi_conn_con(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
   1384     t_scalar_t opt_length)
   1385 {
   1386 	size_t	len;
   1387 	MBLKP	mp;
   1388 
   1389 	len = sizeof (struct T_conn_con) + src_length + opt_length;
   1390 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_CON)) != NULL) {
   1391 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_con)];
   1392 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
   1393 	}
   1394 	return (mp);
   1395 }
   1396 
   1397 MBLKP
   1398 mi_tpi_conn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
   1399     t_scalar_t opt_length, t_scalar_t seqnum)
   1400 {
   1401 	size_t	len;
   1402 	MBLKP	mp;
   1403 
   1404 	len = sizeof (struct T_conn_ind) + src_length + opt_length;
   1405 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_IND)) != NULL) {
   1406 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_ind)];
   1407 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
   1408 		((struct T_conn_ind *)mp->b_rptr)->SEQ_number = seqnum;
   1409 		mp->b_datap->db_type = M_PROTO;
   1410 	}
   1411 	return (mp);
   1412 }
   1413 
   1414 MBLKP
   1415 mi_tpi_extconn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length,
   1416     char *opt, t_scalar_t opt_length, char *dst, t_scalar_t dst_length,
   1417     t_scalar_t seqnum)
   1418 {
   1419 	size_t	len;
   1420 	MBLKP	mp;
   1421 
   1422 	len = sizeof (struct T_extconn_ind) + src_length + opt_length +
   1423 	    dst_length;
   1424 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_EXTCONN_IND)) !=
   1425 	    NULL) {
   1426 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_extconn_ind)];
   1427 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
   1428 		((struct T_extconn_ind *)mp->b_rptr)->DEST_length = dst_length;
   1429 		((struct T_extconn_ind *)mp->b_rptr)->DEST_offset =
   1430 		    (t_scalar_t)(mp->b_wptr - mp->b_rptr);
   1431 		if (dst_length > 0) {
   1432 			bcopy(dst, (char *)mp->b_wptr, dst_length);
   1433 			mp->b_wptr += dst_length;
   1434 		}
   1435 		((struct T_extconn_ind *)mp->b_rptr)->SEQ_number = seqnum;
   1436 		mp->b_datap->db_type = M_PROTO;
   1437 	}
   1438 	return (mp);
   1439 }
   1440 
   1441 MBLKP
   1442 mi_tpi_discon_ind(MBLKP trailer_mp, t_scalar_t reason, t_scalar_t seqnum)
   1443 {
   1444 	MBLKP	mp;
   1445 	struct T_discon_ind	*tdi;
   1446 
   1447 	if ((mp = mi_tpi_trailer_alloc(trailer_mp,
   1448 	    sizeof (struct T_discon_ind), T_DISCON_IND)) != NULL) {
   1449 		tdi = (struct T_discon_ind *)mp->b_rptr;
   1450 		tdi->DISCON_reason = reason;
   1451 		tdi->SEQ_number = seqnum;
   1452 	}
   1453 	return (mp);
   1454 }
   1455 
   1456 /*
   1457  * Allocate and fill in a TPI err ack packet using the 'mp' passed in
   1458  * for the 'error_prim' context as well as sacrifice.
   1459  */
   1460 MBLKP
   1461 mi_tpi_err_ack_alloc(MBLKP mp, t_scalar_t tlierr, int unixerr)
   1462 {
   1463 	struct T_error_ack	*teackp;
   1464 	t_scalar_t error_prim;
   1465 
   1466 	if (!mp)
   1467 		return (NULL);
   1468 	error_prim = ((TPRIMP)mp->b_rptr)->type;
   1469 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack),
   1470 	    M_PCPROTO, T_ERROR_ACK)) != NULL) {
   1471 		teackp = (struct T_error_ack *)mp->b_rptr;
   1472 		teackp->ERROR_prim = error_prim;
   1473 		teackp->TLI_error = tlierr;
   1474 		teackp->UNIX_error = unixerr;
   1475 	}
   1476 	return (mp);
   1477 }
   1478 
   1479 MBLKP
   1480 mi_tpi_ok_ack_alloc_extra(MBLKP mp, int extra)
   1481 {
   1482 	t_scalar_t correct_prim;
   1483 
   1484 	if (!mp)
   1485 		return (NULL);
   1486 	correct_prim = ((TPRIMP)mp->b_rptr)->type;
   1487 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack) + extra,
   1488 	    M_PCPROTO, T_OK_ACK)) != NULL) {
   1489 		((struct T_ok_ack *)mp->b_rptr)->CORRECT_prim = correct_prim;
   1490 		mp->b_wptr -= extra;
   1491 	}
   1492 	return (mp);
   1493 }
   1494 
   1495 MBLKP
   1496 mi_tpi_ok_ack_alloc(MBLKP mp)
   1497 {
   1498 	return (mi_tpi_ok_ack_alloc_extra(mp, 0));
   1499 }
   1500 
   1501 MBLKP
   1502 mi_tpi_ordrel_ind(void)
   1503 {
   1504 	MBLKP	mp;
   1505 
   1506 	if ((mp = allocb(sizeof (struct T_ordrel_ind), BPRI_HI)) != NULL) {
   1507 		mp->b_datap->db_type = M_PROTO;
   1508 		((struct T_ordrel_ind *)mp->b_rptr)->PRIM_type = T_ORDREL_IND;
   1509 		mp->b_wptr += sizeof (struct T_ordrel_ind);
   1510 	}
   1511 	return (mp);
   1512 }
   1513 
   1514 static MBLKP
   1515 mi_tpi_trailer_alloc(MBLKP trailer_mp, size_t size, t_scalar_t type)
   1516 {
   1517 	MBLKP	mp;
   1518 
   1519 	if ((mp = allocb(size, BPRI_MED)) != NULL) {
   1520 		mp->b_cont = trailer_mp;
   1521 		mp->b_datap->db_type = M_PROTO;
   1522 		((union T_primitives *)mp->b_rptr)->type = type;
   1523 		mp->b_wptr += size;
   1524 	}
   1525 	return (mp);
   1526 }
   1527 
   1528 MBLKP
   1529 mi_tpi_uderror_ind(char *dest, t_scalar_t dest_length, char *opt,
   1530     t_scalar_t opt_length, t_scalar_t error)
   1531 {
   1532 	size_t	len;
   1533 	MBLKP	mp;
   1534 	struct T_uderror_ind	*tudei;
   1535 
   1536 	len = sizeof (struct T_uderror_ind) + dest_length + opt_length;
   1537 	if ((mp = allocb(len, BPRI_HI)) != NULL) {
   1538 		mp->b_datap->db_type = M_PROTO;
   1539 		tudei = (struct T_uderror_ind *)mp->b_rptr;
   1540 		tudei->PRIM_type = T_UDERROR_IND;
   1541 		tudei->ERROR_type = error;
   1542 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_uderror_ind)];
   1543 		mi_tpi_addr_and_opt(mp, dest, dest_length, opt, opt_length);
   1544 	}
   1545 	return (mp);
   1546 }
   1547 
   1548 IDP
   1549 mi_zalloc(size_t size)
   1550 {
   1551 	IDP	ptr;
   1552 
   1553 	if (ptr = mi_alloc(size, BPRI_LO))
   1554 		bzero(ptr, size);
   1555 	return (ptr);
   1556 }
   1557 
   1558 IDP
   1559 mi_zalloc_sleep(size_t size)
   1560 {
   1561 	IDP	ptr;
   1562 
   1563 	if (ptr = mi_alloc_sleep(size, BPRI_LO))
   1564 		bzero(ptr, size);
   1565 	return (ptr);
   1566 }
   1567