mirror of https://gitee.com/openkylin/linux.git
carl9170: export HW random number generator
All AR9170 hardware have a 16-Bit random number generator. The documentation claims the values are suitable for "security keys". The "throughput" is around 320Kibit/s. It's slow, but it does work without introducing any special offload firmware commands. Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
acf1771221
commit
00044f17af
|
@ -39,3 +39,17 @@ config CARL9170_WPC
|
|||
bool
|
||||
depends on CARL9170 && (INPUT = y || INPUT = CARL9170)
|
||||
default y
|
||||
|
||||
config CARL9170_HWRNG
|
||||
bool "Random number generator"
|
||||
depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170)
|
||||
default n
|
||||
help
|
||||
Provides a hardware random number generator to the kernel.
|
||||
|
||||
SECURITY WARNING: It's relatively easy to eavesdrop all
|
||||
generated random numbers from the transport stream with
|
||||
usbmon [software] or special usb sniffer hardware.
|
||||
|
||||
Say N, unless your setup[i.e.: embedded system] has no
|
||||
other rng source and you can afford to take the risk.
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/usb.h>
|
||||
|
@ -449,6 +450,17 @@ struct ar9170 {
|
|||
unsigned int off_override;
|
||||
bool state;
|
||||
} ps;
|
||||
|
||||
#ifdef CONFIG_CARL9170_HWRNG
|
||||
# define CARL9170_HWRNG_CACHE_SIZE CARL9170_MAX_CMD_PAYLOAD_LEN
|
||||
struct {
|
||||
struct hwrng rng;
|
||||
bool initialized;
|
||||
char name[30 + 1];
|
||||
u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)];
|
||||
unsigned int cache_idx;
|
||||
} rng;
|
||||
#endif /* CONFIG_CARL9170_HWRNG */
|
||||
};
|
||||
|
||||
enum carl9170_ps_off_override_reasons {
|
||||
|
|
|
@ -1468,6 +1468,109 @@ static int carl9170_register_wps_button(struct ar9170 *ar)
|
|||
}
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
|
||||
#ifdef CONFIG_CARL9170_HWRNG
|
||||
static int carl9170_rng_get(struct ar9170 *ar)
|
||||
{
|
||||
|
||||
#define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32))
|
||||
#define RB (CARL9170_MAX_CMD_PAYLOAD_LEN)
|
||||
|
||||
static const __le32 rng_load[RW] = {
|
||||
[0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)};
|
||||
|
||||
u32 buf[RW];
|
||||
|
||||
unsigned int i, off = 0, transfer, count;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN);
|
||||
|
||||
if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized)
|
||||
return -EAGAIN;
|
||||
|
||||
count = ARRAY_SIZE(ar->rng.cache);
|
||||
while (count) {
|
||||
err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
|
||||
RB, (u8 *) rng_load,
|
||||
RB, (u8 *) buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
transfer = min_t(unsigned int, count, RW);
|
||||
for (i = 0; i < transfer; i++)
|
||||
ar->rng.cache[off + i] = buf[i];
|
||||
|
||||
off += transfer;
|
||||
count -= transfer;
|
||||
}
|
||||
|
||||
ar->rng.cache_idx = 0;
|
||||
|
||||
#undef RW
|
||||
#undef RB
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int carl9170_rng_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
struct ar9170 *ar = (struct ar9170 *)rng->priv;
|
||||
int ret = -EIO;
|
||||
|
||||
mutex_lock(&ar->mutex);
|
||||
if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) {
|
||||
ret = carl9170_rng_get(ar);
|
||||
if (ret) {
|
||||
mutex_unlock(&ar->mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*data = ar->rng.cache[ar->rng.cache_idx++];
|
||||
mutex_unlock(&ar->mutex);
|
||||
|
||||
return sizeof(u16);
|
||||
}
|
||||
|
||||
static void carl9170_unregister_hwrng(struct ar9170 *ar)
|
||||
{
|
||||
if (ar->rng.initialized) {
|
||||
hwrng_unregister(&ar->rng.rng);
|
||||
ar->rng.initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int carl9170_register_hwrng(struct ar9170 *ar)
|
||||
{
|
||||
int err;
|
||||
|
||||
snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name),
|
||||
"%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy));
|
||||
ar->rng.rng.name = ar->rng.name;
|
||||
ar->rng.rng.data_read = carl9170_rng_read;
|
||||
ar->rng.rng.priv = (unsigned long)ar;
|
||||
|
||||
if (WARN_ON(ar->rng.initialized))
|
||||
return -EALREADY;
|
||||
|
||||
err = hwrng_register(&ar->rng.rng);
|
||||
if (err) {
|
||||
dev_err(&ar->udev->dev, "Failed to register the random "
|
||||
"number generator (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ar->rng.initialized = true;
|
||||
|
||||
err = carl9170_rng_get(ar);
|
||||
if (err) {
|
||||
carl9170_unregister_hwrng(ar);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_CARL9170_HWRNG */
|
||||
|
||||
static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
|
@ -1878,6 +1981,12 @@ int carl9170_register(struct ar9170 *ar)
|
|||
goto err_unreg;
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
|
||||
#ifdef CONFIG_CARL9170_HWRNG
|
||||
err = carl9170_register_hwrng(ar);
|
||||
if (err)
|
||||
goto err_unreg;
|
||||
#endif /* CONFIG_CARL9170_HWRNG */
|
||||
|
||||
dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
|
||||
|
@ -1910,6 +2019,10 @@ void carl9170_unregister(struct ar9170 *ar)
|
|||
}
|
||||
#endif /* CONFIG_CARL9170_WPC */
|
||||
|
||||
#ifdef CONFIG_CARL9170_HWRNG
|
||||
carl9170_unregister_hwrng(ar);
|
||||
#endif /* CONFIG_CARL9170_HWRNG */
|
||||
|
||||
carl9170_cancel_worker(ar);
|
||||
cancel_work_sync(&ar->restart_work);
|
||||
|
||||
|
|
Loading…
Reference in New Issue