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.
27 * Solaris DDI STREAMS utility routines (PSARC/2003/648).
29 * Please see the appropriate section 9F manpage for documentation.
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/strsubr.h>
38 #include <sys/strsun.h>
39 #include <sys/sysmacros.h>
40 #include <sys/cmn_err.h>
43 merror(queue_t
*wq
, mblk_t
*mp
, int error
)
45 if ((mp
= mexchange(wq
, mp
, 1, M_ERROR
, -1)) == NULL
)
48 *mp
->b_rptr
= (uchar_t
)error
;
53 mioc2ack(mblk_t
*mp
, mblk_t
*dp
, size_t count
, int rval
)
55 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
56 mblk_t
*odp
= mp
->b_cont
; /* allows freemsg() to be a tail call */
58 DB_TYPE(mp
) = M_IOCACK
;
59 iocp
->ioc_count
= count
;
61 iocp
->ioc_rval
= rval
;
65 dp
->b_wptr
= dp
->b_rptr
+ count
;
70 miocack(queue_t
*wq
, mblk_t
*mp
, int count
, int rval
)
72 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
74 DB_TYPE(mp
) = M_IOCACK
;
75 iocp
->ioc_count
= count
;
77 iocp
->ioc_rval
= rval
;
82 miocnak(queue_t
*wq
, mblk_t
*mp
, int count
, int error
)
84 struct iocblk
*iocp
= (struct iocblk
*)mp
->b_rptr
;
86 DB_TYPE(mp
) = M_IOCNAK
;
87 iocp
->ioc_count
= count
;
88 iocp
->ioc_error
= error
;
93 mexchange(queue_t
*wq
, mblk_t
*mp
, size_t size
, uchar_t type
, int32_t primtype
)
95 if (mp
== NULL
|| MBLKSIZE(mp
) < size
|| DB_REF(mp
) > 1) {
97 if ((mp
= allocb(size
, BPRI_LO
)) == NULL
) {
99 if ((mp
= allocb(1, BPRI_HI
)) != NULL
)
100 merror(wq
, mp
, ENOSR
);
107 mp
->b_rptr
= DB_BASE(mp
);
108 mp
->b_wptr
= mp
->b_rptr
+ size
;
110 *(int32_t *)mp
->b_rptr
= primtype
;
120 for (; mp
!= NULL
; mp
= mp
->b_cont
)
127 mcopymsg(mblk_t
*mp
, void *bufp
)
133 for (bp
= mp
; bp
!= NULL
; bp
= bp
->b_cont
) {
135 bcopy(bp
->b_rptr
, dest
, n
);
143 mcopyin(mblk_t
*mp
, void *private, size_t size
, void *useraddr
)
145 struct copyreq
*cp
= (struct copyreq
*)mp
->b_rptr
;
147 if (useraddr
!= NULL
) {
148 cp
->cq_addr
= (caddr_t
)useraddr
;
150 ASSERT(DB_TYPE(mp
) == M_IOCTL
);
151 ASSERT(mp
->b_cont
!= NULL
);
152 ASSERT(((struct iocblk
*)mp
->b_rptr
)->ioc_count
== TRANSPARENT
);
153 cp
->cq_addr
= (caddr_t
)*(uintptr_t *)mp
->b_cont
->b_rptr
;
158 cp
->cq_private
= (mblk_t
*)private;
160 DB_TYPE(mp
) = M_COPYIN
;
161 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct copyreq
);
163 if (mp
->b_cont
!= NULL
) {
170 mcopyout(mblk_t
*mp
, void *private, size_t size
, void *useraddr
, mblk_t
*dp
)
172 struct copyreq
*cp
= (struct copyreq
*)mp
->b_rptr
;
174 if (useraddr
!= NULL
)
175 cp
->cq_addr
= (caddr_t
)useraddr
;
177 ASSERT(DB_TYPE(mp
) == M_IOCTL
);
178 ASSERT(mp
->b_cont
!= NULL
);
179 ASSERT(((struct iocblk
*)mp
->b_rptr
)->ioc_count
== TRANSPARENT
);
180 cp
->cq_addr
= (caddr_t
)*(uintptr_t *)mp
->b_cont
->b_rptr
;
185 cp
->cq_private
= (mblk_t
*)private;
187 DB_TYPE(mp
) = M_COPYOUT
;
188 mp
->b_wptr
= mp
->b_rptr
+ sizeof (struct copyreq
);
191 if (mp
->b_cont
!= NULL
)
194 mp
->b_cont
->b_wptr
= mp
->b_cont
->b_rptr
+ size
;
199 miocpullup(mblk_t
*iocmp
, size_t size
)
201 struct iocblk
*iocp
= (struct iocblk
*)iocmp
->b_rptr
;
202 mblk_t
*datamp
= iocmp
->b_cont
;
206 * We'd like to be sure that DB_TYPE(iocmp) == M_IOCTL, but some
207 * nitwit routines like ttycommon_ioctl() always reset the type of
208 * legitimate M_IOCTL messages to M_IOCACK as a "courtesy" to the
209 * caller, even when the routine does not understand the M_IOCTL.
210 * The ttycommon_ioctl() routine does us the additional favor of
211 * clearing ioc_count, so we cannot rely on it having a correct
212 * size either (blissfully, ttycommon_ioctl() does not screw with
213 * TRANSPARENT messages, so we can still sanity check for that).
215 ASSERT(MBLKL(iocmp
) == sizeof (struct iocblk
));
216 if (MBLKL(iocmp
) != sizeof (struct iocblk
)) {
217 cmn_err(CE_WARN
, "miocpullup: passed mblk_t %p is not an ioctl"
218 " mblk_t", (void *)iocmp
);
222 if (iocp
->ioc_count
== TRANSPARENT
)
231 if (MBLKL(datamp
) >= size
)
234 newdatamp
= msgpullup(datamp
, size
);
235 if (newdatamp
== NULL
) {
236 if (msgdsize(datamp
) < size
)
241 iocmp
->b_cont
= newdatamp
;
246 /* Copy userdata into a new mblk_t */
248 mcopyinuio(struct stdata
*stp
, uio_t
*uiop
, ssize_t iosize
,
249 ssize_t maxblk
, int *errorp
)
251 mblk_t
*head
= NULL
, **tail
= &head
;
252 size_t offset
= stp
->sd_wroff
;
253 size_t tail_len
= stp
->sd_tail
;
255 if (iosize
== INFPSZ
|| iosize
> uiop
->uio_resid
)
256 iosize
= uiop
->uio_resid
;
258 if (maxblk
== INFPSZ
)
261 /* Nothing to do in these cases, so we're done */
262 if (iosize
< 0 || maxblk
< 0 || (maxblk
== 0 && iosize
> 0))
265 if (stp
->sd_flag
& STRCOPYCACHED
)
266 uiop
->uio_extflg
|= UIO_COPY_CACHED
;
269 * We will enter the loop below if iosize is 0; it will allocate an
270 * empty message block and call uiomove(9F) which will just return.
271 * We could avoid that with an extra check but would only slow
272 * down the much more likely case where iosize is larger than 0.
278 blocksize
= MIN(iosize
, maxblk
);
279 ASSERT(blocksize
>= 0);
280 if ((mp
= allocb_cred(offset
+ blocksize
+ tail_len
,
281 CRED(), curproc
->p_pid
)) == NULL
) {
285 mp
->b_rptr
+= offset
;
286 mp
->b_wptr
= mp
->b_rptr
+ blocksize
;
291 /* uiomove(9F) either returns 0 or EFAULT */
292 if ((*errorp
= uiomove(mp
->b_rptr
, (size_t)blocksize
,
293 UIO_WRITE
, uiop
)) != 0) {
294 ASSERT(*errorp
!= ENOMEM
);
300 } while (iosize
> 0);