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(©, 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