xref: /freebsd/sys/opencrypto/criov.c (revision d6b92ffa)
1 /*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 Theo de Raadt
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *   derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/errno.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/mbuf.h>
40 #include <sys/uio.h>
41 
42 #include <opencrypto/cryptodev.h>
43 
44 /*
45  * This macro is only for avoiding code duplication, as we need to skip
46  * given number of bytes in the same way in three functions below.
47  */
48 #define	CUIO_SKIP()	do {						\
49 	KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));		\
50 	KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));		\
51 	while (off > 0) {						\
52 		KASSERT(iol >= 0, ("%s: empty in skip", __func__));	\
53 		if (off < iov->iov_len)					\
54 			break;						\
55 		off -= iov->iov_len;					\
56 		iol--;							\
57 		iov++;							\
58 	}								\
59 } while (0)
60 
61 void
62 cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
63 {
64 	struct iovec *iov = uio->uio_iov;
65 	int iol = uio->uio_iovcnt;
66 	unsigned count;
67 
68 	CUIO_SKIP();
69 	while (len > 0) {
70 		KASSERT(iol >= 0, ("%s: empty", __func__));
71 		count = min(iov->iov_len - off, len);
72 		bcopy(((caddr_t)iov->iov_base) + off, cp, count);
73 		len -= count;
74 		cp += count;
75 		off = 0;
76 		iol--;
77 		iov++;
78 	}
79 }
80 
81 void
82 cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp)
83 {
84 	struct iovec *iov = uio->uio_iov;
85 	int iol = uio->uio_iovcnt;
86 	unsigned count;
87 
88 	CUIO_SKIP();
89 	while (len > 0) {
90 		KASSERT(iol >= 0, ("%s: empty", __func__));
91 		count = min(iov->iov_len - off, len);
92 		bcopy(cp, ((caddr_t)iov->iov_base) + off, count);
93 		len -= count;
94 		cp += count;
95 		off = 0;
96 		iol--;
97 		iov++;
98 	}
99 }
100 
101 /*
102  * Return the index and offset of location in iovec list.
103  */
104 int
105 cuio_getptr(struct uio *uio, int loc, int *off)
106 {
107 	int ind, len;
108 
109 	ind = 0;
110 	while (loc >= 0 && ind < uio->uio_iovcnt) {
111 		len = uio->uio_iov[ind].iov_len;
112 		if (len > loc) {
113 	    		*off = loc;
114 	    		return (ind);
115 		}
116 		loc -= len;
117 		ind++;
118 	}
119 
120 	if (ind > 0 && loc == 0) {
121 		ind--;
122 		*off = uio->uio_iov[ind].iov_len;
123 		return (ind);
124 	}
125 
126 	return (-1);
127 }
128 
129 /*
130  * Apply function f to the data in an iovec list starting "off" bytes from
131  * the beginning, continuing for "len" bytes.
132  */
133 int
134 cuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int),
135     void *arg)
136 {
137 	struct iovec *iov = uio->uio_iov;
138 	int iol = uio->uio_iovcnt;
139 	unsigned count;
140 	int rval;
141 
142 	CUIO_SKIP();
143 	while (len > 0) {
144 		KASSERT(iol >= 0, ("%s: empty", __func__));
145 		count = min(iov->iov_len - off, len);
146 		rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count);
147 		if (rval)
148 			return (rval);
149 		len -= count;
150 		off = 0;
151 		iol--;
152 		iov++;
153 	}
154 	return (0);
155 }
156 
157 void
158 crypto_copyback(int flags, caddr_t buf, int off, int size, c_caddr_t in)
159 {
160 
161 	if ((flags & CRYPTO_F_IMBUF) != 0)
162 		m_copyback((struct mbuf *)buf, off, size, in);
163 	else if ((flags & CRYPTO_F_IOV) != 0)
164 		cuio_copyback((struct uio *)buf, off, size, in);
165 	else
166 		bcopy(in, buf + off, size);
167 }
168 
169 void
170 crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
171 {
172 
173 	if ((flags & CRYPTO_F_IMBUF) != 0)
174 		m_copydata((struct mbuf *)buf, off, size, out);
175 	else if ((flags & CRYPTO_F_IOV) != 0)
176 		cuio_copydata((struct uio *)buf, off, size, out);
177 	else
178 		bcopy(buf + off, out, size);
179 }
180 
181 int
182 crypto_apply(int flags, caddr_t buf, int off, int len,
183     int (*f)(void *, void *, u_int), void *arg)
184 {
185 	int error;
186 
187 	if ((flags & CRYPTO_F_IMBUF) != 0)
188 		error = m_apply((struct mbuf *)buf, off, len, f, arg);
189 	else if ((flags & CRYPTO_F_IOV) != 0)
190 		error = cuio_apply((struct uio *)buf, off, len, f, arg);
191 	else
192 		error = (*f)(arg, buf + off, len);
193 	return (error);
194 }
195 
196 int
197 crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt,
198     int *allocated)
199 {
200 	struct iovec *iov;
201 	struct mbuf *m, *mtmp;
202 	int i, j;
203 
204 	*allocated = 0;
205 	iov = *iovptr;
206 	if (iov == NULL)
207 		*cnt = 0;
208 
209 	m = mbuf;
210 	i = 0;
211 	while (m != NULL) {
212 		if (i == *cnt) {
213 			/* we need to allocate a larger array */
214 			j = 1;
215 			mtmp = m;
216 			while ((mtmp = mtmp->m_next) != NULL)
217 				j++;
218 			iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA,
219 			    M_NOWAIT);
220 			if (iov == NULL)
221 				return ENOMEM;
222 			*allocated = 1;
223 			*cnt = i + j;
224 			memcpy(iov, *iovptr, sizeof *iov * i);
225 		}
226 
227 		iov[i].iov_base = m->m_data;
228 		iov[i].iov_len = m->m_len;
229 
230 		i++;
231 		m = m->m_next;
232 	}
233 
234 	if (*allocated)
235 		KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d",
236 		    *cnt, i));
237 
238 	*iovptr = iov;
239 	*cnt = i;
240 	return 0;
241 }
242