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
68typedef	struct	stroptions *STROPTP;
69typedef 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
81typedef 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
89static int mi_timer_fire(MTBP);
90static int mi_iprintf(char *, va_list, pfi_t, char *);
91static void mi_tpi_addr_and_opt(MBLKP, char *, t_scalar_t, char *, t_scalar_t);
92static MBLKP mi_tpi_trailer_alloc(MBLKP, size_t, t_scalar_t);
93
94/* ARGSUSED1 */
95void *
96mi_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 */
109void *
110mi_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
120int
121mi_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
132void
133mi_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
177void
178mi_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 */
202void
203mi_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
267err_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 */
293void
294mi_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
312void
313mi_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
371MBLKP
372mi_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
412void
413mi_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
440int
441mi_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
465void
466mi_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
478static int
479mi_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 */
633int
634mi_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 */
651int
652mi_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
669int
670mi_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
686IDP
687mi_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 */
702IDP
703mi_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
717IDP
718mi_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 */
732IDP
733mi_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 */
752int
753mi_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
772IDP
773mi_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
785IDP
786mi_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 */
805int
806mi_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
875uint8_t *
876mi_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
889uint8_t *
890mi_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
907int
908mi_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 */
925static int
926mi_sprintf_noop(char *cookie, int ch)
927{
928	char	**cpp = (char **)cookie;
929
930	(*cpp)++;
931	return (1);
932}
933
934int
935mi_sprintf_putc(char *cookie, int ch)
936{
937	char	**cpp = (char **)cookie;
938
939	**cpp = (char)ch;
940	(*cpp)++;
941	return (1);
942}
943
944int
945mi_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
954size_t
955mi_strlen(const char *str)
956{
957	const char *cp = str;
958
959	while (*cp != '\0')
960		cp++;
961	return ((int)(cp - str));
962}
963
964int
965mi_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
1008long
1009mi_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
1083void
1084mi_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 */
1149MBLKP
1150mi_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 */
1175static int
1176mi_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
1189void
1190mi_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 */
1224void
1225mi_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 */
1276void
1277mi_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
1309boolean_t
1310mi_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
1352static void
1353mi_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
1382MBLKP
1383mi_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
1397MBLKP
1398mi_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
1414MBLKP
1415mi_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
1441MBLKP
1442mi_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 */
1460MBLKP
1461mi_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
1479MBLKP
1480mi_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
1495MBLKP
1496mi_tpi_ok_ack_alloc(MBLKP mp)
1497{
1498	return (mi_tpi_ok_ack_alloc_extra(mp, 0));
1499}
1500
1501MBLKP
1502mi_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
1514static MBLKP
1515mi_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
1528MBLKP
1529mi_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
1548IDP
1549mi_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
1558IDP
1559mi_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