Documented fix.
[cryptodev-linux.git] / cryptodev_main.c
blob4f41bc51fecacfbf406c04a36eed65f87e7751c6
1 /*
2 * Driver for /dev/crypto device (aka CryptoDev)
4 * Copyright (c) 2004 Michal Ludvig <mludvig@logix.net.nz>, SuSE Labs
5 * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
7 * This file is part of linux cryptodev.
9 * cryptodev is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * cryptodev is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Device /dev/crypto provides an interface for
25 * accessing kernel CryptoAPI algorithms (ciphers,
26 * hashes) from userspace programs.
28 * /dev/crypto interface was originally introduced in
29 * OpenBSD and this module attempts to keep the API.
33 #include <linux/crypto.h>
34 #include <linux/mm.h>
35 #include <linux/highmem.h>
36 #include <linux/pagemap.h>
37 #include <linux/random.h>
38 #include "cryptodev.h"
39 #include <asm/uaccess.h>
40 #include <asm/ioctl.h>
41 #include <linux/scatterlist.h>
42 #include "cryptodev_int.h"
43 #include "version.h"
45 MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
46 MODULE_DESCRIPTION("CryptoDev driver");
47 MODULE_LICENSE("GPL");
49 /* ====== Compile-time config ====== */
51 #define CRYPTODEV_STATS
53 /* ====== Module parameters ====== */
55 int cryptodev_verbosity = 0;
56 module_param(cryptodev_verbosity, int, 0644);
57 MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
59 #ifdef CRYPTODEV_STATS
60 static int enable_stats = 0;
61 module_param(enable_stats, int, 0644);
62 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
63 #endif
65 /* ====== CryptoAPI ====== */
67 #define FILL_SG(sg,ptr,len) \
68 do { \
69 (sg)->page = virt_to_page(ptr); \
70 (sg)->offset = offset_in_page(ptr); \
71 (sg)->length = len; \
72 (sg)->dma_address = 0; \
73 } while (0)
75 struct csession {
76 struct list_head entry;
77 struct semaphore sem;
78 struct cipher_data cdata;
79 struct hash_data hdata;
80 uint32_t sid;
81 #ifdef CRYPTODEV_STATS
82 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
83 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
84 #endif
85 unsigned long long stat[2];
86 size_t stat_max_size, stat_count;
87 #endif
88 int array_size;
89 struct page **pages;
90 struct scatterlist *sg;
93 struct fcrypt {
94 struct list_head list;
95 struct semaphore sem;
98 /* Prepare session for future use. */
99 static int
100 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
102 struct csession *ses_new = NULL, *ses_ptr;
103 int ret = 0;
104 const char *alg_name=NULL;
105 const char *hash_name=NULL;
106 int hmac_mode = 1;
108 /* Does the request make sense? */
109 if (unlikely(!sop->cipher && !sop->mac)) {
110 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
111 return -EINVAL;
114 switch (sop->cipher) {
115 case 0:
116 break;
117 case CRYPTO_DES_CBC:
118 alg_name = "cbc(des)";
119 break;
120 case CRYPTO_3DES_CBC:
121 alg_name = "cbc(des3_ede)";
122 break;
123 case CRYPTO_BLF_CBC:
124 alg_name = "cbc(blowfish)";
125 break;
126 case CRYPTO_AES_CBC:
127 alg_name = "cbc(aes)";
128 break;
129 case CRYPTO_CAMELLIA_CBC:
130 alg_name = "cbc(camelia)";
131 break;
132 case CRYPTO_NULL:
133 alg_name = "ecb(cipher_null)";
134 break;
135 default:
136 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
137 return -EINVAL;
140 switch (sop->mac) {
141 case 0:
142 break;
143 case CRYPTO_MD5_HMAC:
144 hash_name = "hmac(md5)";
145 break;
146 case CRYPTO_RIPEMD160_HMAC:
147 hash_name = "hmac(rmd160)";
148 break;
149 case CRYPTO_SHA1_HMAC:
150 hash_name = "hmac(sha1)";
151 break;
152 case CRYPTO_SHA2_256_HMAC:
153 hash_name = "hmac(sha256)";
154 break;
155 case CRYPTO_SHA2_384_HMAC:
156 hash_name = "hmac(sha384)";
157 break;
158 case CRYPTO_SHA2_512_HMAC:
159 hash_name = "hmac(sha512)";
160 break;
162 /* non-hmac cases */
163 case CRYPTO_MD5:
164 hash_name = "md5";
165 hmac_mode = 0;
166 break;
167 case CRYPTO_RIPEMD160:
168 hash_name = "rmd160";
169 hmac_mode = 0;
170 break;
171 case CRYPTO_SHA1:
172 hash_name = "sha1";
173 hmac_mode = 0;
174 break;
175 case CRYPTO_SHA2_256:
176 hash_name = "sha256";
177 hmac_mode = 0;
178 break;
179 case CRYPTO_SHA2_384:
180 hash_name = "sha384";
181 hmac_mode = 0;
182 break;
183 case CRYPTO_SHA2_512:
184 hash_name = "sha512";
185 hmac_mode = 0;
186 break;
188 default:
189 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
190 return -EINVAL;
193 /* Create a session and put it to the list. */
194 ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL);
195 if(!ses_new) {
196 return -ENOMEM;
199 /* Set-up crypto transform. */
200 if (alg_name) {
201 uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
203 if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
204 dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
205 alg_name, (size_t)sop->keylen*8);
206 ret = -EINVAL;
207 goto error_cipher;
210 ret = copy_from_user(keyp, sop->key, sop->keylen);
211 if (unlikely(ret)) {
212 goto error_cipher;
215 ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp, sop->keylen);
217 if (ret < 0) {
218 dprintk(1,KERN_DEBUG,"%s: Failed to load cipher for %s\n", __func__,
219 alg_name);
220 ret = -EINVAL;
221 goto error_cipher;
225 if (hash_name) {
226 uint8_t keyp[CRYPTO_HMAC_MAX_KEY_LEN];
228 if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
229 dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
230 alg_name, (size_t)sop->mackeylen*8);
231 ret = -EINVAL;
232 goto error_hash;
235 ret = copy_from_user(keyp, sop->mackey, sop->mackeylen);
236 if (unlikely(ret)) {
237 goto error_hash;
240 ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, keyp, sop->mackeylen);
241 if (ret != 0) {
242 dprintk(1,KERN_DEBUG,"%s: Failed to load hash for %s\n", __func__,
243 hash_name);
244 ret = -EINVAL;
245 goto error_hash;
249 ses_new->array_size = 16;
250 dprintk(2, KERN_DEBUG, "%s: preallocating for %d user pages\n",
251 __func__, ses_new->array_size);
252 ses_new->pages = kzalloc(ses_new->array_size *
253 sizeof(struct page *), GFP_KERNEL);
254 ses_new->sg = kzalloc(ses_new->array_size *
255 sizeof(struct scatterlist), GFP_KERNEL);
257 /* put the new session to the list */
258 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
259 init_MUTEX(&ses_new->sem);
261 down(&fcr->sem);
262 restart:
263 list_for_each_entry(ses_ptr, &fcr->list, entry) {
264 /* Check for duplicate SID */
265 if (unlikely(ses_new->sid == ses_ptr->sid)) {
266 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
267 /* Unless we have a broken RNG this
268 shouldn't loop forever... ;-) */
269 goto restart;
273 list_add(&ses_new->entry, &fcr->list);
274 up(&fcr->sem);
276 /* Fill in some values for the user. */
277 sop->ses = ses_new->sid;
279 return 0;
281 error_hash:
282 cryptodev_cipher_deinit( &ses_new->cdata);
283 error_cipher:
284 if (ses_new) kfree(ses_new);
286 return ret;
290 /* Everything that needs to be done when remowing a session. */
291 static inline void
292 crypto_destroy_session(struct csession *ses_ptr)
294 if(down_trylock(&ses_ptr->sem)) {
295 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
296 ses_ptr->sid);
297 down(&ses_ptr->sem);
299 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
300 #if defined(CRYPTODEV_STATS)
301 if(enable_stats)
302 dprintk(2, KERN_DEBUG,
303 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
304 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
305 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
306 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
307 ses_ptr->stat[COP_DECRYPT]) /
308 ses_ptr->stat_count) : 0,
309 ses_ptr->stat_count);
310 #endif
311 cryptodev_cipher_deinit(&ses_ptr->cdata);
312 cryptodev_hash_deinit(&ses_ptr->hdata);
313 dprintk(2, KERN_DEBUG, "%s: freeing space for %d user pages\n",
314 __func__, ses_ptr->array_size);
315 kfree(ses_ptr->pages);
316 kfree(ses_ptr->sg);
317 up(&ses_ptr->sem);
318 kfree(ses_ptr);
321 /* Look up a session by ID and remove. */
322 static int
323 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
325 struct csession *tmp, *ses_ptr;
326 struct list_head *head;
327 int ret = 0;
329 down(&fcr->sem);
330 head = &fcr->list;
331 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
332 if(ses_ptr->sid == sid) {
333 list_del(&ses_ptr->entry);
334 crypto_destroy_session(ses_ptr);
335 break;
339 if (unlikely(!ses_ptr)) {
340 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
341 ret = -ENOENT;
343 up(&fcr->sem);
345 return ret;
348 /* Remove all sessions when closing the file */
349 static int
350 crypto_finish_all_sessions(struct fcrypt *fcr)
352 struct csession *tmp, *ses_ptr;
353 struct list_head *head;
355 down(&fcr->sem);
357 head = &fcr->list;
358 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
359 list_del(&ses_ptr->entry);
360 crypto_destroy_session(ses_ptr);
362 up(&fcr->sem);
364 return 0;
367 /* Look up session by session ID. The returned session is locked. */
368 static struct csession *
369 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
371 struct csession *ses_ptr;
373 down(&fcr->sem);
374 list_for_each_entry(ses_ptr, &fcr->list, entry) {
375 if(ses_ptr->sid == sid) {
376 down(&ses_ptr->sem);
377 break;
380 up(&fcr->sem);
382 return ses_ptr;
385 static int
386 hash_n_crypt(struct csession *ses_ptr, struct crypt_op *cop,
387 struct scatterlist *src_sg, struct scatterlist *dst_sg, uint32_t len)
389 int ret;
391 /* Always hash before encryption and after decryption. Maybe
392 * we should introduce a flag to switch... TBD later on.
394 if (cop->op == COP_ENCRYPT) {
395 if (ses_ptr->hdata.init != 0) {
396 ret = cryptodev_hash_update(&ses_ptr->hdata, src_sg, len);
397 if (unlikely(ret))
398 goto out_err;
400 if (ses_ptr->cdata.init != 0) {
401 ret = cryptodev_cipher_encrypt( &ses_ptr->cdata, src_sg, dst_sg, len);
403 if (unlikely(ret))
404 goto out_err;
406 } else {
407 if (ses_ptr->cdata.init != 0) {
408 ret = cryptodev_cipher_decrypt( &ses_ptr->cdata, src_sg, dst_sg, len);
410 if (unlikely(ret))
411 goto out_err;
414 if (ses_ptr->hdata.init != 0) {
415 ret = cryptodev_hash_update(&ses_ptr->hdata, dst_sg, len);
416 if (unlikely(ret))
417 goto out_err;
420 return 0;
421 out_err:
422 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
423 return ret;
427 /* This is the main crypto function - feed it with plaintext
428 and get a ciphertext (or vice versa :-) */
429 static int
430 __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop)
432 char *data;
433 char __user *src, __user *dst;
434 struct scatterlist sg;
435 size_t nbytes, bufsize;
436 int ret = 0;
438 nbytes = cop->len;
439 data = (char*)__get_free_page(GFP_KERNEL);
441 if (unlikely(!data)) {
442 return -ENOMEM;
444 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
446 src = cop->src;
447 dst = cop->dst;
449 while(nbytes > 0) {
450 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
452 ret = copy_from_user(data, src, current_len);
453 if (unlikely(ret))
454 break;
456 sg_init_one(&sg, data, current_len);
458 ret = hash_n_crypt(ses_ptr, cop, &sg, &sg, current_len);
460 if (unlikely(ret))
461 break;
463 if (ses_ptr->cdata.init != 0) {
464 ret = copy_to_user(dst, data, current_len);
465 if (unlikely(ret))
466 break;
469 dst += current_len;
470 nbytes -= current_len;
471 src += current_len;
474 free_page((unsigned long)data);
475 return ret;
478 #ifndef DISABLE_ZCOPY
480 static void release_user_pages(struct page **pg, int pagecount)
482 while (pagecount--) {
483 if (!PageReserved(pg[pagecount]))
484 SetPageDirty(pg[pagecount]);
485 page_cache_release(pg[pagecount]);
489 /* last page - first page + 1 */
490 #define PAGECOUNT(buf, buflen) \
491 ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \
492 (((unsigned long) buf & PAGE_MASK) >> PAGE_SHIFT) + 1)
494 /* offset of buf in it's first page */
495 #define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK)
497 #define MIN(a, b) ((a > b) ? b : a)
499 /* fetch the pages addr resides in into pg and initialise sg with them */
500 static int __get_userbuf(uint8_t *addr, uint32_t len, int write,
501 int pgcount, struct page **pg, struct scatterlist *sg)
503 int ret, pglen, i = 0;
504 struct scatterlist *sgp;
506 down_write(&current->mm->mmap_sem);
507 ret = get_user_pages(current, current->mm,
508 (unsigned long)addr, pgcount, write, 0, pg, NULL);
509 up_write(&current->mm->mmap_sem);
510 if (ret != pgcount)
511 return -EINVAL;
513 sg_init_table(sg, pgcount);
515 pglen = MIN(PAGE_SIZE - PAGEOFFSET(addr), len);
516 sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr));
518 len -= pglen;
519 for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) {
520 pglen = MIN(PAGE_SIZE, len);
521 sg_set_page(sgp, pg[i++], pglen, 0);
522 len -= pglen;
524 sg_mark_end(sg_last(sg, pgcount));
525 return 0;
528 /* make cop->src and cop->dst available in scatterlists */
529 static int get_userbuf(struct csession *ses,
530 struct crypt_op *cop, struct scatterlist **src_sg,
531 struct scatterlist **dst_sg, int *tot_pages)
533 int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1;
535 BUG_ON(!cop->src);
536 src_pagecount = PAGECOUNT(cop->src, cop->len);
537 if (!ses->cdata.init) { /* hashing only */
538 write_src = 0;
539 } else if (cop->src != cop->dst) { /* non-in-situ transformation */
540 BUG_ON(!cop->dst);
541 dst_pagecount = PAGECOUNT(cop->dst, cop->len);
542 write_src = 0;
544 (*tot_pages) = pagecount = src_pagecount + dst_pagecount;
546 if (pagecount > ses->array_size) {
547 while (ses->array_size < pagecount)
548 ses->array_size *= 2;
550 dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n",
551 __func__, ses->array_size);
552 ses->pages = krealloc(ses->pages, ses->array_size *
553 sizeof(struct page *), GFP_KERNEL);
554 ses->sg = krealloc(ses->sg, ses->array_size *
555 sizeof(struct scatterlist), GFP_KERNEL);
557 if (ses->sg == NULL || ses->pages == NULL) {
558 return -ENOMEM;
562 if (__get_userbuf(cop->src, cop->len, write_src,
563 src_pagecount, ses->pages, ses->sg)) {
564 dprintk(1, KERN_ERR, "failed to get user pages for data input\n");
565 return -EINVAL;
567 (*src_sg) = (*dst_sg) = ses->sg;
569 if (dst_pagecount) {
570 (*dst_sg) = ses->sg + src_pagecount;
572 if (__get_userbuf(cop->dst, cop->len, 1, dst_pagecount,
573 ses->pages + src_pagecount, *dst_sg)) {
574 dprintk(1, KERN_ERR, "failed to get user pages for data output\n");
575 release_user_pages(ses->pages, src_pagecount);
576 return -EINVAL;
579 return 0;
582 /* This is the main crypto function - zero-copy edition */
583 static int
584 __crypto_run_zc(struct csession *ses_ptr, struct crypt_op *cop)
586 struct scatterlist *src_sg, *dst_sg;
587 int ret = 0, pagecount;
589 ret = get_userbuf(ses_ptr, cop, &src_sg, &dst_sg, &pagecount);
590 if (unlikely(ret)) {
591 dprintk(1, KERN_ERR, "Error getting user pages. Falling back to non zero copy.\n");
592 return __crypto_run_std(ses_ptr, cop);
595 ret = hash_n_crypt(ses_ptr, cop, src_sg, dst_sg, cop->len);
597 release_user_pages(ses_ptr->pages, pagecount);
598 return ret;
601 #endif /* DISABLE_ZCOPY */
603 static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
605 struct csession *ses_ptr;
606 uint8_t hash_output[AALG_MAX_RESULT_LEN];
607 int ret;
609 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
610 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
611 return -EINVAL;
614 /* this also enters ses_ptr->sem */
615 ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
616 if (unlikely(!ses_ptr)) {
617 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
618 return -EINVAL;
621 if (ses_ptr->hdata.init != 0) {
622 ret = cryptodev_hash_reset(&ses_ptr->hdata);
623 if (unlikely(ret)) {
624 dprintk(1, KERN_ERR,
625 "error in cryptodev_hash_reset()\n");
626 goto out_unlock;
630 if (ses_ptr->cdata.init != 0) {
631 int blocksize = ses_ptr->cdata.blocksize;
633 if (unlikely(cop->len % blocksize)) {
634 dprintk(1, KERN_ERR,
635 "data size (%u) isn't a multiple of block size (%u)\n",
636 cop->len, blocksize);
637 ret = -EINVAL;
638 goto out_unlock;
641 if (cop->iv) {
642 uint8_t iv[EALG_MAX_BLOCK_LEN];
644 ret = copy_from_user(iv, cop->iv, min( (int)sizeof(iv), (ses_ptr->cdata.ivsize)));
645 if (unlikely(ret)) {
646 dprintk(1, KERN_ERR, "error copying IV (%d bytes)\n", min( (int)sizeof(iv), (ses_ptr->cdata.ivsize)));
647 goto out_unlock;
650 cryptodev_cipher_set_iv(&ses_ptr->cdata, iv, ses_ptr->cdata.ivsize);
654 #ifdef DISABLE_ZCOPY
655 ret = __crypto_run_std(ses_ptr, cop);
656 #else /* normal */
657 ret = __crypto_run_zc(ses_ptr, cop);
658 #endif
659 if (unlikely(ret))
660 goto out_unlock;
662 if (ses_ptr->hdata.init != 0) {
663 ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
664 if (unlikely(ret)) {
665 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
666 goto out_unlock;
669 if (unlikely(copy_to_user(cop->mac, hash_output, ses_ptr->hdata.digestsize)))
670 goto out_unlock;
673 #if defined(CRYPTODEV_STATS)
674 if (enable_stats) {
675 /* this is safe - we check cop->op at the function entry */
676 ses_ptr->stat[cop->op] += cop->len;
677 if (ses_ptr->stat_max_size < cop->len)
678 ses_ptr->stat_max_size = cop->len;
679 ses_ptr->stat_count++;
681 #endif
683 out_unlock:
684 up(&ses_ptr->sem);
685 return ret;
688 /* ====== /dev/crypto ====== */
690 static int
691 cryptodev_open(struct inode *inode, struct file *filp)
693 struct fcrypt *fcr;
695 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
696 if(!fcr)
697 return -ENOMEM;
699 memset(fcr, 0, sizeof(*fcr));
700 init_MUTEX(&fcr->sem);
701 INIT_LIST_HEAD(&fcr->list);
702 filp->private_data = fcr;
704 return 0;
707 static int
708 cryptodev_release(struct inode *inode, struct file *filp)
710 struct fcrypt *fcr = filp->private_data;
712 if(fcr) {
713 crypto_finish_all_sessions(fcr);
714 kfree(fcr);
715 filp->private_data = NULL;
718 return 0;
721 static int
722 clonefd(struct file *filp)
724 struct fdtable *fdt = files_fdtable(current->files);
725 int ret;
726 ret = get_unused_fd();
727 if (ret >= 0) {
728 get_file(filp);
729 FD_SET(ret, fdt->open_fds);
730 fd_install(ret, filp);
733 return ret;
736 static int
737 cryptodev_ioctl(struct inode *inode, struct file *filp,
738 unsigned int cmd, unsigned long arg)
740 int __user *p = (void __user *)arg;
741 struct session_op sop;
742 struct crypt_op cop;
743 struct fcrypt *fcr = filp->private_data;
744 uint32_t ses;
745 int ret, fd;
747 if (unlikely(!fcr))
748 BUG();
750 switch (cmd) {
751 case CIOCASYMFEAT:
752 put_user(0, p);
753 return 0;
754 case CRIOGET:
755 fd = clonefd(filp);
756 put_user(fd, p);
757 return 0;
759 case CIOCGSESSION:
760 ret = copy_from_user(&sop, (void*)arg, sizeof(sop));
761 if (unlikely(ret))
762 return ret;
764 ret = crypto_create_session(fcr, &sop);
765 if (unlikely(ret))
766 return ret;
767 return copy_to_user((void*)arg, &sop, sizeof(sop));
769 case CIOCFSESSION:
770 ret = get_user(ses, (uint32_t*)arg);
771 if (unlikely(ret))
772 return ret;
774 return crypto_finish_session(fcr, ses);
776 case CIOCCRYPT:
777 ret = copy_from_user(&cop, (void*)arg, sizeof(cop));
778 if (unlikely(ret))
779 return ret;
781 ret = crypto_run(fcr, &cop);
782 if (unlikely(ret))
783 return ret;
784 return copy_to_user((void*)arg, &cop, sizeof(cop));
786 default:
787 return -EINVAL;
791 /* compatibility code for 32bit userlands */
792 #ifdef CONFIG_COMPAT
794 static inline void
795 compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
797 sop->cipher = compat->cipher;
798 sop->mac = compat->mac;
799 sop->keylen = compat->keylen;
801 sop->key = compat_ptr(compat->key);
802 sop->mackeylen = compat->mackeylen;
803 sop->mackey = compat_ptr(compat->mackey);
804 sop->ses = compat->ses;
807 static inline void
808 session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
810 compat->cipher = sop->cipher;
811 compat->mac = sop->mac;
812 compat->keylen = sop->keylen;
814 compat->key = ptr_to_compat(sop->key);
815 compat->mackeylen = sop->mackeylen;
816 compat->mackey = ptr_to_compat(sop->mackey);
817 compat->ses = sop->ses;
820 static inline void
821 compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
823 cop->ses = compat->ses;
824 cop->op = compat->op;
825 cop->flags = compat->flags;
826 cop->len = compat->len;
828 cop->src = compat_ptr(compat->src);
829 cop->dst = compat_ptr(compat->dst);
830 cop->mac = compat_ptr(compat->mac);
831 cop->iv = compat_ptr(compat->iv);
834 static inline void
835 crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
837 compat->ses = cop->ses;
838 compat->op = cop->op;
839 compat->flags = cop->flags;
840 compat->len = cop->len;
842 compat->src = ptr_to_compat(cop->src);
843 compat->dst = ptr_to_compat(cop->dst);
844 compat->mac = ptr_to_compat(cop->mac);
845 compat->iv = ptr_to_compat(cop->iv);
848 static long
849 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
851 struct fcrypt *fcr = file->private_data;
852 struct session_op sop;
853 struct compat_session_op compat_sop;
854 struct crypt_op cop;
855 struct compat_crypt_op compat_cop;
856 int ret;
858 if (unlikely(!fcr))
859 BUG();
861 switch (cmd) {
862 case CIOCASYMFEAT:
863 case CRIOGET:
864 case CIOCFSESSION:
865 return cryptodev_ioctl(NULL, file, cmd, arg);
867 case COMPAT_CIOCGSESSION:
868 ret = copy_from_user(&compat_sop,
869 (void *)arg, sizeof(compat_sop));
870 if (unlikely(ret))
871 return ret;
873 compat_to_session_op(&compat_sop, &sop);
875 ret = crypto_create_session(fcr, &sop);
876 if (unlikely(ret))
877 return ret;
879 session_op_to_compat(&sop, &compat_sop);
880 return copy_to_user((void*)arg,
881 &compat_sop, sizeof(compat_sop));
883 case COMPAT_CIOCCRYPT:
884 ret = copy_from_user(&compat_cop,
885 (void*)arg, sizeof(compat_cop));
886 if (unlikely(ret))
887 return ret;
889 compat_to_crypt_op(&compat_cop, &cop);
891 ret = crypto_run(fcr, &cop);
892 if (unlikely(ret))
893 return ret;
895 crypt_op_to_compat(&cop, &compat_cop);
896 return copy_to_user((void*)arg,
897 &compat_cop, sizeof(compat_cop));
899 default:
900 return -EINVAL;
904 #endif /* CONFIG_COMPAT */
906 struct file_operations cryptodev_fops = {
907 .owner = THIS_MODULE,
908 .open = cryptodev_open,
909 .release = cryptodev_release,
910 .ioctl = cryptodev_ioctl,
911 #ifdef CONFIG_COMPAT
912 .compat_ioctl = cryptodev_compat_ioctl,
913 #endif /* CONFIG_COMPAT */
916 struct miscdevice cryptodev = {
917 .minor = MISC_DYNAMIC_MINOR,
918 .name = "crypto",
919 .fops = &cryptodev_fops,
922 static int
923 cryptodev_register(void)
925 int rc;
927 rc = misc_register (&cryptodev);
928 if (unlikely(rc)) {
929 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
930 return rc;
933 return 0;
936 static void
937 cryptodev_deregister(void)
939 misc_deregister(&cryptodev);
942 /* ====== Module init/exit ====== */
944 int __init init_cryptodev(void)
946 int rc;
948 rc = cryptodev_register();
949 if (unlikely(rc))
950 return rc;
952 printk(KERN_INFO PFX "driver %s loaded.\n", VERSION);
954 return 0;
957 void __exit exit_cryptodev(void)
959 cryptodev_deregister();
960 printk(KERN_INFO PFX "driver unloaded.\n");
963 module_init(init_cryptodev);
964 module_exit(exit_cryptodev);