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 #include <sys/limits.h> 42 #include <sys/lock.h> 43 44 #include <opencrypto/cryptodev.h> 45 46 /* 47 * This macro is only for avoiding code duplication, as we need to skip 48 * given number of bytes in the same way in three functions below. 49 */ 50 #define CUIO_SKIP() do { \ 51 KASSERT(off >= 0, ("%s: off %d < 0", __func__, off)); \ 52 KASSERT(len >= 0, ("%s: len %d < 0", __func__, len)); \ 53 while (off > 0) { \ 54 KASSERT(iol >= 0, ("%s: empty in skip", __func__)); \ 55 if (off < iov->iov_len) \ 56 break; \ 57 off -= iov->iov_len; \ 58 iol--; \ 59 iov++; \ 60 } \ 61 } while (0) 62 63 void 64 cuio_copydata(struct uio* uio, int off, int len, caddr_t cp) 65 { 66 struct iovec *iov = uio->uio_iov; 67 int iol = uio->uio_iovcnt; 68 unsigned count; 69 70 CUIO_SKIP(); 71 while (len > 0) { 72 KASSERT(iol >= 0, ("%s: empty", __func__)); 73 count = min(iov->iov_len - off, len); 74 bcopy(((caddr_t)iov->iov_base) + off, cp, count); 75 len -= count; 76 cp += count; 77 off = 0; 78 iol--; 79 iov++; 80 } 81 } 82 83 void 84 cuio_copyback(struct uio* uio, int off, int len, c_caddr_t cp) 85 { 86 struct iovec *iov = uio->uio_iov; 87 int iol = uio->uio_iovcnt; 88 unsigned count; 89 90 CUIO_SKIP(); 91 while (len > 0) { 92 KASSERT(iol >= 0, ("%s: empty", __func__)); 93 count = min(iov->iov_len - off, len); 94 bcopy(cp, ((caddr_t)iov->iov_base) + off, count); 95 len -= count; 96 cp += count; 97 off = 0; 98 iol--; 99 iov++; 100 } 101 } 102 103 /* 104 * Return the index and offset of location in iovec list. 105 */ 106 int 107 cuio_getptr(struct uio *uio, int loc, int *off) 108 { 109 int ind, len; 110 111 ind = 0; 112 while (loc >= 0 && ind < uio->uio_iovcnt) { 113 len = uio->uio_iov[ind].iov_len; 114 if (len > loc) { 115 *off = loc; 116 return (ind); 117 } 118 loc -= len; 119 ind++; 120 } 121 122 if (ind > 0 && loc == 0) { 123 ind--; 124 *off = uio->uio_iov[ind].iov_len; 125 return (ind); 126 } 127 128 return (-1); 129 } 130 131 /* 132 * Apply function f to the data in an iovec list starting "off" bytes from 133 * the beginning, continuing for "len" bytes. 134 */ 135 int 136 cuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int), 137 void *arg) 138 { 139 struct iovec *iov = uio->uio_iov; 140 int iol = uio->uio_iovcnt; 141 unsigned count; 142 int rval; 143 144 CUIO_SKIP(); 145 while (len > 0) { 146 KASSERT(iol >= 0, ("%s: empty", __func__)); 147 count = min(iov->iov_len - off, len); 148 rval = (*f)(arg, ((caddr_t)iov->iov_base) + off, count); 149 if (rval) 150 return (rval); 151 len -= count; 152 off = 0; 153 iol--; 154 iov++; 155 } 156 return (0); 157 } 158 159 void 160 crypto_copyback(int flags, caddr_t buf, int off, int size, c_caddr_t in) 161 { 162 163 if ((flags & CRYPTO_F_IMBUF) != 0) 164 m_copyback((struct mbuf *)buf, off, size, in); 165 else if ((flags & CRYPTO_F_IOV) != 0) 166 cuio_copyback((struct uio *)buf, off, size, in); 167 else 168 bcopy(in, buf + off, size); 169 } 170 171 void 172 crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out) 173 { 174 175 if ((flags & CRYPTO_F_IMBUF) != 0) 176 m_copydata((struct mbuf *)buf, off, size, out); 177 else if ((flags & CRYPTO_F_IOV) != 0) 178 cuio_copydata((struct uio *)buf, off, size, out); 179 else 180 bcopy(buf + off, out, size); 181 } 182 183 int 184 crypto_apply(int flags, caddr_t buf, int off, int len, 185 int (*f)(void *, void *, u_int), void *arg) 186 { 187 int error; 188 189 if ((flags & CRYPTO_F_IMBUF) != 0) 190 error = m_apply((struct mbuf *)buf, off, len, f, arg); 191 else if ((flags & CRYPTO_F_IOV) != 0) 192 error = cuio_apply((struct uio *)buf, off, len, f, arg); 193 else 194 error = (*f)(arg, buf + off, len); 195 return (error); 196 } 197 198 int 199 crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt, 200 int *allocated) 201 { 202 struct iovec *iov; 203 struct mbuf *m, *mtmp; 204 int i, j; 205 206 *allocated = 0; 207 iov = *iovptr; 208 if (iov == NULL) 209 *cnt = 0; 210 211 m = mbuf; 212 i = 0; 213 while (m != NULL) { 214 if (i == *cnt) { 215 /* we need to allocate a larger array */ 216 j = 1; 217 mtmp = m; 218 while ((mtmp = mtmp->m_next) != NULL) 219 j++; 220 iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA, 221 M_NOWAIT); 222 if (iov == NULL) 223 return ENOMEM; 224 *allocated = 1; 225 *cnt = i + j; 226 memcpy(iov, *iovptr, sizeof *iov * i); 227 } 228 229 iov[i].iov_base = m->m_data; 230 iov[i].iov_len = m->m_len; 231 232 i++; 233 m = m->m_next; 234 } 235 236 if (*allocated) 237 KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d", 238 *cnt, i)); 239 240 *iovptr = iov; 241 *cnt = i; 242 return 0; 243 } 244 245 static inline void * 246 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len) 247 { 248 int rel_off; 249 250 MPASS(skip <= INT_MAX); 251 252 m = m_getptr(m, (int)skip, &rel_off); 253 if (m == NULL) 254 return (NULL); 255 256 MPASS(rel_off >= 0); 257 skip = rel_off; 258 if (skip + len > m->m_len) 259 return (NULL); 260 261 return (mtod(m, char*) + skip); 262 } 263 264 static inline void * 265 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len) 266 { 267 int rel_off, idx; 268 269 MPASS(skip <= INT_MAX); 270 idx = cuio_getptr(uio, (int)skip, &rel_off); 271 if (idx < 0) 272 return (NULL); 273 274 MPASS(rel_off >= 0); 275 skip = rel_off; 276 if (skip + len > uio->uio_iov[idx].iov_len) 277 return (NULL); 278 return ((char *)uio->uio_iov[idx].iov_base + skip); 279 } 280 281 void * 282 crypto_contiguous_subsegment(int crp_flags, void *crpbuf, 283 size_t skip, size_t len) 284 { 285 if ((crp_flags & CRYPTO_F_IMBUF) != 0) 286 return (m_contiguous_subsegment(crpbuf, skip, len)); 287 else if ((crp_flags & CRYPTO_F_IOV) != 0) 288 return (cuio_contiguous_segment(crpbuf, skip, len)); 289 else { 290 MPASS((crp_flags & (CRYPTO_F_IMBUF | CRYPTO_F_IOV)) != 291 (CRYPTO_F_IMBUF | CRYPTO_F_IOV)); 292 return ((char*)crpbuf + skip); 293 } 294 } 295 296