Skip to content

Commit

Permalink
at76c50x-usb: Extract bssid from authentication frame
Browse files Browse the repository at this point in the history
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: Sebastian Smolorz <sesmo@gmx.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sebastian Smolorz authored and John W. Linville committed Jun 24, 2010
1 parent 41b4b28 commit a185045
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
36 changes: 36 additions & 0 deletions drivers/net/wireless/at76c50x-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
* Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
* 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
* modify it under the terms of the GNU General Public License as
Expand Down Expand Up @@ -1685,6 +1686,22 @@ static int at76_join(struct at76_priv *priv)
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)
{
struct at76_priv *priv = urb->context;
Expand Down Expand Up @@ -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_tx_buffer *tx_buffer = priv->bulk_out_buffer;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
int padding, submit_len, ret;

at76_dbg(DBG_MAC80211, "%s()", __func__);
Expand All @@ -1732,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
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);

at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
Expand Down Expand Up @@ -1806,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
at76_dbg(DBG_MAC80211, "%s()", __func__);

cancel_delayed_work(&priv->dwork_hw_scan);
cancel_work_sync(&priv->work_join_bssid);
cancel_work_sync(&priv->work_set_promisc);

mutex_lock(&priv->mtx);
Expand Down Expand Up @@ -2107,6 +2141,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
mutex_init(&priv->mtx);
INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
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);

tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
Expand Down Expand Up @@ -2508,5 +2543,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("Sebastian Smolorz <sesmo@gmx.net>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
1 change: 1 addition & 0 deletions drivers/net/wireless/at76c50x-usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ struct at76_priv {
/* work queues */
struct work_struct work_set_promisc;
struct work_struct work_submit_rx;
struct work_struct work_join_bssid;
struct delayed_work dwork_hw_scan;

struct tasklet_struct rx_tasklet;
Expand Down

0 comments on commit a185045

Please sign in to comment.