xref: /freebsd/sys/opencrypto/criov.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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 
30091d81d1SSam Leffler #include <sys/param.h>
31091d81d1SSam Leffler #include <sys/systm.h>
32091d81d1SSam Leffler #include <sys/proc.h>
33091d81d1SSam Leffler #include <sys/errno.h>
34091d81d1SSam Leffler #include <sys/malloc.h>
35091d81d1SSam Leffler #include <sys/kernel.h>
3611d2e1e8SPawel Jakub Dawidek #include <sys/mbuf.h>
37091d81d1SSam Leffler #include <sys/uio.h>
38ff2038a9SMatt Macy #include <sys/limits.h>
39ff2038a9SMatt Macy #include <sys/lock.h>
40e6f6d0c9SAlan Somers #include <sys/sdt.h>
41e6f6d0c9SAlan Somers 
42e6f6d0c9SAlan Somers #include <machine/vmparam.h>
43e6f6d0c9SAlan Somers 
44e6f6d0c9SAlan Somers #include <vm/vm.h>
45e6f6d0c9SAlan Somers #include <vm/vm_page.h>
46e6f6d0c9SAlan Somers #include <vm/pmap.h>
47091d81d1SSam Leffler 
48091d81d1SSam Leffler #include <opencrypto/cryptodev.h>
49091d81d1SSam Leffler 
50e6f6d0c9SAlan Somers SDT_PROVIDER_DECLARE(opencrypto);
51e6f6d0c9SAlan Somers 
528f91d4abSPawel Jakub Dawidek /*
53e6f6d0c9SAlan Somers  * These macros are only for avoiding code duplication, as we need to skip
54e6f6d0c9SAlan Somers  * given number of bytes in the same way in several functions below.
558f91d4abSPawel Jakub Dawidek  */
568f91d4abSPawel Jakub Dawidek #define	CUIO_SKIP()	do {						\
578f91d4abSPawel Jakub Dawidek 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
588f91d4abSPawel Jakub Dawidek 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
598f91d4abSPawel Jakub Dawidek 	while (off > 0) {						\
608f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
618f91d4abSPawel Jakub Dawidek 		if (off < iov->iov_len)					\
628f91d4abSPawel Jakub Dawidek 			break;						\
638f91d4abSPawel Jakub Dawidek 		off -= iov->iov_len;					\
648f91d4abSPawel Jakub Dawidek 		iol--;							\
658f91d4abSPawel Jakub Dawidek 		iov++;							\
668f91d4abSPawel Jakub Dawidek 	}								\
678f91d4abSPawel Jakub Dawidek } while (0)
688f91d4abSPawel Jakub Dawidek 
69e6f6d0c9SAlan Somers #define CVM_PAGE_SKIP()	do {					\
70e6f6d0c9SAlan Somers 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
71e6f6d0c9SAlan Somers 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
72e6f6d0c9SAlan Somers 	while (off > 0) {						\
73e6f6d0c9SAlan Somers 		if (off < PAGE_SIZE)					\
74e6f6d0c9SAlan Somers 			break;						\
75e6f6d0c9SAlan Somers 		processed += PAGE_SIZE - off;				\
76e6f6d0c9SAlan Somers 		off -= PAGE_SIZE - off;					\
77e6f6d0c9SAlan Somers 		pages++;						\
78e6f6d0c9SAlan Somers 	}								\
79e6f6d0c9SAlan Somers } while (0)
80e6f6d0c9SAlan Somers 
819c0e3d3aSJohn Baldwin static void
cuio_copydata(struct uio * uio,int off,int len,caddr_t cp)82091d81d1SSam Leffler cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
83091d81d1SSam Leffler {
84091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
853471fcf3SEd Maste 	int iol __diagused = uio->uio_iovcnt;
86091d81d1SSam Leffler 	unsigned count;
87091d81d1SSam Leffler 
888f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
89091d81d1SSam Leffler 	while (len > 0) {
908f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
91091d81d1SSam Leffler 		count = min(iov->iov_len - off, len);
92091d81d1SSam Leffler 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
93091d81d1SSam Leffler 		len -= count;
94091d81d1SSam Leffler 		cp += count;
95091d81d1SSam Leffler 		off = 0;
96091d81d1SSam Leffler 		iol--;
97091d81d1SSam Leffler 		iov++;
98091d81d1SSam Leffler 	}
99091d81d1SSam Leffler }
100091d81d1SSam Leffler 
1019c0e3d3aSJohn Baldwin static void
cuio_copyback(struct uio * uio,int off,int len,c_caddr_t cp)1027dd10fdeSJohn Baldwin cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp)
103091d81d1SSam Leffler {
104091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
1053471fcf3SEd Maste 	int iol __diagused = uio->uio_iovcnt;
106091d81d1SSam Leffler 	unsigned count;
107091d81d1SSam Leffler 
1088f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
109091d81d1SSam Leffler 	while (len > 0) {
1108f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
111091d81d1SSam Leffler 		count = min(iov->iov_len - off, len);
112091d81d1SSam Leffler 		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
113091d81d1SSam Leffler 		len -= count;
114091d81d1SSam Leffler 		cp += count;
115091d81d1SSam Leffler 		off = 0;
116091d81d1SSam Leffler 		iol--;
117091d81d1SSam Leffler 		iov++;
118091d81d1SSam Leffler 	}
119091d81d1SSam Leffler }
120091d81d1SSam Leffler 
121091d81d1SSam Leffler /*
12208fca7a5SJohn-Mark Gurney  * Return the index and offset of location in iovec list.
123091d81d1SSam Leffler  */
1249c0e3d3aSJohn Baldwin static int
cuio_getptr(struct uio * uio,int loc,int * off)125091d81d1SSam Leffler cuio_getptr(struct uio *uio, int loc, int *off)
126091d81d1SSam Leffler {
12708fca7a5SJohn-Mark Gurney 	int ind, len;
128091d81d1SSam Leffler 
12908fca7a5SJohn-Mark Gurney 	ind = 0;
13008fca7a5SJohn-Mark Gurney 	while (loc >= 0 && ind < uio->uio_iovcnt) {
13108fca7a5SJohn-Mark Gurney 		len = uio->uio_iov[ind].iov_len;
13208fca7a5SJohn-Mark Gurney 		if (len > loc) {
133091d81d1SSam Leffler 	    		*off = loc;
13408fca7a5SJohn-Mark Gurney 	    		return (ind);
13508fca7a5SJohn-Mark Gurney 		}
13608fca7a5SJohn-Mark Gurney 		loc -= len;
13708fca7a5SJohn-Mark Gurney 		ind++;
138091d81d1SSam Leffler 	}
139091d81d1SSam Leffler 
14008fca7a5SJohn-Mark Gurney 	if (ind > 0 && loc == 0) {
14108fca7a5SJohn-Mark Gurney 		ind--;
14208fca7a5SJohn-Mark Gurney 		*off = uio->uio_iov[ind].iov_len;
14308fca7a5SJohn-Mark Gurney 		return (ind);
144091d81d1SSam Leffler 	}
145091d81d1SSam Leffler 
14608fca7a5SJohn-Mark Gurney 	return (-1);
147091d81d1SSam Leffler }
1488f91d4abSPawel Jakub Dawidek 
149e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
150e6f6d0c9SAlan Somers /*
151e6f6d0c9SAlan Somers  * Apply function f to the data in a vm_page_t list starting "off" bytes from
152e6f6d0c9SAlan Somers  * the beginning, continuing for "len" bytes.
153e6f6d0c9SAlan Somers  */
154e6f6d0c9SAlan Somers static int
cvm_page_apply(vm_page_t * pages,int off,int len,int (* f)(void *,const void *,u_int),void * arg)155e6f6d0c9SAlan Somers cvm_page_apply(vm_page_t *pages, int off, int len,
156e6f6d0c9SAlan Somers     int (*f)(void *, const void *, u_int), void *arg)
157e6f6d0c9SAlan Somers {
1584d54d1b7SScott Long 	int processed __unused;
159e6f6d0c9SAlan Somers 	unsigned count;
160e6f6d0c9SAlan Somers 	int rval;
161e6f6d0c9SAlan Somers 
1624d54d1b7SScott Long 	processed = 0;
163e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
164e6f6d0c9SAlan Somers 	while (len > 0) {
165e6f6d0c9SAlan Somers 		char *kaddr = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages));
166e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
167e6f6d0c9SAlan Somers 		rval = (*f)(arg, kaddr + off, count);
168e6f6d0c9SAlan Somers 		if (rval)
169e6f6d0c9SAlan Somers 			return (rval);
170e6f6d0c9SAlan Somers 		len -= count;
1714d54d1b7SScott Long 		processed += count;
172e6f6d0c9SAlan Somers 		off = 0;
173e6f6d0c9SAlan Somers 		pages++;
174e6f6d0c9SAlan Somers 	}
175e6f6d0c9SAlan Somers 	return (0);
176e6f6d0c9SAlan Somers }
177e6f6d0c9SAlan Somers 
178e6f6d0c9SAlan Somers static inline void *
cvm_page_contiguous_segment(vm_page_t * pages,size_t skip,int len)179e6f6d0c9SAlan Somers cvm_page_contiguous_segment(vm_page_t *pages, size_t skip, int len)
180e6f6d0c9SAlan Somers {
181e6f6d0c9SAlan Somers 	if ((skip + len - 1) / PAGE_SIZE > skip / PAGE_SIZE)
182e6f6d0c9SAlan Somers 		return (NULL);
183e6f6d0c9SAlan Somers 
184e6f6d0c9SAlan Somers 	pages += (skip / PAGE_SIZE);
185e6f6d0c9SAlan Somers 	skip -= rounddown(skip, PAGE_SIZE);
186e6f6d0c9SAlan Somers 	return (((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages))) + skip);
187e6f6d0c9SAlan Somers }
188e6f6d0c9SAlan Somers 
189e6f6d0c9SAlan Somers /*
190e6f6d0c9SAlan Somers  * Copy len bytes of data from the vm_page_t array, skipping the first off
191e6f6d0c9SAlan Somers  * bytes, into the pointer cp.  Return the number of bytes skipped and copied.
192e6f6d0c9SAlan Somers  * Does not verify the length of the array.
193e6f6d0c9SAlan Somers  */
194e6f6d0c9SAlan Somers static int
cvm_page_copyback(vm_page_t * pages,int off,int len,c_caddr_t cp)195e6f6d0c9SAlan Somers cvm_page_copyback(vm_page_t *pages, int off, int len, c_caddr_t cp)
196e6f6d0c9SAlan Somers {
197e6f6d0c9SAlan Somers 	int processed = 0;
198e6f6d0c9SAlan Somers 	unsigned count;
199e6f6d0c9SAlan Somers 
200e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
201e6f6d0c9SAlan Somers 	while (len > 0) {
202e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
203e6f6d0c9SAlan Somers 		bcopy(cp, (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off,
204e6f6d0c9SAlan Somers 		    count);
205e6f6d0c9SAlan Somers 		len -= count;
206e6f6d0c9SAlan Somers 		cp += count;
207e6f6d0c9SAlan Somers 		processed += count;
208e6f6d0c9SAlan Somers 		off = 0;
209e6f6d0c9SAlan Somers 		pages++;
210e6f6d0c9SAlan Somers 	}
211e6f6d0c9SAlan Somers 	return (processed);
212e6f6d0c9SAlan Somers }
213e6f6d0c9SAlan Somers 
214e6f6d0c9SAlan Somers /*
215e6f6d0c9SAlan Somers  * Copy len bytes of data from the pointer cp into the vm_page_t array,
216e6f6d0c9SAlan Somers  * skipping the first off bytes, Return the number of bytes skipped and copied.
217e6f6d0c9SAlan Somers  * Does not verify the length of the array.
218e6f6d0c9SAlan Somers  */
219e6f6d0c9SAlan Somers static int
cvm_page_copydata(vm_page_t * pages,int off,int len,caddr_t cp)220e6f6d0c9SAlan Somers cvm_page_copydata(vm_page_t *pages, int off, int len, caddr_t cp)
221e6f6d0c9SAlan Somers {
222e6f6d0c9SAlan Somers 	int processed = 0;
223e6f6d0c9SAlan Somers 	unsigned count;
224e6f6d0c9SAlan Somers 
225e6f6d0c9SAlan Somers 	CVM_PAGE_SKIP();
226e6f6d0c9SAlan Somers 	while (len > 0) {
227e6f6d0c9SAlan Somers 		count = min(PAGE_SIZE - off, len);
228e6f6d0c9SAlan Somers 		bcopy(((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(*pages)) + off), cp,
229e6f6d0c9SAlan Somers 		    count);
230e6f6d0c9SAlan Somers 		len -= count;
231e6f6d0c9SAlan Somers 		cp += count;
232e6f6d0c9SAlan Somers 		processed += count;
233e6f6d0c9SAlan Somers 		off = 0;
234e6f6d0c9SAlan Somers 		pages++;
235e6f6d0c9SAlan Somers 	}
236e6f6d0c9SAlan Somers 	return processed;
237e6f6d0c9SAlan Somers }
238e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
239e6f6d0c9SAlan Somers 
2401c8f4b3cSJohn Baldwin /*
2411c8f4b3cSJohn Baldwin  * Given a starting page in an m_epg, determine the length of the
2421c8f4b3cSJohn Baldwin  * current physically contiguous segment.
2431c8f4b3cSJohn Baldwin  */
2441c8f4b3cSJohn Baldwin static __inline size_t
m_epg_pages_extent(struct mbuf * m,int idx,u_int pglen)2451c8f4b3cSJohn Baldwin m_epg_pages_extent(struct mbuf *m, int idx, u_int pglen)
2461c8f4b3cSJohn Baldwin {
2471c8f4b3cSJohn Baldwin 	size_t len;
2481c8f4b3cSJohn Baldwin 	u_int i;
2491c8f4b3cSJohn Baldwin 
2501c8f4b3cSJohn Baldwin 	len = pglen;
2511c8f4b3cSJohn Baldwin 	for (i = idx + 1; i < m->m_epg_npgs; i++) {
2521c8f4b3cSJohn Baldwin 		if (m->m_epg_pa[i - 1] + PAGE_SIZE != m->m_epg_pa[i])
2531c8f4b3cSJohn Baldwin 			break;
2541c8f4b3cSJohn Baldwin 		len += m_epg_pagelen(m, i, 0);
2551c8f4b3cSJohn Baldwin 	}
2561c8f4b3cSJohn Baldwin 	return (len);
2571c8f4b3cSJohn Baldwin }
2581c8f4b3cSJohn Baldwin 
259beb817edSJohn Baldwin static void *
m_epg_segment(struct mbuf * m,size_t offset,size_t * len)260beb817edSJohn Baldwin m_epg_segment(struct mbuf *m, size_t offset, size_t *len)
2611c8f4b3cSJohn Baldwin {
2621c8f4b3cSJohn Baldwin 	u_int i, pglen, pgoff;
2631c8f4b3cSJohn Baldwin 
2641c8f4b3cSJohn Baldwin 	offset += mtod(m, vm_offset_t);
265beb817edSJohn Baldwin 	if (offset < m->m_epg_hdrlen) {
266beb817edSJohn Baldwin 		*len = m->m_epg_hdrlen - offset;
2671c8f4b3cSJohn Baldwin 		return (m->m_epg_hdr + offset);
268beb817edSJohn Baldwin 	}
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);
273beb817edSJohn Baldwin 		if (offset < pglen) {
274beb817edSJohn Baldwin 			*len = m_epg_pages_extent(m, i, pglen) - offset;
2751c8f4b3cSJohn Baldwin 			return ((void *)PHYS_TO_DMAP(m->m_epg_pa[i] + pgoff +
2761c8f4b3cSJohn Baldwin 			    offset));
277beb817edSJohn Baldwin 		}
2781c8f4b3cSJohn Baldwin 		offset -= pglen;
2791c8f4b3cSJohn Baldwin 		pgoff = 0;
2801c8f4b3cSJohn Baldwin 	}
2811c8f4b3cSJohn Baldwin 	KASSERT(offset <= m->m_epg_trllen, ("%s: offset beyond trailer",
2821c8f4b3cSJohn Baldwin 	    __func__));
283beb817edSJohn Baldwin 	*len = m->m_epg_trllen - offset;
2841c8f4b3cSJohn Baldwin 	return (m->m_epg_trail + offset);
2851c8f4b3cSJohn Baldwin }
2861c8f4b3cSJohn Baldwin 
2871c8f4b3cSJohn Baldwin static __inline void *
m_epg_contiguous_subsegment(struct mbuf * m,size_t skip,size_t len)2881c8f4b3cSJohn Baldwin m_epg_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
2891c8f4b3cSJohn Baldwin {
290beb817edSJohn Baldwin 	void *base;
291beb817edSJohn Baldwin 	size_t seglen;
2921c8f4b3cSJohn Baldwin 
293beb817edSJohn Baldwin 	base = m_epg_segment(m, skip, &seglen);
294beb817edSJohn Baldwin 	if (len > seglen)
2951c8f4b3cSJohn Baldwin 		return (NULL);
296beb817edSJohn Baldwin 	return (base);
2971c8f4b3cSJohn Baldwin }
2981c8f4b3cSJohn Baldwin 
2999c0e3d3aSJohn Baldwin void
crypto_cursor_init(struct crypto_buffer_cursor * cc,const struct crypto_buffer * cb)3009c0e3d3aSJohn Baldwin crypto_cursor_init(struct crypto_buffer_cursor *cc,
3019c0e3d3aSJohn Baldwin     const struct crypto_buffer *cb)
3029c0e3d3aSJohn Baldwin {
3039c0e3d3aSJohn Baldwin 	memset(cc, 0, sizeof(*cc));
3049c0e3d3aSJohn Baldwin 	cc->cc_type = cb->cb_type;
3059c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
3069c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
3079c0e3d3aSJohn Baldwin 		cc->cc_buf = cb->cb_buf;
3089c0e3d3aSJohn Baldwin 		cc->cc_buf_len = cb->cb_buf_len;
3099c0e3d3aSJohn Baldwin 		break;
3109c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
311883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
3129c0e3d3aSJohn Baldwin 		cc->cc_mbuf = cb->cb_mbuf;
3139c0e3d3aSJohn Baldwin 		break;
314e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
315e6f6d0c9SAlan Somers 		cc->cc_vmpage = cb->cb_vm_page;
316e6f6d0c9SAlan Somers 		cc->cc_buf_len = cb->cb_vm_page_len;
317e6f6d0c9SAlan Somers 		cc->cc_offset = cb->cb_vm_page_offset;
318e6f6d0c9SAlan Somers 		break;
3199c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
3209c0e3d3aSJohn Baldwin 		cc->cc_iov = cb->cb_uio->uio_iov;
321718d4a1dSMark Johnston 		cc->cc_buf_len = cb->cb_uio->uio_resid;
3229c0e3d3aSJohn Baldwin 		break;
3239c0e3d3aSJohn Baldwin 	default:
3249c0e3d3aSJohn Baldwin #ifdef INVARIANTS
3259c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cb->cb_type);
3269c0e3d3aSJohn Baldwin #endif
3279c0e3d3aSJohn Baldwin 		break;
3289c0e3d3aSJohn Baldwin 	}
3299c0e3d3aSJohn Baldwin }
3309c0e3d3aSJohn Baldwin 
331e6f6d0c9SAlan Somers SDT_PROBE_DEFINE2(opencrypto, criov, cursor_advance, vmpage, "struct crypto_buffer_cursor*", "size_t");
332e6f6d0c9SAlan Somers 
3339c0e3d3aSJohn Baldwin void
crypto_cursor_advance(struct crypto_buffer_cursor * cc,size_t amount)3349c0e3d3aSJohn Baldwin crypto_cursor_advance(struct crypto_buffer_cursor *cc, size_t amount)
3359c0e3d3aSJohn Baldwin {
3369c0e3d3aSJohn Baldwin 	size_t remain;
3379c0e3d3aSJohn Baldwin 
3389c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
3399c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
3409c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= amount);
3419c0e3d3aSJohn Baldwin 		cc->cc_buf += amount;
3429c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= amount;
3439c0e3d3aSJohn Baldwin 		break;
3449c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
3459c0e3d3aSJohn Baldwin 		for (;;) {
3469c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
3479c0e3d3aSJohn Baldwin 			if (amount < remain) {
3489c0e3d3aSJohn Baldwin 				cc->cc_offset += amount;
3499c0e3d3aSJohn Baldwin 				break;
3509c0e3d3aSJohn Baldwin 			}
3519c0e3d3aSJohn Baldwin 			amount -= remain;
3529c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
3539c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
3549c0e3d3aSJohn Baldwin 			if (amount == 0)
3559c0e3d3aSJohn Baldwin 				break;
3569c0e3d3aSJohn Baldwin 		}
3579c0e3d3aSJohn Baldwin 		break;
358883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
359883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + amount);
360883a0196SJohn Baldwin 		cc->cc_offset += amount;
361883a0196SJohn Baldwin 		break;
362e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
363e6f6d0c9SAlan Somers 		for (;;) {
364e6f6d0c9SAlan Somers 			SDT_PROBE2(opencrypto, criov, cursor_advance, vmpage,
365e6f6d0c9SAlan Somers 			    cc, amount);
366e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
367e6f6d0c9SAlan Somers 			if (amount < remain) {
368e6f6d0c9SAlan Somers 				cc->cc_buf_len -= amount;
369e6f6d0c9SAlan Somers 				cc->cc_offset += amount;
370e6f6d0c9SAlan Somers 				break;
371e6f6d0c9SAlan Somers 			}
372e6f6d0c9SAlan Somers 			cc->cc_buf_len -= remain;
373e6f6d0c9SAlan Somers 			amount -= remain;
374e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
375e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
376e6f6d0c9SAlan Somers 			if (amount == 0 || cc->cc_buf_len == 0)
377e6f6d0c9SAlan Somers 				break;
378e6f6d0c9SAlan Somers 		}
379e6f6d0c9SAlan Somers 		break;
3809c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
3819c0e3d3aSJohn Baldwin 		for (;;) {
3829c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
3839c0e3d3aSJohn Baldwin 			if (amount < remain) {
3849c0e3d3aSJohn Baldwin 				cc->cc_offset += amount;
3859c0e3d3aSJohn Baldwin 				break;
3869c0e3d3aSJohn Baldwin 			}
387718d4a1dSMark Johnston 			cc->cc_buf_len -= remain;
3889c0e3d3aSJohn Baldwin 			amount -= remain;
3899c0e3d3aSJohn Baldwin 			cc->cc_iov++;
3909c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
3919c0e3d3aSJohn Baldwin 			if (amount == 0)
3929c0e3d3aSJohn Baldwin 				break;
3939c0e3d3aSJohn Baldwin 		}
3949c0e3d3aSJohn Baldwin 		break;
3959c0e3d3aSJohn Baldwin 	default:
3969c0e3d3aSJohn Baldwin #ifdef INVARIANTS
3979c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
3989c0e3d3aSJohn Baldwin #endif
3999c0e3d3aSJohn Baldwin 		break;
4009c0e3d3aSJohn Baldwin 	}
4019c0e3d3aSJohn Baldwin }
4029c0e3d3aSJohn Baldwin 
4039c0e3d3aSJohn Baldwin void *
crypto_cursor_segment(struct crypto_buffer_cursor * cc,size_t * len)404beb817edSJohn Baldwin crypto_cursor_segment(struct crypto_buffer_cursor *cc, size_t *len)
4059c0e3d3aSJohn Baldwin {
4069c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
4079c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
408718d4a1dSMark Johnston 	case CRYPTO_BUF_UIO:
409718d4a1dSMark Johnston 	case CRYPTO_BUF_VMPAGE:
410718d4a1dSMark Johnston 		if (cc->cc_buf_len == 0) {
411718d4a1dSMark Johnston 			*len = 0;
412718d4a1dSMark Johnston 			return (NULL);
413718d4a1dSMark Johnston 		}
414718d4a1dSMark Johnston 		break;
4159c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
416883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
417beb817edSJohn Baldwin 		if (cc->cc_mbuf == NULL) {
418beb817edSJohn Baldwin 			*len = 0;
4199c0e3d3aSJohn Baldwin 			return (NULL);
420beb817edSJohn Baldwin 		}
421718d4a1dSMark Johnston 		break;
422718d4a1dSMark Johnston 	default:
423718d4a1dSMark Johnston #ifdef INVARIANTS
424718d4a1dSMark Johnston 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
425718d4a1dSMark Johnston #endif
426718d4a1dSMark Johnston 		*len = 0;
427718d4a1dSMark Johnston 		return (NULL);
428718d4a1dSMark Johnston 	}
429718d4a1dSMark Johnston 
430718d4a1dSMark Johnston 	switch (cc->cc_type) {
431718d4a1dSMark Johnston 	case CRYPTO_BUF_CONTIG:
432718d4a1dSMark Johnston 		*len = cc->cc_buf_len;
433718d4a1dSMark Johnston 		return (cc->cc_buf);
434718d4a1dSMark Johnston 	case CRYPTO_BUF_MBUF:
435718d4a1dSMark Johnston 	case CRYPTO_BUF_SINGLE_MBUF:
4361c8f4b3cSJohn Baldwin 		if (cc->cc_mbuf->m_flags & M_EXTPG)
437beb817edSJohn Baldwin 			return (m_epg_segment(cc->cc_mbuf, cc->cc_offset, len));
438beb817edSJohn Baldwin 		*len = cc->cc_mbuf->m_len - cc->cc_offset;
4399c0e3d3aSJohn Baldwin 		return (mtod(cc->cc_mbuf, char *) + cc->cc_offset);
440e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
441beb817edSJohn Baldwin 		*len = PAGE_SIZE - cc->cc_offset;
442e6f6d0c9SAlan Somers 		return ((char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
443e6f6d0c9SAlan Somers 		    *cc->cc_vmpage)) + cc->cc_offset);
4449c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
445beb817edSJohn Baldwin 		*len = cc->cc_iov->iov_len - cc->cc_offset;
4469c0e3d3aSJohn Baldwin 		return ((char *)cc->cc_iov->iov_base + cc->cc_offset);
4479c0e3d3aSJohn Baldwin 	default:
448718d4a1dSMark Johnston 		__assert_unreachable();
4499c0e3d3aSJohn Baldwin 	}
4509c0e3d3aSJohn Baldwin }
4519c0e3d3aSJohn Baldwin 
4529c0e3d3aSJohn Baldwin void
crypto_cursor_copyback(struct crypto_buffer_cursor * cc,int size,const void * vsrc)4539c0e3d3aSJohn Baldwin crypto_cursor_copyback(struct crypto_buffer_cursor *cc, int size,
4549c0e3d3aSJohn Baldwin     const void *vsrc)
4559c0e3d3aSJohn Baldwin {
4569c0e3d3aSJohn Baldwin 	size_t remain, todo;
4579c0e3d3aSJohn Baldwin 	const char *src;
4589c0e3d3aSJohn Baldwin 	char *dst;
4599c0e3d3aSJohn Baldwin 
4609c0e3d3aSJohn Baldwin 	src = vsrc;
4619c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
4629c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
4639c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= size);
4649c0e3d3aSJohn Baldwin 		memcpy(cc->cc_buf, src, size);
4659c0e3d3aSJohn Baldwin 		cc->cc_buf += size;
4669c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= size;
4679c0e3d3aSJohn Baldwin 		break;
4689c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
4699c0e3d3aSJohn Baldwin 		for (;;) {
4701c8f4b3cSJohn Baldwin 			/*
4711c8f4b3cSJohn Baldwin 			 * This uses m_copyback() for individual
4721c8f4b3cSJohn Baldwin 			 * mbufs so that cc_mbuf and cc_offset are
4731c8f4b3cSJohn Baldwin 			 * updated.
4741c8f4b3cSJohn Baldwin 			 */
4759c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
4769c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
4771c8f4b3cSJohn Baldwin 			m_copyback(cc->cc_mbuf, cc->cc_offset, todo, src);
4784542cd93SJohn Baldwin 			src += todo;
4799c0e3d3aSJohn Baldwin 			if (todo < remain) {
4809c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
4819c0e3d3aSJohn Baldwin 				break;
4829c0e3d3aSJohn Baldwin 			}
4839c0e3d3aSJohn Baldwin 			size -= todo;
4849c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
4859c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
4869c0e3d3aSJohn Baldwin 			if (size == 0)
4879c0e3d3aSJohn Baldwin 				break;
4889c0e3d3aSJohn Baldwin 		}
4899c0e3d3aSJohn Baldwin 		break;
490883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
491883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + size);
492883a0196SJohn Baldwin 		m_copyback(cc->cc_mbuf, cc->cc_offset, size, src);
493883a0196SJohn Baldwin 		cc->cc_offset += size;
494883a0196SJohn Baldwin 		break;
495e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
496e6f6d0c9SAlan Somers 		for (;;) {
497e6f6d0c9SAlan Somers 			dst = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
498e6f6d0c9SAlan Somers 			    *cc->cc_vmpage)) + cc->cc_offset;
499e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
500e6f6d0c9SAlan Somers 			todo = MIN(remain, size);
501e6f6d0c9SAlan Somers 			memcpy(dst, src, todo);
502e6f6d0c9SAlan Somers 			src += todo;
503e6f6d0c9SAlan Somers 			cc->cc_buf_len -= todo;
504e6f6d0c9SAlan Somers 			if (todo < remain) {
505e6f6d0c9SAlan Somers 				cc->cc_offset += todo;
506e6f6d0c9SAlan Somers 				break;
507e6f6d0c9SAlan Somers 			}
508e6f6d0c9SAlan Somers 			size -= todo;
509e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
510e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
511e6f6d0c9SAlan Somers 			if (size == 0)
512e6f6d0c9SAlan Somers 				break;
513e6f6d0c9SAlan Somers 		}
514e6f6d0c9SAlan Somers 		break;
5159c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
5169c0e3d3aSJohn Baldwin 		for (;;) {
5179c0e3d3aSJohn Baldwin 			dst = (char *)cc->cc_iov->iov_base + cc->cc_offset;
5189c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
5199c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
5209c0e3d3aSJohn Baldwin 			memcpy(dst, src, todo);
5214542cd93SJohn Baldwin 			src += todo;
522718d4a1dSMark Johnston 			cc->cc_buf_len -= todo;
5239c0e3d3aSJohn Baldwin 			if (todo < remain) {
5249c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
5259c0e3d3aSJohn Baldwin 				break;
5269c0e3d3aSJohn Baldwin 			}
5279c0e3d3aSJohn Baldwin 			size -= todo;
5289c0e3d3aSJohn Baldwin 			cc->cc_iov++;
5299c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
5309c0e3d3aSJohn Baldwin 			if (size == 0)
5319c0e3d3aSJohn Baldwin 				break;
5329c0e3d3aSJohn Baldwin 		}
5339c0e3d3aSJohn Baldwin 		break;
5349c0e3d3aSJohn Baldwin 	default:
5359c0e3d3aSJohn Baldwin #ifdef INVARIANTS
5369c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
5379c0e3d3aSJohn Baldwin #endif
5389c0e3d3aSJohn Baldwin 		break;
5399c0e3d3aSJohn Baldwin 	}
5409c0e3d3aSJohn Baldwin }
5419c0e3d3aSJohn Baldwin 
5429c0e3d3aSJohn Baldwin void
crypto_cursor_copydata(struct crypto_buffer_cursor * cc,int size,void * vdst)5439c0e3d3aSJohn Baldwin crypto_cursor_copydata(struct crypto_buffer_cursor *cc, int size, void *vdst)
5449c0e3d3aSJohn Baldwin {
5459c0e3d3aSJohn Baldwin 	size_t remain, todo;
5469c0e3d3aSJohn Baldwin 	const char *src;
5479c0e3d3aSJohn Baldwin 	char *dst;
5489c0e3d3aSJohn Baldwin 
5499c0e3d3aSJohn Baldwin 	dst = vdst;
5509c0e3d3aSJohn Baldwin 	switch (cc->cc_type) {
5519c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
5529c0e3d3aSJohn Baldwin 		MPASS(cc->cc_buf_len >= size);
5539c0e3d3aSJohn Baldwin 		memcpy(dst, cc->cc_buf, size);
5549c0e3d3aSJohn Baldwin 		cc->cc_buf += size;
5559c0e3d3aSJohn Baldwin 		cc->cc_buf_len -= size;
5569c0e3d3aSJohn Baldwin 		break;
5579c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
5589c0e3d3aSJohn Baldwin 		for (;;) {
5591c8f4b3cSJohn Baldwin 			/*
5601c8f4b3cSJohn Baldwin 			 * This uses m_copydata() for individual
5611c8f4b3cSJohn Baldwin 			 * mbufs so that cc_mbuf and cc_offset are
5621c8f4b3cSJohn Baldwin 			 * updated.
5631c8f4b3cSJohn Baldwin 			 */
5649c0e3d3aSJohn Baldwin 			remain = cc->cc_mbuf->m_len - cc->cc_offset;
5659c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
5661c8f4b3cSJohn Baldwin 			m_copydata(cc->cc_mbuf, cc->cc_offset, todo, dst);
5679c0e3d3aSJohn Baldwin 			dst += todo;
5689c0e3d3aSJohn Baldwin 			if (todo < remain) {
5699c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
5709c0e3d3aSJohn Baldwin 				break;
5719c0e3d3aSJohn Baldwin 			}
5729c0e3d3aSJohn Baldwin 			size -= todo;
5739c0e3d3aSJohn Baldwin 			cc->cc_mbuf = cc->cc_mbuf->m_next;
5749c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
5759c0e3d3aSJohn Baldwin 			if (size == 0)
5769c0e3d3aSJohn Baldwin 				break;
5779c0e3d3aSJohn Baldwin 		}
5789c0e3d3aSJohn Baldwin 		break;
579883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
580883a0196SJohn Baldwin 		MPASS(cc->cc_mbuf->m_len >= cc->cc_offset + size);
581883a0196SJohn Baldwin 		m_copydata(cc->cc_mbuf, cc->cc_offset, size, dst);
582883a0196SJohn Baldwin 		cc->cc_offset += size;
583883a0196SJohn Baldwin 		break;
584e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
585e6f6d0c9SAlan Somers 		for (;;) {
586e6f6d0c9SAlan Somers 			src = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(
587e6f6d0c9SAlan Somers 			    *cc->cc_vmpage)) + cc->cc_offset;
588e6f6d0c9SAlan Somers 			remain = MIN(PAGE_SIZE - cc->cc_offset, cc->cc_buf_len);
589e6f6d0c9SAlan Somers 			todo = MIN(remain, size);
590e6f6d0c9SAlan Somers 			memcpy(dst, src, todo);
591*9f7fdd8cSMark Johnston 			dst += todo;
592e6f6d0c9SAlan Somers 			cc->cc_buf_len -= todo;
593e6f6d0c9SAlan Somers 			if (todo < remain) {
594e6f6d0c9SAlan Somers 				cc->cc_offset += todo;
595e6f6d0c9SAlan Somers 				break;
596e6f6d0c9SAlan Somers 			}
597e6f6d0c9SAlan Somers 			size -= todo;
598e6f6d0c9SAlan Somers 			cc->cc_vmpage++;
599e6f6d0c9SAlan Somers 			cc->cc_offset = 0;
600e6f6d0c9SAlan Somers 			if (size == 0)
601e6f6d0c9SAlan Somers 				break;
602e6f6d0c9SAlan Somers 		}
603e6f6d0c9SAlan Somers 		break;
6049c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
6059c0e3d3aSJohn Baldwin 		for (;;) {
6069c0e3d3aSJohn Baldwin 			src = (const char *)cc->cc_iov->iov_base +
6079c0e3d3aSJohn Baldwin 			    cc->cc_offset;
6089c0e3d3aSJohn Baldwin 			remain = cc->cc_iov->iov_len - cc->cc_offset;
6099c0e3d3aSJohn Baldwin 			todo = MIN(remain, size);
6109c0e3d3aSJohn Baldwin 			memcpy(dst, src, todo);
6119c0e3d3aSJohn Baldwin 			dst += todo;
612718d4a1dSMark Johnston 			cc->cc_buf_len -= todo;
6139c0e3d3aSJohn Baldwin 			if (todo < remain) {
6149c0e3d3aSJohn Baldwin 				cc->cc_offset += todo;
6159c0e3d3aSJohn Baldwin 				break;
6169c0e3d3aSJohn Baldwin 			}
6179c0e3d3aSJohn Baldwin 			size -= todo;
6189c0e3d3aSJohn Baldwin 			cc->cc_iov++;
6199c0e3d3aSJohn Baldwin 			cc->cc_offset = 0;
6209c0e3d3aSJohn Baldwin 			if (size == 0)
6219c0e3d3aSJohn Baldwin 				break;
6229c0e3d3aSJohn Baldwin 		}
6239c0e3d3aSJohn Baldwin 		break;
6249c0e3d3aSJohn Baldwin 	default:
6259c0e3d3aSJohn Baldwin #ifdef INVARIANTS
6269c0e3d3aSJohn Baldwin 		panic("%s: invalid buffer type %d", __func__, cc->cc_type);
6279c0e3d3aSJohn Baldwin #endif
6289c0e3d3aSJohn Baldwin 		break;
6299c0e3d3aSJohn Baldwin 	}
6309c0e3d3aSJohn Baldwin }
6319c0e3d3aSJohn Baldwin 
6329c0e3d3aSJohn Baldwin /*
6339c0e3d3aSJohn Baldwin  * To avoid advancing 'cursor', make a local copy that gets advanced
6349c0e3d3aSJohn Baldwin  * instead.
6359c0e3d3aSJohn Baldwin  */
6369c0e3d3aSJohn Baldwin void
crypto_cursor_copydata_noadv(struct crypto_buffer_cursor * cc,int size,void * vdst)6379c0e3d3aSJohn Baldwin crypto_cursor_copydata_noadv(struct crypto_buffer_cursor *cc, int size,
6389c0e3d3aSJohn Baldwin     void *vdst)
6399c0e3d3aSJohn Baldwin {
6409c0e3d3aSJohn Baldwin 	struct crypto_buffer_cursor copy;
6419c0e3d3aSJohn Baldwin 
6429c0e3d3aSJohn Baldwin 	copy = *cc;
6439c0e3d3aSJohn Baldwin 	crypto_cursor_copydata(&copy, size, vdst);
6449c0e3d3aSJohn Baldwin }
6459c0e3d3aSJohn Baldwin 
6468f91d4abSPawel Jakub Dawidek /*
6478f91d4abSPawel Jakub Dawidek  * Apply function f to the data in an iovec list starting "off" bytes from
6488f91d4abSPawel Jakub Dawidek  * the beginning, continuing for "len" bytes.
6498f91d4abSPawel Jakub Dawidek  */
6509c0e3d3aSJohn Baldwin static int
cuio_apply(struct uio * uio,int off,int len,int (* f)(void *,const void *,u_int),void * arg)6519b6b2f86SJohn Baldwin cuio_apply(struct uio *uio, int off, int len,
6529b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
6538f91d4abSPawel Jakub Dawidek {
6548f91d4abSPawel Jakub Dawidek 	struct iovec *iov = uio->uio_iov;
6553471fcf3SEd Maste 	int iol __diagused = uio->uio_iovcnt;
6568f91d4abSPawel Jakub Dawidek 	unsigned count;
6578f91d4abSPawel Jakub Dawidek 	int rval;
6588f91d4abSPawel Jakub Dawidek 
6598f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
6608f91d4abSPawel Jakub Dawidek 	while (len > 0) {
6618f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
6628f91d4abSPawel Jakub Dawidek 		count = min(iov->iov_len - off, len);
6638f91d4abSPawel Jakub Dawidek 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
6648f91d4abSPawel Jakub Dawidek 		if (rval)
6658f91d4abSPawel Jakub Dawidek 			return (rval);
6668f91d4abSPawel Jakub Dawidek 		len -= count;
6678f91d4abSPawel Jakub Dawidek 		off = 0;
6688f91d4abSPawel Jakub Dawidek 		iol--;
6698f91d4abSPawel Jakub Dawidek 		iov++;
6708f91d4abSPawel Jakub Dawidek 	}
6718f91d4abSPawel Jakub Dawidek 	return (0);
6728f91d4abSPawel Jakub Dawidek }
67311d2e1e8SPawel Jakub Dawidek 
67411d2e1e8SPawel Jakub Dawidek void
crypto_copyback(struct cryptop * crp,int off,int size,const void * src)675c0341432SJohn Baldwin crypto_copyback(struct cryptop *crp, int off, int size, const void *src)
67611d2e1e8SPawel Jakub Dawidek {
6779c0e3d3aSJohn Baldwin 	struct crypto_buffer *cb;
67811d2e1e8SPawel Jakub Dawidek 
6799c0e3d3aSJohn Baldwin 	if (crp->crp_obuf.cb_type != CRYPTO_BUF_NONE)
6809c0e3d3aSJohn Baldwin 		cb = &crp->crp_obuf;
6819c0e3d3aSJohn Baldwin 	else
6829c0e3d3aSJohn Baldwin 		cb = &crp->crp_buf;
6839c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
684c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
685883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
6869c0e3d3aSJohn Baldwin 		m_copyback(cb->cb_mbuf, off, size, src);
687c0341432SJohn Baldwin 		break;
688e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
689e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
690e6f6d0c9SAlan Somers 		MPASS(size <= cb->cb_vm_page_len);
691e6f6d0c9SAlan Somers 		MPASS(size + off <=
692e6f6d0c9SAlan Somers 		    cb->cb_vm_page_len + cb->cb_vm_page_offset);
693e6f6d0c9SAlan Somers 		cvm_page_copyback(cb->cb_vm_page,
694e6f6d0c9SAlan Somers 		    off + cb->cb_vm_page_offset, size, src);
695e6f6d0c9SAlan Somers 		break;
696e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
697c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
6989c0e3d3aSJohn Baldwin 		cuio_copyback(cb->cb_uio, off, size, src);
699c0341432SJohn Baldwin 		break;
700c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
7019c0e3d3aSJohn Baldwin 		MPASS(off + size <= cb->cb_buf_len);
7029c0e3d3aSJohn Baldwin 		bcopy(src, cb->cb_buf + off, size);
703c0341432SJohn Baldwin 		break;
704c0341432SJohn Baldwin 	default:
7059c0e3d3aSJohn Baldwin #ifdef INVARIANTS
7069c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", cb->cb_type);
7079c0e3d3aSJohn Baldwin #endif
7089c0e3d3aSJohn Baldwin 		break;
709c0341432SJohn Baldwin 	}
71011d2e1e8SPawel Jakub Dawidek }
71111d2e1e8SPawel Jakub Dawidek 
71211d2e1e8SPawel Jakub Dawidek void
crypto_copydata(struct cryptop * crp,int off,int size,void * dst)713c0341432SJohn Baldwin crypto_copydata(struct cryptop *crp, int off, int size, void *dst)
71411d2e1e8SPawel Jakub Dawidek {
71511d2e1e8SPawel Jakub Dawidek 
7169c0e3d3aSJohn Baldwin 	switch (crp->crp_buf.cb_type) {
717c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
718883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
7199c0e3d3aSJohn Baldwin 		m_copydata(crp->crp_buf.cb_mbuf, off, size, dst);
720c0341432SJohn Baldwin 		break;
721e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
722e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
723e6f6d0c9SAlan Somers 		MPASS(size <= crp->crp_buf.cb_vm_page_len);
724e6f6d0c9SAlan Somers 		MPASS(size + off <= crp->crp_buf.cb_vm_page_len +
725e6f6d0c9SAlan Somers 		    crp->crp_buf.cb_vm_page_offset);
726e6f6d0c9SAlan Somers 		cvm_page_copydata(crp->crp_buf.cb_vm_page,
727e6f6d0c9SAlan Somers 		    off + crp->crp_buf.cb_vm_page_offset, size, dst);
728e6f6d0c9SAlan Somers 		break;
729e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
730c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
7319c0e3d3aSJohn Baldwin 		cuio_copydata(crp->crp_buf.cb_uio, off, size, dst);
732c0341432SJohn Baldwin 		break;
733c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
7349c0e3d3aSJohn Baldwin 		MPASS(off + size <= crp->crp_buf.cb_buf_len);
7359c0e3d3aSJohn Baldwin 		bcopy(crp->crp_buf.cb_buf + off, dst, size);
736c0341432SJohn Baldwin 		break;
737c0341432SJohn Baldwin 	default:
7389c0e3d3aSJohn Baldwin #ifdef INVARIANTS
7399c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", crp->crp_buf.cb_type);
7409c0e3d3aSJohn Baldwin #endif
7419c0e3d3aSJohn Baldwin 		break;
742c0341432SJohn Baldwin 	}
74311d2e1e8SPawel Jakub Dawidek }
74411d2e1e8SPawel Jakub Dawidek 
74511d2e1e8SPawel Jakub Dawidek int
crypto_apply_buf(struct crypto_buffer * cb,int off,int len,int (* f)(void *,const void *,u_int),void * arg)7469c0e3d3aSJohn Baldwin crypto_apply_buf(struct crypto_buffer *cb, int off, int len,
7479b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
7489c0e3d3aSJohn Baldwin {
7499c0e3d3aSJohn Baldwin 	int error;
7509c0e3d3aSJohn Baldwin 
7519c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
7529c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_MBUF:
753883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
7549b6b2f86SJohn Baldwin 		error = m_apply(cb->cb_mbuf, off, len,
7559b6b2f86SJohn Baldwin 		    (int (*)(void *, void *, u_int))f, arg);
7569c0e3d3aSJohn Baldwin 		break;
7579c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_UIO:
7589c0e3d3aSJohn Baldwin 		error = cuio_apply(cb->cb_uio, off, len, f, arg);
7599c0e3d3aSJohn Baldwin 		break;
760e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
761e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
762e6f6d0c9SAlan Somers 		error = cvm_page_apply(cb->cb_vm_page,
763e6f6d0c9SAlan Somers 		    off + cb->cb_vm_page_offset, len, f, arg);
764e6f6d0c9SAlan Somers 		break;
765e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
7669c0e3d3aSJohn Baldwin 	case CRYPTO_BUF_CONTIG:
7679c0e3d3aSJohn Baldwin 		MPASS(off + len <= cb->cb_buf_len);
7689c0e3d3aSJohn Baldwin 		error = (*f)(arg, cb->cb_buf + off, len);
7699c0e3d3aSJohn Baldwin 		break;
7709c0e3d3aSJohn Baldwin 	default:
7719c0e3d3aSJohn Baldwin #ifdef INVARIANTS
7729c0e3d3aSJohn Baldwin 		panic("invalid crypto buf type %d", cb->cb_type);
7739c0e3d3aSJohn Baldwin #endif
7749c0e3d3aSJohn Baldwin 		error = 0;
7759c0e3d3aSJohn Baldwin 		break;
7769c0e3d3aSJohn Baldwin 	}
7779c0e3d3aSJohn Baldwin 	return (error);
7789c0e3d3aSJohn Baldwin }
7799c0e3d3aSJohn Baldwin 
7809c0e3d3aSJohn Baldwin int
crypto_apply(struct cryptop * crp,int off,int len,int (* f)(void *,const void *,u_int),void * arg)781c0341432SJohn Baldwin crypto_apply(struct cryptop *crp, int off, int len,
7829b6b2f86SJohn Baldwin     int (*f)(void *, const void *, u_int), void *arg)
78311d2e1e8SPawel Jakub Dawidek {
7849c0e3d3aSJohn Baldwin 	return (crypto_apply_buf(&crp->crp_buf, off, len, f, arg));
78508fca7a5SJohn-Mark Gurney }
786ff2038a9SMatt Macy 
787ff2038a9SMatt Macy static inline void *
m_contiguous_subsegment(struct mbuf * m,size_t skip,size_t len)788ff2038a9SMatt Macy m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len)
789ff2038a9SMatt Macy {
790ff2038a9SMatt Macy 	int rel_off;
791ff2038a9SMatt Macy 
792ff2038a9SMatt Macy 	MPASS(skip <= INT_MAX);
793ff2038a9SMatt Macy 
794ff2038a9SMatt Macy 	m = m_getptr(m, (int)skip, &rel_off);
795ff2038a9SMatt Macy 	if (m == NULL)
796ff2038a9SMatt Macy 		return (NULL);
797ff2038a9SMatt Macy 
798ff2038a9SMatt Macy 	MPASS(rel_off >= 0);
799ff2038a9SMatt Macy 	skip = rel_off;
800ff2038a9SMatt Macy 	if (skip + len > m->m_len)
801ff2038a9SMatt Macy 		return (NULL);
802ff2038a9SMatt Macy 
8031c8f4b3cSJohn Baldwin 	if (m->m_flags & M_EXTPG)
8041c8f4b3cSJohn Baldwin 		return (m_epg_contiguous_subsegment(m, skip, len));
805ff2038a9SMatt Macy 	return (mtod(m, char*) + skip);
806ff2038a9SMatt Macy }
807ff2038a9SMatt Macy 
808ff2038a9SMatt Macy static inline void *
cuio_contiguous_segment(struct uio * uio,size_t skip,size_t len)809ff2038a9SMatt Macy cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len)
810ff2038a9SMatt Macy {
811ff2038a9SMatt Macy 	int rel_off, idx;
812ff2038a9SMatt Macy 
813ff2038a9SMatt Macy 	MPASS(skip <= INT_MAX);
814ff2038a9SMatt Macy 	idx = cuio_getptr(uio, (int)skip, &rel_off);
815ff2038a9SMatt Macy 	if (idx < 0)
816ff2038a9SMatt Macy 		return (NULL);
817ff2038a9SMatt Macy 
818ff2038a9SMatt Macy 	MPASS(rel_off >= 0);
819ff2038a9SMatt Macy 	skip = rel_off;
820ff2038a9SMatt Macy 	if (skip + len > uio->uio_iov[idx].iov_len)
821ff2038a9SMatt Macy 		return (NULL);
822ff2038a9SMatt Macy 	return ((char *)uio->uio_iov[idx].iov_base + skip);
823ff2038a9SMatt Macy }
824ff2038a9SMatt Macy 
825ff2038a9SMatt Macy void *
crypto_buffer_contiguous_subsegment(struct crypto_buffer * cb,size_t skip,size_t len)8269c0e3d3aSJohn Baldwin crypto_buffer_contiguous_subsegment(struct crypto_buffer *cb, size_t skip,
8279c0e3d3aSJohn Baldwin     size_t len)
828ff2038a9SMatt Macy {
829ff2038a9SMatt Macy 
8309c0e3d3aSJohn Baldwin 	switch (cb->cb_type) {
831c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
832883a0196SJohn Baldwin 	case CRYPTO_BUF_SINGLE_MBUF:
8339c0e3d3aSJohn Baldwin 		return (m_contiguous_subsegment(cb->cb_mbuf, skip, len));
834c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
8359c0e3d3aSJohn Baldwin 		return (cuio_contiguous_segment(cb->cb_uio, skip, len));
836e6f6d0c9SAlan Somers #if CRYPTO_MAY_HAVE_VMPAGE
837e6f6d0c9SAlan Somers 	case CRYPTO_BUF_VMPAGE:
838e6f6d0c9SAlan Somers 		MPASS(skip + len <= cb->cb_vm_page_len);
839e6f6d0c9SAlan Somers 		return (cvm_page_contiguous_segment(cb->cb_vm_page,
840e6f6d0c9SAlan Somers 		    skip + cb->cb_vm_page_offset, len));
841e6f6d0c9SAlan Somers #endif /* CRYPTO_MAY_HAVE_VMPAGE */
842c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
8439c0e3d3aSJohn Baldwin 		MPASS(skip + len <= cb->cb_buf_len);
8449c0e3d3aSJohn Baldwin 		return (cb->cb_buf + skip);
845c0341432SJohn Baldwin 	default:
8469c0e3d3aSJohn Baldwin #ifdef INVARIANTS
8479c0e3d3aSJohn Baldwin 		panic("invalid crp buf type %d", cb->cb_type);
8489c0e3d3aSJohn Baldwin #endif
8499c0e3d3aSJohn Baldwin 		return (NULL);
850c0341432SJohn Baldwin 	}
851c0341432SJohn Baldwin }
8529c0e3d3aSJohn Baldwin 
8539c0e3d3aSJohn Baldwin void *
crypto_contiguous_subsegment(struct cryptop * crp,size_t skip,size_t len)8549c0e3d3aSJohn Baldwin crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len)
8559c0e3d3aSJohn Baldwin {
8569c0e3d3aSJohn Baldwin 	return (crypto_buffer_contiguous_subsegment(&crp->crp_buf, skip, len));
8579c0e3d3aSJohn Baldwin }
858