2008-08-04 14:17:39

by Ivo Van Doorn

[permalink] [raw]
Subject: Please pull 'upstream' branch of rt2x00

Hi John,

Only 5 patches, but they do bump rt2x00 to a new version: 2.2.0
This series will add HW crypto support to rt2x00, by default it
has been enabled for rt61pci and rt73usb.

rt2500usb has also been created, but currently does not work
since it requires different handling then rt61pci and rt73usb. Because
I am focussing on different areas in rt2x00 now, it will take some
time before I get back to rt2500usb HW crypto (if there are any volunteers
to take a shot at rt2500usb HW crypto, they are welcome).

rt2500pci supports HW crypto as well, but I won't implement it due
to the way it has to be enabled. It comes down to the fact that during
TX the key has to be provided, and after the encryption an interupt will
be raised after which the frame can be kicked to the air. In the RX path
the same happens, including that after RX the key has to be provided
as well. This will cause the number of IRQ events to double during HW
crypto, and several changes are required in mac80211 to make it possible.
Because of that I see no point in doing anything with it.

Ivo

----
The following changes since commit 2471b779e2f93d76bd4c041e4a8f5a27c859d7ce:
John W. Linville (1):
Revert "mac80211: add direct probe before association"

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git/ upstream

Ivo van Doorn (5):
rt2x00: Implement HW encryption
rt2x00: Implement HW encryption (rt61pci)
rt2x00: Implement HW encryption (rt73usb)
rt2x00: Gather channel information in structure
rt2x00: Release rt2x00 2.2.0

drivers/net/wireless/rt2x00/Kconfig | 6 +
drivers/net/wireless/rt2x00/Makefile | 1 +
drivers/net/wireless/rt2x00/rt2400pci.c | 40 ++--
drivers/net/wireless/rt2x00/rt2400pci.h | 22 +--
drivers/net/wireless/rt2x00/rt2500pci.c | 39 +++--
drivers/net/wireless/rt2x00/rt2500pci.h | 17 +-
drivers/net/wireless/rt2x00/rt2500usb.c | 39 +++--
drivers/net/wireless/rt2x00/rt2500usb.h | 17 +-
drivers/net/wireless/rt2x00/rt2x00.h | 64 +++++-
drivers/net/wireless/rt2x00/rt2x00config.c | 4 +
drivers/net/wireless/rt2x00/rt2x00crypto.c | 215 +++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00debug.c | 97 +++++++++
drivers/net/wireless/rt2x00/rt2x00dev.c | 48 +++--
drivers/net/wireless/rt2x00/rt2x00lib.h | 47 ++++
drivers/net/wireless/rt2x00/rt2x00mac.c | 110 +++++++++-
drivers/net/wireless/rt2x00/rt2x00queue.c | 81 +++++++-
drivers/net/wireless/rt2x00/rt2x00queue.h | 73 ++++++-
drivers/net/wireless/rt2x00/rt2x00reg.h | 19 ++-
drivers/net/wireless/rt2x00/rt61pci.c | 298 ++++++++++++++++++++++++--
drivers/net/wireless/rt2x00/rt61pci.h | 38 ++--
drivers/net/wireless/rt2x00/rt73usb.c | 314 +++++++++++++++++++++++++---
drivers/net/wireless/rt2x00/rt73usb.h | 38 ++--
22 files changed, 1418 insertions(+), 209 deletions(-)
create mode 100644 drivers/net/wireless/rt2x00/rt2x00crypto.c


2008-08-04 14:18:18

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 4/5] rt2x00: Gather channel information in structure

Channel information which is read from EEPROM should
be read into an array containing per-channel information.
This removes the requirement of multiple arrays and makes
the channel handling a bit cleaner and easier to expand.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2400pci.c | 40 +++++++++++++++----------
drivers/net/wireless/rt2x00/rt2400pci.h | 22 +++++---------
drivers/net/wireless/rt2x00/rt2500pci.c | 39 +++++++++++++++++--------
drivers/net/wireless/rt2x00/rt2500pci.h | 17 +++--------
drivers/net/wireless/rt2x00/rt2500usb.c | 39 +++++++++++++++++--------
drivers/net/wireless/rt2x00/rt2500usb.h | 17 +++--------
drivers/net/wireless/rt2x00/rt2x00.h | 23 ++++++++++-----
drivers/net/wireless/rt2x00/rt2x00config.c | 4 ++
drivers/net/wireless/rt2x00/rt2x00dev.c | 18 ++---------
drivers/net/wireless/rt2x00/rt61pci.c | 42 ++++++++++++++++-----------
drivers/net/wireless/rt2x00/rt61pci.h | 17 +++--------
drivers/net/wireless/rt2x00/rt73usb.c | 43 +++++++++++++++------------
drivers/net/wireless/rt2x00/rt73usb.h | 17 +++--------
13 files changed, 176 insertions(+), 162 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 4c0538d..0107cec 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1404,7 +1404,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* RF value list for RF2420 & RF2421
* Supports: 2.4 GHz
*/
-static const struct rf_channel rf_vals_bg[] = {
+static const struct rf_channel rf_vals_b[] = {
{ 1, 0x00022058, 0x000c1fda, 0x00000101, 0 },
{ 2, 0x00022058, 0x000c1fee, 0x00000101, 0 },
{ 3, 0x00022058, 0x000c2002, 0x00000101, 0 },
@@ -1421,10 +1421,11 @@ static const struct rf_channel rf_vals_bg[] = {
{ 14, 0x00022058, 0x000c20fa, 0x00000101, 0 },
};

-static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
- u8 *txpower;
+ struct channel_info *info;
+ char *tx_power;
unsigned int i;

/*
@@ -1440,23 +1441,28 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));

/*
- * Convert tx_power array in eeprom.
- */
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
- /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK;
- spec->tx_power_a = NULL;
- spec->tx_power_bg = txpower;
- spec->tx_power_default = DEFAULT_TXPOWER;

- spec->num_channels = ARRAY_SIZE(rf_vals_bg);
- spec->channels = rf_vals_bg;
+ spec->num_channels = ARRAY_SIZE(rf_vals_b);
+ spec->channels = rf_vals_b;
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ spec->channels_info = info;
+
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+ return 0;
}

static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1477,7 +1483,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw specifications.
*/
- rt2400pci_probe_hw_mode(rt2x00dev);
+ retval = rt2400pci_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;

/*
* This device requires the atim queue and DMA-mapped skbs.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index bc55642..bbff381 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -938,19 +938,13 @@
#define MAX_TXPOWER 62
#define DEFAULT_TXPOWER 39

-#define TXPOWER_FROM_DEV(__txpower) \
-({ \
- ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
- ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
- (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \
-})
-
-#define TXPOWER_TO_DEV(__txpower) \
-({ \
- (__txpower) += MIN_TXPOWER; \
- ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \
- (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \
- (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \
-})
+#define __CLAMP_TX(__txpower) \
+ clamp_t(char, (__txpower), MIN_TXPOWER, MAX_TXPOWER)
+
+#define TXPOWER_FROM_DEV(__txpower) \
+ ((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER)
+
+#define TXPOWER_TO_DEV(__txpower) \
+ MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER)

#endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 181a146..e0ff76f 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1721,10 +1721,11 @@ static const struct rf_channel rf_vals_5222[] = {
{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
};

-static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
- u8 *txpower;
+ struct channel_info *info;
+ char *tx_power;
unsigned int i;

/*
@@ -1741,20 +1742,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));

/*
- * Convert tx_power array in eeprom.
- */
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
- /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- spec->tx_power_a = NULL;
- spec->tx_power_bg = txpower;
- spec->tx_power_default = DEFAULT_TXPOWER;

if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
@@ -1776,6 +1767,26 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
}
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ spec->channels_info = info;
+
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+ if (spec->num_channels > 14) {
+ for (i = 14; i < spec->num_channels; i++)
+ info[i].tx_power1 = DEFAULT_TXPOWER;
+ }
+
+ return 0;
}

static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1796,7 +1807,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw specifications.
*/
- rt2500pci_probe_hw_mode(rt2x00dev);
+ retval = rt2500pci_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;

/*
* This device requires the atim queue and DMA-mapped skbs.
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index 42f3769..8c26bef 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1223,17 +1223,10 @@
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24

-#define TXPOWER_FROM_DEV(__txpower) \
-({ \
- ((__txpower) > MAX_TXPOWER) ? \
- DEFAULT_TXPOWER : (__txpower); \
-})
-
-#define TXPOWER_TO_DEV(__txpower) \
-({ \
- ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
- (__txpower)); \
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+ (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)

#endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index c6f6eb6..df78bd3 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1652,10 +1652,11 @@ static const struct rf_channel rf_vals_5222[] = {
{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
};

-static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
- u8 *txpower;
+ struct channel_info *info;
+ char *tx_power;
unsigned int i;

/*
@@ -1674,20 +1675,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));

/*
- * Convert tx_power array in eeprom.
- */
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
- /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- spec->tx_power_a = NULL;
- spec->tx_power_bg = txpower;
- spec->tx_power_default = DEFAULT_TXPOWER;

if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
@@ -1709,6 +1700,26 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->num_channels = ARRAY_SIZE(rf_vals_5222);
spec->channels = rf_vals_5222;
}
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ spec->channels_info = info;
+
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+ if (spec->num_channels > 14) {
+ for (i = 14; i < spec->num_channels; i++)
+ info[i].tx_power1 = DEFAULT_TXPOWER;
+ }
+
+ return 0;
}

static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1729,7 +1740,9 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw specifications.
*/
- rt2500usb_probe_hw_mode(rt2x00dev);
+ retval = rt2500usb_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;

/*
* This device requires the atim queue
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 4769ffe..89e5ed2 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -825,17 +825,10 @@
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24

-#define TXPOWER_FROM_DEV(__txpower) \
-({ \
- ((__txpower) > MAX_TXPOWER) ? \
- DEFAULT_TXPOWER : (__txpower); \
-})
-
-#define TXPOWER_TO_DEV(__txpower) \
-({ \
- ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
- (__txpower)); \
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+ (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)

#endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index ae5c090..61f853f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -144,6 +144,17 @@ struct rf_channel {
};

/*
+ * Channel information structure
+ */
+struct channel_info {
+ unsigned int flags;
+#define GEOGRAPHY_ALLOWED 0x00000001
+
+ short tx_power1;
+ short tx_power2;
+};
+
+/*
* Antenna setup values.
*/
struct antenna_setup {
@@ -394,10 +405,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
* @num_channels: Number of supported channels. This is used as array size
* for @tx_power_a, @tx_power_bg and @channels.
* @channels: Device/chipset specific channel values (See &struct rf_channel).
- * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL).
- * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL).
- * @tx_power_default: Default TX power value to use when either
- * @tx_power_a or @tx_power_bg is missing.
+ * @channels_info: Additional information for channels (See &struct channel_info).
*/
struct hw_mode_spec {
unsigned int supported_bands;
@@ -410,10 +418,7 @@ struct hw_mode_spec {

unsigned int num_channels;
const struct rf_channel *channels;
-
- const u8 *tx_power_a;
- const u8 *tx_power_bg;
- u8 tx_power_default;
+ const struct channel_info *channels_info;
};

/*
@@ -425,7 +430,9 @@ struct hw_mode_spec {
*/
struct rt2x00lib_conf {
struct ieee80211_conf *conf;
+
struct rf_channel rf;
+ struct channel_info channel;

struct antenna_setup ant;

diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index d134c3b..ea37c79 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -245,6 +245,10 @@ config:
memcpy(&libconf.rf,
&rt2x00dev->spec.channels[conf->channel->hw_value],
sizeof(libconf.rf));
+
+ memcpy(&libconf.channel,
+ &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+ sizeof(libconf.channel));
}

if (flags & CONFIG_UPDATE_ANTENNA) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 1829522..328ff8b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -818,7 +818,6 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
struct ieee80211_rate *rates;
unsigned int num_rates;
unsigned int i;
- unsigned char tx_power;

num_rates = 0;
if (spec->supported_rates & SUPPORT_RATE_CCK)
@@ -844,20 +843,9 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
* Initialize Channel list.
*/
for (i = 0; i < spec->num_channels; i++) {
- if (spec->channels[i].channel <= 14) {
- if (spec->tx_power_bg)
- tx_power = spec->tx_power_bg[i];
- else
- tx_power = spec->tx_power_default;
- } else {
- if (spec->tx_power_a)
- tx_power = spec->tx_power_a[i];
- else
- tx_power = spec->tx_power_default;
- }
-
rt2x00lib_channel(&channels[i],
- spec->channels[i].channel, tx_power, i);
+ spec->channels[i].channel,
+ spec->channels_info[i].tx_power1, i);
}

/*
@@ -909,6 +897,8 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
}
+
+ kfree(rt2x00dev->spec.channels_info);
}

static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 86e7a50..87012f8 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2514,10 +2514,11 @@ static const struct rf_channel rf_vals_seq[] = {
{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
};

-static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
- u8 *txpower;
+ struct channel_info *info;
+ char *tx_power;
unsigned int i;

/*
@@ -2534,20 +2535,10 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));

/*
- * Convert tx_power array in eeprom.
- */
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
- /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- spec->tx_power_a = NULL;
- spec->tx_power_bg = txpower;
- spec->tx_power_default = DEFAULT_TXPOWER;

if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
spec->num_channels = 14;
@@ -2561,13 +2552,28 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(&rt2x00dev->chip, RF5325)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_seq);
+ }
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ spec->channels_info = info;

- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);

- spec->tx_power_a = txpower;
+ if (spec->num_channels > 14) {
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 14; i < spec->num_channels; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
}
+
+ return 0;
}

static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -2588,7 +2594,9 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw specifications.
*/
- rt61pci_probe_hw_mode(rt2x00dev);
+ retval = rt61pci_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;

/*
* This device requires firmware and DMA mapped skbs.
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6d591ce..8ec1451 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1482,17 +1482,10 @@ struct hw_pairwise_ta_entry {
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24

-#define TXPOWER_FROM_DEV(__txpower) \
-({ \
- ((__txpower) > MAX_TXPOWER) ? \
- DEFAULT_TXPOWER : (__txpower); \
-})
-
-#define TXPOWER_TO_DEV(__txpower) \
-({ \
- ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
- (__txpower)); \
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+ (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)

#endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index ddba747..1bd6b3f 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2107,10 +2107,11 @@ static const struct rf_channel rf_vals_5225_2527[] = {
};


-static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
- u8 *txpower;
+ struct channel_info *info;
+ char *tx_power;
unsigned int i;

/*
@@ -2127,20 +2128,10 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
EEPROM_MAC_ADDR_0));

/*
- * Convert tx_power array in eeprom.
- */
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
-
- /*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- spec->tx_power_a = NULL;
- spec->tx_power_bg = txpower;
- spec->tx_power_default = DEFAULT_TXPOWER;

if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
@@ -2158,14 +2149,26 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->channels = rf_vals_5225_2527;
}

- if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
- rt2x00_rf(&rt2x00dev->chip, RF5226)) {
- txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
- for (i = 0; i < 14; i++)
- txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;

- spec->tx_power_a = txpower;
+ spec->channels_info = info;
+
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+
+ if (spec->num_channels > 14) {
+ tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 14; i < spec->num_channels; i++)
+ info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
}
+
+ return 0;
}

static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -2186,7 +2189,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize hw specifications.
*/
- rt73usb_probe_hw_mode(rt2x00dev);
+ retval = rt73usb_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;

/*
* This device requires firmware.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 91e04d3..868386c 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -1050,17 +1050,10 @@ struct hw_pairwise_ta_entry {
#define MAX_TXPOWER 31
#define DEFAULT_TXPOWER 24

-#define TXPOWER_FROM_DEV(__txpower) \
-({ \
- ((__txpower) > MAX_TXPOWER) ? \
- DEFAULT_TXPOWER : (__txpower); \
-})
-
-#define TXPOWER_TO_DEV(__txpower) \
-({ \
- ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
- (__txpower)); \
-})
+#define TXPOWER_FROM_DEV(__txpower) \
+ (((u8)(__txpower)) > MAX_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_TXPOWER, MAX_TXPOWER)

#endif /* RT73USB_H */
--
1.5.6.1


2008-08-04 17:33:22

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [PATCH 3/5] rt2x00: Implement HW encryption (rt73usb)

On Monday 04 August 2008, Stefanik G=E1bor wrote:
> On Mon, Aug 4, 2008 at 4:38 PM, Ivo van Doorn <[email protected]> wro=
te:
> > rt73usb supports hardware encryption.
> > rt73usb supports up to 4 shared keys and up to 64 pairwise keys.

<...>

> We need modparams for disabling HW crypto support if it misbehaves.

Hmm, I'm not that big fan of module parameters, but perhaps there shoul=
d
indeed be some toggle possibility. Well, I'll add that in a few days.

Ivo

2008-08-04 14:19:29

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 1/5] rt2x00: Implement HW encryption

Various rt2x00 devices support hardware encryption.

Most of them require the IV/EIV to be generated by mac80211,
but require it to be provided seperately instead of within
the frame itself. This means that rt2x00lib should extract
the data from the frame and place it in the frame descriptor.
During RX the IV/EIV is provided in the descriptor by the
hardware which means that it should be inserted into the
frame by rt2x00lib.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/Kconfig | 4 +
drivers/net/wireless/rt2x00/Makefile | 1 +
drivers/net/wireless/rt2x00/rt2x00.h | 39 +++++-
drivers/net/wireless/rt2x00/rt2x00crypto.c | 215 ++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00debug.c | 97 +++++++++++++
drivers/net/wireless/rt2x00/rt2x00dev.c | 30 ++++-
drivers/net/wireless/rt2x00/rt2x00lib.h | 47 ++++++
drivers/net/wireless/rt2x00/rt2x00mac.c | 110 +++++++++++++-
drivers/net/wireless/rt2x00/rt2x00queue.c | 81 ++++++++++-
drivers/net/wireless/rt2x00/rt2x00queue.h | 73 +++++++++-
drivers/net/wireless/rt2x00/rt2x00reg.h | 19 +++-
11 files changed, 686 insertions(+), 30 deletions(-)
create mode 100644 drivers/net/wireless/rt2x00/rt2x00crypto.c

diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index d485a86..2f60e17 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -33,6 +33,10 @@ config RT2X00_LIB_FIRMWARE
depends on RT2X00_LIB
select FW_LOADER

+config RT2X00_LIB_CRYPTO
+ boolean
+ depends on RT2X00_LIB
+
config RT2X00_LIB_RFKILL
boolean
depends on RT2X00_LIB
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 1087dbc..917cb4f 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -3,6 +3,7 @@ rt2x00lib-y += rt2x00mac.o
rt2x00lib-y += rt2x00config.o
rt2x00lib-y += rt2x00queue.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
+rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 8b10ea4..ae5c090 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -452,6 +452,23 @@ struct rt2x00lib_erp {
};

/*
+ * Configuration structure for hardware encryption.
+ */
+struct rt2x00lib_crypto {
+ enum cipher cipher;
+
+ enum set_key_cmd cmd;
+ const u8 *address;
+
+ u32 bssidx;
+ u32 aid;
+
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+};
+
+/*
* Configuration structure wrapper around the
* rt2x00 interface configuration handler.
*/
@@ -547,6 +564,12 @@ struct rt2x00lib_ops {
/*
* Configuration handlers.
*/
+ int (*config_shared_key) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key);
+ int (*config_pairwise_key) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key);
void (*config_filter) (struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags);
void (*config_intf) (struct rt2x00_dev *rt2x00dev,
@@ -609,7 +632,7 @@ enum rt2x00_flags {
DEVICE_DIRTY_CONFIG,

/*
- * Driver features
+ * Driver requirements
*/
DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_BEACON_GUARD,
@@ -618,9 +641,14 @@ enum rt2x00_flags {
DRIVER_REQUIRE_DMA,

/*
- * Driver configuration
+ * Driver features
*/
CONFIG_SUPPORT_HW_BUTTON,
+ CONFIG_SUPPORT_HW_CRYPTO,
+
+ /*
+ * Driver configuration
+ */
CONFIG_FRAME_TYPE,
CONFIG_RF_SEQUENCE,
CONFIG_EXTERNAL_LNA_A,
@@ -966,6 +994,13 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list);
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_address, const u8 *address,
+ struct ieee80211_key_conf *key);
+#else
+#define rt2x00mac_set_key NULL
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
new file mode 100644
index 0000000..e1448cf
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -0,0 +1,215 @@
+/*
+ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 crypto specific routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
+{
+ switch (key->alg) {
+ case ALG_WEP:
+ if (key->keylen == LEN_WEP40)
+ return CIPHER_WEP64;
+ else
+ return CIPHER_WEP128;
+ case ALG_TKIP:
+ return CIPHER_TKIP;
+ case ALG_CCMP:
+ return CIPHER_AES;
+ default:
+ return CIPHER_NONE;
+ }
+}
+
+unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
+{
+ struct ieee80211_key_conf *key = tx_info->control.hw_key;
+ unsigned int overhead = 0;
+
+ /*
+ * Extend frame length to include IV/EIV/ICV/MMIC,
+ * note that these lengths should only be added when
+ * mac80211 does not generate it.
+ */
+ overhead += tx_info->control.icv_len;
+
+ if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+ overhead += tx_info->control.iv_len;
+
+ if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
+ if (key->alg == ALG_TKIP)
+ overhead += 8;
+ }
+
+ return overhead;
+}
+
+void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (unlikely(!iv_len))
+ return;
+
+ /* Copy IV/EIV data */
+ if (iv_len >= 4)
+ memcpy(&skbdesc->iv, skb->data + header_length, 4);
+ if (iv_len >= 8)
+ memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4);
+
+ /* Move ieee80211 header */
+ memmove(skb->data + iv_len, skb->data, header_length);
+
+ /* Pull buffer to correct size */
+ skb_pull(skb, iv_len);
+
+ /* IV/EIV data has officially be stripped */
+ skbdesc->flags |= FRAME_DESC_IV_STRIPPED;
+}
+
+void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb);
+ const unsigned int iv_len =
+ ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4);
+
+ if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED))
+ return;
+
+ skb_push(skb, iv_len);
+
+ /* Move ieee80211 header */
+ memmove(skb->data, skb->data + iv_len, header_length);
+
+ /* Copy IV/EIV data */
+ if (iv_len >= 4)
+ memcpy(skb->data + header_length, &skbdesc->iv, 4);
+ if (iv_len >= 8)
+ memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4);
+
+ /* IV/EIV data has returned into the frame */
+ skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED;
+}
+
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
+ unsigned int header_length,
+ struct rxdone_entry_desc *rxdesc)
+{
+ unsigned int payload_len = rxdesc->size - header_length;
+ unsigned int iv_len;
+ unsigned int icv_len;
+ unsigned int transfer = 0;
+
+ /*
+ * WEP64/WEP128: Provides IV & ICV
+ * TKIP: Provides IV/EIV & ICV
+ * AES: Provies IV/EIV & ICV
+ */
+ switch (rxdesc->cipher) {
+ case CIPHER_WEP64:
+ case CIPHER_WEP128:
+ iv_len = 4;
+ icv_len = 4;
+ break;
+ case CIPHER_TKIP:
+ iv_len = 8;
+ icv_len = 4;
+ break;
+ case CIPHER_AES:
+ iv_len = 8;
+ icv_len = 8;
+ break;
+ default:
+ /* Unsupport type */
+ return;
+ }
+
+ /*
+ * Make room for new data, note that we increase both
+ * headsize and tailsize when required. The tailsize is
+ * only needed when ICV data needs to be inserted and
+ * the padding is smaller then the ICV data.
+ * When alignment requirements is greater then the
+ * ICV data we must trim the skb to the correct size
+ * because we need to remove the extra bytes.
+ */
+ skb_push(skb, iv_len + align);
+ if (align < icv_len)
+ skb_put(skb, icv_len - align);
+ else if (align > icv_len)
+ skb_trim(skb, rxdesc->size + iv_len + icv_len);
+
+ /* Move ieee80211 header */
+ memmove(skb->data + transfer,
+ skb->data + transfer + iv_len + align,
+ header_length);
+ transfer += header_length;
+
+ /* Copy IV data */
+ if (iv_len >= 4) {
+ memcpy(skb->data + transfer, &rxdesc->iv, 4);
+ transfer += 4;
+ }
+
+ /* Copy EIV data */
+ if (iv_len >= 8) {
+ memcpy(skb->data + transfer, &rxdesc->eiv, 4);
+ transfer += 4;
+ }
+
+ /* Move payload */
+ if (align) {
+ memmove(skb->data + transfer,
+ skb->data + transfer + align,
+ payload_len);
+ }
+
+ /*
+ * NOTE: Always count the payload as transfered,
+ * even when alignment was set to zero. This is required
+ * for determining the correct offset for the ICV data.
+ */
+ transfer += payload_len;
+
+ /* Copy ICV data */
+ if (icv_len >= 4) {
+ memcpy(skb->data + transfer, &rxdesc->icv, 4);
+ /*
+ * AES appends 8 bytes, we can't fill the upper
+ * 4 bytes, but mac80211 doesn't care about what
+ * we provide here anyway and strips it immediately.
+ */
+ transfer += icv_len;
+ }
+
+ /* IV/EIV/ICV has been inserted into frame */
+ rxdesc->size = transfer;
+ rxdesc->flags &= ~RX_FLAG_IV_STRIPPED;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 6bee1d6..5cf4c85 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -35,6 +35,13 @@

#define MAX_LINE_LENGTH 64

+struct rt2x00debug_crypto {
+ unsigned long success;
+ unsigned long icv_error;
+ unsigned long mic_error;
+ unsigned long key_error;
+};
+
struct rt2x00debug_intf {
/*
* Pointer to driver structure where
@@ -63,6 +70,7 @@ struct rt2x00debug_intf {
* - queue folder
* - frame dump file
* - queue stats file
+ * - crypto stats file
*/
struct dentry *driver_folder;
struct dentry *driver_entry;
@@ -80,6 +88,7 @@ struct rt2x00debug_intf {
struct dentry *queue_folder;
struct dentry *queue_frame_dump_entry;
struct dentry *queue_stats_entry;
+ struct dentry *crypto_stats_entry;

/*
* The frame dump file only allows a single reader,
@@ -98,6 +107,12 @@ struct rt2x00debug_intf {
wait_queue_head_t frame_dump_waitqueue;

/*
+ * HW crypto statistics.
+ * All statistics are stored seperately per cipher type.
+ */
+ struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];
+
+ /*
* Driver and chipset files will use a data buffer
* that has been created in advance. This will simplify
* the code since we can use the debugfs functions.
@@ -114,6 +129,25 @@ struct rt2x00debug_intf {
unsigned int offset_rf;
};

+void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+ enum cipher cipher, enum rx_crypto status)
+{
+ struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+
+ if (cipher == CIPHER_TKIP_NO_MIC)
+ cipher = CIPHER_TKIP;
+ if (cipher == CIPHER_NONE || cipher > CIPHER_MAX)
+ return;
+
+ /* Remove CIPHER_NONE index */
+ cipher--;
+
+ intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS);
+ intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV);
+ intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC);
+ intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY);
+}
+
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb)
{
@@ -327,6 +361,59 @@ static const struct file_operations rt2x00debug_fop_queue_stats = {
.release = rt2x00debug_file_release,
};

+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+static ssize_t rt2x00debug_read_crypto_stats(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ char *name[] = { "WEP64", "WEP128", "TKIP", "AES" };
+ char *data;
+ char *temp;
+ size_t size;
+ unsigned int i;
+
+ if (*offset)
+ return 0;
+
+ data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ temp = data;
+ temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n");
+
+ for (i = 0; i < CIPHER_MAX; i++) {
+ temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i],
+ intf->crypto_stats[i].success,
+ intf->crypto_stats[i].icv_error,
+ intf->crypto_stats[i].mic_error,
+ intf->crypto_stats[i].key_error);
+ }
+
+ size = strlen(data);
+ size = min(size, length);
+
+ if (copy_to_user(buf, data, size)) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ kfree(data);
+
+ *offset += size;
+ return size;
+}
+
+static const struct file_operations rt2x00debug_fop_crypto_stats = {
+ .owner = THIS_MODULE,
+ .read = rt2x00debug_read_crypto_stats,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
+};
+#endif
+
#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
static ssize_t rt2x00debug_read_##__name(struct file *file, \
char __user *buf, \
@@ -569,6 +656,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_stats);

+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ intf->crypto_stats_entry =
+ debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
+ intf, &rt2x00debug_fop_crypto_stats);
+#endif
+
return;

exit:
@@ -587,6 +681,9 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)

skb_queue_purge(&intf->frame_dump_skbqueue);

+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+ debugfs_remove(intf->crypto_stats_entry);
+#endif
debugfs_remove(intf->queue_stats_entry);
debugfs_remove(intf->queue_frame_dump_entry);
debugfs_remove(intf->queue_folder);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index f42283a..1829522 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -508,6 +508,15 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00queue_unmap_skb(rt2x00dev, entry->skb);

/*
+ * If the IV/EIV data was stripped from the frame before it was
+ * passed to the hardware, we should now reinsert it again because
+ * mac80211 will expect the the same data to be present it the
+ * frame as it was passed to us.
+ */
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ rt2x00crypto_tx_insert_iv(entry->skb);
+
+ /*
* Send frame to debugfs immediately, after this call is completed
* we are going to overwrite the skb->cb array.
*/
@@ -585,7 +594,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
struct ieee80211_supported_band *sband;
struct ieee80211_hdr *hdr;
const struct rt2x00_rate *rate;
- unsigned int header_size;
+ unsigned int header_length;
unsigned int align;
unsigned int i;
int idx = -1;
@@ -613,10 +622,19 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* The data behind the ieee80211 header must be
* aligned on a 4 byte boundary.
*/
- header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
- align = ((unsigned long)(entry->skb->data + header_size)) & 3;
+ header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+ align = ((unsigned long)(entry->skb->data + header_length)) & 3;

- if (align) {
+ /*
+ * Hardware might have stripped the IV/EIV/ICV data,
+ * in that case it is possible that the data was
+ * provided seperately (through hardware descriptor)
+ * in which case we should reinsert the data into the frame.
+ */
+ if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) {
+ rt2x00crypto_rx_insert_iv(entry->skb, align,
+ header_length, &rxdesc);
+ } else if (align) {
skb_push(entry->skb, align);
/* Move entire frame in 1 command */
memmove(entry->skb->data, entry->skb->data + align,
@@ -657,6 +675,10 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
(rxdesc.dev_flags & RXDONE_MY_BSS))
rt2x00lib_update_link_stats(&rt2x00dev->link, rxdesc.rssi);

+ rt2x00debug_update_crypto(rt2x00dev,
+ rxdesc.cipher,
+ rxdesc.cipher_status);
+
rt2x00dev->link.qual.rx_success++;

rx_status->mactime = rxdesc.timestamp;
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index c5fb3a7..7bbc16b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -181,6 +181,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb);
+void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+ enum cipher cipher, enum rx_crypto status);
#else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
@@ -195,9 +197,54 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
}
+
+static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
+ enum cipher cipher,
+ enum rx_crypto status)
+{
+}
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */

/*
+ * Crypto handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key);
+unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info);
+void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len);
+void rt2x00crypto_tx_insert_iv(struct sk_buff *skb);
+void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
+ unsigned int header_length,
+ struct rxdone_entry_desc *rxdesc);
+#else
+static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
+{
+ return CIPHER_NONE;
+}
+
+static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info)
+{
+ return 0;
+}
+
+static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb,
+ unsigned int iv_len)
+{
+}
+
+static inline void rt2x00crypto_tx_insert_iv(struct sk_buff *skb)
+{
+}
+
+static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
+ unsigned int align,
+ unsigned int header_length,
+ struct rxdone_entry_desc *rxdesc)
+{
+}
+#endif
+
+/*
* RFkill handlers.
*/
#ifdef CONFIG_RT2X00_LIB_RFKILL
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 03732a4..bb9d489 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -36,22 +36,22 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
struct ieee80211_tx_info *rts_info;
struct sk_buff *skb;
- int size;
+ unsigned int data_length;
int retval = 0;

if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
- size = sizeof(struct ieee80211_cts);
+ data_length = sizeof(struct ieee80211_cts);
else
- size = sizeof(struct ieee80211_rts);
+ data_length = sizeof(struct ieee80211_rts);

- skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
+ skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
if (unlikely(!skb)) {
WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
return -ENOMEM;
}

skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
- skb_put(skb, size);
+ skb_put(skb, data_length);

/*
* Copy TX information over from original frame to
@@ -64,7 +64,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
- rts_info->control.hw_key = NULL;
rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -74,13 +73,24 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;

+ skb->do_not_encrypt = 1;
+
+ /*
+ * RTS/CTS frame should use the length of the frame plus any
+ * encryption overhead that will be added by the hardware.
+ */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+ if (!frag_skb->do_not_encrypt)
+ data_length += rt2x00crypto_tx_overhead(tx_info);
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
- frag_skb->data, size, tx_info,
+ frag_skb->data, data_length, tx_info,
(struct ieee80211_cts *)(skb->data));
else
ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
- frag_skb->data, size, tx_info,
+ frag_skb->data, data_length, tx_info,
(struct ieee80211_rts *)(skb->data));

retval = rt2x00queue_write_tx_frame(queue, skb);
@@ -444,6 +454,90 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);

+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_address, const u8 *address,
+ struct ieee80211_key_conf *key)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int (*set_key) (struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key);
+ struct rt2x00lib_crypto crypto;
+
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ return -EOPNOTSUPP;
+ else if (key->keylen > 32)
+ return -ENOSPC;
+
+ memset(&crypto, 0, sizeof(crypto));
+
+ /*
+ * When in STA mode, bssidx is always 0 otherwise local_address[5]
+ * contains the bss number, see BSS_ID_MASK comments for details.
+ */
+ if (rt2x00dev->intf_sta_count)
+ crypto.bssidx = 0;
+ else
+ crypto.bssidx =
+ local_address[5] & (rt2x00dev->ops->max_ap_intf - 1);
+
+ crypto.cipher = rt2x00crypto_key_to_cipher(key);
+ if (crypto.cipher == CIPHER_NONE)
+ return -EOPNOTSUPP;
+
+ crypto.cmd = cmd;
+ crypto.address = address;
+
+ if (crypto.cipher == CIPHER_TKIP) {
+ if (key->keylen > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
+ memcpy(&crypto.key,
+ &key->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
+ sizeof(crypto.key));
+
+ if (key->keylen > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+ memcpy(&crypto.tx_mic,
+ &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+ sizeof(crypto.tx_mic));
+
+ if (key->keylen > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
+ memcpy(&crypto.rx_mic,
+ &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+ sizeof(crypto.rx_mic));
+ } else
+ memcpy(&crypto.key, &key->key[0], key->keylen);
+
+ /*
+ * Each BSS has a maximum of 4 shared keys.
+ * Shared key index values:
+ * 0) BSS0 key0
+ * 1) BSS0 key1
+ * ...
+ * 4) BSS1 key0
+ * ...
+ * 8) BSS2 key0
+ * ...
+ * Both pairwise as shared key indeces are determined by
+ * driver. This is required because the hardware requires
+ * keys to be assigned in correct order (When key 1 is
+ * provided but key 0 is not, then the key is not found
+ * by the hardware during RX).
+ */
+ key->hw_key_idx = 0;
+
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ set_key = rt2x00dev->ops->lib->config_pairwise_key;
+ else
+ set_key = rt2x00dev->ops->lib->config_shared_key;
+
+ if (!set_key)
+ return -EOPNOTSUPP;
+
+ return set_key(rt2x00dev, &crypto, key);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
int rt2x00mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 898cdd7..c0f97c5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -33,10 +33,11 @@
struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- unsigned int frame_size;
- unsigned int reserved_size;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
+ unsigned int frame_size;
+ unsigned int head_size = 0;
+ unsigned int tail_size = 0;

/*
* The frame size includes descriptor size, because the
@@ -49,16 +50,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
* this means we need at least 3 bytes for moving the frame
* into the correct offset.
*/
- reserved_size = 4;
+ head_size = 4;
+
+ /*
+ * For IV/EIV/ICV assembly we must make sure there is
+ * at least 8 bytes bytes available in headroom for IV/EIV
+ * and 4 bytes for ICV data as tailroon.
+ */
+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ head_size += 8;
+ tail_size += 4;
+ }
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */

/*
* Allocate skbuffer.
*/
- skb = dev_alloc_skb(frame_size + reserved_size);
+ skb = dev_alloc_skb(frame_size + head_size + tail_size);
if (!skb)
return NULL;

- skb_reserve(skb, reserved_size);
+ /*
+ * Make sure we not have a frame with the requested bytes
+ * available in the head and tail.
+ */
+ skb_reserve(skb, head_size);
skb_put(skb, frame_size);

/*
@@ -140,7 +157,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
txdesc->cw_max = entry->queue->cw_max;
txdesc->aifs = entry->queue->aifs;

- /* Data length should be extended with 4 bytes for CRC */
+ /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */
data_length = entry->skb->len + 4;

/*
@@ -149,6 +166,35 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
__set_bit(ENTRY_TXD_ACK, &txdesc->flags);

+#ifdef CONFIG_RT2X00_LIB_CRYPTO
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) &&
+ !entry->skb->do_not_encrypt) {
+ struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
+
+ __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
+
+ txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key);
+
+ if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags);
+
+ txdesc->key_idx = hw_key->hw_key_idx;
+ txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb);
+
+ /*
+ * Extend frame length to include all encryption overhead
+ * that will be added by the hardware.
+ */
+ data_length += rt2x00crypto_tx_overhead(tx_info);
+
+ if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV))
+ __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags);
+
+ if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+ __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags);
+ }
+#endif /* CONFIG_RT2X00_LIB_CRYPTO */
+
/*
* Check if this is a RTS/CTS frame
*/
@@ -305,6 +351,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct txentry_desc txdesc;
struct skb_frame_desc *skbdesc;
+ unsigned int iv_len = IEEE80211_SKB_CB(skb)->control.iv_len;

if (unlikely(rt2x00queue_full(queue)))
return -EINVAL;
@@ -326,15 +373,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
rt2x00queue_create_tx_descriptor(entry, &txdesc);

/*
- * skb->cb array is now ours and we are free to use it.
+ * All information is retreived from the skb->cb array,
+ * now we should claim ownership of the driver part of that
+ * array.
*/
skbdesc = get_skb_frame_desc(entry->skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;

+ /*
+ * When hardware encryption is supported, and this frame
+ * is to be encrypted, we should strip the IV/EIV data from
+ * the frame so we can provide it to the driver seperately.
+ */
+ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
+ !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags))
+ rt2x00crypto_tx_remove_iv(skb, iv_len);
+
+ /*
+ * It could be possible that the queue was corrupted and this
+ * call failed. Just drop the frame, we cannot rollback and pass
+ * the frame to mac80211 because the skb->cb has now been tainted.
+ */
if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
__clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- return -EIO;
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+ return 0;
}

if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index a4a8c57..01a6567 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -87,10 +87,13 @@ enum data_queue_qid {
*
* @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX
* @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
+ * @FRAME_DESC_IV_STRIPPED: Frame contained a IV/EIV provided by
+ * mac80211 but was stripped for processing by the driver.
*/
enum skb_frame_desc_flags {
- SKBDESC_DMA_MAPPED_RX = (1 << 0),
- SKBDESC_DMA_MAPPED_TX = (1 << 1),
+ SKBDESC_DMA_MAPPED_RX = 1 << 0,
+ SKBDESC_DMA_MAPPED_TX = 1 << 1,
+ FRAME_DESC_IV_STRIPPED = 1 << 2,
};

/**
@@ -104,6 +107,8 @@ enum skb_frame_desc_flags {
* @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside
* of the scope of the skb->data pointer.
+ * @iv: IV data used during encryption/decryption.
+ * @eiv: EIV data used during encryption/decryption.
* @skb_dma: (PCI-only) the DMA address associated with the sk buffer.
* @entry: The entry to which this sk buffer belongs.
*/
@@ -113,6 +118,9 @@ struct skb_frame_desc {
unsigned int desc_len;
void *desc;

+ __le32 iv;
+ __le32 eiv;
+
dma_addr_t skb_dma;

struct queue_entry *entry;
@@ -152,7 +160,11 @@ enum rxdone_entry_desc_flags {
* @size: Data size of the received frame.
* @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
* @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
-
+ * @cipher: Cipher type used during decryption.
+ * @cipher_status: Decryption status.
+ * @iv: IV data used during decryption.
+ * @eiv: EIV data used during decryption.
+ * @icv: ICV data used during decryption.
*/
struct rxdone_entry_desc {
u64 timestamp;
@@ -161,6 +173,12 @@ struct rxdone_entry_desc {
int size;
int flags;
int dev_flags;
+ u8 cipher;
+ u8 cipher_status;
+
+ __le32 iv;
+ __le32 eiv;
+ __le32 icv;
};

/**
@@ -206,6 +224,10 @@ struct txdone_entry_desc {
* @ENTRY_TXD_BURST: This frame belongs to the same burst event.
* @ENTRY_TXD_ACK: An ACK is required for this frame.
* @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
+ * @ENTRY_TXD_ENCRYPT: This frame should be encrypted.
+ * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared).
+ * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware.
+ * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
@@ -218,6 +240,10 @@ enum txentry_desc_flags {
ENTRY_TXD_BURST,
ENTRY_TXD_ACK,
ENTRY_TXD_RETRY_MODE,
+ ENTRY_TXD_ENCRYPT,
+ ENTRY_TXD_ENCRYPT_PAIRWISE,
+ ENTRY_TXD_ENCRYPT_IV,
+ ENTRY_TXD_ENCRYPT_MMIC,
};

/**
@@ -236,6 +262,9 @@ enum txentry_desc_flags {
* @ifs: IFS value.
* @cw_min: cwmin value.
* @cw_max: cwmax value.
+ * @cipher: Cipher type used for encryption.
+ * @key_idx: Key index used for encryption.
+ * @iv_offset: Position where IV should be inserted by hardware.
*/
struct txentry_desc {
unsigned long flags;
@@ -252,6 +281,10 @@ struct txentry_desc {
short ifs;
short cw_min;
short cw_max;
+
+ enum cipher cipher;
+ u16 key_idx;
+ u16 iv_offset;
};

/**
@@ -484,25 +517,51 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
}

/**
- * rt2x00_desc_read - Read a word from the hardware descriptor.
+ * _rt2x00_desc_read - Read a word from the hardware descriptor.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be read.
+ * @value: Address where the descriptor value should be written into.
+ */
+static inline void _rt2x00_desc_read(__le32 *desc, const u8 word, __le32 *value)
+{
+ *value = desc[word];
+}
+
+/**
+ * rt2x00_desc_read - Read a word from the hardware descriptor, this
+ * function will take care of the byte ordering.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be read.
* @value: Address where the descriptor value should be written into.
*/
static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value)
{
- *value = le32_to_cpu(desc[word]);
+ __le32 tmp;
+ _rt2x00_desc_read(desc, word, &tmp);
+ *value = le32_to_cpu(tmp);
+}
+
+/**
+ * rt2x00_desc_write - write a word to the hardware descriptor, this
+ * function will take care of the byte ordering.
+ * @desc: Base descriptor address
+ * @word: Word index from where the descriptor should be written.
+ * @value: Value that should be written into the descriptor.
+ */
+static inline void _rt2x00_desc_write(__le32 *desc, const u8 word, __le32 value)
+{
+ desc[word] = value;
}

/**
- * rt2x00_desc_write - wrote a word to the hardware descriptor.
+ * rt2x00_desc_write - write a word to the hardware descriptor.
* @desc: Base descriptor address
* @word: Word index from where the descriptor should be written.
* @value: Value that should be written into the descriptor.
*/
static inline void rt2x00_desc_write(__le32 *desc, const u8 word, u32 value)
{
- desc[word] = cpu_to_le32(value);
+ _rt2x00_desc_write(desc, word, cpu_to_le32(value));
}

#endif /* RT2X00QUEUE_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 7e88ce5..6d5acf9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -27,6 +27,16 @@
#define RT2X00REG_H

/*
+ * RX crypto status
+ */
+enum rx_crypto {
+ RX_CRYPTO_SUCCESS = 0,
+ RX_CRYPTO_FAIL_ICV = 1,
+ RX_CRYPTO_FAIL_MIC = 2,
+ RX_CRYPTO_FAIL_KEY = 3,
+};
+
+/*
* Antenna values
*/
enum antenna {
@@ -104,7 +114,14 @@ enum cipher {
*/
CIPHER_CKIP64 = 5,
CIPHER_CKIP128 = 6,
- CIPHER_TKIP_NO_MIC = 7,
+ CIPHER_TKIP_NO_MIC = 7, /* Don't send to device */
+
+/*
+ * Max cipher type.
+ * Note that CIPHER_NONE isn't counted, and CKIP64 and CKIP128
+ * are excluded due to limitations in mac80211.
+ */
+ CIPHER_MAX = 4,
};

/*
--
1.5.6.1


2008-08-04 14:18:30

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 3/5] rt2x00: Implement HW encryption (rt73usb)

rt73usb supports hardware encryption.
rt73usb supports up to 4 shared keys and up to 64 pairwise keys.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/Kconfig | 1 +
drivers/net/wireless/rt2x00/rt73usb.c | 271 ++++++++++++++++++++++++++++++++-
drivers/net/wireless/rt2x00/rt73usb.h | 21 +++-
3 files changed, 285 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index f333f61..11f590d 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -156,6 +156,7 @@ config RT73USB
depends on USB
select RT2X00_LIB_USB
select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_CRYPTO
select CRC_ITU_T
---help---
This adds support for rt2501 wireless chipset family.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 9761eaa..ddba747 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -357,6 +357,219 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev,
/*
* Configuration handlers.
*/
+static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ struct rt2x00_field32 field;
+ int timeout;
+ u32 mask;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * rt2x00lib can't determine the correct free
+ * key_idx for shared keys. We have 1 register
+ * with key valid bits. The goal is simple, read
+ * the register, if that is full we have no slots
+ * left.
+ * Note that each BSS is allowed to have up to 4
+ * shared keys, so put a mask over the allowed
+ * entries.
+ */
+ mask = (0xf << crypto->bssidx);
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ reg &= mask;
+
+ if (reg && reg == mask)
+ return -ENOSPC;
+
+ key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
+
+ /*
+ * Upload key to hardware
+ */
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ reg = SHARED_KEY_ENTRY(key->hw_key_idx);
+ timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
+ rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, reg,
+ &key_entry,
+ sizeof(key_entry),
+ timeout);
+
+ /*
+ * The cipher types are stored over 2 registers.
+ * bssidx 0 and 1 keys are stored in SEC_CSR1 and
+ * bssidx 1 and 2 keys are stored in SEC_CSR5.
+ * Using the correct defines correctly will cause overhead,
+ * so just calculate the correct offset.
+ */
+ if (key->hw_key_idx < 8) {
+ field.bit_offset = (3 * key->hw_key_idx);
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
+ rt2x00_set_field32(&reg, field, crypto->cipher);
+ rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
+ } else {
+ field.bit_offset = (3 * (key->hw_key_idx - 8));
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
+ rt2x00_set_field32(&reg, field, crypto->cipher);
+ rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
+ }
+
+ /*
+ * The driver does not support the IV/EIV generation
+ * in hardware. However it doesn't support the IV/EIV
+ * inside the ieee80211 frame either, but requires it
+ * to be provided seperately for the descriptor.
+ * rt2x00lib will cut the IV/EIV data out of all frames
+ * given to us by mac80211, but we must tell mac80211
+ * to generate the IV/EIV data.
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+
+ /*
+ * SEC_CSR0 contains only single-bit fields to indicate
+ * a particular key is valid. Because using the FIELD32()
+ * defines directly will cause a lot of overhead we use
+ * a calculation to determine the correct bit directly.
+ */
+ mask = 1 << key->hw_key_idx;
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
+
+ return 0;
+}
+
+static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_pairwise_ta_entry addr_entry;
+ struct hw_key_entry key_entry;
+ int timeout;
+ u32 mask;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * rt2x00lib can't determine the correct free
+ * key_idx for pairwise keys. We have 2 registers
+ * with key valid bits. The goal is simple, read
+ * the first register, if that is full move to
+ * the next register.
+ * When both registers are full, we drop the key,
+ * otherwise we use the first invalid entry.
+ */
+ rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ if (reg && reg == ~0) {
+ key->hw_key_idx = 32;
+ rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ if (reg && reg == ~0)
+ return -ENOSPC;
+ }
+
+ key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
+
+ /*
+ * Upload key to hardware
+ */
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+ timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
+ rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, reg,
+ &key_entry,
+ sizeof(key_entry),
+ timeout);
+
+ /*
+ * Send the address and cipher type to the hardware register.
+ * This data fits within the CSR cache size, so we can use
+ * rt73usb_register_multiwrite() directly.
+ */
+ memset(&addr_entry, 0, sizeof(addr_entry));
+ memcpy(&addr_entry, crypto->address, ETH_ALEN);
+ addr_entry.cipher = crypto->cipher;
+
+ reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
+ rt73usb_register_multiwrite(rt2x00dev, reg,
+ &addr_entry, sizeof(addr_entry));
+
+ /*
+ * Enable pairwise lookup table for given BSS idx,
+ * without this received frames will not be decrypted
+ * by the hardware.
+ */
+ rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
+ reg |= (1 << crypto->bssidx);
+ rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
+
+ /*
+ * The driver does not support the IV/EIV generation
+ * in hardware. However it doesn't support the IV/EIV
+ * inside the ieee80211 frame either, but requires it
+ * to be provided seperately for the descriptor.
+ * rt2x00lib will cut the IV/EIV data out of all frames
+ * given to us by mac80211, but we must tell mac80211
+ * to generate the IV/EIV data.
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+
+ /*
+ * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
+ * a particular key is valid. Because using the FIELD32()
+ * defines directly will cause a lot of overhead we use
+ * a calculation to determine the correct bit directly.
+ */
+ if (key->hw_key_idx < 32) {
+ mask = 1 << key->hw_key_idx;
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
+ } else {
+ mask = 1 << (key->hw_key_idx - 32);
+
+ rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
+ }
+
+ return 0;
+}
+
static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
@@ -1265,8 +1478,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
* TX descriptor initialization
*/
static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
- struct txentry_desc *txdesc)
+ struct sk_buff *skb,
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
@@ -1280,7 +1493,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
- rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_desc_write(txd, 1, word);
@@ -1292,6 +1505,11 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);

+ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+ _rt2x00_desc_write(txd, 3, skbdesc->iv);
+ _rt2x00_desc_write(txd, 4, skbdesc->eiv);
+ }
+
rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
TXPOWER_TO_DEV(rt2x00dev->tx_power));
@@ -1313,12 +1531,16 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+ test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+ test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
skb->len - skbdesc->desc_len);
rt2x00_set_field32(&word, TXD_W0_BURST2,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
rt2x00_desc_write(txd, 0, word);
}

@@ -1468,6 +1690,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
static void rt73usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = (__le32 *)entry->skb->data;
u32 word0;
@@ -1489,6 +1712,38 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;

+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ rxdesc->cipher =
+ rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+ rxdesc->cipher_status =
+ rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
+ }
+
+ if (rxdesc->cipher != CIPHER_NONE) {
+ _rt2x00_desc_read(rxd, 2, &rxdesc->iv);
+ _rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
+ _rt2x00_desc_read(rxd, 4, &rxdesc->icv);
+
+ /*
+ * Hardware has stripped IV/EIV data from 802.11 frame during
+ * decryption. It has provided the data seperately but rt2x00lib
+ * should decide if it should be reinserted.
+ */
+ rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+ /*
+ * FIXME: Legacy driver indicates that the frame does
+ * contain the Michael Mic. Unfortunately, in rt2x00
+ * the MIC seems to be missing completely...
+ */
+ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
+ if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+ rxdesc->flags |= RX_FLAG_DECRYPTED;
+ else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+ rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+ }
+
/*
* Obtain the status about this packet.
* When frame was received with an OFDM bitrate,
@@ -1496,7 +1751,7 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
* a CCK bitrate the signal is the rate in 100kbit/s.
*/
rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
+ rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);

if (rt2x00_get_field32(word0, RXD_W0_OFDM))
@@ -1938,6 +2193,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
+ __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);

/*
* Set the rssi offset.
@@ -1997,6 +2253,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
.configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt73usb_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
@@ -2024,6 +2281,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt73usb_kick_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
+ .config_shared_key = rt73usb_config_shared_key,
+ .config_pairwise_key = rt73usb_config_pairwise_key,
.config_filter = rt73usb_config_filter,
.config_intf = rt73usb_config_intf,
.config_erp = rt73usb_config_erp,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 1484935..91e04d3 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -92,6 +92,16 @@
#define PAIRWISE_KEY_TABLE_BASE 0x1200
#define PAIRWISE_TA_TABLE_BASE 0x1a00

+#define SHARED_KEY_ENTRY(__idx) \
+ ( SHARED_KEY_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+ ( PAIRWISE_KEY_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_TA_ENTRY(__idx) \
+ ( PAIRWISE_TA_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+
struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
@@ -100,7 +110,8 @@ struct hw_key_entry {

struct hw_pairwise_ta_entry {
u8 address[6];
- u8 reserved[2];
+ u8 cipher;
+ u8 reserved;
} __attribute__ ((packed));

/*
@@ -563,6 +574,10 @@ struct hw_pairwise_ta_entry {
* SEC_CSR4: Pairwise key table lookup control.
*/
#define SEC_CSR4 0x30b0
+#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001)
+#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002)
+#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004)
+#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008)

/*
* SEC_CSR5: shared key table security mode register.
@@ -1010,8 +1025,10 @@ struct hw_pairwise_ta_entry {

/*
* Word4
+ * ICV: Received ICV of originally encrypted.
+ * NOTE: This is a guess, the official definition is "reserved"
*/
-#define RXD_W4_RESERVED FIELD32(0xffffffff)
+#define RXD_W4_ICV FIELD32(0xffffffff)

/*
* the above 20-byte is called RXINFO and will be DMAed to MAC RX block
--
1.5.6.1


2008-08-05 18:05:58

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [Rt2400-devel] Please pull 'upstream' branch of rt2x00

On Tuesday 05 August 2008, Larry Finger wrote:
> Will Dyson wrote:
> > On Mon, Aug 4, 2008 at 10:36 AM, Ivo van Doorn <[email protected]> wrote:
> >> Hi John,
> >>
> >> Only 5 patches, but they do bump rt2x00 to a new version: 2.2.0
> >> This series will add HW crypto support to rt2x00, by default it
> >> has been enabled for rt61pci and rt73usb.
> >
> > Seems to work well on my rt61pci card!
> >
> > In fact, it reports a higher link quality (and maintains a higher
> > bitrate) than the version in current wireless-testing. The quality
> > report also fluctuates less than previously. This is consistent over a
> > few hours of testing with streaming PCM audio.
> >
> > I do get a lockdep warning when bringing up the device, however.
> >
> > =============================================
> > [ INFO: possible recursive locking detected ]
> > 2.6.27-rc1-rt2-wl #1
> > ---------------------------------------------
> > rt61pci/4405 is trying to acquire lock:
> > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > ieee80211_scan_completed+0x172/0x320 [mac80211]
> >
> > but task is already holding lock:
> > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > ieee80211_scan_completed+0x172/0x320 [mac80211]
> >
>
> I get that same lockdep warning when using the mainline kernel with b43. It
> doesn't seem to cause any problems.

Sounds like a mac80211 bug then, can't find something obvious at first glance,
but perhaps Johannes has an idea?

Ivo

2008-08-04 14:18:27

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 5/5] rt2x00: Release rt2x00 2.2.0


Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/rt2x00.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 61f853f..7476a4e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -44,7 +44,7 @@
/*
* Module information.
*/
-#define DRV_VERSION "2.1.8"
+#define DRV_VERSION "2.2.0"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"

/*
--
1.5.6.1


2008-08-05 01:43:26

by Larry Finger

[permalink] [raw]
Subject: Re: [Rt2400-devel] Please pull 'upstream' branch of rt2x00

Will Dyson wrote:
> On Mon, Aug 4, 2008 at 10:36 AM, Ivo van Doorn <[email protected]> wrote:
>> Hi John,
>>
>> Only 5 patches, but they do bump rt2x00 to a new version: 2.2.0
>> This series will add HW crypto support to rt2x00, by default it
>> has been enabled for rt61pci and rt73usb.
>
> Seems to work well on my rt61pci card!
>
> In fact, it reports a higher link quality (and maintains a higher
> bitrate) than the version in current wireless-testing. The quality
> report also fluctuates less than previously. This is consistent over a
> few hours of testing with streaming PCM audio.
>
> I do get a lockdep warning when bringing up the device, however.
>
> =============================================
> [ INFO: possible recursive locking detected ]
> 2.6.27-rc1-rt2-wl #1
> ---------------------------------------------
> rt61pci/4405 is trying to acquire lock:
> (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> ieee80211_scan_completed+0x172/0x320 [mac80211]
>
> but task is already holding lock:
> (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> ieee80211_scan_completed+0x172/0x320 [mac80211]
>

I get that same lockdep warning when using the mainline kernel with b43. It
doesn't seem to cause any problems.

Larry


2008-08-04 14:18:07

by Ivo Van Doorn

[permalink] [raw]
Subject: [PATCH 2/5] rt2x00: Implement HW encryption (rt61pci)

rt61pci supports hardware encryption.
rt61pci supports up to 4 shared keys and up to 64 pairwise keys.

Signed-off-by: Ivo van Doorn <[email protected]>
---
drivers/net/wireless/rt2x00/Kconfig | 1 +
drivers/net/wireless/rt2x00/rt61pci.c | 256 ++++++++++++++++++++++++++++++++-
drivers/net/wireless/rt2x00/rt61pci.h | 21 +++-
3 files changed, 270 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 2f60e17..f333f61 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -107,6 +107,7 @@ config RT61PCI
depends on PCI
select RT2X00_LIB_PCI
select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_CRYPTO
select CRC_ITU_T
select EEPROM_93CX6
---help---
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 087e90b..86e7a50 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -346,6 +346,204 @@ static void rt61pci_init_led(struct rt2x00_dev *rt2x00dev,
/*
* Configuration handlers.
*/
+static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ struct rt2x00_field32 field;
+ u32 mask;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * rt2x00lib can't determine the correct free
+ * key_idx for shared keys. We have 1 register
+ * with key valid bits. The goal is simple, read
+ * the register, if that is full we have no slots
+ * left.
+ * Note that each BSS is allowed to have up to 4
+ * shared keys, so put a mask over the allowed
+ * entries.
+ */
+ mask = (0xf << crypto->bssidx);
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+ reg &= mask;
+
+ if (reg && reg == mask)
+ return -ENOSPC;
+
+ key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
+
+ /*
+ * Upload key to hardware
+ */
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ reg = SHARED_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
+
+ /*
+ * The cipher types are stored over 2 registers.
+ * bssidx 0 and 1 keys are stored in SEC_CSR1 and
+ * bssidx 1 and 2 keys are stored in SEC_CSR5.
+ * Using the correct defines correctly will cause overhead,
+ * so just calculate the correct offset.
+ */
+ if (key->hw_key_idx < 8) {
+ field.bit_offset = (3 * key->hw_key_idx);
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR1, &reg);
+ rt2x00_set_field32(&reg, field, crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR1, reg);
+ } else {
+ field.bit_offset = (3 * (key->hw_key_idx - 8));
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR5, &reg);
+ rt2x00_set_field32(&reg, field, crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR5, reg);
+ }
+
+ /*
+ * The driver does not support the IV/EIV generation
+ * in hardware. However it doesn't support the IV/EIV
+ * inside the ieee80211 frame either, but requires it
+ * to be provided seperately for the descriptor.
+ * rt2x00lib will cut the IV/EIV data out of all frames
+ * given to us by mac80211, but we must tell mac80211
+ * to generate the IV/EIV data.
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+
+ /*
+ * SEC_CSR0 contains only single-bit fields to indicate
+ * a particular key is valid. Because using the FIELD32()
+ * defines directly will cause a lot of overhead we use
+ * a calculation to determine the correct bit directly.
+ */
+ mask = 1 << key->hw_key_idx;
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR0, reg);
+
+ return 0;
+}
+
+static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_pairwise_ta_entry addr_entry;
+ struct hw_key_entry key_entry;
+ u32 mask;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * rt2x00lib can't determine the correct free
+ * key_idx for pairwise keys. We have 2 registers
+ * with key valid bits. The goal is simple, read
+ * the first register, if that is full move to
+ * the next register.
+ * When both registers are full, we drop the key,
+ * otherwise we use the first invalid entry.
+ */
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+ if (reg && reg == ~0) {
+ key->hw_key_idx = 32;
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+ if (reg && reg == ~0)
+ return -ENOSPC;
+ }
+
+ key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
+
+ /*
+ * Upload key to hardware
+ */
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ memset(&addr_entry, 0, sizeof(addr_entry));
+ memcpy(&addr_entry, crypto->address, ETH_ALEN);
+ addr_entry.cipher = crypto->cipher;
+
+ reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
+
+ reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, reg,
+ &addr_entry, sizeof(addr_entry));
+
+ /*
+ * Enable pairwise lookup table for given BSS idx,
+ * without this received frames will not be decrypted
+ * by the hardware.
+ */
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR4, &reg);
+ reg |= (1 << crypto->bssidx);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR4, reg);
+
+ /*
+ * The driver does not support the IV/EIV generation
+ * in hardware. However it doesn't support the IV/EIV
+ * inside the ieee80211 frame either, but requires it
+ * to be provided seperately for the descriptor.
+ * rt2x00lib will cut the IV/EIV data out of all frames
+ * given to us by mac80211, but we must tell mac80211
+ * to generate the IV/EIV data.
+ */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+
+ /*
+ * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
+ * a particular key is valid. Because using the FIELD32()
+ * defines directly will cause a lot of overhead we use
+ * a calculation to determine the correct bit directly.
+ */
+ if (key->hw_key_idx < 32) {
+ mask = 1 << key->hw_key_idx;
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR2, reg);
+ } else {
+ mask = 1 << (key->hw_key_idx - 32);
+
+ rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+ if (crypto->cmd == SET_KEY)
+ reg |= mask;
+ else if (crypto->cmd == DISABLE_KEY)
+ reg &= ~mask;
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR3, reg);
+ }
+
+ return 0;
+}
+
static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
const unsigned int filter_flags)
{
@@ -1533,8 +1731,8 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
* TX descriptor initialization
*/
static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
- struct txentry_desc *txdesc)
+ struct sk_buff *skb,
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
@@ -1548,7 +1746,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
- rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
@@ -1561,6 +1759,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
rt2x00_desc_write(txd, 2, word);

+ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
+ _rt2x00_desc_write(txd, 3, skbdesc->iv);
+ _rt2x00_desc_write(txd, 4, skbdesc->eiv);
+ }
+
rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
@@ -1595,11 +1798,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+ test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+ test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
rt2x00_set_field32(&word, TXD_W0_BURST,
test_bit(ENTRY_TXD_BURST, &txdesc->flags));
- rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
rt2x00_desc_write(txd, 0, word);
}

@@ -1718,6 +1925,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
static void rt61pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0;
u32 word1;
@@ -1728,6 +1936,38 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;

+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ rxdesc->cipher =
+ rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+ rxdesc->cipher_status =
+ rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
+ }
+
+ if (rxdesc->cipher != CIPHER_NONE) {
+ _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv);
+ _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv);
+ _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv);
+
+ /*
+ * Hardware has stripped IV/EIV data from 802.11 frame during
+ * decryption. It has provided the data seperately but rt2x00lib
+ * should decide if it should be reinserted.
+ */
+ rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+ /*
+ * FIXME: Legacy driver indicates that the frame does
+ * contain the Michael Mic. Unfortunately, in rt2x00
+ * the MIC seems to be missing completely...
+ */
+ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
+ if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+ rxdesc->flags |= RX_FLAG_DECRYPTED;
+ else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+ rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+ }
+
/*
* Obtain the status about this packet.
* When frame was received with an OFDM bitrate,
@@ -1735,7 +1975,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
* a CCK bitrate the signal is the rate in 100kbit/s.
*/
rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
+ rxdesc->rssi = rt61pci_agc_to_rssi(rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);

if (rt2x00_get_field32(word0, RXD_W0_OFDM))
@@ -2355,6 +2595,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
*/
__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+ __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);

/*
* Set the rssi offset.
@@ -2404,6 +2645,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
.configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.set_retry_limit = rt61pci_set_retry_limit,
.bss_info_changed = rt2x00mac_bss_info_changed,
@@ -2432,6 +2674,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.write_beacon = rt61pci_write_beacon,
.kick_tx_queue = rt61pci_kick_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone,
+ .config_shared_key = rt61pci_config_shared_key,
+ .config_pairwise_key = rt61pci_config_pairwise_key,
.config_filter = rt61pci_config_filter,
.config_intf = rt61pci_config_intf,
.config_erp = rt61pci_config_erp,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 1004d5b..6d591ce 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -134,6 +134,16 @@
#define PAIRWISE_KEY_TABLE_BASE 0x1200
#define PAIRWISE_TA_TABLE_BASE 0x1a00

+#define SHARED_KEY_ENTRY(__idx) \
+ ( SHARED_KEY_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+ ( PAIRWISE_KEY_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_key_entry)) )
+#define PAIRWISE_TA_ENTRY(__idx) \
+ ( PAIRWISE_TA_TABLE_BASE + \
+ ((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+
struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
@@ -142,7 +152,8 @@ struct hw_key_entry {

struct hw_pairwise_ta_entry {
u8 address[6];
- u8 reserved[2];
+ u8 cipher;
+ u8 reserved;
} __attribute__ ((packed));

/*
@@ -662,6 +673,10 @@ struct hw_pairwise_ta_entry {
* SEC_CSR4: Pairwise key table lookup control.
*/
#define SEC_CSR4 0x30b0
+#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001)
+#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002)
+#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004)
+#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008)

/*
* SEC_CSR5: shared key table security mode register.
@@ -1428,8 +1443,10 @@ struct hw_pairwise_ta_entry {

/*
* Word4
+ * ICV: Received ICV of originally encrypted.
+ * NOTE: This is a guess, the official definition is "reserved"
*/
-#define RXD_W4_RESERVED FIELD32(0xffffffff)
+#define RXD_W4_ICV FIELD32(0xffffffff)

/*
* the above 20-byte is called RXINFO and will be DMAed to MAC RX block
--
1.5.6.1


2008-08-05 18:20:11

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [Rt2400-devel] Please pull 'upstream' branch of rt2x00

On Tuesday 05 August 2008, Johannes Berg wrote:
> On Tue, 2008-08-05 at 20:30 +0200, Ivo van Doorn wrote:
>
> > > > =============================================
> > > > [ INFO: possible recursive locking detected ]
> > > > 2.6.27-rc1-rt2-wl #1
> > > > ---------------------------------------------
> > > > rt61pci/4405 is trying to acquire lock:
> > > > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > > > ieee80211_scan_completed+0x172/0x320 [mac80211]
> > > >
> > > > but task is already holding lock:
> > > > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > > > ieee80211_scan_completed+0x172/0x320 [mac80211]
> > > >
> > >
> > > I get that same lockdep warning when using the mainline kernel with b43. It
> > > doesn't seem to cause any problems.
> >
> > Sounds like a mac80211 bug then, can't find something obvious at first glance,
> > but perhaps Johannes has an idea?
>
> I ignore everything with the TX lock in it because those have been
> wrongly annotated in a bunch of versions, including -rc1 afaik.

Heh ok. :)

Ivo

2008-08-05 01:21:48

by Will Dyson

[permalink] [raw]
Subject: Re: [Rt2400-devel] Please pull 'upstream' branch of rt2x00

On Mon, Aug 4, 2008 at 10:36 AM, Ivo van Doorn <[email protected]> wrote:
> Hi John,
>
> Only 5 patches, but they do bump rt2x00 to a new version: 2.2.0
> This series will add HW crypto support to rt2x00, by default it
> has been enabled for rt61pci and rt73usb.

Seems to work well on my rt61pci card!

In fact, it reports a higher link quality (and maintains a higher
bitrate) than the version in current wireless-testing. The quality
report also fluctuates less than previously. This is consistent over a
few hours of testing with streaming PCM audio.

I do get a lockdep warning when bringing up the device, however.

=============================================
[ INFO: possible recursive locking detected ]
2.6.27-rc1-rt2-wl #1
---------------------------------------------
rt61pci/4405 is trying to acquire lock:
(_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
ieee80211_scan_completed+0x172/0x320 [mac80211]

but task is already holding lock:
(_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
ieee80211_scan_completed+0x172/0x320 [mac80211]

other info that might help us debug this:
3 locks held by rt61pci/4405:
#0: ((name)){--..}, at: [<ffffffff80250741>] run_workqueue+0xa1/0x230
#1: (&(&local->scan_work)->work){--..}, at: [<ffffffff80250741>]
run_workqueue+0xa1/0x230
#2: (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
ieee80211_scan_completed+0x172/0x320 [mac80211]

stack backtrace:
Pid: 4405, comm: rt61pci Not tainted 2.6.27-rc1-rt2-wl #1

Call Trace:
[<ffffffff802657ac>] __lock_acquire+0xb1c/0x12d0
[<ffffffff8024939e>] ? __mod_timer+0xbe/0xe0
[<ffffffff80265fb9>] lock_acquire+0x59/0x80
[<ffffffffa014cc52>] ? ieee80211_scan_completed+0x172/0x320 [mac80211]
[<ffffffff8055e5d4>] _spin_lock+0x34/0x50
[<ffffffffa014cc52>] ieee80211_scan_completed+0x172/0x320 [mac80211]
[<ffffffffa014d0bb>] ieee80211_sta_scan_work+0x8b/0x210 [mac80211]
[<ffffffffa014d030>] ? ieee80211_sta_scan_work+0x0/0x210 [mac80211]
[<ffffffffa014d030>] ? ieee80211_sta_scan_work+0x0/0x210 [mac80211]
[<ffffffff8025078b>] run_workqueue+0xeb/0x230
[<ffffffff80250977>] worker_thread+0xa7/0x120
[<ffffffff80254f30>] ? autoremove_wake_function+0x0/0x40
[<ffffffff802508d0>] ? worker_thread+0x0/0x120
[<ffffffff80254b89>] kthread+0x49/0x80
[<ffffffff8020d5b9>] child_rip+0xa/0x11
[<ffffffff8020cbc3>] ? restore_args+0x0/0x30
[<ffffffff80254b40>] ? kthread+0x0/0x80
[<ffffffff8020d5af>] ? child_rip+0x0/0x11


--
Will Dyson

2008-08-04 17:22:22

by Gábor Stefanik

[permalink] [raw]
Subject: Re: [PATCH 3/5] rt2x00: Implement HW encryption (rt73usb)

On Mon, Aug 4, 2008 at 4:38 PM, Ivo van Doorn <[email protected]> wrote:
> rt73usb supports hardware encryption.
> rt73usb supports up to 4 shared keys and up to 64 pairwise keys.
>
> Signed-off-by: Ivo van Doorn <[email protected]>
> ---
> drivers/net/wireless/rt2x00/Kconfig | 1 +
> drivers/net/wireless/rt2x00/rt73usb.c | 271 ++++++++++++++++++++++++++++++++-
> drivers/net/wireless/rt2x00/rt73usb.h | 21 +++-
> 3 files changed, 285 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
> index f333f61..11f590d 100644
> --- a/drivers/net/wireless/rt2x00/Kconfig
> +++ b/drivers/net/wireless/rt2x00/Kconfig
> @@ -156,6 +156,7 @@ config RT73USB
> depends on USB
> select RT2X00_LIB_USB
> select RT2X00_LIB_FIRMWARE
> + select RT2X00_LIB_CRYPTO
> select CRC_ITU_T
> ---help---
> This adds support for rt2501 wireless chipset family.
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
> index 9761eaa..ddba747 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.c
> +++ b/drivers/net/wireless/rt2x00/rt73usb.c
> @@ -357,6 +357,219 @@ static void rt73usb_init_led(struct rt2x00_dev *rt2x00dev,
> /*
> * Configuration handlers.
> */
> +static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
> + struct rt2x00lib_crypto *crypto,
> + struct ieee80211_key_conf *key)
> +{
> + struct hw_key_entry key_entry;
> + struct rt2x00_field32 field;
> + int timeout;
> + u32 mask;
> + u32 reg;
> +
> + if (crypto->cmd == SET_KEY) {
> + /*
> + * rt2x00lib can't determine the correct free
> + * key_idx for shared keys. We have 1 register
> + * with key valid bits. The goal is simple, read
> + * the register, if that is full we have no slots
> + * left.
> + * Note that each BSS is allowed to have up to 4
> + * shared keys, so put a mask over the allowed
> + * entries.
> + */
> + mask = (0xf << crypto->bssidx);
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
> + reg &= mask;
> +
> + if (reg && reg == mask)
> + return -ENOSPC;
> +
> + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
> +
> + /*
> + * Upload key to hardware
> + */
> + memcpy(key_entry.key, crypto->key,
> + sizeof(key_entry.key));
> + memcpy(key_entry.tx_mic, crypto->tx_mic,
> + sizeof(key_entry.tx_mic));
> + memcpy(key_entry.rx_mic, crypto->rx_mic,
> + sizeof(key_entry.rx_mic));
> +
> + reg = SHARED_KEY_ENTRY(key->hw_key_idx);
> + timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
> + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
> + USB_VENDOR_REQUEST_OUT, reg,
> + &key_entry,
> + sizeof(key_entry),
> + timeout);
> +
> + /*
> + * The cipher types are stored over 2 registers.
> + * bssidx 0 and 1 keys are stored in SEC_CSR1 and
> + * bssidx 1 and 2 keys are stored in SEC_CSR5.
> + * Using the correct defines correctly will cause overhead,
> + * so just calculate the correct offset.
> + */
> + if (key->hw_key_idx < 8) {
> + field.bit_offset = (3 * key->hw_key_idx);
> + field.bit_mask = 0x7 << field.bit_offset;
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR1, &reg);
> + rt2x00_set_field32(&reg, field, crypto->cipher);
> + rt73usb_register_write(rt2x00dev, SEC_CSR1, reg);
> + } else {
> + field.bit_offset = (3 * (key->hw_key_idx - 8));
> + field.bit_mask = 0x7 << field.bit_offset;
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR5, &reg);
> + rt2x00_set_field32(&reg, field, crypto->cipher);
> + rt73usb_register_write(rt2x00dev, SEC_CSR5, reg);
> + }
> +
> + /*
> + * The driver does not support the IV/EIV generation
> + * in hardware. However it doesn't support the IV/EIV
> + * inside the ieee80211 frame either, but requires it
> + * to be provided seperately for the descriptor.
> + * rt2x00lib will cut the IV/EIV data out of all frames
> + * given to us by mac80211, but we must tell mac80211
> + * to generate the IV/EIV data.
> + */
> + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
> + }
> +
> + /*
> + * SEC_CSR0 contains only single-bit fields to indicate
> + * a particular key is valid. Because using the FIELD32()
> + * defines directly will cause a lot of overhead we use
> + * a calculation to determine the correct bit directly.
> + */
> + mask = 1 << key->hw_key_idx;
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR0, &reg);
> + if (crypto->cmd == SET_KEY)
> + reg |= mask;
> + else if (crypto->cmd == DISABLE_KEY)
> + reg &= ~mask;
> + rt73usb_register_write(rt2x00dev, SEC_CSR0, reg);
> +
> + return 0;
> +}
> +
> +static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
> + struct rt2x00lib_crypto *crypto,
> + struct ieee80211_key_conf *key)
> +{
> + struct hw_pairwise_ta_entry addr_entry;
> + struct hw_key_entry key_entry;
> + int timeout;
> + u32 mask;
> + u32 reg;
> +
> + if (crypto->cmd == SET_KEY) {
> + /*
> + * rt2x00lib can't determine the correct free
> + * key_idx for pairwise keys. We have 2 registers
> + * with key valid bits. The goal is simple, read
> + * the first register, if that is full move to
> + * the next register.
> + * When both registers are full, we drop the key,
> + * otherwise we use the first invalid entry.
> + */
> + rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
> + if (reg && reg == ~0) {
> + key->hw_key_idx = 32;
> + rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
> + if (reg && reg == ~0)
> + return -ENOSPC;
> + }
> +
> + key->hw_key_idx += reg ? (ffz(reg) - 1) : 0;
> +
> + /*
> + * Upload key to hardware
> + */
> + memcpy(key_entry.key, crypto->key,
> + sizeof(key_entry.key));
> + memcpy(key_entry.tx_mic, crypto->tx_mic,
> + sizeof(key_entry.tx_mic));
> + memcpy(key_entry.rx_mic, crypto->rx_mic,
> + sizeof(key_entry.rx_mic));
> +
> + reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
> + timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
> + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
> + USB_VENDOR_REQUEST_OUT, reg,
> + &key_entry,
> + sizeof(key_entry),
> + timeout);
> +
> + /*
> + * Send the address and cipher type to the hardware register.
> + * This data fits within the CSR cache size, so we can use
> + * rt73usb_register_multiwrite() directly.
> + */
> + memset(&addr_entry, 0, sizeof(addr_entry));
> + memcpy(&addr_entry, crypto->address, ETH_ALEN);
> + addr_entry.cipher = crypto->cipher;
> +
> + reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
> + rt73usb_register_multiwrite(rt2x00dev, reg,
> + &addr_entry, sizeof(addr_entry));
> +
> + /*
> + * Enable pairwise lookup table for given BSS idx,
> + * without this received frames will not be decrypted
> + * by the hardware.
> + */
> + rt73usb_register_read(rt2x00dev, SEC_CSR4, &reg);
> + reg |= (1 << crypto->bssidx);
> + rt73usb_register_write(rt2x00dev, SEC_CSR4, reg);
> +
> + /*
> + * The driver does not support the IV/EIV generation
> + * in hardware. However it doesn't support the IV/EIV
> + * inside the ieee80211 frame either, but requires it
> + * to be provided seperately for the descriptor.
> + * rt2x00lib will cut the IV/EIV data out of all frames
> + * given to us by mac80211, but we must tell mac80211
> + * to generate the IV/EIV data.
> + */
> + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
> + }
> +
> + /*
> + * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
> + * a particular key is valid. Because using the FIELD32()
> + * defines directly will cause a lot of overhead we use
> + * a calculation to determine the correct bit directly.
> + */
> + if (key->hw_key_idx < 32) {
> + mask = 1 << key->hw_key_idx;
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR2, &reg);
> + if (crypto->cmd == SET_KEY)
> + reg |= mask;
> + else if (crypto->cmd == DISABLE_KEY)
> + reg &= ~mask;
> + rt73usb_register_write(rt2x00dev, SEC_CSR2, reg);
> + } else {
> + mask = 1 << (key->hw_key_idx - 32);
> +
> + rt73usb_register_read(rt2x00dev, SEC_CSR3, &reg);
> + if (crypto->cmd == SET_KEY)
> + reg |= mask;
> + else if (crypto->cmd == DISABLE_KEY)
> + reg &= ~mask;
> + rt73usb_register_write(rt2x00dev, SEC_CSR3, reg);
> + }
> +
> + return 0;
> +}
> +
> static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev,
> const unsigned int filter_flags)
> {
> @@ -1265,8 +1478,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
> * TX descriptor initialization
> */
> static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
> - struct sk_buff *skb,
> - struct txentry_desc *txdesc)
> + struct sk_buff *skb,
> + struct txentry_desc *txdesc)
> {
> struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
> __le32 *txd = skbdesc->desc;
> @@ -1280,7 +1493,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
> rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
> rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
> rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
> - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
> + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
> rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
> test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
> rt2x00_desc_write(txd, 1, word);
> @@ -1292,6 +1505,11 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
> rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high);
> rt2x00_desc_write(txd, 2, word);
>
> + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) {
> + _rt2x00_desc_write(txd, 3, skbdesc->iv);
> + _rt2x00_desc_write(txd, 4, skbdesc->eiv);
> + }
> +
> rt2x00_desc_read(txd, 5, &word);
> rt2x00_set_field32(&word, TXD_W5_TX_POWER,
> TXPOWER_TO_DEV(rt2x00dev->tx_power));
> @@ -1313,12 +1531,16 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
> rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
> rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
> test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
> - rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
> + rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
> + test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
> + rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
> + test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
> + rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
> rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT,
> skb->len - skbdesc->desc_len);
> rt2x00_set_field32(&word, TXD_W0_BURST2,
> test_bit(ENTRY_TXD_BURST, &txdesc->flags));
> - rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
> + rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
> rt2x00_desc_write(txd, 0, word);
> }
>
> @@ -1468,6 +1690,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
> static void rt73usb_fill_rxdone(struct queue_entry *entry,
> struct rxdone_entry_desc *rxdesc)
> {
> + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
> __le32 *rxd = (__le32 *)entry->skb->data;
> u32 word0;
> @@ -1489,6 +1712,38 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
> if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
> rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
>
> + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
> + rxdesc->cipher =
> + rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
> + rxdesc->cipher_status =
> + rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
> + }
> +
> + if (rxdesc->cipher != CIPHER_NONE) {
> + _rt2x00_desc_read(rxd, 2, &rxdesc->iv);
> + _rt2x00_desc_read(rxd, 3, &rxdesc->eiv);
> + _rt2x00_desc_read(rxd, 4, &rxdesc->icv);
> +
> + /*
> + * Hardware has stripped IV/EIV data from 802.11 frame during
> + * decryption. It has provided the data seperately but rt2x00lib
> + * should decide if it should be reinserted.
> + */
> + rxdesc->flags |= RX_FLAG_IV_STRIPPED;
> +
> + /*
> + * FIXME: Legacy driver indicates that the frame does
> + * contain the Michael Mic. Unfortunately, in rt2x00
> + * the MIC seems to be missing completely...
> + */
> + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
> +
> + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
> + rxdesc->flags |= RX_FLAG_DECRYPTED;
> + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
> + rxdesc->flags |= RX_FLAG_MMIC_ERROR;
> + }
> +
> /*
> * Obtain the status about this packet.
> * When frame was received with an OFDM bitrate,
> @@ -1496,7 +1751,7 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
> * a CCK bitrate the signal is the rate in 100kbit/s.
> */
> rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
> - rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
> + rxdesc->rssi = rt73usb_agc_to_rssi(rt2x00dev, word1);
> rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
>
> if (rt2x00_get_field32(word0, RXD_W0_OFDM))
> @@ -1938,6 +2193,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
> */
> __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
> __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
> + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
>
> /*
> * Set the rssi offset.
> @@ -1997,6 +2253,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
> .config = rt2x00mac_config,
> .config_interface = rt2x00mac_config_interface,
> .configure_filter = rt2x00mac_configure_filter,
> + .set_key = rt2x00mac_set_key,
> .get_stats = rt2x00mac_get_stats,
> .set_retry_limit = rt73usb_set_retry_limit,
> .bss_info_changed = rt2x00mac_bss_info_changed,
> @@ -2024,6 +2281,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
> .get_tx_data_len = rt73usb_get_tx_data_len,
> .kick_tx_queue = rt73usb_kick_tx_queue,
> .fill_rxdone = rt73usb_fill_rxdone,
> + .config_shared_key = rt73usb_config_shared_key,
> + .config_pairwise_key = rt73usb_config_pairwise_key,
> .config_filter = rt73usb_config_filter,
> .config_intf = rt73usb_config_intf,
> .config_erp = rt73usb_config_erp,
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
> index 1484935..91e04d3 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.h
> +++ b/drivers/net/wireless/rt2x00/rt73usb.h
> @@ -92,6 +92,16 @@
> #define PAIRWISE_KEY_TABLE_BASE 0x1200
> #define PAIRWISE_TA_TABLE_BASE 0x1a00
>
> +#define SHARED_KEY_ENTRY(__idx) \
> + ( SHARED_KEY_TABLE_BASE + \
> + ((__idx) * sizeof(struct hw_key_entry)) )
> +#define PAIRWISE_KEY_ENTRY(__idx) \
> + ( PAIRWISE_KEY_TABLE_BASE + \
> + ((__idx) * sizeof(struct hw_key_entry)) )
> +#define PAIRWISE_TA_ENTRY(__idx) \
> + ( PAIRWISE_TA_TABLE_BASE + \
> + ((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
> +
> struct hw_key_entry {
> u8 key[16];
> u8 tx_mic[8];
> @@ -100,7 +110,8 @@ struct hw_key_entry {
>
> struct hw_pairwise_ta_entry {
> u8 address[6];
> - u8 reserved[2];
> + u8 cipher;
> + u8 reserved;
> } __attribute__ ((packed));
>
> /*
> @@ -563,6 +574,10 @@ struct hw_pairwise_ta_entry {
> * SEC_CSR4: Pairwise key table lookup control.
> */
> #define SEC_CSR4 0x30b0
> +#define SEC_CSR4_ENABLE_BSS0 FIELD32(0x00000001)
> +#define SEC_CSR4_ENABLE_BSS1 FIELD32(0x00000002)
> +#define SEC_CSR4_ENABLE_BSS2 FIELD32(0x00000004)
> +#define SEC_CSR4_ENABLE_BSS3 FIELD32(0x00000008)
>
> /*
> * SEC_CSR5: shared key table security mode register.
> @@ -1010,8 +1025,10 @@ struct hw_pairwise_ta_entry {
>
> /*
> * Word4
> + * ICV: Received ICV of originally encrypted.
> + * NOTE: This is a guess, the official definition is "reserved"
> */
> -#define RXD_W4_RESERVED FIELD32(0xffffffff)
> +#define RXD_W4_ICV FIELD32(0xffffffff)
>
> /*
> * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
> --
> 1.5.6.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

We need modparams for disabling HW crypto support if it misbehaves.

--
Vista: [V]iruses, [I]ntruders, [S]pyware, [T]rojans and [A]dware. :-)

2008-08-05 18:12:22

by Johannes Berg

[permalink] [raw]
Subject: Re: [Rt2400-devel] Please pull 'upstream' branch of rt2x00

On Tue, 2008-08-05 at 20:30 +0200, Ivo van Doorn wrote:

> > > =============================================
> > > [ INFO: possible recursive locking detected ]
> > > 2.6.27-rc1-rt2-wl #1
> > > ---------------------------------------------
> > > rt61pci/4405 is trying to acquire lock:
> > > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > > ieee80211_scan_completed+0x172/0x320 [mac80211]
> > >
> > > but task is already holding lock:
> > > (_xmit_IEEE80211#2){-...}, at: [<ffffffffa014cc52>]
> > > ieee80211_scan_completed+0x172/0x320 [mac80211]
> > >
> >
> > I get that same lockdep warning when using the mainline kernel with b43. It
> > doesn't seem to cause any problems.
>
> Sounds like a mac80211 bug then, can't find something obvious at first glance,
> but perhaps Johannes has an idea?

I ignore everything with the TX lock in it because those have been
wrongly annotated in a bunch of versions, including -rc1 afaik.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part