Commit a185045c authored by Sebastian Smolorz's avatar Sebastian Smolorz Committed by John W. Linville

at76c50x-usb: Extract bssid from authentication frame

The driver at76c50x-usb is unable to authenticate with an AP since
kernel 2.6.31 for the following reason: The join command of the firmware
needs to be sent with the right bssid before any transmission can start.
Before kernel 2.6.31 mac80211 informed its drivers about the changing
bssid early enough for at76c50x-usb but during the development of 2.6.31
mac80211's behaviour changed. Now a new bssid is set after the
association.

This patch changes the tx routine of the driver at76c50x-usb in such a
way that a new bssid is extracted from an authentication frame and the
join command with that bssid is processed.
Signed-off-by: default avatarSebastian Smolorz <sesmo@gmx.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 41b4b289
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com> * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
* Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org> * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
* Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi> * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
* Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -1685,6 +1686,22 @@ static int at76_join(struct at76_priv *priv) ...@@ -1685,6 +1686,22 @@ static int at76_join(struct at76_priv *priv)
return 0; return 0;
} }
static void at76_work_join_bssid(struct work_struct *work)
{
struct at76_priv *priv = container_of(work, struct at76_priv,
work_join_bssid);
if (priv->device_unplugged)
return;
mutex_lock(&priv->mtx);
if (is_valid_ether_addr(priv->bssid))
at76_join(priv);
mutex_unlock(&priv->mtx);
}
static void at76_mac80211_tx_callback(struct urb *urb) static void at76_mac80211_tx_callback(struct urb *urb)
{ {
struct at76_priv *priv = urb->context; struct at76_priv *priv = urb->context;
...@@ -1722,6 +1739,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1722,6 +1739,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct at76_priv *priv = hw->priv; struct at76_priv *priv = hw->priv;
struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
int padding, submit_len, ret; int padding, submit_len, ret;
at76_dbg(DBG_MAC80211, "%s()", __func__); at76_dbg(DBG_MAC80211, "%s()", __func__);
...@@ -1732,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1732,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
/* The following code lines are important when the device is going to
* authenticate with a new bssid. The driver must send CMD_JOIN before
* an authentication frame is transmitted. For this to succeed, the
* correct bssid of the AP must be known. As mac80211 does not inform
* drivers about the bssid prior to the authentication process the
* following workaround is necessary. If the TX frame is an
* authentication frame extract the bssid and send the CMD_JOIN. */
if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
if (compare_ether_addr(priv->bssid, mgmt->bssid)) {
memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
ieee80211_queue_work(hw, &priv->work_join_bssid);
return NETDEV_TX_BUSY;
}
}
ieee80211_stop_queues(hw); ieee80211_stop_queues(hw);
at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
...@@ -1806,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) ...@@ -1806,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
at76_dbg(DBG_MAC80211, "%s()", __func__); at76_dbg(DBG_MAC80211, "%s()", __func__);
cancel_delayed_work(&priv->dwork_hw_scan); cancel_delayed_work(&priv->dwork_hw_scan);
cancel_work_sync(&priv->work_join_bssid);
cancel_work_sync(&priv->work_set_promisc); cancel_work_sync(&priv->work_set_promisc);
mutex_lock(&priv->mtx); mutex_lock(&priv->mtx);
...@@ -2107,6 +2141,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev) ...@@ -2107,6 +2141,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
mutex_init(&priv->mtx); mutex_init(&priv->mtx);
INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc); INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx); INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
INIT_WORK(&priv->work_join_bssid, at76_work_join_bssid);
INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan); INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0); tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
...@@ -2508,5 +2543,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>"); ...@@ -2508,5 +2543,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>"); MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>"); MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
MODULE_AUTHOR("Sebastian Smolorz <sesmo@gmx.net>");
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -387,6 +387,7 @@ struct at76_priv { ...@@ -387,6 +387,7 @@ struct at76_priv {
/* work queues */ /* work queues */
struct work_struct work_set_promisc; struct work_struct work_set_promisc;
struct work_struct work_submit_rx; struct work_struct work_submit_rx;
struct work_struct work_join_bssid;
struct delayed_work dwork_hw_scan; struct delayed_work dwork_hw_scan;
struct tasklet_struct rx_tasklet; struct tasklet_struct rx_tasklet;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment