* [PATCH 1/7] Fix possible mutex double-locking
@ 2008-07-04 17:43 Milan Plzik
2008-07-04 17:44 ` [PATCH 2/7] Don't leave queues stopped when not neccessary Milan Plzik
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:43 UTC (permalink / raw)
To: linux-wireless
After finishing scan, at76_dwork_hw_scan locks priv->mtx and calls
ieee80211_scan_completed, which in turn can possibly call at76_config,
which tries to lock the mutex again.
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index eab8f16..dc6edb3 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1897,8 +1897,6 @@ static void at76_dwork_hw_scan(struct work_struct *work)
dwork_hw_scan.work);
int ret;
- mutex_lock(&priv->mtx);
-
ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
at76_dbg(DBG_MAC80211, "%s: CMD_SCAN status 0x%02x", __func__, ret);
@@ -1909,16 +1907,16 @@ static void at76_dwork_hw_scan(struct work_struct *work)
SCAN_POLL_INTERVAL);
goto exit;
}
-
+
ieee80211_scan_completed(priv->hw);
if (is_valid_ether_addr(priv->bssid))
at76_join(priv);
- ieee80211_wake_queues(priv->hw);
+// CHECKME: ieee80211_wake_queues(priv->hw);
exit:
- mutex_unlock(&priv->mtx);
+ return;
}
static int at76_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/7] Don't leave queues stopped when not neccessary.
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
2008-07-04 17:44 ` [PATCH 3/7] Remove usage of data which were already skb_pull-ed Milan Plzik
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
at76_usb driver doesn't enable transmit queue very often -- in fact the
only place where queues are being started is tx callback handler. This
patch adds calls to ieee80211_start_queues to proper places, so the card
will not hang in state with queues stopped.
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 14 +++++++++++---
1 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index dc6edb3..13ea9ca 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1910,8 +1910,13 @@ static void at76_dwork_hw_scan(struct work_struct *work)
ieee80211_scan_completed(priv->hw);
- if (is_valid_ether_addr(priv->bssid))
+ if (is_valid_ether_addr(priv->bssid)) {
+ ieee80211_start_queues(priv->hw);
at76_join(priv);
+ } else
+ ieee80211_stop_queues(priv->hw);
+
+ ieee80211_start_queues(priv->hw);
// CHECKME: ieee80211_wake_queues(priv->hw);
@@ -1974,10 +1979,13 @@ static int at76_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
priv->channel = conf->channel->hw_value;
- if (is_valid_ether_addr(priv->bssid))
+ if (is_valid_ether_addr(priv->bssid)) {
at76_join(priv);
- else
+ ieee80211_start_queues(priv->hw);
+ } else {
+ ieee80211_stop_queues(priv->hw);
at76_start_monitor(priv);
+ };
mutex_unlock(&priv->mtx);
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/7] Remove usage of data which were already skb_pull-ed.
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
2008-07-04 17:44 ` [PATCH 2/7] Don't leave queues stopped when not neccessary Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
2008-07-04 17:44 ` [PATCH 4/7] Some at76-based devices don't include FCS in received frames Milan Plzik
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
at76_rx_tasklet makes use of data referenced by 'buf' despite of the fact
they were already marked as free by skb_pull. This patch delays skb_pull, so
data will remain valid.
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index 13ea9ca..b6d06b8 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1594,15 +1594,16 @@ static void at76_rx_tasklet(unsigned long param)
wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi,
buf->noise_level, buf->link_quality);
- skb_pull(priv->rx_skb, AT76_RX_HDRLEN);
- skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength));
- at76_dbg_dump(DBG_RX_DATA, priv->rx_skb->data,
- priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len);
+
+ skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength) + AT76_RX_HDRLEN);
+ at76_dbg_dump(DBG_RX_DATA, &priv->rx_skb->data[AT76_RX_HDRLEN],
+ priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len - AT76_RX_HDRLEN);
rx_status.signal = buf->rssi;
rx_status.flag |= RX_FLAG_DECRYPTED;
rx_status.flag |= RX_FLAG_IV_STRIPPED;
+ skb_pull(priv->rx_skb, AT76_RX_HDRLEN);
at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
priv->rx_skb->len, priv->rx_skb->data_len);
ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/7] Some at76-based devices don't include FCS in received frames.
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
2008-07-04 17:44 ` [PATCH 2/7] Don't leave queues stopped when not neccessary Milan Plzik
2008-07-04 17:44 ` [PATCH 3/7] Remove usage of data which were already skb_pull-ed Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
2008-07-04 17:44 ` [PATCH 5/7] Minor final fixes Milan Plzik
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
Make at76_init_new_device to register device with hwflag
IEEE80211_HW_RX_INCLUDES_FCS only in case when it is not proven otherwise
(with firmware 1.103 and, according to atmelwlandriver, with rfmd, r505 and
r505_2958 devices, the frame doesn't include FCS).
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index b6d06b8..43ec42c 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -106,6 +106,8 @@
static int at76_debug = DBG_DEFAULTS;
+#define FIRMWARE_IS_WPA(ver) ((ver.major == 1) && (ver.minor == 103))
+
/* Protect against concurrent firmware loading and parsing */
static struct mutex fw_mutex;
@@ -306,6 +308,11 @@ static inline int at76_is_503rfmd(enum board_type board)
return (board == BOARD_503 || board == BOARD_503_ACC);
}
+static inline int at76_is_505(enum board_type board)
+{
+ return (board == BOARD_505 || BOARD_505_2958);
+}
+
static inline int at76_is_505a(enum board_type board)
{
return (board == BOARD_505A || board == BOARD_505AMX);
@@ -1597,7 +1604,7 @@ static void at76_rx_tasklet(unsigned long param)
skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength) + AT76_RX_HDRLEN);
at76_dbg_dump(DBG_RX_DATA, &priv->rx_skb->data[AT76_RX_HDRLEN],
- priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len - AT76_RX_HDRLEN);
+ priv->rx_skb->len, "RX: len=%d", (int)(priv->rx_skb->len - AT76_RX_HDRLEN));
rx_status.signal = buf->rssi;
rx_status.flag |= RX_FLAG_DECRYPTED;
@@ -2277,8 +2284,14 @@ static int at76_init_new_device(struct at76_priv *priv,
/* mac80211 initialisation */
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
- priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC;
+
+ if (FIRMWARE_IS_WPA(priv->fw_version) &&
+ (at76_is_503rfmd(priv->board_type) ||
+ at76_is_505(priv->board_type)))
+ priv->hw->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+ else
+ priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_UNSPEC;
SET_IEEE80211_DEV(priv->hw, &interface->dev);
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/7] Minor final fixes.
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
` (2 preceding siblings ...)
2008-07-04 17:44 ` [PATCH 4/7] Some at76-based devices don't include FCS in received frames Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
2008-07-04 17:44 ` [PATCH 6/7] Adds support for WEP operation with 1.103.x firmware Milan Plzik
2008-07-04 17:44 ` [PATCH 7/7] Add WPA support for 1.103 firmware Milan Plzik
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
- report rate at which was frame received
- fix the issue with growing latencies (call ieee80211_wake_queues from tx
complete handler)
- tx handler doesn't report ack'ed frame anymore -- the adapter doesn't
report ACK status
- association after loading driver now works at first attempt
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index 43ec42c..612c714 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1607,6 +1607,7 @@ static void at76_rx_tasklet(unsigned long param)
priv->rx_skb->len, "RX: len=%d", (int)(priv->rx_skb->len - AT76_RX_HDRLEN));
rx_status.signal = buf->rssi;
+ rx_status.rate_idx = buf->rx_rate; /* FIXME: is rate_idx still present in structure? */
rx_status.flag |= RX_FLAG_DECRYPTED;
rx_status.flag |= RX_FLAG_IV_STRIPPED;
@@ -1707,7 +1708,7 @@ static void at76_mac80211_tx_callback(struct urb *urb)
switch (urb->status) {
case 0:
/* success */
- info->flags |= IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK; /* FIXME: is the frame really ACKed when tx_callback is called ? */
break;
case -ENOENT:
case -ECONNRESET:
@@ -1919,12 +1920,12 @@ static void at76_dwork_hw_scan(struct work_struct *work)
ieee80211_scan_completed(priv->hw);
if (is_valid_ether_addr(priv->bssid)) {
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
at76_join(priv);
} else
ieee80211_stop_queues(priv->hw);
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
// CHECKME: ieee80211_wake_queues(priv->hw);
@@ -1989,7 +1990,7 @@ static int at76_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
if (is_valid_ether_addr(priv->bssid)) {
at76_join(priv);
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
} else {
ieee80211_stop_queues(priv->hw);
at76_start_monitor(priv);
@@ -2016,9 +2017,12 @@ static int at76_config_interface(struct ieee80211_hw *hw,
memcpy(priv->essid, conf->ssid, conf->ssid_len);
priv->essid_size = conf->ssid_len;
- if (is_valid_ether_addr(priv->bssid))
+ if (is_valid_ether_addr(priv->bssid)) {
/* mac80211 is joining a bss */
+ ieee80211_wake_queues(priv->hw);
at76_join(priv);
+ } else
+ ieee80211_stop_queues(priv->hw);
mutex_unlock(&priv->mtx);
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6/7] Adds support for WEP operation with 1.103.x firmware.
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
` (3 preceding siblings ...)
2008-07-04 17:44 ` [PATCH 5/7] Minor final fixes Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
2008-07-04 17:44 ` [PATCH 7/7] Add WPA support for 1.103 firmware Milan Plzik
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 214 ++++++++++++++++++++++++++++++++++++++-
drivers/net/wireless/at76_usb.h | 47 ++++++++-
2 files changed, 256 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index 612c714..5b6fa5c 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1069,6 +1069,45 @@ exit:
kfree(m);
}
+static void at76_dump_mib_mac_encryption(struct at76_priv *priv)
+{
+ int i;
+ int ret;
+ /*int key_len;*/
+ struct mib_mac_encryption *m = kmalloc(sizeof(struct mib_mac_encryption), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_ENCRYPTION, m,
+ sizeof(struct mib_mac_encryption));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MAC_ENCRYPTION) failed: %d\n",
+ wiphy_name(priv->hw->wiphy), ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MAC_ENCRYPTION: tkip_bssid %s priv_invoked %u "
+ "ciph_key_id %u grp_key_id %u excl_unencr %u "
+ "ckip_key_perm %u wep_icv_err %u wep_excluded %u",
+ wiphy_name(priv->hw->wiphy), mac2str(m->tkip_bssid),
+ m->privacy_invoked, m->cipher_default_key_id,
+ m->cipher_default_group_key_id, m->exclude_unencrypted,
+ m->ckip_key_permutation,
+ le32_to_cpu(m->wep_icv_error_count),
+ le32_to_cpu(m->wep_excluded_count));
+
+ /*key_len = (m->encryption_level == 1) ?
+ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;*/
+
+ for (i = 0; i < CIPHER_KEYS; i++)
+ at76_dbg(DBG_MIB, "%s: MIB MAC_ENCRYPTION: key %d: %s",
+ wiphy_name(priv->hw->wiphy), i,
+ hex2str(m->cipher_default_keyvalue[i], CIPHER_KEY_LEN));
+exit:
+ kfree(m);
+}
+
static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
{
int ret;
@@ -1601,7 +1640,6 @@ static void at76_rx_tasklet(unsigned long param)
wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi,
buf->noise_level, buf->link_quality);
-
skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength) + AT76_RX_HDRLEN);
at76_dbg_dump(DBG_RX_DATA, &priv->rx_skb->data[AT76_RX_HDRLEN],
priv->rx_skb->len, "RX: len=%d", (int)(priv->rx_skb->len - AT76_RX_HDRLEN));
@@ -1760,7 +1798,18 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
tx_buffer->padding = padding;
tx_buffer->wlength = cpu_to_le16(skb->len);
tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, info)->hw_value;
- memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved));
+ if (FIRMWARE_IS_WPA(priv->fw_version) && !(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
+ tx_buffer->key_id = (control->key_idx);
+ tx_buffer->cipher_type = priv->keys[control->key_idx].cipher;
+ tx_buffer->cipher_length = priv->keys[control->key_idx].keylen;
+ tx_buffer->reserved = 0;
+ } else {
+ tx_buffer->key_id = 0;
+ tx_buffer->cipher_type = 0;
+ tx_buffer->cipher_length = 0;
+ tx_buffer->reserved = 0;
+ };
+ /* memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved)); */
memcpy(tx_buffer->packet, skb->data, skb->len);
at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr",
@@ -1823,7 +1872,8 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
if (!priv->device_unplugged) {
/* We are called by "ifconfig ethX down", not because the
* device is not available anymore. */
- at76_set_radio(priv, 0);
+ if (at76_set_radio(priv, 0) == 1)
+ at76_wait_completion(priv, CMD_RADIO_ON);
/* We unlink rx_urb because at76_open() re-submits it.
* If unplugged, at76_delete_device() takes care of it. */
@@ -2061,7 +2111,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
queue_work(hw->workqueue, &priv->work_set_promisc);
}
-static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int at76_set_key_oldfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_address, const u8 *address,
struct ieee80211_key_conf *key)
{
@@ -2109,6 +2159,151 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return 0;
}
+static int at76_set_key_newfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_address, const u8 *address,
+ struct ieee80211_key_conf *key)
+{
+ struct at76_priv *priv = hw->priv;
+ int ret = -EOPNOTSUPP;
+
+ at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
+ "key->keylen %d",
+ __func__, cmd, key->alg, key->keyidx, key->keylen);
+
+ mutex_lock(&priv->mtx);
+
+ priv->mib_buf.type = MIB_MAC_ENCRYPTION;
+
+ if (cmd == DISABLE_KEY) {
+ priv->mib_buf.size = CIPHER_KEY_LEN;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption,
+ cipher_default_keyvalue[key->keyidx]);
+ memset(priv->mib_buf.data.data, 0, CIPHER_KEY_LEN);
+ if (at76_set_mib(priv, &priv->mib_buf) != CMD_STATUS_COMPLETE)
+ ret = -EOPNOTSUPP; /* -EIO would be probably better */
+ else {
+ ret = 0;
+ priv->keys[key->keyidx].cipher = CIPHER_NONE;
+ priv->keys[key->keyidx].keylen = 0;
+ };
+ if (priv->default_group_key == key->keyidx)
+ priv->default_group_key = 0xff;
+
+ if (priv->default_pairwise_key == key->keyidx)
+ priv->default_pairwise_key = 0xff;
+ /* If default pairwise key is removed, fall back to
+ * group key? */
+ goto exit;
+ };
+
+ if (cmd == SET_KEY) {
+ /* store key into MIB */
+ priv->mib_buf.size = CIPHER_KEY_LEN;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption,
+ cipher_default_keyvalue[key->keyidx]);
+ memset(priv->mib_buf.data.data, 0, CIPHER_KEY_LEN);
+ memcpy(priv->mib_buf.data.data, key->key, key->keylen);
+
+ switch (key->alg) {
+ case ALG_WEP:
+ if (key->keylen == 5) {
+ priv->keys[key->keyidx].cipher =
+ CIPHER_WEP64;
+ priv->keys[key->keyidx].keylen = 8;
+ } else if (key->keylen == 13) {
+ priv->keys[key->keyidx].cipher =
+ CIPHER_WEP128;
+ /* Firmware needs this */
+ priv->keys[key->keyidx].keylen = 8;
+ } else {
+ ret = -EOPNOTSUPP;
+ goto exit;
+ };
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto exit;
+
+ };
+
+ priv->mib_buf.data.data[38] = priv->keys[key->keyidx].cipher;
+ priv->mib_buf.data.data[39] = 1; /* Taken from atmelwlandriver,
+ not documented */
+
+ if (is_valid_ether_addr(address))
+ /* Pairwise key */
+ priv->mib_buf.data.data[39] |= (KEY_PAIRWISE | KEY_TX);
+ else if (is_broadcast_ether_addr(address))
+ /* Group key */
+ priv->mib_buf.data.data[39] |= (KEY_TX);
+ else /* Key used only for transmission ??? */
+ priv->mib_buf.data.data[39] |= (KEY_TX);
+
+ if (at76_set_mib(priv, &priv->mib_buf) !=
+ CMD_STATUS_COMPLETE) {
+ ret = -EOPNOTSUPP; /* -EIO would be probably better */
+ goto exit;
+ };
+ key->hw_key_idx = key->keyidx;
+
+ /* Set up default keys */
+ if (is_broadcast_ether_addr(address))
+ priv->default_group_key = key->keyidx;
+ if (is_valid_ether_addr(address))
+ priv->default_pairwise_key = key->keyidx;
+
+ /* Set up encryption MIBs */
+
+ /* first block of settings */
+ priv->mib_buf.size = 3;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption,
+ privacy_invoked);
+ priv->mib_buf.data.data[0] = 1; /* privacy_invoked */
+ priv->mib_buf.data.data[1] = priv->default_pairwise_key;
+ priv->mib_buf.data.data[2] = priv->default_group_key;
+
+ if ((ret = at76_set_mib(priv, &priv->mib_buf)) !=
+ CMD_STATUS_COMPLETE)
+ goto exit;
+
+ /* second block of settings */
+ priv->mib_buf.size = 3;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption,
+ exclude_unencrypted);
+ priv->mib_buf.data.data[0] = 1; /* exclude_unencrypted */
+ priv->mib_buf.data.data[1] = 0; /* wep_encryption_type */
+ priv->mib_buf.data.data[2] = 0; /* ckip_key_permutation */
+
+ if ((ret = at76_set_mib(priv, &priv->mib_buf)) !=
+ CMD_STATUS_COMPLETE)
+ goto exit;
+ ret = 0;
+ };
+exit:
+ at76_dump_mib_mac_encryption(priv);
+ mutex_unlock(&priv->mtx);
+ return ret;
+}
+
+static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_address, const u8 *address,
+ struct ieee80211_key_conf *key)
+{
+ struct at76_priv *priv = hw->priv;
+
+ // int i;
+
+ at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
+ "key->keylen %d",
+ __func__, cmd, key->alg, key->keyidx, key->keylen);
+
+ if (FIRMWARE_IS_WPA(priv->fw_version))
+ return at76_set_key_newfw(hw, cmd, local_address, address, key);
+ else
+ return at76_set_key_oldfw(hw, cmd, local_address, address, key);
+
+}
+
static const struct ieee80211_ops at76_ops = {
.tx = at76_mac80211_tx,
.add_interface = at76_add_interface,
@@ -2285,6 +2480,8 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->scan_min_time = DEF_SCAN_MIN_TIME;
priv->scan_max_time = DEF_SCAN_MAX_TIME;
priv->scan_mode = SCAN_TYPE_ACTIVE;
+ priv->default_pairwise_key = 0xff;
+ priv->default_group_key = 0xff;
/* mac80211 initialisation */
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
@@ -2317,6 +2514,15 @@ static int at76_init_new_device(struct at76_priv *priv,
printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
wiphy_name(priv->hw->wiphy),
priv->regulatory_domain, priv->domain->name);
+ printk(KERN_INFO "%s: WPA support: ", wiphy_name(priv->hw->wiphy));
+ if (!FIRMWARE_IS_WPA(priv->fw_version))
+ printk("none\n");
+ else {
+ if (!at76_is_505a(priv->board_type))
+ printk("TKIP\n");
+ else
+ printk("TKIP, AES/CCMP\n");
+ };
exit:
return ret;
diff --git a/drivers/net/wireless/at76_usb.h b/drivers/net/wireless/at76_usb.h
index 1ec5ccf..8bb352f 100644
--- a/drivers/net/wireless/at76_usb.h
+++ b/drivers/net/wireless/at76_usb.h
@@ -65,6 +65,7 @@ enum board_type {
#define MIB_MAC 0x03
#define MIB_MAC_MGMT 0x05
#define MIB_MAC_WEP 0x06
+#define MIB_MAC_ENCRYPTION 0x06
#define MIB_PHY 0x07
#define MIB_FW_VERSION 0x08
#define MIB_MDOMAIN 0x09
@@ -89,6 +90,26 @@ enum board_type {
#define AT76_PM_ON 2
#define AT76_PM_SMART 3
+/* cipher values for encryption keys */
+#define CIPHER_NONE 0 /* this value is only guessed */
+#define CIPHER_WEP64 1
+#define CIPHER_TKIP 2
+#define CIPHER_CCMP 3
+#define CIPHER_CCX 4 /* for consistency sake only */
+#define CIPHER_WEP128 5
+
+/* bit flags key types for encryption keys */
+#define KEY_PAIRWISE 2
+#define KEY_TX 4
+
+#define CIPHER_KEYS (4)
+#define CIPHER_KEY_LEN (40)
+
+struct key_config {
+ u8 cipher;
+ u8 keylen;
+};
+
struct hwcfg_r505 {
u8 cr39_values[14];
u8 reserved1[14];
@@ -132,6 +153,8 @@ union at76_hwcfg {
#define WEP_LARGE_KEY_LEN (104 / 8)
#define WEP_KEYS (4)
+
+
struct at76_card_config {
u8 exclude_unencrypted;
u8 promiscuous_mode;
@@ -180,7 +203,10 @@ struct at76_tx_buffer {
__le16 wlength;
u8 tx_rate;
u8 padding;
- u8 reserved[4];
+ u8 key_id;
+ u8 cipher_type;
+ u8 cipher_length;
+ u8 reserved;
u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
} __attribute__((packed));
@@ -228,6 +254,7 @@ struct set_mib_buffer {
u8 byte;
__le16 word;
u8 addr[ETH_ALEN];
+ u8 data[256]; /* we need more space for mib_mac_encryption */
} data;
} __attribute__((packed));
@@ -305,6 +332,20 @@ struct mib_mac_wep {
u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */
} __attribute__((packed));
+struct mib_mac_encryption {
+ u8 cipher_default_keyvalue[CIPHER_KEYS][CIPHER_KEY_LEN];
+ u8 tkip_bssid[6];
+ u8 privacy_invoked;
+ u8 cipher_default_key_id;
+ u8 cipher_default_group_key_id;
+ u8 exclude_unencrypted;
+ u8 wep_encryption_type;
+ u8 ckip_key_permutation; /* bool */
+ __le32 wep_icv_error_count;
+ __le32 wep_excluded_count;
+ u8 key_rsc[CIPHER_KEYS][8];
+} __attribute__((packed));
+
struct mib_phy {
__le32 ed_threshold;
@@ -442,6 +483,10 @@ struct at76_priv {
struct ieee80211_hw *hw;
int mac80211_registered;
+
+ struct key_config keys[4]; /* installed key types */
+ u8 default_pairwise_key;
+ u8 default_group_key;
};
#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 7/7] Add WPA support for 1.103 firmware
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
` (4 preceding siblings ...)
2008-07-04 17:44 ` [PATCH 6/7] Adds support for WEP operation with 1.103.x firmware Milan Plzik
@ 2008-07-04 17:44 ` Milan Plzik
5 siblings, 0 replies; 7+ messages in thread
From: Milan Plzik @ 2008-07-04 17:44 UTC (permalink / raw)
To: linux-wireless
Based on atmelwlandriver analysis, this patch implements support for WPA.
TKIP was tested and working, AES/CCMP needs testing on 505A or 505AMX
device.
Signed-off-by: Milan Plzik <milan.plzik@gmail.com>
---
drivers/net/wireless/at76_usb.c | 74 ++++++++++++++++++++++++++++++++++-----
1 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/at76_usb.c b/drivers/net/wireless/at76_usb.c
index 5b6fa5c..a0513d7 100644
--- a/drivers/net/wireless/at76_usb.c
+++ b/drivers/net/wireless/at76_usb.c
@@ -1002,6 +1002,40 @@ static int at76_add_mac_address(struct at76_priv *priv, void *addr)
return ret;
}
+static int at76_set_tkip_bssid(struct at76_priv *priv, const void *addr)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC_ENCRYPTION;
+ priv->mib_buf.size = ETH_ALEN;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption, tkip_bssid);
+ memcpy(priv->mib_buf.data.addr, addr, ETH_ALEN);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (MAC_ENCRYPTION, tkip_bssid) failed: %d\n",
+ wiphy_name(priv->hw->wiphy), ret);
+
+ return ret;
+}
+
+static int at76_reset_rsc(struct at76_priv *priv)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC_ENCRYPTION;
+ priv->mib_buf.size = 4 * 8;
+ priv->mib_buf.index = offsetof(struct mib_mac_encryption, key_rsc);
+ memset(priv->mib_buf.data.data, 0 , priv->mib_buf.size);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (MAC_ENCRYPTION, key_rsc) failed: %d\n",
+ wiphy_name(priv->hw->wiphy), ret);
+
+ return ret;
+}
+
static void at76_dump_mib_mac_addr(struct at76_priv *priv)
{
int i;
@@ -1798,10 +1832,10 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
tx_buffer->padding = padding;
tx_buffer->wlength = cpu_to_le16(skb->len);
tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, info)->hw_value;
- if (FIRMWARE_IS_WPA(priv->fw_version) && !(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
- tx_buffer->key_id = (control->key_idx);
- tx_buffer->cipher_type = priv->keys[control->key_idx].cipher;
- tx_buffer->cipher_length = priv->keys[control->key_idx].keylen;
+ if (FIRMWARE_IS_WPA(priv->fw_version) && !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
+ tx_buffer->key_id = (info->control.hw_key->keyidx);
+ tx_buffer->cipher_type = priv->keys[info->control.hw_key->keyidx].cipher;
+ tx_buffer->cipher_length = priv->keys[info->control.hw_key->keyidx].keylen;
tx_buffer->reserved = 0;
} else {
tx_buffer->key_id = 0;
@@ -1944,7 +1978,8 @@ static int at76_join(struct at76_priv *priv)
wiphy_name(priv->hw->wiphy), ret);
return 0;
}
-
+
+ at76_set_tkip_bssid(priv, priv->bssid);
at76_set_pm_mode(priv);
return 0;
@@ -1972,13 +2007,10 @@ static void at76_dwork_hw_scan(struct work_struct *work)
if (is_valid_ether_addr(priv->bssid)) {
ieee80211_wake_queues(priv->hw);
at76_join(priv);
- } else
- ieee80211_stop_queues(priv->hw);
+ }
ieee80211_wake_queues(priv->hw);
-// CHECKME: ieee80211_wake_queues(priv->hw);
-
exit:
return;
}
@@ -2182,7 +2214,7 @@ static int at76_set_key_newfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (at76_set_mib(priv, &priv->mib_buf) != CMD_STATUS_COMPLETE)
ret = -EOPNOTSUPP; /* -EIO would be probably better */
else {
- ret = 0;
+
priv->keys[key->keyidx].cipher = CIPHER_NONE;
priv->keys[key->keyidx].keylen = 0;
};
@@ -2193,6 +2225,7 @@ static int at76_set_key_newfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
priv->default_pairwise_key = 0xff;
/* If default pairwise key is removed, fall back to
* group key? */
+ ret = 0;
goto exit;
};
@@ -2220,6 +2253,22 @@ static int at76_set_key_newfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
goto exit;
};
break;
+ case ALG_TKIP:
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ priv->keys[key->keyidx].cipher = CIPHER_TKIP;
+ priv->keys[key->keyidx].keylen = 12;
+ break;
+
+ case ALG_CCMP:
+ if (!at76_is_505a(priv->board_type)) {
+ ret = -EOPNOTSUPP;
+ goto exit;
+ };
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ priv->keys[key->keyidx].cipher = CIPHER_CCMP;
+ priv->keys[key->keyidx].keylen = 16;
+ break;
+
default:
ret = -EOPNOTSUPP;
goto exit;
@@ -2244,6 +2293,10 @@ static int at76_set_key_newfw(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = -EOPNOTSUPP; /* -EIO would be probably better */
goto exit;
};
+
+ if ((key->alg == ALG_TKIP) || (key->alg == ALG_CCMP))
+ at76_reset_rsc(priv);
+
key->hw_key_idx = key->keyidx;
/* Set up default keys */
@@ -2742,5 +2795,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
+MODULE_AUTHOR("Milan Plzik <milan.plzik@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2008-07-04 17:44 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-04 17:43 [PATCH 1/7] Fix possible mutex double-locking Milan Plzik
2008-07-04 17:44 ` [PATCH 2/7] Don't leave queues stopped when not neccessary Milan Plzik
2008-07-04 17:44 ` [PATCH 3/7] Remove usage of data which were already skb_pull-ed Milan Plzik
2008-07-04 17:44 ` [PATCH 4/7] Some at76-based devices don't include FCS in received frames Milan Plzik
2008-07-04 17:44 ` [PATCH 5/7] Minor final fixes Milan Plzik
2008-07-04 17:44 ` [PATCH 6/7] Adds support for WEP operation with 1.103.x firmware Milan Plzik
2008-07-04 17:44 ` [PATCH 7/7] Add WPA support for 1.103 firmware Milan Plzik
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.