kernel - Tear out descriptor polling
[dragonfly.git] / sys / opencrypto / cryptodev.c
1 /*      $FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.41 2009/09/04 09:48:18 pjd Exp $   */
2 /*      $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $  */
3
4 /*-
5  * Copyright (c) 2001 Theo de Raadt
6  * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in the
16  *   documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *   derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Effort sponsored in part by the Defense Advanced Research Projects
32  * Agency (DARPA) and Air Force Research Laboratory, Air Force
33  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/device.h>
40 #include <sys/mbuf.h>
41 #include <sys/lock.h>
42 #include <sys/sysctl.h>
43 #include <sys/file.h>
44 #include <sys/filedesc.h>
45 #include <sys/errno.h>
46 #include <sys/uio.h>
47 #include <sys/random.h>
48 #include <sys/conf.h>
49 #include <sys/module.h>
50 #include <sys/kernel.h>
51 #include <sys/fcntl.h>
52 #include <sys/proc.h>
53
54 #include <sys/file2.h>
55 #include <sys/thread2.h>
56 #include <sys/mplock2.h>
57
58 #include <opencrypto/cryptodev.h>
59 #include <opencrypto/xform.h>
60
61 struct csession {
62         TAILQ_ENTRY(csession) next;
63         u_int64_t       sid;
64         u_int32_t       ses;
65         struct lock     lock;
66
67         u_int32_t       cipher;
68         struct enc_xform *txform;
69         u_int32_t       mac;
70         struct auth_hash *thash;
71
72         caddr_t         key;
73         int             keylen;
74         u_char          tmp_iv[EALG_MAX_BLOCK_LEN];
75
76         caddr_t         mackey;
77         int             mackeylen;
78
79         struct iovec    iovec;
80         struct uio      uio;
81         int             error;
82 };
83
84 struct fcrypt {
85         TAILQ_HEAD(csessionlist, csession) csessions;
86         int             sesn;
87 };
88
89 static  int cryptof_rw(struct file *fp, struct uio *uio,
90                     struct ucred *cred, int flags);
91 static  int cryptof_ioctl(struct file *, u_long, caddr_t,
92                     struct ucred *, struct sysmsg *);
93 static  int cryptof_kqfilter(struct file *, struct knote *);
94 static  int cryptof_stat(struct file *, struct stat *, struct ucred *);
95 static  int cryptof_close(struct file *);
96
97 static struct fileops cryptofops = {
98     .fo_read = cryptof_rw,
99     .fo_write = cryptof_rw,
100     .fo_ioctl = cryptof_ioctl,
101     .fo_kqfilter = cryptof_kqfilter,
102     .fo_stat = cryptof_stat,
103     .fo_close = cryptof_close,
104     .fo_shutdown = nofo_shutdown
105 };
106
107 static struct csession *csefind(struct fcrypt *, u_int);
108 static int csedelete(struct fcrypt *, struct csession *);
109 static struct csession *cseadd(struct fcrypt *, struct csession *);
110 static struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t,
111     u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *,
112     struct auth_hash *);
113 static int csefree(struct csession *);
114
115 static  int cryptodev_op(struct csession *, struct crypt_op *, struct ucred *);
116 static  int cryptodev_key(struct crypt_kop *);
117 static  int cryptodev_find(struct crypt_find_op *);
118
119 static int
120 cryptof_rw(
121         struct file *fp,
122         struct uio *uio,
123         struct ucred *active_cred,
124         int flags)
125 {
126         return (EIO);
127 }
128
129 /*
130  * Check a crypto identifier to see if it requested
131  * a software device/driver.  This can be done either
132  * by device name/class or through search constraints.
133  */
134 static int
135 checkforsoftware(int crid)
136 {
137         if (crid & CRYPTOCAP_F_SOFTWARE)
138                 return EINVAL;          /* XXX */
139         if ((crid & CRYPTOCAP_F_HARDWARE) == 0 &&
140             (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0)
141                 return EINVAL;          /* XXX */
142         return 0;
143 }
144
145 /* ARGSUSED */
146 static int
147 cryptof_ioctl(struct file *fp, u_long cmd, caddr_t data,
148               struct ucred *cred, struct sysmsg *msg)
149 {
150 #define SES2(p) ((struct session2_op *)p)
151         struct cryptoini cria, crie;
152         struct fcrypt *fcr = fp->f_data;
153         struct csession *cse;
154         struct session_op *sop;
155         struct crypt_op *cop;
156         struct enc_xform *txform = NULL;
157         struct auth_hash *thash = NULL;
158         struct crypt_kop *kop;
159         u_int64_t sid;
160         u_int32_t ses;
161         int error = 0, crid;
162
163         switch (cmd) {
164         case CIOCGSESSION:
165         case CIOCGSESSION2:
166                 sop = (struct session_op *)data;
167                 switch (sop->cipher) {
168                 case 0:
169                         break;
170                 case CRYPTO_DES_CBC:
171                         txform = &enc_xform_des;
172                         break;
173                 case CRYPTO_3DES_CBC:
174                         txform = &enc_xform_3des;
175                         break;
176                 case CRYPTO_BLF_CBC:
177                         txform = &enc_xform_blf;
178                         break;
179                 case CRYPTO_CAST_CBC:
180                         txform = &enc_xform_cast5;
181                         break;
182                 case CRYPTO_SKIPJACK_CBC:
183                         txform = &enc_xform_skipjack;
184                         break;
185                 case CRYPTO_AES_CBC:
186                         txform = &enc_xform_rijndael128;
187                         break;
188                 case CRYPTO_NULL_CBC:
189                         txform = &enc_xform_null;
190                         break;
191                 case CRYPTO_ARC4:
192                         txform = &enc_xform_arc4;
193                         break;
194                 case CRYPTO_CAMELLIA_CBC:
195                         txform = &enc_xform_camellia;
196                         break;
197                 default:
198                         return (EINVAL);
199                 }
200
201                 switch (sop->mac) {
202                 case 0:
203                         break;
204                 case CRYPTO_MD5_HMAC:
205                         thash = &auth_hash_hmac_md5;
206                         break;
207                 case CRYPTO_SHA1_HMAC:
208                         thash = &auth_hash_hmac_sha1;
209                         break;
210                 case CRYPTO_SHA2_256_HMAC:
211                         thash = &auth_hash_hmac_sha2_256;
212                         break;
213                 case CRYPTO_SHA2_384_HMAC:
214                         thash = &auth_hash_hmac_sha2_384;
215                         break;
216                 case CRYPTO_SHA2_512_HMAC:
217                         thash = &auth_hash_hmac_sha2_512;
218                         break;
219                 case CRYPTO_RIPEMD160_HMAC:
220                         thash = &auth_hash_hmac_ripemd_160;
221                         break;
222 #ifdef notdef
223                 case CRYPTO_MD5:
224                         thash = &auth_hash_md5;
225                         break;
226                 case CRYPTO_SHA1:
227                         thash = &auth_hash_sha1;
228                         break;
229 #endif
230                 case CRYPTO_NULL_HMAC:
231                         thash = &auth_hash_null;
232                         break;
233                 default:
234                         return (EINVAL);
235                 }
236
237                 bzero(&crie, sizeof(crie));
238                 bzero(&cria, sizeof(cria));
239
240                 if (txform) {
241                         crie.cri_alg = txform->type;
242                         crie.cri_klen = sop->keylen * 8;
243                         if (sop->keylen > txform->maxkey ||
244                             sop->keylen < txform->minkey) {
245                                 error = EINVAL;
246                                 goto bail;
247                         }
248
249                         crie.cri_key = kmalloc(crie.cri_klen / 8,
250                             M_XDATA, M_WAITOK);
251                         if ((error = copyin(sop->key, crie.cri_key,
252                             crie.cri_klen / 8)))
253                                 goto bail;
254                         if (thash)
255                                 crie.cri_next = &cria;
256                 }
257
258                 if (thash) {
259                         cria.cri_alg = thash->type;
260                         cria.cri_klen = sop->mackeylen * 8;
261                         if (sop->mackeylen != thash->keysize) {
262                                 error = EINVAL;
263                                 goto bail;
264                         }
265
266                         if (cria.cri_klen) {
267                                 cria.cri_key = kmalloc(cria.cri_klen / 8,
268                                     M_XDATA, M_WAITOK);
269                                 if ((error = copyin(sop->mackey, cria.cri_key,
270                                     cria.cri_klen / 8)))
271                                         goto bail;
272                         }
273                 }
274
275                 /* NB: CIOGSESSION2 has the crid */
276                 if (cmd == CIOCGSESSION2) {
277                         crid = SES2(sop)->crid;
278                         error = checkforsoftware(crid);
279                         if (error)
280                                 goto bail;
281                 } else
282                         crid = CRYPTOCAP_F_HARDWARE;
283                 error = crypto_newsession(&sid, (txform ? &crie : &cria), crid);
284                 if (error)
285                         goto bail;
286
287                 cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen,
288                     cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform,
289                     thash);
290
291                 if (cse == NULL) {
292                         crypto_freesession(sid);
293                         error = EINVAL;
294                         goto bail;
295                 }
296                 sop->ses = cse->ses;
297                 if (cmd == CIOCGSESSION2) {
298                         /* return hardware/driver id */
299                         SES2(sop)->crid = CRYPTO_SESID2HID(cse->sid);
300                 }
301 bail:
302                 if (error) {
303                         if (crie.cri_key)
304                                 kfree(crie.cri_key, M_XDATA);
305                         if (cria.cri_key)
306                                 kfree(cria.cri_key, M_XDATA);
307                 }
308                 break;
309         case CIOCFSESSION:
310                 ses = *(u_int32_t *)data;
311                 cse = csefind(fcr, ses);
312                 if (cse == NULL)
313                         return (EINVAL);
314                 csedelete(fcr, cse);
315                 error = csefree(cse);
316                 break;
317         case CIOCCRYPT:
318                 cop = (struct crypt_op *)data;
319                 cse = csefind(fcr, cop->ses);
320                 if (cse == NULL)
321                         return (EINVAL);
322                 error = cryptodev_op(cse, cop, cred);
323                 break;
324         case CIOCKEY:
325         case CIOCKEY2:
326                 if (!crypto_userasymcrypto)
327                         return (EPERM);         /* XXX compat? */
328                 get_mplock();
329                 kop = (struct crypt_kop *)data;
330                 if (cmd == CIOCKEY) {
331                         /* NB: crypto core enforces s/w driver use */
332                         kop->crk_crid =
333                             CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
334                 }
335                 error = cryptodev_key(kop);
336                 rel_mplock();
337                 break;
338         case CIOCASYMFEAT:
339                 if (!crypto_userasymcrypto) {
340                         /*
341                          * NB: if user asym crypto operations are
342                          * not permitted return "no algorithms"
343                          * so well-behaved applications will just
344                          * fallback to doing them in software.
345                          */
346                         *(int *)data = 0;
347                 } else
348                         error = crypto_getfeat((int *)data);
349                 break;
350         case CIOCFINDDEV:
351                 error = cryptodev_find((struct crypt_find_op *)data);
352                 break;
353         default:
354                 error = EINVAL;
355                 break;
356         }
357         return (error);
358 #undef SES2
359 }
360
361 static int cryptodev_cb(void *);
362
363
364 static int
365 cryptodev_op(struct csession *cse, struct crypt_op *cop,
366     struct ucred *active_cred)
367 {
368         struct cryptop *crp = NULL;
369         struct cryptodesc *crde = NULL, *crda = NULL;
370         int error;
371
372         if (cop->len > 256*1024-4)
373                 return (E2BIG);
374
375         if (cse->txform) {
376                 if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0)
377                         return (EINVAL);
378         }
379
380         bzero(&cse->uio, sizeof(cse->uio));
381         cse->uio.uio_iov = &cse->iovec;
382         cse->uio.uio_iovcnt = 1;
383         cse->uio.uio_offset = 0;
384         cse->uio.uio_resid = cop->len;
385         cse->uio.uio_segflg = UIO_SYSSPACE;
386         cse->uio.uio_rw = UIO_WRITE;
387         /* XXX: not sure, was td, now curthread? */
388         cse->uio.uio_td = curthread;
389         cse->uio.uio_iov[0].iov_len = cop->len;
390         if (cse->thash) {
391                 cse->uio.uio_iov[0].iov_len += cse->thash->hashsize;
392                 cse->uio.uio_resid += cse->thash->hashsize;
393         }
394         cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
395             M_XDATA, M_WAITOK);
396
397         crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL));
398         if (crp == NULL) {
399                 error = ENOMEM;
400                 goto bail;
401         }
402
403         if (cse->thash) {
404                 crda = crp->crp_desc;
405                 if (cse->txform)
406                         crde = crda->crd_next;
407         } else {
408                 if (cse->txform)
409                         crde = crp->crp_desc;
410                 else {
411                         error = EINVAL;
412                         goto bail;
413                 }
414         }
415
416         if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len)))
417                 goto bail;
418
419         if (crda) {
420                 crda->crd_skip = 0;
421                 crda->crd_len = cop->len;
422                 crda->crd_inject = cop->len;
423
424                 crda->crd_alg = cse->mac;
425                 crda->crd_key = cse->mackey;
426                 crda->crd_klen = cse->mackeylen * 8;
427         }
428
429         if (crde) {
430                 if (cop->op == COP_ENCRYPT)
431                         crde->crd_flags |= CRD_F_ENCRYPT;
432                 else
433                         crde->crd_flags &= ~CRD_F_ENCRYPT;
434                 crde->crd_len = cop->len;
435                 crde->crd_inject = 0;
436
437                 crde->crd_alg = cse->cipher;
438                 crde->crd_key = cse->key;
439                 crde->crd_klen = cse->keylen * 8;
440         }
441
442         crp->crp_ilen = cop->len;
443         crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
444                        | (cop->flags & COP_F_BATCH);
445         crp->crp_buf = (caddr_t)&cse->uio;
446         crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
447         crp->crp_sid = cse->sid;
448         crp->crp_opaque = (void *)cse;
449
450         if (cop->iv) {
451                 if (crde == NULL) {
452                         error = EINVAL;
453                         goto bail;
454                 }
455                 if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
456                         error = EINVAL;
457                         goto bail;
458                 }
459                 if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize)))
460                         goto bail;
461                 bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize);
462                 crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
463                 crde->crd_skip = 0;
464         } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
465                 crde->crd_skip = 0;
466         } else if (crde) {
467                 crde->crd_flags |= CRD_F_IV_PRESENT;
468                 crde->crd_skip = cse->txform->blocksize;
469                 crde->crd_len -= cse->txform->blocksize;
470         }
471
472         if (cop->mac && crda == NULL) {
473                 error = EINVAL;
474                 goto bail;
475         }
476
477 again:
478         /*
479          * Let the dispatch run unlocked, then, interlock against the
480          * callback before checking if the operation completed and going
481          * to sleep.  This insures drivers don't inherit our lock which
482          * results in a lock order reversal between crypto_dispatch forced
483          * entry and the crypto_done callback into us.
484          */
485         error = crypto_dispatch(crp);
486         lockmgr(&cse->lock, LK_EXCLUSIVE);
487         if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0)
488                 error = lksleep(crp, &cse->lock, 0, "crydev", 0);
489         lockmgr(&cse->lock, LK_RELEASE);
490
491         if (error != 0)
492                 goto bail;
493
494         if (crp->crp_etype == EAGAIN) {
495                 crp->crp_etype = 0;
496                 crp->crp_flags &= ~CRYPTO_F_DONE;
497                 goto again;
498         }
499
500         if (crp->crp_etype != 0) {
501                 error = crp->crp_etype;
502                 goto bail;
503         }
504
505         if (cse->error) {
506                 error = cse->error;
507                 goto bail;
508         }
509
510         if (cop->dst &&
511             (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len)))
512                 goto bail;
513
514         if (cop->mac &&
515             (error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
516             cop->mac, cse->thash->hashsize)))
517                 goto bail;
518
519 bail:
520         if (crp)
521                 crypto_freereq(crp);
522         if (cse->uio.uio_iov[0].iov_base)
523                 kfree(cse->uio.uio_iov[0].iov_base, M_XDATA);
524
525         return (error);
526 }
527
528 static int
529 cryptodev_cb(void *op)
530 {
531         struct cryptop *crp = (struct cryptop *) op;
532         struct csession *cse = (struct csession *)crp->crp_opaque;
533
534         lockmgr(&cse->lock, LK_EXCLUSIVE);
535         cse->error = crp->crp_etype;
536         wakeup_one(crp);
537         lockmgr(&cse->lock, LK_RELEASE);
538         return (0);
539 }
540
541 static int
542 cryptodevkey_cb(void *op)
543 {
544         struct cryptkop *krp = (struct cryptkop *) op;
545
546         wakeup_one(krp);
547         return (0);
548 }
549
550 static int
551 cryptodev_key(struct crypt_kop *kop)
552 {
553         struct cryptkop *krp = NULL;
554         int error = EINVAL;
555         int in, out, size, i;
556
557         if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
558                 return (EFBIG);
559         }
560
561         in = kop->crk_iparams;
562         out = kop->crk_oparams;
563         switch (kop->crk_op) {
564         case CRK_MOD_EXP:
565                 if (in == 3 && out == 1)
566                         break;
567                 return (EINVAL);
568         case CRK_MOD_EXP_CRT:
569                 if (in == 6 && out == 1)
570                         break;
571                 return (EINVAL);
572         case CRK_DSA_SIGN:
573                 if (in == 5 && out == 2)
574                         break;
575                 return (EINVAL);
576         case CRK_DSA_VERIFY:
577                 if (in == 7 && out == 0)
578                         break;
579                 return (EINVAL);
580         case CRK_DH_COMPUTE_KEY:
581                 if (in == 3 && out == 1)
582                         break;
583                 return (EINVAL);
584         default:
585                 return (EINVAL);
586         }
587
588         krp = (struct cryptkop *)kmalloc(sizeof *krp, M_XDATA, M_WAITOK | M_ZERO);
589         krp->krp_op = kop->crk_op;
590         krp->krp_status = kop->crk_status;
591         krp->krp_iparams = kop->crk_iparams;
592         krp->krp_oparams = kop->crk_oparams;
593         krp->krp_crid = kop->crk_crid;
594         krp->krp_status = 0;
595         krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
596
597         for (i = 0; i < CRK_MAXPARAM; i++) {
598                 if (kop->crk_param[i].crp_nbits > 65536)
599                         /* Limit is the same as in OpenBSD */
600                         goto fail;
601                 krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
602         }
603         for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
604                 size = (krp->krp_param[i].crp_nbits + 7) / 8;
605                 if (size == 0)
606                         continue;
607                 krp->krp_param[i].crp_p = kmalloc(size, M_XDATA, M_WAITOK);
608                 if (i >= krp->krp_iparams)
609                         continue;
610                 error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size);
611                 if (error)
612                         goto fail;
613         }
614
615         error = crypto_kdispatch(krp);
616         if (error)
617                 goto fail;
618         error = tsleep(krp, 0, "crydev", 0);
619         if (error) {
620                 /* XXX can this happen?  if so, how do we recover? */
621                 goto fail;
622         }
623         
624         kop->crk_crid = krp->krp_crid;          /* device that did the work */
625         if (krp->krp_status != 0) {
626                 error = krp->krp_status;
627                 goto fail;
628         }
629
630         for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
631                 size = (krp->krp_param[i].crp_nbits + 7) / 8;
632                 if (size == 0)
633                         continue;
634                 error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size);
635                 if (error)
636                         goto fail;
637         }
638
639 fail:
640         if (krp) {
641                 kop->crk_status = krp->krp_status;
642                 for (i = 0; i < CRK_MAXPARAM; i++) {
643                         if (krp->krp_param[i].crp_p)
644                                 kfree(krp->krp_param[i].crp_p, M_XDATA);
645                 }
646                 kfree(krp, M_XDATA);
647         }
648         return (error);
649 }
650
651 static int
652 cryptodev_find(struct crypt_find_op *find)
653 {
654         device_t dev;
655
656         if (find->crid != -1) {
657                 dev = crypto_find_device_byhid(find->crid);
658                 if (dev == NULL)
659                         return (ENOENT);
660                 strlcpy(find->name, device_get_nameunit(dev),
661                     sizeof(find->name));
662         } else {
663                 find->crid = crypto_find_driver(find->name);
664                 if (find->crid == -1)
665                         return (ENOENT);
666         }
667         return (0);
668 }
669
670 /*
671  * MPSAFE
672  */
673 static int
674 cryptof_kqfilter(struct file *fp, struct knote *kn)
675 {
676
677         return (0);
678 }
679
680 /*
681  * MPSAFE
682  */
683 static int
684 cryptof_stat(struct file *fp, struct stat *sb, struct ucred *cred)
685 {
686         return (EOPNOTSUPP);
687 }
688
689 /*
690  * MPALMOSTSAFE - acquires mplock
691  */
692 static int
693 cryptof_close(struct file *fp)
694 {
695         struct fcrypt *fcr = fp->f_data;
696         struct csession *cse;
697
698         get_mplock();
699         fcr = (struct fcrypt *)fp->f_data;
700         while ((cse = TAILQ_FIRST(&fcr->csessions))) {
701                 TAILQ_REMOVE(&fcr->csessions, cse, next);
702                 (void)csefree(cse);
703         }
704         fp->f_data = NULL;
705         rel_mplock();
706
707         kfree(fcr, M_XDATA);
708         return (0);
709 }
710
711 static struct csession *
712 csefind(struct fcrypt *fcr, u_int ses)
713 {
714         struct csession *cse;
715
716         TAILQ_FOREACH(cse, &fcr->csessions, next)
717                 if (cse->ses == ses)
718                         return (cse);
719         return (NULL);
720 }
721
722 static int
723 csedelete(struct fcrypt *fcr, struct csession *cse_del)
724 {
725         struct csession *cse;
726
727         TAILQ_FOREACH(cse, &fcr->csessions, next) {
728                 if (cse == cse_del) {
729                         TAILQ_REMOVE(&fcr->csessions, cse, next);
730                         return (1);
731                 }
732         }
733         return (0);
734 }
735         
736 static struct csession *
737 cseadd(struct fcrypt *fcr, struct csession *cse)
738 {
739         TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
740         cse->ses = fcr->sesn++;
741         return (cse);
742 }
743
744 struct csession *
745 csecreate(struct fcrypt *fcr, u_int64_t sid, caddr_t key, u_int64_t keylen,
746     caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac,
747     struct enc_xform *txform, struct auth_hash *thash)
748 {
749         struct csession *cse;
750
751         cse = kmalloc(sizeof(struct csession), M_XDATA, M_NOWAIT);
752         if (cse == NULL)
753                 return NULL;
754         lockinit(&cse->lock, "cryptodev", 0, LK_CANRECURSE);
755         cse->key = key;
756         cse->keylen = keylen/8;
757         cse->mackey = mackey;
758         cse->mackeylen = mackeylen/8;
759         cse->sid = sid;
760         cse->cipher = cipher;
761         cse->mac = mac;
762         cse->txform = txform;
763         cse->thash = thash;
764         cseadd(fcr, cse);
765         return (cse);
766 }
767
768 static int
769 csefree(struct csession *cse)
770 {
771         int error;
772
773         error = crypto_freesession(cse->sid);
774         lockuninit(&cse->lock);
775         if (cse->key)
776                 kfree(cse->key, M_XDATA);
777         if (cse->mackey)
778                 kfree(cse->mackey, M_XDATA);
779         kfree(cse, M_XDATA);
780         return (error);
781 }
782
783 static int
784 cryptoopen(struct dev_open_args *ap)
785 {
786         return (0);
787 }
788
789 static int
790 cryptoread(struct dev_read_args *ap)
791 {
792         return (EIO);
793 }
794
795 static int
796 cryptowrite(struct dev_write_args *ap)
797 {
798         return (EIO);
799 }
800
801 static int
802 cryptoioctl(struct dev_ioctl_args *ap)
803 {
804         struct thread *td = curthread;
805         struct file *f;
806         struct fcrypt *fcr;
807         int fd, error;
808
809         switch (ap->a_cmd) {
810         case CRIOGET:
811                 fcr = kmalloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK);
812                 TAILQ_INIT(&fcr->csessions);
813                 fcr->sesn = 0;
814
815                 KKASSERT(td->td_lwp);
816                 error = falloc(td->td_lwp, &f, &fd);
817
818                 if (error) {
819                         kfree(fcr, M_XDATA);
820                         return (error);
821                 }
822                 /* falloc automatically provides an extra reference to 'f'. */
823                 f->f_flag = FREAD | FWRITE;
824                 f->f_type = DTYPE_CRYPTO;
825                 f->f_ops = &cryptofops;
826                 f->f_data = fcr;
827                 fsetfd(td->td_proc->p_fd, f, fd);
828                 *(u_int32_t *)ap->a_data = fd;
829                 fdrop(f);
830
831                 break;
832         case CRIOFINDDEV:
833                 error = cryptodev_find((struct crypt_find_op *)ap->a_data);
834                 break;
835         case CRIOASYMFEAT:
836                 error = crypto_getfeat((int *)ap->a_data);
837                 break;
838         default:
839                 error = EINVAL;
840                 break;
841         }
842         return (error);
843 }
844
845 static struct dev_ops crypto_ops = {
846         { "crypto", 0, D_MPSAFE_READ | D_MPSAFE_WRITE | D_MPSAFE_IOCTL },
847         .d_open =       cryptoopen,
848         .d_read =       cryptoread,
849         .d_write =      cryptowrite,
850         .d_ioctl =      cryptoioctl,
851 };
852
853 /*
854  * Initialization code, both for static and dynamic loading.
855  */
856 static int
857 cryptodev_modevent(module_t mod, int type, void *unused)
858 {
859         switch (type) {
860         case MOD_LOAD:
861                 if (bootverbose)
862                         kprintf("crypto: <crypto device>\n");
863                 make_dev(&crypto_ops, 0, UID_ROOT, GID_WHEEL,
864                          0666, "crypto");
865                 return 0;
866         case MOD_UNLOAD:
867                 /*XXX disallow if active sessions */
868                 //dev_ops_remove(&crypto_ops, 0, 0);
869                 dev_ops_remove_all(&crypto_ops);
870                 return 0;
871         }
872         return EINVAL;
873 }
874
875 static moduledata_t cryptodev_mod = {
876         "cryptodev",
877         cryptodev_modevent,
878         0
879 };
880 MODULE_VERSION(cryptodev, 1);
881 DECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
882 MODULE_DEPEND(cryptodev, crypto, 1, 1, 1);
883 MODULE_DEPEND(cryptodev, zlib, 1, 1, 1);