xref: /freebsd/sys/opencrypto/criov.c (revision c03414326909ed7a740be3ba63fbbef01fe513a8)
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(struct cryptop *crp, int off, int size, const void *src)
161 {
162 
163 	switch (crp->crp_buf_type) {
164 	case CRYPTO_BUF_MBUF:
165 		m_copyback(crp->crp_mbuf, off, size, src);
166 		break;
167 	case CRYPTO_BUF_UIO:
168 		cuio_copyback(crp->crp_uio, off, size, src);
169 		break;
170 	case CRYPTO_BUF_CONTIG:
171 		bcopy(src, crp->crp_buf + off, size);
172 		break;
173 	default:
174 		panic("invalid crp buf type %d", crp->crp_buf_type);
175 	}
176 }
177 
178 void
179 crypto_copydata(struct cryptop *crp, int off, int size, void *dst)
180 {
181 
182 	switch (crp->crp_buf_type) {
183 	case CRYPTO_BUF_MBUF:
184 		m_copydata(crp->crp_mbuf, off, size, dst);
185 		break;
186 	case CRYPTO_BUF_UIO:
187 		cuio_copydata(crp->crp_uio, off, size, dst);
188 		break;
189 	case CRYPTO_BUF_CONTIG:
190 		bcopy(crp->crp_buf + off, dst, size);
191 		break;
192 	default:
193 		panic("invalid crp buf type %d", crp->crp_buf_type);
194 	}
195 }
196 
197 int
198 crypto_apply(struct cryptop *crp, int off, int len,
199     int (*f)(void *, void *, u_int), void *arg)
200 {
201 	int error;
202 
203 	switch (crp->crp_buf_type) {
204 	case CRYPTO_BUF_MBUF:
205 		error = m_apply(crp->crp_mbuf, off, len, f, arg);
206 		break;
207 	case CRYPTO_BUF_UIO:
208 		error = cuio_apply(crp->crp_uio, off, len, f, arg);
209 		break;
210 	case CRYPTO_BUF_CONTIG:
211 		error = (*f)(arg, crp->crp_buf + off, len);
212 		break;
213 	default:
214 		panic("invalid crp buf type %d", crp->crp_buf_type);
215 	}
216 	return (error);
217 }
218 
219 int
220 crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt,
221     int *allocated)
222 {
223 	struct iovec *iov;
224 	struct mbuf *m, *mtmp;
225 	int i, j;
226 
227 	*allocated = 0;
228 	iov = *iovptr;
229 	if (iov == NULL)
230 		*cnt = 0;
231 
232 	m = mbuf;
233 	i = 0;
234 	while (m != NULL) {
235 		if (i == *cnt) {
236 			/* we need to allocate a larger array */
237 			j = 1;
238 			mtmp = m;
239 			while ((mtmp = mtmp->m_next) != NULL)
240 				j++;
241 			iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA,
242 			    M_NOWAIT);
243 			if (iov == NULL)
244 				return ENOMEM;
245 			*allocated = 1;
246 			*cnt = i + j;
247 			memcpy(iov, *iovptr, sizeof *iov * i);
248 		}
249 
250 		iov[i].iov_base = m->m_data;
251 		iov[i].iov_len = m->m_len;
252 
253 		i++;
254 		m = m->m_next;
255 	}
256 
257 	if (*allocated)
258 		KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d",
259 		    *cnt, i));
260 
261 	*iovptr = iov;
262 	*cnt = i;
263 	return 0;
264 }
265 
266 static inline void *
267 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
268 {
269 	int rel_off;
270 
271 	MPASS(skip <= INT_MAX);
272 
273 	m = m_getptr(m, (int)skip, &rel_off);
274 	if (m == NULL)
275 		return (NULL);
276 
277 	MPASS(rel_off >= 0);
278 	skip = rel_off;
279 	if (skip + len > m->m_len)
280 		return (NULL);
281 
282 	return (mtod(m, char*) + skip);
283 }
284 
285 static inline void *
286 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
287 {
288 	int rel_off, idx;
289 
290 	MPASS(skip <= INT_MAX);
291 	idx = cuio_getptr(uio, (int)skip, &rel_off);
292 	if (idx < 0)
293 		return (NULL);
294 
295 	MPASS(rel_off >= 0);
296 	skip = rel_off;
297 	if (skip + len > uio->uio_iov[idx].iov_len)
298 		return (NULL);
299 	return ((char *)uio->uio_iov[idx].iov_base + skip);
300 }
301 
302 void *
303 crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len)
304 {
305 
306 	switch (crp->crp_buf_type) {
307 	case CRYPTO_BUF_MBUF:
308 		return (m_contiguous_subsegment(crp->crp_mbuf, skip, len));
309 	case CRYPTO_BUF_UIO:
310 		return (cuio_contiguous_segment(crp->crp_uio, skip, len));
311 	case CRYPTO_BUF_CONTIG:
312 		return (crp->crp_buf + skip);
313 	default:
314 		panic("invalid crp buf type %d", crp->crp_buf_type);
315 	}
316 }
317