summaryrefslogtreecommitdiffstats
path: root/sys/opencrypto/cryptodev.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2007-03-21 03:42:51 +0000
committersam <sam@FreeBSD.org>2007-03-21 03:42:51 +0000
commitf96ba7ffdacde02e9c3e989c8f6e3e7539b74b46 (patch)
tree05fc03ec94859546cbef49b9fe30d492c4f7bf19 /sys/opencrypto/cryptodev.c
parent3f9dd9edcb00155dff6a9b7686ce432606296d79 (diff)
downloadFreeBSD-src-f96ba7ffdacde02e9c3e989c8f6e3e7539b74b46.zip
FreeBSD-src-f96ba7ffdacde02e9c3e989c8f6e3e7539b74b46.tar.gz
Overhaul driver/subsystem api's:
o make all crypto drivers have a device_t; pseudo drivers like the s/w crypto driver synthesize one o change the api between the crypto subsystem and drivers to use kobj; cryptodev_if.m defines this api o use the fact that all crypto drivers now have a device_t to add support for specifying which of several potential devices to use when doing crypto operations o add new ioctls that allow user apps to select a specific crypto device to use (previous ioctls maintained for compatibility) o overhaul crypto subsystem code to eliminate lots of cruft and hide implementation details from drivers o bring in numerous fixes from Michale Richardson/hifn; mostly for 795x parts o add an optional mechanism for mmap'ing the hifn 795x public key h/w to user space for use by openssl (not enabled by default) o update crypto test tools to use new ioctl's and add cmd line options to specify a device to use for tests These changes will also enable much future work on improving the core crypto subsystem; including proper load balancing and interposing code between the core and drivers to dispatch small operations to the s/w driver as appropriate. These changes were instigated by the work of Michael Richardson. Reviewed by: pjd Approved by: re
Diffstat (limited to 'sys/opencrypto/cryptodev.c')
-rw-r--r--sys/opencrypto/cryptodev.c130
1 files changed, 101 insertions, 29 deletions
diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c
index f3fb9db..7de290c 100644
--- a/sys/opencrypto/cryptodev.c
+++ b/sys/opencrypto/cryptodev.c
@@ -2,6 +2,7 @@
/*-
* Copyright (c) 2001 Theo de Raadt
+ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/fcntl.h>
+#include <sys/bus.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform.h>
@@ -113,6 +115,7 @@ static int csefree(struct csession *);
static int cryptodev_op(struct csession *, struct crypt_op *,
struct ucred *, struct thread *td);
static int cryptodev_key(struct crypt_kop *);
+static int cryptodev_find(struct crypt_find_op *);
static int
cryptof_rw(
@@ -126,6 +129,22 @@ cryptof_rw(
return (EIO);
}
+/*
+ * Check a crypto identifier to see if it requested
+ * a software device/driver. This can be done either
+ * by device name/class or through search constraints.
+ */
+static int
+checkforsoftware(int crid)
+{
+ if (crid & CRYPTOCAP_F_SOFTWARE)
+ return EINVAL; /* XXX */
+ if ((crid & CRYPTOCAP_F_HARDWARE) == 0 &&
+ (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0)
+ return EINVAL; /* XXX */
+ return 0;
+}
+
/* ARGSUSED */
static int
cryptof_ioctl(
@@ -135,6 +154,7 @@ cryptof_ioctl(
struct ucred *active_cred,
struct thread *td)
{
+#define SES2(p) ((struct session2_op *)p)
struct cryptoini cria, crie;
struct fcrypt *fcr = fp->f_data;
struct csession *cse;
@@ -142,16 +162,14 @@ cryptof_ioctl(
struct crypt_op *cop;
struct enc_xform *txform = NULL;
struct auth_hash *thash = NULL;
+ struct crypt_kop *kop;
u_int64_t sid;
u_int32_t ses;
- int error = 0;
+ int error = 0, crid;
- /*
- * XXX: Not sure Giant is needed, but better safe than sorry
- */
- mtx_lock(&Giant);
switch (cmd) {
case CIOCGSESSION:
+ case CIOCGSESSION2:
sop = (struct session_op *)data;
switch (sop->cipher) {
case 0:
@@ -181,7 +199,6 @@ cryptof_ioctl(
txform = &enc_xform_arc4;
break;
default:
- mtx_unlock(&Giant);
return (EINVAL);
}
@@ -218,7 +235,6 @@ cryptof_ioctl(
thash = &auth_hash_null;
break;
default:
- mtx_unlock(&Giant);
return (EINVAL);
}
@@ -260,15 +276,17 @@ cryptof_ioctl(
}
}
- error = crypto_newsession(&sid, (txform ? &crie : &cria), 1);
- if (error) {
- if (crypto_devallowsoft) {
- error = crypto_newsession(&sid,
- (txform ? &crie : &cria), 0);
- }
+ /* NB: CIOGSESSION2 has the crid */
+ if (cmd == CIOCGSESSION2) {
+ crid = SES2(sop)->crid;
+ error = checkforsoftware(crid);
if (error)
goto bail;
- }
+ } else
+ crid = CRYPTOCAP_F_HARDWARE;
+ error = crypto_newsession(&sid, (txform ? &crie : &cria), crid);
+ if (error)
+ goto bail;
cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen,
cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform,
@@ -280,7 +298,10 @@ cryptof_ioctl(
goto bail;
}
sop->ses = cse->ses;
-
+ if (cmd == CIOCGSESSION2) {
+ /* return hardware/driver id */
+ SES2(sop)->crid = CRYPTO_SESID2HID(cse->sid);
+ }
bail:
if (error) {
if (crie.cri_key)
@@ -292,33 +313,53 @@ bail:
case CIOCFSESSION:
ses = *(u_int32_t *)data;
cse = csefind(fcr, ses);
- if (cse == NULL) {
- mtx_unlock(&Giant);
+ if (cse == NULL)
return (EINVAL);
- }
csedelete(fcr, cse);
error = csefree(cse);
break;
case CIOCCRYPT:
cop = (struct crypt_op *)data;
cse = csefind(fcr, cop->ses);
- if (cse == NULL) {
- mtx_unlock(&Giant);
+ if (cse == NULL)
return (EINVAL);
- }
error = cryptodev_op(cse, cop, active_cred, td);
break;
case CIOCKEY:
- error = cryptodev_key((struct crypt_kop *)data);
+ case CIOCKEY2:
+ if (!crypto_userasymcrypto)
+ return (EPERM); /* XXX compat? */
+ mtx_lock(&Giant);
+ kop = (struct crypt_kop *)data;
+ if (cmd == CIOCKEY) {
+ /* NB: crypto core enforces s/w driver use */
+ kop->crk_crid =
+ CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
+ }
+ error = cryptodev_key(kop);
+ mtx_unlock(&Giant);
break;
case CIOCASYMFEAT:
- error = crypto_getfeat((int *)data);
+ if (!crypto_userasymcrypto) {
+ /*
+ * NB: if user asym crypto operations are
+ * not permitted return "no algorithms"
+ * so well-behaved applications will just
+ * fallback to doing them in software.
+ */
+ *(int *)data = 0;
+ } else
+ error = crypto_getfeat((int *)data);
+ break;
+ case CIOCFINDDEV:
+ error = cryptodev_find((struct crypt_find_op *)data);
break;
default:
error = EINVAL;
+ break;
}
- mtx_unlock(&Giant);
return (error);
+#undef SES2
}
static int cryptodev_cb(void *);
@@ -485,12 +526,16 @@ cryptodev_cb(void *op)
{
struct cryptop *crp = (struct cryptop *) op;
struct csession *cse = (struct csession *)crp->crp_opaque;
+ int error;
- cse->error = crp->crp_etype;
- if (crp->crp_etype == EAGAIN)
- return crypto_dispatch(crp);
+ error = crp->crp_etype;
+ if (error == EAGAIN)
+ error = crypto_dispatch(crp);
mtx_lock(&cse->lock);
- wakeup_one(crp);
+ if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
+ cse->error = error;
+ wakeup_one(crp);
+ }
mtx_unlock(&cse->lock);
return (0);
}
@@ -500,7 +545,7 @@ cryptodevkey_cb(void *op)
{
struct cryptkop *krp = (struct cryptkop *) op;
- wakeup(krp);
+ wakeup_one(krp);
return (0);
}
@@ -550,6 +595,7 @@ cryptodev_key(struct crypt_kop *kop)
krp->krp_status = kop->crk_status;
krp->krp_iparams = kop->crk_iparams;
krp->krp_oparams = kop->crk_oparams;
+ krp->krp_crid = kop->crk_crid;
krp->krp_status = 0;
krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
@@ -576,6 +622,7 @@ cryptodev_key(struct crypt_kop *kop)
goto fail;
}
+ kop->crk_crid = krp->krp_crid; /* device that did the work */
if (krp->krp_status != 0) {
error = krp->krp_status;
goto fail;
@@ -602,6 +649,25 @@ fail:
return (error);
}
+static int
+cryptodev_find(struct crypt_find_op *find)
+{
+ device_t dev;
+
+ if (find->crid != -1) {
+ dev = crypto_find_device_byhid(find->crid);
+ if (dev == NULL)
+ return (ENOENT);
+ strlcpy(find->name, device_get_nameunit(dev),
+ sizeof(find->name));
+ } else {
+ find->crid = crypto_find_driver(find->name);
+ if (find->crid == -1)
+ return (ENOENT);
+ }
+ return (0);
+}
+
/* ARGSUSED */
static int
cryptof_poll(
@@ -775,6 +841,12 @@ cryptoioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread
*(u_int32_t *)data = fd;
fdrop(f, td);
break;
+ case CRIOFINDDEV:
+ error = cryptodev_find((struct crypt_find_op *)data);
+ break;
+ case CRIOASYMFEAT:
+ error = crypto_getfeat((int *)data);
+ break;
default:
error = EINVAL;
break;
OpenPOWER on IntegriCloud