Home | History | Annotate | Download | only in inet
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 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, MAXMIN, 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] &