xref: /titanic_52/usr/src/uts/common/io/strsun.c (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Solaris DDI STREAMS utility routines (PSARC/2003/648).
31  *
32  * Please see the appropriate section 9F manpage for documentation.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 #include <sys/errno.h>
38 #include <sys/stream.h>
39 #include <sys/stropts.h>
40 #include <sys/strsun.h>
41 #include <sys/cmn_err.h>
42 
43 void
44 merror(queue_t *wq, mblk_t *mp, int error)
45 {
46 	if ((mp = mexchange(wq, mp, 1, M_ERROR, -1)) == NULL)
47 		return;
48 
49 	*mp->b_rptr = (uchar_t)error;
50 	qreply(wq, mp);
51 }
52 
53 void
54 mioc2ack(mblk_t *mp, mblk_t *dp, size_t count, int rval)
55 {
56 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
57 	mblk_t *odp = mp->b_cont;  	/* allows freemsg() to be a tail call */
58 
59 	DB_TYPE(mp) = M_IOCACK;
60 	iocp->ioc_count = count;
61 	iocp->ioc_error = 0;
62 	iocp->ioc_rval = rval;
63 
64 	mp->b_cont = dp;
65 	if (dp != NULL)
66 		dp->b_wptr = dp->b_rptr + count;
67 	freemsg(odp);
68 }
69 
70 void
71 miocack(queue_t *wq, mblk_t *mp, int count, int rval)
72 {
73 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
74 
75 	DB_TYPE(mp) = M_IOCACK;
76 	iocp->ioc_count = count;
77 	iocp->ioc_error = 0;
78 	iocp->ioc_rval = rval;
79 	qreply(wq, mp);
80 }
81 
82 void
83 miocnak(queue_t *wq, mblk_t *mp, int count, int error)
84 {
85 	struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
86 
87 	DB_TYPE(mp) = M_IOCNAK;
88 	iocp->ioc_count = count;
89 	iocp->ioc_error = error;
90 	qreply(wq, mp);
91 }
92 
93 mblk_t *
94 mexchange(queue_t *wq, mblk_t *mp, size_t size, uchar_t type, int32_t primtype)
95 {
96 	if (mp == NULL || MBLKSIZE(mp) < size || DB_REF(mp) > 1) {
97 		freemsg(mp);
98 		if ((mp = allocb(size, BPRI_LO)) == NULL) {
99 			if (wq != NULL) {
100 				if ((mp = allocb(1, BPRI_HI)) != NULL)
101 					merror(wq, mp, ENOSR);
102 			}
103 			return (NULL);
104 		}
105 	}
106 
107 	DB_TYPE(mp) = type;
108 	mp->b_rptr = DB_BASE(mp);
109 	mp->b_wptr = mp->b_rptr + size;
110 	if (primtype >= 0)
111 		*(int32_t *)mp->b_rptr = primtype;
112 
113 	return (mp);
114 }
115 
116 size_t
117 msgsize(mblk_t *mp)
118 {
119 	size_t	n = 0;
120 
121 	for (; mp != NULL; mp = mp->b_cont)
122 		n += MBLKL(mp);
123 
124 	return (n);
125 }
126 
127 void
128 mcopymsg(mblk_t *mp, void *bufp)
129 {
130 	caddr_t	dest = bufp;
131 	mblk_t	*bp;
132 	size_t	n;
133 
134 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
135 		n = MBLKL(bp);
136 		bcopy(bp->b_rptr, dest, n);
137 		dest += n;
138 	}
139 
140 	freemsg(mp);
141 }
142 
143 void
144 mcopyin(mblk_t *mp, void *private, size_t size, void *useraddr)
145 {
146 	struct copyreq *cp = (struct copyreq *)mp->b_rptr;
147 
148 	if (useraddr != NULL) {
149 		cp->cq_addr = (caddr_t)useraddr;
150 	} else {
151 		ASSERT(DB_TYPE(mp) == M_IOCTL);
152 		ASSERT(mp->b_cont != NULL);
153 		ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT);
154 		cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr;
155 	}
156 
157 	cp->cq_flag = 0;
158 	cp->cq_size = size;
159 	cp->cq_private = (mblk_t *)private;
160 
161 	DB_TYPE(mp) = M_COPYIN;
162 	mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
163 
164 	if (mp->b_cont != NULL) {
165 		freemsg(mp->b_cont);
166 		mp->b_cont = NULL;
167 	}
168 }
169 
170 void
171 mcopyout(mblk_t *mp, void *private, size_t size, void *useraddr, mblk_t *dp)
172 {
173 	struct copyreq *cp = (struct copyreq *)mp->b_rptr;
174 
175 	if (useraddr != NULL)
176 		cp->cq_addr = (caddr_t)useraddr;
177 	else {
178 		ASSERT(DB_TYPE(mp) == M_IOCTL);
179 		ASSERT(mp->b_cont != NULL);
180 		ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT);
181 		cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr;
182 	}
183 
184 	cp->cq_flag = 0;
185 	cp->cq_size = size;
186 	cp->cq_private = (mblk_t *)private;
187 
188 	DB_TYPE(mp) = M_COPYOUT;
189 	mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
190 
191 	if (dp != NULL) {
192 		if (mp->b_cont != NULL)
193 			freemsg(mp->b_cont);
194 		mp->b_cont = dp;
195 		mp->b_cont->b_wptr = mp->b_cont->b_rptr + size;
196 	}
197 }
198 
199 int
200 miocpullup(mblk_t *iocmp, size_t size)
201 {
202 	struct iocblk	*iocp = (struct iocblk *)iocmp->b_rptr;
203 	mblk_t		*datamp = iocmp->b_cont;
204 	mblk_t		*newdatamp;
205 
206 	/*
207 	 * We'd like to be sure that DB_TYPE(iocmp) == M_IOCTL, but some
208 	 * nitwit routines like ttycommon_ioctl() always reset the type of
209 	 * legitimate M_IOCTL messages to M_IOCACK as a "courtesy" to the
210 	 * caller, even when the routine does not understand the M_IOCTL.
211 	 * The ttycommon_ioctl() routine does us the additional favor of
212 	 * clearing ioc_count, so we cannot rely on it having a correct
213 	 * size either (blissfully, ttycommon_ioctl() does not screw with
214 	 * TRANSPARENT messages, so we can still sanity check for that).
215 	 */
216 	ASSERT(MBLKL(iocmp) == sizeof (struct iocblk));
217 	if (MBLKL(iocmp) != sizeof (struct iocblk)) {
218 		cmn_err(CE_WARN, "miocpullup: passed mblk_t %p is not an ioctl"
219 		    " mblk_t", (void *)iocmp);
220 		return (EINVAL);
221 	}
222 
223 	if (iocp->ioc_count == TRANSPARENT)
224 		return (EINVAL);
225 
226 	if (size == 0)
227 		return (0);
228 
229 	if (datamp == NULL)
230 		return (EINVAL);
231 
232 	if (MBLKL(datamp) >= size)
233 		return (0);
234 
235 	newdatamp = msgpullup(datamp, size);
236 	if (newdatamp == NULL) {
237 		if (msgdsize(datamp) < size)
238 			return (EINVAL);
239 		return (ENOMEM);
240 	}
241 
242 	iocmp->b_cont = newdatamp;
243 	freemsg(datamp);
244 	return (0);
245 }
246