xref: /freebsd/sys/opencrypto/criov.c (revision 7cc42f6d)
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 #include <sys/sdt.h>
44 
45 #include <machine/vmparam.h>
46 
47 #include <vm/vm.h>
48 #include <vm/vm_page.h>
49 #include <vm/pmap.h>
50 
51 #include <opencrypto/cryptodev.h>
52 
53 SDT_PROVIDER_DECLARE(opencrypto);
54 
55 /*
56  * These macros are only for avoiding code duplication, as we need to skip
57  * given number of bytes in the same way in several functions below.
58  */
59 #define	CUIO_SKIP()	do {						\
60 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
61 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
62 	while (off > 0) {						\
63 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
64 		if (off < iov->iov_len)					\
65 			break;						\
66 		off -= iov->iov_len;					\
67 		iol--;							\
68 		iov++;							\
69 	}								\
70 } while (0)
71 
72 #define CVM_PAGE_SKIP()	do {					\
73 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
74 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
75 	while (off > 0) {						\
76 		if (off < PAGE_SIZE)					\
77 			break;						\
78 		processed += PAGE_SIZE - off;				\
79 		off -= PAGE_SIZE - off;					\
80 		pages++;						\
81 	}								\
82 } while (0)
83 
84 static void
85 cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
86 {
87 	struct iovec *iov = uio->uio_iov;
88 	int iol = uio->uio_iovcnt;
89 	unsigned count;
90 
91 	CUIO_SKIP();
92 	while (len > 0) {
93 		KASSERT(iol >= 0, ("%s: empty", __func__));
94 		count = min(iov->iov_len - off, len);
95 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
96 		len -= count;
97 		cp += count;
98 		off = 0;
99 		iol--;
100 		iov++;
101 	}
102 }
103 
104 static void
105 cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp)
106 {
107 	struct iovec *iov = uio->uio_iov;
108 	int iol = uio->uio_iovcnt;
109 	unsigned count;
110 
111 	CUIO_SKIP();
112 	while (len > 0) {
113 		KASSERT(iol >= 0, ("%s: empty", __func__));
114 		count = min(iov->iov_len - off, len);
115 		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
116 		len -= count;
117 		cp += count;
118 		off = 0;
119 		iol--;
120 		iov++;
121 	}
122 }
123 
124 /*
125  * Return the index and offset of location in iovec list.
126  */
127 static int
128 cuio_getptr(struct uio *uio, int loc, int *off)
129 {
130 	int ind, len;
131 
132 	ind = 0;
133 	while (loc >= 0 && ind < uio->uio_iovcnt) {
134 		len = uio->uio_iov[ind].iov_len;
135 		if (len > loc) {
136 	    		*off = loc;
137 	    		return (ind);
138 		}
139 		loc -= len;
140 		ind++;
141 	}
142 
143 	if (ind > 0 && loc == 0) {
144 		ind--;
145 		*off = uio->uio_iov[ind].iov_len;
146 		return (ind);
147 	}
148 
149 	return (-1);
150 }
151 
152 #if CRYPTO_MAY_HAVE_VMPAGE
153 /*
154  * Apply function f to the data in a vm_page_t list starting "off" bytes from
155  * the beginning, continuing for "len" bytes.
156  */
157 static int
158 cvm_page_apply(vm_page_t *pages, int off, int len,
159     int (*f)(void *, const void *, u_int), void *arg)
160 {
161 	int processed = 0;
162 	unsigned count;
163 	int rval;
164 
165 	CVM_PAGE_SKIP();
166 	while (len > 0) {
167 		char *kaddr = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages));
168 		count = min(PAGE_SIZE - off, len);
169 		rval = (*f)(arg, kaddr + off, count);
170 		if (rval)
171 			return (rval);
172 		len -= count;
173 		processed += count;
174 		off = 0;
175 		pages++;
176 	}
177 	return (0);
178 }
179 
180 static inline void *
181 cvm_page_contiguous_segment(vm_page_t *pages, size_t skip, int len)
182 {
183 	if ((skip + len - 1) / PAGE_SIZE > skip / PAGE_SIZE)
184 		return (NULL);
185 
186 	pages += (skip / PAGE_SIZE);
187 	skip -= rounddown(skip, PAGE_SIZE);
188 	return (((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages))) + skip);
189 }
190 
191 /*
192  * Copy len bytes of data from the vm_page_t array, skipping the first off
193  * bytes, into the pointer cp.  Return the number of bytes skipped and copied.
194  * Does not verify the length of the array.
195  */
196 static int
197 cvm_page_copyback(vm_page_t *pages, int off, int len, c_caddr_t cp)
198 {
199 	int processed = 0;
200 	unsigned count;
201 
202 	CVM_PAGE_SKIP();
203 	while (len > 0) {
204 		count = min(PAGE_SIZE - off, len);
205 		bcopy(cp, (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off,
206 		    count);
207 		len -= count;
208 		cp += count;
209 		processed += count;
210 		off = 0;
211 		pages++;
212 	}
213 	return (processed);
214 }
215 
216 /*
217  * Copy len bytes of data from the pointer cp into the vm_page_t array,
218  * skipping the first off bytes, Return the number of bytes skipped and copied.
219  * Does not verify the length of the array.
220  */
221 static int
222 cvm_page_copydata(vm_page_t *pages, int off, int len, caddr_t cp)
223 {
224 	int processed = 0;
225 	unsigned count;
226 
227 	CVM_PAGE_SKIP();
228 	while (len > 0) {
229 		count = min(PAGE_SIZE - off, len);
230 		bcopy(((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off), cp,
231 		    count);
232 		len -= count;
233 		cp += count;
234 		processed += count;
235 		off = 0;
236 		pages++;
237 	}
238 	return processed;
239 }
240 #endif /* CRYPTO_MAY_HAVE_VMPAGE */
241 
242 void
243 crypto_cursor_init(struct crypto_buffer_cursor *cc,
244     const struct crypto_buffer *cb)
245 {
246 	memset(cc, 0, sizeof(*cc));
247 	cc->cc_type = cb->cb_type;
248 	switch (cc->cc_type) {
249 	case CRYPTO_BUF_CONTIG:
250 		cc->cc_buf = cb->cb_buf;
251 		cc->cc_buf_len = cb->cb_buf_len;
252 		break;
253 	case CRYPTO_BUF_MBUF:
254 		cc->cc_mbuf = cb->cb_mbuf;
255 		break;
256 	case CRYPTO_BUF_VMPAGE:
257 		cc->cc_vmpage = cb->cb_vm_page;
258 		cc->cc_buf_len = cb->cb_vm_page_len;
259 		cc->cc_offset = cb->cb_vm_page_offset;
260 		break;
261 	case CRYPTO_BUF_UIO:
262 		cc->cc_iov = cb->cb_uio->uio_iov;
263 		break;
264 	default:
265 #ifdef INVARIANTS
266 		panic("%s: invalid buffer type %d", __func__, cb->cb_type);
267 #endif
268 		break;
269 	}
270 }
271 
272 SDT_PROBE_DEFINE2(opencrypto, criov, cursor_advance, vmpage, "struct crypto_buffer_cursor*", "size_t");
273 
274 void
275 crypto_cursor_advance(struct crypto_buffer_cursor *cc, size_t amount)
276 {
277 	size_t remain;
278 
279 	switch (cc->cc_type) {
280 	case CRYPTO_BUF_CONTIG:
281 		MPASS(cc->cc_buf_len >= amount);
282 		cc->cc_buf += amount;
283 		cc->cc_buf_len -= amount;
284 		break;
285 	case CRYPTO_BUF_MBUF:
286 		for (;;) {
287 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
288 			if (amount < remain) {
289 				cc->cc_offset += amount;
290 				break;
291 			}
292 			amount -= remain;
293 			cc->cc_mbuf = cc->cc_mbuf->m_next;
294 			cc->cc_offset = 0;
295 			if (amount == 0)
296 				break;
297 		}
298 		break;
299 	case CRYPTO_BUF_VMPAGE:
300 		for (;;) {
301 			SDT_PROBE2(opencrypto, criov, cursor_advance, vmpage,
302 			    cc, amount);
303 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
304 			if (amount < remain) {
305 				cc->cc_buf_len -= amount;
306 				cc->cc_offset += amount;
307 				break;
308 			}
309 			cc->cc_buf_len -= remain;
310 			amount -= remain;
311 			cc->cc_vmpage++;
312 			cc->cc_offset = 0;
313 			if (amount == 0 || cc->cc_buf_len == 0)
314 				break;
315 		}
316 		break;
317 	case CRYPTO_BUF_UIO:
318 		for (;;) {
319 			remain = cc->cc_iov->iov_len - cc->cc_offset;
320 			if (amount < remain) {
321 				cc->cc_offset += amount;
322 				break;
323 			}
324 			amount -= remain;
325 			cc->cc_iov++;
326 			cc->cc_offset = 0;
327 			if (amount == 0)
328 				break;
329 		}
330 		break;
331 	default:
332 #ifdef INVARIANTS
333 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
334 #endif
335 		break;
336 	}
337 }
338 
339 void *
340 crypto_cursor_segbase(struct crypto_buffer_cursor *cc)
341 {
342 	switch (cc->cc_type) {
343 	case CRYPTO_BUF_CONTIG:
344 		return (cc->cc_buf);
345 	case CRYPTO_BUF_MBUF:
346 		if (cc->cc_mbuf == NULL)
347 			return (NULL);
348 		KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
349 		    ("%s: not supported for unmapped mbufs", __func__));
350 		return (mtod(cc->cc_mbuf, char *) + cc->cc_offset);
351 	case CRYPTO_BUF_VMPAGE:
352 		return ((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
353 		    *cc->cc_vmpage)) + cc->cc_offset);
354 	case CRYPTO_BUF_UIO:
355 		return ((char *)cc->cc_iov->iov_base + cc->cc_offset);
356 	default:
357 #ifdef INVARIANTS
358 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
359 #endif
360 		return (NULL);
361 	}
362 }
363 
364 size_t
365 crypto_cursor_seglen(struct crypto_buffer_cursor *cc)
366 {
367 	switch (cc->cc_type) {
368 	case CRYPTO_BUF_CONTIG:
369 		return (cc->cc_buf_len);
370 	case CRYPTO_BUF_VMPAGE:
371 		return (PAGE_SIZE - cc->cc_offset);
372 	case CRYPTO_BUF_MBUF:
373 		if (cc->cc_mbuf == NULL)
374 			return (0);
375 		return (cc->cc_mbuf->m_len - cc->cc_offset);
376 	case CRYPTO_BUF_UIO:
377 		return (cc->cc_iov->iov_len - cc->cc_offset);
378 	default:
379 #ifdef INVARIANTS
380 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
381 #endif
382 		return (0);
383 	}
384 }
385 
386 void
387 crypto_cursor_copyback(struct crypto_buffer_cursor *cc, int size,
388     const void *vsrc)
389 {
390 	size_t remain, todo;
391 	const char *src;
392 	char *dst;
393 
394 	src = vsrc;
395 	switch (cc->cc_type) {
396 	case CRYPTO_BUF_CONTIG:
397 		MPASS(cc->cc_buf_len >= size);
398 		memcpy(cc->cc_buf, src, size);
399 		cc->cc_buf += size;
400 		cc->cc_buf_len -= size;
401 		break;
402 	case CRYPTO_BUF_MBUF:
403 		for (;;) {
404 			KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
405 			    ("%s: not supported for unmapped mbufs", __func__));
406 			dst = mtod(cc->cc_mbuf, char *) + cc->cc_offset;
407 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
408 			todo = MIN(remain, size);
409 			memcpy(dst, src, todo);
410 			src += todo;
411 			if (todo < remain) {
412 				cc->cc_offset += todo;
413 				break;
414 			}
415 			size -= todo;
416 			cc->cc_mbuf = cc->cc_mbuf->m_next;
417 			cc->cc_offset = 0;
418 			if (size == 0)
419 				break;
420 		}
421 		break;
422 	case CRYPTO_BUF_VMPAGE:
423 		for (;;) {
424 			dst = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
425 			    *cc->cc_vmpage)) + cc->cc_offset;
426 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
427 			todo = MIN(remain, size);
428 			memcpy(dst, src, todo);
429 			src += todo;
430 			cc->cc_buf_len -= todo;
431 			if (todo < remain) {
432 				cc->cc_offset += todo;
433 				break;
434 			}
435 			size -= todo;
436 			cc->cc_vmpage++;
437 			cc->cc_offset = 0;
438 			if (size == 0)
439 				break;
440 		}
441 		break;
442 	case CRYPTO_BUF_UIO:
443 		for (;;) {
444 			dst = (char *)cc->cc_iov->iov_base + cc->cc_offset;
445 			remain = cc->cc_iov->iov_len - cc->cc_offset;
446 			todo = MIN(remain, size);
447 			memcpy(dst, src, todo);
448 			src += todo;
449 			if (todo < remain) {
450 				cc->cc_offset += todo;
451 				break;
452 			}
453 			size -= todo;
454 			cc->cc_iov++;
455 			cc->cc_offset = 0;
456 			if (size == 0)
457 				break;
458 		}
459 		break;
460 	default:
461 #ifdef INVARIANTS
462 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
463 #endif
464 		break;
465 	}
466 }
467 
468 void
469 crypto_cursor_copydata(struct crypto_buffer_cursor *cc, int size, void *vdst)
470 {
471 	size_t remain, todo;
472 	const char *src;
473 	char *dst;
474 
475 	dst = vdst;
476 	switch (cc->cc_type) {
477 	case CRYPTO_BUF_CONTIG:
478 		MPASS(cc->cc_buf_len >= size);
479 		memcpy(dst, cc->cc_buf, size);
480 		cc->cc_buf += size;
481 		cc->cc_buf_len -= size;
482 		break;
483 	case CRYPTO_BUF_MBUF:
484 		for (;;) {
485 			KASSERT((cc->cc_mbuf->m_flags & M_EXTPG) == 0,
486 			    ("%s: not supported for unmapped mbufs", __func__));
487 			src = mtod(cc->cc_mbuf, const char *) + cc->cc_offset;
488 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
489 			todo = MIN(remain, size);
490 			memcpy(dst, src, todo);
491 			dst += todo;
492 			if (todo < remain) {
493 				cc->cc_offset += todo;
494 				break;
495 			}
496 			size -= todo;
497 			cc->cc_mbuf = cc->cc_mbuf->m_next;
498 			cc->cc_offset = 0;
499 			if (size == 0)
500 				break;
501 		}
502 		break;
503 	case CRYPTO_BUF_VMPAGE:
504 		for (;;) {
505 			src = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
506 			    *cc->cc_vmpage)) + cc->cc_offset;
507 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
508 			todo = MIN(remain, size);
509 			memcpy(dst, src, todo);
510 			src += todo;
511 			cc->cc_buf_len -= todo;
512 			if (todo < remain) {
513 				cc->cc_offset += todo;
514 				break;
515 			}
516 			size -= todo;
517 			cc->cc_vmpage++;
518 			cc->cc_offset = 0;
519 			if (size == 0)
520 				break;
521 		}
522 		break;
523 	case CRYPTO_BUF_UIO:
524 		for (;;) {
525 			src = (const char *)cc->cc_iov->iov_base +
526 			    cc->cc_offset;
527 			remain = cc->cc_iov->iov_len - cc->cc_offset;
528 			todo = MIN(remain, size);
529 			memcpy(dst, src, todo);
530 			dst += todo;
531 			if (todo < remain) {
532 				cc->cc_offset += todo;
533 				break;
534 			}
535 			size -= todo;
536 			cc->cc_iov++;
537 			cc->cc_offset = 0;
538 			if (size == 0)
539 				break;
540 		}
541 		break;
542 	default:
543 #ifdef INVARIANTS
544 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
545 #endif
546 		break;
547 	}
548 }
549 
550 /*
551  * To avoid advancing 'cursor', make a local copy that gets advanced
552  * instead.
553  */
554 void
555 crypto_cursor_copydata_noadv(struct crypto_buffer_cursor *cc, int size,
556     void *vdst)
557 {
558 	struct crypto_buffer_cursor copy;
559 
560 	copy = *cc;
561 	crypto_cursor_copydata(&copy, size, vdst);
562 }
563 
564 /*
565  * Apply function f to the data in an iovec list starting "off" bytes from
566  * the beginning, continuing for "len" bytes.
567  */
568 static int
569 cuio_apply(struct uio *uio, int off, int len,
570     int (*f)(void *, const void *, u_int), void *arg)
571 {
572 	struct iovec *iov = uio->uio_iov;
573 	int iol = uio->uio_iovcnt;
574 	unsigned count;
575 	int rval;
576 
577 	CUIO_SKIP();
578 	while (len > 0) {
579 		KASSERT(iol >= 0, ("%s: empty", __func__));
580 		count = min(iov->iov_len - off, len);
581 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
582 		if (rval)
583 			return (rval);
584 		len -= count;
585 		off = 0;
586 		iol--;
587 		iov++;
588 	}
589 	return (0);
590 }
591 
592 void
593 crypto_copyback(struct cryptop *crp, int off, int size, const void *src)
594 {
595 	struct crypto_buffer *cb;
596 
597 	if (crp->crp_obuf.cb_type != CRYPTO_BUF_NONE)
598 		cb = &crp->crp_obuf;
599 	else
600 		cb = &crp->crp_buf;
601 	switch (cb->cb_type) {
602 	case CRYPTO_BUF_MBUF:
603 		m_copyback(cb->cb_mbuf, off, size, src);
604 		break;
605 #if CRYPTO_MAY_HAVE_VMPAGE
606 	case CRYPTO_BUF_VMPAGE:
607 		MPASS(size <= cb->cb_vm_page_len);
608 		MPASS(size + off <=
609 		    cb->cb_vm_page_len + cb->cb_vm_page_offset);
610 		cvm_page_copyback(cb->cb_vm_page,
611 		    off + cb->cb_vm_page_offset, size, src);
612 		break;
613 #endif /* CRYPTO_MAY_HAVE_VMPAGE */
614 	case CRYPTO_BUF_UIO:
615 		cuio_copyback(cb->cb_uio, off, size, src);
616 		break;
617 	case CRYPTO_BUF_CONTIG:
618 		MPASS(off + size <= cb->cb_buf_len);
619 		bcopy(src, cb->cb_buf + off, size);
620 		break;
621 	default:
622 #ifdef INVARIANTS
623 		panic("invalid crp buf type %d", cb->cb_type);
624 #endif
625 		break;
626 	}
627 }
628 
629 void
630 crypto_copydata(struct cryptop *crp, int off, int size, void *dst)
631 {
632 
633 	switch (crp->crp_buf.cb_type) {
634 	case CRYPTO_BUF_MBUF:
635 		m_copydata(crp->crp_buf.cb_mbuf, off, size, dst);
636 		break;
637 #if CRYPTO_MAY_HAVE_VMPAGE
638 	case CRYPTO_BUF_VMPAGE:
639 		MPASS(size <= crp->crp_buf.cb_vm_page_len);
640 		MPASS(size + off <= crp->crp_buf.cb_vm_page_len +
641 		    crp->crp_buf.cb_vm_page_offset);
642 		cvm_page_copydata(crp->crp_buf.cb_vm_page,
643 		    off + crp->crp_buf.cb_vm_page_offset, size, dst);
644 		break;
645 #endif /* CRYPTO_MAY_HAVE_VMPAGE */
646 	case CRYPTO_BUF_UIO:
647 		cuio_copydata(crp->crp_buf.cb_uio, off, size, dst);
648 		break;
649 	case CRYPTO_BUF_CONTIG:
650 		MPASS(off + size <= crp->crp_buf.cb_buf_len);
651 		bcopy(crp->crp_buf.cb_buf + off, dst, size);
652 		break;
653 	default:
654 #ifdef INVARIANTS
655 		panic("invalid crp buf type %d", crp->crp_buf.cb_type);
656 #endif
657 		break;
658 	}
659 }
660 
661 int
662 crypto_apply_buf(struct crypto_buffer *cb, int off, int len,
663     int (*f)(void *, const void *, u_int), void *arg)
664 {
665 	int error;
666 
667 	switch (cb->cb_type) {
668 	case CRYPTO_BUF_MBUF:
669 		error = m_apply(cb->cb_mbuf, off, len,
670 		    (int (*)(void *, void *, u_int))f, arg);
671 		break;
672 	case CRYPTO_BUF_UIO:
673 		error = cuio_apply(cb->cb_uio, off, len, f, arg);
674 		break;
675 #if CRYPTO_MAY_HAVE_VMPAGE
676 	case CRYPTO_BUF_VMPAGE:
677 		error = cvm_page_apply(cb->cb_vm_page,
678 		    off + cb->cb_vm_page_offset, len, f, arg);
679 		break;
680 #endif /* CRYPTO_MAY_HAVE_VMPAGE */
681 	case CRYPTO_BUF_CONTIG:
682 		MPASS(off + len <= cb->cb_buf_len);
683 		error = (*f)(arg, cb->cb_buf + off, len);
684 		break;
685 	default:
686 #ifdef INVARIANTS
687 		panic("invalid crypto buf type %d", cb->cb_type);
688 #endif
689 		error = 0;
690 		break;
691 	}
692 	return (error);
693 }
694 
695 int
696 crypto_apply(struct cryptop *crp, int off, int len,
697     int (*f)(void *, const void *, u_int), void *arg)
698 {
699 	return (crypto_apply_buf(&crp->crp_buf, off, len, f, arg));
700 }
701 
702 static inline void *
703 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
704 {
705 	int rel_off;
706 
707 	MPASS(skip <= INT_MAX);
708 
709 	m = m_getptr(m, (int)skip, &rel_off);
710 	if (m == NULL)
711 		return (NULL);
712 
713 	MPASS(rel_off >= 0);
714 	skip = rel_off;
715 	if (skip + len > m->m_len)
716 		return (NULL);
717 
718 	return (mtod(m, char*) + skip);
719 }
720 
721 static inline void *
722 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
723 {
724 	int rel_off, idx;
725 
726 	MPASS(skip <= INT_MAX);
727 	idx = cuio_getptr(uio, (int)skip, &rel_off);
728 	if (idx < 0)
729 		return (NULL);
730 
731 	MPASS(rel_off >= 0);
732 	skip = rel_off;
733 	if (skip + len > uio->uio_iov[idx].iov_len)
734 		return (NULL);
735 	return ((char *)uio->uio_iov[idx].iov_base + skip);
736 }
737 
738 void *
739 crypto_buffer_contiguous_subsegment(struct crypto_buffer *cb, size_t skip,
740     size_t len)
741 {
742 
743 	switch (cb->cb_type) {
744 	case CRYPTO_BUF_MBUF:
745 		return (m_contiguous_subsegment(cb->cb_mbuf, skip, len));
746 	case CRYPTO_BUF_UIO:
747 		return (cuio_contiguous_segment(cb->cb_uio, skip, len));
748 #if CRYPTO_MAY_HAVE_VMPAGE
749 	case CRYPTO_BUF_VMPAGE:
750 		MPASS(skip + len <= cb->cb_vm_page_len);
751 		return (cvm_page_contiguous_segment(cb->cb_vm_page,
752 		    skip + cb->cb_vm_page_offset, len));
753 #endif /* CRYPTO_MAY_HAVE_VMPAGE */
754 	case CRYPTO_BUF_CONTIG:
755 		MPASS(skip + len <= cb->cb_buf_len);
756 		return (cb->cb_buf + skip);
757 	default:
758 #ifdef INVARIANTS
759 		panic("invalid crp buf type %d", cb->cb_type);
760 #endif
761 		return (NULL);
762 	}
763 }
764 
765 void *
766 crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len)
767 {
768 	return (crypto_buffer_contiguous_subsegment(&crp->crp_buf, skip, len));
769 }
770