xref: /titanic_52/usr/src/uts/common/inet/mi.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1990 Mentat Inc. */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <sys/types.h>
31 #include <inet/common.h>	/* for various inet/mi.h and inet/nd.h needs */
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/strsun.h>
35 #include <sys/sysmacros.h>
36 #include <inet/nd.h>
37 #include <inet/mi.h>
38 #define	_SUN_TPI_VERSION 2
39 #include <sys/tihdr.h>
40 #include <sys/timod.h>
41 #include <sys/vtrace.h>
42 #include <sys/kmem.h>
43 #include <sys/mkdev.h>
44 #include <sys/strlog.h>
45 #include <sys/ddi.h>
46 #include <sys/suntpi.h>
47 #include <sys/cmn_err.h>
48 #include <sys/debug.h>
49 #include <sys/kobj.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, "0x%p_", (void *)mi_headp);
824 		(void) sprintf(strchr(arena_name, '_') + 1, "minor");
825 		mi_head = (mi_head_t *)mi_zalloc_sleep(sizeof (mi_head_t));
826 		*mi_headp = (void *)mi_head;
827 		/* Setup doubly linked list */
828 		mi_head->mh_o.mi_o_next = &mi_head->mh_o;
829 		mi_head->mh_o.mi_o_prev = &mi_head->mh_o;
830 		mi_head->mh_o.mi_o_dev = 0;	/* For asserts only */
831 		mi_head->mh_arena = (vmem_t *)inet_minor_create(arena_name,
832 		    INET_MIN_DEV, KM_SLEEP);
833 	}
834 	ASSERT(ptr != NULL);
835 	mi_o = (MI_OP)ptr;
836 	mi_o--;
837 
838 	if (sflag == MODOPEN) {
839 		devp = NULL;
840 		/*
841 		 * Set device number to MAXMIN + incrementing number.
842 		 */
843 		dev = MAXMIN + ++mi_head->mh_module_dev;
844 		/* check for wraparound */
845 		if (dev <= MAXMIN) {
846 			dev = MAXMIN + 1;
847 			mi_head->mh_module_dev = 1;
848 		}
849 	} else if (devp == NULL) {
850 		/* Detached open */
851 		dev = (dev_t)OPENFAIL;
852 	} else if ((dev = inet_minor_alloc(mi_head->mh_arena)) == 0) {
853 		return (EBUSY);
854 	}
855 
856 	mi_o->mi_o_dev = dev;
857 	insert = (&mi_head->mh_o);
858 	mi_o->mi_o_next = insert;
859 	insert->mi_o_prev->mi_o_next = mi_o;
860 	mi_o->mi_o_prev = insert->mi_o_prev;
861 	insert->mi_o_prev = mi_o;
862 
863 	if (sflag == MODOPEN)
864 		mi_o->mi_o_isdev = B_FALSE;
865 	else
866 		mi_o->mi_o_isdev = B_TRUE;
867 
868 	if (devp)
869 		*devp = makedevice(getemajor(*devp), (minor_t)dev);
870 	return (0);
871 }
872 
873 uint8_t *
874 mi_offset_param(mblk_t *mp, size_t offset, size_t len)
875 {
876 	size_t	msg_len;
877 
878 	if (!mp)
879 		return (NULL);
880 	msg_len = mp->b_wptr - mp->b_rptr;
881 	if (msg_len == 0 || offset > msg_len || len > msg_len ||
882 	    (offset + len) > msg_len || len == 0)
883 		return (NULL);
884 	return (&mp->b_rptr[offset]);
885 }
886 
887 uint8_t *
888 mi_offset_paramc(mblk_t *mp, size_t offset, size_t len)
889 {
890 	uint8_t	*param;
891 
892 	for (; mp; mp = mp->b_cont) {
893 		int type = mp->b_datap->db_type;
894 		if (datamsg(type)) {
895 			if (param = mi_offset_param(mp, offset, len))
896 				return (param);
897 			if (offset < mp->b_wptr - mp->b_rptr)
898 				break;
899 			offset -= mp->b_wptr - mp->b_rptr;
900 		}
901 	}
902 	return (NULL);
903 }
904 
905 
906 boolean_t
907 mi_set_sth_hiwat(queue_t *q, size_t size)
908 {
909 	MBLKP	mp;
910 	STROPTP stropt;
911 
912 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
913 		return (B_FALSE);
914 	mp->b_datap->db_type = M_SETOPTS;
915 	mp->b_wptr += sizeof (*stropt);
916 	stropt = (STROPTP)mp->b_rptr;
917 	stropt->so_flags = SO_HIWAT;
918 	stropt->so_hiwat = size;
919 	putnext(q, mp);
920 	return (B_TRUE);
921 }
922 
923 boolean_t
924 mi_set_sth_lowat(queue_t *q, size_t size)
925 {
926 	MBLKP	mp;
927 	STROPTP stropt;
928 
929 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
930 		return (B_FALSE);
931 	mp->b_datap->db_type = M_SETOPTS;
932 	mp->b_wptr += sizeof (*stropt);
933 	stropt = (STROPTP)mp->b_rptr;
934 	stropt->so_flags = SO_LOWAT;
935 	stropt->so_lowat = size;
936 	putnext(q, mp);
937 	return (B_TRUE);
938 }
939 
940 /* ARGSUSED */
941 boolean_t
942 mi_set_sth_maxblk(queue_t *q, ssize_t size)
943 {
944 	MBLKP	mp;
945 	STROPTP stropt;
946 
947 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
948 		return (B_FALSE);
949 	mp->b_datap->db_type = M_SETOPTS;
950 	mp->b_wptr += sizeof (*stropt);
951 	stropt = (STROPTP)mp->b_rptr;
952 	stropt->so_flags = SO_MAXBLK;
953 	stropt->so_maxblk = size;
954 	putnext(q, mp);
955 	return (B_TRUE);
956 }
957 
958 boolean_t
959 mi_set_sth_copyopt(queue_t *q, int copyopt)
960 {
961 	MBLKP	mp;
962 	STROPTP stropt;
963 
964 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
965 		return (B_FALSE);
966 	mp->b_datap->db_type = M_SETOPTS;
967 	mp->b_wptr += sizeof (*stropt);
968 	stropt = (STROPTP)mp->b_rptr;
969 	stropt->so_flags = SO_COPYOPT;
970 	stropt->so_copyopt = (ushort_t)copyopt;
971 	putnext(q, mp);
972 	return (B_TRUE);
973 }
974 
975 boolean_t
976 mi_set_sth_wroff(queue_t *q, size_t size)
977 {
978 	MBLKP	mp;
979 	STROPTP stropt;
980 
981 	if (!(mp = allocb(sizeof (*stropt), BPRI_LO)))
982 		return (B_FALSE);
983 	mp->b_datap->db_type = M_SETOPTS;
984 	mp->b_wptr += sizeof (*stropt);
985 	stropt = (STROPTP)mp->b_rptr;
986 	stropt->so_flags = SO_WROFF;
987 	stropt->so_wroff = (ushort_t)size;
988 	putnext(q, mp);
989 	return (B_TRUE);
990 }
991 
992 int
993 mi_sprintf(char *buf, char *fmt, ...)
994 {
995 	va_list	ap;
996 	int	count = -1;
997 	va_start(ap, fmt);
998 	if (buf) {
999 		count = mi_iprintf(fmt, ap, (pfi_t)mi_sprintf_putc,
1000 		    (char *)&buf);
1001 		if (count != -1)
1002 			(void) mi_sprintf_putc((char *)&buf, '\0');
1003 	}
1004 	va_end(ap);
1005 	return (count);
1006 }
1007 
1008 /* Used to count without writing data */
1009 /* ARGSUSED1 */
1010 static int
1011 mi_sprintf_noop(char *cookie, int ch)
1012 {
1013 	char	**cpp = (char **)cookie;
1014 
1015 	(*cpp)++;
1016 	return (1);
1017 }
1018 
1019 int
1020 mi_sprintf_putc(char *cookie, int ch)
1021 {
1022 	char	**cpp = (char **)cookie;
1023 
1024 	**cpp = (char)ch;
1025 	(*cpp)++;
1026 	return (1);
1027 }
1028 
1029 int
1030 mi_strcmp(const char *cp1, const char *cp2)
1031 {
1032 	while (*cp1++ == *cp2++) {
1033 		if (!cp2[-1])
1034 			return (0);
1035 	}
1036 	return ((uint_t)cp2[-1]  & 0xFF) - ((uint_t)cp1[-1] & 0xFF);
1037 }
1038 
1039 size_t
1040 mi_strlen(const char *str)
1041 {
1042 	const char *cp = str;
1043 
1044 	while (*cp != '\0')
1045 		cp++;
1046 	return ((int)(cp - str));
1047 }
1048 
1049 int
1050 mi_strlog(queue_t *q, char level, ushort_t flags, char *fmt, ...)
1051 {
1052 	va_list	ap;
1053 	char	buf[200];
1054 	char	*alloc_buf = buf;
1055 	int	count = -1;
1056 	char	*cp;
1057 	short	mid;
1058 	int	ret;
1059 	short	sid;
1060 
1061 	sid = 0;
1062 	mid = 0;
1063 	if (q != NULL) {
1064 		mid = q->q_qinfo->qi_minfo->mi_idnum;
1065 	}
1066 
1067 	/* Find out how many bytes we need and allocate if necesary */
1068 	va_start(ap, fmt);
1069 	cp = buf;
1070 	count = mi_iprintf(fmt, ap, mi_sprintf_noop, (char *)&cp);
1071 	if (count > sizeof (buf) &&
1072 	    !(alloc_buf = mi_alloc((uint_t)count + 2, BPRI_MED))) {
1073 		va_end(ap);
1074 		return (-1);
1075 	}
1076 	va_end(ap);
1077 
1078 	va_start(ap, fmt);
1079 	cp = alloc_buf;
1080 	count = mi_iprintf(fmt, ap, mi_sprintf_putc, (char *)&cp);
1081 	if (count != -1)
1082 		(void) mi_sprintf_putc((char *)&cp, '\0');
1083 	else
1084 		alloc_buf[0] = '\0';
1085 	va_end(ap);
1086 
1087 	ret = strlog(mid, sid, level, flags, alloc_buf);
1088 	if (alloc_buf != buf)
1089 		mi_free(alloc_buf);
1090 	return (ret);
1091 }
1092 
1093 long
1094 mi_strtol(const char *str, char **ptr, int base)
1095 {
1096 	const char *cp;
1097 	int	digits;
1098 	long	value;
1099 	boolean_t	is_negative;
1100 
1101 	cp = str;
1102 	while (*cp == ' ' || *cp == '\t' || *cp == '\n')
1103 		cp++;
1104 	is_negative = (*cp == '-');
1105 	if (is_negative)
1106 		cp++;
1107 	if (base == 0) {
1108 		base = 10;
1109 		if (*cp == '0') {
1110 			base = 8;
1111 			cp++;
1112 			if (*cp == 'x' || *cp == 'X') {
1113 				base = 16;
1114 				cp++;
1115 			}
1116 		}
1117 	}
1118 	value = 0;
1119 	for (; *cp != '\0'; cp++) {
1120 		if (*cp >= '0' && *cp <= '9')
1121 			digits = *cp - '0';
1122 		else if (*cp >= 'a' && *cp <= 'f')
1123 			digits = *cp - 'a' + 10;
1124 		else if (*cp >= 'A' && *cp <= 'F')
1125 			digits = *cp - 'A' + 10;
1126 		else
1127 			break;
1128 		if (digits >= base)
1129 			break;
1130 		value = (value * base) + digits;
1131 	}
1132 	/* Note: we cast away const here deliberately */
1133 	if (ptr != NULL)
1134 		*ptr = (char *)cp;
1135 	if (is_negative)
1136 		value = -value;
1137 	return (value);
1138 }
1139 
1140 /*
1141  *		mi_timer mechanism.
1142  *
1143  * Each timer is represented by a timer mblk and a (streams) queue. When the
1144  * timer fires the timer mblk will be put on the associated streams queue
1145  * so that the streams module can process the timer even in its service
1146  * procedure.
1147  *
1148  * The interface consists of 4 entry points:
1149  *	mi_timer_alloc		- create a timer mblk
1150  *	mi_timer_free		- free a timer mblk
1151  *	mi_timer		- start, restart, stop, or move the
1152  *				  timer to a different queue
1153  *	mi_timer_valid		- called by streams module to verify that
1154  *				  the timer did indeed fire.
1155  */
1156 
1157 
1158 
1159 
1160 /*
1161  * Start, restart, stop, or move the timer to a new queue.
1162  * If "tim" is -2 the timer is moved to a different queue.
1163  * If "tim" is -1 the timer is stopped.
1164  * Otherwise, the timer is stopped if it is already running, and
1165  * set to fire tim milliseconds from now.
1166  */
1167 
1168 void
1169 mi_timer(queue_t *q, MBLKP mp, clock_t tim)
1170 {
1171 	MTBP	mtb;
1172 	int	state;
1173 
1174 	ASSERT(tim >= -2);
1175 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1176 		return;
1177 	mtb = (MTBP)mp->b_datap->db_base;
1178 	ASSERT(mp->b_datap->db_type == M_PCSIG);
1179 	if (tim >= 0) {
1180 		mtb->mtb_q = q;
1181 		state = mtb->mtb_state;
1182 		tim = MSEC_TO_TICK(tim);
1183 		if (state == TB_RUNNING) {
1184 			if (untimeout(mtb->mtb_tid) < 0) {
1185 				/* Message has already been putq */
1186 				ASSERT(mtb->mtb_q->q_first == mp ||
1187 				    mp->b_prev || mp->b_next);
1188 				mtb->mtb_state = TB_RESCHED;
1189 				mtb->mtb_time_left = tim;
1190 				/* mi_timer_valid will start timer */
1191 				return;
1192 			}
1193 		} else if (state != TB_IDLE) {
1194 			ASSERT(state != TB_TO_BE_FREED);
1195 			if (state == TB_CANCELLED) {
1196 				ASSERT(mtb->mtb_q->q_first == mp ||
1197 				    mp->b_prev || mp->b_next);
1198 				mtb->mtb_state = TB_RESCHED;
1199 				mtb->mtb_time_left = tim;
1200 				/* mi_timer_valid will start timer */
1201 				return;
1202 			}
1203 			if (state == TB_RESCHED) {
1204 				ASSERT(mtb->mtb_q->q_first == mp ||
1205 				    mp->b_prev || mp->b_next);
1206 				mtb->mtb_time_left = tim;
1207 				/* mi_timer_valid will start timer */
1208 				return;
1209 			}
1210 		}
1211 		mtb->mtb_state = TB_RUNNING;
1212 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
1213 		return;
1214 	}
1215 	switch (tim) {
1216 	case -1:
1217 		mi_timer_stop(mp);
1218 		break;
1219 	case -2:
1220 		mi_timer_move(q, mp);
1221 		break;
1222 	}
1223 }
1224 
1225 /*
1226  * Allocate an M_PCSIG timer message. The space between db_base and
1227  * b_rptr is used by the mi_timer mechanism, and after b_rptr there are
1228  * "size" bytes that the caller can use for its own purposes.
1229  *
1230  * Note that db_type has to be a priority message since otherwise
1231  * the putq will not cause the service procedure to run when
1232  * there is flow control.
1233  */
1234 MBLKP
1235 mi_timer_alloc(size_t size)
1236 {
1237 	MBLKP	mp;
1238 	MTBP	mtb;
1239 
1240 	if ((mp = allocb(size + sizeof (MTB), BPRI_HI)) != NULL) {
1241 		mp->b_datap->db_type = M_PCSIG;
1242 		mtb = (MTBP)mp->b_datap->db_base;
1243 		mp->b_rptr = (uchar_t *)&mtb[1];
1244 		mp->b_wptr = mp->b_rptr + size;
1245 		mtb->mtb_state = TB_IDLE;
1246 		mtb->mtb_mp = mp;
1247 		mtb->mtb_q = NULL;
1248 		return (mp);
1249 	}
1250 	return (NULL);
1251 }
1252 
1253 /*
1254  * timeout() callback function.
1255  * Put the message on the current queue.
1256  * If the timer is stopped or moved to a different queue after
1257  * it has fired then mi_timer() and mi_timer_valid() will clean
1258  * things up.
1259  */
1260 static int
1261 mi_timer_fire(MTBP mtb)
1262 {
1263 	ASSERT(mtb == (MTBP)mtb->mtb_mp->b_datap->db_base);
1264 	ASSERT(mtb->mtb_mp->b_datap->db_type == M_PCSIG);
1265 	return (putq(mtb->mtb_q, mtb->mtb_mp));
1266 }
1267 
1268 /*
1269  * Logically free a timer mblk (that might have a pending timeout().)
1270  * If the timer has fired and the mblk has been put on the queue then
1271  * mi_timer_valid will free the mblk.
1272  */
1273 
1274 void
1275 mi_timer_free(MBLKP mp)
1276 {
1277 	MTBP	mtb;
1278 	int	state;
1279 
1280 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1281 		return;
1282 	mtb = (MTBP)mp->b_datap->db_base;
1283 	state = mtb->mtb_state;
1284 	if (state == TB_RUNNING) {
1285 		if (untimeout(mtb->mtb_tid) < 0) {
1286 			/* Message has already been putq */
1287 			ASSERT(mtb->mtb_q->q_first == mp ||
1288 			    mp->b_prev || mp->b_next);
1289 			mtb->mtb_state = TB_TO_BE_FREED;
1290 			/* mi_timer_valid will free the mblk */
1291 			return;
1292 		}
1293 	} else if (state != TB_IDLE) {
1294 		/* Message has already been putq */
1295 		ASSERT(mtb->mtb_q->q_first == mp ||
1296 		    mp->b_prev || mp->b_next);
1297 		ASSERT(state != TB_TO_BE_FREED);
1298 		mtb->mtb_state = TB_TO_BE_FREED;
1299 		/* mi_timer_valid will free the mblk */
1300 		return;
1301 	}
1302 	ASSERT(mtb->mtb_q ==  NULL || mtb->mtb_q->q_first != mp);
1303 	freemsg(mp);
1304 }
1305 
1306 /*
1307  * Called from mi_timer(,,-2)
1308  */
1309 void
1310 mi_timer_move(queue_t *q, MBLKP mp)
1311 {
1312 	MTBP	mtb;
1313 	clock_t	tim;
1314 
1315 	if (!q || !mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1316 		return;
1317 
1318 	mtb = (MTBP)mp->b_datap->db_base;
1319 	/*
1320 	 * Need to untimeout and restart to make
1321 	 * sure that the mblk is not about to be putq on the old queue
1322 	 * by mi_timer_fire.
1323 	 */
1324 	if (mtb->mtb_state == TB_RUNNING) {
1325 		if ((tim = untimeout(mtb->mtb_tid)) < 0) {
1326 			/*
1327 			 * Message has already been putq. Move from old queue
1328 			 * to new queue.
1329 			 */
1330 			ASSERT(mtb->mtb_q->q_first == mp ||
1331 			    mp->b_prev || mp->b_next);
1332 			rmvq(mtb->mtb_q, mp);
1333 			ASSERT(mtb->mtb_q->q_first != mp &&
1334 			    mp->b_prev == NULL && mp->b_next == NULL);
1335 			mtb->mtb_q = q;
1336 			(void) putq(mtb->mtb_q, mp);
1337 			return;
1338 		}
1339 		mtb->mtb_q = q;
1340 		mtb->mtb_state = TB_RUNNING;
1341 		mtb->mtb_tid = timeout((pfv_t)mi_timer_fire, mtb, tim);
1342 	} else if (mtb->mtb_state != TB_IDLE) {
1343 		ASSERT(mtb->mtb_state != TB_TO_BE_FREED);
1344 		/*
1345 		 * Message is already sitting on queue. Move to new queue.
1346 		 */
1347 		ASSERT(mtb->mtb_q->q_first == mp ||
1348 		    mp->b_prev || mp->b_next);
1349 		rmvq(mtb->mtb_q, mp);
1350 		ASSERT(mtb->mtb_q->q_first != mp &&
1351 		    mp->b_prev == NULL && mp->b_next == NULL);
1352 		mtb->mtb_q = q;
1353 		(void) putq(mtb->mtb_q, mp);
1354 	} else
1355 		mtb->mtb_q = q;
1356 }
1357 
1358 /*
1359  * Called from mi_timer(,,-1)
1360  */
1361 void
1362 mi_timer_stop(MBLKP mp)
1363 {
1364 	MTBP	mtb;
1365 	int	state;
1366 
1367 	if (!mp || (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB))
1368 		return;
1369 
1370 	mtb = (MTBP)mp->b_datap->db_base;
1371 	state = mtb->mtb_state;
1372 	if (state == TB_RUNNING) {
1373 		if (untimeout(mtb->mtb_tid) < 0) {
1374 			/* Message has already been putq */
1375 			ASSERT(mtb->mtb_q->q_first == mp ||
1376 			    mp->b_prev || mp->b_next);
1377 			mtb->mtb_state = TB_CANCELLED;
1378 		} else {
1379 			mtb->mtb_state = TB_IDLE;
1380 		}
1381 	} else if (state == TB_RESCHED) {
1382 		ASSERT(mtb->mtb_q->q_first == mp ||
1383 		    mp->b_prev || mp->b_next);
1384 		mtb->mtb_state = TB_CANCELLED;
1385 	}
1386 }
1387 
1388 /*
1389  * The user of the mi_timer mechanism is required to call mi_timer_valid() for
1390  * each M_PCSIG message processed in the service procedures.
1391  * mi_timer_valid will return "true" if the timer actually did fire.
1392  */
1393 
1394 boolean_t
1395 mi_timer_valid(MBLKP mp)
1396 {
1397 	MTBP	mtb;
1398 	int	state;
1399 
1400 	if (!mp	|| (mp->b_rptr - mp->b_datap->db_base) != sizeof (MTB) ||
1401 	    mp->b_datap->db_type != M_PCSIG)
1402 		return (B_FALSE);
1403 	mtb = (MTBP)mp->b_datap->db_base;
1404 	state = mtb->mtb_state;
1405 	if (state != TB_RUNNING) {
1406 		ASSERT(state != TB_IDLE);
1407 		if (state == TB_TO_BE_FREED) {
1408 			/*
1409 			 * mi_timer_free was called after the message
1410 			 * was putq'ed.
1411 			 */
1412 			freemsg(mp);
1413 			return (B_FALSE);
1414 		}
1415 		if (state == TB_CANCELLED) {
1416 			/* The timer was stopped after the mblk was putq'ed */
1417 			mtb->mtb_state = TB_IDLE;
1418 			return (B_FALSE);
1419 		}
1420 		if (state == TB_RESCHED) {
1421 			/*
1422 			 * The timer was stopped and then restarted after
1423 			 * the mblk was putq'ed.
1424 			 * mtb_time_left contains the number of ticks that
1425 			 * the timer was restarted with.
1426 			 */
1427 			mtb->mtb_state = TB_RUNNING;
1428 			mtb->mtb_tid = timeout((pfv_t)mi_timer_fire,
1429 			    mtb, mtb->mtb_time_left);
1430 			return (B_FALSE);
1431 		}
1432 	}
1433 	mtb->mtb_state = TB_IDLE;
1434 	return (B_TRUE);
1435 }
1436 
1437 static void
1438 mi_tpi_addr_and_opt(MBLKP mp, char *addr, t_scalar_t addr_length,
1439     char *opt, t_scalar_t opt_length)
1440 {
1441 	struct T_unitdata_ind	*tudi;
1442 
1443 	/*
1444 	 * This code is used more than just for unitdata ind
1445 	 * (also for T_CONN_IND and T_CONN_CON) and
1446 	 * relies on correct functioning on the happy
1447 	 * coincidence that the the address and option buffers
1448 	 * represented by length/offset in all these primitives
1449 	 * are isomorphic in terms of offset from start of data
1450 	 * structure
1451 	 */
1452 	tudi = (struct T_unitdata_ind *)mp->b_rptr;
1453 	tudi->SRC_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
1454 	tudi->SRC_length = addr_length;
1455 	if (addr_length > 0) {
1456 		bcopy(addr, (char *)mp->b_wptr, addr_length);
1457 		mp->b_wptr += addr_length;
1458 	}
1459 	tudi->OPT_offset = (t_scalar_t)(mp->b_wptr - mp->b_rptr);
1460 	tudi->OPT_length = opt_length;
1461 	if (opt_length > 0) {
1462 		bcopy(opt, (char *)mp->b_wptr, opt_length);
1463 		mp->b_wptr += opt_length;
1464 	}
1465 }
1466 
1467 MBLKP
1468 mi_tpi_conn_con(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
1469     t_scalar_t opt_length)
1470 {
1471 	size_t	len;
1472 	MBLKP	mp;
1473 
1474 	len = sizeof (struct T_conn_con) + src_length + opt_length;
1475 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_CON)) != NULL) {
1476 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_con)];
1477 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1478 	}
1479 	return (mp);
1480 }
1481 
1482 MBLKP
1483 mi_tpi_conn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length, char *opt,
1484     t_scalar_t opt_length, t_scalar_t seqnum)
1485 {
1486 	size_t	len;
1487 	MBLKP	mp;
1488 
1489 	len = sizeof (struct T_conn_ind) + src_length + opt_length;
1490 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_CONN_IND)) != NULL) {
1491 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_conn_ind)];
1492 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1493 		((struct T_conn_ind *)mp->b_rptr)->SEQ_number = seqnum;
1494 		mp->b_datap->db_type = M_PROTO;
1495 	}
1496 	return (mp);
1497 }
1498 
1499 MBLKP
1500 mi_tpi_extconn_ind(MBLKP trailer_mp, char *src, t_scalar_t src_length,
1501     char *opt, t_scalar_t opt_length, char *dst, t_scalar_t dst_length,
1502     t_scalar_t seqnum)
1503 {
1504 	size_t	len;
1505 	MBLKP	mp;
1506 
1507 	len = sizeof (struct T_extconn_ind) + src_length + opt_length +
1508 	    dst_length;
1509 	if ((mp = mi_tpi_trailer_alloc(trailer_mp, len, T_EXTCONN_IND)) !=
1510 	    NULL) {
1511 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_extconn_ind)];
1512 		mi_tpi_addr_and_opt(mp, src, src_length, opt, opt_length);
1513 		((struct T_extconn_ind *)mp->b_rptr)->DEST_length = dst_length;
1514 		((struct T_extconn_ind *)mp->b_rptr)->DEST_offset =
1515 			(t_scalar_t)(mp->b_wptr - mp->b_rptr);
1516 		if (dst_length > 0) {
1517 			bcopy(dst, (char *)mp->b_wptr, dst_length);
1518 			mp->b_wptr += dst_length;
1519 		}
1520 		((struct T_extconn_ind *)mp->b_rptr)->SEQ_number = seqnum;
1521 		mp->b_datap->db_type = M_PROTO;
1522 	}
1523 	return (mp);
1524 }
1525 
1526 MBLKP
1527 mi_tpi_discon_ind(MBLKP trailer_mp, t_scalar_t reason, t_scalar_t seqnum)
1528 {
1529 	MBLKP	mp;
1530 	struct T_discon_ind	*tdi;
1531 
1532 	if ((mp = mi_tpi_trailer_alloc(trailer_mp,
1533 	    sizeof (struct T_discon_ind), T_DISCON_IND)) != NULL) {
1534 		tdi = (struct T_discon_ind *)mp->b_rptr;
1535 		tdi->DISCON_reason = reason;
1536 		tdi->SEQ_number = seqnum;
1537 	}
1538 	return (mp);
1539 }
1540 
1541 /*
1542  * Allocate and fill in a TPI err ack packet using the 'mp' passed in
1543  * for the 'error_prim' context as well as sacrifice.
1544  */
1545 MBLKP
1546 mi_tpi_err_ack_alloc(MBLKP mp, t_scalar_t tlierr, int unixerr)
1547 {
1548 	struct T_error_ack	*teackp;
1549 	t_scalar_t error_prim;
1550 
1551 	if (!mp)
1552 		return (NULL);
1553 	error_prim = ((TPRIMP)mp->b_rptr)->type;
1554 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack),
1555 	    M_PCPROTO, T_ERROR_ACK)) != NULL) {
1556 		teackp = (struct T_error_ack *)mp->b_rptr;
1557 		teackp->ERROR_prim = error_prim;
1558 		teackp->TLI_error = tlierr;
1559 		teackp->UNIX_error = unixerr;
1560 	}
1561 	return (mp);
1562 }
1563 
1564 MBLKP
1565 mi_tpi_ok_ack_alloc_extra(MBLKP mp, int extra)
1566 {
1567 	t_scalar_t correct_prim;
1568 
1569 	if (!mp)
1570 		return (NULL);
1571 	correct_prim = ((TPRIMP)mp->b_rptr)->type;
1572 	if ((mp = tpi_ack_alloc(mp, sizeof (struct T_ok_ack) + extra,
1573 	    M_PCPROTO, T_OK_ACK)) != NULL) {
1574 		((struct T_ok_ack *)mp->b_rptr)->CORRECT_prim = correct_prim;
1575 		mp->b_wptr -= extra;
1576 	}
1577 	return (mp);
1578 }
1579 
1580 MBLKP
1581 mi_tpi_ok_ack_alloc(MBLKP mp)
1582 {
1583 	return (mi_tpi_ok_ack_alloc_extra(mp, 0));
1584 }
1585 
1586 MBLKP
1587 mi_tpi_ordrel_ind(void)
1588 {
1589 	MBLKP	mp;
1590 
1591 	if ((mp = allocb(sizeof (struct T_ordrel_ind), BPRI_HI)) != NULL) {
1592 		mp->b_datap->db_type = M_PROTO;
1593 		((struct T_ordrel_ind *)mp->b_rptr)->PRIM_type = T_ORDREL_IND;
1594 		mp->b_wptr += sizeof (struct T_ordrel_ind);
1595 	}
1596 	return (mp);
1597 }
1598 
1599 static MBLKP
1600 mi_tpi_trailer_alloc(MBLKP trailer_mp, size_t size, t_scalar_t type)
1601 {
1602 	MBLKP	mp;
1603 
1604 	if ((mp = allocb(size, BPRI_MED)) != NULL) {
1605 		mp->b_cont = trailer_mp;
1606 		mp->b_datap->db_type = M_PROTO;
1607 		((union T_primitives *)mp->b_rptr)->type = type;
1608 		mp->b_wptr += size;
1609 	}
1610 	return (mp);
1611 }
1612 
1613 MBLKP
1614 mi_tpi_uderror_ind(char *dest, t_scalar_t dest_length, char *opt,
1615     t_scalar_t opt_length, t_scalar_t error)
1616 {
1617 	size_t	len;
1618 	MBLKP	mp;
1619 	struct T_uderror_ind	*tudei;
1620 
1621 	len = sizeof (struct T_uderror_ind) + dest_length + opt_length;
1622 	if ((mp = allocb(len, BPRI_HI)) != NULL) {
1623 		mp->b_datap->db_type = M_PROTO;
1624 		tudei = (struct T_uderror_ind *)mp->b_rptr;
1625 		tudei->PRIM_type = T_UDERROR_IND;
1626 		tudei->ERROR_type = error;
1627 		mp->b_wptr = &mp->b_rptr[sizeof (struct T_uderror_ind)];
1628 		mi_tpi_addr_and_opt(mp, dest, dest_length, opt, opt_length);
1629 	}
1630 	return (mp);
1631 }
1632 
1633 IDP
1634 mi_zalloc(size_t size)
1635 {
1636 	IDP	ptr;
1637 
1638 	if (ptr = mi_alloc(size, BPRI_LO))
1639 		bzero(ptr, size);
1640 	return (ptr);
1641 }
1642 
1643 IDP
1644 mi_zalloc_sleep(size_t size)
1645 {
1646 	IDP	ptr;
1647 
1648 	if (ptr = mi_alloc_sleep(size, BPRI_LO))
1649 		bzero(ptr, size);
1650 	return (ptr);
1651 }
1652