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