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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 /* Copyright (c) 1990 Mentat Inc. */
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>
35 #define _SUN_TPI_VERSION 2
36 #include <sys/tihdr.h>
37 #include <sys/timod.h>
38 #include <sys/vtrace.h>
40 #include <sys/mkdev.h>
41 #include <sys/strlog.h>
43 #include <sys/suntpi.h>
44 #include <sys/cmn_err.h>
45 #include <sys/debug.h>
47 #include <sys/stropts.h>
48 #include <sys/strsubr.h>
49 #include <inet/proto_set.h>
51 #define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9')
52 #define ISUPPER(ch) ((ch) >= 'A' && (ch) <= 'Z')
53 #define tolower(ch) ('a' + ((ch) - 'A'))
55 #define MI_IS_TRANSPARENT(mp) (mp->b_cont && \
56 (mp->b_cont->b_rptr != mp->b_cont->b_wptr))
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.
68 typedef struct stroptions
*STROPTP
;
69 typedef union T_primitives
*TPRIMP
;
71 /* Timer block states. */
75 * Could not stop/free before putq
77 #define TB_RESCHED 3 /* mtb_time_left contains tick count */
78 #define TB_CANCELLED 4
79 #define TB_TO_BE_FREED 5
81 typedef struct mtb_s
{
86 clock_t mtb_time_left
;
89 static int mi_timer_fire(MTBP
);
90 static int mi_iprintf(char *, va_list, pfi_t
, char *);
91 static void mi_tpi_addr_and_opt(MBLKP
, char *, t_scalar_t
, char *, t_scalar_t
);
92 static MBLKP
mi_tpi_trailer_alloc(MBLKP
, size_t, t_scalar_t
);
96 mi_alloc(size_t size
, uint_t pri
)
100 size
+= sizeof (size
);
101 if (ptr
= kmem_alloc(size
, KM_NOSLEEP
)) {
110 mi_alloc_sleep(size_t size
, uint_t pri
)
114 size
+= sizeof (size
);
115 ptr
= kmem_alloc(size
, KM_SLEEP
);
121 mi_close_comm(void **mi_headp
, queue_t
*q
)
126 mi_close_unlink(mi_headp
, ptr
);
128 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
133 mi_close_unlink(void **mi_headp
, IDP ptr
)
135 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
144 if (mi_o
->mi_o_next
== NULL
) {
146 ASSERT(mi_o
->mi_o_prev
== NULL
);
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
);
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
);
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
;
165 mi_o
->mi_o_dev
= (dev_t
)OPENFAIL
;
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
);
178 mi_close_free(IDP ptr
)
187 ASSERT(mi_o
->mi_o_next
== NULL
&& mi_o
->mi_o_prev
== NULL
);
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.
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.
203 mi_copyin(queue_t
*q
, MBLKP mp
, char *uaddr
, size_t len
)
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
;
211 ASSERT(mp
->b_datap
->db_type
== M_IOCTL
&& !uaddr
);
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
;
220 bcopy(mp
->b_cont
->b_rptr
, &cq
->cq_addr
, sizeof (cq
->cq_addr
));
222 mp
->b_datap
->db_type
= M_COPYIN
;
228 * A non-transparent ioctl. Need to convert into M_IOCDATA message.
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).
236 err
= miocpullup(mp
, len
);
240 mp1
= allocb(0, BPRI_MED
);
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.
250 mp1
->b_cont
= mp
->b_cont
;
252 MI_COPY_COUNT(mp
) = 1;
253 MI_COPY_DIRECTION(mp
) = MI_COPY_IN
;
254 mp
->b_cont
= mp1
->b_cont
;
258 * Leave a pointer to the 0 byte block in cp_private field for
259 * future use by the mi_copy_* routines.
261 mp
->b_datap
->db_type
= M_IOCDATA
;
262 cp
->cp_private
= mp1
;
268 iocp
->ioc_error
= err
;
274 mp
->b_datap
->db_type
= M_IOCACK
;
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.
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.
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).
294 mi_copyin_n(queue_t
*q
, MBLKP mp
, size_t offset
, size_t len
)
296 struct copyreq
*cq
= (struct copyreq
*)mp
->b_rptr
;
298 ASSERT(mp
->b_datap
->db_type
== M_IOCDATA
);
301 MI_COPY_DIRECTION(mp
) = MI_COPY_IN
;
302 cq
->cq_private
= mp
->b_cont
;
305 bcopy(mp
->b_cont
->b_rptr
, &cq
->cq_addr
, sizeof (cq
->cq_addr
));
306 cq
->cq_addr
+= offset
;
308 mp
->b_datap
->db_type
= M_COPYIN
;
313 mi_copyout(queue_t
*q
, MBLKP mp
)
315 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
316 struct copyreq
*cq
= (struct copyreq
*)iocp
;
317 struct copyresp
*cp
= (struct copyresp
*)cq
;
321 if (mp
->b_datap
->db_type
!= M_IOCDATA
|| !mp
->b_cont
) {
322 mi_copy_done(q
, mp
, EPROTO
);
325 /* Check completion of previous copyout operation. */
327 if ((int)(uintptr_t)cp
->cp_rval
|| !mp1
->b_cont
) {
328 mi_copy_done(q
, mp
, (int)(uintptr_t)cp
->cp_rval
);
331 if (!mp1
->b_cont
->b_cont
&& !MI_IS_TRANSPARENT(mp
)) {
334 mp
->b_cont
= mp1
->b_cont
;
339 iocp
->ioc_count
= mp1
->b_wptr
- mp1
->b_rptr
;
341 mp
->b_datap
->db_type
= M_IOCACK
;
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;
352 cq
->cq_private
= mp1
;
353 /* Find message preceding last. */
354 for (mp2
= mp1
; mp2
->b_cont
->b_cont
; mp2
= mp2
->b_cont
)
357 bcopy((char *)mp1
->b_rptr
, (char *)&cq
->cq_addr
,
358 sizeof (cq
->cq_addr
));
360 cq
->cq_addr
= (char *)mp2
->b_cont
->b_next
;
362 mp
->b_datap
->db_type
= M_COPYOUT
;
366 cq
->cq_size
= mp1
->b_wptr
- mp1
->b_rptr
;
372 mi_copyout_alloc(queue_t
*q
, MBLKP mp
, char *uaddr
, size_t len
,
373 boolean_t free_on_error
)
375 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
378 if (mp
->b_datap
->db_type
== M_IOCTL
) {
379 if (iocp
->ioc_count
!= TRANSPARENT
) {
380 mp1
= allocb(0, BPRI_MED
);
383 iocp
->ioc_error
= ENOMEM
;
387 mp
->b_datap
->db_type
= M_IOCACK
;
392 mp1
->b_cont
= mp
->b_cont
;
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
;
401 mp1
= allocb(len
, BPRI_MED
);
404 mi_copy_done(q
, mp
, ENOMEM
);
408 mp1
->b_next
= (MBLKP
)uaddr
;
413 mi_copy_done(queue_t
*q
, MBLKP mp
, int err
)
420 if (!q
|| (mp
->b_wptr
- mp
->b_rptr
) < sizeof (struct iocblk
)) {
424 iocp
= (struct iocblk
*)mp
->b_rptr
;
425 mp
->b_datap
->db_type
= M_IOCACK
;
426 iocp
->ioc_error
= err
;
429 if ((mp1
= mp
->b_cont
) != NULL
) {
430 for (; mp1
; mp1
= mp1
->b_cont
) {
441 mi_copy_state(queue_t
*q
, MBLKP mp
, MBLKP
*mpp
)
443 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
444 struct copyresp
*cp
= (struct copyresp
*)iocp
;
448 mp
->b_cont
= cp
->cp_private
;
450 if (mp1
->b_cont
&& !pullupmsg(mp1
, -1)) {
451 mi_copy_done(q
, mp
, ENOMEM
);
454 linkb(mp
->b_cont
, mp1
);
456 if ((int)(uintptr_t)cp
->cp_rval
) {
457 mi_copy_done(q
, mp
, (int)(uintptr_t)cp
->cp_rval
);
460 if (mpp
&& MI_COPY_DIRECTION(mp
) == MI_COPY_IN
)
462 return (MI_COPY_STATE(mp
));
472 if ((size
= ((size_t *)ptr
)[-1]) <= 0)
473 cmn_err(CE_PANIC
, "mi_free");
475 kmem_free((void *) ((size_t *)ptr
- 1), size
);
479 mi_iprintf(char *fmt
, va_list ap
, pfi_t putc_func
, char *cookie
)
482 char buf
[(sizeof (long) * 3) + 1];
483 static char hex_val
[] = "0123456789abcdef";
492 boolean_t zero_filled
;
498 if (*fmt
!= '%' || *++fmt
== '%') {
499 count
+= (*putc_func
)(cookie
, *fmt
++);
503 zero_filled
= B_TRUE
;
508 zero_filled
= B_FALSE
;
510 for (digits
= 0; ISDIGIT(*fmt
); fmt
++) {
512 digits
+= (*fmt
- '0');
530 count
+= (*putc_func
)(cookie
, va_arg(ap
, int *));
535 case 'm': /* Print out memory, 2 hex chars per byte */
537 fcp
= va_arg(ap
, char *);
539 if ((cp1
= va_arg(ap
, char *)) != NULL
)
545 for (fcp
= (char *)"(NULL)"; *fcp
; fcp
++)
546 count
+= (*putc_func
)(cookie
, *fcp
);
549 int u1
= *fcp
++ & 0xFF;
550 count
+= (*putc_func
)(cookie
,
551 hex_val
[(u1
>>4)& 0xF]);
552 count
+= (*putc_func
)(cookie
,
568 fcp
= va_arg(ap
, char *);
570 if ((cp1
= va_arg(ap
, char *)) != NULL
)
576 fcp
= (char *)"(NULL)";
578 count
+= (*putc_func
)(cookie
, *fcp
++);
579 if (digits
&& --digits
== 0)
583 count
+= (*putc_func
)(cookie
, ' ');
594 val
= va_arg(ap
, long);
596 val
= va_arg(ap
, int);
597 if (base
== 10 && ch
!= 'u') {
599 count
+= (*putc_func
)(cookie
, '-');
609 /* Hand overload/restore the register variable 'fmt' */
615 *--fmt
= hex_val
[uval
% base
];
616 if (digits
&& --digits
== 0)
618 } while (uval
/= base
);
620 while (digits
> 0 && fmt
> buf
) {
626 count
+= (*putc_func
)(cookie
, *fmt
++);
634 mi_mpprintf(MBLKP mp
, char *fmt
, ...)
641 count
= mi_iprintf(fmt
, ap
, (pfi_t
)mi_mpprintf_putc
,
644 (void) mi_mpprintf_putc((char *)mp
, '\0');
652 mi_mpprintf_nr(MBLKP mp
, char *fmt
, ...)
659 (void) adjmsg(mp
, -1);
660 count
= mi_iprintf(fmt
, ap
, (pfi_t
)mi_mpprintf_putc
,
663 (void) mi_mpprintf_putc((char *)mp
, '\0');
670 mi_mpprintf_putc(char *cookie
, int ch
)
672 MBLKP mp
= (MBLKP
)cookie
;
676 if (mp
->b_wptr
>= mp
->b_datap
->db_lim
) {
677 mp
->b_cont
= allocb(1024, BPRI_HI
);
682 *mp
->b_wptr
++ = (unsigned char)ch
;
687 mi_first_ptr(void **mi_headp
)
689 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
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]);
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.
703 mi_first_dev_ptr(void **mi_headp
)
705 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
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
;
718 mi_next_ptr(void **mi_headp
, IDP ptr
)
720 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
721 MI_OP mi_op
= ((MI_OP
)ptr
) - 1;
723 if ((mi_op
= mi_op
->mi_o_next
) != NULL
&& mi_op
!= &mi_head
->mh_o
)
724 return ((IDP
)&mi_op
[1]);
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.
733 mi_next_dev_ptr(void **mi_headp
, IDP ptr
)
735 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
736 MI_OP mi_op
= ((MI_OP
)ptr
) - 1;
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
;
748 * Self clone the device
749 * XXX - should we still support clone device
753 mi_open_comm(void **mi_headp
, size_t size
, queue_t
*q
, dev_t
*devp
,
754 int flag
, int sflag
, cred_t
*credp
)
759 if (q
->q_ptr
!= NULL
)
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
);
766 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
773 mi_open_alloc_sleep(size_t size
)
777 if (size
> (UINT_MAX
- sizeof (MI_O
)))
780 mi_o
= (MI_OP
)mi_zalloc_sleep(size
+ sizeof (MI_O
));
786 mi_open_alloc(size_t size
)
790 if (size
> (UINT_MAX
- sizeof (MI_O
)))
793 if ((mi_o
= (MI_OP
)mi_zalloc(size
+ sizeof (MI_O
))) == NULL
)
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.
806 mi_open_link(void **mi_headp
, IDP ptr
, dev_t
*devp
, int flag
, int sflag
,
809 mi_head_t
*mi_head
= *(mi_head_t
**)mi_headp
;
814 if (mi_head
== NULL
) {
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
);
823 (void) sprintf(arena_name
, "Hex0x%p_",
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
);
840 if (sflag
== MODOPEN
) {
843 * Set device number to MAXMIN + incrementing number.
845 dev
= MAXMIN
+ ++mi_head
->mh_module_dev
;
846 /* check for wraparound */
849 mi_head
->mh_module_dev
= 1;
851 } else if (devp
== NULL
) {
853 dev
= (dev_t
)OPENFAIL
;
854 } else if ((dev
= inet_minor_alloc(mi_head
->mh_arena
)) == 0) {
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
;
865 if (sflag
== MODOPEN
)
866 mi_o
->mi_o_isdev
= B_FALSE
;
868 mi_o
->mi_o_isdev
= B_TRUE
;
871 *devp
= makedevice(getemajor(*devp
), (minor_t
)dev
);
876 mi_offset_param(mblk_t
*mp
, size_t offset
, size_t len
)
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)
886 return (&mp
->b_rptr
[offset
]);
890 mi_offset_paramc(mblk_t
*mp
, size_t offset
, size_t len
)
894 for (; mp
; mp
= mp
->b_cont
) {
895 int type
= mp
->b_datap
->db_type
;
897 if (param
= mi_offset_param(mp
, offset
, len
))
899 if (offset
< mp
->b_wptr
- mp
->b_rptr
)
901 offset
-= mp
->b_wptr
- mp
->b_rptr
;
908 mi_sprintf(char *buf
, char *fmt
, ...)
914 count
= mi_iprintf(fmt
, ap
, (pfi_t
)mi_sprintf_putc
,
917 (void) mi_sprintf_putc((char *)&buf
, '\0');
923 /* Used to count without writing data */
926 mi_sprintf_noop(char *cookie
, int ch
)
928 char **cpp
= (char **)cookie
;
935 mi_sprintf_putc(char *cookie
, int ch
)
937 char **cpp
= (char **)cookie
;
945 mi_strcmp(const char *cp1
, const char *cp2
)
947 while (*cp1
++ == *cp2
++) {
951 return ((uint_t
)cp2
[-1] & 0xFF) - ((uint_t
)cp1
[-1] & 0xFF);
955 mi_strlen(const char *str
)
957 const char *cp
= str
;
961 return ((int)(cp
- str
));
965 mi_strlog(queue_t
*q
, char level
, ushort_t flags
, char *fmt
, ...)
969 char *alloc_buf
= buf
;
979 mid
= q
->q_qinfo
->qi_minfo
->mi_idnum
;
982 /* Find out how many bytes we need and allocate if necesary */
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
))) {
995 count
= mi_iprintf(fmt
, ap
, mi_sprintf_putc
, (char *)&cp
);
997 (void) mi_sprintf_putc((char *)&cp
, '\0');
1002 ret
= strlog(mid
, sid
, level
, flags
, alloc_buf
);
1003 if (alloc_buf
!= buf
)
1009 mi_strtol(const char *str
, char **ptr
, int base
)
1014 boolean_t is_negative
;
1017 while (*cp
== ' ' || *cp
== '\t' || *cp
== '\n')
1019 is_negative
= (*cp
== '-');
1027 if (*cp
== 'x' || *cp
== 'X') {
1034 for (; *cp
!= '\0'; cp
++) {
1035 if (*cp
>= '0' && *cp
<= '9')
1037 else if (*cp
>= 'a' && *cp
<= 'f')
1038 digits
= *cp
- 'a' + 10;
1039 else if (*cp
>= 'A' && *cp
<= 'F')
1040 digits
= *cp
- 'A' + 10;
1045 value
= (value
* base
) + digits
;
1047 /* Note: we cast away const here deliberately */
1056 * mi_timer mechanism.
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
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.
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.
1084 mi_timer(queue_t
*q
, MBLKP mp
, clock_t tim
)
1090 if (!q
|| !mp
|| (mp
->b_rptr
- mp
->b_datap
->db_base
) != sizeof (MTB
))
1092 mtb
= (MTBP
)mp
->b_datap
->db_base
;
1093 ASSERT(mp
->b_datap
->db_type
== M_PCSIG
);
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 */
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 */
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 */
1126 mtb
->mtb_state
= TB_RUNNING
;
1127 mtb
->mtb_tid
= timeout((pfv_t
)mi_timer_fire
, mtb
, tim
);
1135 mi_timer_move(q
, mp
);
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.
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.
1150 mi_timer_alloc(size_t size
)
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
;
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
1176 mi_timer_fire(MTBP mtb
)
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
));
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.
1190 mi_timer_free(MBLKP mp
)
1195 if (!mp
|| (mp
->b_rptr
- mp
->b_datap
->db_base
) != sizeof (MTB
))
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 */
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 */
1217 ASSERT(mtb
->mtb_q
== NULL
|| mtb
->mtb_q
->q_first
!= mp
);
1222 * Called from mi_timer(,,-2)
1225 mi_timer_move(queue_t
*q
, MBLKP mp
)
1230 if (!q
|| !mp
|| (mp
->b_rptr
- mp
->b_datap
->db_base
) != sizeof (MTB
))
1233 mtb
= (MTBP
)mp
->b_datap
->db_base
;
1235 * Need to untimeout and restart to make
1236 * sure that the mblk is not about to be putq on the old queue
1239 if (mtb
->mtb_state
== TB_RUNNING
) {
1240 if ((tim
= untimeout(mtb
->mtb_tid
)) < 0) {
1242 * Message has already been putq. Move from old queue
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
);
1251 (void) putq(mtb
->mtb_q
, mp
);
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
);
1260 * Message is already sitting on queue. Move to new queue.
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
);
1268 (void) putq(mtb
->mtb_q
, mp
);
1274 * Called from mi_timer(,,-1)
1277 mi_timer_stop(MBLKP mp
)
1282 if (!mp
|| (mp
->b_rptr
- mp
->b_datap
->db_base
) != sizeof (MTB
))
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
;
1294 mtb
->mtb_state
= TB_IDLE
;
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
;
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.
1310 mi_timer_valid(MBLKP mp
)
1315 if (!mp
|| (mp
->b_rptr
- mp
->b_datap
->db_base
) != sizeof (MTB
) ||
1316 mp
->b_datap
->db_type
!= M_PCSIG
)
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
) {
1324 * mi_timer_free was called after the message
1330 if (state
== TB_CANCELLED
) {
1331 /* The timer was stopped after the mblk was putq'ed */
1332 mtb
->mtb_state
= TB_IDLE
;
1335 if (state
== TB_RESCHED
) {
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.
1342 mtb
->mtb_state
= TB_RUNNING
;
1343 mtb
->mtb_tid
= timeout((pfv_t
)mi_timer_fire
,
1344 mtb
, mtb
->mtb_time_left
);
1348 mtb
->mtb_state
= TB_IDLE
;
1353 mi_tpi_addr_and_opt(MBLKP mp
, char *addr
, t_scalar_t addr_length
,
1354 char *opt
, t_scalar_t opt_length
)
1356 struct T_unitdata_ind
*tudi
;
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
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
;
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
;
1383 mi_tpi_conn_con(MBLKP trailer_mp
, char *src
, t_scalar_t src_length
, char *opt
,
1384 t_scalar_t opt_length
)
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
);
1398 mi_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
)
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
;
1415 mi_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
,
1422 len
= sizeof (struct T_extconn_ind
) + src_length
+ opt_length
+
1424 if ((mp
= mi_tpi_trailer_alloc(trailer_mp
, len
, T_EXTCONN_IND
)) !=
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
;
1435 ((struct T_extconn_ind
*)mp
->b_rptr
)->SEQ_number
= seqnum
;
1436 mp
->b_datap
->db_type
= M_PROTO
;
1442 mi_tpi_discon_ind(MBLKP trailer_mp
, t_scalar_t reason
, t_scalar_t seqnum
)
1445 struct T_discon_ind
*tdi
;
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
;
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.
1461 mi_tpi_err_ack_alloc(MBLKP mp
, t_scalar_t tlierr
, int unixerr
)
1463 struct T_error_ack
*teackp
;
1464 t_scalar_t error_prim
;
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
;
1480 mi_tpi_ok_ack_alloc_extra(MBLKP mp
, int extra
)
1482 t_scalar_t correct_prim
;
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
;
1496 mi_tpi_ok_ack_alloc(MBLKP mp
)
1498 return (mi_tpi_ok_ack_alloc_extra(mp
, 0));
1502 mi_tpi_ordrel_ind(void)
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
);
1515 mi_tpi_trailer_alloc(MBLKP trailer_mp
, size_t size
, t_scalar_t type
)
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
;
1529 mi_tpi_uderror_ind(char *dest
, t_scalar_t dest_length
, char *opt
,
1530 t_scalar_t opt_length
, t_scalar_t error
)
1534 struct T_uderror_ind
*tudei
;
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
);
1549 mi_zalloc(size_t size
)
1553 if (ptr
= mi_alloc(size
, BPRI_LO
))
1559 mi_zalloc_sleep(size_t size
)
1563 if (ptr
= mi_alloc_sleep(size
, BPRI_LO
))