1 /* $NetBSD: cgd.c,v 1.12 2003/06/29 22:29:58 fvdl Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roland C. Dowdeswell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.12 2003/06/29 22:29:58 fvdl Exp $"); 41 42 #include <sys/types.h> 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/errno.h> 47 #include <sys/buf.h> 48 #include <sys/malloc.h> 49 #include <sys/pool.h> 50 #include <sys/ioctl.h> 51 #include <sys/device.h> 52 #include <sys/disk.h> 53 #include <sys/disklabel.h> 54 #include <sys/fcntl.h> 55 #include <sys/vnode.h> 56 #include <sys/lock.h> 57 #include <sys/conf.h> 58 59 #include <dev/dkvar.h> 60 #include <dev/cgdvar.h> 61 62 /* Entry Point Functions */ 63 64 void cgdattach(int); 65 66 dev_type_open(cgdopen); 67 dev_type_close(cgdclose); 68 dev_type_read(cgdread); 69 dev_type_write(cgdwrite); 70 dev_type_ioctl(cgdioctl); 71 dev_type_strategy(cgdstrategy); 72 dev_type_dump(cgddump); 73 dev_type_size(cgdsize); 74 75 const struct bdevsw cgd_bdevsw = { 76 cgdopen, cgdclose, cgdstrategy, cgdioctl, 77 cgddump, cgdsize, D_DISK 78 }; 79 80 const struct cdevsw cgd_cdevsw = { 81 cgdopen, cgdclose, cgdread, cgdwrite, cgdioctl, 82 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 83 }; 84 85 /* Internal Functions */ 86 87 static void cgdstart(struct dk_softc *, struct buf *); 88 static void cgdiodone(struct buf *); 89 90 static int cgd_ioctl_set(struct cgd_softc *, void *, struct proc *); 91 static int cgd_ioctl_clr(struct cgd_softc *, void *, struct proc *); 92 static int cgdinit(struct cgd_softc *, char *, struct vnode *, 93 struct proc *); 94 static void cgd_cipher(struct cgd_softc *, caddr_t, caddr_t, 95 size_t, daddr_t, size_t, int); 96 97 /* Pseudo-disk Interface */ 98 99 static struct dk_intf the_dkintf = { 100 DTYPE_CGD, 101 "cgd", 102 cgdopen, 103 cgdclose, 104 cgdstrategy, 105 cgdstart, 106 }; 107 static struct dk_intf *di = &the_dkintf; 108 109 /* DIAGNOSTIC and DEBUG definitions */ 110 111 #if defined(CGDDEBUG) && !defined(DEBUG) 112 #define DEBUG 113 #endif 114 115 #ifdef DEBUG 116 int cgddebug = 0; 117 118 #define CGDB_FOLLOW 0x1 119 #define CGDB_IO 0x2 120 #define CGDB_CRYPTO 0x4 121 122 #define IFDEBUG(x,y) if (cgddebug & (x)) y 123 #define DPRINTF(x,y) IFDEBUG(x, printf y) 124 #define DPRINTF_FOLLOW(y) DPRINTF(CGDB_FOLLOW, y) 125 126 static void hexprint(char *, void *, int); 127 128 #else 129 #define IFDEBUG(x,y) 130 #define DPRINTF(x,y) 131 #define DPRINTF_FOLLOW(y) 132 #endif 133 134 #ifdef DIAGNOSTIC 135 #define DIAGPANIC(x) panic x 136 #define DIAGCONDPANIC(x,y) if (x) panic y 137 #else 138 #define DIAGPANIC(x) 139 #define DIAGCONDPANIC(x,y) 140 #endif 141 142 /* Component Buffer Pool structures and macros */ 143 144 struct cgdbuf { 145 struct buf cb_buf; /* new I/O buf */ 146 struct buf *cb_obp; /* ptr. to original I/O buf */ 147 struct cgd_softc *cb_sc; /* pointer to cgd softc */ 148 }; 149 150 struct pool cgd_cbufpool; 151 152 #define CGD_GETBUF() pool_get(&cgd_cbufpool, PR_NOWAIT) 153 #define CGD_PUTBUF(cbp) pool_put(&cgd_cbufpool, cbp) 154 155 /* Global variables */ 156 157 struct cgd_softc *cgd_softc; 158 int numcgd = 0; 159 160 /* Utility Functions */ 161 162 #define CGDUNIT(x) DISKUNIT(x) 163 #define GETCGD_SOFTC(_cs, x) if (!((_cs) = getcgd_softc(x))) return ENXIO 164 165 static struct cgd_softc * 166 getcgd_softc(dev_t dev) 167 { 168 int unit = CGDUNIT(dev); 169 170 DPRINTF_FOLLOW(("getcgd_softc(0x%x): unit = %d\n", dev, unit)); 171 if (unit >= numcgd) 172 return NULL; 173 return &cgd_softc[unit]; 174 } 175 176 /* The code */ 177 178 static void 179 cgdsoftc_init(struct cgd_softc *cs, int num) 180 { 181 char buf[DK_XNAME_SIZE]; 182 183 memset(cs, 0x0, sizeof(*cs)); 184 snprintf(buf, DK_XNAME_SIZE, "cgd%d", num); 185 dk_sc_init(&cs->sc_dksc, cs, buf); 186 } 187 188 void 189 cgdattach(int num) 190 { 191 int i; 192 193 DPRINTF_FOLLOW(("cgdattach(%d)\n", num)); 194 if (num <= 0) { 195 DIAGPANIC(("cgdattach: count <= 0")); 196 return; 197 } 198 199 cgd_softc = (void *)malloc(num * sizeof(*cgd_softc), M_DEVBUF, M_NOWAIT); 200 if (!cgd_softc) { 201 printf("WARNING: unable to malloc(9) memory for crypt disks\n"); 202 DIAGPANIC(("cgdattach: cannot malloc(9) enough memory")); 203 return; 204 } 205 206 numcgd = num; 207 for (i=0; i<num; i++) 208 cgdsoftc_init(&cgd_softc[i], i); 209 210 /* Init component buffer pool. XXX, can we put this in dksubr.c? */ 211 pool_init(&cgd_cbufpool, sizeof(struct cgdbuf), 0, 0, 0, 212 "cgdpl", NULL); 213 } 214 215 int 216 cgdopen(dev_t dev, int flags, int fmt, struct proc *p) 217 { 218 struct cgd_softc *cs; 219 220 DPRINTF_FOLLOW(("cgdopen(%d, %d)\n", dev, flags)); 221 GETCGD_SOFTC(cs, dev); 222 return dk_open(di, &cs->sc_dksc, dev, flags, fmt, p); 223 } 224 225 int 226 cgdclose(dev_t dev, int flags, int fmt, struct proc *p) 227 { 228 struct cgd_softc *cs; 229 230 DPRINTF_FOLLOW(("cgdclose(%d, %d)\n", dev, flags)); 231 GETCGD_SOFTC(cs, dev); 232 return dk_close(di, &cs->sc_dksc, dev, flags, fmt, p); 233 } 234 235 void 236 cgdstrategy(struct buf *bp) 237 { 238 struct cgd_softc *cs = getcgd_softc(bp->b_dev); 239 240 DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp, 241 (long)bp->b_bcount)); 242 /* XXXrcd: Should we test for (cs != NULL)? */ 243 dk_strategy(di, &cs->sc_dksc, bp); 244 return; 245 } 246 247 int 248 cgdsize(dev_t dev) 249 { 250 struct cgd_softc *cs = getcgd_softc(dev); 251 252 DPRINTF_FOLLOW(("cgdsize(%d)\n", dev)); 253 if (!cs) 254 return -1; 255 return dk_size(di, &cs->sc_dksc, dev); 256 } 257 258 static void 259 cgdstart(struct dk_softc *dksc, struct buf *bp) 260 { 261 struct cgd_softc *cs = dksc->sc_osc; 262 struct cgdbuf *cbp; 263 struct partition *pp; 264 caddr_t addr; 265 caddr_t newaddr; 266 daddr_t bn; 267 268 DPRINTF_FOLLOW(("cgdstart(%p, %p)\n", dksc, bp)); 269 disk_busy(&dksc->sc_dkdev); /* XXX: put in dksubr.c */ 270 271 /* XXXrcd: 272 * Translate partition relative blocks to absolute blocks, 273 * this probably belongs (somehow) in dksubr.c, since it 274 * is independant of the underlying code... This will require 275 * that the interface be expanded slightly, though. 276 */ 277 bn = bp->b_blkno; 278 if (DISKPART(bp->b_dev) != RAW_PART) { 279 pp = &cs->sc_dksc.sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)]; 280 bn += pp->p_offset; 281 } 282 283 /* 284 * If we are writing, then we need to encrypt the outgoing 285 * block. In the best case scenario, we are able to allocate 286 * enough memory to encrypt the data in a new block, otherwise 287 * we encrypt it in place (noting we'll have to decrypt it after 288 * the write.) 289 */ 290 newaddr = addr = bp->b_data; 291 if ((bp->b_flags & B_READ) == 0) { 292 newaddr = malloc(bp->b_bcount, M_DEVBUF, 0); 293 if (!newaddr) 294 newaddr = addr; 295 cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn, 296 DEV_BSIZE, CGD_CIPHER_ENCRYPT); 297 } 298 299 cbp = CGD_GETBUF(); 300 if (cbp == NULL) { 301 bp->b_error = ENOMEM; 302 bp->b_flags |= B_ERROR; 303 if (newaddr != addr) 304 free(newaddr, M_DEVBUF); 305 biodone(bp); 306 disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ)); 307 return; 308 } 309 BUF_INIT(&cbp->cb_buf); 310 cbp->cb_buf.b_data = newaddr; 311 cbp->cb_buf.b_flags = bp->b_flags | B_CALL; 312 cbp->cb_buf.b_iodone = cgdiodone; 313 cbp->cb_buf.b_proc = bp->b_proc; 314 cbp->cb_buf.b_dev = cs->sc_tdev; 315 cbp->cb_buf.b_blkno = bn; 316 cbp->cb_buf.b_vp = cs->sc_tvn; 317 cbp->cb_buf.b_bcount = bp->b_bcount; 318 319 /* context for cgdiodone */ 320 cbp->cb_obp = bp; 321 cbp->cb_sc = cs; 322 323 if ((cbp->cb_buf.b_flags & B_READ) == 0) 324 cbp->cb_buf.b_vp->v_numoutput++; 325 VOP_STRATEGY(&cbp->cb_buf); 326 } 327 328 void 329 cgdiodone(struct buf *vbp) 330 { 331 struct cgdbuf *cbp = (struct cgdbuf *)vbp; 332 struct buf *obp = cbp->cb_obp; 333 struct buf *nbp = &cbp->cb_buf; 334 struct cgd_softc *cs = cbp->cb_sc; 335 struct dk_softc *dksc = &cs->sc_dksc; 336 int s; 337 338 DPRINTF_FOLLOW(("cgdiodone(%p)\n", vbp)); 339 DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %ld resid %ld\n", 340 obp, obp->b_bcount, obp->b_resid)); 341 DPRINTF(CGDB_IO, (" dev 0x%x, cbp %p bn %" PRId64 " addr %p bcnt %ld\n", 342 cbp->cb_buf.b_dev, cbp, cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, 343 cbp->cb_buf.b_bcount)); 344 s = splbio(); 345 if (nbp->b_flags & B_ERROR) { 346 obp->b_flags |= B_ERROR; 347 obp->b_error = nbp->b_error ? nbp->b_error : EIO; 348 349 printf("%s: error %d\n", dksc->sc_xname, obp->b_error); 350 } 351 352 /* Perform the decryption if we need to: 353 * o if we are reading, or 354 * o we wrote and couldn't allocate memory. 355 * 356 * Note: use the blocknumber from nbp, since it is what 357 * we used to encrypt the blocks. 358 */ 359 360 if (nbp->b_flags & B_READ || nbp->b_data == obp->b_data) 361 cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount, 362 nbp->b_blkno, DEV_BSIZE, CGD_CIPHER_DECRYPT); 363 364 /* If we managed to allocate memory, free it now... */ 365 if (nbp->b_data != obp->b_data) 366 free(nbp->b_data, M_DEVBUF); 367 368 CGD_PUTBUF(cbp); 369 370 /* Request is complete for whatever reason */ 371 obp->b_resid = 0; 372 if (obp->b_flags & B_ERROR) 373 obp->b_resid = obp->b_bcount; 374 disk_unbusy(&dksc->sc_dkdev, obp->b_bcount - obp->b_resid, 375 (obp->b_flags & B_READ)); 376 biodone(obp); 377 splx(s); 378 } 379 380 /* XXX: we should probably put these into dksubr.c, mostly */ 381 int 382 cgdread(dev_t dev, struct uio *uio, int flags) 383 { 384 struct cgd_softc *cs; 385 struct dk_softc *dksc; 386 387 DPRINTF_FOLLOW(("cgdread(%d, %p, %d)\n", dev, uio, flags)); 388 GETCGD_SOFTC(cs, dev); 389 dksc = &cs->sc_dksc; 390 if ((dksc->sc_flags & DKF_INITED) == 0) 391 return ENXIO; 392 /* XXX see the comments about minphys in ccd.c */ 393 return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio); 394 } 395 396 /* XXX: we should probably put these into dksubr.c, mostly */ 397 int 398 cgdwrite(dev_t dev, struct uio *uio, int flags) 399 { 400 struct cgd_softc *cs; 401 struct dk_softc *dksc; 402 403 DPRINTF_FOLLOW(("cgdwrite(%d, %p, %d)\n", dev, uio, flags)); 404 GETCGD_SOFTC(cs, dev); 405 dksc = &cs->sc_dksc; 406 if ((dksc->sc_flags & DKF_INITED) == 0) 407 return ENXIO; 408 /* XXX see the comments about minphys in ccd.c */ 409 return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio); 410 } 411 412 int 413 cgdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 414 { 415 struct cgd_softc *cs; 416 struct dk_softc *dksc; 417 int ret; 418 int part = DISKPART(dev); 419 int pmask = 1 << part; 420 421 DPRINTF_FOLLOW(("cgdioctl(%d, %ld, %p, %d, %p)\n", 422 dev, cmd, data, flag, p)); 423 GETCGD_SOFTC(cs, dev); 424 dksc = &cs->sc_dksc; 425 switch (cmd) { 426 case CGDIOCSET: 427 case CGDIOCCLR: 428 if ((flag & FWRITE) == 0) 429 return EBADF; 430 } 431 432 if ((ret = lockmgr(&dksc->sc_lock, LK_EXCLUSIVE, NULL)) != 0) 433 return ret; 434 435 switch (cmd) { 436 case CGDIOCSET: 437 if (dksc->sc_flags & DKF_INITED) 438 ret = EBUSY; 439 else 440 ret = cgd_ioctl_set(cs, data, p); 441 break; 442 case CGDIOCCLR: 443 if (!(dksc->sc_flags & DKF_INITED)) { 444 ret = ENXIO; 445 break; 446 } 447 if (DK_BUSY(&cs->sc_dksc, pmask)) { 448 ret = EBUSY; 449 break; 450 } 451 ret = cgd_ioctl_clr(cs, data, p); 452 break; 453 default: 454 ret = dk_ioctl(di, dksc, dev, cmd, data, flag, p); 455 break; 456 } 457 458 lockmgr(&dksc->sc_lock, LK_RELEASE, NULL); 459 return ret; 460 } 461 462 int 463 cgddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 464 { 465 struct cgd_softc *cs; 466 467 DPRINTF_FOLLOW(("cgddump(%d, %" PRId64 ", %p, %lu)\n", dev, blkno, va, 468 (unsigned long)size)); 469 GETCGD_SOFTC(cs, dev); 470 return dk_dump(di, &cs->sc_dksc, dev, blkno, va, size); 471 } 472 473 /* 474 * XXXrcd: 475 * for now we hardcode the maximum key length. 476 */ 477 #define MAX_KEYSIZE 1024 478 479 /* ARGSUSED */ 480 static int 481 cgd_ioctl_set(struct cgd_softc *cs, void *data, struct proc *p) 482 { 483 struct cgd_ioctl *ci = data; 484 struct vnode *vp; 485 int ret; 486 char *cp; 487 char inbuf[MAX_KEYSIZE]; 488 489 cp = ci->ci_disk; 490 if ((ret = dk_lookup(cp, p, &vp)) != 0) 491 return ret; 492 493 if ((ret = cgdinit(cs, cp, vp, p)) != 0) 494 goto bail; 495 496 memset(inbuf, 0x0, sizeof(inbuf)); 497 ret = copyinstr(ci->ci_alg, inbuf, 256, NULL); 498 if (ret) 499 goto bail; 500 cs->sc_cfuncs = cryptfuncs_find(inbuf); 501 if (!cs->sc_cfuncs) { 502 ret = EINVAL; 503 goto bail; 504 } 505 506 /* right now we only support encblkno, so hard-code it */ 507 memset(inbuf, 0x0, sizeof(inbuf)); 508 ret = copyinstr(ci->ci_ivmethod, inbuf, sizeof(inbuf), NULL); 509 if (ret) 510 goto bail; 511 if (strcmp("encblkno", inbuf)) { 512 ret = EINVAL; 513 goto bail; 514 } 515 516 if (ci->ci_keylen > MAX_KEYSIZE) { 517 ret = EINVAL; 518 goto bail; 519 } 520 memset(inbuf, 0x0, sizeof(inbuf)); 521 ret = copyin(ci->ci_key, inbuf, ci->ci_keylen); 522 if (ret) 523 goto bail; 524 525 cs->sc_cdata.cf_blocksize = ci->ci_blocksize; 526 cs->sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO; 527 cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf, 528 &cs->sc_cdata.cf_blocksize); 529 memset(inbuf, 0x0, sizeof(inbuf)); 530 if (!cs->sc_cdata.cf_priv) { 531 printf("cgd: unable to initialize cipher\n"); 532 ret = EINVAL; /* XXX is this the right error? */ 533 goto bail; 534 } 535 536 cs->sc_dksc.sc_flags |= DKF_INITED; 537 538 /* Attach the disk. */ 539 disk_attach(&cs->sc_dksc.sc_dkdev); 540 541 /* Try and read the disklabel. */ 542 dk_getdisklabel(di, &cs->sc_dksc, 0 /* XXX ? */); 543 544 return 0; 545 546 bail: 547 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 548 return ret; 549 } 550 551 /* ARGSUSED */ 552 static int 553 cgd_ioctl_clr(struct cgd_softc *cs, void *data, struct proc *p) 554 { 555 556 (void)vn_close(cs->sc_tvn, FREAD|FWRITE, p->p_ucred, p); 557 cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv); 558 free(cs->sc_tpath, M_DEVBUF); 559 cs->sc_dksc.sc_flags &= ~DKF_INITED; 560 disk_detach(&cs->sc_dksc.sc_dkdev); 561 562 return 0; 563 } 564 565 static int 566 cgdinit(struct cgd_softc *cs, char *cpath, struct vnode *vp, 567 struct proc *p) 568 { 569 struct dk_geom *pdg; 570 struct partinfo dpart; 571 struct vattr va; 572 size_t size; 573 int maxsecsize = 0; 574 int ret; 575 char tmppath[MAXPATHLEN]; 576 577 cs->sc_dksc.sc_size = 0; 578 cs->sc_tvn = vp; 579 580 memset(tmppath, 0x0, sizeof(tmppath)); 581 ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen); 582 if (ret) 583 goto bail; 584 cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK); 585 memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen); 586 587 if ((ret = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) 588 goto bail; 589 590 cs->sc_tdev = va.va_rdev; 591 592 ret = VOP_IOCTL(vp, DIOCGPART, &dpart, FREAD, p->p_ucred, p); 593 if (ret) 594 goto bail; 595 596 maxsecsize = 597 ((dpart.disklab->d_secsize > maxsecsize) ? 598 dpart.disklab->d_secsize : maxsecsize); 599 size = dpart.part->p_size; 600 601 if (!size) { 602 ret = ENODEV; 603 goto bail; 604 } 605 606 cs->sc_dksc.sc_size = size; 607 608 /* 609 * XXX here we should probe the underlying device. If we 610 * are accessing a partition of type RAW_PART, then 611 * we should populate our initial geometry with the 612 * geometry that we discover from the device. 613 */ 614 pdg = &cs->sc_dksc.sc_geom; 615 pdg->pdg_secsize = DEV_BSIZE; 616 pdg->pdg_ntracks = 1; 617 pdg->pdg_nsectors = 1024 * (1024 / pdg->pdg_secsize); 618 pdg->pdg_ncylinders = cs->sc_dksc.sc_size / pdg->pdg_nsectors; 619 620 bail: 621 if (ret && cs->sc_tpath) 622 free(cs->sc_tpath, M_DEVBUF); 623 return ret; 624 } 625 626 /* 627 * Our generic cipher entry point. This takes care of the 628 * IV mode and passes off the work to the specific cipher. 629 * We implement here the IV method ``encrypted block 630 * number''. 631 * 632 * For the encryption case, we accomplish this by setting 633 * up a struct uio where the first iovec of the source is 634 * the blocknumber and the first iovec of the dest is a 635 * sink. We then call the cipher with an IV of zero, and 636 * the right thing happens. 637 * 638 * For the decryption case, we use the same basic mechanism 639 * for symmetry, but we encrypt the block number in the 640 * first iovec. 641 * 642 * We mainly do this to avoid requiring the definition of 643 * an ECB mode. 644 * 645 * XXXrcd: for now we rely on our own crypto framework defined 646 * in dev/cgd_crypto.c. This will change when we 647 * get a generic kernel crypto framework. 648 */ 649 650 static void 651 blkno2blkno_buf(char *buf, daddr_t blkno) 652 { 653 int i; 654 655 /* Set up the blkno in blkno_buf, here we do not care much 656 * about the final layout of the information as long as we 657 * can guarantee that each sector will have a different IV 658 * and that the endianness of the machine will not affect 659 * the representation that we have chosen. 660 * 661 * We choose this representation, because it does not rely 662 * on the size of buf (which is the blocksize of the cipher), 663 * but allows daddr_t to grow without breaking existing 664 * disks. 665 * 666 * Note that blkno2blkno_buf does not take a size as input, 667 * and hence must be called on a pre-zeroed buffer of length 668 * greater than or equal to sizeof(daddr_t). 669 */ 670 for (i=0; i < sizeof(daddr_t); i++) { 671 *buf++ = blkno & 0xff; 672 blkno >>= 8; 673 } 674 } 675 676 static void 677 cgd_cipher(struct cgd_softc *cs, caddr_t dst, caddr_t src, 678 size_t len, daddr_t blkno, size_t secsize, int dir) 679 { 680 cfunc_cipher *cipher = cs->sc_cfuncs->cf_cipher; 681 struct uio dstuio; 682 struct uio srcuio; 683 struct iovec dstiov[2]; 684 struct iovec srciov[2]; 685 int blocksize = cs->sc_cdata.cf_blocksize; 686 char sink[blocksize]; 687 char zero_iv[blocksize]; 688 char blkno_buf[blocksize]; 689 690 DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir)); 691 692 DIAGCONDPANIC(len % blocksize != 0, 693 ("cgd_cipher: len %% blocksize != 0")); 694 695 /* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */ 696 DIAGCONDPANIC(sizeof(daddr_t) > blocksize, 697 ("cgd_cipher: sizeof(daddr_t) > blocksize")); 698 699 memset(zero_iv, 0x0, sizeof(zero_iv)); 700 701 dstuio.uio_iov = dstiov; 702 dstuio.uio_iovcnt = 2; 703 704 srcuio.uio_iov = srciov; 705 srcuio.uio_iovcnt = 2; 706 707 dstiov[0].iov_base = sink; 708 dstiov[0].iov_len = blocksize; 709 srciov[0].iov_base = blkno_buf; 710 srciov[0].iov_len = blocksize; 711 dstiov[1].iov_len = secsize; 712 srciov[1].iov_len = secsize; 713 714 for (; len > 0; len -= secsize) { 715 dstiov[1].iov_base = dst; 716 srciov[1].iov_base = src; 717 718 memset(blkno_buf, 0x0, sizeof(blkno_buf)); 719 blkno2blkno_buf(blkno_buf, blkno); 720 if (dir == CGD_CIPHER_DECRYPT) { 721 dstuio.uio_iovcnt = 1; 722 srcuio.uio_iovcnt = 1; 723 IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf", 724 blkno_buf, sizeof(blkno_buf))); 725 cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, 726 zero_iv, CGD_CIPHER_ENCRYPT); 727 memcpy(blkno_buf, sink, blocksize); 728 dstuio.uio_iovcnt = 2; 729 srcuio.uio_iovcnt = 2; 730 } 731 732 IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf", 733 blkno_buf, sizeof(blkno_buf))); 734 cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir); 735 IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink", 736 sink, sizeof(sink))); 737 738 dst += secsize; 739 src += secsize; 740 blkno++; 741 } 742 } 743 744 #ifdef DEBUG 745 static void 746 hexprint(char *start, void *buf, int len) 747 { 748 char *c = buf; 749 750 DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0")); 751 printf("%s: len=%06d 0x", start, len); 752 while (len--) 753 printf("%02x", (unsigned) *c++); 754 } 755 #endif 756