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