xref: /freebsd/sys/opencrypto/criov.c (revision e17f5b1d)
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 static 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 static 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 static 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 void
132 crypto_cursor_init(struct crypto_buffer_cursor *cc,
133     const struct crypto_buffer *cb)
134 {
135 	memset(cc, 0, sizeof(*cc));
136 	cc->cc_type = cb->cb_type;
137 	switch (cc->cc_type) {
138 	case CRYPTO_BUF_CONTIG:
139 		cc->cc_buf = cb->cb_buf;
140 		cc->cc_buf_len = cb->cb_buf_len;
141 		break;
142 	case CRYPTO_BUF_MBUF:
143 		cc->cc_mbuf = cb->cb_mbuf;
144 		break;
145 	case CRYPTO_BUF_UIO:
146 		cc->cc_iov = cb->cb_uio->uio_iov;
147 		break;
148 	default:
149 #ifdef INVARIANTS
150 		panic("%s: invalid buffer type %d", __func__, cb->cb_type);
151 #endif
152 		break;
153 	}
154 }
155 
156 void
157 crypto_cursor_advance(struct crypto_buffer_cursor *cc, size_t amount)
158 {
159 	size_t remain;
160 
161 	switch (cc->cc_type) {
162 	case CRYPTO_BUF_CONTIG:
163 		MPASS(cc->cc_buf_len >= amount);
164 		cc->cc_buf += amount;
165 		cc->cc_buf_len -= amount;
166 		break;
167 	case CRYPTO_BUF_MBUF:
168 		for (;;) {
169 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
170 			if (amount < remain) {
171 				cc->cc_offset += amount;
172 				break;
173 			}
174 			amount -= remain;
175 			cc->cc_mbuf = cc->cc_mbuf->m_next;
176 			cc->cc_offset = 0;
177 			if (amount == 0)
178 				break;
179 		}
180 		break;
181 	case CRYPTO_BUF_UIO:
182 		for (;;) {
183 			remain = cc->cc_iov->iov_len - cc->cc_offset;
184 			if (amount < remain) {
185 				cc->cc_offset += amount;
186 				break;
187 			}
188 			amount -= remain;
189 			cc->cc_iov++;
190 			cc->cc_offset = 0;
191 			if (amount == 0)
192 				break;
193 		}
194 		break;
195 	default:
196 #ifdef INVARIANTS
197 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
198 #endif
199 		break;
200 	}
201 }
202 
203 void *
204 crypto_cursor_segbase(struct crypto_buffer_cursor *cc)
205 {
206 	switch (cc->cc_type) {
207 	case CRYPTO_BUF_CONTIG:
208 		return (cc->cc_buf);
209 	case CRYPTO_BUF_MBUF:
210 		if (cc->cc_mbuf == NULL)
211 			return (NULL);
212 		KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
213 		    ("%s: not supported for unmapped mbufs", __func__));
214 		return (mtod(cc->cc_mbuf, char *) + cc->cc_offset);
215 	case CRYPTO_BUF_UIO:
216 		return ((char *)cc->cc_iov->iov_base + cc->cc_offset);
217 	default:
218 #ifdef INVARIANTS
219 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
220 #endif
221 		return (NULL);
222 	}
223 }
224 
225 size_t
226 crypto_cursor_seglen(struct crypto_buffer_cursor *cc)
227 {
228 	switch (cc->cc_type) {
229 	case CRYPTO_BUF_CONTIG:
230 		return (cc->cc_buf_len);
231 	case CRYPTO_BUF_MBUF:
232 		if (cc->cc_mbuf == NULL)
233 			return (0);
234 		return (cc->cc_mbuf->m_len - cc->cc_offset);
235 	case CRYPTO_BUF_UIO:
236 		return (cc->cc_iov->iov_len - cc->cc_offset);
237 	default:
238 #ifdef INVARIANTS
239 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
240 #endif
241 		return (0);
242 	}
243 }
244 
245 void
246 crypto_cursor_copyback(struct crypto_buffer_cursor *cc, int size,
247     const void *vsrc)
248 {
249 	size_t remain, todo;
250 	const char *src;
251 	char *dst;
252 
253 	src = vsrc;
254 	switch (cc->cc_type) {
255 	case CRYPTO_BUF_CONTIG:
256 		MPASS(cc->cc_buf_len >= size);
257 		memcpy(cc->cc_buf, src, size);
258 		cc->cc_buf += size;
259 		cc->cc_buf_len -= size;
260 		break;
261 	case CRYPTO_BUF_MBUF:
262 		for (;;) {
263 			KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
264 			    ("%s: not supported for unmapped mbufs", __func__));
265 			dst = mtod(cc->cc_mbuf, char *) + cc->cc_offset;
266 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
267 			todo = MIN(remain, size);
268 			memcpy(dst, src, todo);
269 			src += todo;
270 			if (todo < remain) {
271 				cc->cc_offset += todo;
272 				break;
273 			}
274 			size -= todo;
275 			cc->cc_mbuf = cc->cc_mbuf->m_next;
276 			cc->cc_offset = 0;
277 			if (size == 0)
278 				break;
279 		}
280 		break;
281 	case CRYPTO_BUF_UIO:
282 		for (;;) {
283 			dst = (char *)cc->cc_iov->iov_base + cc->cc_offset;
284 			remain = cc->cc_iov->iov_len - cc->cc_offset;
285 			todo = MIN(remain, size);
286 			memcpy(dst, src, todo);
287 			src += todo;
288 			if (todo < remain) {
289 				cc->cc_offset += todo;
290 				break;
291 			}
292 			size -= todo;
293 			cc->cc_iov++;
294 			cc->cc_offset = 0;
295 			if (size == 0)
296 				break;
297 		}
298 		break;
299 	default:
300 #ifdef INVARIANTS
301 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
302 #endif
303 		break;
304 	}
305 }
306 
307 void
308 crypto_cursor_copydata(struct crypto_buffer_cursor *cc, int size, void *vdst)
309 {
310 	size_t remain, todo;
311 	const char *src;
312 	char *dst;
313 
314 	dst = vdst;
315 	switch (cc->cc_type) {
316 	case CRYPTO_BUF_CONTIG:
317 		MPASS(cc->cc_buf_len >= size);
318 		memcpy(dst, cc->cc_buf, size);
319 		cc->cc_buf += size;
320 		cc->cc_buf_len -= size;
321 		break;
322 	case CRYPTO_BUF_MBUF:
323 		for (;;) {
324 			KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
325 			    ("%s: not supported for unmapped mbufs", __func__));
326 			src = mtod(cc->cc_mbuf, const char *) + cc->cc_offset;
327 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
328 			todo = MIN(remain, size);
329 			memcpy(dst, src, todo);
330 			dst += todo;
331 			if (todo < remain) {
332 				cc->cc_offset += todo;
333 				break;
334 			}
335 			size -= todo;
336 			cc->cc_mbuf = cc->cc_mbuf->m_next;
337 			cc->cc_offset = 0;
338 			if (size == 0)
339 				break;
340 		}
341 		break;
342 	case CRYPTO_BUF_UIO:
343 		for (;;) {
344 			src = (const char *)cc->cc_iov->iov_base +
345 			    cc->cc_offset;
346 			remain = cc->cc_iov->iov_len - cc->cc_offset;
347 			todo = MIN(remain, size);
348 			memcpy(dst, src, todo);
349 			dst += todo;
350 			if (todo < remain) {
351 				cc->cc_offset += todo;
352 				break;
353 			}
354 			size -= todo;
355 			cc->cc_iov++;
356 			cc->cc_offset = 0;
357 			if (size == 0)
358 				break;
359 		}
360 		break;
361 	default:
362 #ifdef INVARIANTS
363 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
364 #endif
365 		break;
366 	}
367 }
368 
369 /*
370  * To avoid advancing 'cursor', make a local copy that gets advanced
371  * instead.
372  */
373 void
374 crypto_cursor_copydata_noadv(struct crypto_buffer_cursor *cc, int size,
375     void *vdst)
376 {
377 	struct crypto_buffer_cursor copy;
378 
379 	copy = *cc;
380 	crypto_cursor_copydata(&copy, size, vdst);
381 }
382 
383 /*
384  * Apply function f to the data in an iovec list starting "off" bytes from
385  * the beginning, continuing for "len" bytes.
386  */
387 static int
388 cuio_apply(struct uio *uio, int off, int len,
389     int (*f)(void *, const void *, u_int), void *arg)
390 {
391 	struct iovec *iov = uio->uio_iov;
392 	int iol = uio->uio_iovcnt;
393 	unsigned count;
394 	int rval;
395 
396 	CUIO_SKIP();
397 	while (len > 0) {
398 		KASSERT(iol >= 0, ("%s: empty", __func__));
399 		count = min(iov->iov_len - off, len);
400 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
401 		if (rval)
402 			return (rval);
403 		len -= count;
404 		off = 0;
405 		iol--;
406 		iov++;
407 	}
408 	return (0);
409 }
410 
411 void
412 crypto_copyback(struct cryptop *crp, int off, int size, const void *src)
413 {
414 	struct crypto_buffer *cb;
415 
416 	if (crp->crp_obuf.cb_type != CRYPTO_BUF_NONE)
417 		cb = &crp->crp_obuf;
418 	else
419 		cb = &crp->crp_buf;
420 	switch (cb->cb_type) {
421 	case CRYPTO_BUF_MBUF:
422 		m_copyback(cb->cb_mbuf, off, size, src);
423 		break;
424 	case CRYPTO_BUF_UIO:
425 		cuio_copyback(cb->cb_uio, off, size, src);
426 		break;
427 	case CRYPTO_BUF_CONTIG:
428 		MPASS(off + size <= cb->cb_buf_len);
429 		bcopy(src, cb->cb_buf + off, size);
430 		break;
431 	default:
432 #ifdef INVARIANTS
433 		panic("invalid crp buf type %d", cb->cb_type);
434 #endif
435 		break;
436 	}
437 }
438 
439 void
440 crypto_copydata(struct cryptop *crp, int off, int size, void *dst)
441 {
442 
443 	switch (crp->crp_buf.cb_type) {
444 	case CRYPTO_BUF_MBUF:
445 		m_copydata(crp->crp_buf.cb_mbuf, off, size, dst);
446 		break;
447 	case CRYPTO_BUF_UIO:
448 		cuio_copydata(crp->crp_buf.cb_uio, off, size, dst);
449 		break;
450 	case CRYPTO_BUF_CONTIG:
451 		MPASS(off + size <= crp->crp_buf.cb_buf_len);
452 		bcopy(crp->crp_buf.cb_buf + off, dst, size);
453 		break;
454 	default:
455 #ifdef INVARIANTS
456 		panic("invalid crp buf type %d", crp->crp_buf.cb_type);
457 #endif
458 		break;
459 	}
460 }
461 
462 int
463 crypto_apply_buf(struct crypto_buffer *cb, int off, int len,
464     int (*f)(void *, const void *, u_int), void *arg)
465 {
466 	int error;
467 
468 	switch (cb->cb_type) {
469 	case CRYPTO_BUF_MBUF:
470 		error = m_apply(cb->cb_mbuf, off, len,
471 		    (int (*)(void *, void *, u_int))f, arg);
472 		break;
473 	case CRYPTO_BUF_UIO:
474 		error = cuio_apply(cb->cb_uio, off, len, f, arg);
475 		break;
476 	case CRYPTO_BUF_CONTIG:
477 		MPASS(off + len <= cb->cb_buf_len);
478 		error = (*f)(arg, cb->cb_buf + off, len);
479 		break;
480 	default:
481 #ifdef INVARIANTS
482 		panic("invalid crypto buf type %d", cb->cb_type);
483 #endif
484 		error = 0;
485 		break;
486 	}
487 	return (error);
488 }
489 
490 int
491 crypto_apply(struct cryptop *crp, int off, int len,
492     int (*f)(void *, const void *, u_int), void *arg)
493 {
494 	return (crypto_apply_buf(&crp->crp_buf, off, len, f, arg));
495 }
496 
497 static inline void *
498 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
499 {
500 	int rel_off;
501 
502 	MPASS(skip <= INT_MAX);
503 
504 	m = m_getptr(m, (int)skip, &rel_off);
505 	if (m == NULL)
506 		return (NULL);
507 
508 	MPASS(rel_off >= 0);
509 	skip = rel_off;
510 	if (skip + len > m->m_len)
511 		return (NULL);
512 
513 	return (mtod(m, char*) + skip);
514 }
515 
516 static inline void *
517 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
518 {
519 	int rel_off, idx;
520 
521 	MPASS(skip <= INT_MAX);
522 	idx = cuio_getptr(uio, (int)skip, &rel_off);
523 	if (idx < 0)
524 		return (NULL);
525 
526 	MPASS(rel_off >= 0);
527 	skip = rel_off;
528 	if (skip + len > uio->uio_iov[idx].iov_len)
529 		return (NULL);
530 	return ((char *)uio->uio_iov[idx].iov_base + skip);
531 }
532 
533 void *
534 crypto_buffer_contiguous_subsegment(struct crypto_buffer *cb, size_t skip,
535     size_t len)
536 {
537 
538 	switch (cb->cb_type) {
539 	case CRYPTO_BUF_MBUF:
540 		return (m_contiguous_subsegment(cb->cb_mbuf, skip, len));
541 	case CRYPTO_BUF_UIO:
542 		return (cuio_contiguous_segment(cb->cb_uio, skip, len));
543 	case CRYPTO_BUF_CONTIG:
544 		MPASS(skip + len <= cb->cb_buf_len);
545 		return (cb->cb_buf + skip);
546 	default:
547 #ifdef INVARIANTS
548 		panic("invalid crp buf type %d", cb->cb_type);
549 #endif
550 		return (NULL);
551 	}
552 }
553 
554 void *
555 crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len)
556 {
557 	return (crypto_buffer_contiguous_subsegment(&crp->crp_buf, skip, len));
558 }
559