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(struct cryptop *crp, int off, int size, const void *src) 161 { 162 163 switch (crp->crp_buf_type) { 164 case CRYPTO_BUF_MBUF: 165 m_copyback(crp->crp_mbuf, off, size, src); 166 break; 167 case CRYPTO_BUF_UIO: 168 cuio_copyback(crp->crp_uio, off, size, src); 169 break; 170 case CRYPTO_BUF_CONTIG: 171 bcopy(src, crp->crp_buf + off, size); 172 break; 173 default: 174 panic("invalid crp buf type %d", crp->crp_buf_type); 175 } 176 } 177 178 void 179 crypto_copydata(struct cryptop *crp, int off, int size, void *dst) 180 { 181 182 switch (crp->crp_buf_type) { 183 case CRYPTO_BUF_MBUF: 184 m_copydata(crp->crp_mbuf, off, size, dst); 185 break; 186 case CRYPTO_BUF_UIO: 187 cuio_copydata(crp->crp_uio, off, size, dst); 188 break; 189 case CRYPTO_BUF_CONTIG: 190 bcopy(crp->crp_buf + off, dst, size); 191 break; 192 default: 193 panic("invalid crp buf type %d", crp->crp_buf_type); 194 } 195 } 196 197 int 198 crypto_apply(struct cryptop *crp, int off, int len, 199 int (*f)(void *, void *, u_int), void *arg) 200 { 201 int error; 202 203 switch (crp->crp_buf_type) { 204 case CRYPTO_BUF_MBUF: 205 error = m_apply(crp->crp_mbuf, off, len, f, arg); 206 break; 207 case CRYPTO_BUF_UIO: 208 error = cuio_apply(crp->crp_uio, off, len, f, arg); 209 break; 210 case CRYPTO_BUF_CONTIG: 211 error = (*f)(arg, crp->crp_buf + off, len); 212 break; 213 default: 214 panic("invalid crp buf type %d", crp->crp_buf_type); 215 } 216 return (error); 217 } 218 219 int 220 crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt, 221 int *allocated) 222 { 223 struct iovec *iov; 224 struct mbuf *m, *mtmp; 225 int i, j; 226 227 *allocated = 0; 228 iov = *iovptr; 229 if (iov == NULL) 230 *cnt = 0; 231 232 m = mbuf; 233 i = 0; 234 while (m != NULL) { 235 if (i == *cnt) { 236 /* we need to allocate a larger array */ 237 j = 1; 238 mtmp = m; 239 while ((mtmp = mtmp->m_next) != NULL) 240 j++; 241 iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA, 242 M_NOWAIT); 243 if (iov == NULL) 244 return ENOMEM; 245 *allocated = 1; 246 *cnt = i + j; 247 memcpy(iov, *iovptr, sizeof *iov * i); 248 } 249 250 iov[i].iov_base = m->m_data; 251 iov[i].iov_len = m->m_len; 252 253 i++; 254 m = m->m_next; 255 } 256 257 if (*allocated) 258 KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d", 259 *cnt, i)); 260 261 *iovptr = iov; 262 *cnt = i; 263 return 0; 264 } 265 266 static inline void * 267 m_contiguous_subsegment(struct mbuf *m, size_t skip, size_t len) 268 { 269 int rel_off; 270 271 MPASS(skip <= INT_MAX); 272 273 m = m_getptr(m, (int)skip, &rel_off); 274 if (m == NULL) 275 return (NULL); 276 277 MPASS(rel_off >= 0); 278 skip = rel_off; 279 if (skip + len > m->m_len) 280 return (NULL); 281 282 return (mtod(m, char*) + skip); 283 } 284 285 static inline void * 286 cuio_contiguous_segment(struct uio *uio, size_t skip, size_t len) 287 { 288 int rel_off, idx; 289 290 MPASS(skip <= INT_MAX); 291 idx = cuio_getptr(uio, (int)skip, &rel_off); 292 if (idx < 0) 293 return (NULL); 294 295 MPASS(rel_off >= 0); 296 skip = rel_off; 297 if (skip + len > uio->uio_iov[idx].iov_len) 298 return (NULL); 299 return ((char *)uio->uio_iov[idx].iov_base + skip); 300 } 301 302 void * 303 crypto_contiguous_subsegment(struct cryptop *crp, size_t skip, size_t len) 304 { 305 306 switch (crp->crp_buf_type) { 307 case CRYPTO_BUF_MBUF: 308 return (m_contiguous_subsegment(crp->crp_mbuf, skip, len)); 309 case CRYPTO_BUF_UIO: 310 return (cuio_contiguous_segment(crp->crp_uio, skip, len)); 311 case CRYPTO_BUF_CONTIG: 312 return (crp->crp_buf + skip); 313 default: 314 panic("invalid crp buf type %d", crp->crp_buf_type); 315 } 316 } 317