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