📄 crypto.c
字号:
(CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) { /* * XXX Do some performance testing to determine placing. * XXX We probably need an auxiliary data structure that * XXX describes relative performances. */ cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED; cap->cc_max_op_len[alg] = maxoplen; if (crypto_verbose) printk("crypto: driver %u registers alg %u flags %u maxoplen %u\n" , driverid , alg , flags , maxoplen ); if (cap->cc_process == NULL) { cap->cc_arg = arg; cap->cc_newsession = newses; cap->cc_process = process; cap->cc_freesession = freeses; cap->cc_sessions = 0; /* Unmark */ } err = 0; } else err = EINVAL; CRYPTO_DRIVER_UNLOCK(); return err;}/* * Unregister a crypto driver. If there are pending sessions using it, * leave enough information around so that subsequent calls using those * sessions will correctly detect the driver has been unregistered and * reroute requests. */intcrypto_unregister(u_int32_t driverid, int alg){ int i, err, d_flags; u_int32_t ses; struct cryptocap *cap; dprintk("%s()\n", __FUNCTION__); CRYPTO_DRIVER_LOCK(); cap = crypto_checkdriver(driverid); if (cap != NULL && (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) && cap->cc_alg[alg] != 0) { cap->cc_alg[alg] = 0; cap->cc_max_op_len[alg] = 0; /* Was this the last algorithm ? */ for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++) if (cap->cc_alg[i] != 0) break; if (i == CRYPTO_ALGORITHM_MAX + 1) { ses = cap->cc_sessions; memset(cap, 0, sizeof(struct cryptocap)); if (ses != 0) { /* * If there are pending sessions, just mark as invalid. */ cap->cc_flags |= CRYPTOCAP_F_CLEANUP; cap->cc_sessions = ses; } } err = 0; } else err = EINVAL; CRYPTO_DRIVER_UNLOCK(); return err;}/* * Unregister all algorithms associated with a crypto driver. * If there are pending sessions using it, leave enough information * around so that subsequent calls using those sessions will * correctly detect the driver has been unregistered and reroute * requests. */intcrypto_unregister_all(u_int32_t driverid){ int i, err, d_flags; u_int32_t ses; struct cryptocap *cap; dprintk("%s()\n", __FUNCTION__); CRYPTO_DRIVER_LOCK(); cap = crypto_checkdriver(driverid); if (cap != NULL) { for (i = CRYPTO_ALGORITHM_MIN; i <= CRYPTO_ALGORITHM_MAX; i++) { cap->cc_alg[i] = 0; cap->cc_max_op_len[i] = 0; } ses = cap->cc_sessions; memset(cap, 0, sizeof(struct cryptocap)); if (ses != 0) { /* * If there are pending sessions, just mark as invalid. */ cap->cc_flags |= CRYPTOCAP_F_CLEANUP; cap->cc_sessions = ses; } err = 0; } else err = EINVAL; CRYPTO_DRIVER_UNLOCK(); return err;}/* * Clear blockage on a driver. The what parameter indicates whether * the driver is now ready for cryptop's and/or cryptokop's. */intcrypto_unblock(u_int32_t driverid, int what){ struct cryptocap *cap; int needwakeup, err, q_flags; dprintk("%s()\n", __FUNCTION__); CRYPTO_Q_LOCK(); cap = crypto_checkdriver(driverid); if (cap != NULL) { needwakeup = 0; if (what & CRYPTO_SYMQ) { needwakeup |= cap->cc_qblocked; cap->cc_qblocked = 0; } if (what & CRYPTO_ASYMQ) { needwakeup |= cap->cc_kqblocked; cap->cc_kqblocked = 0; } if (needwakeup) wake_up_interruptible(&cryptoproc_wait); err = 0; } else err = EINVAL; CRYPTO_Q_UNLOCK(); return err;}/* * Add a crypto request to a queue, to be processed by the kernel thread. */intcrypto_dispatch(struct cryptop *crp){ u_int32_t hid = CRYPTO_SESID2HID(crp->crp_sid); int result, q_flags; dprintk("%s()\n", __FUNCTION__); cryptostats.cs_ops++; CRYPTO_Q_LOCK(); if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) { struct cryptocap *cap; /* * Caller marked the request to be processed * immediately; dispatch it directly to the * driver unless the driver is currently blocked. */ cap = crypto_checkdriver(hid); if (cap && !cap->cc_qblocked) { result = crypto_invoke(crp, 0); if (result == ERESTART) { /* * The driver ran out of resources, mark the * driver ``blocked'' for cryptop's and put * the request on the queue. * * XXX ops are placed at the tail so their * order is preserved but this can place them * behind batch'd ops. */ crypto_drivers[hid].cc_qblocked = 1; list_add_tail(&crp->crp_list, &crp_q); cryptostats.cs_blocks++; result = 0; } } else { /* * The driver is blocked, just queue the op until * it unblocks and the kernel thread gets kicked. */ list_add_tail(&crp->crp_list, &crp_q); result = 0; } } else { int wasempty; /* * Caller marked the request as ``ok to delay''; * queue it for the dispatch thread. This is desirable * when the operation is low priority and/or suitable * for batching. */ wasempty = list_empty(&crp_q); list_add_tail(&crp->crp_list, &crp_q); if (wasempty) wake_up_interruptible(&cryptoproc_wait); result = 0; } CRYPTO_Q_UNLOCK(); return result;}/* * Add an asymetric crypto request to a queue, * to be processed by the kernel thread. */intcrypto_kdispatch(struct cryptkop *krp){ struct cryptocap *cap; int result, q_flags; dprintk("%s()\n", __FUNCTION__); cryptostats.cs_kops++; CRYPTO_Q_LOCK(); cap = crypto_checkdriver(krp->krp_hid); if (cap && !cap->cc_kqblocked) { result = crypto_kinvoke(krp, 0); if (result == ERESTART) { /* * The driver ran out of resources, mark the * driver ``blocked'' for cryptkop's and put * the request back in the queue. It would * best to put the request back where we got * it but that's hard so for now we put it * at the front. This should be ok; putting * it at the end does not work. */ crypto_drivers[krp->krp_hid].cc_kqblocked = 1; list_add_tail(&krp->krp_list, &crp_kq); cryptostats.cs_kblocks++; } } else { /* * The driver is blocked, just queue the op until * it unblocks and the kernel thread gets kicked. */ list_add_tail(&krp->krp_list, &crp_kq); result = 0; } CRYPTO_Q_UNLOCK(); return result;}/* * Dispatch an assymetric crypto request to the appropriate crypto devices. */static intcrypto_kinvoke(struct cryptkop *krp, int hint){ u_int32_t hid; int error; dprintk("%s()\n", __FUNCTION__); if (!crypto_q_locked) printk("crypto: crypto_kinvoke called without lock!\n"); /* Sanity checks. */ if (krp == NULL) { dprintk("%s,%d: null krp\n", __FILE__, __LINE__); return EINVAL; } if (krp->krp_callback == NULL) { dprintk("%s,%d: null krp_callback\n", __FILE__, __LINE__); kfree(krp); /* XXX allocated in cryptodev */ return EINVAL; } for (hid = 0; hid < crypto_drivers_num; hid++) { if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_SOFTWARE) && !crypto_devallowsoft) continue; if (crypto_drivers[hid].cc_kprocess == NULL) continue; if ((crypto_drivers[hid].cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) == 0) continue; break; } if (hid < crypto_drivers_num) { krp->krp_hid = hid; error = crypto_drivers[hid].cc_kprocess( crypto_drivers[hid].cc_karg, krp, hint); } else { dprintk("%s,%d: ENODEV\n", __FILE__, __LINE__); error = ENODEV; } if (error) { krp->krp_status = error; crypto_kdone(krp); } return 0;}/* * Dispatch a crypto request to the appropriate crypto devices. */static intcrypto_invoke(struct cryptop *crp, int hint){ u_int32_t hid; int (*process)(void*, struct cryptop *, int); dprintk("%s()\n", __FUNCTION__); if (crypto_q_locked == 0) printk("crypto: crypto_invoke called without lock!\n"); /* Sanity checks. */ if (crp == NULL) return EINVAL; if (crp->crp_callback == NULL) { crypto_freereq(crp); return EINVAL; } if (crp->crp_desc == NULL) { crp->crp_etype = EINVAL; crypto_done(crp); return 0; } hid = CRYPTO_SESID2HID(crp->crp_sid); if (hid < crypto_drivers_num) { if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) crypto_freesession(crp->crp_sid); process = crypto_drivers[hid].cc_process; } else { process = NULL; } if (process == NULL) { struct cryptodesc *crd; u_int64_t nid; /* * Driver has unregistered; migrate the session and return * an error to the caller so they'll resubmit the op. */ for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next) crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI); if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI), 0) == 0) crp->crp_sid = nid; crp->crp_etype = EAGAIN; crypto_done(crp); return 0; } else { /* * Invoke the driver to process the request. */ return (*process)(crypto_drivers[hid].cc_arg, crp, hint); }}/* * Release a set of crypto descriptors. */voidcrypto_freereq(struct cryptop *crp){ struct cryptodesc *crd; if (crp == NULL) return; while ((crd = crp->crp_desc) != NULL) { crp->crp_desc = crd->crd_next; kmem_cache_free(cryptodesc_zone, crd); } kmem_cache_free(cryptop_zone, crp);}/* * Acquire a set of crypto descriptors. */struct cryptop *crypto_getreq(int num){ struct cryptodesc *crd; struct cryptop *crp; crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC); if (crp != NULL) { memset(crp, 0, sizeof(*crp)); INIT_LIST_HEAD(&crp->crp_list); init_waitqueue_head(&crp->crp_waitq); while (num--) { crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC); if (crd == NULL) { crypto_freereq(crp); return NULL; } memset(crd, 0, sizeof(*crd)); crd->crd_next = crp->crp_desc; crp->crp_desc = crd; } } return crp;}/* * Invoke the callback on behalf of the driver. */voidcrypto_done(struct cryptop *crp){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -