xref: /freebsd/sys/opencrypto/criov.c (revision 883a0196b629a07e52562b4103cc0f6391083080)
1091d81d1SSam Leffler /*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
2091d81d1SSam Leffler 
360727d8bSWarner Losh /*-
4091d81d1SSam Leffler  * Copyright (c) 1999 Theo de Raadt
5091d81d1SSam Leffler  *
6091d81d1SSam Leffler  * Redistribution and use in source and binary forms, with or without
7091d81d1SSam Leffler  * modification, are permitted provided that the following conditions
8091d81d1SSam Leffler  * are met:
9091d81d1SSam Leffler  *
10091d81d1SSam Leffler  * 1. Redistributions of source code must retain the above copyright
11091d81d1SSam Leffler  *   notice, this list of conditions and the following disclaimer.
12091d81d1SSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
13091d81d1SSam Leffler  *   notice, this list of conditions and the following disclaimer in the
14091d81d1SSam Leffler  *   documentation and/or other materials provided with the distribution.
15091d81d1SSam Leffler  * 3. The name of the author may not be used to endorse or promote products
16091d81d1SSam Leffler  *   derived from this software without specific prior written permission.
17091d81d1SSam Leffler  *
18091d81d1SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19091d81d1SSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20091d81d1SSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21091d81d1SSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22091d81d1SSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23091d81d1SSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24091d81d1SSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25091d81d1SSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26091d81d1SSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27091d81d1SSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28091d81d1SSam Leffler  */
29091d81d1SSam Leffler 
302c446514SDavid E. O'Brien #include <sys/cdefs.h>
312c446514SDavid E. O'Brien __FBSDID("$FreeBSD$");
322c446514SDavid E. O'Brien 
33091d81d1SSam Leffler #include <sys/param.h>
34091d81d1SSam Leffler #include <sys/systm.h>
35091d81d1SSam Leffler #include <sys/proc.h>
36091d81d1SSam Leffler #include <sys/errno.h>
37091d81d1SSam Leffler #include <sys/malloc.h>
38091d81d1SSam Leffler #include <sys/kernel.h>
3911d2e1e8SPawel Jakub Dawidek #include <sys/mbuf.h>
40091d81d1SSam Leffler #include <sys/uio.h>
41ff2038a9SMatt Macy #include <sys/limits.h>
42ff2038a9SMatt Macy #include <sys/lock.h>
43e6f6d0c9SAlan Somers #include <sys/sdt.h>
44e6f6d0c9SAlan Somers 
45e6f6d0c9SAlan Somers #include <machine/vmparam.h>
46e6f6d0c9SAlan Somers 
47e6f6d0c9SAlan Somers #include <vm/vm.h>
48e6f6d0c9SAlan Somers #include <vm/vm_page.h>
49e6f6d0c9SAlan Somers #include <vm/pmap.h>
50091d81d1SSam Leffler 
51091d81d1SSam Leffler #include <opencrypto/cryptodev.h>
52091d81d1SSam Leffler 
53e6f6d0c9SAlan Somers SDT_PROVIDER_DECLARE(opencrypto);
54e6f6d0c9SAlan Somers 
558f91d4abSPawel Jakub Dawidek /*
56e6f6d0c9SAlan Somers  * These macros are only for avoiding code duplication, as we need to skip
57e6f6d0c9SAlan Somers  * given number of bytes in the same way in several functions below.
588f91d4abSPawel Jakub Dawidek  */
598f91d4abSPawel Jakub Dawidek #define	CUIO_SKIP()	do {						\
608f91d4abSPawel Jakub Dawidek 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
618f91d4abSPawel Jakub Dawidek 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
628f91d4abSPawel Jakub Dawidek 	while (off > 0) {						\
638f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
648f91d4abSPawel Jakub Dawidek 		if (off < iov->iov_len)					\
658f91d4abSPawel Jakub Dawidek 			break;						\
668f91d4abSPawel Jakub Dawidek 		off -= iov->iov_len;					\
678f91d4abSPawel Jakub Dawidek 		iol--;							\
688f91d4abSPawel Jakub Dawidek 		iov++;							\
698f91d4abSPawel Jakub Dawidek 	}								\
708f91d4abSPawel Jakub Dawidek } while (0)
718f91d4abSPawel Jakub Dawidek 
72e6f6d0c9SAlan Somers #define CVM_PAGE_SKIP()	do {					\
73e6f6d0c9SAlan Somers 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
74e6f6d0c9SAlan Somers 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
75e6f6d0c9SAlan Somers 	while (off > 0) {						\
76e6f6d0c9SAlan Somers 		if (off < PAGE_SIZE)					\
77e6f6d0c9SAlan Somers 			break;						\
78e6f6d0c9SAlan Somers 		processed += PAGE_SIZE - off;				\
79e6f6d0c9SAlan Somers 		off -= PAGE_SIZE - off;					\
80e6f6d0c9SAlan Somers 		pages++;						\
81e6f6d0c9SAlan Somers 	}								\
82e6f6d0c9SAlan Somers } while (0)
83e6f6d0c9SAlan Somers 
849c0e3d3aSJohn Baldwin static void
85091d81d1SSam Leffler cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
86091d81d1SSam Leffler {
87091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
88091d81d1SSam Leffler 	int iol = uio->uio_iovcnt;
89091d81d1SSam Leffler 	unsigned count;
90091d81d1SSam Leffler 
918f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
92091d81d1SSam Leffler 	while (len > 0) {
938f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
94091d81d1SSam Leffler 		count = min(iov->iov_len - off, len);
95091d81d1SSam Leffler 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
96091d81d1SSam Leffler 		len -= count;
97091d81d1SSam Leffler 		cp += count;
98091d81d1SSam Leffler 		off = 0;
99091d81d1SSam Leffler 		iol--;
100091d81d1SSam Leffler 		iov++;
101091d81d1SSam Leffler 	}
102091d81d1SSam Leffler }
103091d81d1SSam Leffler 
1049c0e3d3aSJohn Baldwin static void
1057dd10fdeSJohn Baldwin cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp)
106091d81d1SSam Leffler {
107091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
108091d81d1SSam Leffler 	int iol = uio->uio_iovcnt;
109091d81d1SSam Leffler 	unsigned count;
110091d81d1SSam Leffler 
1118f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
112091d81d1SSam Leffler 	while (len > 0) {
1138f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
114091d81d1SSam Leffler 		count = min(iov->iov_len - off, len);
115091d81d1SSam Leffler 		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
116091d81d1SSam Leffler 		len -= count;
117091d81d1SSam Leffler 		cp += count;
118091d81d1SSam Leffler 		off = 0;
119091d81d1SSam Leffler 		iol--;
120091d81d1SSam Leffler 		iov++;
121091d81d1SSam Leffler 	}
122091d81d1SSam Leffler }
123091d81d1SSam Leffler 
124091d81d1SSam Leffler /*
12508fca7a5SJohn-Mark Gurney  * Return the index and offset of location in iovec list.
126091d81d1SSam Leffler  */
1279c0e3d3aSJohn Baldwin static int
128091d81d1SSam Leffler cuio_getptr(struct uio *uio, int loc, int *off)
129091d81d1SSam Leffler {
13008fca7a5SJohn-Mark Gurney 	int ind, len;
131091d81d1SSam Leffler 
13208fca7a5SJohn-Mark Gurney 	ind = 0;
13308fca7a5SJohn-Mark Gurney 	while (loc >= 0 && ind < uio->uio_iovcnt) {
13408fca7a5SJohn-Mark Gurney 		len = uio->uio_iov[ind].iov_len;
13508fca7a5SJohn-Mark Gurney 		if (len > loc) {
136091d81d1SSam Leffler 	    		*off = loc;
13708fca7a5SJohn-Mark Gurney 	    		return (ind);
13808fca7a5SJohn-Mark Gurney 		}
13908fca7a5SJohn-Mark Gurney 		loc -= len;
14008fca7a5SJohn-Mark Gurney 		ind++;
141091d81d1SSam Leffler 	}
142091d81d1SSam Leffler 
14308fca7a5SJohn-Mark Gurney 	if (ind > 0 && loc == 0) {
14408fca7a5SJohn-Mark Gurney 		ind--;
14508fca7a5SJohn-Mark Gurney 		*off = uio->uio_iov[ind].iov_len;
14608fca7a5SJohn-Mark Gurney 		return (ind);
147091d81d1SSam Leffler 	}
148091d81d1SSam Leffler 
14908fca7a5SJohn-Mark Gurney 	return (-1);
150091d81d1SSam Leffler }
1518f91d4abSPawel Jakub Dawidek 
152e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
153e6f6d0c9SAlan Somers /*
154e6f6d0c9SAlan Somers  * Apply function f to the data in a vm_page_t list starting "off" bytes from
155e6f6d0c9SAlan Somers  * the beginning, continuing for "len" bytes.
156e6f6d0c9SAlan Somers  */
157e6f6d0c9SAlan Somers static int
158e6f6d0c9SAlan Somers cvm_page_apply(vm_page_t *pages, int off, int len,
159e6f6d0c9SAlan Somers     int (*f)(void *, const void *, u_int), void *arg)
160e6f6d0c9SAlan Somers {
161e6f6d0c9SAlan Somers 	int processed = 0;
162e6f6d0c9SAlan Somers 	unsigned count;
163e6f6d0c9SAlan Somers 	int rval;
164e6f6d0c9SAlan Somers 
165e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
166e6f6d0c9SAlan Somers 	while (len > 0) {
167e6f6d0c9SAlan Somers 		char *kaddr = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages));
168e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
169e6f6d0c9SAlan Somers 		rval = (*f)(arg, kaddr + off, count);
170e6f6d0c9SAlan Somers 		if (rval)
171e6f6d0c9SAlan Somers 			return (rval);
172e6f6d0c9SAlan Somers 		len -= count;
173e6f6d0c9SAlan Somers 		processed += count;
174e6f6d0c9SAlan Somers 		off = 0;
175e6f6d0c9SAlan Somers 		pages++;
176e6f6d0c9SAlan Somers 	}
177e6f6d0c9SAlan Somers 	return (0);
178e6f6d0c9SAlan Somers }
179e6f6d0c9SAlan Somers 
180e6f6d0c9SAlan Somers static inline void *
181e6f6d0c9SAlan Somers cvm_page_contiguous_segment(vm_page_t *pages, size_t skip, int len)
182e6f6d0c9SAlan Somers {
183e6f6d0c9SAlan Somers 	if ((skip + len - 1) / PAGE_SIZE > skip / PAGE_SIZE)
184e6f6d0c9SAlan Somers 		return (NULL);
185e6f6d0c9SAlan Somers 
186e6f6d0c9SAlan Somers 	pages += (skip / PAGE_SIZE);
187e6f6d0c9SAlan Somers 	skip -= rounddown(skip, PAGE_SIZE);
188e6f6d0c9SAlan Somers 	return (((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages))) + skip);
189e6f6d0c9SAlan Somers }
190e6f6d0c9SAlan Somers 
191e6f6d0c9SAlan Somers /*
192e6f6d0c9SAlan Somers  * Copy len bytes of data from the vm_page_t array, skipping the first off
193e6f6d0c9SAlan Somers  * bytes, into the pointer cp.  Return the number of bytes skipped and copied.
194e6f6d0c9SAlan Somers  * Does not verify the length of the array.
195e6f6d0c9SAlan Somers  */
196e6f6d0c9SAlan Somers static int
197e6f6d0c9SAlan Somers cvm_page_copyback(vm_page_t *pages, int off, int len, c_caddr_t cp)
198e6f6d0c9SAlan Somers {
199e6f6d0c9SAlan Somers 	int processed = 0;
200e6f6d0c9SAlan Somers 	unsigned count;
201e6f6d0c9SAlan Somers 
202e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
203e6f6d0c9SAlan Somers 	while (len > 0) {
204e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
205e6f6d0c9SAlan Somers 		bcopy(cp, (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off,
206e6f6d0c9SAlan Somers 		    count);
207e6f6d0c9SAlan Somers 		len -= count;
208e6f6d0c9SAlan Somers 		cp += count;
209e6f6d0c9SAlan Somers 		processed += count;
210e6f6d0c9SAlan Somers 		off = 0;
211e6f6d0c9SAlan Somers 		pages++;
212e6f6d0c9SAlan Somers 	}
213e6f6d0c9SAlan Somers 	return (processed);
214e6f6d0c9SAlan Somers }
215e6f6d0c9SAlan Somers 
216e6f6d0c9SAlan Somers /*
217e6f6d0c9SAlan Somers  * Copy len bytes of data from the pointer cp into the vm_page_t array,
218e6f6d0c9SAlan Somers  * skipping the first off bytes, Return the number of bytes skipped and copied.
219e6f6d0c9SAlan Somers  * Does not verify the length of the array.
220e6f6d0c9SAlan Somers  */
221e6f6d0c9SAlan Somers static int
222e6f6d0c9SAlan Somers cvm_page_copydata(vm_page_t *pages, int off, int len, caddr_t cp)
223e6f6d0c9SAlan Somers {
224e6f6d0c9SAlan Somers 	int processed = 0;
225e6f6d0c9SAlan Somers 	unsigned count;
226e6f6d0c9SAlan Somers 
227e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
228e6f6d0c9SAlan Somers 	while (len > 0) {
229e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
230e6f6d0c9SAlan Somers 		bcopy(((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off), cp,
231e6f6d0c9SAlan Somers 		    count);
232e6f6d0c9SAlan Somers 		len -= count;
233e6f6d0c9SAlan Somers 		cp += count;
234e6f6d0c9SAlan Somers 		processed += count;
235e6f6d0c9SAlan Somers 		off = 0;
236e6f6d0c9SAlan Somers 		pages++;
237e6f6d0c9SAlan Somers 	}
238e6f6d0c9SAlan Somers 	return processed;
239e6f6d0c9SAlan Somers }
240e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
241e6f6d0c9SAlan Somers 
2421c8f4b3cSJohn Baldwin /*
2431c8f4b3cSJohn Baldwin  * Given a starting page in an m_epg, determine the length of the
2441c8f4b3cSJohn Baldwin  * current physically contiguous segment.
2451c8f4b3cSJohn Baldwin  */
2461c8f4b3cSJohn Baldwin static __inline size_t
2471c8f4b3cSJohn Baldwin m_epg_pages_extent(struct mbuf *m, int idx, u_int pglen)
2481c8f4b3cSJohn Baldwin {
2491c8f4b3cSJohn Baldwin 	size_t len;
2501c8f4b3cSJohn Baldwin 	u_int i;
2511c8f4b3cSJohn Baldwin 
2521c8f4b3cSJohn Baldwin 	len = pglen;
2531c8f4b3cSJohn Baldwin 	for (i = idx + 1; i < m->m_epg_npgs; i++) {
2541c8f4b3cSJohn Baldwin 		if (m->m_epg_pa[i - 1] + PAGE_SIZE != m->m_epg_pa[i])
2551c8f4b3cSJohn Baldwin 			break;
2561c8f4b3cSJohn Baldwin 		len += m_epg_pagelen(m, i, 0);
2571c8f4b3cSJohn Baldwin 	}
2581c8f4b3cSJohn Baldwin 	return (len);
2591c8f4b3cSJohn Baldwin }
2601c8f4b3cSJohn Baldwin 
2611c8f4b3cSJohn Baldwin static __inline void *
2621c8f4b3cSJohn Baldwin m_epg_segbase(struct mbuf *m, size_t offset)
2631c8f4b3cSJohn Baldwin {
2641c8f4b3cSJohn Baldwin 	u_int i, pglen, pgoff;
2651c8f4b3cSJohn Baldwin 
2661c8f4b3cSJohn Baldwin 	offset += mtod(m, vm_offset_t);
2671c8f4b3cSJohn Baldwin 	if (offset < m->m_epg_hdrlen)
2681c8f4b3cSJohn Baldwin 		return (m->m_epg_hdr + offset);
2691c8f4b3cSJohn Baldwin 	offset -= m->m_epg_hdrlen;
2701c8f4b3cSJohn Baldwin 	pgoff = m->m_epg_1st_off;
2711c8f4b3cSJohn Baldwin 	for (i = 0; i < m->m_epg_npgs; i++) {
2721c8f4b3cSJohn Baldwin 		pglen = m_epg_pagelen(m, i, pgoff);
2731c8f4b3cSJohn Baldwin 		if (offset < pglen)
2741c8f4b3cSJohn Baldwin 			return ((void *)PHYS_TO_DMAP(m->m_epg_pa[i] + pgoff +
2751c8f4b3cSJohn Baldwin 			    offset));
2761c8f4b3cSJohn Baldwin 		offset -= pglen;
2771c8f4b3cSJohn Baldwin 		pgoff = 0;
2781c8f4b3cSJohn Baldwin 	}
2791c8f4b3cSJohn Baldwin 	KASSERT(offset <= m->m_epg_trllen, ("%s: offset beyond trailer",
2801c8f4b3cSJohn Baldwin 	    __func__));
2811c8f4b3cSJohn Baldwin 	return (m->m_epg_trail + offset);
2821c8f4b3cSJohn Baldwin }
2831c8f4b3cSJohn Baldwin 
2841c8f4b3cSJohn Baldwin static __inline size_t
2851c8f4b3cSJohn Baldwin m_epg_seglen(struct mbuf *m, size_t offset)
2861c8f4b3cSJohn Baldwin {
2871c8f4b3cSJohn Baldwin 	u_int i, pglen, pgoff;
2881c8f4b3cSJohn Baldwin 
2891c8f4b3cSJohn Baldwin 	offset += mtod(m, vm_offset_t);
2901c8f4b3cSJohn Baldwin 	if (offset < m->m_epg_hdrlen)
2911c8f4b3cSJohn Baldwin 		return (m->m_epg_hdrlen - offset);
2921c8f4b3cSJohn Baldwin 	offset -= m->m_epg_hdrlen;
2931c8f4b3cSJohn Baldwin 	pgoff = m->m_epg_1st_off;
2941c8f4b3cSJohn Baldwin 	for (i = 0; i < m->m_epg_npgs; i++) {
2951c8f4b3cSJohn Baldwin 		pglen = m_epg_pagelen(m, i, pgoff);
2961c8f4b3cSJohn Baldwin 		if (offset < pglen)
2971c8f4b3cSJohn Baldwin 			return (m_epg_pages_extent(m, i, pglen) - offset);
2981c8f4b3cSJohn Baldwin 		offset -= pglen;
2991c8f4b3cSJohn Baldwin 		pgoff = 0;
3001c8f4b3cSJohn Baldwin 	}
3011c8f4b3cSJohn Baldwin 	KASSERT(offset <= m->m_epg_trllen, ("%s: offset beyond trailer",
3021c8f4b3cSJohn Baldwin 	    __func__));
3031c8f4b3cSJohn Baldwin 	return (m->m_epg_trllen - offset);
3041c8f4b3cSJohn Baldwin }
3051c8f4b3cSJohn Baldwin 
3061c8f4b3cSJohn Baldwin static __inline void *
3071c8f4b3cSJohn Baldwin m_epg_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
3081c8f4b3cSJohn Baldwin {
3091c8f4b3cSJohn Baldwin 	u_int i, pglen, pgoff;
3101c8f4b3cSJohn Baldwin 
3111c8f4b3cSJohn Baldwin 	skip += mtod(m, vm_offset_t);
3121c8f4b3cSJohn Baldwin 	if (skip < m->m_epg_hdrlen) {
3131c8f4b3cSJohn Baldwin 		if (len > m->m_epg_hdrlen - skip)
3141c8f4b3cSJohn Baldwin 			return (NULL);
3151c8f4b3cSJohn Baldwin 		return (m->m_epg_hdr + skip);
3161c8f4b3cSJohn Baldwin 	}
3171c8f4b3cSJohn Baldwin 	skip -= m->m_epg_hdrlen;
3181c8f4b3cSJohn Baldwin 	pgoff = m->m_epg_1st_off;
3191c8f4b3cSJohn Baldwin 	for (i = 0; i < m->m_epg_npgs; i++) {
3201c8f4b3cSJohn Baldwin 		pglen = m_epg_pagelen(m, i, pgoff);
3211c8f4b3cSJohn Baldwin 		if (skip < pglen) {
3221c8f4b3cSJohn Baldwin 			if (len > m_epg_pages_extent(m, i, pglen) - skip)
3231c8f4b3cSJohn Baldwin 				return (NULL);
3241c8f4b3cSJohn Baldwin 			return ((void *)PHYS_TO_DMAP(m->m_epg_pa[i] + pgoff +
3251c8f4b3cSJohn Baldwin 			    skip));
3261c8f4b3cSJohn Baldwin 		}
3271c8f4b3cSJohn Baldwin 		skip -= pglen;
3281c8f4b3cSJohn Baldwin 		pgoff = 0;
3291c8f4b3cSJohn Baldwin 	}
3301c8f4b3cSJohn Baldwin 	KASSERT(skip <= m->m_epg_trllen && len <= m->m_epg_trllen - skip,
3311c8f4b3cSJohn Baldwin 	    ("%s: segment beyond trailer", __func__));
3321c8f4b3cSJohn Baldwin 	return (m->m_epg_trail + skip);
3331c8f4b3cSJohn Baldwin }
3341c8f4b3cSJohn Baldwin 
3359c0e3d3aSJohn Baldwin void
3369c0e3d3aSJohn Baldwin crypto_cursor_init(struct crypto_buffer_cursor *cc,
3379c0e3d3aSJohn Baldwin     const struct crypto_buffer *cb)
3389c0e3d3aSJohn Baldwin {
3399c0e3d3aSJohn Baldwin 	memset(cc, 0, sizeof(*cc));
3409c0e3d3aSJohn Baldwin 	cc->cc_type = cb->cb_type;
3419c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
3429c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
3439c0e3d3aSJohn Baldwin 		cc->cc_buf = cb->cb_buf;
3449c0e3d3aSJohn Baldwin 		cc->cc_buf_len = cb->cb_buf_len;
3459c0e3d3aSJohn Baldwin 		break;
3469c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
347*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
3489c0e3d3aSJohn Baldwin 		cc->cc_mbuf = cb->cb_mbuf;
3499c0e3d3aSJohn Baldwin 		break;
350e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
351e6f6d0c9SAlan Somers 		cc->cc_vmpage = cb->cb_vm_page;
352e6f6d0c9SAlan Somers 		cc->cc_buf_len = cb->cb_vm_page_len;
353e6f6d0c9SAlan Somers 		cc->cc_offset = cb->cb_vm_page_offset;
354e6f6d0c9SAlan Somers 		break;
3559c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
3569c0e3d3aSJohn Baldwin 		cc->cc_iov = cb->cb_uio->uio_iov;
3579c0e3d3aSJohn Baldwin 		break;
3589c0e3d3aSJohn Baldwin 	default:
3599c0e3d3aSJohn Baldwin #ifdef INVARIANTS
3609c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cb->cb_type);
3619c0e3d3aSJohn Baldwin #endif
3629c0e3d3aSJohn Baldwin 		break;
3639c0e3d3aSJohn Baldwin 	}
3649c0e3d3aSJohn Baldwin }
3659c0e3d3aSJohn Baldwin 
366e6f6d0c9SAlan Somers SDT_PROBE_DEFINE2(opencrypto, criov, cursor_advance, vmpage, "struct crypto_buffer_cursor*", "size_t");
367e6f6d0c9SAlan Somers 
3689c0e3d3aSJohn Baldwin void
3699c0e3d3aSJohn Baldwin crypto_cursor_advance(struct crypto_buffer_cursor *cc, size_t amount)
3709c0e3d3aSJohn Baldwin {
3719c0e3d3aSJohn Baldwin 	size_t remain;
3729c0e3d3aSJohn Baldwin 
3739c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
3749c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
3759c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= amount);
3769c0e3d3aSJohn Baldwin 		cc->cc_buf += amount;
3779c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= amount;
3789c0e3d3aSJohn Baldwin 		break;
3799c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
3809c0e3d3aSJohn Baldwin 		for (;;) {
3819c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
3829c0e3d3aSJohn Baldwin 			if (amount < remain) {
3839c0e3d3aSJohn Baldwin 				cc->cc_offset += amount;
3849c0e3d3aSJohn Baldwin 				break;
3859c0e3d3aSJohn Baldwin 			}
3869c0e3d3aSJohn Baldwin 			amount -= remain;
3879c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
3889c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
3899c0e3d3aSJohn Baldwin 			if (amount == 0)
3909c0e3d3aSJohn Baldwin 				break;
3919c0e3d3aSJohn Baldwin 		}
3929c0e3d3aSJohn Baldwin 		break;
393*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
394*883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + amount);
395*883a0196SJohn Baldwin 		cc->cc_offset += amount;
396*883a0196SJohn Baldwin 		break;
397e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
398e6f6d0c9SAlan Somers 		for (;;) {
399e6f6d0c9SAlan Somers 			SDT_PROBE2(opencrypto, criov, cursor_advance, vmpage,
400e6f6d0c9SAlan Somers 			    cc, amount);
401e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
402e6f6d0c9SAlan Somers 			if (amount < remain) {
403e6f6d0c9SAlan Somers 				cc->cc_buf_len -= amount;
404e6f6d0c9SAlan Somers 				cc->cc_offset += amount;
405e6f6d0c9SAlan Somers 				break;
406e6f6d0c9SAlan Somers 			}
407e6f6d0c9SAlan Somers 			cc->cc_buf_len -= remain;
408e6f6d0c9SAlan Somers 			amount -= remain;
409e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
410e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
411e6f6d0c9SAlan Somers 			if (amount == 0 || cc->cc_buf_len == 0)
412e6f6d0c9SAlan Somers 				break;
413e6f6d0c9SAlan Somers 		}
414e6f6d0c9SAlan Somers 		break;
4159c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
4169c0e3d3aSJohn Baldwin 		for (;;) {
4179c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
4189c0e3d3aSJohn Baldwin 			if (amount < remain) {
4199c0e3d3aSJohn Baldwin 				cc->cc_offset += amount;
4209c0e3d3aSJohn Baldwin 				break;
4219c0e3d3aSJohn Baldwin 			}
4229c0e3d3aSJohn Baldwin 			amount -= remain;
4239c0e3d3aSJohn Baldwin 			cc->cc_iov++;
4249c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
4259c0e3d3aSJohn Baldwin 			if (amount == 0)
4269c0e3d3aSJohn Baldwin 				break;
4279c0e3d3aSJohn Baldwin 		}
4289c0e3d3aSJohn Baldwin 		break;
4299c0e3d3aSJohn Baldwin 	default:
4309c0e3d3aSJohn Baldwin #ifdef INVARIANTS
4319c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
4329c0e3d3aSJohn Baldwin #endif
4339c0e3d3aSJohn Baldwin 		break;
4349c0e3d3aSJohn Baldwin 	}
4359c0e3d3aSJohn Baldwin }
4369c0e3d3aSJohn Baldwin 
4379c0e3d3aSJohn Baldwin void *
4389c0e3d3aSJohn Baldwin crypto_cursor_segbase(struct crypto_buffer_cursor *cc)
4399c0e3d3aSJohn Baldwin {
4409c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
4419c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
4429c0e3d3aSJohn Baldwin 		return (cc->cc_buf);
4439c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
444*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
4459c0e3d3aSJohn Baldwin 		if (cc->cc_mbuf == NULL)
4469c0e3d3aSJohn Baldwin 			return (NULL);
4471c8f4b3cSJohn Baldwin 		if (cc->cc_mbuf->m_flags & M_EXTPG)
4481c8f4b3cSJohn Baldwin 			return (m_epg_segbase(cc->cc_mbuf, cc->cc_offset));
4499c0e3d3aSJohn Baldwin 		return (mtod(cc->cc_mbuf, char *) + cc->cc_offset);
450e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
451e6f6d0c9SAlan Somers 		return ((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
452e6f6d0c9SAlan Somers 		    *cc->cc_vmpage)) + cc->cc_offset);
4539c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
4549c0e3d3aSJohn Baldwin 		return ((char *)cc->cc_iov->iov_base + cc->cc_offset);
4559c0e3d3aSJohn Baldwin 	default:
4569c0e3d3aSJohn Baldwin #ifdef INVARIANTS
4579c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
4589c0e3d3aSJohn Baldwin #endif
4599c0e3d3aSJohn Baldwin 		return (NULL);
4609c0e3d3aSJohn Baldwin 	}
4619c0e3d3aSJohn Baldwin }
4629c0e3d3aSJohn Baldwin 
4639c0e3d3aSJohn Baldwin size_t
4649c0e3d3aSJohn Baldwin crypto_cursor_seglen(struct crypto_buffer_cursor *cc)
4659c0e3d3aSJohn Baldwin {
4669c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
4679c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
4689c0e3d3aSJohn Baldwin 		return (cc->cc_buf_len);
469e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
470e6f6d0c9SAlan Somers 		return (PAGE_SIZE - cc->cc_offset);
4719c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
472*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
4739c0e3d3aSJohn Baldwin 		if (cc->cc_mbuf == NULL)
4749c0e3d3aSJohn Baldwin 			return (0);
4751c8f4b3cSJohn Baldwin 		if (cc->cc_mbuf->m_flags & M_EXTPG)
4761c8f4b3cSJohn Baldwin 			return (m_epg_seglen(cc->cc_mbuf, cc->cc_offset));
4779c0e3d3aSJohn Baldwin 		return (cc->cc_mbuf->m_len - cc->cc_offset);
4789c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
4799c0e3d3aSJohn Baldwin 		return (cc->cc_iov->iov_len - cc->cc_offset);
4809c0e3d3aSJohn Baldwin 	default:
4819c0e3d3aSJohn Baldwin #ifdef INVARIANTS
4829c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
4839c0e3d3aSJohn Baldwin #endif
4849c0e3d3aSJohn Baldwin 		return (0);
4859c0e3d3aSJohn Baldwin 	}
4869c0e3d3aSJohn Baldwin }
4879c0e3d3aSJohn Baldwin 
4889c0e3d3aSJohn Baldwin void
4899c0e3d3aSJohn Baldwin crypto_cursor_copyback(struct crypto_buffer_cursor *cc, int size,
4909c0e3d3aSJohn Baldwin     const void *vsrc)
4919c0e3d3aSJohn Baldwin {
4929c0e3d3aSJohn Baldwin 	size_t remain, todo;
4939c0e3d3aSJohn Baldwin 	const char *src;
4949c0e3d3aSJohn Baldwin 	char *dst;
4959c0e3d3aSJohn Baldwin 
4969c0e3d3aSJohn Baldwin 	src = vsrc;
4979c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
4989c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
4999c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= size);
5009c0e3d3aSJohn Baldwin 		memcpy(cc->cc_buf, src, size);
5019c0e3d3aSJohn Baldwin 		cc->cc_buf += size;
5029c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= size;
5039c0e3d3aSJohn Baldwin 		break;
5049c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
5059c0e3d3aSJohn Baldwin 		for (;;) {
5061c8f4b3cSJohn Baldwin 			/*
5071c8f4b3cSJohn Baldwin 			 * This uses m_copyback() for individual
5081c8f4b3cSJohn Baldwin 			 * mbufs so that cc_mbuf and cc_offset are
5091c8f4b3cSJohn Baldwin 			 * updated.
5101c8f4b3cSJohn Baldwin 			 */
5119c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
5129c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
5131c8f4b3cSJohn Baldwin 			m_copyback(cc->cc_mbuf, cc->cc_offset, todo, src);
5144542cd93SJohn Baldwin 			src += todo;
5159c0e3d3aSJohn Baldwin 			if (todo < remain) {
5169c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
5179c0e3d3aSJohn Baldwin 				break;
5189c0e3d3aSJohn Baldwin 			}
5199c0e3d3aSJohn Baldwin 			size -= todo;
5209c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
5219c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
5229c0e3d3aSJohn Baldwin 			if (size == 0)
5239c0e3d3aSJohn Baldwin 				break;
5249c0e3d3aSJohn Baldwin 		}
5259c0e3d3aSJohn Baldwin 		break;
526*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
527*883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + size);
528*883a0196SJohn Baldwin 		m_copyback(cc->cc_mbuf, cc->cc_offset, size, src);
529*883a0196SJohn Baldwin 		cc->cc_offset += size;
530*883a0196SJohn Baldwin 		break;
531e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
532e6f6d0c9SAlan Somers 		for (;;) {
533e6f6d0c9SAlan Somers 			dst = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
534e6f6d0c9SAlan Somers 			    *cc->cc_vmpage)) + cc->cc_offset;
535e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
536e6f6d0c9SAlan Somers 			todo = MIN(remain, size);
537e6f6d0c9SAlan Somers 			memcpy(dst, src, todo);
538e6f6d0c9SAlan Somers 			src += todo;
539e6f6d0c9SAlan Somers 			cc->cc_buf_len -= todo;
540e6f6d0c9SAlan Somers 			if (todo < remain) {
541e6f6d0c9SAlan Somers 				cc->cc_offset += todo;
542e6f6d0c9SAlan Somers 				break;
543e6f6d0c9SAlan Somers 			}
544e6f6d0c9SAlan Somers 			size -= todo;
545e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
546e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
547e6f6d0c9SAlan Somers 			if (size == 0)
548e6f6d0c9SAlan Somers 				break;
549e6f6d0c9SAlan Somers 		}
550e6f6d0c9SAlan Somers 		break;
5519c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
5529c0e3d3aSJohn Baldwin 		for (;;) {
5539c0e3d3aSJohn Baldwin 			dst = (char *)cc->cc_iov->iov_base + cc->cc_offset;
5549c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
5559c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
5569c0e3d3aSJohn Baldwin 			memcpy(dst, src, todo);
5574542cd93SJohn Baldwin 			src += todo;
5589c0e3d3aSJohn Baldwin 			if (todo < remain) {
5599c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
5609c0e3d3aSJohn Baldwin 				break;
5619c0e3d3aSJohn Baldwin 			}
5629c0e3d3aSJohn Baldwin 			size -= todo;
5639c0e3d3aSJohn Baldwin 			cc->cc_iov++;
5649c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
5659c0e3d3aSJohn Baldwin 			if (size == 0)
5669c0e3d3aSJohn Baldwin 				break;
5679c0e3d3aSJohn Baldwin 		}
5689c0e3d3aSJohn Baldwin 		break;
5699c0e3d3aSJohn Baldwin 	default:
5709c0e3d3aSJohn Baldwin #ifdef INVARIANTS
5719c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
5729c0e3d3aSJohn Baldwin #endif
5739c0e3d3aSJohn Baldwin 		break;
5749c0e3d3aSJohn Baldwin 	}
5759c0e3d3aSJohn Baldwin }
5769c0e3d3aSJohn Baldwin 
5779c0e3d3aSJohn Baldwin void
5789c0e3d3aSJohn Baldwin crypto_cursor_copydata(struct crypto_buffer_cursor *cc, int size, void *vdst)
5799c0e3d3aSJohn Baldwin {
5809c0e3d3aSJohn Baldwin 	size_t remain, todo;
5819c0e3d3aSJohn Baldwin 	const char *src;
5829c0e3d3aSJohn Baldwin 	char *dst;
5839c0e3d3aSJohn Baldwin 
5849c0e3d3aSJohn Baldwin 	dst = vdst;
5859c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
5869c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
5879c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= size);
5889c0e3d3aSJohn Baldwin 		memcpy(dst, cc->cc_buf, size);
5899c0e3d3aSJohn Baldwin 		cc->cc_buf += size;
5909c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= size;
5919c0e3d3aSJohn Baldwin 		break;
5929c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
5939c0e3d3aSJohn Baldwin 		for (;;) {
5941c8f4b3cSJohn Baldwin 			/*
5951c8f4b3cSJohn Baldwin 			 * This uses m_copydata() for individual
5961c8f4b3cSJohn Baldwin 			 * mbufs so that cc_mbuf and cc_offset are
5971c8f4b3cSJohn Baldwin 			 * updated.
5981c8f4b3cSJohn Baldwin 			 */
5999c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
6009c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
6011c8f4b3cSJohn Baldwin 			m_copydata(cc->cc_mbuf, cc->cc_offset, todo, dst);
6029c0e3d3aSJohn Baldwin 			dst += todo;
6039c0e3d3aSJohn Baldwin 			if (todo < remain) {
6049c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
6059c0e3d3aSJohn Baldwin 				break;
6069c0e3d3aSJohn Baldwin 			}
6079c0e3d3aSJohn Baldwin 			size -= todo;
6089c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
6099c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
6109c0e3d3aSJohn Baldwin 			if (size == 0)
6119c0e3d3aSJohn Baldwin 				break;
6129c0e3d3aSJohn Baldwin 		}
6139c0e3d3aSJohn Baldwin 		break;
614*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
615*883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + size);
616*883a0196SJohn Baldwin 		m_copydata(cc->cc_mbuf, cc->cc_offset, size, dst);
617*883a0196SJohn Baldwin 		cc->cc_offset += size;
618*883a0196SJohn Baldwin 		break;
619e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
620e6f6d0c9SAlan Somers 		for (;;) {
621e6f6d0c9SAlan Somers 			src = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
622e6f6d0c9SAlan Somers 			    *cc->cc_vmpage)) + cc->cc_offset;
623e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
624e6f6d0c9SAlan Somers 			todo = MIN(remain, size);
625e6f6d0c9SAlan Somers 			memcpy(dst, src, todo);
626e6f6d0c9SAlan Somers 			src += todo;
627e6f6d0c9SAlan Somers 			cc->cc_buf_len -= todo;
628e6f6d0c9SAlan Somers 			if (todo < remain) {
629e6f6d0c9SAlan Somers 				cc->cc_offset += todo;
630e6f6d0c9SAlan Somers 				break;
631e6f6d0c9SAlan Somers 			}
632e6f6d0c9SAlan Somers 			size -= todo;
633e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
634e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
635e6f6d0c9SAlan Somers 			if (size == 0)
636e6f6d0c9SAlan Somers 				break;
637e6f6d0c9SAlan Somers 		}
638e6f6d0c9SAlan Somers 		break;
6399c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
6409c0e3d3aSJohn Baldwin 		for (;;) {
6419c0e3d3aSJohn Baldwin 			src = (const char *)cc->cc_iov->iov_base +
6429c0e3d3aSJohn Baldwin 			    cc->cc_offset;
6439c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
6449c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
6459c0e3d3aSJohn Baldwin 			memcpy(dst, src, todo);
6469c0e3d3aSJohn Baldwin 			dst += todo;
6479c0e3d3aSJohn Baldwin 			if (todo < remain) {
6489c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
6499c0e3d3aSJohn Baldwin 				break;
6509c0e3d3aSJohn Baldwin 			}
6519c0e3d3aSJohn Baldwin 			size -= todo;
6529c0e3d3aSJohn Baldwin 			cc->cc_iov++;
6539c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
6549c0e3d3aSJohn Baldwin 			if (size == 0)
6559c0e3d3aSJohn Baldwin 				break;
6569c0e3d3aSJohn Baldwin 		}
6579c0e3d3aSJohn Baldwin 		break;
6589c0e3d3aSJohn Baldwin 	default:
6599c0e3d3aSJohn Baldwin #ifdef INVARIANTS
6609c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
6619c0e3d3aSJohn Baldwin #endif
6629c0e3d3aSJohn Baldwin 		break;
6639c0e3d3aSJohn Baldwin 	}
6649c0e3d3aSJohn Baldwin }
6659c0e3d3aSJohn Baldwin 
6669c0e3d3aSJohn Baldwin /*
6679c0e3d3aSJohn Baldwin  * To avoid advancing 'cursor', make a local copy that gets advanced
6689c0e3d3aSJohn Baldwin  * instead.
6699c0e3d3aSJohn Baldwin  */
6709c0e3d3aSJohn Baldwin void
6719c0e3d3aSJohn Baldwin crypto_cursor_copydata_noadv(struct crypto_buffer_cursor *cc, int size,
6729c0e3d3aSJohn Baldwin     void *vdst)
6739c0e3d3aSJohn Baldwin {
6749c0e3d3aSJohn Baldwin 	struct crypto_buffer_cursor copy;
6759c0e3d3aSJohn Baldwin 
6769c0e3d3aSJohn Baldwin 	copy = *cc;
6779c0e3d3aSJohn Baldwin 	crypto_cursor_copydata(&copy, size, vdst);
6789c0e3d3aSJohn Baldwin }
6799c0e3d3aSJohn Baldwin 
6808f91d4abSPawel Jakub Dawidek /*
6818f91d4abSPawel Jakub Dawidek  * Apply function f to the data in an iovec list starting "off" bytes from
6828f91d4abSPawel Jakub Dawidek  * the beginning, continuing for "len" bytes.
6838f91d4abSPawel Jakub Dawidek  */
6849c0e3d3aSJohn Baldwin static int
6859b6b2f86SJohn Baldwin cuio_apply(struct uio *uio, int off, int len,
6869b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
6878f91d4abSPawel Jakub Dawidek {
6888f91d4abSPawel Jakub Dawidek 	struct iovec *iov = uio->uio_iov;
6898f91d4abSPawel Jakub Dawidek 	int iol = uio->uio_iovcnt;
6908f91d4abSPawel Jakub Dawidek 	unsigned count;
6918f91d4abSPawel Jakub Dawidek 	int rval;
6928f91d4abSPawel Jakub Dawidek 
6938f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
6948f91d4abSPawel Jakub Dawidek 	while (len > 0) {
6958f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
6968f91d4abSPawel Jakub Dawidek 		count = min(iov->iov_len - off, len);
6978f91d4abSPawel Jakub Dawidek 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
6988f91d4abSPawel Jakub Dawidek 		if (rval)
6998f91d4abSPawel Jakub Dawidek 			return (rval);
7008f91d4abSPawel Jakub Dawidek 		len -= count;
7018f91d4abSPawel Jakub Dawidek 		off = 0;
7028f91d4abSPawel Jakub Dawidek 		iol--;
7038f91d4abSPawel Jakub Dawidek 		iov++;
7048f91d4abSPawel Jakub Dawidek 	}
7058f91d4abSPawel Jakub Dawidek 	return (0);
7068f91d4abSPawel Jakub Dawidek }
70711d2e1e8SPawel Jakub Dawidek 
70811d2e1e8SPawel Jakub Dawidek void
709c0341432SJohn Baldwin crypto_copyback(struct cryptop *crp, int off, int size, const void *src)
71011d2e1e8SPawel Jakub Dawidek {
7119c0e3d3aSJohn Baldwin 	struct crypto_buffer *cb;
71211d2e1e8SPawel Jakub Dawidek 
7139c0e3d3aSJohn Baldwin 	if (crp->crp_obuf.cb_type != CRYPTO_BUF_NONE)
7149c0e3d3aSJohn Baldwin 		cb = &crp->crp_obuf;
7159c0e3d3aSJohn Baldwin 	else
7169c0e3d3aSJohn Baldwin 		cb = &crp->crp_buf;
7179c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
718c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
719*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
7209c0e3d3aSJohn Baldwin 		m_copyback(cb->cb_mbuf, off, size, src);
721c0341432SJohn Baldwin 		break;
722e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
723e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
724e6f6d0c9SAlan Somers 		MPASS(size <= cb->cb_vm_page_len);
725e6f6d0c9SAlan Somers 		MPASS(size + off <=
726e6f6d0c9SAlan Somers 		    cb->cb_vm_page_len + cb->cb_vm_page_offset);
727e6f6d0c9SAlan Somers 		cvm_page_copyback(cb->cb_vm_page,
728e6f6d0c9SAlan Somers 		    off + cb->cb_vm_page_offset, size, src);
729e6f6d0c9SAlan Somers 		break;
730e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
731c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
7329c0e3d3aSJohn Baldwin 		cuio_copyback(cb->cb_uio, off, size, src);
733c0341432SJohn Baldwin 		break;
734c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
7359c0e3d3aSJohn Baldwin 		MPASS(off + size <= cb->cb_buf_len);
7369c0e3d3aSJohn Baldwin 		bcopy(src, cb->cb_buf + off, size);
737c0341432SJohn Baldwin 		break;
738c0341432SJohn Baldwin 	default:
7399c0e3d3aSJohn Baldwin #ifdef INVARIANTS
7409c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", cb->cb_type);
7419c0e3d3aSJohn Baldwin #endif
7429c0e3d3aSJohn Baldwin 		break;
743c0341432SJohn Baldwin 	}
74411d2e1e8SPawel Jakub Dawidek }
74511d2e1e8SPawel Jakub Dawidek 
74611d2e1e8SPawel Jakub Dawidek void
747c0341432SJohn Baldwin crypto_copydata(struct cryptop *crp, int off, int size, void *dst)
74811d2e1e8SPawel Jakub Dawidek {
74911d2e1e8SPawel Jakub Dawidek 
7509c0e3d3aSJohn Baldwin 	switch (crp->crp_buf.cb_type) {
751c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
752*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
7539c0e3d3aSJohn Baldwin 		m_copydata(crp->crp_buf.cb_mbuf, off, size, dst);
754c0341432SJohn Baldwin 		break;
755e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
756e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
757e6f6d0c9SAlan Somers 		MPASS(size <= crp->crp_buf.cb_vm_page_len);
758e6f6d0c9SAlan Somers 		MPASS(size + off <= crp->crp_buf.cb_vm_page_len +
759e6f6d0c9SAlan Somers 		    crp->crp_buf.cb_vm_page_offset);
760e6f6d0c9SAlan Somers 		cvm_page_copydata(crp->crp_buf.cb_vm_page,
761e6f6d0c9SAlan Somers 		    off + crp->crp_buf.cb_vm_page_offset, size, dst);
762e6f6d0c9SAlan Somers 		break;
763e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
764c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
7659c0e3d3aSJohn Baldwin 		cuio_copydata(crp->crp_buf.cb_uio, off, size, dst);
766c0341432SJohn Baldwin 		break;
767c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
7689c0e3d3aSJohn Baldwin 		MPASS(off + size <= crp->crp_buf.cb_buf_len);
7699c0e3d3aSJohn Baldwin 		bcopy(crp->crp_buf.cb_buf + off, dst, size);
770c0341432SJohn Baldwin 		break;
771c0341432SJohn Baldwin 	default:
7729c0e3d3aSJohn Baldwin #ifdef INVARIANTS
7739c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", crp->crp_buf.cb_type);
7749c0e3d3aSJohn Baldwin #endif
7759c0e3d3aSJohn Baldwin 		break;
776c0341432SJohn Baldwin 	}
77711d2e1e8SPawel Jakub Dawidek }
77811d2e1e8SPawel Jakub Dawidek 
77911d2e1e8SPawel Jakub Dawidek int
7809c0e3d3aSJohn Baldwin crypto_apply_buf(struct crypto_buffer *cb, int off, int len,
7819b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
7829c0e3d3aSJohn Baldwin {
7839c0e3d3aSJohn Baldwin 	int error;
7849c0e3d3aSJohn Baldwin 
7859c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
7869c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
787*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
7889b6b2f86SJohn Baldwin 		error = m_apply(cb->cb_mbuf, off, len,
7899b6b2f86SJohn Baldwin 		    (int (*)(void *, void *, u_int))f, arg);
7909c0e3d3aSJohn Baldwin 		break;
7919c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
7929c0e3d3aSJohn Baldwin 		error = cuio_apply(cb->cb_uio, off, len, f, arg);
7939c0e3d3aSJohn Baldwin 		break;
794e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
795e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
796e6f6d0c9SAlan Somers 		error = cvm_page_apply(cb->cb_vm_page,
797e6f6d0c9SAlan Somers 		    off + cb->cb_vm_page_offset, len, f, arg);
798e6f6d0c9SAlan Somers 		break;
799e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
8009c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
8019c0e3d3aSJohn Baldwin 		MPASS(off + len <= cb->cb_buf_len);
8029c0e3d3aSJohn Baldwin 		error = (*f)(arg, cb->cb_buf + off, len);
8039c0e3d3aSJohn Baldwin 		break;
8049c0e3d3aSJohn Baldwin 	default:
8059c0e3d3aSJohn Baldwin #ifdef INVARIANTS
8069c0e3d3aSJohn Baldwin 		panic("invalid crypto buf type %d", cb->cb_type);
8079c0e3d3aSJohn Baldwin #endif
8089c0e3d3aSJohn Baldwin 		error = 0;
8099c0e3d3aSJohn Baldwin 		break;
8109c0e3d3aSJohn Baldwin 	}
8119c0e3d3aSJohn Baldwin 	return (error);
8129c0e3d3aSJohn Baldwin }
8139c0e3d3aSJohn Baldwin 
8149c0e3d3aSJohn Baldwin int
815c0341432SJohn Baldwin crypto_apply(struct cryptop *crp, int off, int len,
8169b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
81711d2e1e8SPawel Jakub Dawidek {
8189c0e3d3aSJohn Baldwin 	return (crypto_apply_buf(&crp->crp_buf, off, len, f, arg));
81908fca7a5SJohn-Mark Gurney }
820ff2038a9SMatt Macy 
821ff2038a9SMatt Macy static inline void *
822ff2038a9SMatt Macy m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
823ff2038a9SMatt Macy {
824ff2038a9SMatt Macy 	int rel_off;
825ff2038a9SMatt Macy 
826ff2038a9SMatt Macy 	MPASS(skip <= INT_MAX);
827ff2038a9SMatt Macy 
828ff2038a9SMatt Macy 	m = m_getptr(m, (int)skip, &rel_off);
829ff2038a9SMatt Macy 	if (m == NULL)
830ff2038a9SMatt Macy 		return (NULL);
831ff2038a9SMatt Macy 
832ff2038a9SMatt Macy 	MPASS(rel_off >= 0);
833ff2038a9SMatt Macy 	skip = rel_off;
834ff2038a9SMatt Macy 	if (skip + len > m->m_len)
835ff2038a9SMatt Macy 		return (NULL);
836ff2038a9SMatt Macy 
8371c8f4b3cSJohn Baldwin 	if (m->m_flags & M_EXTPG)
8381c8f4b3cSJohn Baldwin 		return (m_epg_contiguous_subsegment(m, skip, len));
839ff2038a9SMatt Macy 	return (mtod(m, char*) + skip);
840ff2038a9SMatt Macy }
841ff2038a9SMatt Macy 
842ff2038a9SMatt Macy static inline void *
843ff2038a9SMatt Macy cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
844ff2038a9SMatt Macy {
845ff2038a9SMatt Macy 	int rel_off, idx;
846ff2038a9SMatt Macy 
847ff2038a9SMatt Macy 	MPASS(skip <= INT_MAX);
848ff2038a9SMatt Macy 	idx = cuio_getptr(uio, (int)skip, &rel_off);
849ff2038a9SMatt Macy 	if (idx < 0)
850ff2038a9SMatt Macy 		return (NULL);
851ff2038a9SMatt Macy 
852ff2038a9SMatt Macy 	MPASS(rel_off >= 0);
853ff2038a9SMatt Macy 	skip = rel_off;
854ff2038a9SMatt Macy 	if (skip + len > uio->uio_iov[idx].iov_len)
855ff2038a9SMatt Macy 		return (NULL);
856ff2038a9SMatt Macy 	return ((char *)uio->uio_iov[idx].iov_base + skip);
857ff2038a9SMatt Macy }
858ff2038a9SMatt Macy 
859ff2038a9SMatt Macy void *
8609c0e3d3aSJohn Baldwin crypto_buffer_contiguous_subsegment(struct crypto_buffer *cb, size_t skip,
8619c0e3d3aSJohn Baldwin     size_t len)
862ff2038a9SMatt Macy {
863ff2038a9SMatt Macy 
8649c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
865c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
866*883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
8679c0e3d3aSJohn Baldwin 		return (m_contiguous_subsegment(cb->cb_mbuf, skip, len));
868c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
8699c0e3d3aSJohn Baldwin 		return (cuio_contiguous_segment(cb->cb_uio, skip, len));
870e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
871e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
872e6f6d0c9SAlan Somers 		MPASS(skip + len <= cb->cb_vm_page_len);
873e6f6d0c9SAlan Somers 		return (cvm_page_contiguous_segment(cb->cb_vm_page,
874e6f6d0c9SAlan Somers 		    skip + cb->cb_vm_page_offset, len));
875e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
876c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
8779c0e3d3aSJohn Baldwin 		MPASS(skip + len <= cb->cb_buf_len);
8789c0e3d3aSJohn Baldwin 		return (cb->cb_buf + skip);
879c0341432SJohn Baldwin 	default:
8809c0e3d3aSJohn Baldwin #ifdef INVARIANTS
8819c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", cb->cb_type);
8829c0e3d3aSJohn Baldwin #endif
8839c0e3d3aSJohn Baldwin 		return (NULL);
884c0341432SJohn Baldwin 	}
885c0341432SJohn Baldwin }
8869c0e3d3aSJohn Baldwin 
8879c0e3d3aSJohn Baldwin void *
8889c0e3d3aSJohn Baldwin crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len)
8899c0e3d3aSJohn Baldwin {
8909c0e3d3aSJohn Baldwin 	return (crypto_buffer_contiguous_subsegment(&crp->crp_buf, skip, len));
8919c0e3d3aSJohn Baldwin }
892