/* * hw_random/core.c: HWRNG core API * * Copyright 2006 Michael Buesch <m@bues.ch> * Copyright 2005 (c) MontaVista Software, Inc. * * Please read Documentation/admin-guide/hw_random.rst for details on use. * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference.
*/
staticstruct hwrng *current_rng; /* the current rng has been explicitly chosen by user via sysfs */ staticint cur_rng_set_by_user; staticstruct task_struct *hwrng_fill; /* list of registered rngs */ static LIST_HEAD(rng_list); /* Protects rng_list and current_rng */ static DEFINE_MUTEX(rng_mutex); /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ static DEFINE_MUTEX(reading_mutex); staticint data_avail; static u8 *rng_buffer, *rng_fillbuf; staticunsignedshort current_quality; staticunsignedshort default_quality = 1024; /* default to maximum */
module_param(current_quality, ushort, 0644);
MODULE_PARM_DESC(current_quality, "current hwrng entropy estimation per 1024 bits of input -- obsolete, use rng_quality instead");
module_param(default_quality, ushort, 0644);
MODULE_PARM_DESC(default_quality, "default maximum entropy content of hwrng per 1024 bits of input");
if (mutex_lock_interruptible(&rng_mutex)) return ERR_PTR(-ERESTARTSYS);
rng = get_current_rng_nolock();
mutex_unlock(&rng_mutex); return rng;
}
staticvoid put_rng(struct hwrng *rng)
{ /* * Hold rng_mutex here so we serialize in case they set_current_rng * on rng again immediately.
*/
mutex_lock(&rng_mutex); if (rng)
kref_put(&rng->ref, cleanup_rng);
mutex_unlock(&rng_mutex);
}
staticint hwrng_init(struct hwrng *rng)
{ if (kref_get_unless_zero(&rng->ref)) goto skip_init;
staticint enable_best_rng(void)
{ struct hwrng *rng, *new_rng = NULL; int ret = -ENODEV;
BUG_ON(!mutex_is_locked(&rng_mutex));
/* no rng to use? */ if (list_empty(&rng_list)) {
drop_current_rng();
cur_rng_set_by_user = 0; return 0;
}
/* use the rng which offers the best quality */
list_for_each_entry(rng, &rng_list, list) { if (!new_rng || rng->quality > new_rng->quality)
new_rng = rng;
}
ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); if (!ret)
cur_rng_set_by_user = 0;
/* If we cannot credit at least one bit of entropy, * keep track of the remainder for the next iteration
*/
entropy = rc * quality * 8 + entropy_credit; if ((entropy >> 10) == 0)
entropy_credit = entropy;
int hwrng_register(struct hwrng *rng)
{ int err = -EINVAL; struct hwrng *tmp;
if (!rng->name || (!rng->data_read && !rng->read)) goto out;
mutex_lock(&rng_mutex);
/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) { if (strcmp(tmp->name, rng->name) == 0) goto out_unlock;
}
list_add_tail(&rng->list, &rng_list);
/* Adjust quality field to always have a proper value */
rng->quality = min_t(u16, min_t(u16, default_quality, 1024), rng->quality ?: 1024);
if (!current_rng ||
(!cur_rng_set_by_user && rng->quality > current_rng->quality)) { /* * Set new rng as current as the new rng source * provides better entropy quality and was not * chosen by userspace.
*/
err = set_current_rng(rng); if (err) goto out_unlock;
}
mutex_unlock(&rng_mutex); return 0;
out_unlock:
mutex_unlock(&rng_mutex);
out: return err;
}
EXPORT_SYMBOL_GPL(hwrng_register);
void hwrng_unregister(struct hwrng *rng)
{ struct hwrng *new_rng; int err;
mutex_lock(&rng_mutex);
list_del(&rng->list);
complete_all(&rng->dying); if (current_rng == rng) {
err = enable_best_rng(); if (err) {
drop_current_rng();
cur_rng_set_by_user = 0;
}
}
new_rng = get_current_rng_nolock(); if (list_empty(&rng_list)) {
mutex_unlock(&rng_mutex); if (hwrng_fill)
kthread_stop(hwrng_fill);
} else
mutex_unlock(&rng_mutex);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.