Home | History | Annotate | Line # | Download | only in dev
cgd.c revision 1.114.4.6
      1  1.114.4.6  pgoyette /* $NetBSD: cgd.c,v 1.114.4.6 2017/04/29 10:50:46 pgoyette Exp $ */
      2        1.1     elric 
      3        1.1     elric /*-
      4        1.1     elric  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5        1.1     elric  * All rights reserved.
      6        1.1     elric  *
      7        1.1     elric  * This code is derived from software contributed to The NetBSD Foundation
      8        1.1     elric  * by Roland C. Dowdeswell.
      9        1.1     elric  *
     10        1.1     elric  * Redistribution and use in source and binary forms, with or without
     11        1.1     elric  * modification, are permitted provided that the following conditions
     12        1.1     elric  * are met:
     13        1.1     elric  * 1. Redistributions of source code must retain the above copyright
     14        1.1     elric  *    notice, this list of conditions and the following disclaimer.
     15        1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17        1.1     elric  *    documentation and/or other materials provided with the distribution.
     18        1.1     elric  *
     19        1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.1     elric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.1     elric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.1     elric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.1     elric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.1     elric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.1     elric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.1     elric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.1     elric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.1     elric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.1     elric  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1     elric  */
     31        1.1     elric 
     32        1.1     elric #include <sys/cdefs.h>
     33  1.114.4.6  pgoyette __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.114.4.6 2017/04/29 10:50:46 pgoyette Exp $");
     34        1.1     elric 
     35        1.1     elric #include <sys/types.h>
     36        1.1     elric #include <sys/param.h>
     37        1.1     elric #include <sys/systm.h>
     38        1.1     elric #include <sys/proc.h>
     39        1.1     elric #include <sys/errno.h>
     40        1.1     elric #include <sys/buf.h>
     41       1.21      yamt #include <sys/bufq.h>
     42        1.1     elric #include <sys/malloc.h>
     43       1.74    jruoho #include <sys/module.h>
     44        1.1     elric #include <sys/pool.h>
     45        1.1     elric #include <sys/ioctl.h>
     46        1.1     elric #include <sys/device.h>
     47        1.1     elric #include <sys/disk.h>
     48        1.1     elric #include <sys/disklabel.h>
     49        1.1     elric #include <sys/fcntl.h>
     50       1.71  dholland #include <sys/namei.h> /* for pathbuf */
     51        1.1     elric #include <sys/vnode.h>
     52        1.1     elric #include <sys/conf.h>
     53       1.62  christos #include <sys/syslog.h>
     54        1.1     elric 
     55        1.1     elric #include <dev/dkvar.h>
     56        1.1     elric #include <dev/cgdvar.h>
     57        1.1     elric 
     58       1.88   hannken #include <miscfs/specfs/specdev.h> /* for v_rdev */
     59       1.88   hannken 
     60      1.102  christos #include "ioconf.h"
     61      1.102  christos 
     62      1.112     alnsn struct selftest_params {
     63      1.112     alnsn 	const char *alg;
     64      1.112     alnsn 	int blocksize;	/* number of bytes */
     65      1.112     alnsn 	int secsize;
     66      1.112     alnsn 	daddr_t blkno;
     67      1.112     alnsn 	int keylen;	/* number of bits */
     68      1.112     alnsn 	int txtlen;	/* number of bytes */
     69      1.112     alnsn 	const uint8_t *key;
     70      1.112     alnsn 	const uint8_t *ptxt;
     71      1.112     alnsn 	const uint8_t *ctxt;
     72      1.112     alnsn };
     73      1.112     alnsn 
     74        1.1     elric /* Entry Point Functions */
     75        1.1     elric 
     76       1.18   thorpej static dev_type_open(cgdopen);
     77       1.18   thorpej static dev_type_close(cgdclose);
     78       1.18   thorpej static dev_type_read(cgdread);
     79       1.18   thorpej static dev_type_write(cgdwrite);
     80       1.18   thorpej static dev_type_ioctl(cgdioctl);
     81       1.18   thorpej static dev_type_strategy(cgdstrategy);
     82       1.18   thorpej static dev_type_dump(cgddump);
     83       1.18   thorpej static dev_type_size(cgdsize);
     84        1.1     elric 
     85        1.1     elric const struct bdevsw cgd_bdevsw = {
     86  1.114.4.1  pgoyette 	DEVSW_MODULE_INIT
     87       1.84  dholland 	.d_open = cgdopen,
     88       1.84  dholland 	.d_close = cgdclose,
     89       1.84  dholland 	.d_strategy = cgdstrategy,
     90       1.84  dholland 	.d_ioctl = cgdioctl,
     91       1.84  dholland 	.d_dump = cgddump,
     92       1.84  dholland 	.d_psize = cgdsize,
     93       1.89  dholland 	.d_discard = nodiscard,
     94       1.84  dholland 	.d_flag = D_DISK
     95        1.1     elric };
     96        1.1     elric 
     97        1.1     elric const struct cdevsw cgd_cdevsw = {
     98  1.114.4.1  pgoyette 	DEVSW_MODULE_INIT
     99       1.84  dholland 	.d_open = cgdopen,
    100       1.84  dholland 	.d_close = cgdclose,
    101       1.84  dholland 	.d_read = cgdread,
    102       1.84  dholland 	.d_write = cgdwrite,
    103       1.84  dholland 	.d_ioctl = cgdioctl,
    104       1.84  dholland 	.d_stop = nostop,
    105       1.84  dholland 	.d_tty = notty,
    106       1.84  dholland 	.d_poll = nopoll,
    107       1.84  dholland 	.d_mmap = nommap,
    108       1.84  dholland 	.d_kqfilter = nokqfilter,
    109       1.90  dholland 	.d_discard = nodiscard,
    110       1.84  dholland 	.d_flag = D_DISK
    111        1.1     elric };
    112        1.1     elric 
    113      1.112     alnsn /*
    114      1.112     alnsn  * Vector 5 from IEEE 1619/D16 truncated to 64 bytes, blkno 1.
    115      1.112     alnsn  */
    116      1.112     alnsn static const uint8_t selftest_aes_xts_256_ptxt[64] = {
    117      1.112     alnsn 	0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
    118      1.112     alnsn 	0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
    119      1.112     alnsn 	0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
    120      1.112     alnsn 	0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
    121      1.112     alnsn 	0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
    122      1.112     alnsn 	0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
    123      1.112     alnsn 	0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
    124      1.112     alnsn 	0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
    125      1.112     alnsn };
    126      1.112     alnsn 
    127      1.112     alnsn static const uint8_t selftest_aes_xts_256_ctxt[512] = {
    128      1.112     alnsn 	0x26, 0x4d, 0x3c, 0xa8, 0x51, 0x21, 0x94, 0xfe,
    129      1.112     alnsn 	0xc3, 0x12, 0xc8, 0xc9, 0x89, 0x1f, 0x27, 0x9f,
    130      1.112     alnsn 	0xef, 0xdd, 0x60, 0x8d, 0x0c, 0x02, 0x7b, 0x60,
    131      1.112     alnsn 	0x48, 0x3a, 0x3f, 0xa8, 0x11, 0xd6, 0x5e, 0xe5,
    132      1.112     alnsn 	0x9d, 0x52, 0xd9, 0xe4, 0x0e, 0xc5, 0x67, 0x2d,
    133      1.112     alnsn 	0x81, 0x53, 0x2b, 0x38, 0xb6, 0xb0, 0x89, 0xce,
    134      1.112     alnsn 	0x95, 0x1f, 0x0f, 0x9c, 0x35, 0x59, 0x0b, 0x8b,
    135      1.112     alnsn 	0x97, 0x8d, 0x17, 0x52, 0x13, 0xf3, 0x29, 0xbb,
    136      1.112     alnsn };
    137      1.112     alnsn 
    138      1.112     alnsn static const uint8_t selftest_aes_xts_256_key[33] = {
    139      1.112     alnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
    140      1.112     alnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
    141      1.112     alnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
    142      1.112     alnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
    143      1.112     alnsn 	0
    144      1.112     alnsn };
    145      1.112     alnsn 
    146      1.112     alnsn /*
    147      1.112     alnsn  * Vector 11 from IEEE 1619/D16 truncated to 64 bytes, blkno 0xffff.
    148      1.112     alnsn  */
    149      1.112     alnsn static const uint8_t selftest_aes_xts_512_ptxt[64] = {
    150      1.112     alnsn 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    151      1.112     alnsn 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    152      1.112     alnsn 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    153      1.112     alnsn 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
    154      1.112     alnsn 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    155      1.112     alnsn 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
    156      1.112     alnsn 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    157      1.112     alnsn 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
    158      1.112     alnsn };
    159      1.112     alnsn 
    160      1.112     alnsn static const uint8_t selftest_aes_xts_512_ctxt[64] = {
    161      1.112     alnsn 	0x77, 0xa3, 0x12, 0x51, 0x61, 0x8a, 0x15, 0xe6,
    162      1.112     alnsn 	0xb9, 0x2d, 0x1d, 0x66, 0xdf, 0xfe, 0x7b, 0x50,
    163      1.112     alnsn 	0xb5, 0x0b, 0xad, 0x55, 0x23, 0x05, 0xba, 0x02,
    164      1.112     alnsn 	0x17, 0xa6, 0x10, 0x68, 0x8e, 0xff, 0x7e, 0x11,
    165      1.112     alnsn 	0xe1, 0xd0, 0x22, 0x54, 0x38, 0xe0, 0x93, 0x24,
    166      1.112     alnsn 	0x2d, 0x6d, 0xb2, 0x74, 0xfd, 0xe8, 0x01, 0xd4,
    167      1.112     alnsn 	0xca, 0xe0, 0x6f, 0x20, 0x92, 0xc7, 0x28, 0xb2,
    168      1.112     alnsn 	0x47, 0x85, 0x59, 0xdf, 0x58, 0xe8, 0x37, 0xc2,
    169      1.112     alnsn };
    170      1.112     alnsn 
    171      1.112     alnsn static const uint8_t selftest_aes_xts_512_key[65] = {
    172      1.112     alnsn 	0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
    173      1.112     alnsn 	0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26,
    174      1.112     alnsn 	0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69,
    175      1.112     alnsn 	0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27,
    176      1.112     alnsn 	0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
    177      1.112     alnsn 	0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95,
    178      1.112     alnsn 	0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37,
    179      1.112     alnsn 	0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92,
    180      1.112     alnsn 	0
    181      1.112     alnsn };
    182      1.112     alnsn 
    183      1.112     alnsn const struct selftest_params selftests[] = {
    184      1.112     alnsn 	{
    185      1.112     alnsn 		.alg = "aes-xts",
    186      1.112     alnsn 		.blocksize = 16,
    187      1.112     alnsn 		.secsize = 512,
    188      1.112     alnsn 		.blkno = 1,
    189      1.112     alnsn 		.keylen = 256,
    190      1.112     alnsn 		.txtlen = sizeof(selftest_aes_xts_256_ptxt),
    191      1.112     alnsn 		.key  = selftest_aes_xts_256_key,
    192      1.112     alnsn 		.ptxt = selftest_aes_xts_256_ptxt,
    193      1.112     alnsn 		.ctxt = selftest_aes_xts_256_ctxt
    194      1.112     alnsn 	},
    195      1.112     alnsn 	{
    196      1.112     alnsn 		.alg = "aes-xts",
    197      1.112     alnsn 		.blocksize = 16,
    198      1.112     alnsn 		.secsize = 512,
    199      1.112     alnsn 		.blkno = 0xffff,
    200      1.112     alnsn 		.keylen = 512,
    201      1.112     alnsn 		.txtlen = sizeof(selftest_aes_xts_512_ptxt),
    202      1.112     alnsn 		.key  = selftest_aes_xts_512_key,
    203      1.112     alnsn 		.ptxt = selftest_aes_xts_512_ptxt,
    204      1.112     alnsn 		.ctxt = selftest_aes_xts_512_ctxt
    205      1.112     alnsn 	}
    206      1.112     alnsn };
    207      1.112     alnsn 
    208       1.65    dyoung static int cgd_match(device_t, cfdata_t, void *);
    209       1.65    dyoung static void cgd_attach(device_t, device_t, void *);
    210       1.65    dyoung static int cgd_detach(device_t, int);
    211  1.114.4.1  pgoyette static struct cgd_softc	*cgd_spawn(int, device_t *);
    212       1.65    dyoung static int cgd_destroy(device_t);
    213       1.65    dyoung 
    214        1.1     elric /* Internal Functions */
    215        1.1     elric 
    216       1.99   mlelstv static int	cgd_diskstart(device_t, struct buf *);
    217        1.1     elric static void	cgdiodone(struct buf *);
    218      1.108  riastrad static int	cgd_dumpblocks(device_t, void *, daddr_t, int);
    219        1.1     elric 
    220       1.32  christos static int	cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
    221       1.65    dyoung static int	cgd_ioctl_clr(struct cgd_softc *, struct lwp *);
    222       1.78  christos static int	cgd_ioctl_get(dev_t, void *, struct lwp *);
    223       1.27  drochner static int	cgdinit(struct cgd_softc *, const char *, struct vnode *,
    224       1.32  christos 			struct lwp *);
    225       1.44  christos static void	cgd_cipher(struct cgd_softc *, void *, void *,
    226        1.1     elric 			   size_t, daddr_t, size_t, int);
    227        1.1     elric 
    228       1.29      yamt static struct dkdriver cgddkdriver = {
    229       1.98   mlelstv         .d_minphys  = minphys,
    230       1.98   mlelstv         .d_open = cgdopen,
    231       1.98   mlelstv         .d_close = cgdclose,
    232       1.98   mlelstv         .d_strategy = cgdstrategy,
    233       1.98   mlelstv         .d_iosize = NULL,
    234       1.99   mlelstv         .d_diskstart = cgd_diskstart,
    235      1.108  riastrad         .d_dumpblocks = cgd_dumpblocks,
    236       1.98   mlelstv         .d_lastclose = NULL
    237       1.29      yamt };
    238       1.29      yamt 
    239       1.65    dyoung CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc),
    240       1.65    dyoung     cgd_match, cgd_attach, cgd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
    241       1.65    dyoung extern struct cfdriver cgd_cd;
    242       1.65    dyoung 
    243        1.1     elric /* DIAGNOSTIC and DEBUG definitions */
    244        1.1     elric 
    245        1.1     elric #if defined(CGDDEBUG) && !defined(DEBUG)
    246        1.1     elric #define DEBUG
    247        1.1     elric #endif
    248        1.1     elric 
    249        1.1     elric #ifdef DEBUG
    250        1.1     elric int cgddebug = 0;
    251        1.1     elric 
    252        1.1     elric #define CGDB_FOLLOW	0x1
    253        1.1     elric #define CGDB_IO	0x2
    254        1.1     elric #define CGDB_CRYPTO	0x4
    255        1.1     elric 
    256        1.1     elric #define IFDEBUG(x,y)		if (cgddebug & (x)) y
    257        1.1     elric #define DPRINTF(x,y)		IFDEBUG(x, printf y)
    258        1.1     elric #define DPRINTF_FOLLOW(y)	DPRINTF(CGDB_FOLLOW, y)
    259        1.1     elric 
    260       1.26  drochner static void	hexprint(const char *, void *, int);
    261        1.1     elric 
    262        1.1     elric #else
    263        1.1     elric #define IFDEBUG(x,y)
    264        1.1     elric #define DPRINTF(x,y)
    265        1.1     elric #define DPRINTF_FOLLOW(y)
    266        1.1     elric #endif
    267        1.1     elric 
    268        1.1     elric #ifdef DIAGNOSTIC
    269       1.22     perry #define DIAGPANIC(x)		panic x
    270        1.1     elric #define DIAGCONDPANIC(x,y)	if (x) panic y
    271        1.1     elric #else
    272        1.1     elric #define DIAGPANIC(x)
    273        1.1     elric #define DIAGCONDPANIC(x,y)
    274        1.1     elric #endif
    275        1.1     elric 
    276        1.1     elric /* Global variables */
    277        1.1     elric 
    278        1.1     elric /* Utility Functions */
    279        1.1     elric 
    280        1.1     elric #define CGDUNIT(x)		DISKUNIT(x)
    281  1.114.4.1  pgoyette #define GETCGD_SOFTC(_cs, x, _dv)			\
    282  1.114.4.1  pgoyette 	if (((_cs) = getcgd_softc(x, &_dv)) == NULL) {	\
    283  1.114.4.1  pgoyette 		return ENXIO;				\
    284  1.114.4.1  pgoyette 	}
    285        1.1     elric 
    286       1.65    dyoung /* The code */
    287       1.65    dyoung 
    288  1.114.4.1  pgoyette /*
    289  1.114.4.1  pgoyette  * Lookup the device and return it's softc.  If the device doesn't
    290  1.114.4.1  pgoyette  * exist, spawn it.
    291  1.114.4.1  pgoyette  *
    292  1.114.4.1  pgoyette  * In either case, the device is "acquired", and must be "released"
    293  1.114.4.1  pgoyette  * by the caller after it is finished with the softc.
    294  1.114.4.1  pgoyette  */
    295        1.1     elric static struct cgd_softc *
    296  1.114.4.1  pgoyette getcgd_softc(dev_t dev, device_t *self)
    297        1.1     elric {
    298        1.1     elric 	int	unit = CGDUNIT(dev);
    299       1.65    dyoung 	struct cgd_softc *sc;
    300        1.1     elric 
    301       1.56    cegger 	DPRINTF_FOLLOW(("getcgd_softc(0x%"PRIx64"): unit = %d\n", dev, unit));
    302       1.65    dyoung 
    303  1.114.4.1  pgoyette 	*self = device_lookup_acquire(&cgd_cd, unit);
    304  1.114.4.1  pgoyette 
    305  1.114.4.1  pgoyette 	if (*self == NULL) {
    306  1.114.4.1  pgoyette 		sc = cgd_spawn(unit, self);
    307  1.114.4.1  pgoyette 	} else {
    308  1.114.4.1  pgoyette 		sc = device_private(*self);
    309  1.114.4.1  pgoyette 	}
    310  1.114.4.1  pgoyette 
    311       1.65    dyoung 	return sc;
    312        1.1     elric }
    313        1.1     elric 
    314       1.65    dyoung static int
    315       1.65    dyoung cgd_match(device_t self, cfdata_t cfdata, void *aux)
    316       1.65    dyoung {
    317       1.65    dyoung 
    318       1.65    dyoung 	return 1;
    319       1.65    dyoung }
    320        1.1     elric 
    321        1.1     elric static void
    322       1.65    dyoung cgd_attach(device_t parent, device_t self, void *aux)
    323        1.1     elric {
    324  1.114.4.1  pgoyette 	struct cgd_softc *sc;
    325  1.114.4.1  pgoyette 
    326  1.114.4.1  pgoyette 	sc = device_private(self);
    327        1.1     elric 
    328       1.85     skrll 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
    329       1.98   mlelstv 	dk_init(&sc->sc_dksc, self, DKTYPE_CGD);
    330       1.65    dyoung 	disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver);
    331       1.70     joerg 
    332       1.98   mlelstv 	if (!pmf_device_register(self, NULL, NULL))
    333      1.107   msaitoh 		aprint_error_dev(self,
    334      1.107   msaitoh 		    "unable to register power management hooks\n");
    335       1.65    dyoung }
    336       1.65    dyoung 
    337       1.65    dyoung 
    338  1.114.4.1  pgoyette /*
    339  1.114.4.4  pgoyette  * The caller must hold a reference to the device's localcount.
    340  1.114.4.1  pgoyette  */
    341       1.65    dyoung static int
    342       1.65    dyoung cgd_detach(device_t self, int flags)
    343       1.65    dyoung {
    344       1.67    dyoung 	int ret;
    345       1.67    dyoung 	const int pmask = 1 << RAW_PART;
    346       1.65    dyoung 	struct cgd_softc *sc = device_private(self);
    347       1.67    dyoung 	struct dk_softc *dksc = &sc->sc_dksc;
    348       1.67    dyoung 
    349       1.67    dyoung 	if (DK_BUSY(dksc, pmask))
    350       1.67    dyoung 		return EBUSY;
    351       1.65    dyoung 
    352       1.98   mlelstv 	if (DK_ATTACHED(dksc) &&
    353       1.67    dyoung 	    (ret = cgd_ioctl_clr(sc, curlwp)) != 0)
    354       1.67    dyoung 		return ret;
    355       1.65    dyoung 
    356       1.67    dyoung 	disk_destroy(&dksc->sc_dkdev);
    357       1.86  christos 	mutex_destroy(&sc->sc_lock);
    358       1.65    dyoung 
    359       1.67    dyoung 	return 0;
    360        1.1     elric }
    361        1.1     elric 
    362        1.1     elric void
    363        1.1     elric cgdattach(int num)
    364        1.1     elric {
    365       1.65    dyoung 	int error;
    366       1.65    dyoung 
    367       1.65    dyoung 	error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
    368       1.65    dyoung 	if (error != 0)
    369       1.65    dyoung 		aprint_error("%s: unable to register cfattach\n",
    370       1.65    dyoung 		    cgd_cd.cd_name);
    371       1.65    dyoung }
    372       1.65    dyoung 
    373       1.65    dyoung static struct cgd_softc *
    374  1.114.4.1  pgoyette cgd_spawn(int unit, device_t *self)
    375       1.65    dyoung {
    376       1.65    dyoung 	cfdata_t cf;
    377  1.114.4.1  pgoyette 	struct cgd_softc *sc;
    378       1.65    dyoung 
    379       1.65    dyoung 	cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
    380       1.65    dyoung 	cf->cf_name = cgd_cd.cd_name;
    381       1.65    dyoung 	cf->cf_atname = cgd_cd.cd_name;
    382       1.65    dyoung 	cf->cf_unit = unit;
    383       1.65    dyoung 	cf->cf_fstate = FSTATE_STAR;
    384       1.65    dyoung 
    385  1.114.4.1  pgoyette 	if (config_attach_pseudo(cf) == NULL)
    386  1.114.4.1  pgoyette 		return NULL;
    387  1.114.4.1  pgoyette 
    388  1.114.4.2  pgoyette 	if ((*self = device_lookup_acquire(&cgd_cd, unit)) == NULL)
    389  1.114.4.1  pgoyette 		return NULL;
    390  1.114.4.1  pgoyette 	else {
    391  1.114.4.1  pgoyette 		/*
    392  1.114.4.1  pgoyette 		 * Note that we return while still holding a reference
    393  1.114.4.1  pgoyette 		 * to the device!
    394  1.114.4.1  pgoyette 		 */
    395  1.114.4.1  pgoyette 		sc = device_private(*self);
    396  1.114.4.1  pgoyette 		return sc;
    397  1.114.4.1  pgoyette 	}
    398       1.65    dyoung }
    399       1.65    dyoung 
    400       1.65    dyoung static int
    401       1.65    dyoung cgd_destroy(device_t dev)
    402       1.65    dyoung {
    403       1.65    dyoung 	int error;
    404       1.65    dyoung 	cfdata_t cf;
    405        1.1     elric 
    406       1.65    dyoung 	cf = device_cfdata(dev);
    407  1.114.4.4  pgoyette 	error = config_detach_release(dev, DETACH_QUIET);
    408  1.114.4.1  pgoyette 	if (error == 0)
    409  1.114.4.1  pgoyette 		free(cf, M_DEVBUF);
    410  1.114.4.1  pgoyette 
    411  1.114.4.1  pgoyette 	return error;
    412        1.1     elric }
    413        1.1     elric 
    414       1.18   thorpej static int
    415       1.32  christos cgdopen(dev_t dev, int flags, int fmt, struct lwp *l)
    416        1.1     elric {
    417  1.114.4.1  pgoyette 	device_t self;
    418  1.114.4.1  pgoyette 	int	error;
    419        1.1     elric 	struct	cgd_softc *cs;
    420        1.1     elric 
    421       1.56    cegger 	DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
    422  1.114.4.1  pgoyette 	GETCGD_SOFTC(cs, dev, self);
    423  1.114.4.1  pgoyette 	error = dk_open(&cs->sc_dksc, dev, flags, fmt, l);
    424  1.114.4.1  pgoyette 	device_release(self);
    425  1.114.4.1  pgoyette 	return error;
    426        1.1     elric }
    427        1.1     elric 
    428       1.18   thorpej static int
    429       1.32  christos cgdclose(dev_t dev, int flags, int fmt, struct lwp *l)
    430        1.1     elric {
    431       1.65    dyoung 	int error;
    432  1.114.4.1  pgoyette 	device_t self;
    433        1.1     elric 	struct	cgd_softc *cs;
    434       1.65    dyoung 	struct	dk_softc *dksc;
    435        1.1     elric 
    436       1.56    cegger 	DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
    437  1.114.4.1  pgoyette 	GETCGD_SOFTC(cs, dev, self);
    438       1.65    dyoung 	dksc = &cs->sc_dksc;
    439  1.114.4.1  pgoyette 	if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0) {
    440  1.114.4.1  pgoyette 		device_release(self);
    441       1.65    dyoung 		return error;
    442  1.114.4.1  pgoyette 	}
    443       1.65    dyoung 
    444       1.98   mlelstv 	if (!DK_ATTACHED(dksc)) {
    445       1.77     elric 		if ((error = cgd_destroy(cs->sc_dksc.sc_dev)) != 0) {
    446       1.77     elric 			aprint_error_dev(dksc->sc_dev,
    447       1.65    dyoung 			    "unable to detach instance\n");
    448       1.65    dyoung 		}
    449  1.114.4.3  pgoyette 		return error;
    450  1.114.4.2  pgoyette 	}
    451  1.114.4.5  pgoyette 
    452  1.114.4.5  pgoyette 	/* Unit is still attached - just return */
    453  1.114.4.2  pgoyette 	device_release(self);
    454       1.65    dyoung 	return 0;
    455        1.1     elric }
    456        1.1     elric 
    457       1.18   thorpej static void
    458        1.1     elric cgdstrategy(struct buf *bp)
    459        1.1     elric {
    460  1.114.4.1  pgoyette 	device_t self;
    461  1.114.4.1  pgoyette 	struct	cgd_softc *cs = getcgd_softc(bp->b_dev, &self);
    462        1.1     elric 
    463        1.1     elric 	DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp,
    464        1.1     elric 	    (long)bp->b_bcount));
    465       1.72  riastrad 
    466      1.111   mlelstv 	if (!cs) {
    467      1.111   mlelstv 		bp->b_error = ENXIO;
    468      1.111   mlelstv 		goto bail;
    469      1.111   mlelstv 	}
    470      1.111   mlelstv 
    471       1.72  riastrad 	/*
    472      1.111   mlelstv 	 * Reject unaligned writes.
    473       1.72  riastrad 	 */
    474      1.111   mlelstv 	if (((uintptr_t)bp->b_data & 3) != 0) {
    475       1.72  riastrad 		bp->b_error = EINVAL;
    476      1.111   mlelstv 		goto bail;
    477       1.72  riastrad 	}
    478       1.72  riastrad 
    479       1.98   mlelstv 	dk_strategy(&cs->sc_dksc, bp);
    480  1.114.4.1  pgoyette 	device_release(self);
    481        1.1     elric 	return;
    482      1.111   mlelstv 
    483      1.111   mlelstv bail:
    484      1.111   mlelstv 	bp->b_resid = bp->b_bcount;
    485      1.111   mlelstv 	biodone(bp);
    486  1.114.4.1  pgoyette 	if (self)
    487  1.114.4.1  pgoyette 		device_release(self);
    488      1.111   mlelstv 	return;
    489        1.1     elric }
    490        1.1     elric 
    491       1.18   thorpej static int
    492        1.1     elric cgdsize(dev_t dev)
    493        1.1     elric {
    494  1.114.4.1  pgoyette 	int retval;
    495  1.114.4.1  pgoyette 	device_t self;
    496  1.114.4.1  pgoyette 	struct cgd_softc *cs = getcgd_softc(dev, &self);
    497        1.1     elric 
    498       1.56    cegger 	DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
    499        1.1     elric 	if (!cs)
    500  1.114.4.1  pgoyette 		retval = -1;
    501  1.114.4.1  pgoyette 	else
    502  1.114.4.1  pgoyette 		retval = dk_size(&cs->sc_dksc, dev);
    503  1.114.4.1  pgoyette 
    504  1.114.4.1  pgoyette 	device_release(self);
    505  1.114.4.1  pgoyette 	return retval;
    506        1.1     elric }
    507        1.1     elric 
    508       1.16     elric /*
    509       1.16     elric  * cgd_{get,put}data are functions that deal with getting a buffer
    510       1.16     elric  * for the new encrypted data.  We have a buffer per device so that
    511       1.16     elric  * we can ensure that we can always have a transaction in flight.
    512       1.16     elric  * We use this buffer first so that we have one less piece of
    513       1.16     elric  * malloc'ed data at any given point.
    514       1.16     elric  */
    515       1.16     elric 
    516       1.16     elric static void *
    517       1.16     elric cgd_getdata(struct dk_softc *dksc, unsigned long size)
    518       1.16     elric {
    519       1.77     elric 	struct	cgd_softc *cs = (struct cgd_softc *)dksc;
    520       1.44  christos 	void *	data = NULL;
    521       1.16     elric 
    522       1.85     skrll 	mutex_enter(&cs->sc_lock);
    523       1.16     elric 	if (cs->sc_data_used == 0) {
    524       1.16     elric 		cs->sc_data_used = 1;
    525       1.16     elric 		data = cs->sc_data;
    526       1.16     elric 	}
    527       1.85     skrll 	mutex_exit(&cs->sc_lock);
    528       1.16     elric 
    529       1.16     elric 	if (data)
    530       1.16     elric 		return data;
    531       1.16     elric 
    532       1.16     elric 	return malloc(size, M_DEVBUF, M_NOWAIT);
    533       1.16     elric }
    534       1.16     elric 
    535        1.1     elric static void
    536       1.44  christos cgd_putdata(struct dk_softc *dksc, void *data)
    537       1.16     elric {
    538       1.77     elric 	struct	cgd_softc *cs = (struct cgd_softc *)dksc;
    539       1.16     elric 
    540       1.16     elric 	if (data == cs->sc_data) {
    541       1.85     skrll 		mutex_enter(&cs->sc_lock);
    542       1.16     elric 		cs->sc_data_used = 0;
    543       1.85     skrll 		mutex_exit(&cs->sc_lock);
    544       1.16     elric 	} else {
    545       1.16     elric 		free(data, M_DEVBUF);
    546       1.16     elric 	}
    547       1.16     elric }
    548       1.16     elric 
    549       1.99   mlelstv static int
    550       1.99   mlelstv cgd_diskstart(device_t dev, struct buf *bp)
    551        1.1     elric {
    552       1.98   mlelstv 	struct	cgd_softc *cs = device_private(dev);
    553       1.98   mlelstv 	struct	dk_softc *dksc = &cs->sc_dksc;
    554      1.105   mlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    555       1.99   mlelstv 	struct	buf *nbp;
    556       1.44  christos 	void *	addr;
    557       1.44  christos 	void *	newaddr;
    558        1.1     elric 	daddr_t	bn;
    559       1.49        ad 	struct	vnode *vp;
    560        1.1     elric 
    561       1.99   mlelstv 	DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n", dksc, bp));
    562        1.1     elric 
    563       1.99   mlelstv 	bn = bp->b_rawblkno;
    564       1.22     perry 
    565       1.99   mlelstv 	/*
    566       1.99   mlelstv 	 * We attempt to allocate all of our resources up front, so that
    567       1.99   mlelstv 	 * we can fail quickly if they are unavailable.
    568       1.99   mlelstv 	 */
    569       1.99   mlelstv 	nbp = getiobuf(cs->sc_tvn, false);
    570       1.99   mlelstv 	if (nbp == NULL)
    571       1.99   mlelstv 		return EAGAIN;
    572       1.16     elric 
    573       1.99   mlelstv 	/*
    574       1.99   mlelstv 	 * If we are writing, then we need to encrypt the outgoing
    575       1.99   mlelstv 	 * block into a new block of memory.
    576       1.99   mlelstv 	 */
    577       1.99   mlelstv 	newaddr = addr = bp->b_data;
    578       1.99   mlelstv 	if ((bp->b_flags & B_READ) == 0) {
    579       1.99   mlelstv 		newaddr = cgd_getdata(dksc, bp->b_bcount);
    580       1.99   mlelstv 		if (!newaddr) {
    581       1.99   mlelstv 			putiobuf(nbp);
    582       1.99   mlelstv 			return EAGAIN;
    583       1.16     elric 		}
    584       1.99   mlelstv 		cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn,
    585      1.105   mlelstv 		    dg->dg_secsize, CGD_CIPHER_ENCRYPT);
    586       1.99   mlelstv 	}
    587        1.1     elric 
    588       1.99   mlelstv 	nbp->b_data = newaddr;
    589       1.99   mlelstv 	nbp->b_flags = bp->b_flags;
    590       1.99   mlelstv 	nbp->b_oflags = bp->b_oflags;
    591       1.99   mlelstv 	nbp->b_cflags = bp->b_cflags;
    592       1.99   mlelstv 	nbp->b_iodone = cgdiodone;
    593       1.99   mlelstv 	nbp->b_proc = bp->b_proc;
    594      1.105   mlelstv 	nbp->b_blkno = btodb(bn * dg->dg_secsize);
    595       1.99   mlelstv 	nbp->b_bcount = bp->b_bcount;
    596       1.99   mlelstv 	nbp->b_private = bp;
    597       1.99   mlelstv 
    598       1.99   mlelstv 	BIO_COPYPRIO(nbp, bp);
    599       1.99   mlelstv 
    600       1.99   mlelstv 	if ((nbp->b_flags & B_READ) == 0) {
    601       1.99   mlelstv 		vp = nbp->b_vp;
    602       1.99   mlelstv 		mutex_enter(vp->v_interlock);
    603       1.99   mlelstv 		vp->v_numoutput++;
    604       1.99   mlelstv 		mutex_exit(vp->v_interlock);
    605       1.17       dbj 	}
    606       1.99   mlelstv 	VOP_STRATEGY(cs->sc_tvn, nbp);
    607       1.99   mlelstv 
    608       1.99   mlelstv 	return 0;
    609        1.1     elric }
    610        1.1     elric 
    611       1.18   thorpej static void
    612       1.17       dbj cgdiodone(struct buf *nbp)
    613        1.1     elric {
    614  1.114.4.1  pgoyette 	device_t self;
    615       1.17       dbj 	struct	buf *obp = nbp->b_private;
    616  1.114.4.1  pgoyette 	struct	cgd_softc *cs = getcgd_softc(obp->b_dev, &self);
    617        1.1     elric 	struct	dk_softc *dksc = &cs->sc_dksc;
    618      1.105   mlelstv 	struct	disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    619      1.105   mlelstv 	daddr_t	bn;
    620       1.22     perry 
    621       1.17       dbj 	KDASSERT(cs);
    622        1.1     elric 
    623       1.17       dbj 	DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp));
    624       1.20      yamt 	DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n",
    625        1.1     elric 	    obp, obp->b_bcount, obp->b_resid));
    626      1.107   msaitoh 	DPRINTF(CGDB_IO, (" dev 0x%"PRIx64", nbp %p bn %" PRId64
    627      1.107   msaitoh 	    " addr %p bcnt %d\n", nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data,
    628      1.107   msaitoh 		nbp->b_bcount));
    629       1.46        ad 	if (nbp->b_error != 0) {
    630       1.46        ad 		obp->b_error = nbp->b_error;
    631       1.62  christos 		DPRINTF(CGDB_IO, ("%s: error %d\n", dksc->sc_xname,
    632       1.62  christos 		    obp->b_error));
    633        1.1     elric 	}
    634        1.1     elric 
    635       1.16     elric 	/* Perform the decryption if we are reading.
    636        1.1     elric 	 *
    637        1.1     elric 	 * Note: use the blocknumber from nbp, since it is what
    638        1.1     elric 	 *       we used to encrypt the blocks.
    639        1.1     elric 	 */
    640        1.1     elric 
    641      1.105   mlelstv 	if (nbp->b_flags & B_READ) {
    642      1.105   mlelstv 		bn = dbtob(nbp->b_blkno) / dg->dg_secsize;
    643        1.1     elric 		cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount,
    644      1.105   mlelstv 		    bn, dg->dg_secsize, CGD_CIPHER_DECRYPT);
    645      1.105   mlelstv 	}
    646        1.1     elric 
    647       1.16     elric 	/* If we allocated memory, free it now... */
    648        1.1     elric 	if (nbp->b_data != obp->b_data)
    649       1.16     elric 		cgd_putdata(dksc, nbp->b_data);
    650        1.1     elric 
    651       1.33      yamt 	putiobuf(nbp);
    652        1.1     elric 
    653      1.100   mlelstv 	/* Request is complete for whatever reason */
    654      1.100   mlelstv 	obp->b_resid = 0;
    655      1.100   mlelstv 	if (obp->b_error != 0)
    656      1.100   mlelstv 		obp->b_resid = obp->b_bcount;
    657      1.100   mlelstv 
    658       1.99   mlelstv 	dk_done(dksc, obp);
    659  1.114.4.1  pgoyette 	device_release(self);
    660  1.114.4.1  pgoyette 
    661      1.101   mlelstv 	dk_start(dksc, NULL);
    662        1.1     elric }
    663        1.1     elric 
    664      1.108  riastrad static int
    665      1.108  riastrad cgd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
    666      1.108  riastrad {
    667      1.108  riastrad 	struct cgd_softc *sc = device_private(dev);
    668      1.108  riastrad 	struct dk_softc *dksc = &sc->sc_dksc;
    669      1.108  riastrad 	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
    670      1.108  riastrad 	size_t nbytes, blksize;
    671      1.108  riastrad 	void *buf;
    672      1.108  riastrad 	int error;
    673      1.108  riastrad 
    674      1.108  riastrad 	/*
    675      1.108  riastrad 	 * dk_dump gives us units of disklabel sectors.  Everything
    676      1.108  riastrad 	 * else in cgd uses units of diskgeom sectors.  These had
    677      1.108  riastrad 	 * better agree; otherwise we need to figure out how to convert
    678      1.108  riastrad 	 * between them.
    679      1.108  riastrad 	 */
    680      1.108  riastrad 	KASSERTMSG((dg->dg_secsize == dksc->sc_dkdev.dk_label->d_secsize),
    681      1.108  riastrad 	    "diskgeom secsize %"PRIu32" != disklabel secsize %"PRIu32,
    682      1.108  riastrad 	    dg->dg_secsize, dksc->sc_dkdev.dk_label->d_secsize);
    683      1.108  riastrad 	blksize = dg->dg_secsize;
    684      1.108  riastrad 
    685      1.108  riastrad 	/*
    686      1.108  riastrad 	 * Compute the number of bytes in this request, which dk_dump
    687      1.108  riastrad 	 * has `helpfully' converted to a number of blocks for us.
    688      1.108  riastrad 	 */
    689      1.108  riastrad 	nbytes = nblk*blksize;
    690      1.108  riastrad 
    691      1.108  riastrad 	/* Try to acquire a buffer to store the ciphertext.  */
    692      1.108  riastrad 	buf = cgd_getdata(dksc, nbytes);
    693      1.108  riastrad 	if (buf == NULL)
    694      1.108  riastrad 		/* Out of memory: give up.  */
    695      1.108  riastrad 		return ENOMEM;
    696      1.108  riastrad 
    697      1.108  riastrad 	/* Encrypt the caller's data into the temporary buffer.  */
    698      1.108  riastrad 	cgd_cipher(sc, buf, va, nbytes, blkno, blksize, CGD_CIPHER_ENCRYPT);
    699      1.108  riastrad 
    700      1.108  riastrad 	/* Pass it on to the underlying disk device.  */
    701      1.108  riastrad 	error = bdev_dump(sc->sc_tdev, blkno, buf, nbytes);
    702      1.108  riastrad 
    703      1.108  riastrad 	/* Release the buffer.  */
    704      1.108  riastrad 	cgd_putdata(dksc, buf);
    705      1.108  riastrad 
    706      1.108  riastrad 	/* Return any error from the underlying disk device.  */
    707      1.108  riastrad 	return error;
    708      1.108  riastrad }
    709      1.108  riastrad 
    710        1.1     elric /* XXX: we should probably put these into dksubr.c, mostly */
    711       1.18   thorpej static int
    712       1.40  christos cgdread(dev_t dev, struct uio *uio, int flags)
    713        1.1     elric {
    714  1.114.4.1  pgoyette 	device_t self;
    715  1.114.4.1  pgoyette 	int	error;
    716        1.1     elric 	struct	cgd_softc *cs;
    717        1.1     elric 	struct	dk_softc *dksc;
    718        1.1     elric 
    719       1.56    cegger 	DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n",
    720       1.56    cegger 	    (unsigned long long)dev, uio, flags));
    721  1.114.4.1  pgoyette 	GETCGD_SOFTC(cs, dev, self);
    722        1.1     elric 	dksc = &cs->sc_dksc;
    723  1.114.4.1  pgoyette 	if (!DK_ATTACHED(dksc)) {
    724  1.114.4.1  pgoyette 		device_release(self);
    725        1.1     elric 		return ENXIO;
    726  1.114.4.1  pgoyette 	}
    727  1.114.4.1  pgoyette 	error = physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
    728  1.114.4.1  pgoyette 	device_release(self);
    729  1.114.4.1  pgoyette 	return error;
    730        1.1     elric }
    731        1.1     elric 
    732        1.1     elric /* XXX: we should probably put these into dksubr.c, mostly */
    733       1.18   thorpej static int
    734       1.40  christos cgdwrite(dev_t dev, struct uio *uio, int flags)
    735        1.1     elric {
    736  1.114.4.1  pgoyette 	device_t self;
    737  1.114.4.1  pgoyette 	int	error;
    738        1.1     elric 	struct	cgd_softc *cs;
    739        1.1     elric 	struct	dk_softc *dksc;
    740        1.1     elric 
    741       1.56    cegger 	DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
    742  1.114.4.1  pgoyette 	GETCGD_SOFTC(cs, dev, self);
    743        1.1     elric 	dksc = &cs->sc_dksc;
    744  1.114.4.1  pgoyette 	if (!DK_ATTACHED(dksc)) {
    745  1.114.4.1  pgoyette 		device_release(self);
    746        1.1     elric 		return ENXIO;
    747  1.114.4.1  pgoyette 	}
    748  1.114.4.1  pgoyette 	error = physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
    749  1.114.4.1  pgoyette 	device_release(self);
    750  1.114.4.1  pgoyette 	return error;
    751        1.1     elric }
    752        1.1     elric 
    753       1.18   thorpej static int
    754       1.44  christos cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    755        1.1     elric {
    756  1.114.4.1  pgoyette 	device_t self;
    757        1.1     elric 	struct	cgd_softc *cs;
    758        1.1     elric 	struct	dk_softc *dksc;
    759        1.1     elric 	int	part = DISKPART(dev);
    760        1.1     elric 	int	pmask = 1 << part;
    761  1.114.4.1  pgoyette 	int	error = 0;
    762        1.1     elric 
    763       1.56    cegger 	DPRINTF_FOLLOW(("cgdioctl(0x%"PRIx64", %ld, %p, %d, %p)\n",
    764       1.32  christos 	    dev, cmd, data, flag, l));
    765       1.78  christos 
    766        1.1     elric 	switch (cmd) {
    767       1.93  christos 	case CGDIOCGET:
    768       1.93  christos 		return cgd_ioctl_get(dev, data, l);
    769        1.1     elric 	case CGDIOCSET:
    770        1.1     elric 	case CGDIOCCLR:
    771        1.1     elric 		if ((flag & FWRITE) == 0)
    772        1.1     elric 			return EBADF;
    773       1.78  christos 		/* FALLTHROUGH */
    774       1.78  christos 	default:
    775  1.114.4.1  pgoyette 		GETCGD_SOFTC(cs, dev, self);
    776       1.78  christos 		dksc = &cs->sc_dksc;
    777       1.78  christos 		break;
    778        1.1     elric 	}
    779        1.1     elric 
    780        1.1     elric 	switch (cmd) {
    781        1.1     elric 	case CGDIOCSET:
    782       1.98   mlelstv 		if (DK_ATTACHED(dksc))
    783  1.114.4.1  pgoyette 			error = EBUSY;
    784  1.114.4.1  pgoyette 		else
    785  1.114.4.1  pgoyette 			error = cgd_ioctl_set(cs, data, l);
    786  1.114.4.1  pgoyette 		break;
    787        1.1     elric 	case CGDIOCCLR:
    788       1.65    dyoung 		if (DK_BUSY(&cs->sc_dksc, pmask))
    789  1.114.4.2  pgoyette 			error = EBUSY;
    790  1.114.4.2  pgoyette 		else
    791  1.114.4.2  pgoyette 			error = cgd_ioctl_clr(cs, l);
    792  1.114.4.2  pgoyette 		break;
    793      1.114  jdolecek 	case DIOCGCACHE:
    794       1.57       apb 	case DIOCCACHESYNC:
    795      1.114  jdolecek 		if (!DK_ATTACHED(dksc))
    796      1.114  jdolecek 			return ENOENT;
    797       1.57       apb 		/*
    798       1.57       apb 		 * We pass this call down to the underlying disk.
    799       1.57       apb 		 */
    800  1.114.4.1  pgoyette 		else
    801  1.114.4.1  pgoyette 			error = VOP_IOCTL(cs->sc_tvn, cmd, data, flag,
    802  1.114.4.1  pgoyette 			    l->l_cred);
    803  1.114.4.1  pgoyette 		break;
    804      1.103  christos 	case DIOCGSTRATEGY:
    805      1.103  christos 	case DIOCSSTRATEGY:
    806  1.114.4.1  pgoyette 		if (!DK_ATTACHED(dksc)) {
    807  1.114.4.1  pgoyette 			error = ENOENT;
    808  1.114.4.1  pgoyette 			break;
    809  1.114.4.1  pgoyette 		}
    810      1.103  christos 		/*FALLTHROUGH*/
    811        1.1     elric 	default:
    812  1.114.4.1  pgoyette 		error = dk_ioctl(dksc, dev, cmd, data, flag, l);
    813  1.114.4.1  pgoyette 		break;
    814       1.93  christos 	case CGDIOCGET:
    815       1.93  christos 		KASSERT(0);
    816  1.114.4.1  pgoyette 		error = EINVAL;
    817  1.114.4.1  pgoyette 		break;
    818        1.1     elric 	}
    819  1.114.4.1  pgoyette 	device_release(self);
    820  1.114.4.1  pgoyette 	return error;
    821        1.1     elric }
    822        1.1     elric 
    823       1.18   thorpej static int
    824       1.44  christos cgddump(dev_t dev, daddr_t blkno, void *va, size_t size)
    825        1.1     elric {
    826  1.114.4.1  pgoyette 	device_t self;
    827  1.114.4.1  pgoyette 	int	error;
    828        1.1     elric 	struct	cgd_softc *cs;
    829        1.1     elric 
    830       1.56    cegger 	DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
    831       1.56    cegger 	    dev, blkno, va, (unsigned long)size));
    832  1.114.4.1  pgoyette 	GETCGD_SOFTC(cs, dev, self);
    833  1.114.4.1  pgoyette 	error = dk_dump(&cs->sc_dksc, dev, blkno, va, size);
    834  1.114.4.1  pgoyette 	device_release(self);
    835  1.114.4.1  pgoyette 	return error;
    836        1.1     elric }
    837        1.1     elric 
    838        1.1     elric /*
    839        1.1     elric  * XXXrcd:
    840        1.1     elric  *  for now we hardcode the maximum key length.
    841        1.1     elric  */
    842        1.1     elric #define MAX_KEYSIZE	1024
    843        1.1     elric 
    844       1.53  christos static const struct {
    845       1.53  christos 	const char *n;
    846       1.53  christos 	int v;
    847       1.53  christos 	int d;
    848       1.53  christos } encblkno[] = {
    849       1.53  christos 	{ "encblkno",  CGD_CIPHER_CBC_ENCBLKNO8, 1 },
    850       1.53  christos 	{ "encblkno8", CGD_CIPHER_CBC_ENCBLKNO8, 1 },
    851       1.53  christos 	{ "encblkno1", CGD_CIPHER_CBC_ENCBLKNO1, 8 },
    852       1.53  christos };
    853       1.53  christos 
    854        1.1     elric /* ARGSUSED */
    855        1.1     elric static int
    856       1.32  christos cgd_ioctl_set(struct cgd_softc *cs, void *data, struct lwp *l)
    857        1.1     elric {
    858        1.1     elric 	struct	 cgd_ioctl *ci = data;
    859        1.1     elric 	struct	 vnode *vp;
    860        1.1     elric 	int	 ret;
    861       1.53  christos 	size_t	 i;
    862       1.43    cbiere 	size_t	 keybytes;			/* key length in bytes */
    863       1.27  drochner 	const char *cp;
    864       1.71  dholland 	struct pathbuf *pb;
    865       1.36  christos 	char	 *inbuf;
    866       1.80  christos 	struct dk_softc *dksc = &cs->sc_dksc;
    867        1.1     elric 
    868        1.1     elric 	cp = ci->ci_disk;
    869       1.71  dholland 
    870       1.71  dholland 	ret = pathbuf_copyin(ci->ci_disk, &pb);
    871       1.71  dholland 	if (ret != 0) {
    872       1.71  dholland 		return ret;
    873       1.71  dholland 	}
    874       1.71  dholland 	ret = dk_lookup(pb, l, &vp);
    875       1.71  dholland 	pathbuf_destroy(pb);
    876       1.71  dholland 	if (ret != 0) {
    877        1.1     elric 		return ret;
    878       1.71  dholland 	}
    879        1.1     elric 
    880       1.36  christos 	inbuf = malloc(MAX_KEYSIZE, M_TEMP, M_WAITOK);
    881       1.36  christos 
    882       1.32  christos 	if ((ret = cgdinit(cs, cp, vp, l)) != 0)
    883        1.1     elric 		goto bail;
    884        1.1     elric 
    885       1.36  christos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
    886        1.1     elric 	ret = copyinstr(ci->ci_alg, inbuf, 256, NULL);
    887        1.1     elric 	if (ret)
    888        1.1     elric 		goto bail;
    889        1.1     elric 	cs->sc_cfuncs = cryptfuncs_find(inbuf);
    890        1.1     elric 	if (!cs->sc_cfuncs) {
    891        1.1     elric 		ret = EINVAL;
    892        1.1     elric 		goto bail;
    893        1.1     elric 	}
    894        1.1     elric 
    895       1.43    cbiere 	(void)memset(inbuf, 0, MAX_KEYSIZE);
    896       1.36  christos 	ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL);
    897        1.1     elric 	if (ret)
    898        1.1     elric 		goto bail;
    899       1.53  christos 
    900       1.53  christos 	for (i = 0; i < __arraycount(encblkno); i++)
    901       1.53  christos 		if (strcmp(encblkno[i].n, inbuf) == 0)
    902       1.53  christos 			break;
    903       1.53  christos 
    904       1.53  christos 	if (i == __arraycount(encblkno)) {
    905        1.1     elric 		ret = EINVAL;
    906        1.1     elric 		goto bail;
    907        1.1     elric 	}
    908        1.1     elric 
    909       1.15       dan 	keybytes = ci->ci_keylen / 8 + 1;
    910       1.15       dan 	if (keybytes > MAX_KEYSIZE) {
    911        1.1     elric 		ret = EINVAL;
    912        1.1     elric 		goto bail;
    913        1.1     elric 	}
    914       1.53  christos 
    915       1.36  christos 	(void)memset(inbuf, 0, MAX_KEYSIZE);
    916       1.15       dan 	ret = copyin(ci->ci_key, inbuf, keybytes);
    917        1.1     elric 	if (ret)
    918        1.1     elric 		goto bail;
    919        1.1     elric 
    920        1.1     elric 	cs->sc_cdata.cf_blocksize = ci->ci_blocksize;
    921       1.53  christos 	cs->sc_cdata.cf_mode = encblkno[i].v;
    922       1.78  christos 	cs->sc_cdata.cf_keylen = ci->ci_keylen;
    923        1.1     elric 	cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf,
    924        1.1     elric 	    &cs->sc_cdata.cf_blocksize);
    925       1.62  christos 	if (cs->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) {
    926       1.62  christos 	    log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n",
    927       1.63  christos 		cs->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE);
    928       1.62  christos 	    cs->sc_cdata.cf_priv = NULL;
    929       1.62  christos 	}
    930       1.78  christos 
    931       1.53  christos 	/*
    932       1.53  christos 	 * The blocksize is supposed to be in bytes. Unfortunately originally
    933       1.53  christos 	 * it was expressed in bits. For compatibility we maintain encblkno
    934       1.53  christos 	 * and encblkno8.
    935       1.53  christos 	 */
    936       1.53  christos 	cs->sc_cdata.cf_blocksize /= encblkno[i].d;
    937       1.97  riastrad 	(void)explicit_memset(inbuf, 0, MAX_KEYSIZE);
    938        1.1     elric 	if (!cs->sc_cdata.cf_priv) {
    939        1.1     elric 		ret = EINVAL;		/* XXX is this the right error? */
    940        1.1     elric 		goto bail;
    941        1.1     elric 	}
    942       1.36  christos 	free(inbuf, M_TEMP);
    943        1.1     elric 
    944       1.80  christos 	bufq_alloc(&dksc->sc_bufq, "fcfs", 0);
    945       1.16     elric 
    946       1.16     elric 	cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK);
    947       1.16     elric 	cs->sc_data_used = 0;
    948       1.16     elric 
    949       1.98   mlelstv 	/* Attach the disk. */
    950       1.98   mlelstv 	dk_attach(dksc);
    951       1.98   mlelstv 	disk_attach(&dksc->sc_dkdev);
    952        1.1     elric 
    953       1.80  christos 	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
    954       1.77     elric 
    955       1.29      yamt 	/* Discover wedges on this disk. */
    956       1.80  christos 	dkwedge_discover(&dksc->sc_dkdev);
    957       1.29      yamt 
    958        1.1     elric 	return 0;
    959        1.1     elric 
    960        1.1     elric bail:
    961       1.36  christos 	free(inbuf, M_TEMP);
    962       1.51        ad 	(void)vn_close(vp, FREAD|FWRITE, l->l_cred);
    963        1.1     elric 	return ret;
    964        1.1     elric }
    965        1.1     elric 
    966        1.1     elric /* ARGSUSED */
    967        1.1     elric static int
    968       1.65    dyoung cgd_ioctl_clr(struct cgd_softc *cs, struct lwp *l)
    969        1.1     elric {
    970       1.80  christos 	struct	dk_softc *dksc = &cs->sc_dksc;
    971       1.65    dyoung 
    972       1.98   mlelstv 	if (!DK_ATTACHED(dksc))
    973       1.65    dyoung 		return ENXIO;
    974       1.16     elric 
    975       1.29      yamt 	/* Delete all of our wedges. */
    976       1.80  christos 	dkwedge_delall(&dksc->sc_dkdev);
    977       1.29      yamt 
    978       1.16     elric 	/* Kill off any queued buffers. */
    979      1.104   mlelstv 	dk_drain(dksc);
    980       1.80  christos 	bufq_free(dksc->sc_bufq);
    981        1.1     elric 
    982       1.51        ad 	(void)vn_close(cs->sc_tvn, FREAD|FWRITE, l->l_cred);
    983        1.1     elric 	cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv);
    984        1.1     elric 	free(cs->sc_tpath, M_DEVBUF);
    985       1.16     elric 	free(cs->sc_data, M_DEVBUF);
    986       1.16     elric 	cs->sc_data_used = 0;
    987       1.98   mlelstv 	dk_detach(dksc);
    988       1.80  christos 	disk_detach(&dksc->sc_dkdev);
    989        1.1     elric 
    990        1.1     elric 	return 0;
    991        1.1     elric }
    992        1.1     elric 
    993        1.1     elric static int
    994       1.78  christos cgd_ioctl_get(dev_t dev, void *data, struct lwp *l)
    995       1.78  christos {
    996  1.114.4.1  pgoyette 	device_t self;
    997  1.114.4.1  pgoyette 	struct cgd_softc *cs = getcgd_softc(dev, &self);
    998       1.78  christos 	struct cgd_user *cgu;
    999       1.78  christos 	int unit;
   1000       1.80  christos 	struct	dk_softc *dksc = &cs->sc_dksc;
   1001       1.78  christos 
   1002       1.78  christos 	unit = CGDUNIT(dev);
   1003       1.78  christos 	cgu = (struct cgd_user *)data;
   1004       1.78  christos 
   1005       1.78  christos 	DPRINTF_FOLLOW(("cgd_ioctl_get(0x%"PRIx64", %d, %p, %p)\n",
   1006       1.78  christos 			   dev, unit, data, l));
   1007       1.78  christos 
   1008       1.78  christos 	if (cgu->cgu_unit == -1)
   1009       1.78  christos 		cgu->cgu_unit = unit;
   1010       1.78  christos 
   1011  1.114.4.1  pgoyette 	if (cgu->cgu_unit < 0) {
   1012  1.114.4.1  pgoyette 		device_release(self);
   1013       1.78  christos 		return EINVAL;	/* XXX: should this be ENXIO? */
   1014  1.114.4.1  pgoyette 	}
   1015       1.78  christos 
   1016  1.114.4.1  pgoyette 	/*
   1017  1.114.4.1  pgoyette 	 * XXX This appears to be redundant, given the initialization
   1018  1.114.4.1  pgoyette 	 * XXX when it was declared.  Leave it for now, but don't
   1019  1.114.4.1  pgoyette 	 * XXX take an extra reference to the device!
   1020  1.114.4.1  pgoyette 	 */
   1021       1.78  christos 	cs = device_lookup_private(&cgd_cd, unit);
   1022       1.98   mlelstv 	if (cs == NULL || !DK_ATTACHED(dksc)) {
   1023       1.78  christos 		cgu->cgu_dev = 0;
   1024       1.78  christos 		cgu->cgu_alg[0] = '\0';
   1025       1.78  christos 		cgu->cgu_blocksize = 0;
   1026       1.78  christos 		cgu->cgu_mode = 0;
   1027       1.78  christos 		cgu->cgu_keylen = 0;
   1028       1.78  christos 	}
   1029       1.78  christos 	else {
   1030       1.78  christos 		cgu->cgu_dev = cs->sc_tdev;
   1031       1.78  christos 		strlcpy(cgu->cgu_alg, cs->sc_cfuncs->cf_name,
   1032       1.78  christos 		    sizeof(cgu->cgu_alg));
   1033       1.78  christos 		cgu->cgu_blocksize = cs->sc_cdata.cf_blocksize;
   1034       1.78  christos 		cgu->cgu_mode = cs->sc_cdata.cf_mode;
   1035       1.78  christos 		cgu->cgu_keylen = cs->sc_cdata.cf_keylen;
   1036       1.78  christos 	}
   1037  1.114.4.1  pgoyette 	device_release(self);
   1038       1.78  christos 	return 0;
   1039       1.78  christos }
   1040       1.78  christos 
   1041       1.78  christos static int
   1042       1.27  drochner cgdinit(struct cgd_softc *cs, const char *cpath, struct vnode *vp,
   1043       1.32  christos 	struct lwp *l)
   1044        1.1     elric {
   1045       1.80  christos 	struct	disk_geom *dg;
   1046        1.1     elric 	int	ret;
   1047       1.36  christos 	char	*tmppath;
   1048       1.76  christos 	uint64_t psize;
   1049       1.76  christos 	unsigned secsize;
   1050       1.80  christos 	struct dk_softc *dksc = &cs->sc_dksc;
   1051        1.1     elric 
   1052        1.1     elric 	cs->sc_tvn = vp;
   1053       1.36  christos 	cs->sc_tpath = NULL;
   1054        1.1     elric 
   1055       1.36  christos 	tmppath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
   1056        1.1     elric 	ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen);
   1057        1.1     elric 	if (ret)
   1058        1.1     elric 		goto bail;
   1059        1.1     elric 	cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK);
   1060        1.1     elric 	memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen);
   1061        1.1     elric 
   1062       1.88   hannken 	cs->sc_tdev = vp->v_rdev;
   1063        1.1     elric 
   1064       1.76  christos 	if ((ret = getdisksize(vp, &psize, &secsize)) != 0)
   1065        1.1     elric 		goto bail;
   1066        1.1     elric 
   1067       1.76  christos 	if (psize == 0) {
   1068        1.1     elric 		ret = ENODEV;
   1069        1.1     elric 		goto bail;
   1070        1.1     elric 	}
   1071        1.1     elric 
   1072        1.1     elric 	/*
   1073        1.1     elric 	 * XXX here we should probe the underlying device.  If we
   1074        1.1     elric 	 *     are accessing a partition of type RAW_PART, then
   1075        1.1     elric 	 *     we should populate our initial geometry with the
   1076        1.1     elric 	 *     geometry that we discover from the device.
   1077        1.1     elric 	 */
   1078       1.80  christos 	dg = &dksc->sc_dkdev.dk_geom;
   1079       1.80  christos 	memset(dg, 0, sizeof(*dg));
   1080       1.80  christos 	dg->dg_secperunit = psize;
   1081      1.105   mlelstv 	dg->dg_secsize = secsize;
   1082       1.80  christos 	dg->dg_ntracks = 1;
   1083      1.105   mlelstv 	dg->dg_nsectors = 1024 * 1024 / dg->dg_secsize;
   1084       1.80  christos 	dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors;
   1085        1.1     elric 
   1086        1.1     elric bail:
   1087       1.36  christos 	free(tmppath, M_TEMP);
   1088        1.1     elric 	if (ret && cs->sc_tpath)
   1089        1.1     elric 		free(cs->sc_tpath, M_DEVBUF);
   1090        1.1     elric 	return ret;
   1091        1.1     elric }
   1092        1.1     elric 
   1093        1.1     elric /*
   1094        1.1     elric  * Our generic cipher entry point.  This takes care of the
   1095        1.1     elric  * IV mode and passes off the work to the specific cipher.
   1096        1.1     elric  * We implement here the IV method ``encrypted block
   1097        1.1     elric  * number''.
   1098       1.22     perry  *
   1099        1.1     elric  * XXXrcd: for now we rely on our own crypto framework defined
   1100        1.1     elric  *         in dev/cgd_crypto.c.  This will change when we
   1101        1.1     elric  *         get a generic kernel crypto framework.
   1102        1.1     elric  */
   1103        1.1     elric 
   1104        1.1     elric static void
   1105       1.25   xtraeme blkno2blkno_buf(char *sbuf, daddr_t blkno)
   1106        1.1     elric {
   1107        1.1     elric 	int	i;
   1108        1.1     elric 
   1109        1.1     elric 	/* Set up the blkno in blkno_buf, here we do not care much
   1110        1.1     elric 	 * about the final layout of the information as long as we
   1111        1.1     elric 	 * can guarantee that each sector will have a different IV
   1112        1.1     elric 	 * and that the endianness of the machine will not affect
   1113        1.1     elric 	 * the representation that we have chosen.
   1114        1.1     elric 	 *
   1115        1.1     elric 	 * We choose this representation, because it does not rely
   1116        1.1     elric 	 * on the size of buf (which is the blocksize of the cipher),
   1117        1.1     elric 	 * but allows daddr_t to grow without breaking existing
   1118        1.1     elric 	 * disks.
   1119        1.1     elric 	 *
   1120        1.1     elric 	 * Note that blkno2blkno_buf does not take a size as input,
   1121        1.1     elric 	 * and hence must be called on a pre-zeroed buffer of length
   1122        1.1     elric 	 * greater than or equal to sizeof(daddr_t).
   1123        1.1     elric 	 */
   1124        1.1     elric 	for (i=0; i < sizeof(daddr_t); i++) {
   1125       1.25   xtraeme 		*sbuf++ = blkno & 0xff;
   1126        1.1     elric 		blkno >>= 8;
   1127        1.1     elric 	}
   1128        1.1     elric }
   1129        1.1     elric 
   1130        1.1     elric static void
   1131       1.44  christos cgd_cipher(struct cgd_softc *cs, void *dstv, void *srcv,
   1132       1.44  christos     size_t len, daddr_t blkno, size_t secsize, int dir)
   1133        1.1     elric {
   1134       1.44  christos 	char		*dst = dstv;
   1135      1.112     alnsn 	char		*src = srcv;
   1136      1.112     alnsn 	cfunc_cipher_prep	*ciprep = cs->sc_cfuncs->cf_cipher_prep;
   1137        1.1     elric 	cfunc_cipher	*cipher = cs->sc_cfuncs->cf_cipher;
   1138        1.1     elric 	struct uio	dstuio;
   1139        1.1     elric 	struct uio	srcuio;
   1140        1.1     elric 	struct iovec	dstiov[2];
   1141        1.1     elric 	struct iovec	srciov[2];
   1142       1.42  christos 	size_t		blocksize = cs->sc_cdata.cf_blocksize;
   1143      1.105   mlelstv 	size_t		todo;
   1144      1.112     alnsn 	char		blkno_buf[CGD_MAXBLOCKSIZE], *iv;
   1145        1.1     elric 
   1146        1.1     elric 	DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir));
   1147        1.1     elric 
   1148       1.22     perry 	DIAGCONDPANIC(len % blocksize != 0,
   1149        1.1     elric 	    ("cgd_cipher: len %% blocksize != 0"));
   1150        1.1     elric 
   1151        1.1     elric 	/* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */
   1152        1.1     elric 	DIAGCONDPANIC(sizeof(daddr_t) > blocksize,
   1153        1.1     elric 	    ("cgd_cipher: sizeof(daddr_t) > blocksize"));
   1154        1.1     elric 
   1155      1.112     alnsn 	DIAGCONDPANIC(blocksize > CGD_MAXBLOCKSIZE,
   1156      1.112     alnsn 	    ("cgd_cipher: blocksize > CGD_MAXBLOCKSIZE"));
   1157        1.1     elric 
   1158        1.1     elric 	dstuio.uio_iov = dstiov;
   1159      1.112     alnsn 	dstuio.uio_iovcnt = 1;
   1160        1.1     elric 
   1161        1.1     elric 	srcuio.uio_iov = srciov;
   1162      1.112     alnsn 	srcuio.uio_iovcnt = 1;
   1163        1.1     elric 
   1164      1.105   mlelstv 	for (; len > 0; len -= todo) {
   1165      1.105   mlelstv 		todo = MIN(len, secsize);
   1166      1.105   mlelstv 
   1167      1.112     alnsn 		dstiov[0].iov_base = dst;
   1168      1.112     alnsn 		srciov[0].iov_base = src;
   1169      1.112     alnsn 		dstiov[0].iov_len  = todo;
   1170      1.112     alnsn 		srciov[0].iov_len  = todo;
   1171        1.1     elric 
   1172       1.64  christos 		memset(blkno_buf, 0x0, blocksize);
   1173        1.1     elric 		blkno2blkno_buf(blkno_buf, blkno);
   1174        1.1     elric 		IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf",
   1175       1.64  christos 		    blkno_buf, blocksize));
   1176      1.112     alnsn 
   1177      1.112     alnsn 		/*
   1178      1.112     alnsn 		 * Compute an initial IV. All ciphers
   1179      1.112     alnsn 		 * can convert blkno_buf in-place.
   1180      1.112     alnsn 		 */
   1181      1.112     alnsn 		iv = blkno_buf;
   1182      1.112     alnsn 		ciprep(cs->sc_cdata.cf_priv, iv, blkno_buf, blocksize, dir);
   1183      1.112     alnsn 		IFDEBUG(CGDB_CRYPTO, hexprint("step 2: iv", iv, blocksize));
   1184      1.112     alnsn 
   1185      1.112     alnsn 		cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, iv, dir);
   1186        1.1     elric 
   1187      1.105   mlelstv 		dst += todo;
   1188      1.105   mlelstv 		src += todo;
   1189        1.1     elric 		blkno++;
   1190        1.1     elric 	}
   1191        1.1     elric }
   1192        1.1     elric 
   1193        1.1     elric #ifdef DEBUG
   1194        1.1     elric static void
   1195       1.26  drochner hexprint(const char *start, void *buf, int len)
   1196        1.1     elric {
   1197        1.1     elric 	char	*c = buf;
   1198        1.1     elric 
   1199        1.1     elric 	DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0"));
   1200        1.1     elric 	printf("%s: len=%06d 0x", start, len);
   1201        1.1     elric 	while (len--)
   1202       1.43    cbiere 		printf("%02x", (unsigned char) *c++);
   1203        1.1     elric }
   1204        1.1     elric #endif
   1205       1.58      haad 
   1206      1.112     alnsn static void
   1207      1.112     alnsn selftest(void)
   1208      1.112     alnsn {
   1209      1.112     alnsn 	struct cgd_softc cs;
   1210      1.112     alnsn 	void *buf;
   1211      1.112     alnsn 
   1212      1.112     alnsn 	printf("running cgd selftest ");
   1213      1.112     alnsn 
   1214      1.112     alnsn 	for (size_t i = 0; i < __arraycount(selftests); i++) {
   1215      1.112     alnsn 		const char *alg = selftests[i].alg;
   1216      1.112     alnsn 		const uint8_t *key = selftests[i].key;
   1217      1.112     alnsn 		int keylen = selftests[i].keylen;
   1218      1.112     alnsn 		int txtlen = selftests[i].txtlen;
   1219      1.112     alnsn 
   1220      1.112     alnsn 		printf("%s-%d ", alg, keylen);
   1221      1.112     alnsn 
   1222      1.112     alnsn 		memset(&cs, 0, sizeof(cs));
   1223      1.112     alnsn 
   1224      1.112     alnsn 		cs.sc_cfuncs = cryptfuncs_find(alg);
   1225      1.112     alnsn 		if (cs.sc_cfuncs == NULL)
   1226      1.112     alnsn 			panic("%s not implemented", alg);
   1227      1.112     alnsn 
   1228      1.112     alnsn 		cs.sc_cdata.cf_blocksize = 8 * selftests[i].blocksize;
   1229      1.112     alnsn 		cs.sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO1;
   1230      1.112     alnsn 		cs.sc_cdata.cf_keylen = keylen;
   1231      1.112     alnsn 
   1232      1.112     alnsn 		cs.sc_cdata.cf_priv = cs.sc_cfuncs->cf_init(keylen,
   1233      1.112     alnsn 		    key, &cs.sc_cdata.cf_blocksize);
   1234      1.112     alnsn 		if (cs.sc_cdata.cf_priv == NULL)
   1235      1.112     alnsn 			panic("cf_priv is NULL");
   1236      1.112     alnsn 		if (cs.sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE)
   1237      1.112     alnsn 			panic("bad block size %zu", cs.sc_cdata.cf_blocksize);
   1238      1.112     alnsn 
   1239      1.112     alnsn 		cs.sc_cdata.cf_blocksize /= 8;
   1240      1.112     alnsn 
   1241      1.112     alnsn 		buf = malloc(txtlen, M_DEVBUF, M_WAITOK);
   1242      1.112     alnsn 		memcpy(buf, selftests[i].ptxt, txtlen);
   1243      1.112     alnsn 
   1244      1.112     alnsn 		cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
   1245      1.112     alnsn 				selftests[i].secsize, CGD_CIPHER_ENCRYPT);
   1246      1.112     alnsn 		if (memcmp(buf, selftests[i].ctxt, txtlen) != 0)
   1247      1.112     alnsn 			panic("encryption is broken");
   1248      1.112     alnsn 
   1249      1.112     alnsn 		cgd_cipher(&cs, buf, buf, txtlen, selftests[i].blkno,
   1250      1.112     alnsn 				selftests[i].secsize, CGD_CIPHER_DECRYPT);
   1251      1.112     alnsn 		if (memcmp(buf, selftests[i].ptxt, txtlen) != 0)
   1252      1.112     alnsn 			panic("decryption is broken");
   1253      1.112     alnsn 
   1254      1.112     alnsn 		free(buf, M_DEVBUF);
   1255      1.112     alnsn 		cs.sc_cfuncs->cf_destroy(cs.sc_cdata.cf_priv);
   1256      1.112     alnsn 	}
   1257      1.112     alnsn 
   1258      1.112     alnsn 	printf("done\n");
   1259      1.112     alnsn }
   1260      1.112     alnsn 
   1261      1.113     kamil MODULE(MODULE_CLASS_DRIVER, cgd, "blowfish,des,dk_subr");
   1262       1.74    jruoho 
   1263       1.58      haad #ifdef _MODULE
   1264       1.66    dyoung CFDRIVER_DECL(cgd, DV_DISK, NULL);
   1265      1.109  pgoyette 
   1266      1.109  pgoyette devmajor_t cgd_bmajor = -1, cgd_cmajor = -1;
   1267       1.74    jruoho #endif
   1268       1.58      haad 
   1269       1.58      haad static int
   1270       1.58      haad cgd_modcmd(modcmd_t cmd, void *arg)
   1271       1.58      haad {
   1272       1.82    martin 	int error = 0;
   1273       1.74    jruoho 
   1274       1.58      haad 	switch (cmd) {
   1275       1.58      haad 	case MODULE_CMD_INIT:
   1276      1.112     alnsn 		selftest();
   1277       1.74    jruoho #ifdef _MODULE
   1278       1.66    dyoung 		error = config_cfdriver_attach(&cgd_cd);
   1279       1.66    dyoung 		if (error)
   1280       1.66    dyoung 			break;
   1281       1.66    dyoung 
   1282       1.66    dyoung 		error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
   1283       1.66    dyoung 	        if (error) {
   1284       1.66    dyoung 			config_cfdriver_detach(&cgd_cd);
   1285  1.114.4.1  pgoyette 			aprint_error("%s: unable to register cfattach for "
   1286      1.109  pgoyette 			    "%s, error %d\n", __func__, cgd_cd.cd_name, error);
   1287       1.66    dyoung 			break;
   1288       1.66    dyoung 		}
   1289      1.109  pgoyette 		/*
   1290      1.109  pgoyette 		 * Attach the {b,c}devsw's
   1291      1.109  pgoyette 		 */
   1292      1.109  pgoyette 		error = devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1293      1.109  pgoyette 		    &cgd_cdevsw, &cgd_cmajor);
   1294       1.74    jruoho 
   1295      1.109  pgoyette 		/*
   1296      1.109  pgoyette 		 * If devsw_attach fails, remove from autoconf database
   1297      1.109  pgoyette 		 */
   1298       1.66    dyoung 		if (error) {
   1299       1.66    dyoung 			config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
   1300       1.66    dyoung 			config_cfdriver_detach(&cgd_cd);
   1301      1.109  pgoyette 			aprint_error("%s: unable to attach %s devsw, "
   1302      1.109  pgoyette 			    "error %d", __func__, cgd_cd.cd_name, error);
   1303       1.66    dyoung 			break;
   1304       1.66    dyoung 		}
   1305       1.74    jruoho #endif
   1306       1.58      haad 		break;
   1307       1.58      haad 
   1308       1.58      haad 	case MODULE_CMD_FINI:
   1309       1.74    jruoho #ifdef _MODULE
   1310      1.109  pgoyette 		/*
   1311      1.109  pgoyette 		 * Remove {b,c}devsw's
   1312      1.109  pgoyette 		 */
   1313      1.109  pgoyette 		devsw_detach(&cgd_bdevsw, &cgd_cdevsw);
   1314      1.109  pgoyette 
   1315      1.109  pgoyette 		/*
   1316      1.109  pgoyette 		 * Now remove device from autoconf database
   1317      1.109  pgoyette 		 */
   1318       1.66    dyoung 		error = config_cfattach_detach(cgd_cd.cd_name, &cgd_ca);
   1319      1.109  pgoyette 		if (error) {
   1320      1.110  pgoyette 			(void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1321      1.109  pgoyette 			    &cgd_cdevsw, &cgd_cmajor);
   1322      1.109  pgoyette 			aprint_error("%s: failed to detach %s cfattach, "
   1323      1.109  pgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
   1324  1.114.4.1  pgoyette 			break;
   1325      1.109  pgoyette 		}
   1326      1.109  pgoyette 		error = config_cfdriver_detach(&cgd_cd);
   1327      1.109  pgoyette 		if (error) {
   1328      1.110  pgoyette 			(void)config_cfattach_attach(cgd_cd.cd_name, &cgd_ca);
   1329      1.110  pgoyette 			(void)devsw_attach("cgd", &cgd_bdevsw, &cgd_bmajor,
   1330      1.109  pgoyette 			    &cgd_cdevsw, &cgd_cmajor);
   1331      1.109  pgoyette 			aprint_error("%s: failed to detach %s cfdriver, "
   1332      1.109  pgoyette 			    "error %d\n", __func__, cgd_cd.cd_name, error);
   1333       1.66    dyoung 			break;
   1334      1.109  pgoyette 		}
   1335       1.74    jruoho #endif
   1336       1.58      haad 		break;
   1337       1.58      haad 
   1338       1.58      haad 	case MODULE_CMD_STAT:
   1339      1.109  pgoyette 		error = ENOTTY;
   1340      1.109  pgoyette 		break;
   1341       1.58      haad 	default:
   1342      1.109  pgoyette 		error = ENOTTY;
   1343      1.109  pgoyette 		break;
   1344       1.58      haad 	}
   1345       1.58      haad 
   1346       1.58      haad 	return error;
   1347       1.58      haad }
   1348