1104476Ssam/*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
2104476Ssam
3139825Simp/*-
4104476Ssam * Copyright (c) 1999 Theo de Raadt
5104476Ssam *
6104476Ssam * Redistribution and use in source and binary forms, with or without
7104476Ssam * modification, are permitted provided that the following conditions
8104476Ssam * are met:
9104476Ssam *
10104476Ssam * 1. Redistributions of source code must retain the above copyright
11104476Ssam *   notice, this list of conditions and the following disclaimer.
12104476Ssam * 2. Redistributions in binary form must reproduce the above copyright
13104476Ssam *   notice, this list of conditions and the following disclaimer in the
14104476Ssam *   documentation and/or other materials provided with the distribution.
15104476Ssam * 3. The name of the author may not be used to endorse or promote products
16104476Ssam *   derived from this software without specific prior written permission.
17104476Ssam *
18104476Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19104476Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20104476Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21104476Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22104476Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23104476Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24104476Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25104476Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26104476Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27104476Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28104476Ssam */
29104476Ssam
30116191Sobrien#include <sys/cdefs.h>
31116191Sobrien__FBSDID("$FreeBSD$");
32116191Sobrien
33104476Ssam#include <sys/param.h>
34104476Ssam#include <sys/systm.h>
35104476Ssam#include <sys/proc.h>
36104476Ssam#include <sys/errno.h>
37104476Ssam#include <sys/malloc.h>
38104476Ssam#include <sys/kernel.h>
39159241Spjd#include <sys/mbuf.h>
40104476Ssam#include <sys/uio.h>
41104476Ssam
42104476Ssam#include <opencrypto/cryptodev.h>
43104476Ssam
44158698Spjd/*
45158698Spjd * This macro is only for avoiding code duplication, as we need to skip
46158698Spjd * given number of bytes in the same way in three functions below.
47158698Spjd */
48158698Spjd#define	CUIO_SKIP()	do {						\
49158698Spjd	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
50158698Spjd	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
51158698Spjd	while (off > 0) {						\
52158698Spjd		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
53158698Spjd		if (off < iov->iov_len)					\
54158698Spjd			break;						\
55158698Spjd		off -= iov->iov_len;					\
56158698Spjd		iol--;							\
57158698Spjd		iov++;							\
58158698Spjd	}								\
59158698Spjd} while (0)
60158698Spjd
61104476Ssamvoid
62104476Ssamcuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
63104476Ssam{
64104476Ssam	struct iovec *iov = uio->uio_iov;
65104476Ssam	int iol = uio->uio_iovcnt;
66104476Ssam	unsigned count;
67104476Ssam
68158698Spjd	CUIO_SKIP();
69104476Ssam	while (len > 0) {
70158698Spjd		KASSERT(iol >= 0, ("%s: empty", __func__));
71104476Ssam		count = min(iov->iov_len - off, len);
72104476Ssam		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
73104476Ssam		len -= count;
74104476Ssam		cp += count;
75104476Ssam		off = 0;
76104476Ssam		iol--;
77104476Ssam		iov++;
78104476Ssam	}
79104476Ssam}
80104476Ssam
81104476Ssamvoid
82104476Ssamcuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
83104476Ssam{
84104476Ssam	struct iovec *iov = uio->uio_iov;
85104476Ssam	int iol = uio->uio_iovcnt;
86104476Ssam	unsigned count;
87104476Ssam
88158698Spjd	CUIO_SKIP();
89104476Ssam	while (len > 0) {
90158698Spjd		KASSERT(iol >= 0, ("%s: empty", __func__));
91104476Ssam		count = min(iov->iov_len - off, len);
92104476Ssam		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
93104476Ssam		len -= count;
94104476Ssam		cp += count;
95104476Ssam		off = 0;
96104476Ssam		iol--;
97104476Ssam		iov++;
98104476Ssam	}
99104476Ssam}
100104476Ssam
101104476Ssam/*
102104476Ssam * Return a pointer to iov/offset of location in iovec list.
103104476Ssam */
104104476Ssamstruct iovec *
105104476Ssamcuio_getptr(struct uio *uio, int loc, int *off)
106104476Ssam{
107104476Ssam	struct iovec *iov = uio->uio_iov;
108104476Ssam	int iol = uio->uio_iovcnt;
109104476Ssam
110104476Ssam	while (loc >= 0) {
111104476Ssam		/* Normal end of search */
112104476Ssam		if (loc < iov->iov_len) {
113104476Ssam	    		*off = loc;
114104476Ssam	    		return (iov);
115104476Ssam		}
116104476Ssam
117104476Ssam		loc -= iov->iov_len;
118104476Ssam		if (iol == 0) {
119104476Ssam			if (loc == 0) {
120104476Ssam				/* Point at the end of valid data */
121104476Ssam				*off = iov->iov_len;
122104476Ssam				return (iov);
123104476Ssam			} else
124104476Ssam				return (NULL);
125104476Ssam		} else {
126104476Ssam			iov++, iol--;
127104476Ssam		}
128104476Ssam    	}
129104476Ssam
130104476Ssam	return (NULL);
131104476Ssam}
132158698Spjd
133158698Spjd/*
134158698Spjd * Apply function f to the data in an iovec list starting "off" bytes from
135158698Spjd * the beginning, continuing for "len" bytes.
136158698Spjd */
137158698Spjdint
138158698Spjdcuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int),
139158698Spjd    void *arg)
140158698Spjd{
141158698Spjd	struct iovec *iov = uio->uio_iov;
142158698Spjd	int iol = uio->uio_iovcnt;
143158698Spjd	unsigned count;
144158698Spjd	int rval;
145158698Spjd
146158698Spjd	CUIO_SKIP();
147158698Spjd	while (len > 0) {
148158698Spjd		KASSERT(iol >= 0, ("%s: empty", __func__));
149158698Spjd		count = min(iov->iov_len - off, len);
150158698Spjd		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
151158698Spjd		if (rval)
152158698Spjd			return (rval);
153158698Spjd		len -= count;
154158698Spjd		off = 0;
155158698Spjd		iol--;
156158698Spjd		iov++;
157158698Spjd	}
158158698Spjd	return (0);
159158698Spjd}
160159241Spjd
161159241Spjdvoid
162159241Spjdcrypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
163159241Spjd{
164159241Spjd
165159241Spjd	if ((flags & CRYPTO_F_IMBUF) != 0)
166159241Spjd		m_copyback((struct mbuf *)buf, off, size, in);
167159241Spjd	else if ((flags & CRYPTO_F_IOV) != 0)
168159241Spjd		cuio_copyback((struct uio *)buf, off, size, in);
169159241Spjd	else
170159241Spjd		bcopy(in, buf + off, size);
171159241Spjd}
172159241Spjd
173159241Spjdvoid
174159241Spjdcrypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
175159241Spjd{
176159241Spjd
177159241Spjd	if ((flags & CRYPTO_F_IMBUF) != 0)
178159241Spjd		m_copydata((struct mbuf *)buf, off, size, out);
179159241Spjd	else if ((flags & CRYPTO_F_IOV) != 0)
180159241Spjd		cuio_copydata((struct uio *)buf, off, size, out);
181159241Spjd	else
182159241Spjd		bcopy(buf + off, out, size);
183159241Spjd}
184159241Spjd
185159241Spjdint
186159241Spjdcrypto_apply(int flags, caddr_t buf, int off, int len,
187159241Spjd    int (*f)(void *, void *, u_int), void *arg)
188159241Spjd{
189159241Spjd	int error;
190159241Spjd
191159241Spjd	if ((flags & CRYPTO_F_IMBUF) != 0)
192159241Spjd		error = m_apply((struct mbuf *)buf, off, len, f, arg);
193159241Spjd	else if ((flags & CRYPTO_F_IOV) != 0)
194159241Spjd		error = cuio_apply((struct uio *)buf, off, len, f, arg);
195159241Spjd	else
196159241Spjd		error = (*f)(arg, buf + off, len);
197159241Spjd	return (error);
198159241Spjd}
199