diff options
Diffstat (limited to 'drivers/net/wireless/at76c50x-usb.c')
-rw-r--r-- | drivers/net/wireless/at76c50x-usb.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index cb3d4b70bcbc..98328b7f8332 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com> | 7 | * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com> |
8 | * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org> | 8 | * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org> |
9 | * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi> | 9 | * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi> |
10 | * Copyright (c) 2010 Sebastian Smolorz <sesmo@gmx.net> | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public License as | 13 | * 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 | return 0; | 1686 | return 0; |
1686 | } | 1687 | } |
1687 | 1688 | ||
1689 | static void at76_work_join_bssid(struct work_struct *work) | ||
1690 | { | ||
1691 | struct at76_priv *priv = container_of(work, struct at76_priv, | ||
1692 | work_join_bssid); | ||
1693 | |||
1694 | if (priv->device_unplugged) | ||
1695 | return; | ||
1696 | |||
1697 | mutex_lock(&priv->mtx); | ||
1698 | |||
1699 | if (is_valid_ether_addr(priv->bssid)) | ||
1700 | at76_join(priv); | ||
1701 | |||
1702 | mutex_unlock(&priv->mtx); | ||
1703 | } | ||
1704 | |||
1688 | static void at76_mac80211_tx_callback(struct urb *urb) | 1705 | static void at76_mac80211_tx_callback(struct urb *urb) |
1689 | { | 1706 | { |
1690 | struct at76_priv *priv = urb->context; | 1707 | struct at76_priv *priv = urb->context; |
@@ -1722,6 +1739,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1722 | struct at76_priv *priv = hw->priv; | 1739 | struct at76_priv *priv = hw->priv; |
1723 | struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; | 1740 | struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; |
1724 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1741 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1742 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1725 | int padding, submit_len, ret; | 1743 | int padding, submit_len, ret; |
1726 | 1744 | ||
1727 | at76_dbg(DBG_MAC80211, "%s()", __func__); | 1745 | at76_dbg(DBG_MAC80211, "%s()", __func__); |
@@ -1732,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1732 | return NETDEV_TX_BUSY; | 1750 | return NETDEV_TX_BUSY; |
1733 | } | 1751 | } |
1734 | 1752 | ||
1753 | /* The following code lines are important when the device is going to | ||
1754 | * authenticate with a new bssid. The driver must send CMD_JOIN before | ||
1755 | * an authentication frame is transmitted. For this to succeed, the | ||
1756 | * correct bssid of the AP must be known. As mac80211 does not inform | ||
1757 | * drivers about the bssid prior to the authentication process the | ||
1758 | * following workaround is necessary. If the TX frame is an | ||
1759 | * authentication frame extract the bssid and send the CMD_JOIN. */ | ||
1760 | if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) { | ||
1761 | if (compare_ether_addr(priv->bssid, mgmt->bssid)) { | ||
1762 | memcpy(priv->bssid, mgmt->bssid, ETH_ALEN); | ||
1763 | ieee80211_queue_work(hw, &priv->work_join_bssid); | ||
1764 | return NETDEV_TX_BUSY; | ||
1765 | } | ||
1766 | } | ||
1767 | |||
1735 | ieee80211_stop_queues(hw); | 1768 | ieee80211_stop_queues(hw); |
1736 | 1769 | ||
1737 | at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ | 1770 | at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ |
@@ -1806,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) | |||
1806 | at76_dbg(DBG_MAC80211, "%s()", __func__); | 1839 | at76_dbg(DBG_MAC80211, "%s()", __func__); |
1807 | 1840 | ||
1808 | cancel_delayed_work(&priv->dwork_hw_scan); | 1841 | cancel_delayed_work(&priv->dwork_hw_scan); |
1842 | cancel_work_sync(&priv->work_join_bssid); | ||
1809 | cancel_work_sync(&priv->work_set_promisc); | 1843 | cancel_work_sync(&priv->work_set_promisc); |
1810 | 1844 | ||
1811 | mutex_lock(&priv->mtx); | 1845 | mutex_lock(&priv->mtx); |
@@ -2107,6 +2141,7 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev) | |||
2107 | mutex_init(&priv->mtx); | 2141 | mutex_init(&priv->mtx); |
2108 | INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc); | 2142 | INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc); |
2109 | INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx); | 2143 | INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx); |
2144 | INIT_WORK(&priv->work_join_bssid, at76_work_join_bssid); | ||
2110 | INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan); | 2145 | INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan); |
2111 | 2146 | ||
2112 | tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0); | 2147 | tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0); |
@@ -2508,5 +2543,6 @@ MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>"); | |||
2508 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); | 2543 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); |
2509 | MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>"); | 2544 | MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>"); |
2510 | MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>"); | 2545 | MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>"); |
2546 | MODULE_AUTHOR("Sebastian Smolorz <sesmo@gmx.net>"); | ||
2511 | MODULE_DESCRIPTION(DRIVER_DESC); | 2547 | MODULE_DESCRIPTION(DRIVER_DESC); |
2512 | MODULE_LICENSE("GPL"); | 2548 | MODULE_LICENSE("GPL"); |