diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2011-08-15 14:09:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-24 14:41:42 -0400 |
commit | 00044f17afd36bf6397b9a2a12f242a057449e9a (patch) | |
tree | 5b216a3fa13357b352bebd28272e0698380a2b54 /drivers/net/wireless/ath/carl9170 | |
parent | acf1771221f2877ab5d36487930cd6a2ecaa73e6 (diff) |
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>
Diffstat (limited to 'drivers/net/wireless/ath/carl9170')
-rw-r--r-- | drivers/net/wireless/ath/carl9170/Kconfig | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath/carl9170/carl9170.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 113 |
3 files changed, 139 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 2d1b821b440..267d5dcf82d 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig | |||
@@ -39,3 +39,17 @@ config CARL9170_WPC | |||
39 | bool | 39 | bool |
40 | depends on CARL9170 && (INPUT = y || INPUT = CARL9170) | 40 | depends on CARL9170 && (INPUT = y || INPUT = CARL9170) |
41 | default y | 41 | default y |
42 | |||
43 | config CARL9170_HWRNG | ||
44 | bool "Random number generator" | ||
45 | depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170) | ||
46 | default n | ||
47 | help | ||
48 | Provides a hardware random number generator to the kernel. | ||
49 | |||
50 | SECURITY WARNING: It's relatively easy to eavesdrop all | ||
51 | generated random numbers from the transport stream with | ||
52 | usbmon [software] or special usb sniffer hardware. | ||
53 | |||
54 | Say N, unless your setup[i.e.: embedded system] has no | ||
55 | other rng source and you can afford to take the risk. | ||
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 74350d63f68..6cfbb419e2f 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/firmware.h> | 43 | #include <linux/firmware.h> |
44 | #include <linux/completion.h> | 44 | #include <linux/completion.h> |
45 | #include <linux/spinlock.h> | 45 | #include <linux/spinlock.h> |
46 | #include <linux/hw_random.h> | ||
46 | #include <net/cfg80211.h> | 47 | #include <net/cfg80211.h> |
47 | #include <net/mac80211.h> | 48 | #include <net/mac80211.h> |
48 | #include <linux/usb.h> | 49 | #include <linux/usb.h> |
@@ -449,6 +450,17 @@ struct ar9170 { | |||
449 | unsigned int off_override; | 450 | unsigned int off_override; |
450 | bool state; | 451 | bool state; |
451 | } ps; | 452 | } ps; |
453 | |||
454 | #ifdef CONFIG_CARL9170_HWRNG | ||
455 | # define CARL9170_HWRNG_CACHE_SIZE CARL9170_MAX_CMD_PAYLOAD_LEN | ||
456 | struct { | ||
457 | struct hwrng rng; | ||
458 | bool initialized; | ||
459 | char name[30 + 1]; | ||
460 | u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)]; | ||
461 | unsigned int cache_idx; | ||
462 | } rng; | ||
463 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
452 | }; | 464 | }; |
453 | 465 | ||
454 | enum carl9170_ps_off_override_reasons { | 466 | enum carl9170_ps_off_override_reasons { |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 85cb1bdebaa..782b8f3ae58 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -1468,6 +1468,109 @@ static int carl9170_register_wps_button(struct ar9170 *ar) | |||
1468 | } | 1468 | } |
1469 | #endif /* CONFIG_CARL9170_WPC */ | 1469 | #endif /* CONFIG_CARL9170_WPC */ |
1470 | 1470 | ||
1471 | #ifdef CONFIG_CARL9170_HWRNG | ||
1472 | static int carl9170_rng_get(struct ar9170 *ar) | ||
1473 | { | ||
1474 | |||
1475 | #define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32)) | ||
1476 | #define RB (CARL9170_MAX_CMD_PAYLOAD_LEN) | ||
1477 | |||
1478 | static const __le32 rng_load[RW] = { | ||
1479 | [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)}; | ||
1480 | |||
1481 | u32 buf[RW]; | ||
1482 | |||
1483 | unsigned int i, off = 0, transfer, count; | ||
1484 | int err; | ||
1485 | |||
1486 | BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN); | ||
1487 | |||
1488 | if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized) | ||
1489 | return -EAGAIN; | ||
1490 | |||
1491 | count = ARRAY_SIZE(ar->rng.cache); | ||
1492 | while (count) { | ||
1493 | err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG, | ||
1494 | RB, (u8 *) rng_load, | ||
1495 | RB, (u8 *) buf); | ||
1496 | if (err) | ||
1497 | return err; | ||
1498 | |||
1499 | transfer = min_t(unsigned int, count, RW); | ||
1500 | for (i = 0; i < transfer; i++) | ||
1501 | ar->rng.cache[off + i] = buf[i]; | ||
1502 | |||
1503 | off += transfer; | ||
1504 | count -= transfer; | ||
1505 | } | ||
1506 | |||
1507 | ar->rng.cache_idx = 0; | ||
1508 | |||
1509 | #undef RW | ||
1510 | #undef RB | ||
1511 | return 0; | ||
1512 | } | ||
1513 | |||
1514 | static int carl9170_rng_read(struct hwrng *rng, u32 *data) | ||
1515 | { | ||
1516 | struct ar9170 *ar = (struct ar9170 *)rng->priv; | ||
1517 | int ret = -EIO; | ||
1518 | |||
1519 | mutex_lock(&ar->mutex); | ||
1520 | if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) { | ||
1521 | ret = carl9170_rng_get(ar); | ||
1522 | if (ret) { | ||
1523 | mutex_unlock(&ar->mutex); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | *data = ar->rng.cache[ar->rng.cache_idx++]; | ||
1529 | mutex_unlock(&ar->mutex); | ||
1530 | |||
1531 | return sizeof(u16); | ||
1532 | } | ||
1533 | |||
1534 | static void carl9170_unregister_hwrng(struct ar9170 *ar) | ||
1535 | { | ||
1536 | if (ar->rng.initialized) { | ||
1537 | hwrng_unregister(&ar->rng.rng); | ||
1538 | ar->rng.initialized = false; | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | static int carl9170_register_hwrng(struct ar9170 *ar) | ||
1543 | { | ||
1544 | int err; | ||
1545 | |||
1546 | snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name), | ||
1547 | "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy)); | ||
1548 | ar->rng.rng.name = ar->rng.name; | ||
1549 | ar->rng.rng.data_read = carl9170_rng_read; | ||
1550 | ar->rng.rng.priv = (unsigned long)ar; | ||
1551 | |||
1552 | if (WARN_ON(ar->rng.initialized)) | ||
1553 | return -EALREADY; | ||
1554 | |||
1555 | err = hwrng_register(&ar->rng.rng); | ||
1556 | if (err) { | ||
1557 | dev_err(&ar->udev->dev, "Failed to register the random " | ||
1558 | "number generator (%d)\n", err); | ||
1559 | return err; | ||
1560 | } | ||
1561 | |||
1562 | ar->rng.initialized = true; | ||
1563 | |||
1564 | err = carl9170_rng_get(ar); | ||
1565 | if (err) { | ||
1566 | carl9170_unregister_hwrng(ar); | ||
1567 | return err; | ||
1568 | } | ||
1569 | |||
1570 | return 0; | ||
1571 | } | ||
1572 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
1573 | |||
1471 | static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, | 1574 | static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, |
1472 | struct survey_info *survey) | 1575 | struct survey_info *survey) |
1473 | { | 1576 | { |
@@ -1878,6 +1981,12 @@ int carl9170_register(struct ar9170 *ar) | |||
1878 | goto err_unreg; | 1981 | goto err_unreg; |
1879 | #endif /* CONFIG_CARL9170_WPC */ | 1982 | #endif /* CONFIG_CARL9170_WPC */ |
1880 | 1983 | ||
1984 | #ifdef CONFIG_CARL9170_HWRNG | ||
1985 | err = carl9170_register_hwrng(ar); | ||
1986 | if (err) | ||
1987 | goto err_unreg; | ||
1988 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
1989 | |||
1881 | dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", | 1990 | dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", |
1882 | wiphy_name(ar->hw->wiphy)); | 1991 | wiphy_name(ar->hw->wiphy)); |
1883 | 1992 | ||
@@ -1910,6 +2019,10 @@ void carl9170_unregister(struct ar9170 *ar) | |||
1910 | } | 2019 | } |
1911 | #endif /* CONFIG_CARL9170_WPC */ | 2020 | #endif /* CONFIG_CARL9170_WPC */ |
1912 | 2021 | ||
2022 | #ifdef CONFIG_CARL9170_HWRNG | ||
2023 | carl9170_unregister_hwrng(ar); | ||
2024 | #endif /* CONFIG_CARL9170_HWRNG */ | ||
2025 | |||
1913 | carl9170_cancel_worker(ar); | 2026 | carl9170_cancel_worker(ar); |
1914 | cancel_work_sync(&ar->restart_work); | 2027 | cancel_work_sync(&ar->restart_work); |
1915 | 2028 | ||