xref: /freebsd/sys/opencrypto/criov.c (revision 11d2e1e8fff75655552f3144613810f37dd85c2a)
1091d81d1SSam Leffler /*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
2091d81d1SSam Leffler 
360727d8bSWarner Losh /*-
4091d81d1SSam Leffler  * Copyright (c) 1999 Theo de Raadt
5091d81d1SSam Leffler  *
6091d81d1SSam Leffler  * Redistribution and use in source and binary forms, with or without
7091d81d1SSam Leffler  * modification, are permitted provided that the following conditions
8091d81d1SSam Leffler  * are met:
9091d81d1SSam Leffler  *
10091d81d1SSam Leffler  * 1. Redistributions of source code must retain the above copyright
11091d81d1SSam Leffler  *   notice, this list of conditions and the following disclaimer.
12091d81d1SSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
13091d81d1SSam Leffler  *   notice, this list of conditions and the following disclaimer in the
14091d81d1SSam Leffler  *   documentation and/or other materials provided with the distribution.
15091d81d1SSam Leffler  * 3. The name of the author may not be used to endorse or promote products
16091d81d1SSam Leffler  *   derived from this software without specific prior written permission.
17091d81d1SSam Leffler  *
18091d81d1SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19091d81d1SSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20091d81d1SSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21091d81d1SSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22091d81d1SSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23091d81d1SSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24091d81d1SSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25091d81d1SSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26091d81d1SSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27091d81d1SSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28091d81d1SSam Leffler  */
29091d81d1SSam Leffler 
302c446514SDavid E. O'Brien #include <sys/cdefs.h>
312c446514SDavid E. O'Brien __FBSDID("$FreeBSD$");
322c446514SDavid E. O'Brien 
33091d81d1SSam Leffler #include <sys/param.h>
34091d81d1SSam Leffler #include <sys/systm.h>
35091d81d1SSam Leffler #include <sys/proc.h>
36091d81d1SSam Leffler #include <sys/errno.h>
37091d81d1SSam Leffler #include <sys/malloc.h>
38091d81d1SSam Leffler #include <sys/kernel.h>
3911d2e1e8SPawel Jakub Dawidek #include <sys/mbuf.h>
40091d81d1SSam Leffler #include <sys/uio.h>
41091d81d1SSam Leffler 
42091d81d1SSam Leffler #include <opencrypto/cryptodev.h>
43091d81d1SSam Leffler 
448f91d4abSPawel Jakub Dawidek /*
458f91d4abSPawel Jakub Dawidek  * This macro is only for avoiding code duplication, as we need to skip
468f91d4abSPawel Jakub Dawidek  * given number of bytes in the same way in three functions below.
478f91d4abSPawel Jakub Dawidek  */
488f91d4abSPawel Jakub Dawidek #define	CUIO_SKIP()	do {						\
498f91d4abSPawel Jakub Dawidek 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
508f91d4abSPawel Jakub Dawidek 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
518f91d4abSPawel Jakub Dawidek 	while (off > 0) {						\
528f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
538f91d4abSPawel Jakub Dawidek 		if (off < iov->iov_len)					\
548f91d4abSPawel Jakub Dawidek 			break;						\
558f91d4abSPawel Jakub Dawidek 		off -= iov->iov_len;					\
568f91d4abSPawel Jakub Dawidek 		iol--;							\
578f91d4abSPawel Jakub Dawidek 		iov++;							\
588f91d4abSPawel Jakub Dawidek 	}								\
598f91d4abSPawel Jakub Dawidek } while (0)
608f91d4abSPawel Jakub Dawidek 
61091d81d1SSam Leffler void
62091d81d1SSam Leffler cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
63091d81d1SSam Leffler {
64091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
65091d81d1SSam Leffler 	int iol = uio->uio_iovcnt;
66091d81d1SSam Leffler 	unsigned count;
67091d81d1SSam Leffler 
688f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
69091d81d1SSam Leffler 	while (len > 0) {
708f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
71091d81d1SSam Leffler 		count = min(iov->iov_len - off, len);
72091d81d1SSam Leffler 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
73091d81d1SSam Leffler 		len -= count;
74091d81d1SSam Leffler 		cp += count;
75091d81d1SSam Leffler 		off = 0;
76091d81d1SSam Leffler 		iol--;
77091d81d1SSam Leffler 		iov++;
78091d81d1SSam Leffler 	}
79091d81d1SSam Leffler }
80091d81d1SSam Leffler 
81091d81d1SSam Leffler void
82091d81d1SSam Leffler cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
83091d81d1SSam Leffler {
84091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
85091d81d1SSam Leffler 	int iol = 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(cp, ((caddr_t)iov->iov_base) + off, 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 
101091d81d1SSam Leffler /*
102091d81d1SSam Leffler  * Return a pointer to iov/offset of location in iovec list.
103091d81d1SSam Leffler  */
104091d81d1SSam Leffler struct iovec *
105091d81d1SSam Leffler cuio_getptr(struct uio *uio, int loc, int *off)
106091d81d1SSam Leffler {
107091d81d1SSam Leffler 	struct iovec *iov = uio->uio_iov;
108091d81d1SSam Leffler 	int iol = uio->uio_iovcnt;
109091d81d1SSam Leffler 
110091d81d1SSam Leffler 	while (loc >= 0) {
111091d81d1SSam Leffler 		/* Normal end of search */
112091d81d1SSam Leffler 		if (loc < iov->iov_len) {
113091d81d1SSam Leffler 	    		*off = loc;
114091d81d1SSam Leffler 	    		return (iov);
115091d81d1SSam Leffler 		}
116091d81d1SSam Leffler 
117091d81d1SSam Leffler 		loc -= iov->iov_len;
118091d81d1SSam Leffler 		if (iol == 0) {
119091d81d1SSam Leffler 			if (loc == 0) {
120091d81d1SSam Leffler 				/* Point at the end of valid data */
121091d81d1SSam Leffler 				*off = iov->iov_len;
122091d81d1SSam Leffler 				return (iov);
123091d81d1SSam Leffler 			} else
124091d81d1SSam Leffler 				return (NULL);
125091d81d1SSam Leffler 		} else {
126091d81d1SSam Leffler 			iov++, iol--;
127091d81d1SSam Leffler 		}
128091d81d1SSam Leffler     	}
129091d81d1SSam Leffler 
130091d81d1SSam Leffler 	return (NULL);
131091d81d1SSam Leffler }
1328f91d4abSPawel Jakub Dawidek 
1338f91d4abSPawel Jakub Dawidek /*
1348f91d4abSPawel Jakub Dawidek  * Apply function f to the data in an iovec list starting "off" bytes from
1358f91d4abSPawel Jakub Dawidek  * the beginning, continuing for "len" bytes.
1368f91d4abSPawel Jakub Dawidek  */
1378f91d4abSPawel Jakub Dawidek int
1388f91d4abSPawel Jakub Dawidek cuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int),
1398f91d4abSPawel Jakub Dawidek     void *arg)
1408f91d4abSPawel Jakub Dawidek {
1418f91d4abSPawel Jakub Dawidek 	struct iovec *iov = uio->uio_iov;
1428f91d4abSPawel Jakub Dawidek 	int iol = uio->uio_iovcnt;
1438f91d4abSPawel Jakub Dawidek 	unsigned count;
1448f91d4abSPawel Jakub Dawidek 	int rval;
1458f91d4abSPawel Jakub Dawidek 
1468f91d4abSPawel Jakub Dawidek 	CUIO_SKIP();
1478f91d4abSPawel Jakub Dawidek 	while (len > 0) {
1488f91d4abSPawel Jakub Dawidek 		KASSERT(iol >= 0, ("%s: empty", __func__));
1498f91d4abSPawel Jakub Dawidek 		count = min(iov->iov_len - off, len);
1508f91d4abSPawel Jakub Dawidek 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
1518f91d4abSPawel Jakub Dawidek 		if (rval)
1528f91d4abSPawel Jakub Dawidek 			return (rval);
1538f91d4abSPawel Jakub Dawidek 		len -= count;
1548f91d4abSPawel Jakub Dawidek 		off = 0;
1558f91d4abSPawel Jakub Dawidek 		iol--;
1568f91d4abSPawel Jakub Dawidek 		iov++;
1578f91d4abSPawel Jakub Dawidek 	}
1588f91d4abSPawel Jakub Dawidek 	return (0);
1598f91d4abSPawel Jakub Dawidek }
16011d2e1e8SPawel Jakub Dawidek 
16111d2e1e8SPawel Jakub Dawidek void
16211d2e1e8SPawel Jakub Dawidek crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
16311d2e1e8SPawel Jakub Dawidek {
16411d2e1e8SPawel Jakub Dawidek 
16511d2e1e8SPawel Jakub Dawidek 	if ((flags & CRYPTO_F_IMBUF) != 0)
16611d2e1e8SPawel Jakub Dawidek 		m_copyback((struct mbuf *)buf, off, size, in);
16711d2e1e8SPawel Jakub Dawidek 	else if ((flags & CRYPTO_F_IOV) != 0)
16811d2e1e8SPawel Jakub Dawidek 		cuio_copyback((struct uio *)buf, off, size, in);
16911d2e1e8SPawel Jakub Dawidek 	else
17011d2e1e8SPawel Jakub Dawidek 		bcopy(in, buf + off, size);
17111d2e1e8SPawel Jakub Dawidek }
17211d2e1e8SPawel Jakub Dawidek 
17311d2e1e8SPawel Jakub Dawidek void
17411d2e1e8SPawel Jakub Dawidek crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
17511d2e1e8SPawel Jakub Dawidek {
17611d2e1e8SPawel Jakub Dawidek 
17711d2e1e8SPawel Jakub Dawidek 	if ((flags & CRYPTO_F_IMBUF) != 0)
17811d2e1e8SPawel Jakub Dawidek 		m_copydata((struct mbuf *)buf, off, size, out);
17911d2e1e8SPawel Jakub Dawidek 	else if ((flags & CRYPTO_F_IOV) != 0)
18011d2e1e8SPawel Jakub Dawidek 		cuio_copydata((struct uio *)buf, off, size, out);
18111d2e1e8SPawel Jakub Dawidek 	else
18211d2e1e8SPawel Jakub Dawidek 		bcopy(buf + off, out, size);
18311d2e1e8SPawel Jakub Dawidek }
18411d2e1e8SPawel Jakub Dawidek 
18511d2e1e8SPawel Jakub Dawidek int
18611d2e1e8SPawel Jakub Dawidek crypto_apply(int flags, caddr_t buf, int off, int len,
18711d2e1e8SPawel Jakub Dawidek     int (*f)(void *, void *, u_int), void *arg)
18811d2e1e8SPawel Jakub Dawidek {
18911d2e1e8SPawel Jakub Dawidek 	int error;
19011d2e1e8SPawel Jakub Dawidek 
19111d2e1e8SPawel Jakub Dawidek 	if ((flags & CRYPTO_F_IMBUF) != 0)
19211d2e1e8SPawel Jakub Dawidek 		error = m_apply((struct mbuf *)buf, off, len, f, arg);
19311d2e1e8SPawel Jakub Dawidek 	else if ((flags & CRYPTO_F_IOV) != 0)
19411d2e1e8SPawel Jakub Dawidek 		error = cuio_apply((struct uio *)buf, off, len, f, arg);
19511d2e1e8SPawel Jakub Dawidek 	else
19611d2e1e8SPawel Jakub Dawidek 		error = (*f)(arg, buf + off, len);
19711d2e1e8SPawel Jakub Dawidek 	return (error);
19811d2e1e8SPawel Jakub Dawidek }
199