Annotation of src/sys/dev/cgd.c, Revision 1.17
1.17 ! dbj 1: /* $NetBSD: cgd.c,v 1.16 2004/03/27 23:23:06 elric Exp $ */
1.1 elric 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>
1.17 ! dbj 40: __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.16 2004/03/27 23:23:06 elric Exp $");
1.1 elric 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,
1.4 jdolecek 82: nostop, notty, nopoll, nommap, nokqfilter, D_DISK
1.1 elric 83: };
84:
85: /* Internal Functions */
86:
1.16 elric 87: static int cgdstart(struct dk_softc *, struct buf *);
1.1 elric 88: static void cgdiodone(struct buf *);
89:
1.12 fvdl 90: static int cgd_ioctl_set(struct cgd_softc *, void *, struct proc *);
91: static int cgd_ioctl_clr(struct cgd_softc *, void *, struct proc *);
1.1 elric 92: static int cgdinit(struct cgd_softc *, char *, struct vnode *,
1.12 fvdl 93: struct proc *);
1.1 elric 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: /* Global variables */
143:
144: struct cgd_softc *cgd_softc;
145: int numcgd = 0;
146:
147: /* Utility Functions */
148:
149: #define CGDUNIT(x) DISKUNIT(x)
150: #define GETCGD_SOFTC(_cs, x) if (!((_cs) = getcgd_softc(x))) return ENXIO
151:
152: static struct cgd_softc *
153: getcgd_softc(dev_t dev)
154: {
155: int unit = CGDUNIT(dev);
156:
157: DPRINTF_FOLLOW(("getcgd_softc(0x%x): unit = %d\n", dev, unit));
158: if (unit >= numcgd)
159: return NULL;
160: return &cgd_softc[unit];
161: }
162:
163: /* The code */
164:
165: static void
166: cgdsoftc_init(struct cgd_softc *cs, int num)
167: {
168: char buf[DK_XNAME_SIZE];
169:
170: memset(cs, 0x0, sizeof(*cs));
171: snprintf(buf, DK_XNAME_SIZE, "cgd%d", num);
1.16 elric 172: simple_lock_init(&cs->sc_slock);
1.1 elric 173: dk_sc_init(&cs->sc_dksc, cs, buf);
174: }
175:
176: void
177: cgdattach(int num)
178: {
179: int i;
180:
181: DPRINTF_FOLLOW(("cgdattach(%d)\n", num));
182: if (num <= 0) {
183: DIAGPANIC(("cgdattach: count <= 0"));
184: return;
185: }
186:
1.10 agc 187: cgd_softc = (void *)malloc(num * sizeof(*cgd_softc), M_DEVBUF, M_NOWAIT);
188: if (!cgd_softc) {
1.1 elric 189: printf("WARNING: unable to malloc(9) memory for crypt disks\n");
190: DIAGPANIC(("cgdattach: cannot malloc(9) enough memory"));
191: return;
192: }
193:
194: numcgd = num;
195: for (i=0; i<num; i++)
196: cgdsoftc_init(&cgd_softc[i], i);
197: }
198:
199: int
1.12 fvdl 200: cgdopen(dev_t dev, int flags, int fmt, struct proc *p)
1.1 elric 201: {
202: struct cgd_softc *cs;
203:
204: DPRINTF_FOLLOW(("cgdopen(%d, %d)\n", dev, flags));
205: GETCGD_SOFTC(cs, dev);
1.12 fvdl 206: return dk_open(di, &cs->sc_dksc, dev, flags, fmt, p);
1.1 elric 207: }
208:
209: int
1.12 fvdl 210: cgdclose(dev_t dev, int flags, int fmt, struct proc *p)
1.1 elric 211: {
212: struct cgd_softc *cs;
213:
214: DPRINTF_FOLLOW(("cgdclose(%d, %d)\n", dev, flags));
215: GETCGD_SOFTC(cs, dev);
1.12 fvdl 216: return dk_close(di, &cs->sc_dksc, dev, flags, fmt, p);
1.1 elric 217: }
218:
219: void
220: cgdstrategy(struct buf *bp)
221: {
222: struct cgd_softc *cs = getcgd_softc(bp->b_dev);
223:
224: DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp,
225: (long)bp->b_bcount));
226: /* XXXrcd: Should we test for (cs != NULL)? */
227: dk_strategy(di, &cs->sc_dksc, bp);
228: return;
229: }
230:
231: int
232: cgdsize(dev_t dev)
233: {
234: struct cgd_softc *cs = getcgd_softc(dev);
235:
236: DPRINTF_FOLLOW(("cgdsize(%d)\n", dev));
237: if (!cs)
238: return -1;
239: return dk_size(di, &cs->sc_dksc, dev);
240: }
241:
1.16 elric 242: /*
243: * cgd_{get,put}data are functions that deal with getting a buffer
244: * for the new encrypted data. We have a buffer per device so that
245: * we can ensure that we can always have a transaction in flight.
246: * We use this buffer first so that we have one less piece of
247: * malloc'ed data at any given point.
248: */
249:
250: static void *
251: cgd_getdata(struct dk_softc *dksc, unsigned long size)
252: {
253: struct cgd_softc *cs =dksc->sc_osc;
254: caddr_t data = NULL;
255:
256: simple_lock(&cs->sc_slock);
257: if (cs->sc_data_used == 0) {
258: cs->sc_data_used = 1;
259: data = cs->sc_data;
260: }
261: simple_unlock(&cs->sc_slock);
262:
263: if (data)
264: return data;
265:
266: return malloc(size, M_DEVBUF, M_NOWAIT);
267: }
268:
1.1 elric 269: static void
1.16 elric 270: cgd_putdata(struct dk_softc *dksc, caddr_t data)
271: {
272: struct cgd_softc *cs =dksc->sc_osc;
273:
274: if (data == cs->sc_data) {
275: simple_lock(&cs->sc_slock);
276: cs->sc_data_used = 0;
277: simple_unlock(&cs->sc_slock);
278: } else {
279: free(data, M_DEVBUF);
280: }
281: }
282:
283: static int
1.1 elric 284: cgdstart(struct dk_softc *dksc, struct buf *bp)
285: {
286: struct cgd_softc *cs = dksc->sc_osc;
1.17 ! dbj 287: struct buf *nbp;
1.1 elric 288: struct partition *pp;
289: caddr_t addr;
290: caddr_t newaddr;
291: daddr_t bn;
1.17 ! dbj 292: int s;
1.1 elric 293:
294: DPRINTF_FOLLOW(("cgdstart(%p, %p)\n", dksc, bp));
295: disk_busy(&dksc->sc_dkdev); /* XXX: put in dksubr.c */
296:
297: /* XXXrcd:
298: * Translate partition relative blocks to absolute blocks,
299: * this probably belongs (somehow) in dksubr.c, since it
300: * is independant of the underlying code... This will require
301: * that the interface be expanded slightly, though.
302: */
303: bn = bp->b_blkno;
304: if (DISKPART(bp->b_dev) != RAW_PART) {
305: pp = &cs->sc_dksc.sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
306: bn += pp->p_offset;
307: }
308:
309: /*
1.16 elric 310: * We attempt to allocate all of our resources up front, so that
311: * we can fail quickly if they are unavailable.
312: */
1.17 ! dbj 313:
! 314: s = splbio();
! 315: nbp = pool_get(&bufpool, PR_NOWAIT);
! 316: splx(s);
! 317: if (nbp == NULL) {
1.16 elric 318: disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
319: return -1;
320: }
321:
322: /*
1.1 elric 323: * If we are writing, then we need to encrypt the outgoing
1.16 elric 324: * block into a new block of memory. If we fail, then we
325: * return an error and let the dksubr framework deal with it.
1.1 elric 326: */
327: newaddr = addr = bp->b_data;
328: if ((bp->b_flags & B_READ) == 0) {
1.16 elric 329: newaddr = cgd_getdata(dksc, bp->b_bcount);
330: if (!newaddr) {
1.17 ! dbj 331: s = splbio();
! 332: pool_put(&bufpool, nbp);
! 333: splx(s);
1.16 elric 334: disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
335: return -1;
336: }
1.1 elric 337: cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn,
338: DEV_BSIZE, CGD_CIPHER_ENCRYPT);
339: }
340:
1.17 ! dbj 341: BUF_INIT(nbp);
! 342: nbp->b_data = newaddr;
! 343: nbp->b_flags = bp->b_flags | B_CALL;
! 344: nbp->b_iodone = cgdiodone;
! 345: nbp->b_proc = bp->b_proc;
! 346: nbp->b_blkno = bn;
! 347: nbp->b_vp = cs->sc_tvn;
! 348: nbp->b_bcount = bp->b_bcount;
! 349: nbp->b_private = bp;
! 350:
! 351: BIO_COPYPRIO(nbp, bp);
! 352:
! 353: if ((nbp->b_flags & B_READ) == 0) {
! 354: V_INCR_NUMOUTPUT(nbp->b_vp);
! 355: }
! 356: VOP_STRATEGY(cs->sc_tvn, nbp);
1.16 elric 357: return 0;
1.1 elric 358: }
359:
1.17 ! dbj 360: /* expected to be called at splbio() */
1.1 elric 361: void
1.17 ! dbj 362: cgdiodone(struct buf *nbp)
1.1 elric 363: {
1.17 ! dbj 364: struct buf *obp = nbp->b_private;
! 365: struct cgd_softc *cs = getcgd_softc(obp->b_dev);
1.1 elric 366: struct dk_softc *dksc = &cs->sc_dksc;
1.17 ! dbj 367:
! 368: KDASSERT(cs);
1.1 elric 369:
1.17 ! dbj 370: DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp));
1.1 elric 371: DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %ld resid %ld\n",
372: obp, obp->b_bcount, obp->b_resid));
1.17 ! dbj 373: DPRINTF(CGDB_IO, (" dev 0x%x, nbp %p bn %" PRId64 " addr %p bcnt %ld\n",
! 374: nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data,
! 375: nbp->b_bcount));
1.1 elric 376: if (nbp->b_flags & B_ERROR) {
377: obp->b_flags |= B_ERROR;
378: obp->b_error = nbp->b_error ? nbp->b_error : EIO;
379:
380: printf("%s: error %d\n", dksc->sc_xname, obp->b_error);
381: }
382:
1.16 elric 383: /* Perform the decryption if we are reading.
1.1 elric 384: *
385: * Note: use the blocknumber from nbp, since it is what
386: * we used to encrypt the blocks.
387: */
388:
1.16 elric 389: if (nbp->b_flags & B_READ)
1.1 elric 390: cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount,
391: nbp->b_blkno, DEV_BSIZE, CGD_CIPHER_DECRYPT);
392:
1.16 elric 393: /* If we allocated memory, free it now... */
1.1 elric 394: if (nbp->b_data != obp->b_data)
1.16 elric 395: cgd_putdata(dksc, nbp->b_data);
1.1 elric 396:
1.17 ! dbj 397: pool_put(&bufpool, nbp);
1.1 elric 398:
399: /* Request is complete for whatever reason */
400: obp->b_resid = 0;
401: if (obp->b_flags & B_ERROR)
402: obp->b_resid = obp->b_bcount;
1.5 mrg 403: disk_unbusy(&dksc->sc_dkdev, obp->b_bcount - obp->b_resid,
404: (obp->b_flags & B_READ));
1.1 elric 405: biodone(obp);
1.16 elric 406: dk_iodone(di, dksc);
1.1 elric 407: }
408:
409: /* XXX: we should probably put these into dksubr.c, mostly */
410: int
411: cgdread(dev_t dev, struct uio *uio, int flags)
412: {
413: struct cgd_softc *cs;
414: struct dk_softc *dksc;
415:
416: DPRINTF_FOLLOW(("cgdread(%d, %p, %d)\n", dev, uio, flags));
417: GETCGD_SOFTC(cs, dev);
418: dksc = &cs->sc_dksc;
419: if ((dksc->sc_flags & DKF_INITED) == 0)
420: return ENXIO;
421: /* XXX see the comments about minphys in ccd.c */
422: return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
423: }
424:
425: /* XXX: we should probably put these into dksubr.c, mostly */
426: int
427: cgdwrite(dev_t dev, struct uio *uio, int flags)
428: {
429: struct cgd_softc *cs;
430: struct dk_softc *dksc;
431:
432: DPRINTF_FOLLOW(("cgdwrite(%d, %p, %d)\n", dev, uio, flags));
433: GETCGD_SOFTC(cs, dev);
434: dksc = &cs->sc_dksc;
435: if ((dksc->sc_flags & DKF_INITED) == 0)
436: return ENXIO;
437: /* XXX see the comments about minphys in ccd.c */
438: return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
439: }
440:
441: int
1.12 fvdl 442: cgdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1.1 elric 443: {
444: struct cgd_softc *cs;
445: struct dk_softc *dksc;
446: int ret;
447: int part = DISKPART(dev);
448: int pmask = 1 << part;
449:
450: DPRINTF_FOLLOW(("cgdioctl(%d, %ld, %p, %d, %p)\n",
1.12 fvdl 451: dev, cmd, data, flag, p));
1.1 elric 452: GETCGD_SOFTC(cs, dev);
453: dksc = &cs->sc_dksc;
454: switch (cmd) {
455: case CGDIOCSET:
456: case CGDIOCCLR:
457: if ((flag & FWRITE) == 0)
458: return EBADF;
459: }
460:
461: if ((ret = lockmgr(&dksc->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
462: return ret;
463:
464: switch (cmd) {
465: case CGDIOCSET:
466: if (dksc->sc_flags & DKF_INITED)
467: ret = EBUSY;
468: else
1.12 fvdl 469: ret = cgd_ioctl_set(cs, data, p);
1.1 elric 470: break;
471: case CGDIOCCLR:
472: if (!(dksc->sc_flags & DKF_INITED)) {
473: ret = ENXIO;
474: break;
475: }
476: if (DK_BUSY(&cs->sc_dksc, pmask)) {
477: ret = EBUSY;
478: break;
479: }
1.12 fvdl 480: ret = cgd_ioctl_clr(cs, data, p);
1.1 elric 481: break;
482: default:
1.12 fvdl 483: ret = dk_ioctl(di, dksc, dev, cmd, data, flag, p);
1.1 elric 484: break;
485: }
486:
487: lockmgr(&dksc->sc_lock, LK_RELEASE, NULL);
488: return ret;
489: }
490:
491: int
492: cgddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
493: {
494: struct cgd_softc *cs;
495:
1.6 bouyer 496: DPRINTF_FOLLOW(("cgddump(%d, %" PRId64 ", %p, %lu)\n", dev, blkno, va,
1.2 elric 497: (unsigned long)size));
1.1 elric 498: GETCGD_SOFTC(cs, dev);
499: return dk_dump(di, &cs->sc_dksc, dev, blkno, va, size);
500: }
501:
502: /*
503: * XXXrcd:
504: * for now we hardcode the maximum key length.
505: */
506: #define MAX_KEYSIZE 1024
507:
508: /* ARGSUSED */
509: static int
1.12 fvdl 510: cgd_ioctl_set(struct cgd_softc *cs, void *data, struct proc *p)
1.1 elric 511: {
512: struct cgd_ioctl *ci = data;
513: struct vnode *vp;
514: int ret;
1.15 dan 515: int keybytes; /* key length in bytes */
1.1 elric 516: char *cp;
517: char inbuf[MAX_KEYSIZE];
518:
519: cp = ci->ci_disk;
1.12 fvdl 520: if ((ret = dk_lookup(cp, p, &vp)) != 0)
1.1 elric 521: return ret;
522:
1.12 fvdl 523: if ((ret = cgdinit(cs, cp, vp, p)) != 0)
1.1 elric 524: goto bail;
525:
526: memset(inbuf, 0x0, sizeof(inbuf));
527: ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
528: if (ret)
529: goto bail;
530: cs->sc_cfuncs = cryptfuncs_find(inbuf);
531: if (!cs->sc_cfuncs) {
532: ret = EINVAL;
533: goto bail;
534: }
535:
536: /* right now we only support encblkno, so hard-code it */
537: memset(inbuf, 0x0, sizeof(inbuf));
538: ret = copyinstr(ci->ci_ivmethod, inbuf, sizeof(inbuf), NULL);
539: if (ret)
540: goto bail;
541: if (strcmp("encblkno", inbuf)) {
542: ret = EINVAL;
543: goto bail;
544: }
545:
1.15 dan 546: keybytes = ci->ci_keylen / 8 + 1;
547: if (keybytes > MAX_KEYSIZE) {
1.1 elric 548: ret = EINVAL;
549: goto bail;
550: }
551: memset(inbuf, 0x0, sizeof(inbuf));
1.15 dan 552: ret = copyin(ci->ci_key, inbuf, keybytes);
1.1 elric 553: if (ret)
554: goto bail;
555:
556: cs->sc_cdata.cf_blocksize = ci->ci_blocksize;
557: cs->sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO;
558: cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
559: &cs->sc_cdata.cf_blocksize);
560: memset(inbuf, 0x0, sizeof(inbuf));
561: if (!cs->sc_cdata.cf_priv) {
562: printf("cgd: unable to initialize cipher\n");
563: ret = EINVAL; /* XXX is this the right error? */
564: goto bail;
565: }
566:
1.16 elric 567: bufq_alloc(&cs->sc_dksc.sc_bufq, BUFQ_FCFS);
568:
569: cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK);
570: cs->sc_data_used = 0;
571:
1.1 elric 572: cs->sc_dksc.sc_flags |= DKF_INITED;
573:
574: /* Attach the disk. */
575: disk_attach(&cs->sc_dksc.sc_dkdev);
576:
577: /* Try and read the disklabel. */
578: dk_getdisklabel(di, &cs->sc_dksc, 0 /* XXX ? */);
579:
580: return 0;
581:
582: bail:
1.12 fvdl 583: (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1.1 elric 584: return ret;
585: }
586:
587: /* ARGSUSED */
588: static int
1.12 fvdl 589: cgd_ioctl_clr(struct cgd_softc *cs, void *data, struct proc *p)
1.1 elric 590: {
1.16 elric 591: struct buf *bp;
592: int s;
593:
594: /* Kill off any queued buffers. */
595: s = splbio();
596: while ((bp = BUFQ_GET(&cs->sc_dksc.sc_bufq)) != NULL) {
597: bp->b_error = EIO;
598: bp->b_flags |= B_ERROR;
599: bp->b_resid = bp->b_bcount;
600: biodone(bp);
601: }
602: splx(s);
603: bufq_free(&cs->sc_dksc.sc_bufq);
1.1 elric 604:
1.12 fvdl 605: (void)vn_close(cs->sc_tvn, FREAD|FWRITE, p->p_ucred, p);
1.1 elric 606: cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv);
607: free(cs->sc_tpath, M_DEVBUF);
1.16 elric 608: free(cs->sc_data, M_DEVBUF);
609: cs->sc_data_used = 0;
1.1 elric 610: cs->sc_dksc.sc_flags &= ~DKF_INITED;
611: disk_detach(&cs->sc_dksc.sc_dkdev);
612:
613: return 0;
614: }
615:
616: static int
617: cgdinit(struct cgd_softc *cs, char *cpath, struct vnode *vp,
1.12 fvdl 618: struct proc *p)
1.1 elric 619: {
620: struct dk_geom *pdg;
621: struct partinfo dpart;
622: struct vattr va;
623: size_t size;
624: int maxsecsize = 0;
625: int ret;
626: char tmppath[MAXPATHLEN];
627:
628: cs->sc_dksc.sc_size = 0;
629: cs->sc_tvn = vp;
630:
631: memset(tmppath, 0x0, sizeof(tmppath));
632: ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen);
633: if (ret)
634: goto bail;
635: cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK);
636: memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen);
637:
1.12 fvdl 638: if ((ret = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0)
1.1 elric 639: goto bail;
640:
641: cs->sc_tdev = va.va_rdev;
642:
1.12 fvdl 643: ret = VOP_IOCTL(vp, DIOCGPART, &dpart, FREAD, p->p_ucred, p);
1.1 elric 644: if (ret)
645: goto bail;
646:
647: maxsecsize =
648: ((dpart.disklab->d_secsize > maxsecsize) ?
649: dpart.disklab->d_secsize : maxsecsize);
650: size = dpart.part->p_size;
651:
652: if (!size) {
653: ret = ENODEV;
654: goto bail;
655: }
656:
657: cs->sc_dksc.sc_size = size;
658:
659: /*
660: * XXX here we should probe the underlying device. If we
661: * are accessing a partition of type RAW_PART, then
662: * we should populate our initial geometry with the
663: * geometry that we discover from the device.
664: */
665: pdg = &cs->sc_dksc.sc_geom;
666: pdg->pdg_secsize = DEV_BSIZE;
667: pdg->pdg_ntracks = 1;
668: pdg->pdg_nsectors = 1024 * (1024 / pdg->pdg_secsize);
669: pdg->pdg_ncylinders = cs->sc_dksc.sc_size / pdg->pdg_nsectors;
670:
671: bail:
672: if (ret && cs->sc_tpath)
673: free(cs->sc_tpath, M_DEVBUF);
674: return ret;
675: }
676:
677: /*
678: * Our generic cipher entry point. This takes care of the
679: * IV mode and passes off the work to the specific cipher.
680: * We implement here the IV method ``encrypted block
681: * number''.
682: *
683: * For the encryption case, we accomplish this by setting
684: * up a struct uio where the first iovec of the source is
685: * the blocknumber and the first iovec of the dest is a
686: * sink. We then call the cipher with an IV of zero, and
687: * the right thing happens.
688: *
689: * For the decryption case, we use the same basic mechanism
690: * for symmetry, but we encrypt the block number in the
691: * first iovec.
692: *
693: * We mainly do this to avoid requiring the definition of
694: * an ECB mode.
695: *
696: * XXXrcd: for now we rely on our own crypto framework defined
697: * in dev/cgd_crypto.c. This will change when we
698: * get a generic kernel crypto framework.
699: */
700:
701: static void
702: blkno2blkno_buf(char *buf, daddr_t blkno)
703: {
704: int i;
705:
706: /* Set up the blkno in blkno_buf, here we do not care much
707: * about the final layout of the information as long as we
708: * can guarantee that each sector will have a different IV
709: * and that the endianness of the machine will not affect
710: * the representation that we have chosen.
711: *
712: * We choose this representation, because it does not rely
713: * on the size of buf (which is the blocksize of the cipher),
714: * but allows daddr_t to grow without breaking existing
715: * disks.
716: *
717: * Note that blkno2blkno_buf does not take a size as input,
718: * and hence must be called on a pre-zeroed buffer of length
719: * greater than or equal to sizeof(daddr_t).
720: */
721: for (i=0; i < sizeof(daddr_t); i++) {
722: *buf++ = blkno & 0xff;
723: blkno >>= 8;
724: }
725: }
726:
727: static void
728: cgd_cipher(struct cgd_softc *cs, caddr_t dst, caddr_t src,
729: size_t len, daddr_t blkno, size_t secsize, int dir)
730: {
731: cfunc_cipher *cipher = cs->sc_cfuncs->cf_cipher;
732: struct uio dstuio;
733: struct uio srcuio;
734: struct iovec dstiov[2];
735: struct iovec srciov[2];
736: int blocksize = cs->sc_cdata.cf_blocksize;
737: char sink[blocksize];
738: char zero_iv[blocksize];
739: char blkno_buf[blocksize];
740:
741: DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
742:
743: DIAGCONDPANIC(len % blocksize != 0,
744: ("cgd_cipher: len %% blocksize != 0"));
745:
746: /* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
747: DIAGCONDPANIC(sizeof(daddr_t) > blocksize,
748: ("cgd_cipher: sizeof(daddr_t) > blocksize"));
749:
750: memset(zero_iv, 0x0, sizeof(zero_iv));
751:
752: dstuio.uio_iov = dstiov;
753: dstuio.uio_iovcnt = 2;
754:
755: srcuio.uio_iov = srciov;
756: srcuio.uio_iovcnt = 2;
757:
758: dstiov[0].iov_base = sink;
759: dstiov[0].iov_len = blocksize;
760: srciov[0].iov_base = blkno_buf;
761: srciov[0].iov_len = blocksize;
762: dstiov[1].iov_len = secsize;
763: srciov[1].iov_len = secsize;
764:
765: for (; len > 0; len -= secsize) {
766: dstiov[1].iov_base = dst;
767: srciov[1].iov_base = src;
768:
769: memset(blkno_buf, 0x0, sizeof(blkno_buf));
770: blkno2blkno_buf(blkno_buf, blkno);
771: if (dir == CGD_CIPHER_DECRYPT) {
772: dstuio.uio_iovcnt = 1;
773: srcuio.uio_iovcnt = 1;
774: IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf",
775: blkno_buf, sizeof(blkno_buf)));
776: cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio,
777: zero_iv, CGD_CIPHER_ENCRYPT);
778: memcpy(blkno_buf, sink, blocksize);
779: dstuio.uio_iovcnt = 2;
780: srcuio.uio_iovcnt = 2;
781: }
782:
783: IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
784: blkno_buf, sizeof(blkno_buf)));
785: cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir);
786: IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink",
787: sink, sizeof(sink)));
788:
789: dst += secsize;
790: src += secsize;
791: blkno++;
792: }
793: }
794:
795: #ifdef DEBUG
796: static void
797: hexprint(char *start, void *buf, int len)
798: {
799: char *c = buf;
800:
801: DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0"));
802: printf("%s: len=%06d 0x", start, len);
803: while (len--)
804: printf("%02x", (unsigned) *c++);
805: }
806: #endif
CVSweb <webmaster@jp.NetBSD.org>