5907 xdrmblk_getpos() is unreliable
[illumos-gate.git] / usr / src / uts / common / io / strsun.c
blobdb6e4aa8dd4b6f16b426212fee457dfb0965ab28
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
42 void
43 merror(queue_t *wq, mblk_t *mp, int error)
45 if ((mp = mexchange(wq, mp, 1, M_ERROR, -1)) == NULL)
46 return;
48 *mp->b_rptr = (uchar_t)error;
49 qreply(wq, mp);
52 void
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;
60 iocp->ioc_error = 0;
61 iocp->ioc_rval = rval;
63 mp->b_cont = dp;
64 if (dp != NULL)
65 dp->b_wptr = dp->b_rptr + count;
66 freemsg(odp);
69 void
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;
76 iocp->ioc_error = 0;
77 iocp->ioc_rval = rval;
78 qreply(wq, mp);
81 void
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;
89 qreply(wq, mp);
92 mblk_t *
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) {
96 freemsg(mp);
97 if ((mp = allocb(size, BPRI_LO)) == NULL) {
98 if (wq != NULL) {
99 if ((mp = allocb(1, BPRI_HI)) != NULL)
100 merror(wq, mp, ENOSR);
102 return (NULL);
106 DB_TYPE(mp) = type;
107 mp->b_rptr = DB_BASE(mp);
108 mp->b_wptr = mp->b_rptr + size;
109 if (primtype >= 0)
110 *(int32_t *)mp->b_rptr = primtype;
112 return (mp);
115 size_t
116 msgsize(mblk_t *mp)
118 size_t n = 0;
120 for (; mp != NULL; mp = mp->b_cont)
121 n += MBLKL(mp);
123 return (n);
126 void
127 mcopymsg(mblk_t *mp, void *bufp)
129 caddr_t dest = bufp;
130 mblk_t *bp;
131 size_t n;
133 for (bp = mp; bp != NULL; bp = bp->b_cont) {
134 n = MBLKL(bp);
135 bcopy(bp->b_rptr, dest, n);
136 dest += n;
139 freemsg(mp);
142 void
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;
149 } else {
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;
156 cp->cq_flag = 0;
157 cp->cq_size = size;
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) {
164 freemsg(mp->b_cont);
165 mp->b_cont = NULL;
169 void
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;
176 else {
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;
183 cp->cq_flag = 0;
184 cp->cq_size = size;
185 cp->cq_private = (mblk_t *)private;
187 DB_TYPE(mp) = M_COPYOUT;
188 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
190 if (dp != NULL) {
191 if (mp->b_cont != NULL)
192 freemsg(mp->b_cont);
193 mp->b_cont = dp;
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;
203 mblk_t *newdatamp;
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);
219 return (EINVAL);
222 if (iocp->ioc_count == TRANSPARENT)
223 return (EINVAL);
225 if (size == 0)
226 return (0);
228 if (datamp == NULL)
229 return (EINVAL);
231 if (MBLKL(datamp) >= size)
232 return (0);
234 newdatamp = msgpullup(datamp, size);
235 if (newdatamp == NULL) {
236 if (msgdsize(datamp) < size)
237 return (EINVAL);
238 return (ENOMEM);
241 iocmp->b_cont = newdatamp;
242 freemsg(datamp);
243 return (0);
246 /* Copy userdata into a new mblk_t */
247 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)
259 maxblk = iosize;
261 /* Nothing to do in these cases, so we're done */
262 if (iosize < 0 || maxblk < 0 || (maxblk == 0 && iosize > 0))
263 goto done;
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.
274 do {
275 ssize_t blocksize;
276 mblk_t *mp;
278 blocksize = MIN(iosize, maxblk);
279 ASSERT(blocksize >= 0);
280 if ((mp = allocb_cred(offset + blocksize + tail_len,
281 CRED(), curproc->p_pid)) == NULL) {
282 *errorp = ENOMEM;
283 return (head);
285 mp->b_rptr += offset;
286 mp->b_wptr = mp->b_rptr + blocksize;
288 *tail = mp;
289 tail = &mp->b_cont;
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);
295 freemsg(head);
296 return (NULL);
299 iosize -= blocksize;
300 } while (iosize > 0);
302 done:
303 *errorp = 0;
304 return (head);