xref: /freebsd/sys/opencrypto/criov.c (revision 0957b409)
1 /*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 Theo de Raadt
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *   derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/errno.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/mbuf.h>
40 #include <sys/uio.h>
41 #include <sys/limits.h>
42 #include <sys/lock.h>
43 
44 #include <opencrypto/cryptodev.h>
45 
46 /*
47  * This macro is only for avoiding code duplication, as we need to skip
48  * given number of bytes in the same way in three functions below.
49  */
50 #define	CUIO_SKIP()	do {						\
51 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
52 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
53 	while (off > 0) {						\
54 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
55 		if (off < iov->iov_len)					\
56 			break;						\
57 		off -= iov->iov_len;					\
58 		iol--;							\
59 		iov++;							\
60 	}								\
61 } while (0)
62 
63 void
64 cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
65 {
66 	struct iovec *iov = uio->uio_iov;
67 	int iol = uio->uio_iovcnt;
68 	unsigned count;
69 
70 	CUIO_SKIP();
71 	while (len > 0) {
72 		KASSERT(iol >= 0, ("%s: empty", __func__));
73 		count = min(iov->iov_len - off, len);
74 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
75 		len -= count;
76 		cp += count;
77 		off = 0;
78 		iol--;
79 		iov++;
80 	}
81 }
82 
83 void
84 cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp)
85 {
86 	struct iovec *iov = uio->uio_iov;
87 	int iol = uio->uio_iovcnt;
88 	unsigned count;
89 
90 	CUIO_SKIP();
91 	while (len > 0) {
92 		KASSERT(iol >= 0, ("%s: empty", __func__));
93 		count = min(iov->iov_len - off, len);
94 		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
95 		len -= count;
96 		cp += count;
97 		off = 0;
98 		iol--;
99 		iov++;
100 	}
101 }
102 
103 /*
104  * Return the index and offset of location in iovec list.
105  */
106 int
107 cuio_getptr(struct uio *uio, int loc, int *off)
108 {
109 	int ind, len;
110 
111 	ind = 0;
112 	while (loc >= 0 && ind < uio->uio_iovcnt) {
113 		len = uio->uio_iov[ind].iov_len;
114 		if (len > loc) {
115 	    		*off = loc;
116 	    		return (ind);
117 		}
118 		loc -= len;
119 		ind++;
120 	}
121 
122 	if (ind > 0 && loc == 0) {
123 		ind--;
124 		*off = uio->uio_iov[ind].iov_len;
125 		return (ind);
126 	}
127 
128 	return (-1);
129 }
130 
131 /*
132  * Apply function f to the data in an iovec list starting "off" bytes from
133  * the beginning, continuing for "len" bytes.
134  */
135 int
136 cuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int),
137     void *arg)
138 {
139 	struct iovec *iov = uio->uio_iov;
140 	int iol = uio->uio_iovcnt;
141 	unsigned count;
142 	int rval;
143 
144 	CUIO_SKIP();
145 	while (len > 0) {
146 		KASSERT(iol >= 0, ("%s: empty", __func__));
147 		count = min(iov->iov_len - off, len);
148 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
149 		if (rval)
150 			return (rval);
151 		len -= count;
152 		off = 0;
153 		iol--;
154 		iov++;
155 	}
156 	return (0);
157 }
158 
159 void
160 crypto_copyback(int flags, caddr_t buf, int off, int size, c_caddr_t in)
161 {
162 
163 	if ((flags & CRYPTO_F_IMBUF) != 0)
164 		m_copyback((struct mbuf *)buf, off, size, in);
165 	else if ((flags & CRYPTO_F_IOV) != 0)
166 		cuio_copyback((struct uio *)buf, off, size, in);
167 	else
168 		bcopy(in, buf + off, size);
169 }
170 
171 void
172 crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
173 {
174 
175 	if ((flags & CRYPTO_F_IMBUF) != 0)
176 		m_copydata((struct mbuf *)buf, off, size, out);
177 	else if ((flags & CRYPTO_F_IOV) != 0)
178 		cuio_copydata((struct uio *)buf, off, size, out);
179 	else
180 		bcopy(buf + off, out, size);
181 }
182 
183 int
184 crypto_apply(int flags, caddr_t buf, int off, int len,
185     int (*f)(void *, void *, u_int), void *arg)
186 {
187 	int error;
188 
189 	if ((flags & CRYPTO_F_IMBUF) != 0)
190 		error = m_apply((struct mbuf *)buf, off, len, f, arg);
191 	else if ((flags & CRYPTO_F_IOV) != 0)
192 		error = cuio_apply((struct uio *)buf, off, len, f, arg);
193 	else
194 		error = (*f)(arg, buf + off, len);
195 	return (error);
196 }
197 
198 int
199 crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt,
200     int *allocated)
201 {
202 	struct iovec *iov;
203 	struct mbuf *m, *mtmp;
204 	int i, j;
205 
206 	*allocated = 0;
207 	iov = *iovptr;
208 	if (iov == NULL)
209 		*cnt = 0;
210 
211 	m = mbuf;
212 	i = 0;
213 	while (m != NULL) {
214 		if (i == *cnt) {
215 			/* we need to allocate a larger array */
216 			j = 1;
217 			mtmp = m;
218 			while ((mtmp = mtmp->m_next) != NULL)
219 				j++;
220 			iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA,
221 			    M_NOWAIT);
222 			if (iov == NULL)
223 				return ENOMEM;
224 			*allocated = 1;
225 			*cnt = i + j;
226 			memcpy(iov, *iovptr, sizeof *iov * i);
227 		}
228 
229 		iov[i].iov_base = m->m_data;
230 		iov[i].iov_len = m->m_len;
231 
232 		i++;
233 		m = m->m_next;
234 	}
235 
236 	if (*allocated)
237 		KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d",
238 		    *cnt, i));
239 
240 	*iovptr = iov;
241 	*cnt = i;
242 	return 0;
243 }
244 
245 static inline void *
246 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
247 {
248 	int rel_off;
249 
250 	MPASS(skip <= INT_MAX);
251 
252 	m = m_getptr(m, (int)skip, &rel_off);
253 	if (m == NULL)
254 		return (NULL);
255 
256 	MPASS(rel_off >= 0);
257 	skip = rel_off;
258 	if (skip + len > m->m_len)
259 		return (NULL);
260 
261 	return (mtod(m, char*) + skip);
262 }
263 
264 static inline void *
265 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
266 {
267 	int rel_off, idx;
268 
269 	MPASS(skip <= INT_MAX);
270 	idx = cuio_getptr(uio, (int)skip, &rel_off);
271 	if (idx < 0)
272 		return (NULL);
273 
274 	MPASS(rel_off >= 0);
275 	skip = rel_off;
276 	if (skip + len > uio->uio_iov[idx].iov_len)
277 		return (NULL);
278 	return ((char *)uio->uio_iov[idx].iov_base + skip);
279 }
280 
281 void *
282 crypto_contiguous_subsegment(int crp_flags, void *crpbuf,
283     size_t skip, size_t len)
284 {
285 	if ((crp_flags & CRYPTO_F_IMBUF) != 0)
286 		return (m_contiguous_subsegment(crpbuf, skip, len));
287 	else if ((crp_flags & CRYPTO_F_IOV) != 0)
288 		return (cuio_contiguous_segment(crpbuf, skip, len));
289 	else {
290 		MPASS((crp_flags & (CRYPTO_F_IMBUF | CRYPTO_F_IOV)) !=
291 		    (CRYPTO_F_IMBUF | CRYPTO_F_IOV));
292 		return ((char*)crpbuf + skip);
293 	}
294 }
295 
296