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