diff options
111 files changed, 3633 insertions, 7660 deletions
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 429b281d40d1..cd8caeab86ea 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 |
@@ -1649,6 +1650,58 @@ exit: | |||
1649 | return NULL; | 1650 | return NULL; |
1650 | } | 1651 | } |
1651 | 1652 | ||
1653 | static int at76_join(struct at76_priv *priv) | ||
1654 | { | ||
1655 | struct at76_req_join join; | ||
1656 | int ret; | ||
1657 | |||
1658 | memset(&join, 0, sizeof(struct at76_req_join)); | ||
1659 | memcpy(join.essid, priv->essid, priv->essid_size); | ||
1660 | join.essid_size = priv->essid_size; | ||
1661 | memcpy(join.bssid, priv->bssid, ETH_ALEN); | ||
1662 | join.bss_type = INFRASTRUCTURE_MODE; | ||
1663 | join.channel = priv->channel; | ||
1664 | join.timeout = cpu_to_le16(2000); | ||
1665 | |||
1666 | at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__); | ||
1667 | ret = at76_set_card_command(priv->udev, CMD_JOIN, &join, | ||
1668 | sizeof(struct at76_req_join)); | ||
1669 | |||
1670 | if (ret < 0) { | ||
1671 | printk(KERN_ERR "%s: at76_set_card_command failed: %d\n", | ||
1672 | wiphy_name(priv->hw->wiphy), ret); | ||
1673 | return 0; | ||
1674 | } | ||
1675 | |||
1676 | ret = at76_wait_completion(priv, CMD_JOIN); | ||
1677 | at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret); | ||
1678 | if (ret != CMD_STATUS_COMPLETE) { | ||
1679 | printk(KERN_ERR "%s: at76_wait_completion failed: %d\n", | ||
1680 | wiphy_name(priv->hw->wiphy), ret); | ||
1681 | return 0; | ||
1682 | } | ||
1683 | |||
1684 | at76_set_pm_mode(priv); | ||
1685 | |||
1686 | return 0; | ||
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 | |||
1652 | static void at76_mac80211_tx_callback(struct urb *urb) | 1705 | static void at76_mac80211_tx_callback(struct urb *urb) |
1653 | { | 1706 | { |
1654 | struct at76_priv *priv = urb->context; | 1707 | struct at76_priv *priv = urb->context; |
@@ -1686,6 +1739,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1686 | struct at76_priv *priv = hw->priv; | 1739 | struct at76_priv *priv = hw->priv; |
1687 | struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; | 1740 | struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; |
1688 | 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; | ||
1689 | int padding, submit_len, ret; | 1743 | int padding, submit_len, ret; |
1690 | 1744 | ||
1691 | at76_dbg(DBG_MAC80211, "%s()", __func__); | 1745 | at76_dbg(DBG_MAC80211, "%s()", __func__); |
@@ -1696,6 +1750,21 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1696 | return NETDEV_TX_BUSY; | 1750 | return NETDEV_TX_BUSY; |
1697 | } | 1751 | } |
1698 | 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 | |||
1699 | ieee80211_stop_queues(hw); | 1768 | ieee80211_stop_queues(hw); |
1700 | 1769 | ||
1701 | at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ | 1770 | at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ |
@@ -1770,6 +1839,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) | |||
1770 | at76_dbg(DBG_MAC80211, "%s()", __func__); | 1839 | at76_dbg(DBG_MAC80211, "%s()", __func__); |
1771 | 1840 | ||
1772 | cancel_delayed_work(&priv->dwork_hw_scan); | 1841 | cancel_delayed_work(&priv->dwork_hw_scan); |
1842 | cancel_work_sync(&priv->work_join_bssid); | ||
1773 | cancel_work_sync(&priv->work_set_promisc); | 1843 | cancel_work_sync(&priv->work_set_promisc); |
1774 | 1844 | ||
1775 | mutex_lock(&priv->mtx); | 1845 | mutex_lock(&priv->mtx); |
@@ -1818,42 +1888,6 @@ static void at76_remove_interface(struct ieee80211_hw *hw, | |||
1818 | at76_dbg(DBG_MAC80211, "%s()", __func__); | 1888 | at76_dbg(DBG_MAC80211, "%s()", __func__); |
1819 | } | 1889 | } |
1820 | 1890 | ||
1821 | static int at76_join(struct at76_priv *priv) | ||
1822 | { | ||
1823 | struct at76_req_join join; | ||
1824 | int ret; | ||
1825 | |||
1826 | memset(&join, 0, sizeof(struct at76_req_join)); | ||
1827 | memcpy(join.essid, priv->essid, priv->essid_size); | ||
1828 | join.essid_size = priv->essid_size; | ||
1829 | memcpy(join.bssid, priv->bssid, ETH_ALEN); | ||
1830 | join.bss_type = INFRASTRUCTURE_MODE; | ||
1831 | join.channel = priv->channel; | ||
1832 | join.timeout = cpu_to_le16(2000); | ||
1833 | |||
1834 | at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__); | ||
1835 | ret = at76_set_card_command(priv->udev, CMD_JOIN, &join, | ||
1836 | sizeof(struct at76_req_join)); | ||
1837 | |||
1838 | if (ret < 0) { | ||
1839 | printk(KERN_ERR "%s: at76_set_card_command failed: %d\n", | ||
1840 | wiphy_name(priv->hw->wiphy), ret); | ||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | ret = at76_wait_completion(priv, CMD_JOIN); | ||
1845 | at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret); | ||
1846 | if (ret != CMD_STATUS_COMPLETE) { | ||
1847 | printk(KERN_ERR "%s: at76_wait_completion failed: %d\n", | ||
1848 | wiphy_name(priv->hw->wiphy), ret); | ||
1849 | return 0; | ||
1850 | } | ||
1851 | |||
1852 | at76_set_pm_mode(priv); | ||
1853 | |||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1857 | static void at76_dwork_hw_scan(struct work_struct *work) | 1891 | static void at76_dwork_hw_scan(struct work_struct *work) |
1858 | { | 1892 | { |
1859 | struct at76_priv *priv = container_of(work, struct at76_priv, | 1893 | struct at76_priv *priv = container_of(work, struct at76_priv, |
@@ -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"); |
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h index 972ea0fc1a0b..4a37447dfc01 100644 --- a/drivers/net/wireless/at76c50x-usb.h +++ b/drivers/net/wireless/at76c50x-usb.h | |||
@@ -387,6 +387,7 @@ struct at76_priv { | |||
387 | /* work queues */ | 387 | /* work queues */ |
388 | struct work_struct work_set_promisc; | 388 | struct work_struct work_set_promisc; |
389 | struct work_struct work_submit_rx; | 389 | struct work_struct work_submit_rx; |
390 | struct work_struct work_join_bssid; | ||
390 | struct delayed_work dwork_hw_scan; | 391 | struct delayed_work dwork_hw_scan; |
391 | 392 | ||
392 | struct tasklet_struct rx_tasklet; | 393 | struct tasklet_struct rx_tasklet; |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 73c4fcd142bb..6284c389ba18 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -1768,7 +1768,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) | |||
1768 | 1768 | ||
1769 | if (enable) { | 1769 | if (enable) { |
1770 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, | 1770 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, |
1771 | AR5K_PHY_RESTART_DIV_GC, 1); | 1771 | AR5K_PHY_RESTART_DIV_GC, 4); |
1772 | 1772 | ||
1773 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, | 1773 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, |
1774 | AR5K_PHY_FAST_ANT_DIV_EN); | 1774 | AR5K_PHY_FAST_ANT_DIV_EN); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 82c3ab756cd0..064168909108 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | |||
@@ -295,6 +295,26 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, | |||
295 | /* Several PCIe massages to ensure proper behaviour */ | 295 | /* Several PCIe massages to ensure proper behaviour */ |
296 | if (ah->config.pcie_waen) | 296 | if (ah->config.pcie_waen) |
297 | REG_WRITE(ah, AR_WA, ah->config.pcie_waen); | 297 | REG_WRITE(ah, AR_WA, ah->config.pcie_waen); |
298 | else | ||
299 | REG_WRITE(ah, AR_WA, ah->WARegVal); | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Configire PCIE after Ini init. SERDES values now come from ini file | ||
304 | * This enables PCIe low power mode. | ||
305 | */ | ||
306 | if (ah->config.pcieSerDesWrite) { | ||
307 | unsigned int i; | ||
308 | struct ar5416IniArray *array; | ||
309 | |||
310 | array = power_off ? &ah->iniPcieSerdes : | ||
311 | &ah->iniPcieSerdesLowPower; | ||
312 | |||
313 | for (i = 0; i < array->ia_rows; i++) { | ||
314 | REG_WRITE(ah, | ||
315 | INI_RA(array, i, 0), | ||
316 | INI_RA(array, i, 1)); | ||
317 | } | ||
298 | } | 318 | } |
299 | } | 319 | } |
300 | 320 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8d163ae4255e..72d5e52abb8f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -226,6 +226,7 @@ struct ath_buf_state { | |||
226 | int bfs_retries; | 226 | int bfs_retries; |
227 | u8 bf_type; | 227 | u8 bf_type; |
228 | u8 bfs_paprd; | 228 | u8 bfs_paprd; |
229 | unsigned long bfs_paprd_timestamp; | ||
229 | u32 bfs_keyix; | 230 | u32 bfs_keyix; |
230 | enum ath9k_key_type bfs_keytype; | 231 | enum ath9k_key_type bfs_keytype; |
231 | }; | 232 | }; |
@@ -425,6 +426,8 @@ int ath_beaconq_config(struct ath_softc *sc); | |||
425 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ | 426 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ |
426 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ | 427 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ |
427 | 428 | ||
429 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | ||
430 | |||
428 | void ath_paprd_calibrate(struct work_struct *work); | 431 | void ath_paprd_calibrate(struct work_struct *work); |
429 | void ath_ani_calibrate(unsigned long data); | 432 | void ath_ani_calibrate(unsigned long data); |
430 | 433 | ||
@@ -516,6 +519,7 @@ void ath_deinit_leds(struct ath_softc *sc); | |||
516 | #define SC_OP_TSF_RESET BIT(11) | 519 | #define SC_OP_TSF_RESET BIT(11) |
517 | #define SC_OP_BT_PRIORITY_DETECTED BIT(12) | 520 | #define SC_OP_BT_PRIORITY_DETECTED BIT(12) |
518 | #define SC_OP_BT_SCAN BIT(13) | 521 | #define SC_OP_BT_SCAN BIT(13) |
522 | #define SC_OP_ANI_RUN BIT(14) | ||
519 | 523 | ||
520 | /* Powersave flags */ | 524 | /* Powersave flags */ |
521 | #define PS_WAIT_FOR_BEACON BIT(0) | 525 | #define PS_WAIT_FOR_BEACON BIT(0) |
@@ -559,7 +563,6 @@ struct ath_softc { | |||
559 | struct mutex mutex; | 563 | struct mutex mutex; |
560 | struct work_struct paprd_work; | 564 | struct work_struct paprd_work; |
561 | struct completion paprd_complete; | 565 | struct completion paprd_complete; |
562 | int paprd_txok; | ||
563 | 566 | ||
564 | u32 intrstatus; | 567 | u32 intrstatus; |
565 | u32 sc_flags; /* SC_OP_* */ | 568 | u32 sc_flags; /* SC_OP_* */ |
@@ -628,6 +631,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) | |||
628 | 631 | ||
629 | extern struct ieee80211_ops ath9k_ops; | 632 | extern struct ieee80211_ops ath9k_ops; |
630 | extern int modparam_nohwcrypt; | 633 | extern int modparam_nohwcrypt; |
634 | extern int led_blink; | ||
631 | 635 | ||
632 | irqreturn_t ath_isr(int irq, void *dev); | 636 | irqreturn_t ath_isr(int irq, void *dev); |
633 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | 637 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 0ee75e79fe35..3a8ee999da5d 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -76,7 +76,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev, | |||
76 | case LED_FULL: | 76 | case LED_FULL: |
77 | if (led->led_type == ATH_LED_ASSOC) { | 77 | if (led->led_type == ATH_LED_ASSOC) { |
78 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | 78 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; |
79 | ieee80211_queue_delayed_work(sc->hw, | 79 | if (led_blink) |
80 | ieee80211_queue_delayed_work(sc->hw, | ||
80 | &sc->ath_led_blink_work, 0); | 81 | &sc->ath_led_blink_work, 0); |
81 | } else if (led->led_type == ATH_LED_RADIO) { | 82 | } else if (led->led_type == ATH_LED_RADIO) { |
82 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); | 83 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); |
@@ -143,7 +144,8 @@ void ath_init_leds(struct ath_softc *sc) | |||
143 | /* LED off, active low */ | 144 | /* LED off, active low */ |
144 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 145 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
145 | 146 | ||
146 | INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); | 147 | if (led_blink) |
148 | INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); | ||
147 | 149 | ||
148 | trigger = ieee80211_get_radio_led_name(sc->hw); | 150 | trigger = ieee80211_get_radio_led_name(sc->hw); |
149 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | 151 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), |
@@ -180,7 +182,8 @@ void ath_init_leds(struct ath_softc *sc) | |||
180 | return; | 182 | return; |
181 | 183 | ||
182 | fail: | 184 | fail: |
183 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | 185 | if (led_blink) |
186 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | ||
184 | ath_deinit_leds(sc); | 187 | ath_deinit_leds(sc); |
185 | } | 188 | } |
186 | 189 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 5f3ea7091ae0..ad9134bddd1e 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -16,10 +16,27 @@ | |||
16 | 16 | ||
17 | #include "htc.h" | 17 | #include "htc.h" |
18 | 18 | ||
19 | /* identify firmware images */ | ||
20 | #define FIRMWARE_AR7010 "ar7010.fw" | ||
21 | #define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" | ||
22 | #define FIRMWARE_AR9271 "ar9271.fw" | ||
23 | |||
24 | MODULE_FIRMWARE(FIRMWARE_AR7010); | ||
25 | MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); | ||
26 | MODULE_FIRMWARE(FIRMWARE_AR9271); | ||
27 | |||
19 | static struct usb_device_id ath9k_hif_usb_ids[] = { | 28 | static struct usb_device_id ath9k_hif_usb_ids[] = { |
20 | { USB_DEVICE(0x0cf3, 0x9271) }, | 29 | { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */ |
21 | { USB_DEVICE(0x0cf3, 0x1006) }, | 30 | { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */ |
22 | { USB_DEVICE(0x0cf3, 0x7010) }, | 31 | { USB_DEVICE(0x0cf3, 0x7010) }, /* Atheros */ |
32 | { USB_DEVICE(0x0cf3, 0x7015) }, /* Atheros */ | ||
33 | { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */ | ||
34 | { USB_DEVICE(0x0846, 0x9018) }, /* Netgear WNDA3200 */ | ||
35 | { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */ | ||
36 | { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ | ||
37 | { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ | ||
38 | { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ | ||
39 | { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ | ||
23 | { }, | 40 | { }, |
24 | }; | 41 | }; |
25 | 42 | ||
@@ -879,17 +896,15 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, | |||
879 | /* Find out which firmware to load */ | 896 | /* Find out which firmware to load */ |
880 | 897 | ||
881 | switch(hif_dev->device_id) { | 898 | switch(hif_dev->device_id) { |
882 | case 0x9271: | ||
883 | case 0x1006: | ||
884 | hif_dev->fw_name = "ar9271.fw"; | ||
885 | break; | ||
886 | case 0x7010: | 899 | case 0x7010: |
900 | case 0x9018: | ||
887 | if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) | 901 | if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) |
888 | hif_dev->fw_name = "ar7010_1_1.fw"; | 902 | hif_dev->fw_name = FIRMWARE_AR7010_1_1; |
889 | else | 903 | else |
890 | hif_dev->fw_name = "ar7010.fw"; | 904 | hif_dev->fw_name = FIRMWARE_AR7010; |
891 | break; | 905 | break; |
892 | default: | 906 | default: |
907 | hif_dev->fw_name = FIRMWARE_AR9271; | ||
893 | break; | 908 | break; |
894 | } | 909 | } |
895 | 910 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 58f52a1dc7ea..3756400e6bf9 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -287,6 +287,7 @@ struct ath9k_debug { | |||
287 | #define ATH_LED_PIN_DEF 1 | 287 | #define ATH_LED_PIN_DEF 1 |
288 | #define ATH_LED_PIN_9287 8 | 288 | #define ATH_LED_PIN_9287 8 |
289 | #define ATH_LED_PIN_9271 15 | 289 | #define ATH_LED_PIN_9271 15 |
290 | #define ATH_LED_PIN_7010 12 | ||
290 | #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ | 291 | #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ |
291 | #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ | 292 | #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ |
292 | 293 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index a63ae88abf3e..148b43317fdb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -244,17 +244,12 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) | |||
244 | */ | 244 | */ |
245 | 245 | ||
246 | switch(devid) { | 246 | switch(devid) { |
247 | case 0x9271: | ||
248 | case 0x1006: | ||
249 | priv->htc->credits = 33; | ||
250 | break; | ||
251 | case 0x7010: | 247 | case 0x7010: |
248 | case 0x9018: | ||
252 | priv->htc->credits = 45; | 249 | priv->htc->credits = 45; |
253 | break; | 250 | break; |
254 | default: | 251 | default: |
255 | dev_err(priv->dev, "ath9k_htc: Unsupported device id: 0x%x\n", | 252 | priv->htc->credits = 33; |
256 | devid); | ||
257 | goto err; | ||
258 | } | 253 | } |
259 | 254 | ||
260 | ret = htc_init(priv->htc); | 255 | ret = htc_init(priv->htc); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 05445d8a9818..e38ca66db849 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -931,6 +931,8 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) | |||
931 | priv->ah->led_pin = ATH_LED_PIN_9287; | 931 | priv->ah->led_pin = ATH_LED_PIN_9287; |
932 | else if (AR_SREV_9271(priv->ah)) | 932 | else if (AR_SREV_9271(priv->ah)) |
933 | priv->ah->led_pin = ATH_LED_PIN_9271; | 933 | priv->ah->led_pin = ATH_LED_PIN_9271; |
934 | else if (AR_DEVID_7010(priv->ah)) | ||
935 | priv->ah->led_pin = ATH_LED_PIN_7010; | ||
934 | else | 936 | else |
935 | priv->ah->led_pin = ATH_LED_PIN_DEF; | 937 | priv->ah->led_pin = ATH_LED_PIN_DEF; |
936 | 938 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 62597f4ca319..3ed5c9ec7bc1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -388,6 +388,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) | |||
388 | ah->config.ht_enable = 0; | 388 | ah->config.ht_enable = 0; |
389 | 389 | ||
390 | ah->config.rx_intr_mitigation = true; | 390 | ah->config.rx_intr_mitigation = true; |
391 | ah->config.pcieSerDesWrite = true; | ||
391 | 392 | ||
392 | /* | 393 | /* |
393 | * We need this for PCI devices only (Cardbus, PCI, miniPCI) | 394 | * We need this for PCI devices only (Cardbus, PCI, miniPCI) |
@@ -571,24 +572,13 @@ static int __ath9k_hw_init(struct ath_hw *ah) | |||
571 | ath9k_hw_init_mode_regs(ah); | 572 | ath9k_hw_init_mode_regs(ah); |
572 | 573 | ||
573 | /* | 574 | /* |
574 | * Configire PCIE after Ini init. SERDES values now come from ini file | 575 | * Read back AR_WA into a permanent copy and set bits 14 and 17. |
575 | * This enables PCIe low power mode. | 576 | * We need to do this to avoid RMW of this register. We cannot |
577 | * read the reg when chip is asleep. | ||
576 | */ | 578 | */ |
577 | if (AR_SREV_9300_20_OR_LATER(ah)) { | 579 | ah->WARegVal = REG_READ(ah, AR_WA); |
578 | u32 regval; | 580 | ah->WARegVal |= (AR_WA_D3_L1_DISABLE | |
579 | unsigned int i; | 581 | AR_WA_ASPM_TIMER_BASED_DISABLE); |
580 | |||
581 | /* Set Bits 16 and 17 in the AR_WA register. */ | ||
582 | regval = REG_READ(ah, AR_WA); | ||
583 | regval |= 0x00030000; | ||
584 | REG_WRITE(ah, AR_WA, regval); | ||
585 | |||
586 | for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) { | ||
587 | REG_WRITE(ah, | ||
588 | INI_RA(&ah->iniPcieSerdesLowPower, i, 0), | ||
589 | INI_RA(&ah->iniPcieSerdesLowPower, i, 1)); | ||
590 | } | ||
591 | } | ||
592 | 582 | ||
593 | if (ah->is_pciexpress) | 583 | if (ah->is_pciexpress) |
594 | ath9k_hw_configpcipowersave(ah, 0, 0); | 584 | ath9k_hw_configpcipowersave(ah, 0, 0); |
@@ -1009,6 +999,11 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) | |||
1009 | 999 | ||
1010 | ENABLE_REGWRITE_BUFFER(ah); | 1000 | ENABLE_REGWRITE_BUFFER(ah); |
1011 | 1001 | ||
1002 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
1003 | REG_WRITE(ah, AR_WA, ah->WARegVal); | ||
1004 | udelay(10); | ||
1005 | } | ||
1006 | |||
1012 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | | 1007 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | |
1013 | AR_RTC_FORCE_WAKE_ON_INT); | 1008 | AR_RTC_FORCE_WAKE_ON_INT); |
1014 | 1009 | ||
@@ -1063,6 +1058,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) | |||
1063 | { | 1058 | { |
1064 | ENABLE_REGWRITE_BUFFER(ah); | 1059 | ENABLE_REGWRITE_BUFFER(ah); |
1065 | 1060 | ||
1061 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
1062 | REG_WRITE(ah, AR_WA, ah->WARegVal); | ||
1063 | udelay(10); | ||
1064 | } | ||
1065 | |||
1066 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | | 1066 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | |
1067 | AR_RTC_FORCE_WAKE_ON_INT); | 1067 | AR_RTC_FORCE_WAKE_ON_INT); |
1068 | 1068 | ||
@@ -1070,6 +1070,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) | |||
1070 | REG_WRITE(ah, AR_RC, AR_RC_AHB); | 1070 | REG_WRITE(ah, AR_RC, AR_RC_AHB); |
1071 | 1071 | ||
1072 | REG_WRITE(ah, AR_RTC_RESET, 0); | 1072 | REG_WRITE(ah, AR_RTC_RESET, 0); |
1073 | udelay(2); | ||
1073 | 1074 | ||
1074 | REGWRITE_BUFFER_FLUSH(ah); | 1075 | REGWRITE_BUFFER_FLUSH(ah); |
1075 | DISABLE_REGWRITE_BUFFER(ah); | 1076 | DISABLE_REGWRITE_BUFFER(ah); |
@@ -1099,6 +1100,11 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) | |||
1099 | 1100 | ||
1100 | static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) | 1101 | static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) |
1101 | { | 1102 | { |
1103 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
1104 | REG_WRITE(ah, AR_WA, ah->WARegVal); | ||
1105 | udelay(10); | ||
1106 | } | ||
1107 | |||
1102 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, | 1108 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, |
1103 | AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); | 1109 | AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); |
1104 | 1110 | ||
@@ -1262,7 +1268,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1262 | macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; | 1268 | macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; |
1263 | 1269 | ||
1264 | /* For chips on which RTC reset is done, save TSF before it gets cleared */ | 1270 | /* For chips on which RTC reset is done, save TSF before it gets cleared */ |
1265 | if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | 1271 | if (AR_SREV_9100(ah) || |
1272 | (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))) | ||
1266 | tsf = ath9k_hw_gettsf64(ah); | 1273 | tsf = ath9k_hw_gettsf64(ah); |
1267 | 1274 | ||
1268 | saveLedState = REG_READ(ah, AR_CFG_LED) & | 1275 | saveLedState = REG_READ(ah, AR_CFG_LED) & |
@@ -1294,7 +1301,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1294 | } | 1301 | } |
1295 | 1302 | ||
1296 | /* Restore TSF */ | 1303 | /* Restore TSF */ |
1297 | if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | 1304 | if (tsf) |
1298 | ath9k_hw_settsf64(ah, tsf); | 1305 | ath9k_hw_settsf64(ah, tsf); |
1299 | 1306 | ||
1300 | if (AR_SREV_9280_10_OR_LATER(ah)) | 1307 | if (AR_SREV_9280_10_OR_LATER(ah)) |
@@ -1307,6 +1314,17 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1307 | if (r) | 1314 | if (r) |
1308 | return r; | 1315 | return r; |
1309 | 1316 | ||
1317 | /* | ||
1318 | * Some AR91xx SoC devices frequently fail to accept TSF writes | ||
1319 | * right after the chip reset. When that happens, write a new | ||
1320 | * value after the initvals have been applied, with an offset | ||
1321 | * based on measured time difference | ||
1322 | */ | ||
1323 | if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) { | ||
1324 | tsf += 1500; | ||
1325 | ath9k_hw_settsf64(ah, tsf); | ||
1326 | } | ||
1327 | |||
1310 | /* Setup MFP options for CCMP */ | 1328 | /* Setup MFP options for CCMP */ |
1311 | if (AR_SREV_9280_20_OR_LATER(ah)) { | 1329 | if (AR_SREV_9280_20_OR_LATER(ah)) { |
1312 | /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt | 1330 | /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt |
@@ -1492,7 +1510,7 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) | |||
1492 | } | 1510 | } |
1493 | EXPORT_SYMBOL(ath9k_hw_keyreset); | 1511 | EXPORT_SYMBOL(ath9k_hw_keyreset); |
1494 | 1512 | ||
1495 | bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) | 1513 | static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) |
1496 | { | 1514 | { |
1497 | u32 macHi, macLo; | 1515 | u32 macHi, macLo; |
1498 | u32 unicast_flag = AR_KEYTABLE_VALID; | 1516 | u32 unicast_flag = AR_KEYTABLE_VALID; |
@@ -1530,7 +1548,6 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) | |||
1530 | 1548 | ||
1531 | return true; | 1549 | return true; |
1532 | } | 1550 | } |
1533 | EXPORT_SYMBOL(ath9k_hw_keysetmac); | ||
1534 | 1551 | ||
1535 | bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | 1552 | bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, |
1536 | const struct ath9k_keyval *k, | 1553 | const struct ath9k_keyval *k, |
@@ -1731,17 +1748,6 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | |||
1731 | } | 1748 | } |
1732 | EXPORT_SYMBOL(ath9k_hw_set_keycache_entry); | 1749 | EXPORT_SYMBOL(ath9k_hw_set_keycache_entry); |
1733 | 1750 | ||
1734 | bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) | ||
1735 | { | ||
1736 | if (entry < ah->caps.keycache_size) { | ||
1737 | u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); | ||
1738 | if (val & AR_KEYTABLE_VALID) | ||
1739 | return true; | ||
1740 | } | ||
1741 | return false; | ||
1742 | } | ||
1743 | EXPORT_SYMBOL(ath9k_hw_keyisvalid); | ||
1744 | |||
1745 | /******************************/ | 1751 | /******************************/ |
1746 | /* Power Management (Chipset) */ | 1752 | /* Power Management (Chipset) */ |
1747 | /******************************/ | 1753 | /******************************/ |
@@ -1768,6 +1774,11 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) | |||
1768 | REG_CLR_BIT(ah, (AR_RTC_RESET), | 1774 | REG_CLR_BIT(ah, (AR_RTC_RESET), |
1769 | AR_RTC_RESET_EN); | 1775 | AR_RTC_RESET_EN); |
1770 | } | 1776 | } |
1777 | |||
1778 | /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ | ||
1779 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
1780 | REG_WRITE(ah, AR_WA, | ||
1781 | ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | ||
1771 | } | 1782 | } |
1772 | 1783 | ||
1773 | /* | 1784 | /* |
@@ -1794,6 +1805,10 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) | |||
1794 | AR_RTC_FORCE_WAKE_EN); | 1805 | AR_RTC_FORCE_WAKE_EN); |
1795 | } | 1806 | } |
1796 | } | 1807 | } |
1808 | |||
1809 | /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */ | ||
1810 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
1811 | REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); | ||
1797 | } | 1812 | } |
1798 | 1813 | ||
1799 | static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) | 1814 | static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) |
@@ -1801,6 +1816,12 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) | |||
1801 | u32 val; | 1816 | u32 val; |
1802 | int i; | 1817 | int i; |
1803 | 1818 | ||
1819 | /* Set Bits 14 and 17 of AR_WA before powering on the chip. */ | ||
1820 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
1821 | REG_WRITE(ah, AR_WA, ah->WARegVal); | ||
1822 | udelay(10); | ||
1823 | } | ||
1824 | |||
1804 | if (setChip) { | 1825 | if (setChip) { |
1805 | if ((REG_READ(ah, AR_RTC_STATUS) & | 1826 | if ((REG_READ(ah, AR_RTC_STATUS) & |
1806 | AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { | 1827 | AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { |
@@ -2155,6 +2176,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2155 | 2176 | ||
2156 | if (AR_SREV_9271(ah)) | 2177 | if (AR_SREV_9271(ah)) |
2157 | pCap->num_gpio_pins = AR9271_NUM_GPIO; | 2178 | pCap->num_gpio_pins = AR9271_NUM_GPIO; |
2179 | else if (AR_DEVID_7010(ah)) | ||
2180 | pCap->num_gpio_pins = AR7010_NUM_GPIO; | ||
2158 | else if (AR_SREV_9285_10_OR_LATER(ah)) | 2181 | else if (AR_SREV_9285_10_OR_LATER(ah)) |
2159 | pCap->num_gpio_pins = AR9285_NUM_GPIO; | 2182 | pCap->num_gpio_pins = AR9285_NUM_GPIO; |
2160 | else if (AR_SREV_9280_10_OR_LATER(ah)) | 2183 | else if (AR_SREV_9280_10_OR_LATER(ah)) |
@@ -2295,8 +2318,15 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) | |||
2295 | 2318 | ||
2296 | BUG_ON(gpio >= ah->caps.num_gpio_pins); | 2319 | BUG_ON(gpio >= ah->caps.num_gpio_pins); |
2297 | 2320 | ||
2298 | gpio_shift = gpio << 1; | 2321 | if (AR_DEVID_7010(ah)) { |
2322 | gpio_shift = gpio; | ||
2323 | REG_RMW(ah, AR7010_GPIO_OE, | ||
2324 | (AR7010_GPIO_OE_AS_INPUT << gpio_shift), | ||
2325 | (AR7010_GPIO_OE_MASK << gpio_shift)); | ||
2326 | return; | ||
2327 | } | ||
2299 | 2328 | ||
2329 | gpio_shift = gpio << 1; | ||
2300 | REG_RMW(ah, | 2330 | REG_RMW(ah, |
2301 | AR_GPIO_OE_OUT, | 2331 | AR_GPIO_OE_OUT, |
2302 | (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), | 2332 | (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), |
@@ -2312,7 +2342,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) | |||
2312 | if (gpio >= ah->caps.num_gpio_pins) | 2342 | if (gpio >= ah->caps.num_gpio_pins) |
2313 | return 0xffffffff; | 2343 | return 0xffffffff; |
2314 | 2344 | ||
2315 | if (AR_SREV_9300_20_OR_LATER(ah)) | 2345 | if (AR_DEVID_7010(ah)) { |
2346 | u32 val; | ||
2347 | val = REG_READ(ah, AR7010_GPIO_IN); | ||
2348 | return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0; | ||
2349 | } else if (AR_SREV_9300_20_OR_LATER(ah)) | ||
2316 | return MS_REG_READ(AR9300, gpio) != 0; | 2350 | return MS_REG_READ(AR9300, gpio) != 0; |
2317 | else if (AR_SREV_9271(ah)) | 2351 | else if (AR_SREV_9271(ah)) |
2318 | return MS_REG_READ(AR9271, gpio) != 0; | 2352 | return MS_REG_READ(AR9271, gpio) != 0; |
@@ -2332,10 +2366,16 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, | |||
2332 | { | 2366 | { |
2333 | u32 gpio_shift; | 2367 | u32 gpio_shift; |
2334 | 2368 | ||
2335 | ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); | 2369 | if (AR_DEVID_7010(ah)) { |
2370 | gpio_shift = gpio; | ||
2371 | REG_RMW(ah, AR7010_GPIO_OE, | ||
2372 | (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift), | ||
2373 | (AR7010_GPIO_OE_MASK << gpio_shift)); | ||
2374 | return; | ||
2375 | } | ||
2336 | 2376 | ||
2377 | ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); | ||
2337 | gpio_shift = 2 * gpio; | 2378 | gpio_shift = 2 * gpio; |
2338 | |||
2339 | REG_RMW(ah, | 2379 | REG_RMW(ah, |
2340 | AR_GPIO_OE_OUT, | 2380 | AR_GPIO_OE_OUT, |
2341 | (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), | 2381 | (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), |
@@ -2345,6 +2385,13 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output); | |||
2345 | 2385 | ||
2346 | void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) | 2386 | void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) |
2347 | { | 2387 | { |
2388 | if (AR_DEVID_7010(ah)) { | ||
2389 | val = val ? 0 : 1; | ||
2390 | REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio), | ||
2391 | AR_GPIO_BIT(gpio)); | ||
2392 | return; | ||
2393 | } | ||
2394 | |||
2348 | if (AR_SREV_9271(ah)) | 2395 | if (AR_SREV_9271(ah)) |
2349 | val = ~val; | 2396 | val = ~val; |
2350 | 2397 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5ecbfcf7470a..bb99e2e1f943 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -235,6 +235,7 @@ struct ath9k_ops_config { | |||
235 | int ack_6mb; | 235 | int ack_6mb; |
236 | u32 cwm_ignore_extcca; | 236 | u32 cwm_ignore_extcca; |
237 | u8 pcie_powersave_enable; | 237 | u8 pcie_powersave_enable; |
238 | bool pcieSerDesWrite; | ||
238 | u8 pcie_clock_req; | 239 | u8 pcie_clock_req; |
239 | u32 pcie_waen; | 240 | u32 pcie_waen; |
240 | u8 analog_shiftreg; | 241 | u8 analog_shiftreg; |
@@ -819,6 +820,12 @@ struct ath_hw { | |||
819 | 820 | ||
820 | u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES]; | 821 | u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES]; |
821 | u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES]; | 822 | u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES]; |
823 | /* | ||
824 | * Store the permanent value of Reg 0x4004in WARegVal | ||
825 | * so we dont have to R/M/W. We should not be reading | ||
826 | * this register when in sleep states. | ||
827 | */ | ||
828 | u32 WARegVal; | ||
822 | }; | 829 | }; |
823 | 830 | ||
824 | static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) | 831 | static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) |
@@ -852,11 +859,9 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); | |||
852 | 859 | ||
853 | /* Key Cache Management */ | 860 | /* Key Cache Management */ |
854 | bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); | 861 | bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); |
855 | bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac); | ||
856 | bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | 862 | bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, |
857 | const struct ath9k_keyval *k, | 863 | const struct ath9k_keyval *k, |
858 | const u8 *mac); | 864 | const u8 *mac); |
859 | bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry); | ||
860 | 865 | ||
861 | /* GPIO / RFKILL / Antennae */ | 866 | /* GPIO / RFKILL / Antennae */ |
862 | void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); | 867 | void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 514a4014c198..8700e3dc53cf 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -33,6 +33,10 @@ int modparam_nohwcrypt; | |||
33 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 33 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); |
34 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | 34 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); |
35 | 35 | ||
36 | int led_blink = 1; | ||
37 | module_param_named(blink, led_blink, int, 0444); | ||
38 | MODULE_PARM_DESC(blink, "Enable LED blink on activity"); | ||
39 | |||
36 | /* We use the hw_value as an index into our private channel structure */ | 40 | /* We use the hw_value as an index into our private channel structure */ |
37 | 41 | ||
38 | #define CHAN2G(_freq, _idx) { \ | 42 | #define CHAN2G(_freq, _idx) { \ |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c8de50fa6378..efbf53534ade 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -268,7 +268,6 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
268 | int time_left; | 268 | int time_left; |
269 | int i; | 269 | int i; |
270 | 270 | ||
271 | ath9k_ps_wakeup(sc); | ||
272 | skb = alloc_skb(len, GFP_KERNEL); | 271 | skb = alloc_skb(len, GFP_KERNEL); |
273 | if (!skb) | 272 | if (!skb) |
274 | return; | 273 | return; |
@@ -289,6 +288,7 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
289 | qnum = sc->tx.hwq_map[WME_AC_BE]; | 288 | qnum = sc->tx.hwq_map[WME_AC_BE]; |
290 | txctl.txq = &sc->tx.txq[qnum]; | 289 | txctl.txq = &sc->tx.txq[qnum]; |
291 | 290 | ||
291 | ath9k_ps_wakeup(sc); | ||
292 | ar9003_paprd_init_table(ah); | 292 | ar9003_paprd_init_table(ah); |
293 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | 293 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { |
294 | if (!(ah->caps.tx_chainmask & BIT(chain))) | 294 | if (!(ah->caps.tx_chainmask & BIT(chain))) |
@@ -310,13 +310,13 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
310 | break; | 310 | break; |
311 | 311 | ||
312 | time_left = wait_for_completion_timeout(&sc->paprd_complete, | 312 | time_left = wait_for_completion_timeout(&sc->paprd_complete, |
313 | 100); | 313 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); |
314 | if (!time_left) { | 314 | if (!time_left) { |
315 | ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, | 315 | ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, |
316 | "Timeout waiting for paprd training on " | 316 | "Timeout waiting for paprd training on " |
317 | "TX chain %d\n", | 317 | "TX chain %d\n", |
318 | chain); | 318 | chain); |
319 | break; | 319 | goto fail_paprd; |
320 | } | 320 | } |
321 | 321 | ||
322 | if (!ar9003_paprd_is_done(ah)) | 322 | if (!ar9003_paprd_is_done(ah)) |
@@ -334,6 +334,7 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
334 | ath_paprd_activate(sc); | 334 | ath_paprd_activate(sc); |
335 | } | 335 | } |
336 | 336 | ||
337 | fail_paprd: | ||
337 | ath9k_ps_restore(sc); | 338 | ath9k_ps_restore(sc); |
338 | } | 339 | } |
339 | 340 | ||
@@ -451,6 +452,10 @@ static void ath_start_ani(struct ath_common *common) | |||
451 | { | 452 | { |
452 | struct ath_hw *ah = common->ah; | 453 | struct ath_hw *ah = common->ah; |
453 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 454 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
455 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
456 | |||
457 | if (!(sc->sc_flags & SC_OP_ANI_RUN)) | ||
458 | return; | ||
454 | 459 | ||
455 | common->ani.longcal_timer = timestamp; | 460 | common->ani.longcal_timer = timestamp; |
456 | common->ani.shortcal_timer = timestamp; | 461 | common->ani.shortcal_timer = timestamp; |
@@ -766,11 +771,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
766 | /* Reset rssi stats */ | 771 | /* Reset rssi stats */ |
767 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 772 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
768 | 773 | ||
774 | sc->sc_flags |= SC_OP_ANI_RUN; | ||
769 | ath_start_ani(common); | 775 | ath_start_ani(common); |
770 | } else { | 776 | } else { |
771 | ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); | 777 | ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); |
772 | common->curaid = 0; | 778 | common->curaid = 0; |
773 | /* Stop ANI */ | 779 | /* Stop ANI */ |
780 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
774 | del_timer_sync(&common->ani.timer); | 781 | del_timer_sync(&common->ani.timer); |
775 | } | 782 | } |
776 | } | 783 | } |
@@ -1241,7 +1248,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1241 | 1248 | ||
1242 | aphy->state = ATH_WIPHY_INACTIVE; | 1249 | aphy->state = ATH_WIPHY_INACTIVE; |
1243 | 1250 | ||
1244 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | 1251 | if (led_blink) |
1252 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | ||
1253 | |||
1245 | cancel_delayed_work_sync(&sc->tx_complete_work); | 1254 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1246 | cancel_work_sync(&sc->paprd_work); | 1255 | cancel_work_sync(&sc->paprd_work); |
1247 | 1256 | ||
@@ -1374,8 +1383,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
1374 | 1383 | ||
1375 | if (vif->type == NL80211_IFTYPE_AP || | 1384 | if (vif->type == NL80211_IFTYPE_AP || |
1376 | vif->type == NL80211_IFTYPE_ADHOC || | 1385 | vif->type == NL80211_IFTYPE_ADHOC || |
1377 | vif->type == NL80211_IFTYPE_MONITOR) | 1386 | vif->type == NL80211_IFTYPE_MONITOR) { |
1387 | sc->sc_flags |= SC_OP_ANI_RUN; | ||
1378 | ath_start_ani(common); | 1388 | ath_start_ani(common); |
1389 | } | ||
1379 | 1390 | ||
1380 | out: | 1391 | out: |
1381 | mutex_unlock(&sc->mutex); | 1392 | mutex_unlock(&sc->mutex); |
@@ -1396,6 +1407,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1396 | mutex_lock(&sc->mutex); | 1407 | mutex_lock(&sc->mutex); |
1397 | 1408 | ||
1398 | /* Stop ANI */ | 1409 | /* Stop ANI */ |
1410 | sc->sc_flags &= ~SC_OP_ANI_RUN; | ||
1399 | del_timer_sync(&common->ani.timer); | 1411 | del_timer_sync(&common->ani.timer); |
1400 | 1412 | ||
1401 | /* Reclaim beacon resources */ | 1413 | /* Reclaim beacon resources */ |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 3e3ccef438db..633e3d949ec0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -704,6 +704,11 @@ | |||
704 | #define AR_WA_BIT7 (1 << 7) | 704 | #define AR_WA_BIT7 (1 << 7) |
705 | #define AR_WA_BIT23 (1 << 23) | 705 | #define AR_WA_BIT23 (1 << 23) |
706 | #define AR_WA_D3_L1_DISABLE (1 << 14) | 706 | #define AR_WA_D3_L1_DISABLE (1 << 14) |
707 | #define AR_WA_D3_TO_L1_DISABLE_REAL (1 << 16) | ||
708 | #define AR_WA_ASPM_TIMER_BASED_DISABLE (1 << 17) | ||
709 | #define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */ | ||
710 | #define AR_WA_ANALOG_SHIFT (1 << 20) | ||
711 | #define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */ | ||
707 | #define AR9285_WA_DEFAULT 0x004a050b | 712 | #define AR9285_WA_DEFAULT 0x004a050b |
708 | #define AR9280_WA_DEFAULT 0x0040073b | 713 | #define AR9280_WA_DEFAULT 0x0040073b |
709 | #define AR_WA_DEFAULT 0x0000073f | 714 | #define AR_WA_DEFAULT 0x0000073f |
@@ -877,6 +882,7 @@ | |||
877 | #define AR_SREV_9271_11(_ah) \ | 882 | #define AR_SREV_9271_11(_ah) \ |
878 | (AR_SREV_9271(_ah) && \ | 883 | (AR_SREV_9271(_ah) && \ |
879 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) | 884 | ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) |
885 | |||
880 | #define AR_SREV_9300(_ah) \ | 886 | #define AR_SREV_9300(_ah) \ |
881 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) | 887 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) |
882 | #define AR_SREV_9300_20(_ah) \ | 888 | #define AR_SREV_9300_20(_ah) \ |
@@ -891,6 +897,10 @@ | |||
891 | (AR_SREV_9285_12_OR_LATER(_ah) && \ | 897 | (AR_SREV_9285_12_OR_LATER(_ah) && \ |
892 | ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) | 898 | ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) |
893 | 899 | ||
900 | #define AR_DEVID_7010(_ah) \ | ||
901 | (((_ah)->hw_version.devid == 0x7010) || \ | ||
902 | ((_ah)->hw_version.devid == 0x9018)) | ||
903 | |||
894 | #define AR_RADIO_SREV_MAJOR 0xf0 | 904 | #define AR_RADIO_SREV_MAJOR 0xf0 |
895 | #define AR_RAD5133_SREV_MAJOR 0xc0 | 905 | #define AR_RAD5133_SREV_MAJOR 0xc0 |
896 | #define AR_RAD2133_SREV_MAJOR 0xd0 | 906 | #define AR_RAD2133_SREV_MAJOR 0xd0 |
@@ -988,6 +998,7 @@ enum { | |||
988 | #define AR9287_NUM_GPIO 11 | 998 | #define AR9287_NUM_GPIO 11 |
989 | #define AR9271_NUM_GPIO 16 | 999 | #define AR9271_NUM_GPIO 16 |
990 | #define AR9300_NUM_GPIO 17 | 1000 | #define AR9300_NUM_GPIO 17 |
1001 | #define AR7010_NUM_GPIO 16 | ||
991 | 1002 | ||
992 | #define AR_GPIO_IN_OUT 0x4048 | 1003 | #define AR_GPIO_IN_OUT 0x4048 |
993 | #define AR_GPIO_IN_VAL 0x0FFFC000 | 1004 | #define AR_GPIO_IN_VAL 0x0FFFC000 |
@@ -1002,6 +1013,8 @@ enum { | |||
1002 | #define AR9271_GPIO_IN_VAL_S 16 | 1013 | #define AR9271_GPIO_IN_VAL_S 16 |
1003 | #define AR9300_GPIO_IN_VAL 0x0001FFFF | 1014 | #define AR9300_GPIO_IN_VAL 0x0001FFFF |
1004 | #define AR9300_GPIO_IN_VAL_S 0 | 1015 | #define AR9300_GPIO_IN_VAL_S 0 |
1016 | #define AR7010_GPIO_IN_VAL 0x0000FFFF | ||
1017 | #define AR7010_GPIO_IN_VAL_S 0 | ||
1005 | 1018 | ||
1006 | #define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) | 1019 | #define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) |
1007 | #define AR_GPIO_OE_OUT_DRV 0x3 | 1020 | #define AR_GPIO_OE_OUT_DRV 0x3 |
@@ -1010,6 +1023,21 @@ enum { | |||
1010 | #define AR_GPIO_OE_OUT_DRV_HI 0x2 | 1023 | #define AR_GPIO_OE_OUT_DRV_HI 0x2 |
1011 | #define AR_GPIO_OE_OUT_DRV_ALL 0x3 | 1024 | #define AR_GPIO_OE_OUT_DRV_ALL 0x3 |
1012 | 1025 | ||
1026 | #define AR7010_GPIO_OE 0x52000 | ||
1027 | #define AR7010_GPIO_OE_MASK 0x1 | ||
1028 | #define AR7010_GPIO_OE_AS_OUTPUT 0x0 | ||
1029 | #define AR7010_GPIO_OE_AS_INPUT 0x1 | ||
1030 | #define AR7010_GPIO_IN 0x52004 | ||
1031 | #define AR7010_GPIO_OUT 0x52008 | ||
1032 | #define AR7010_GPIO_SET 0x5200C | ||
1033 | #define AR7010_GPIO_CLEAR 0x52010 | ||
1034 | #define AR7010_GPIO_INT 0x52014 | ||
1035 | #define AR7010_GPIO_INT_TYPE 0x52018 | ||
1036 | #define AR7010_GPIO_INT_POLARITY 0x5201C | ||
1037 | #define AR7010_GPIO_PENDING 0x52020 | ||
1038 | #define AR7010_GPIO_INT_MASK 0x52024 | ||
1039 | #define AR7010_GPIO_FUNCTION 0x52028 | ||
1040 | |||
1013 | #define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) | 1041 | #define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) |
1014 | #define AR_GPIO_INTR_POL_VAL 0x0001FFFF | 1042 | #define AR_GPIO_INTR_POL_VAL 0x0001FFFF |
1015 | #define AR_GPIO_INTR_POL_VAL_S 0 | 1043 | #define AR_GPIO_INTR_POL_VAL_S 0 |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 20221b8c04fd..c3681a1dc941 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -328,6 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
328 | u32 ba[WME_BA_BMP_SIZE >> 5]; | 328 | u32 ba[WME_BA_BMP_SIZE >> 5]; |
329 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; | 329 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; |
330 | bool rc_update = true; | 330 | bool rc_update = true; |
331 | struct ieee80211_tx_rate rates[4]; | ||
331 | 332 | ||
332 | skb = bf->bf_mpdu; | 333 | skb = bf->bf_mpdu; |
333 | hdr = (struct ieee80211_hdr *)skb->data; | 334 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -335,6 +336,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
335 | tx_info = IEEE80211_SKB_CB(skb); | 336 | tx_info = IEEE80211_SKB_CB(skb); |
336 | hw = bf->aphy->hw; | 337 | hw = bf->aphy->hw; |
337 | 338 | ||
339 | memcpy(rates, tx_info->control.rates, sizeof(rates)); | ||
340 | |||
338 | rcu_read_lock(); | 341 | rcu_read_lock(); |
339 | 342 | ||
340 | /* XXX: use ieee80211_find_sta! */ | 343 | /* XXX: use ieee80211_find_sta! */ |
@@ -375,6 +378,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
375 | txfail = txpending = 0; | 378 | txfail = txpending = 0; |
376 | bf_next = bf->bf_next; | 379 | bf_next = bf->bf_next; |
377 | 380 | ||
381 | skb = bf->bf_mpdu; | ||
382 | tx_info = IEEE80211_SKB_CB(skb); | ||
383 | |||
378 | if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { | 384 | if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { |
379 | /* transmit completion, subframe is | 385 | /* transmit completion, subframe is |
380 | * acked by block ack */ | 386 | * acked by block ack */ |
@@ -428,6 +434,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
428 | spin_unlock_bh(&txq->axq_lock); | 434 | spin_unlock_bh(&txq->axq_lock); |
429 | 435 | ||
430 | if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { | 436 | if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { |
437 | memcpy(tx_info->control.rates, rates, sizeof(rates)); | ||
431 | ath_tx_rc_status(bf, ts, nbad, txok, true); | 438 | ath_tx_rc_status(bf, ts, nbad, txok, true); |
432 | rc_update = false; | 439 | rc_update = false; |
433 | } else { | 440 | } else { |
@@ -1644,6 +1651,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1644 | } | 1651 | } |
1645 | 1652 | ||
1646 | bf->bf_state.bfs_paprd = txctl->paprd; | 1653 | bf->bf_state.bfs_paprd = txctl->paprd; |
1654 | if (txctl->paprd) | ||
1655 | bf->bf_state.bfs_paprd_timestamp = jiffies; | ||
1647 | bf->bf_flags = setup_tx_flags(skb, use_ldpc); | 1656 | bf->bf_flags = setup_tx_flags(skb, use_ldpc); |
1648 | 1657 | ||
1649 | bf->bf_keytype = get_hw_crypto_keytype(skb); | 1658 | bf->bf_keytype = get_hw_crypto_keytype(skb); |
@@ -1944,8 +1953,12 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | |||
1944 | dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); | 1953 | dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); |
1945 | 1954 | ||
1946 | if (bf->bf_state.bfs_paprd) { | 1955 | if (bf->bf_state.bfs_paprd) { |
1947 | sc->paprd_txok = txok; | 1956 | if (time_after(jiffies, |
1948 | complete(&sc->paprd_complete); | 1957 | bf->bf_state.bfs_paprd_timestamp + |
1958 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT))) | ||
1959 | dev_kfree_skb_any(skb); | ||
1960 | else | ||
1961 | complete(&sc->paprd_complete); | ||
1949 | } else { | 1962 | } else { |
1950 | ath_tx_complete(sc, skb, bf->aphy, tx_flags); | 1963 | ath_tx_complete(sc, skb, bf->aphy, tx_flags); |
1951 | ath_debug_stat_tx(sc, txq, bf, ts); | 1964 | ath_debug_stat_tx(sc, txq, bf, ts); |
@@ -2027,7 +2040,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, | |||
2027 | tx_info->status.rates[i].idx = -1; | 2040 | tx_info->status.rates[i].idx = -1; |
2028 | } | 2041 | } |
2029 | 2042 | ||
2030 | tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; | 2043 | tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; |
2031 | } | 2044 | } |
2032 | 2045 | ||
2033 | static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) | 2046 | static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) |
@@ -2138,7 +2151,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2138 | * This frame is sent out as a single frame. | 2151 | * This frame is sent out as a single frame. |
2139 | * Use hardware retry status for this frame. | 2152 | * Use hardware retry status for this frame. |
2140 | */ | 2153 | */ |
2141 | bf->bf_retries = ts.ts_longretry; | ||
2142 | if (ts.ts_status & ATH9K_TXERR_XRETRY) | 2154 | if (ts.ts_status & ATH9K_TXERR_XRETRY) |
2143 | bf->bf_state.bf_type |= BUF_XRETRY; | 2155 | bf->bf_state.bf_type |= BUF_XRETRY; |
2144 | ath_tx_rc_status(bf, &ts, 0, txok, true); | 2156 | ath_tx_rc_status(bf, &ts, 0, txok, true); |
@@ -2268,7 +2280,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
2268 | } | 2280 | } |
2269 | 2281 | ||
2270 | if (!bf_isampdu(bf)) { | 2282 | if (!bf_isampdu(bf)) { |
2271 | bf->bf_retries = txs.ts_longretry; | ||
2272 | if (txs.ts_status & ATH9K_TXERR_XRETRY) | 2283 | if (txs.ts_status & ATH9K_TXERR_XRETRY) |
2273 | bf->bf_state.bf_type |= BUF_XRETRY; | 2284 | bf->bf_state.bf_type |= BUF_XRETRY; |
2274 | ath_tx_rc_status(bf, &txs, 0, txok, true); | 2285 | ath_tx_rc_status(bf, &txs, 0, txok, true); |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7965b70efbab..8e243798ae93 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -1804,7 +1804,7 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) | |||
1804 | dma_reason[2], dma_reason[3], | 1804 | dma_reason[2], dma_reason[3], |
1805 | dma_reason[4], dma_reason[5]); | 1805 | dma_reason[4], dma_reason[5]); |
1806 | b43err(dev->wl, "This device does not support DMA " | 1806 | b43err(dev->wl, "This device does not support DMA " |
1807 | "on your system. Please use PIO instead.\n"); | 1807 | "on your system. It will now be switched to PIO.\n"); |
1808 | /* Fall back to PIO transfers if we get fatal DMA errors! */ | 1808 | /* Fall back to PIO transfers if we get fatal DMA errors! */ |
1809 | dev->use_pio = 1; | 1809 | dev->use_pio = 1; |
1810 | b43_controller_restart(dev, "DMA error"); | 1810 | b43_controller_restart(dev, "DMA error"); |
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c index 4e56b7bbcebd..45933cf8e8c2 100644 --- a/drivers/net/wireless/b43/sdio.c +++ b/drivers/net/wireless/b43/sdio.c | |||
@@ -182,6 +182,7 @@ static void b43_sdio_remove(struct sdio_func *func) | |||
182 | 182 | ||
183 | static const struct sdio_device_id b43_sdio_ids[] = { | 183 | static const struct sdio_device_id b43_sdio_ids[] = { |
184 | { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ | 184 | { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ |
185 | { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */ | ||
185 | { }, | 186 | { }, |
186 | }; | 187 | }; |
187 | 188 | ||
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 231dbd77f5f5..9cadaa296fac 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -688,7 +688,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |||
688 | struct ap_data *ap = data; | 688 | struct ap_data *ap = data; |
689 | struct net_device *dev = ap->local->dev; | 689 | struct net_device *dev = ap->local->dev; |
690 | struct ieee80211_hdr *hdr; | 690 | struct ieee80211_hdr *hdr; |
691 | u16 fc, status; | 691 | u16 status; |
692 | __le16 *pos; | 692 | __le16 *pos; |
693 | struct sta_info *sta = NULL; | 693 | struct sta_info *sta = NULL; |
694 | char *txt = NULL; | 694 | char *txt = NULL; |
@@ -699,7 +699,6 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |||
699 | } | 699 | } |
700 | 700 | ||
701 | hdr = (struct ieee80211_hdr *) skb->data; | 701 | hdr = (struct ieee80211_hdr *) skb->data; |
702 | fc = le16_to_cpu(hdr->frame_control); | ||
703 | if ((!ieee80211_is_assoc_resp(hdr->frame_control) && | 702 | if ((!ieee80211_is_assoc_resp(hdr->frame_control) && |
704 | !ieee80211_is_reassoc_resp(hdr->frame_control)) || | 703 | !ieee80211_is_reassoc_resp(hdr->frame_control)) || |
705 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | 704 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { |
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index eb57d1ea361f..eaee84b55887 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c | |||
@@ -741,9 +741,7 @@ void hostap_set_multicast_list_queue(struct work_struct *work) | |||
741 | local_info_t *local = | 741 | local_info_t *local = |
742 | container_of(work, local_info_t, set_multicast_list_queue); | 742 | container_of(work, local_info_t, set_multicast_list_queue); |
743 | struct net_device *dev = local->dev; | 743 | struct net_device *dev = local->dev; |
744 | struct hostap_interface *iface; | ||
745 | 744 | ||
746 | iface = netdev_priv(dev); | ||
747 | if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | 745 | if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, |
748 | local->is_promisc)) { | 746 | local->is_promisc)) { |
749 | printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", | 747 | printk(KERN_INFO "%s: %sabling promiscuous mode failed\n", |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 7c7235385513..728bb858ba97 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | obj-$(CONFIG_IWLWIFI) += iwlcore.o | 1 | obj-$(CONFIG_IWLWIFI) += iwlcore.o |
2 | iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o | 2 | iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o |
3 | iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o | 3 | iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o |
4 | iwlcore-objs += iwl-scan.o iwl-led.o | 4 | iwlcore-objs += iwl-scan.o iwl-led.o |
5 | iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o | 5 | iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o |
6 | iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o | 6 | iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o |
@@ -11,7 +11,7 @@ CFLAGS_iwl-devtrace.o := -I$(src) | |||
11 | obj-$(CONFIG_IWLAGN) += iwlagn.o | 11 | obj-$(CONFIG_IWLAGN) += iwlagn.o |
12 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o | 12 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o |
13 | iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o | 13 | iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o |
14 | iwlagn-objs += iwl-agn-lib.o | 14 | iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o |
15 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o | 15 | iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o |
16 | 16 | ||
17 | iwlagn-$(CONFIG_IWL4965) += iwl-4965.o | 17 | iwlagn-$(CONFIG_IWL4965) += iwl-4965.o |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index dba91e0233b6..1daf159914ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -157,6 +157,8 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) | |||
157 | BIT(IWL_CALIB_TX_IQ) | | 157 | BIT(IWL_CALIB_TX_IQ) | |
158 | BIT(IWL_CALIB_TX_IQ_PERD) | | 158 | BIT(IWL_CALIB_TX_IQ_PERD) | |
159 | BIT(IWL_CALIB_BASE_BAND); | 159 | BIT(IWL_CALIB_BASE_BAND); |
160 | if (priv->cfg->need_dc_calib) | ||
161 | priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); | ||
160 | 162 | ||
161 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | 163 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; |
162 | 164 | ||
@@ -215,6 +217,7 @@ static struct iwl_lib_ops iwl1000_lib = { | |||
215 | .set_ct_kill = iwl1000_set_ct_threshold, | 217 | .set_ct_kill = iwl1000_set_ct_threshold, |
216 | }, | 218 | }, |
217 | .manage_ibss_station = iwlagn_manage_ibss_station, | 219 | .manage_ibss_station = iwlagn_manage_ibss_station, |
220 | .update_bcast_station = iwl_update_bcast_station, | ||
218 | .debugfs_ops = { | 221 | .debugfs_ops = { |
219 | .rx_stats_read = iwl_ucode_rx_stats_read, | 222 | .rx_stats_read = iwl_ucode_rx_stats_read, |
220 | .tx_stats_read = iwl_ucode_tx_stats_read, | 223 | .tx_stats_read = iwl_ucode_tx_stats_read, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 93d513e14186..a07310fefcf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -406,6 +406,11 @@ static bool iwl3945_good_plcp_health(struct iwl_priv *priv, | |||
406 | unsigned int plcp_msec; | 406 | unsigned int plcp_msec; |
407 | unsigned long plcp_received_jiffies; | 407 | unsigned long plcp_received_jiffies; |
408 | 408 | ||
409 | if (priv->cfg->plcp_delta_threshold == | ||
410 | IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { | ||
411 | IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); | ||
412 | return rc; | ||
413 | } | ||
409 | memcpy(¤t_stat, pkt->u.raw, sizeof(struct | 414 | memcpy(¤t_stat, pkt->u.raw, sizeof(struct |
410 | iwl3945_notif_statistics)); | 415 | iwl3945_notif_statistics)); |
411 | /* | 416 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 83e6a42ca2da..1dd3bc4c107e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1580,7 +1580,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv) | |||
1580 | u32 R4; | 1580 | u32 R4; |
1581 | 1581 | ||
1582 | if (test_bit(STATUS_TEMPERATURE, &priv->status) && | 1582 | if (test_bit(STATUS_TEMPERATURE, &priv->status) && |
1583 | (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { | 1583 | (priv->_agn.statistics.flag & |
1584 | STATISTICS_REPLY_FLG_HT40_MODE_MSK)) { | ||
1584 | IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); | 1585 | IWL_DEBUG_TEMP(priv, "Running HT40 temperature calibration\n"); |
1585 | R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); | 1586 | R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]); |
1586 | R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); | 1587 | R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]); |
@@ -1604,8 +1605,8 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv) | |||
1604 | if (!test_bit(STATUS_TEMPERATURE, &priv->status)) | 1605 | if (!test_bit(STATUS_TEMPERATURE, &priv->status)) |
1605 | vt = sign_extend(R4, 23); | 1606 | vt = sign_extend(R4, 23); |
1606 | else | 1607 | else |
1607 | vt = sign_extend( | 1608 | vt = sign_extend(le32_to_cpu( |
1608 | le32_to_cpu(priv->statistics.general.temperature), 23); | 1609 | priv->_agn.statistics.general.temperature), 23); |
1609 | 1610 | ||
1610 | IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt); | 1611 | IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt); |
1611 | 1612 | ||
@@ -1785,6 +1786,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1785 | { | 1786 | { |
1786 | unsigned long flags; | 1787 | unsigned long flags; |
1787 | u16 ra_tid; | 1788 | u16 ra_tid; |
1789 | int ret; | ||
1788 | 1790 | ||
1789 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || | 1791 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || |
1790 | (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues | 1792 | (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues |
@@ -1800,7 +1802,9 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1800 | ra_tid = BUILD_RAxTID(sta_id, tid); | 1802 | ra_tid = BUILD_RAxTID(sta_id, tid); |
1801 | 1803 | ||
1802 | /* Modify device's station table to Tx this TID */ | 1804 | /* Modify device's station table to Tx this TID */ |
1803 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); | 1805 | ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); |
1806 | if (ret) | ||
1807 | return ret; | ||
1804 | 1808 | ||
1805 | spin_lock_irqsave(&priv->lock, flags); | 1809 | spin_lock_irqsave(&priv->lock, flags); |
1806 | 1810 | ||
@@ -2276,6 +2280,7 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2276 | .set_ct_kill = iwl4965_set_ct_threshold, | 2280 | .set_ct_kill = iwl4965_set_ct_threshold, |
2277 | }, | 2281 | }, |
2278 | .manage_ibss_station = iwlagn_manage_ibss_station, | 2282 | .manage_ibss_station = iwlagn_manage_ibss_station, |
2283 | .update_bcast_station = iwl_update_bcast_station, | ||
2279 | .debugfs_ops = { | 2284 | .debugfs_ops = { |
2280 | .rx_stats_read = iwl_ucode_rx_stats_read, | 2285 | .rx_stats_read = iwl_ucode_rx_stats_read, |
2281 | .tx_stats_read = iwl_ucode_tx_stats_read, | 2286 | .tx_stats_read = iwl_ucode_tx_stats_read, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 32710a801cb0..b8f3e20f2c80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -249,10 +249,11 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) | |||
249 | /* Set initial calibration set */ | 249 | /* Set initial calibration set */ |
250 | priv->hw_params.sens = &iwl5150_sensitivity; | 250 | priv->hw_params.sens = &iwl5150_sensitivity; |
251 | priv->hw_params.calib_init_cfg = | 251 | priv->hw_params.calib_init_cfg = |
252 | BIT(IWL_CALIB_DC) | | ||
253 | BIT(IWL_CALIB_LO) | | 252 | BIT(IWL_CALIB_LO) | |
254 | BIT(IWL_CALIB_TX_IQ) | | 253 | BIT(IWL_CALIB_TX_IQ) | |
255 | BIT(IWL_CALIB_BASE_BAND); | 254 | BIT(IWL_CALIB_BASE_BAND); |
255 | if (priv->cfg->need_dc_calib) | ||
256 | priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); | ||
256 | 257 | ||
257 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | 258 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; |
258 | 259 | ||
@@ -264,7 +265,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) | |||
264 | u32 vt = 0; | 265 | u32 vt = 0; |
265 | s32 offset = iwl_temp_calib_to_offset(priv); | 266 | s32 offset = iwl_temp_calib_to_offset(priv); |
266 | 267 | ||
267 | vt = le32_to_cpu(priv->statistics.general.temperature); | 268 | vt = le32_to_cpu(priv->_agn.statistics.general.temperature); |
268 | vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; | 269 | vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; |
269 | /* now vt hold the temperature in Kelvin */ | 270 | /* now vt hold the temperature in Kelvin */ |
270 | priv->temperature = KELVIN_TO_CELSIUS(vt); | 271 | priv->temperature = KELVIN_TO_CELSIUS(vt); |
@@ -392,6 +393,7 @@ static struct iwl_lib_ops iwl5000_lib = { | |||
392 | .set_ct_kill = iwl5000_set_ct_threshold, | 393 | .set_ct_kill = iwl5000_set_ct_threshold, |
393 | }, | 394 | }, |
394 | .manage_ibss_station = iwlagn_manage_ibss_station, | 395 | .manage_ibss_station = iwlagn_manage_ibss_station, |
396 | .update_bcast_station = iwl_update_bcast_station, | ||
395 | .debugfs_ops = { | 397 | .debugfs_ops = { |
396 | .rx_stats_read = iwl_ucode_rx_stats_read, | 398 | .rx_stats_read = iwl_ucode_rx_stats_read, |
397 | .tx_stats_read = iwl_ucode_tx_stats_read, | 399 | .tx_stats_read = iwl_ucode_tx_stats_read, |
@@ -454,6 +456,7 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
454 | .set_ct_kill = iwl5150_set_ct_threshold, | 456 | .set_ct_kill = iwl5150_set_ct_threshold, |
455 | }, | 457 | }, |
456 | .manage_ibss_station = iwlagn_manage_ibss_station, | 458 | .manage_ibss_station = iwlagn_manage_ibss_station, |
459 | .update_bcast_station = iwl_update_bcast_station, | ||
457 | .debugfs_ops = { | 460 | .debugfs_ops = { |
458 | .rx_stats_read = iwl_ucode_rx_stats_read, | 461 | .rx_stats_read = iwl_ucode_rx_stats_read, |
459 | .tx_stats_read = iwl_ucode_tx_stats_read, | 462 | .tx_stats_read = iwl_ucode_tx_stats_read, |
@@ -660,6 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = { | |||
660 | .ucode_tracing = true, | 663 | .ucode_tracing = true, |
661 | .sensitivity_calib_by_driver = true, | 664 | .sensitivity_calib_by_driver = true, |
662 | .chain_noise_calib_by_driver = true, | 665 | .chain_noise_calib_by_driver = true, |
666 | .need_dc_calib = true, | ||
663 | }; | 667 | }; |
664 | 668 | ||
665 | struct iwl_cfg iwl5150_abg_cfg = { | 669 | struct iwl_cfg iwl5150_abg_cfg = { |
@@ -689,6 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = { | |||
689 | .ucode_tracing = true, | 693 | .ucode_tracing = true, |
690 | .sensitivity_calib_by_driver = true, | 694 | .sensitivity_calib_by_driver = true, |
691 | .chain_noise_calib_by_driver = true, | 695 | .chain_noise_calib_by_driver = true, |
696 | .need_dc_calib = true, | ||
692 | }; | 697 | }; |
693 | 698 | ||
694 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); | 699 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index afdeec56b13f..8577664da77c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -84,9 +84,10 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | /* Indicate calibration version to uCode. */ | 86 | /* Indicate calibration version to uCode. */ |
87 | static void iwl6050_set_calib_version(struct iwl_priv *priv) | 87 | static void iwl6000_set_calib_version(struct iwl_priv *priv) |
88 | { | 88 | { |
89 | if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) | 89 | if (priv->cfg->need_dc_calib && |
90 | (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)) | ||
90 | iwl_set_bit(priv, CSR_GP_DRIVER_REG, | 91 | iwl_set_bit(priv, CSR_GP_DRIVER_REG, |
91 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); | 92 | CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); |
92 | } | 93 | } |
@@ -186,53 +187,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) | |||
186 | BIT(IWL_CALIB_LO) | | 187 | BIT(IWL_CALIB_LO) | |
187 | BIT(IWL_CALIB_TX_IQ) | | 188 | BIT(IWL_CALIB_TX_IQ) | |
188 | BIT(IWL_CALIB_BASE_BAND); | 189 | BIT(IWL_CALIB_BASE_BAND); |
189 | 190 | if (priv->cfg->need_dc_calib) | |
190 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | 191 | priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); |
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int iwl6050_hw_set_hw_params(struct iwl_priv *priv) | ||
196 | { | ||
197 | if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && | ||
198 | priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) | ||
199 | priv->cfg->num_of_queues = | ||
200 | priv->cfg->mod_params->num_of_queues; | ||
201 | |||
202 | priv->hw_params.max_txq_num = priv->cfg->num_of_queues; | ||
203 | priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; | ||
204 | priv->hw_params.scd_bc_tbls_size = | ||
205 | priv->cfg->num_of_queues * | ||
206 | sizeof(struct iwlagn_scd_bc_tbl); | ||
207 | priv->hw_params.tfd_size = sizeof(struct iwl_tfd); | ||
208 | priv->hw_params.max_stations = IWL5000_STATION_COUNT; | ||
209 | priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; | ||
210 | |||
211 | priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; | ||
212 | priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; | ||
213 | |||
214 | priv->hw_params.max_bsm_size = 0; | ||
215 | priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | | ||
216 | BIT(IEEE80211_BAND_5GHZ); | ||
217 | priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; | ||
218 | |||
219 | priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); | ||
220 | priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); | ||
221 | priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; | ||
222 | priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; | ||
223 | |||
224 | if (priv->cfg->ops->lib->temp_ops.set_ct_kill) | ||
225 | priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); | ||
226 | |||
227 | /* Set initial sensitivity parameters */ | ||
228 | /* Set initial calibration set */ | ||
229 | priv->hw_params.sens = &iwl6000_sensitivity; | ||
230 | priv->hw_params.calib_init_cfg = | ||
231 | BIT(IWL_CALIB_XTAL) | | ||
232 | BIT(IWL_CALIB_DC) | | ||
233 | BIT(IWL_CALIB_LO) | | ||
234 | BIT(IWL_CALIB_TX_IQ) | | ||
235 | BIT(IWL_CALIB_BASE_BAND); | ||
236 | 192 | ||
237 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | 193 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; |
238 | 194 | ||
@@ -359,8 +315,10 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
359 | .temp_ops = { | 315 | .temp_ops = { |
360 | .temperature = iwlagn_temperature, | 316 | .temperature = iwlagn_temperature, |
361 | .set_ct_kill = iwl6000_set_ct_threshold, | 317 | .set_ct_kill = iwl6000_set_ct_threshold, |
318 | .set_calib_version = iwl6000_set_calib_version, | ||
362 | }, | 319 | }, |
363 | .manage_ibss_station = iwlagn_manage_ibss_station, | 320 | .manage_ibss_station = iwlagn_manage_ibss_station, |
321 | .update_bcast_station = iwl_update_bcast_station, | ||
364 | .debugfs_ops = { | 322 | .debugfs_ops = { |
365 | .rx_stats_read = iwl_ucode_rx_stats_read, | 323 | .rx_stats_read = iwl_ucode_rx_stats_read, |
366 | .tx_stats_read = iwl_ucode_tx_stats_read, | 324 | .tx_stats_read = iwl_ucode_tx_stats_read, |
@@ -397,79 +355,6 @@ static const struct iwl_ops iwl6000g2b_ops = { | |||
397 | .led = &iwlagn_led_ops, | 355 | .led = &iwlagn_led_ops, |
398 | }; | 356 | }; |
399 | 357 | ||
400 | static struct iwl_lib_ops iwl6050_lib = { | ||
401 | .set_hw_params = iwl6050_hw_set_hw_params, | ||
402 | .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, | ||
403 | .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, | ||
404 | .txq_set_sched = iwlagn_txq_set_sched, | ||
405 | .txq_agg_enable = iwlagn_txq_agg_enable, | ||
406 | .txq_agg_disable = iwlagn_txq_agg_disable, | ||
407 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | ||
408 | .txq_free_tfd = iwl_hw_txq_free_tfd, | ||
409 | .txq_init = iwl_hw_tx_queue_init, | ||
410 | .rx_handler_setup = iwlagn_rx_handler_setup, | ||
411 | .setup_deferred_work = iwlagn_setup_deferred_work, | ||
412 | .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, | ||
413 | .load_ucode = iwlagn_load_ucode, | ||
414 | .dump_nic_event_log = iwl_dump_nic_event_log, | ||
415 | .dump_nic_error_log = iwl_dump_nic_error_log, | ||
416 | .dump_csr = iwl_dump_csr, | ||
417 | .dump_fh = iwl_dump_fh, | ||
418 | .init_alive_start = iwlagn_init_alive_start, | ||
419 | .alive_notify = iwlagn_alive_notify, | ||
420 | .send_tx_power = iwlagn_send_tx_power, | ||
421 | .update_chain_flags = iwl_update_chain_flags, | ||
422 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
423 | .apm_ops = { | ||
424 | .init = iwl_apm_init, | ||
425 | .stop = iwl_apm_stop, | ||
426 | .config = iwl6000_nic_config, | ||
427 | .set_pwr_src = iwl_set_pwr_src, | ||
428 | }, | ||
429 | .eeprom_ops = { | ||
430 | .regulatory_bands = { | ||
431 | EEPROM_REG_BAND_1_CHANNELS, | ||
432 | EEPROM_REG_BAND_2_CHANNELS, | ||
433 | EEPROM_REG_BAND_3_CHANNELS, | ||
434 | EEPROM_REG_BAND_4_CHANNELS, | ||
435 | EEPROM_REG_BAND_5_CHANNELS, | ||
436 | EEPROM_6000_REG_BAND_24_HT40_CHANNELS, | ||
437 | EEPROM_REG_BAND_52_HT40_CHANNELS | ||
438 | }, | ||
439 | .verify_signature = iwlcore_eeprom_verify_signature, | ||
440 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | ||
441 | .release_semaphore = iwlcore_eeprom_release_semaphore, | ||
442 | .calib_version = iwlagn_eeprom_calib_version, | ||
443 | .query_addr = iwlagn_eeprom_query_addr, | ||
444 | .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, | ||
445 | }, | ||
446 | .post_associate = iwl_post_associate, | ||
447 | .isr = iwl_isr_ict, | ||
448 | .config_ap = iwl_config_ap, | ||
449 | .temp_ops = { | ||
450 | .temperature = iwlagn_temperature, | ||
451 | .set_ct_kill = iwl6000_set_ct_threshold, | ||
452 | .set_calib_version = iwl6050_set_calib_version, | ||
453 | }, | ||
454 | .manage_ibss_station = iwlagn_manage_ibss_station, | ||
455 | .debugfs_ops = { | ||
456 | .rx_stats_read = iwl_ucode_rx_stats_read, | ||
457 | .tx_stats_read = iwl_ucode_tx_stats_read, | ||
458 | .general_stats_read = iwl_ucode_general_stats_read, | ||
459 | }, | ||
460 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
461 | .check_plcp_health = iwl_good_plcp_health, | ||
462 | .check_ack_health = iwl_good_ack_health, | ||
463 | }; | ||
464 | |||
465 | static const struct iwl_ops iwl6050_ops = { | ||
466 | .lib = &iwl6050_lib, | ||
467 | .hcmd = &iwlagn_hcmd, | ||
468 | .utils = &iwlagn_hcmd_utils, | ||
469 | .led = &iwlagn_led_ops, | ||
470 | }; | ||
471 | |||
472 | |||
473 | struct iwl_cfg iwl6000g2a_2agn_cfg = { | 358 | struct iwl_cfg iwl6000g2a_2agn_cfg = { |
474 | .name = "6000 Series 2x2 AGN Gen2a", | 359 | .name = "6000 Series 2x2 AGN Gen2a", |
475 | .fw_name_pre = IWL6000G2A_FW_PRE, | 360 | .fw_name_pre = IWL6000G2A_FW_PRE, |
@@ -505,6 +390,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { | |||
505 | .ucode_tracing = true, | 390 | .ucode_tracing = true, |
506 | .sensitivity_calib_by_driver = true, | 391 | .sensitivity_calib_by_driver = true, |
507 | .chain_noise_calib_by_driver = true, | 392 | .chain_noise_calib_by_driver = true, |
393 | .need_dc_calib = true, | ||
508 | }; | 394 | }; |
509 | 395 | ||
510 | struct iwl_cfg iwl6000g2a_2abg_cfg = { | 396 | struct iwl_cfg iwl6000g2a_2abg_cfg = { |
@@ -537,6 +423,9 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { | |||
537 | .chain_noise_scale = 1000, | 423 | .chain_noise_scale = 1000, |
538 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 424 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
539 | .max_event_log_size = 512, | 425 | .max_event_log_size = 512, |
426 | .sensitivity_calib_by_driver = true, | ||
427 | .chain_noise_calib_by_driver = true, | ||
428 | .need_dc_calib = true, | ||
540 | }; | 429 | }; |
541 | 430 | ||
542 | struct iwl_cfg iwl6000g2a_2bg_cfg = { | 431 | struct iwl_cfg iwl6000g2a_2bg_cfg = { |
@@ -569,6 +458,9 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { | |||
569 | .chain_noise_scale = 1000, | 458 | .chain_noise_scale = 1000, |
570 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 459 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
571 | .max_event_log_size = 512, | 460 | .max_event_log_size = 512, |
461 | .sensitivity_calib_by_driver = true, | ||
462 | .chain_noise_calib_by_driver = true, | ||
463 | .need_dc_calib = true, | ||
572 | }; | 464 | }; |
573 | 465 | ||
574 | struct iwl_cfg iwl6000g2b_2agn_cfg = { | 466 | struct iwl_cfg iwl6000g2b_2agn_cfg = { |
@@ -603,6 +495,9 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { | |||
603 | .chain_noise_scale = 1000, | 495 | .chain_noise_scale = 1000, |
604 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 496 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
605 | .max_event_log_size = 512, | 497 | .max_event_log_size = 512, |
498 | .sensitivity_calib_by_driver = true, | ||
499 | .chain_noise_calib_by_driver = true, | ||
500 | .need_dc_calib = true, | ||
606 | }; | 501 | }; |
607 | 502 | ||
608 | struct iwl_cfg iwl6000g2b_2abg_cfg = { | 503 | struct iwl_cfg iwl6000g2b_2abg_cfg = { |
@@ -635,6 +530,9 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { | |||
635 | .chain_noise_scale = 1000, | 530 | .chain_noise_scale = 1000, |
636 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 531 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
637 | .max_event_log_size = 512, | 532 | .max_event_log_size = 512, |
533 | .sensitivity_calib_by_driver = true, | ||
534 | .chain_noise_calib_by_driver = true, | ||
535 | .need_dc_calib = true, | ||
638 | }; | 536 | }; |
639 | 537 | ||
640 | struct iwl_cfg iwl6000g2b_2bgn_cfg = { | 538 | struct iwl_cfg iwl6000g2b_2bgn_cfg = { |
@@ -669,6 +567,9 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { | |||
669 | .chain_noise_scale = 1000, | 567 | .chain_noise_scale = 1000, |
670 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 568 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
671 | .max_event_log_size = 512, | 569 | .max_event_log_size = 512, |
570 | .sensitivity_calib_by_driver = true, | ||
571 | .chain_noise_calib_by_driver = true, | ||
572 | .need_dc_calib = true, | ||
672 | }; | 573 | }; |
673 | 574 | ||
674 | struct iwl_cfg iwl6000g2b_2bg_cfg = { | 575 | struct iwl_cfg iwl6000g2b_2bg_cfg = { |
@@ -701,6 +602,9 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { | |||
701 | .chain_noise_scale = 1000, | 602 | .chain_noise_scale = 1000, |
702 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 603 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
703 | .max_event_log_size = 512, | 604 | .max_event_log_size = 512, |
605 | .sensitivity_calib_by_driver = true, | ||
606 | .chain_noise_calib_by_driver = true, | ||
607 | .need_dc_calib = true, | ||
704 | }; | 608 | }; |
705 | 609 | ||
706 | struct iwl_cfg iwl6000g2b_bgn_cfg = { | 610 | struct iwl_cfg iwl6000g2b_bgn_cfg = { |
@@ -735,6 +639,9 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { | |||
735 | .chain_noise_scale = 1000, | 639 | .chain_noise_scale = 1000, |
736 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 640 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
737 | .max_event_log_size = 512, | 641 | .max_event_log_size = 512, |
642 | .sensitivity_calib_by_driver = true, | ||
643 | .chain_noise_calib_by_driver = true, | ||
644 | .need_dc_calib = true, | ||
738 | }; | 645 | }; |
739 | 646 | ||
740 | struct iwl_cfg iwl6000g2b_bg_cfg = { | 647 | struct iwl_cfg iwl6000g2b_bg_cfg = { |
@@ -767,6 +674,9 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { | |||
767 | .chain_noise_scale = 1000, | 674 | .chain_noise_scale = 1000, |
768 | .monitor_recover_period = IWL_MONITORING_PERIOD, | 675 | .monitor_recover_period = IWL_MONITORING_PERIOD, |
769 | .max_event_log_size = 512, | 676 | .max_event_log_size = 512, |
677 | .sensitivity_calib_by_driver = true, | ||
678 | .chain_noise_calib_by_driver = true, | ||
679 | .need_dc_calib = true, | ||
770 | }; | 680 | }; |
771 | 681 | ||
772 | /* | 682 | /* |
@@ -885,7 +795,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
885 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 795 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
886 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 796 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
887 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 797 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
888 | .ops = &iwl6050_ops, | 798 | .ops = &iwl6000_ops, |
889 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 799 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
890 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, | 800 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, |
891 | .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, | 801 | .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, |
@@ -914,6 +824,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
914 | .ucode_tracing = true, | 824 | .ucode_tracing = true, |
915 | .sensitivity_calib_by_driver = true, | 825 | .sensitivity_calib_by_driver = true, |
916 | .chain_noise_calib_by_driver = true, | 826 | .chain_noise_calib_by_driver = true, |
827 | .need_dc_calib = true, | ||
917 | }; | 828 | }; |
918 | 829 | ||
919 | struct iwl_cfg iwl6050_2abg_cfg = { | 830 | struct iwl_cfg iwl6050_2abg_cfg = { |
@@ -922,7 +833,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { | |||
922 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 833 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
923 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 834 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
924 | .sku = IWL_SKU_A|IWL_SKU_G, | 835 | .sku = IWL_SKU_A|IWL_SKU_G, |
925 | .ops = &iwl6050_ops, | 836 | .ops = &iwl6000_ops, |
926 | .eeprom_size = OTP_LOW_IMAGE_SIZE, | 837 | .eeprom_size = OTP_LOW_IMAGE_SIZE, |
927 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, | 838 | .eeprom_ver = EEPROM_6050_EEPROM_VERSION, |
928 | .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, | 839 | .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, |
@@ -949,6 +860,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { | |||
949 | .ucode_tracing = true, | 860 | .ucode_tracing = true, |
950 | .sensitivity_calib_by_driver = true, | 861 | .sensitivity_calib_by_driver = true, |
951 | .chain_noise_calib_by_driver = true, | 862 | .chain_noise_calib_by_driver = true, |
863 | .need_dc_calib = true, | ||
952 | }; | 864 | }; |
953 | 865 | ||
954 | struct iwl_cfg iwl6000_3agn_cfg = { | 866 | struct iwl_cfg iwl6000_3agn_cfg = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 22fa947e8756..eb052b05e790 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c | |||
@@ -96,17 +96,16 @@ int iwl_send_calib_results(struct iwl_priv *priv) | |||
96 | hcmd.len = priv->calib_results[i].buf_len; | 96 | hcmd.len = priv->calib_results[i].buf_len; |
97 | hcmd.data = priv->calib_results[i].buf; | 97 | hcmd.data = priv->calib_results[i].buf; |
98 | ret = iwl_send_cmd_sync(priv, &hcmd); | 98 | ret = iwl_send_cmd_sync(priv, &hcmd); |
99 | if (ret) | 99 | if (ret) { |
100 | goto err; | 100 | IWL_ERR(priv, "Error %d iteration %d\n", |
101 | ret, i); | ||
102 | break; | ||
103 | } | ||
101 | } | 104 | } |
102 | } | 105 | } |
103 | 106 | ||
104 | return 0; | ||
105 | err: | ||
106 | IWL_ERR(priv, "Error %d iteration %d\n", ret, i); | ||
107 | return ret; | 107 | return ret; |
108 | } | 108 | } |
109 | EXPORT_SYMBOL(iwl_send_calib_results); | ||
110 | 109 | ||
111 | int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) | 110 | int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) |
112 | { | 111 | { |
@@ -121,7 +120,6 @@ int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len) | |||
121 | memcpy(res->buf, buf, len); | 120 | memcpy(res->buf, buf, len); |
122 | return 0; | 121 | return 0; |
123 | } | 122 | } |
124 | EXPORT_SYMBOL(iwl_calib_set); | ||
125 | 123 | ||
126 | void iwl_calib_free_results(struct iwl_priv *priv) | 124 | void iwl_calib_free_results(struct iwl_priv *priv) |
127 | { | 125 | { |
@@ -133,7 +131,6 @@ void iwl_calib_free_results(struct iwl_priv *priv) | |||
133 | priv->calib_results[i].buf_len = 0; | 131 | priv->calib_results[i].buf_len = 0; |
134 | } | 132 | } |
135 | } | 133 | } |
136 | EXPORT_SYMBOL(iwl_calib_free_results); | ||
137 | 134 | ||
138 | /***************************************************************************** | 135 | /***************************************************************************** |
139 | * RUNTIME calibrations framework | 136 | * RUNTIME calibrations framework |
@@ -533,7 +530,6 @@ void iwl_init_sensitivity(struct iwl_priv *priv) | |||
533 | ret |= iwl_sensitivity_write(priv); | 530 | ret |= iwl_sensitivity_write(priv); |
534 | IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret); | 531 | IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret); |
535 | } | 532 | } |
536 | EXPORT_SYMBOL(iwl_init_sensitivity); | ||
537 | 533 | ||
538 | void iwl_sensitivity_calibration(struct iwl_priv *priv, | 534 | void iwl_sensitivity_calibration(struct iwl_priv *priv, |
539 | struct iwl_notif_statistics *resp) | 535 | struct iwl_notif_statistics *resp) |
@@ -639,7 +635,6 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, | |||
639 | iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); | 635 | iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); |
640 | iwl_sensitivity_write(priv); | 636 | iwl_sensitivity_write(priv); |
641 | } | 637 | } |
642 | EXPORT_SYMBOL(iwl_sensitivity_calibration); | ||
643 | 638 | ||
644 | static inline u8 find_first_chain(u8 mask) | 639 | static inline u8 find_first_chain(u8 mask) |
645 | { | 640 | { |
@@ -848,10 +843,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
848 | 843 | ||
849 | if (active_chains != priv->hw_params.valid_rx_ant && | 844 | if (active_chains != priv->hw_params.valid_rx_ant && |
850 | active_chains != priv->chain_noise_data.active_chains) | 845 | active_chains != priv->chain_noise_data.active_chains) |
851 | IWL_WARN(priv, | 846 | IWL_DEBUG_CALIB(priv, |
852 | "Detected that not all antennas are connected! " | 847 | "Detected that not all antennas are connected! " |
853 | "Connected: %#x, valid: %#x.\n", | 848 | "Connected: %#x, valid: %#x.\n", |
854 | active_chains, priv->hw_params.valid_rx_ant); | 849 | active_chains, priv->hw_params.valid_rx_ant); |
855 | 850 | ||
856 | /* Save for use within RXON, TX, SCAN commands, etc. */ | 851 | /* Save for use within RXON, TX, SCAN commands, etc. */ |
857 | priv->chain_noise_data.active_chains = active_chains; | 852 | priv->chain_noise_data.active_chains = active_chains; |
@@ -897,8 +892,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
897 | data->state = IWL_CHAIN_NOISE_DONE; | 892 | data->state = IWL_CHAIN_NOISE_DONE; |
898 | iwl_power_update_mode(priv, false); | 893 | iwl_power_update_mode(priv, false); |
899 | } | 894 | } |
900 | EXPORT_SYMBOL(iwl_chain_noise_calibration); | ||
901 | |||
902 | 895 | ||
903 | void iwl_reset_run_time_calib(struct iwl_priv *priv) | 896 | void iwl_reset_run_time_calib(struct iwl_priv *priv) |
904 | { | 897 | { |
@@ -915,5 +908,3 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv) | |||
915 | * periodically after association */ | 908 | * periodically after association */ |
916 | iwl_send_statistics_request(priv, CMD_ASYNC, true); | 909 | iwl_send_statistics_request(priv, CMD_ASYNC, true); |
917 | } | 910 | } |
918 | EXPORT_SYMBOL(iwl_reset_run_time_calib); | ||
919 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index 3d08dc8af143..75d6bfcbc607 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c | |||
@@ -33,17 +33,17 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) | |||
33 | int p = 0; | 33 | int p = 0; |
34 | 34 | ||
35 | p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", | 35 | p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", |
36 | le32_to_cpu(priv->statistics.flag)); | 36 | le32_to_cpu(priv->_agn.statistics.flag)); |
37 | if (le32_to_cpu(priv->statistics.flag) & | 37 | if (le32_to_cpu(priv->_agn.statistics.flag) & |
38 | UCODE_STATISTICS_CLEAR_MSK) | 38 | UCODE_STATISTICS_CLEAR_MSK) |
39 | p += scnprintf(buf + p, bufsz - p, | 39 | p += scnprintf(buf + p, bufsz - p, |
40 | "\tStatistics have been cleared\n"); | 40 | "\tStatistics have been cleared\n"); |
41 | p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", | 41 | p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", |
42 | (le32_to_cpu(priv->statistics.flag) & | 42 | (le32_to_cpu(priv->_agn.statistics.flag) & |
43 | UCODE_STATISTICS_FREQUENCY_MSK) | 43 | UCODE_STATISTICS_FREQUENCY_MSK) |
44 | ? "2.4 GHz" : "5.2 GHz"); | 44 | ? "2.4 GHz" : "5.2 GHz"); |
45 | p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", | 45 | p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", |
46 | (le32_to_cpu(priv->statistics.flag) & | 46 | (le32_to_cpu(priv->_agn.statistics.flag) & |
47 | UCODE_STATISTICS_NARROW_BAND_MSK) | 47 | UCODE_STATISTICS_NARROW_BAND_MSK) |
48 | ? "enabled" : "disabled"); | 48 | ? "enabled" : "disabled"); |
49 | return p; | 49 | return p; |
@@ -79,22 +79,22 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, | |||
79 | * the last statistics notification from uCode | 79 | * the last statistics notification from uCode |
80 | * might not reflect the current uCode activity | 80 | * might not reflect the current uCode activity |
81 | */ | 81 | */ |
82 | ofdm = &priv->statistics.rx.ofdm; | 82 | ofdm = &priv->_agn.statistics.rx.ofdm; |
83 | cck = &priv->statistics.rx.cck; | 83 | cck = &priv->_agn.statistics.rx.cck; |
84 | general = &priv->statistics.rx.general; | 84 | general = &priv->_agn.statistics.rx.general; |
85 | ht = &priv->statistics.rx.ofdm_ht; | 85 | ht = &priv->_agn.statistics.rx.ofdm_ht; |
86 | accum_ofdm = &priv->accum_statistics.rx.ofdm; | 86 | accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm; |
87 | accum_cck = &priv->accum_statistics.rx.cck; | 87 | accum_cck = &priv->_agn.accum_statistics.rx.cck; |
88 | accum_general = &priv->accum_statistics.rx.general; | 88 | accum_general = &priv->_agn.accum_statistics.rx.general; |
89 | accum_ht = &priv->accum_statistics.rx.ofdm_ht; | 89 | accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht; |
90 | delta_ofdm = &priv->delta_statistics.rx.ofdm; | 90 | delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm; |
91 | delta_cck = &priv->delta_statistics.rx.cck; | 91 | delta_cck = &priv->_agn.delta_statistics.rx.cck; |
92 | delta_general = &priv->delta_statistics.rx.general; | 92 | delta_general = &priv->_agn.delta_statistics.rx.general; |
93 | delta_ht = &priv->delta_statistics.rx.ofdm_ht; | 93 | delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht; |
94 | max_ofdm = &priv->max_delta.rx.ofdm; | 94 | max_ofdm = &priv->_agn.max_delta.rx.ofdm; |
95 | max_cck = &priv->max_delta.rx.cck; | 95 | max_cck = &priv->_agn.max_delta.rx.cck; |
96 | max_general = &priv->max_delta.rx.general; | 96 | max_general = &priv->_agn.max_delta.rx.general; |
97 | max_ht = &priv->max_delta.rx.ofdm_ht; | 97 | max_ht = &priv->_agn.max_delta.rx.ofdm_ht; |
98 | 98 | ||
99 | pos += iwl_statistics_flag(priv, buf, bufsz); | 99 | pos += iwl_statistics_flag(priv, buf, bufsz); |
100 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" | 100 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" |
@@ -560,10 +560,10 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file, | |||
560 | * the last statistics notification from uCode | 560 | * the last statistics notification from uCode |
561 | * might not reflect the current uCode activity | 561 | * might not reflect the current uCode activity |
562 | */ | 562 | */ |
563 | tx = &priv->statistics.tx; | 563 | tx = &priv->_agn.statistics.tx; |
564 | accum_tx = &priv->accum_statistics.tx; | 564 | accum_tx = &priv->_agn.accum_statistics.tx; |
565 | delta_tx = &priv->delta_statistics.tx; | 565 | delta_tx = &priv->_agn.delta_statistics.tx; |
566 | max_tx = &priv->max_delta.tx; | 566 | max_tx = &priv->_agn.max_delta.tx; |
567 | pos += iwl_statistics_flag(priv, buf, bufsz); | 567 | pos += iwl_statistics_flag(priv, buf, bufsz); |
568 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" | 568 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" |
569 | "acumulative delta max\n", | 569 | "acumulative delta max\n", |
@@ -777,18 +777,18 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, | |||
777 | * the last statistics notification from uCode | 777 | * the last statistics notification from uCode |
778 | * might not reflect the current uCode activity | 778 | * might not reflect the current uCode activity |
779 | */ | 779 | */ |
780 | general = &priv->statistics.general; | 780 | general = &priv->_agn.statistics.general; |
781 | dbg = &priv->statistics.general.dbg; | 781 | dbg = &priv->_agn.statistics.general.dbg; |
782 | div = &priv->statistics.general.div; | 782 | div = &priv->_agn.statistics.general.div; |
783 | accum_general = &priv->accum_statistics.general; | 783 | accum_general = &priv->_agn.accum_statistics.general; |
784 | delta_general = &priv->delta_statistics.general; | 784 | delta_general = &priv->_agn.delta_statistics.general; |
785 | max_general = &priv->max_delta.general; | 785 | max_general = &priv->_agn.max_delta.general; |
786 | accum_dbg = &priv->accum_statistics.general.dbg; | 786 | accum_dbg = &priv->_agn.accum_statistics.general.dbg; |
787 | delta_dbg = &priv->delta_statistics.general.dbg; | 787 | delta_dbg = &priv->_agn.delta_statistics.general.dbg; |
788 | max_dbg = &priv->max_delta.general.dbg; | 788 | max_dbg = &priv->_agn.max_delta.general.dbg; |
789 | accum_div = &priv->accum_statistics.general.div; | 789 | accum_div = &priv->_agn.accum_statistics.general.div; |
790 | delta_div = &priv->delta_statistics.general.div; | 790 | delta_div = &priv->_agn.delta_statistics.general.div; |
791 | max_div = &priv->max_delta.general.div; | 791 | max_div = &priv->_agn.max_delta.general.div; |
792 | pos += iwl_statistics_flag(priv, buf, bufsz); | 792 | pos += iwl_statistics_flag(priv, buf, bufsz); |
793 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" | 793 | pos += scnprintf(buf + pos, bufsz - pos, "%-32s current" |
794 | "acumulative delta max\n", | 794 | "acumulative delta max\n", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 3f765ba15cb8..f06d1feedf81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c | |||
@@ -214,11 +214,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) | |||
214 | static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info, | 214 | static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info, |
215 | __le32 *tx_flags) | 215 | __le32 *tx_flags) |
216 | { | 216 | { |
217 | if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || | 217 | *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK; |
218 | (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) | ||
219 | *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; | ||
220 | else | ||
221 | *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; | ||
222 | } | 218 | } |
223 | 219 | ||
224 | /* Calc max signal level (dBm) among 3 possible receivers */ | 220 | /* Calc max signal level (dBm) among 3 possible receivers */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 0e7b0661d61d..5f1e7d802cbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -361,7 +361,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) | |||
361 | void iwlagn_temperature(struct iwl_priv *priv) | 361 | void iwlagn_temperature(struct iwl_priv *priv) |
362 | { | 362 | { |
363 | /* store temperature from statistics (in Celsius) */ | 363 | /* store temperature from statistics (in Celsius) */ |
364 | priv->temperature = le32_to_cpu(priv->statistics.general.temperature); | 364 | priv->temperature = |
365 | le32_to_cpu(priv->_agn.statistics.general.temperature); | ||
365 | iwl_tt_handler(priv); | 366 | iwl_tt_handler(priv); |
366 | } | 367 | } |
367 | 368 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 40933a5de027..35c86d22b14b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -324,18 +324,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, | |||
324 | struct iwl_lq_sta *lq_data, | 324 | struct iwl_lq_sta *lq_data, |
325 | struct ieee80211_sta *sta) | 325 | struct ieee80211_sta *sta) |
326 | { | 326 | { |
327 | if ((tid < TID_MAX_LOAD_COUNT) && | 327 | if (tid < TID_MAX_LOAD_COUNT) |
328 | !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) { | 328 | rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); |
329 | if (priv->cfg->use_rts_for_ht) { | 329 | else |
330 | /* | 330 | IWL_ERR(priv, "tid exceeds max load count: %d/%d\n", |
331 | * switch to RTS/CTS if it is the prefer protection | 331 | tid, TID_MAX_LOAD_COUNT); |
332 | * method for HT traffic | ||
333 | */ | ||
334 | IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n"); | ||
335 | priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN; | ||
336 | iwlcore_commit_rxon(priv); | ||
337 | } | ||
338 | } | ||
339 | } | 332 | } |
340 | 333 | ||
341 | static inline int get_num_of_ant_from_rate(u32 rate_n_flags) | 334 | static inline int get_num_of_ant_from_rate(u32 rate_n_flags) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c new file mode 100644 index 000000000000..d54edc326f81 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * GPL LICENSE SUMMARY | ||
4 | * | ||
5 | * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
19 | * USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | * | ||
28 | *****************************************************************************/ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/sched.h> | ||
34 | |||
35 | #include "iwl-dev.h" | ||
36 | #include "iwl-core.h" | ||
37 | #include "iwl-calib.h" | ||
38 | #include "iwl-sta.h" | ||
39 | #include "iwl-io.h" | ||
40 | #include "iwl-helpers.h" | ||
41 | #include "iwl-agn-hw.h" | ||
42 | #include "iwl-agn.h" | ||
43 | |||
44 | void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | ||
45 | struct iwl_rx_mem_buffer *rxb) | ||
46 | |||
47 | { | ||
48 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
49 | struct iwl_missed_beacon_notif *missed_beacon; | ||
50 | |||
51 | missed_beacon = &pkt->u.missed_beacon; | ||
52 | if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > | ||
53 | priv->missed_beacon_threshold) { | ||
54 | IWL_DEBUG_CALIB(priv, | ||
55 | "missed bcn cnsq %d totl %d rcd %d expctd %d\n", | ||
56 | le32_to_cpu(missed_beacon->consecutive_missed_beacons), | ||
57 | le32_to_cpu(missed_beacon->total_missed_becons), | ||
58 | le32_to_cpu(missed_beacon->num_recvd_beacons), | ||
59 | le32_to_cpu(missed_beacon->num_expected_beacons)); | ||
60 | if (!test_bit(STATUS_SCANNING, &priv->status)) | ||
61 | iwl_init_sensitivity(priv); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | /* Calculate noise level, based on measurements during network silence just | ||
66 | * before arriving beacon. This measurement can be done only if we know | ||
67 | * exactly when to expect beacons, therefore only when we're associated. */ | ||
68 | static void iwl_rx_calc_noise(struct iwl_priv *priv) | ||
69 | { | ||
70 | struct statistics_rx_non_phy *rx_info | ||
71 | = &(priv->_agn.statistics.rx.general); | ||
72 | int num_active_rx = 0; | ||
73 | int total_silence = 0; | ||
74 | int bcn_silence_a = | ||
75 | le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; | ||
76 | int bcn_silence_b = | ||
77 | le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; | ||
78 | int bcn_silence_c = | ||
79 | le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; | ||
80 | int last_rx_noise; | ||
81 | |||
82 | if (bcn_silence_a) { | ||
83 | total_silence += bcn_silence_a; | ||
84 | num_active_rx++; | ||
85 | } | ||
86 | if (bcn_silence_b) { | ||
87 | total_silence += bcn_silence_b; | ||
88 | num_active_rx++; | ||
89 | } | ||
90 | if (bcn_silence_c) { | ||
91 | total_silence += bcn_silence_c; | ||
92 | num_active_rx++; | ||
93 | } | ||
94 | |||
95 | /* Average among active antennas */ | ||
96 | if (num_active_rx) | ||
97 | last_rx_noise = (total_silence / num_active_rx) - 107; | ||
98 | else | ||
99 | last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
100 | |||
101 | IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", | ||
102 | bcn_silence_a, bcn_silence_b, bcn_silence_c, | ||
103 | last_rx_noise); | ||
104 | } | ||
105 | |||
106 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
107 | /* | ||
108 | * based on the assumption of all statistics counter are in DWORD | ||
109 | * FIXME: This function is for debugging, do not deal with | ||
110 | * the case of counters roll-over. | ||
111 | */ | ||
112 | static void iwl_accumulative_statistics(struct iwl_priv *priv, | ||
113 | __le32 *stats) | ||
114 | { | ||
115 | int i; | ||
116 | __le32 *prev_stats; | ||
117 | u32 *accum_stats; | ||
118 | u32 *delta, *max_delta; | ||
119 | |||
120 | prev_stats = (__le32 *)&priv->_agn.statistics; | ||
121 | accum_stats = (u32 *)&priv->_agn.accum_statistics; | ||
122 | delta = (u32 *)&priv->_agn.delta_statistics; | ||
123 | max_delta = (u32 *)&priv->_agn.max_delta; | ||
124 | |||
125 | for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); | ||
126 | i += sizeof(__le32), stats++, prev_stats++, delta++, | ||
127 | max_delta++, accum_stats++) { | ||
128 | if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { | ||
129 | *delta = (le32_to_cpu(*stats) - | ||
130 | le32_to_cpu(*prev_stats)); | ||
131 | *accum_stats += *delta; | ||
132 | if (*delta > *max_delta) | ||
133 | *max_delta = *delta; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* reset accumulative statistics for "no-counter" type statistics */ | ||
138 | priv->_agn.accum_statistics.general.temperature = | ||
139 | priv->_agn.statistics.general.temperature; | ||
140 | priv->_agn.accum_statistics.general.temperature_m = | ||
141 | priv->_agn.statistics.general.temperature_m; | ||
142 | priv->_agn.accum_statistics.general.ttl_timestamp = | ||
143 | priv->_agn.statistics.general.ttl_timestamp; | ||
144 | priv->_agn.accum_statistics.tx.tx_power.ant_a = | ||
145 | priv->_agn.statistics.tx.tx_power.ant_a; | ||
146 | priv->_agn.accum_statistics.tx.tx_power.ant_b = | ||
147 | priv->_agn.statistics.tx.tx_power.ant_b; | ||
148 | priv->_agn.accum_statistics.tx.tx_power.ant_c = | ||
149 | priv->_agn.statistics.tx.tx_power.ant_c; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | #define REG_RECALIB_PERIOD (60) | ||
154 | |||
155 | /** | ||
156 | * iwl_good_plcp_health - checks for plcp error. | ||
157 | * | ||
158 | * When the plcp error is exceeding the thresholds, reset the radio | ||
159 | * to improve the throughput. | ||
160 | */ | ||
161 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
162 | struct iwl_rx_packet *pkt) | ||
163 | { | ||
164 | bool rc = true; | ||
165 | int combined_plcp_delta; | ||
166 | unsigned int plcp_msec; | ||
167 | unsigned long plcp_received_jiffies; | ||
168 | |||
169 | if (priv->cfg->plcp_delta_threshold == | ||
170 | IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { | ||
171 | IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); | ||
172 | return rc; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * check for plcp_err and trigger radio reset if it exceeds | ||
177 | * the plcp error threshold plcp_delta. | ||
178 | */ | ||
179 | plcp_received_jiffies = jiffies; | ||
180 | plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - | ||
181 | (long) priv->plcp_jiffies); | ||
182 | priv->plcp_jiffies = plcp_received_jiffies; | ||
183 | /* | ||
184 | * check to make sure plcp_msec is not 0 to prevent division | ||
185 | * by zero. | ||
186 | */ | ||
187 | if (plcp_msec) { | ||
188 | combined_plcp_delta = | ||
189 | (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) - | ||
190 | le32_to_cpu(priv->_agn.statistics.rx.ofdm.plcp_err)) + | ||
191 | (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) - | ||
192 | le32_to_cpu(priv->_agn.statistics.rx.ofdm_ht.plcp_err)); | ||
193 | |||
194 | if ((combined_plcp_delta > 0) && | ||
195 | ((combined_plcp_delta * 100) / plcp_msec) > | ||
196 | priv->cfg->plcp_delta_threshold) { | ||
197 | /* | ||
198 | * if plcp_err exceed the threshold, | ||
199 | * the following data is printed in csv format: | ||
200 | * Text: plcp_err exceeded %d, | ||
201 | * Received ofdm.plcp_err, | ||
202 | * Current ofdm.plcp_err, | ||
203 | * Received ofdm_ht.plcp_err, | ||
204 | * Current ofdm_ht.plcp_err, | ||
205 | * combined_plcp_delta, | ||
206 | * plcp_msec | ||
207 | */ | ||
208 | IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " | ||
209 | "%u, %u, %u, %u, %d, %u mSecs\n", | ||
210 | priv->cfg->plcp_delta_threshold, | ||
211 | le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), | ||
212 | le32_to_cpu( | ||
213 | priv->_agn.statistics.rx.ofdm.plcp_err), | ||
214 | le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), | ||
215 | le32_to_cpu( | ||
216 | priv->_agn.statistics.rx.ofdm_ht.plcp_err), | ||
217 | combined_plcp_delta, plcp_msec); | ||
218 | rc = false; | ||
219 | } | ||
220 | } | ||
221 | return rc; | ||
222 | } | ||
223 | |||
224 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
225 | struct iwl_rx_mem_buffer *rxb) | ||
226 | { | ||
227 | int change; | ||
228 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
229 | |||
230 | |||
231 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", | ||
232 | (int)sizeof(priv->_agn.statistics), | ||
233 | le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); | ||
234 | |||
235 | change = ((priv->_agn.statistics.general.temperature != | ||
236 | pkt->u.stats.general.temperature) || | ||
237 | ((priv->_agn.statistics.flag & | ||
238 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | ||
239 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | ||
240 | |||
241 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
242 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
243 | #endif | ||
244 | iwl_recover_from_statistics(priv, pkt); | ||
245 | |||
246 | memcpy(&priv->_agn.statistics, &pkt->u.stats, | ||
247 | sizeof(priv->_agn.statistics)); | ||
248 | |||
249 | set_bit(STATUS_STATISTICS, &priv->status); | ||
250 | |||
251 | /* Reschedule the statistics timer to occur in | ||
252 | * REG_RECALIB_PERIOD seconds to ensure we get a | ||
253 | * thermal update even if the uCode doesn't give | ||
254 | * us one */ | ||
255 | mod_timer(&priv->statistics_periodic, jiffies + | ||
256 | msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); | ||
257 | |||
258 | if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && | ||
259 | (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { | ||
260 | iwl_rx_calc_noise(priv); | ||
261 | queue_work(priv->workqueue, &priv->run_time_calib_work); | ||
262 | } | ||
263 | if (priv->cfg->ops->lib->temp_ops.temperature && change) | ||
264 | priv->cfg->ops->lib->temp_ops.temperature(priv); | ||
265 | } | ||
266 | |||
267 | void iwl_reply_statistics(struct iwl_priv *priv, | ||
268 | struct iwl_rx_mem_buffer *rxb) | ||
269 | { | ||
270 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
271 | |||
272 | if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { | ||
273 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
274 | memset(&priv->_agn.accum_statistics, 0, | ||
275 | sizeof(struct iwl_notif_statistics)); | ||
276 | memset(&priv->_agn.delta_statistics, 0, | ||
277 | sizeof(struct iwl_notif_statistics)); | ||
278 | memset(&priv->_agn.max_delta, 0, | ||
279 | sizeof(struct iwl_notif_statistics)); | ||
280 | #endif | ||
281 | IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); | ||
282 | } | ||
283 | iwl_rx_statistics(priv, rxb); | ||
284 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 84df7fca750d..2573234e4db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -233,6 +233,7 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
233 | { | 233 | { |
234 | unsigned long flags; | 234 | unsigned long flags; |
235 | u16 ra_tid; | 235 | u16 ra_tid; |
236 | int ret; | ||
236 | 237 | ||
237 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || | 238 | if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || |
238 | (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues | 239 | (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues |
@@ -248,7 +249,9 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
248 | ra_tid = BUILD_RAxTID(sta_id, tid); | 249 | ra_tid = BUILD_RAxTID(sta_id, tid); |
249 | 250 | ||
250 | /* Modify device's station table to Tx this TID */ | 251 | /* Modify device's station table to Tx this TID */ |
251 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); | 252 | ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); |
253 | if (ret) | ||
254 | return ret; | ||
252 | 255 | ||
253 | spin_lock_irqsave(&priv->lock, flags); | 256 | spin_lock_irqsave(&priv->lock, flags); |
254 | 257 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d857f8496f69..3368cfd25a99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1461,13 +1461,13 @@ bool iwl_good_ack_health(struct iwl_priv *priv, | |||
1461 | 1461 | ||
1462 | actual_ack_cnt_delta = | 1462 | actual_ack_cnt_delta = |
1463 | le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - | 1463 | le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - |
1464 | le32_to_cpu(priv->statistics.tx.actual_ack_cnt); | 1464 | le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt); |
1465 | expected_ack_cnt_delta = | 1465 | expected_ack_cnt_delta = |
1466 | le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) - | 1466 | le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) - |
1467 | le32_to_cpu(priv->statistics.tx.expected_ack_cnt); | 1467 | le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt); |
1468 | ba_timeout_delta = | 1468 | ba_timeout_delta = |
1469 | le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) - | 1469 | le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) - |
1470 | le32_to_cpu(priv->statistics.tx.agg.ba_timeout); | 1470 | le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout); |
1471 | if ((priv->_agn.agg_tids_count > 0) && | 1471 | if ((priv->_agn.agg_tids_count > 0) && |
1472 | (expected_ack_cnt_delta > 0) && | 1472 | (expected_ack_cnt_delta > 0) && |
1473 | (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) | 1473 | (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) |
@@ -1484,10 +1484,10 @@ bool iwl_good_ack_health(struct iwl_priv *priv, | |||
1484 | * DEBUG is not, these will just compile out. | 1484 | * DEBUG is not, these will just compile out. |
1485 | */ | 1485 | */ |
1486 | IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", | 1486 | IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", |
1487 | priv->delta_statistics.tx.rx_detected_cnt); | 1487 | priv->_agn.delta_statistics.tx.rx_detected_cnt); |
1488 | IWL_DEBUG_RADIO(priv, | 1488 | IWL_DEBUG_RADIO(priv, |
1489 | "ack_or_ba_timeout_collision delta = %d\n", | 1489 | "ack_or_ba_timeout_collision delta = %d\n", |
1490 | priv->delta_statistics.tx. | 1490 | priv->_agn.delta_statistics.tx. |
1491 | ack_or_ba_timeout_collision); | 1491 | ack_or_ba_timeout_collision); |
1492 | #endif | 1492 | #endif |
1493 | IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", | 1493 | IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", |
@@ -2310,9 +2310,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
2310 | trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, | 2310 | trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, |
2311 | blink1, blink2, ilink1, ilink2); | 2311 | blink1, blink2, ilink1, ilink2); |
2312 | 2312 | ||
2313 | IWL_ERR(priv, "Desc Time " | 2313 | IWL_ERR(priv, "Desc Time " |
2314 | "data1 data2 line\n"); | 2314 | "data1 data2 line\n"); |
2315 | IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", | 2315 | IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n", |
2316 | desc_lookup(desc), desc, time, data1, data2, line); | 2316 | desc_lookup(desc), desc, time, data1, data2, line); |
2317 | IWL_ERR(priv, "pc blink1 blink2 ilink1 ilink2 hcmd\n"); | 2317 | IWL_ERR(priv, "pc blink1 blink2 ilink1 ilink2 hcmd\n"); |
2318 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n", | 2318 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n", |
@@ -2935,9 +2935,9 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) | |||
2935 | } | 2935 | } |
2936 | 2936 | ||
2937 | if (priv->start_calib) { | 2937 | if (priv->start_calib) { |
2938 | iwl_chain_noise_calibration(priv, &priv->statistics); | 2938 | iwl_chain_noise_calibration(priv, &priv->_agn.statistics); |
2939 | 2939 | ||
2940 | iwl_sensitivity_calibration(priv, &priv->statistics); | 2940 | iwl_sensitivity_calibration(priv, &priv->_agn.statistics); |
2941 | } | 2941 | } |
2942 | 2942 | ||
2943 | mutex_unlock(&priv->mutex); | 2943 | mutex_unlock(&priv->mutex); |
@@ -3368,13 +3368,32 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3368 | return ret; | 3368 | return ret; |
3369 | } | 3369 | } |
3370 | 3370 | ||
3371 | /* | ||
3372 | * switch to RTS/CTS for TX | ||
3373 | */ | ||
3374 | static void iwl_enable_rts_cts(struct iwl_priv *priv) | ||
3375 | { | ||
3376 | |||
3377 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
3378 | return; | ||
3379 | |||
3380 | priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN; | ||
3381 | if (!test_bit(STATUS_SCANNING, &priv->status)) { | ||
3382 | IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n"); | ||
3383 | iwlcore_commit_rxon(priv); | ||
3384 | } else { | ||
3385 | /* scanning, defer the request until scan completed */ | ||
3386 | IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n"); | ||
3387 | } | ||
3388 | } | ||
3389 | |||
3371 | static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | 3390 | static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, |
3372 | struct ieee80211_vif *vif, | 3391 | struct ieee80211_vif *vif, |
3373 | enum ieee80211_ampdu_mlme_action action, | 3392 | enum ieee80211_ampdu_mlme_action action, |
3374 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 3393 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
3375 | { | 3394 | { |
3376 | struct iwl_priv *priv = hw->priv; | 3395 | struct iwl_priv *priv = hw->priv; |
3377 | int ret; | 3396 | int ret = -EINVAL; |
3378 | 3397 | ||
3379 | IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", | 3398 | IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", |
3380 | sta->addr, tid); | 3399 | sta->addr, tid); |
@@ -3382,17 +3401,19 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
3382 | if (!(priv->cfg->sku & IWL_SKU_N)) | 3401 | if (!(priv->cfg->sku & IWL_SKU_N)) |
3383 | return -EACCES; | 3402 | return -EACCES; |
3384 | 3403 | ||
3404 | mutex_lock(&priv->mutex); | ||
3405 | |||
3385 | switch (action) { | 3406 | switch (action) { |
3386 | case IEEE80211_AMPDU_RX_START: | 3407 | case IEEE80211_AMPDU_RX_START: |
3387 | IWL_DEBUG_HT(priv, "start Rx\n"); | 3408 | IWL_DEBUG_HT(priv, "start Rx\n"); |
3388 | return iwl_sta_rx_agg_start(priv, sta, tid, *ssn); | 3409 | ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); |
3410 | break; | ||
3389 | case IEEE80211_AMPDU_RX_STOP: | 3411 | case IEEE80211_AMPDU_RX_STOP: |
3390 | IWL_DEBUG_HT(priv, "stop Rx\n"); | 3412 | IWL_DEBUG_HT(priv, "stop Rx\n"); |
3391 | ret = iwl_sta_rx_agg_stop(priv, sta, tid); | 3413 | ret = iwl_sta_rx_agg_stop(priv, sta, tid); |
3392 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 3414 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
3393 | return 0; | 3415 | ret = 0; |
3394 | else | 3416 | break; |
3395 | return ret; | ||
3396 | case IEEE80211_AMPDU_TX_START: | 3417 | case IEEE80211_AMPDU_TX_START: |
3397 | IWL_DEBUG_HT(priv, "start Tx\n"); | 3418 | IWL_DEBUG_HT(priv, "start Tx\n"); |
3398 | ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); | 3419 | ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); |
@@ -3401,7 +3422,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
3401 | IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", | 3422 | IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", |
3402 | priv->_agn.agg_tids_count); | 3423 | priv->_agn.agg_tids_count); |
3403 | } | 3424 | } |
3404 | return ret; | 3425 | break; |
3405 | case IEEE80211_AMPDU_TX_STOP: | 3426 | case IEEE80211_AMPDU_TX_STOP: |
3406 | IWL_DEBUG_HT(priv, "stop Tx\n"); | 3427 | IWL_DEBUG_HT(priv, "stop Tx\n"); |
3407 | ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); | 3428 | ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); |
@@ -3411,18 +3432,22 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
3411 | priv->_agn.agg_tids_count); | 3432 | priv->_agn.agg_tids_count); |
3412 | } | 3433 | } |
3413 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 3434 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
3414 | return 0; | 3435 | ret = 0; |
3415 | else | 3436 | break; |
3416 | return ret; | ||
3417 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 3437 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
3418 | /* do nothing */ | 3438 | if (priv->cfg->use_rts_for_ht) { |
3419 | return -EOPNOTSUPP; | 3439 | /* |
3420 | default: | 3440 | * switch to RTS/CTS if it is the prefer protection |
3421 | IWL_DEBUG_HT(priv, "unknown\n"); | 3441 | * method for HT traffic |
3422 | return -EINVAL; | 3442 | */ |
3443 | iwl_enable_rts_cts(priv); | ||
3444 | } | ||
3445 | ret = 0; | ||
3423 | break; | 3446 | break; |
3424 | } | 3447 | } |
3425 | return 0; | 3448 | mutex_unlock(&priv->mutex); |
3449 | |||
3450 | return ret; | ||
3426 | } | 3451 | } |
3427 | 3452 | ||
3428 | static void iwl_mac_sta_notify(struct ieee80211_hw *hw, | 3453 | static void iwl_mac_sta_notify(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5c32777b0a49..be9d298cae2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -201,6 +201,16 @@ static inline bool iwl_is_tx_success(u32 status) | |||
201 | (status == TX_STATUS_DIRECT_DONE); | 201 | (status == TX_STATUS_DIRECT_DONE); |
202 | } | 202 | } |
203 | 203 | ||
204 | /* rx */ | ||
205 | void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | ||
206 | struct iwl_rx_mem_buffer *rxb); | ||
207 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
208 | struct iwl_rx_packet *pkt); | ||
209 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
210 | struct iwl_rx_mem_buffer *rxb); | ||
211 | void iwl_reply_statistics(struct iwl_priv *priv, | ||
212 | struct iwl_rx_mem_buffer *rxb); | ||
213 | |||
204 | /* scan */ | 214 | /* scan */ |
205 | void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); | 215 | void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); |
206 | 216 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 28b1098334f7..acf8e980b1fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -1399,18 +1399,27 @@ struct iwl_rx_mpdu_res_start { | |||
1399 | 1399 | ||
1400 | /* REPLY_TX Tx flags field */ | 1400 | /* REPLY_TX Tx flags field */ |
1401 | 1401 | ||
1402 | /* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it | 1402 | /* |
1403 | * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it | ||
1403 | * before this frame. if CTS-to-self required check | 1404 | * before this frame. if CTS-to-self required check |
1404 | * RXON_FLG_SELF_CTS_EN status. */ | 1405 | * RXON_FLG_SELF_CTS_EN status. |
1405 | #define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0) | 1406 | * unused in 3945/4965, used in 5000 series and after |
1407 | */ | ||
1408 | #define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0) | ||
1406 | 1409 | ||
1407 | /* 1: Use Request-To-Send protocol before this frame. | 1410 | /* |
1408 | * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ | 1411 | * 1: Use Request-To-Send protocol before this frame. |
1412 | * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. | ||
1413 | * used in 3945/4965, unused in 5000 series and after | ||
1414 | */ | ||
1409 | #define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) | 1415 | #define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) |
1410 | 1416 | ||
1411 | /* 1: Transmit Clear-To-Send to self before this frame. | 1417 | /* |
1418 | * 1: Transmit Clear-To-Send to self before this frame. | ||
1412 | * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. | 1419 | * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. |
1413 | * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ | 1420 | * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. |
1421 | * used in 3945/4965, unused in 5000 series and after | ||
1422 | */ | ||
1414 | #define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) | 1423 | #define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) |
1415 | 1424 | ||
1416 | /* 1: Expect ACK from receiving station | 1425 | /* 1: Expect ACK from receiving station |
@@ -1430,8 +1439,11 @@ struct iwl_rx_mpdu_res_start { | |||
1430 | * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ | 1439 | * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ |
1431 | #define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) | 1440 | #define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) |
1432 | 1441 | ||
1433 | /* 1: Frame requires full Tx-Op protection. | 1442 | /* |
1434 | * Set this if either RTS or CTS Tx Flag gets set. */ | 1443 | * 1: Frame requires full Tx-Op protection. |
1444 | * Set this if either RTS or CTS Tx Flag gets set. | ||
1445 | * used in 3945/4965, unused in 5000 series and after | ||
1446 | */ | ||
1435 | #define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) | 1447 | #define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) |
1436 | 1448 | ||
1437 | /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. | 1449 | /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 62c50bc0089a..a56fb466d0b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1331,7 +1331,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, | |||
1331 | changed_flags, *total_flags); | 1331 | changed_flags, *total_flags); |
1332 | 1332 | ||
1333 | CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); | 1333 | CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); |
1334 | CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK); | ||
1335 | CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); | 1334 | CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); |
1336 | CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); | 1335 | CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); |
1337 | 1336 | ||
@@ -1346,6 +1345,12 @@ void iwl_configure_filter(struct ieee80211_hw *hw, | |||
1346 | 1345 | ||
1347 | mutex_unlock(&priv->mutex); | 1346 | mutex_unlock(&priv->mutex); |
1348 | 1347 | ||
1348 | /* | ||
1349 | * Receiving all multicast frames is always enabled by the | ||
1350 | * default flags setup in iwl_connection_init_rx_config() | ||
1351 | * since we currently do not support programming multicast | ||
1352 | * filters into the device. | ||
1353 | */ | ||
1349 | *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | | 1354 | *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | |
1350 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; | 1355 | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; |
1351 | } | 1356 | } |
@@ -2105,6 +2110,9 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2105 | iwl_set_flags_for_band(priv, conf->channel->band, priv->vif); | 2110 | iwl_set_flags_for_band(priv, conf->channel->band, priv->vif); |
2106 | spin_unlock_irqrestore(&priv->lock, flags); | 2111 | spin_unlock_irqrestore(&priv->lock, flags); |
2107 | 2112 | ||
2113 | if (priv->cfg->ops->lib->update_bcast_station) | ||
2114 | ret = priv->cfg->ops->lib->update_bcast_station(priv); | ||
2115 | |||
2108 | set_ch_out: | 2116 | set_ch_out: |
2109 | /* The list of supported rates and rate mask can be different | 2117 | /* The list of supported rates and rate mask can be different |
2110 | * for each band; since the band may have changed, reset | 2118 | * for each band; since the band may have changed, reset |
@@ -2837,6 +2845,7 @@ int iwl_pci_resume(struct pci_dev *pdev) | |||
2837 | { | 2845 | { |
2838 | struct iwl_priv *priv = pci_get_drvdata(pdev); | 2846 | struct iwl_priv *priv = pci_get_drvdata(pdev); |
2839 | int ret; | 2847 | int ret; |
2848 | bool hw_rfkill = false; | ||
2840 | 2849 | ||
2841 | /* | 2850 | /* |
2842 | * We disable the RETRY_TIMEOUT register (0x41) to keep | 2851 | * We disable the RETRY_TIMEOUT register (0x41) to keep |
@@ -2851,6 +2860,17 @@ int iwl_pci_resume(struct pci_dev *pdev) | |||
2851 | pci_restore_state(pdev); | 2860 | pci_restore_state(pdev); |
2852 | iwl_enable_interrupts(priv); | 2861 | iwl_enable_interrupts(priv); |
2853 | 2862 | ||
2863 | if (!(iwl_read32(priv, CSR_GP_CNTRL) & | ||
2864 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) | ||
2865 | hw_rfkill = true; | ||
2866 | |||
2867 | if (hw_rfkill) | ||
2868 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
2869 | else | ||
2870 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
2871 | |||
2872 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill); | ||
2873 | |||
2854 | return 0; | 2874 | return 0; |
2855 | } | 2875 | } |
2856 | EXPORT_SYMBOL(iwl_pci_resume); | 2876 | EXPORT_SYMBOL(iwl_pci_resume); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 76288c56a7d7..15930e064022 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -196,6 +196,7 @@ struct iwl_lib_ops { | |||
196 | /* station management */ | 196 | /* station management */ |
197 | int (*manage_ibss_station)(struct iwl_priv *priv, | 197 | int (*manage_ibss_station)(struct iwl_priv *priv, |
198 | struct ieee80211_vif *vif, bool add); | 198 | struct ieee80211_vif *vif, bool add); |
199 | int (*update_bcast_station)(struct iwl_priv *priv); | ||
199 | /* recover from tx queue stall */ | 200 | /* recover from tx queue stall */ |
200 | void (*recover_from_tx_stall)(unsigned long data); | 201 | void (*recover_from_tx_stall)(unsigned long data); |
201 | /* check for plcp health */ | 202 | /* check for plcp health */ |
@@ -330,6 +331,7 @@ struct iwl_cfg { | |||
330 | const bool chain_noise_calib_by_driver; | 331 | const bool chain_noise_calib_by_driver; |
331 | u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; | 332 | u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; |
332 | u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; | 333 | u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; |
334 | const bool need_dc_calib; | ||
333 | }; | 335 | }; |
334 | 336 | ||
335 | /*************************** | 337 | /*************************** |
@@ -455,20 +457,10 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, | |||
455 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); | 457 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); |
456 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | 458 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); |
457 | /* Handlers */ | 459 | /* Handlers */ |
458 | void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | ||
459 | struct iwl_rx_mem_buffer *rxb); | ||
460 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | 460 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, |
461 | struct iwl_rx_mem_buffer *rxb); | 461 | struct iwl_rx_mem_buffer *rxb); |
462 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
463 | struct iwl_rx_packet *pkt); | ||
464 | bool iwl_good_ack_health(struct iwl_priv *priv, | ||
465 | struct iwl_rx_packet *pkt); | ||
466 | void iwl_recover_from_statistics(struct iwl_priv *priv, | 462 | void iwl_recover_from_statistics(struct iwl_priv *priv, |
467 | struct iwl_rx_packet *pkt); | 463 | struct iwl_rx_packet *pkt); |
468 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
469 | struct iwl_rx_mem_buffer *rxb); | ||
470 | void iwl_reply_statistics(struct iwl_priv *priv, | ||
471 | struct iwl_rx_mem_buffer *rxb); | ||
472 | void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); | 464 | void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); |
473 | void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | 465 | void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); |
474 | 466 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index cee3d12eb383..7d9ffc1575de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -1430,10 +1430,10 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, | |||
1430 | return -EFAULT; | 1430 | return -EFAULT; |
1431 | if (sscanf(buf, "%d", &plcp) != 1) | 1431 | if (sscanf(buf, "%d", &plcp) != 1) |
1432 | return -EINVAL; | 1432 | return -EINVAL; |
1433 | if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || | 1433 | if ((plcp < IWL_MAX_PLCP_ERR_THRESHOLD_MIN) || |
1434 | (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) | 1434 | (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX)) |
1435 | priv->cfg->plcp_delta_threshold = | 1435 | priv->cfg->plcp_delta_threshold = |
1436 | IWL_MAX_PLCP_ERR_THRESHOLD_DEF; | 1436 | IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE; |
1437 | else | 1437 | else |
1438 | priv->cfg->plcp_delta_threshold = plcp; | 1438 | priv->cfg->plcp_delta_threshold = plcp; |
1439 | return count; | 1439 | return count; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 338b5177029d..728752aa1bb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1036,11 +1036,12 @@ struct iwl_event_log { | |||
1036 | * This is the threshold value of plcp error rate per 100mSecs. It is | 1036 | * This is the threshold value of plcp error rate per 100mSecs. It is |
1037 | * used to set and check for the validity of plcp_delta. | 1037 | * used to set and check for the validity of plcp_delta. |
1038 | */ | 1038 | */ |
1039 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (0) | 1039 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (1) |
1040 | #define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) | 1040 | #define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) |
1041 | #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) | 1041 | #define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) |
1042 | #define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200) | 1042 | #define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200) |
1043 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) | 1043 | #define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) |
1044 | #define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE (0) | ||
1044 | 1045 | ||
1045 | #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) | 1046 | #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) |
1046 | #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) | 1047 | #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) |
@@ -1224,13 +1225,6 @@ struct iwl_priv { | |||
1224 | struct iwl_power_mgr power_data; | 1225 | struct iwl_power_mgr power_data; |
1225 | struct iwl_tt_mgmt thermal_throttle; | 1226 | struct iwl_tt_mgmt thermal_throttle; |
1226 | 1227 | ||
1227 | struct iwl_notif_statistics statistics; | ||
1228 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1229 | struct iwl_notif_statistics accum_statistics; | ||
1230 | struct iwl_notif_statistics delta_statistics; | ||
1231 | struct iwl_notif_statistics max_delta; | ||
1232 | #endif | ||
1233 | |||
1234 | /* context information */ | 1228 | /* context information */ |
1235 | u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ | 1229 | u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ |
1236 | 1230 | ||
@@ -1323,6 +1317,13 @@ struct iwl_priv { | |||
1323 | 1317 | ||
1324 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; | 1318 | u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; |
1325 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; | 1319 | u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; |
1320 | |||
1321 | struct iwl_notif_statistics statistics; | ||
1322 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1323 | struct iwl_notif_statistics accum_statistics; | ||
1324 | struct iwl_notif_statistics delta_statistics; | ||
1325 | struct iwl_notif_statistics max_delta; | ||
1326 | #endif | ||
1326 | } _agn; | 1327 | } _agn; |
1327 | #endif | 1328 | #endif |
1328 | }; | 1329 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ee11452519e6..a45d02e555cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -629,6 +629,9 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) | |||
629 | calib_ver < priv->cfg->eeprom_calib_ver) | 629 | calib_ver < priv->cfg->eeprom_calib_ver) |
630 | goto err; | 630 | goto err; |
631 | 631 | ||
632 | IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", | ||
633 | eeprom_ver, calib_ver); | ||
634 | |||
632 | return 0; | 635 | return 0; |
633 | err: | 636 | err: |
634 | IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", | 637 | IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 86a353765796..b437f317b979 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -205,26 +205,6 @@ err_bd: | |||
205 | } | 205 | } |
206 | EXPORT_SYMBOL(iwl_rx_queue_alloc); | 206 | EXPORT_SYMBOL(iwl_rx_queue_alloc); |
207 | 207 | ||
208 | void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | ||
209 | struct iwl_rx_mem_buffer *rxb) | ||
210 | |||
211 | { | ||
212 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
213 | struct iwl_missed_beacon_notif *missed_beacon; | ||
214 | |||
215 | missed_beacon = &pkt->u.missed_beacon; | ||
216 | if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > | ||
217 | priv->missed_beacon_threshold) { | ||
218 | IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n", | ||
219 | le32_to_cpu(missed_beacon->consecutive_missed_beacons), | ||
220 | le32_to_cpu(missed_beacon->total_missed_becons), | ||
221 | le32_to_cpu(missed_beacon->num_recvd_beacons), | ||
222 | le32_to_cpu(missed_beacon->num_expected_beacons)); | ||
223 | if (!test_bit(STATUS_SCANNING, &priv->status)) | ||
224 | iwl_init_sensitivity(priv); | ||
225 | } | ||
226 | } | ||
227 | EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); | ||
228 | 208 | ||
229 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | 209 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, |
230 | struct iwl_rx_mem_buffer *rxb) | 210 | struct iwl_rx_mem_buffer *rxb) |
@@ -243,161 +223,6 @@ void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | |||
243 | } | 223 | } |
244 | EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); | 224 | EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif); |
245 | 225 | ||
246 | |||
247 | |||
248 | /* Calculate noise level, based on measurements during network silence just | ||
249 | * before arriving beacon. This measurement can be done only if we know | ||
250 | * exactly when to expect beacons, therefore only when we're associated. */ | ||
251 | static void iwl_rx_calc_noise(struct iwl_priv *priv) | ||
252 | { | ||
253 | struct statistics_rx_non_phy *rx_info | ||
254 | = &(priv->statistics.rx.general); | ||
255 | int num_active_rx = 0; | ||
256 | int total_silence = 0; | ||
257 | int bcn_silence_a = | ||
258 | le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; | ||
259 | int bcn_silence_b = | ||
260 | le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; | ||
261 | int bcn_silence_c = | ||
262 | le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; | ||
263 | int last_rx_noise; | ||
264 | |||
265 | if (bcn_silence_a) { | ||
266 | total_silence += bcn_silence_a; | ||
267 | num_active_rx++; | ||
268 | } | ||
269 | if (bcn_silence_b) { | ||
270 | total_silence += bcn_silence_b; | ||
271 | num_active_rx++; | ||
272 | } | ||
273 | if (bcn_silence_c) { | ||
274 | total_silence += bcn_silence_c; | ||
275 | num_active_rx++; | ||
276 | } | ||
277 | |||
278 | /* Average among active antennas */ | ||
279 | if (num_active_rx) | ||
280 | last_rx_noise = (total_silence / num_active_rx) - 107; | ||
281 | else | ||
282 | last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
283 | |||
284 | IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", | ||
285 | bcn_silence_a, bcn_silence_b, bcn_silence_c, | ||
286 | last_rx_noise); | ||
287 | } | ||
288 | |||
289 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
290 | /* | ||
291 | * based on the assumption of all statistics counter are in DWORD | ||
292 | * FIXME: This function is for debugging, do not deal with | ||
293 | * the case of counters roll-over. | ||
294 | */ | ||
295 | static void iwl_accumulative_statistics(struct iwl_priv *priv, | ||
296 | __le32 *stats) | ||
297 | { | ||
298 | int i; | ||
299 | __le32 *prev_stats; | ||
300 | u32 *accum_stats; | ||
301 | u32 *delta, *max_delta; | ||
302 | |||
303 | prev_stats = (__le32 *)&priv->statistics; | ||
304 | accum_stats = (u32 *)&priv->accum_statistics; | ||
305 | delta = (u32 *)&priv->delta_statistics; | ||
306 | max_delta = (u32 *)&priv->max_delta; | ||
307 | |||
308 | for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); | ||
309 | i += sizeof(__le32), stats++, prev_stats++, delta++, | ||
310 | max_delta++, accum_stats++) { | ||
311 | if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { | ||
312 | *delta = (le32_to_cpu(*stats) - | ||
313 | le32_to_cpu(*prev_stats)); | ||
314 | *accum_stats += *delta; | ||
315 | if (*delta > *max_delta) | ||
316 | *max_delta = *delta; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /* reset accumulative statistics for "no-counter" type statistics */ | ||
321 | priv->accum_statistics.general.temperature = | ||
322 | priv->statistics.general.temperature; | ||
323 | priv->accum_statistics.general.temperature_m = | ||
324 | priv->statistics.general.temperature_m; | ||
325 | priv->accum_statistics.general.ttl_timestamp = | ||
326 | priv->statistics.general.ttl_timestamp; | ||
327 | priv->accum_statistics.tx.tx_power.ant_a = | ||
328 | priv->statistics.tx.tx_power.ant_a; | ||
329 | priv->accum_statistics.tx.tx_power.ant_b = | ||
330 | priv->statistics.tx.tx_power.ant_b; | ||
331 | priv->accum_statistics.tx.tx_power.ant_c = | ||
332 | priv->statistics.tx.tx_power.ant_c; | ||
333 | } | ||
334 | #endif | ||
335 | |||
336 | #define REG_RECALIB_PERIOD (60) | ||
337 | |||
338 | /** | ||
339 | * iwl_good_plcp_health - checks for plcp error. | ||
340 | * | ||
341 | * When the plcp error is exceeding the thresholds, reset the radio | ||
342 | * to improve the throughput. | ||
343 | */ | ||
344 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
345 | struct iwl_rx_packet *pkt) | ||
346 | { | ||
347 | bool rc = true; | ||
348 | int combined_plcp_delta; | ||
349 | unsigned int plcp_msec; | ||
350 | unsigned long plcp_received_jiffies; | ||
351 | |||
352 | /* | ||
353 | * check for plcp_err and trigger radio reset if it exceeds | ||
354 | * the plcp error threshold plcp_delta. | ||
355 | */ | ||
356 | plcp_received_jiffies = jiffies; | ||
357 | plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - | ||
358 | (long) priv->plcp_jiffies); | ||
359 | priv->plcp_jiffies = plcp_received_jiffies; | ||
360 | /* | ||
361 | * check to make sure plcp_msec is not 0 to prevent division | ||
362 | * by zero. | ||
363 | */ | ||
364 | if (plcp_msec) { | ||
365 | combined_plcp_delta = | ||
366 | (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) - | ||
367 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) + | ||
368 | (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) - | ||
369 | le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); | ||
370 | |||
371 | if ((combined_plcp_delta > 0) && | ||
372 | ((combined_plcp_delta * 100) / plcp_msec) > | ||
373 | priv->cfg->plcp_delta_threshold) { | ||
374 | /* | ||
375 | * if plcp_err exceed the threshold, | ||
376 | * the following data is printed in csv format: | ||
377 | * Text: plcp_err exceeded %d, | ||
378 | * Received ofdm.plcp_err, | ||
379 | * Current ofdm.plcp_err, | ||
380 | * Received ofdm_ht.plcp_err, | ||
381 | * Current ofdm_ht.plcp_err, | ||
382 | * combined_plcp_delta, | ||
383 | * plcp_msec | ||
384 | */ | ||
385 | IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " | ||
386 | "%u, %u, %u, %u, %d, %u mSecs\n", | ||
387 | priv->cfg->plcp_delta_threshold, | ||
388 | le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), | ||
389 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), | ||
390 | le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), | ||
391 | le32_to_cpu( | ||
392 | priv->statistics.rx.ofdm_ht.plcp_err), | ||
393 | combined_plcp_delta, plcp_msec); | ||
394 | rc = false; | ||
395 | } | ||
396 | } | ||
397 | return rc; | ||
398 | } | ||
399 | EXPORT_SYMBOL(iwl_good_plcp_health); | ||
400 | |||
401 | void iwl_recover_from_statistics(struct iwl_priv *priv, | 226 | void iwl_recover_from_statistics(struct iwl_priv *priv, |
402 | struct iwl_rx_packet *pkt) | 227 | struct iwl_rx_packet *pkt) |
403 | { | 228 | { |
@@ -431,69 +256,6 @@ void iwl_recover_from_statistics(struct iwl_priv *priv, | |||
431 | } | 256 | } |
432 | EXPORT_SYMBOL(iwl_recover_from_statistics); | 257 | EXPORT_SYMBOL(iwl_recover_from_statistics); |
433 | 258 | ||
434 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
435 | struct iwl_rx_mem_buffer *rxb) | ||
436 | { | ||
437 | int change; | ||
438 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
439 | |||
440 | |||
441 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", | ||
442 | (int)sizeof(priv->statistics), | ||
443 | le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); | ||
444 | |||
445 | change = ((priv->statistics.general.temperature != | ||
446 | pkt->u.stats.general.temperature) || | ||
447 | ((priv->statistics.flag & | ||
448 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | ||
449 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | ||
450 | |||
451 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
452 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
453 | #endif | ||
454 | iwl_recover_from_statistics(priv, pkt); | ||
455 | |||
456 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); | ||
457 | |||
458 | set_bit(STATUS_STATISTICS, &priv->status); | ||
459 | |||
460 | /* Reschedule the statistics timer to occur in | ||
461 | * REG_RECALIB_PERIOD seconds to ensure we get a | ||
462 | * thermal update even if the uCode doesn't give | ||
463 | * us one */ | ||
464 | mod_timer(&priv->statistics_periodic, jiffies + | ||
465 | msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); | ||
466 | |||
467 | if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && | ||
468 | (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { | ||
469 | iwl_rx_calc_noise(priv); | ||
470 | queue_work(priv->workqueue, &priv->run_time_calib_work); | ||
471 | } | ||
472 | if (priv->cfg->ops->lib->temp_ops.temperature && change) | ||
473 | priv->cfg->ops->lib->temp_ops.temperature(priv); | ||
474 | } | ||
475 | EXPORT_SYMBOL(iwl_rx_statistics); | ||
476 | |||
477 | void iwl_reply_statistics(struct iwl_priv *priv, | ||
478 | struct iwl_rx_mem_buffer *rxb) | ||
479 | { | ||
480 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
481 | |||
482 | if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { | ||
483 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
484 | memset(&priv->accum_statistics, 0, | ||
485 | sizeof(struct iwl_notif_statistics)); | ||
486 | memset(&priv->delta_statistics, 0, | ||
487 | sizeof(struct iwl_notif_statistics)); | ||
488 | memset(&priv->max_delta, 0, | ||
489 | sizeof(struct iwl_notif_statistics)); | ||
490 | #endif | ||
491 | IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); | ||
492 | } | ||
493 | iwl_rx_statistics(priv, rxb); | ||
494 | } | ||
495 | EXPORT_SYMBOL(iwl_reply_statistics); | ||
496 | |||
497 | /* | 259 | /* |
498 | * returns non-zero if packet should be dropped | 260 | * returns non-zero if packet should be dropped |
499 | */ | 261 | */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 798f93e0ff50..2a7c399fee1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -537,6 +537,15 @@ void iwl_bg_scan_completed(struct work_struct *work) | |||
537 | /* Since setting the TXPOWER may have been deferred while | 537 | /* Since setting the TXPOWER may have been deferred while |
538 | * performing the scan, fire one off */ | 538 | * performing the scan, fire one off */ |
539 | iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); | 539 | iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); |
540 | |||
541 | /* | ||
542 | * Since setting the RXON may have been deferred while | ||
543 | * performing the scan, fire one off if needed | ||
544 | */ | ||
545 | if (memcmp(&priv->active_rxon, | ||
546 | &priv->staging_rxon, sizeof(priv->staging_rxon))) | ||
547 | iwlcore_commit_rxon(priv); | ||
548 | |||
540 | out: | 549 | out: |
541 | mutex_unlock(&priv->mutex); | 550 | mutex_unlock(&priv->mutex); |
542 | 551 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index d57df6c02db3..9511f03f07e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/mac80211.h> | 30 | #include <net/mac80211.h> |
31 | #include <linux/etherdevice.h> | 31 | #include <linux/etherdevice.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/lockdep.h> | ||
33 | 34 | ||
34 | #include "iwl-dev.h" | 35 | #include "iwl-dev.h" |
35 | #include "iwl-core.h" | 36 | #include "iwl-core.h" |
@@ -54,18 +55,19 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) | |||
54 | } | 55 | } |
55 | } | 56 | } |
56 | 57 | ||
57 | static void iwl_process_add_sta_resp(struct iwl_priv *priv, | 58 | static int iwl_process_add_sta_resp(struct iwl_priv *priv, |
58 | struct iwl_addsta_cmd *addsta, | 59 | struct iwl_addsta_cmd *addsta, |
59 | struct iwl_rx_packet *pkt, | 60 | struct iwl_rx_packet *pkt, |
60 | bool sync) | 61 | bool sync) |
61 | { | 62 | { |
62 | u8 sta_id = addsta->sta.sta_id; | 63 | u8 sta_id = addsta->sta.sta_id; |
63 | unsigned long flags; | 64 | unsigned long flags; |
65 | int ret = -EIO; | ||
64 | 66 | ||
65 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | 67 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { |
66 | IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", | 68 | IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", |
67 | pkt->hdr.flags); | 69 | pkt->hdr.flags); |
68 | return; | 70 | return ret; |
69 | } | 71 | } |
70 | 72 | ||
71 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | 73 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", |
@@ -77,6 +79,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
77 | case ADD_STA_SUCCESS_MSK: | 79 | case ADD_STA_SUCCESS_MSK: |
78 | IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); | 80 | IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); |
79 | iwl_sta_ucode_activate(priv, sta_id); | 81 | iwl_sta_ucode_activate(priv, sta_id); |
82 | ret = 0; | ||
80 | break; | 83 | break; |
81 | case ADD_STA_NO_ROOM_IN_TABLE: | 84 | case ADD_STA_NO_ROOM_IN_TABLE: |
82 | IWL_ERR(priv, "Adding station %d failed, no room in table.\n", | 85 | IWL_ERR(priv, "Adding station %d failed, no room in table.\n", |
@@ -114,6 +117,8 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
114 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 117 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
115 | addsta->sta.addr); | 118 | addsta->sta.addr); |
116 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 119 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
120 | |||
121 | return ret; | ||
117 | } | 122 | } |
118 | 123 | ||
119 | static void iwl_add_sta_callback(struct iwl_priv *priv, | 124 | static void iwl_add_sta_callback(struct iwl_priv *priv, |
@@ -145,8 +150,10 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
145 | 150 | ||
146 | if (flags & CMD_ASYNC) | 151 | if (flags & CMD_ASYNC) |
147 | cmd.callback = iwl_add_sta_callback; | 152 | cmd.callback = iwl_add_sta_callback; |
148 | else | 153 | else { |
149 | cmd.flags |= CMD_WANT_SKB; | 154 | cmd.flags |= CMD_WANT_SKB; |
155 | might_sleep(); | ||
156 | } | ||
150 | 157 | ||
151 | cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); | 158 | cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); |
152 | ret = iwl_send_cmd(priv, &cmd); | 159 | ret = iwl_send_cmd(priv, &cmd); |
@@ -156,7 +163,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
156 | 163 | ||
157 | if (ret == 0) { | 164 | if (ret == 0) { |
158 | pkt = (struct iwl_rx_packet *)cmd.reply_page; | 165 | pkt = (struct iwl_rx_packet *)cmd.reply_page; |
159 | iwl_process_add_sta_resp(priv, sta, pkt, true); | 166 | ret = iwl_process_add_sta_resp(priv, sta, pkt, true); |
160 | } | 167 | } |
161 | iwl_free_pages(priv, cmd.reply_page); | 168 | iwl_free_pages(priv, cmd.reply_page); |
162 | 169 | ||
@@ -831,7 +838,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | |||
831 | { | 838 | { |
832 | unsigned long flags; | 839 | unsigned long flags; |
833 | __le16 key_flags = 0; | 840 | __le16 key_flags = 0; |
834 | int ret; | 841 | struct iwl_addsta_cmd sta_cmd; |
842 | |||
843 | lockdep_assert_held(&priv->mutex); | ||
835 | 844 | ||
836 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 845 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; |
837 | 846 | ||
@@ -871,11 +880,10 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | |||
871 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 880 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
872 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 881 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
873 | 882 | ||
874 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 883 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); |
875 | |||
876 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 884 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
877 | 885 | ||
878 | return ret; | 886 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); |
879 | } | 887 | } |
880 | 888 | ||
881 | static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | 889 | static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, |
@@ -884,7 +892,9 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
884 | { | 892 | { |
885 | unsigned long flags; | 893 | unsigned long flags; |
886 | __le16 key_flags = 0; | 894 | __le16 key_flags = 0; |
887 | int ret; | 895 | struct iwl_addsta_cmd sta_cmd; |
896 | |||
897 | lockdep_assert_held(&priv->mutex); | ||
888 | 898 | ||
889 | key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); | 899 | key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); |
890 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | 900 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); |
@@ -919,11 +929,10 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
919 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 929 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; |
920 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 930 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
921 | 931 | ||
922 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 932 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); |
923 | |||
924 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 933 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
925 | 934 | ||
926 | return ret; | 935 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); |
927 | } | 936 | } |
928 | 937 | ||
929 | static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | 938 | static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, |
@@ -1013,9 +1022,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
1013 | u8 sta_id) | 1022 | u8 sta_id) |
1014 | { | 1023 | { |
1015 | unsigned long flags; | 1024 | unsigned long flags; |
1016 | int ret = 0; | ||
1017 | u16 key_flags; | 1025 | u16 key_flags; |
1018 | u8 keyidx; | 1026 | u8 keyidx; |
1027 | struct iwl_addsta_cmd sta_cmd; | ||
1028 | |||
1029 | lockdep_assert_held(&priv->mutex); | ||
1019 | 1030 | ||
1020 | priv->key_mapping_key--; | 1031 | priv->key_mapping_key--; |
1021 | 1032 | ||
@@ -1062,9 +1073,10 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
1062 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1073 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1063 | return 0; | 1074 | return 0; |
1064 | } | 1075 | } |
1065 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 1076 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); |
1066 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1077 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1067 | return ret; | 1078 | |
1079 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1068 | } | 1080 | } |
1069 | EXPORT_SYMBOL(iwl_remove_dynamic_key); | 1081 | EXPORT_SYMBOL(iwl_remove_dynamic_key); |
1070 | 1082 | ||
@@ -1073,6 +1085,8 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, | |||
1073 | { | 1085 | { |
1074 | int ret; | 1086 | int ret; |
1075 | 1087 | ||
1088 | lockdep_assert_held(&priv->mutex); | ||
1089 | |||
1076 | priv->key_mapping_key++; | 1090 | priv->key_mapping_key++; |
1077 | keyconf->hw_key_idx = HW_KEY_DYNAMIC; | 1091 | keyconf->hw_key_idx = HW_KEY_DYNAMIC; |
1078 | 1092 | ||
@@ -1245,6 +1259,36 @@ int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq) | |||
1245 | } | 1259 | } |
1246 | EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station); | 1260 | EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station); |
1247 | 1261 | ||
1262 | /** | ||
1263 | * iwl_update_bcast_station - update broadcast station's LQ command | ||
1264 | * | ||
1265 | * Only used by iwlagn. Placed here to have all bcast station management | ||
1266 | * code together. | ||
1267 | */ | ||
1268 | int iwl_update_bcast_station(struct iwl_priv *priv) | ||
1269 | { | ||
1270 | unsigned long flags; | ||
1271 | struct iwl_link_quality_cmd *link_cmd; | ||
1272 | u8 sta_id = priv->hw_params.bcast_sta_id; | ||
1273 | |||
1274 | link_cmd = iwl_sta_alloc_lq(priv, sta_id); | ||
1275 | if (!link_cmd) { | ||
1276 | IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); | ||
1277 | return -ENOMEM; | ||
1278 | } | ||
1279 | |||
1280 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1281 | if (priv->stations[sta_id].lq) | ||
1282 | kfree(priv->stations[sta_id].lq); | ||
1283 | else | ||
1284 | IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n"); | ||
1285 | priv->stations[sta_id].lq = link_cmd; | ||
1286 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | EXPORT_SYMBOL_GPL(iwl_update_bcast_station); | ||
1291 | |||
1248 | void iwl_dealloc_bcast_station(struct iwl_priv *priv) | 1292 | void iwl_dealloc_bcast_station(struct iwl_priv *priv) |
1249 | { | 1293 | { |
1250 | unsigned long flags; | 1294 | unsigned long flags; |
@@ -1268,17 +1312,22 @@ EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station); | |||
1268 | /** | 1312 | /** |
1269 | * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table | 1313 | * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table |
1270 | */ | 1314 | */ |
1271 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) | 1315 | int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) |
1272 | { | 1316 | { |
1273 | unsigned long flags; | 1317 | unsigned long flags; |
1318 | struct iwl_addsta_cmd sta_cmd; | ||
1319 | |||
1320 | lockdep_assert_held(&priv->mutex); | ||
1274 | 1321 | ||
1275 | /* Remove "disable" flag, to enable Tx for this TID */ | 1322 | /* Remove "disable" flag, to enable Tx for this TID */ |
1276 | spin_lock_irqsave(&priv->sta_lock, flags); | 1323 | spin_lock_irqsave(&priv->sta_lock, flags); |
1277 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; | 1324 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; |
1278 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); | 1325 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); |
1279 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 1326 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
1280 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 1327 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); |
1281 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1328 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1329 | |||
1330 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1282 | } | 1331 | } |
1283 | EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); | 1332 | EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); |
1284 | 1333 | ||
@@ -1287,6 +1336,9 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, | |||
1287 | { | 1336 | { |
1288 | unsigned long flags; | 1337 | unsigned long flags; |
1289 | int sta_id; | 1338 | int sta_id; |
1339 | struct iwl_addsta_cmd sta_cmd; | ||
1340 | |||
1341 | lockdep_assert_held(&priv->mutex); | ||
1290 | 1342 | ||
1291 | sta_id = iwl_sta_id(sta); | 1343 | sta_id = iwl_sta_id(sta); |
1292 | if (sta_id == IWL_INVALID_STATION) | 1344 | if (sta_id == IWL_INVALID_STATION) |
@@ -1298,10 +1350,10 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, | |||
1298 | priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; | 1350 | priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; |
1299 | priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); | 1351 | priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); |
1300 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 1352 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
1353 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
1301 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1354 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1302 | 1355 | ||
1303 | return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, | 1356 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); |
1304 | CMD_ASYNC); | ||
1305 | } | 1357 | } |
1306 | EXPORT_SYMBOL(iwl_sta_rx_agg_start); | 1358 | EXPORT_SYMBOL(iwl_sta_rx_agg_start); |
1307 | 1359 | ||
@@ -1309,7 +1361,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, | |||
1309 | int tid) | 1361 | int tid) |
1310 | { | 1362 | { |
1311 | unsigned long flags; | 1363 | unsigned long flags; |
1312 | int sta_id, ret; | 1364 | int sta_id; |
1365 | struct iwl_addsta_cmd sta_cmd; | ||
1366 | |||
1367 | lockdep_assert_held(&priv->mutex); | ||
1313 | 1368 | ||
1314 | sta_id = iwl_sta_id(sta); | 1369 | sta_id = iwl_sta_id(sta); |
1315 | if (sta_id == IWL_INVALID_STATION) { | 1370 | if (sta_id == IWL_INVALID_STATION) { |
@@ -1322,11 +1377,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, | |||
1322 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; | 1377 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; |
1323 | priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; | 1378 | priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; |
1324 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 1379 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
1325 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 1380 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); |
1326 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1381 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1327 | 1382 | ||
1328 | return ret; | 1383 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); |
1329 | |||
1330 | } | 1384 | } |
1331 | EXPORT_SYMBOL(iwl_sta_rx_agg_stop); | 1385 | EXPORT_SYMBOL(iwl_sta_rx_agg_stop); |
1332 | 1386 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 5b1b1e461eb6..ba95b1a590a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -60,6 +60,7 @@ void iwl_restore_stations(struct iwl_priv *priv); | |||
60 | void iwl_clear_ucode_stations(struct iwl_priv *priv); | 60 | void iwl_clear_ucode_stations(struct iwl_priv *priv); |
61 | int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq); | 61 | int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq); |
62 | void iwl_dealloc_bcast_station(struct iwl_priv *priv); | 62 | void iwl_dealloc_bcast_station(struct iwl_priv *priv); |
63 | int iwl_update_bcast_station(struct iwl_priv *priv); | ||
63 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); | 64 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); |
64 | int iwl_send_add_sta(struct iwl_priv *priv, | 65 | int iwl_send_add_sta(struct iwl_priv *priv, |
65 | struct iwl_addsta_cmd *sta, u8 flags); | 66 | struct iwl_addsta_cmd *sta, u8 flags); |
@@ -73,7 +74,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, | |||
73 | const u8 *addr); | 74 | const u8 *addr); |
74 | int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 75 | int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
75 | struct ieee80211_sta *sta); | 76 | struct ieee80211_sta *sta); |
76 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); | 77 | int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); |
77 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, | 78 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, |
78 | int tid, u16 ssn); | 79 | int tid, u16 ssn); |
79 | int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, | 80 | int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 697fa6caaceb..8eb347106902 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -1424,7 +1424,7 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv) | |||
1424 | iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32)); | 1424 | iwl_read_targ_mem(priv, base + i + 6 * sizeof(u32)); |
1425 | 1425 | ||
1426 | IWL_ERR(priv, | 1426 | IWL_ERR(priv, |
1427 | "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", | 1427 | "%-13s (0x%X) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", |
1428 | desc_lookup(desc), desc, time, blink1, blink2, | 1428 | desc_lookup(desc), desc, time, blink1, blink2, |
1429 | ilink1, ilink2, data1); | 1429 | ilink1, ilink2, data1); |
1430 | trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0, | 1430 | trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0, |
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 902e95f70f6e..60619678f4ec 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c | |||
@@ -670,20 +670,24 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, | |||
670 | } | 670 | } |
671 | 671 | ||
672 | static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, | 672 | static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, |
673 | enum tx_power_setting type, int dbm) | 673 | enum nl80211_tx_power_setting type, int mbm) |
674 | { | 674 | { |
675 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | 675 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); |
676 | int ret; | 676 | int ret; |
677 | 677 | ||
678 | switch (type) { | 678 | switch (type) { |
679 | case TX_POWER_AUTOMATIC: | 679 | case NL80211_TX_POWER_AUTOMATIC: |
680 | return 0; | 680 | return 0; |
681 | case TX_POWER_FIXED: | 681 | case NL80211_TX_POWER_FIXED: |
682 | if (mbm < 0 || (mbm % 100)) | ||
683 | return -EOPNOTSUPP; | ||
684 | |||
682 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | 685 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) |
683 | return 0; | 686 | return 0; |
684 | 687 | ||
685 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | 688 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, |
686 | CFG_TX_PWR_LIMIT_USR, dbm * 2); | 689 | CFG_TX_PWR_LIMIT_USR, |
690 | MBM_TO_DBM(mbm) * 2); | ||
687 | if (ret < 0) | 691 | if (ret < 0) |
688 | return ret; | 692 | return ret; |
689 | 693 | ||
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 45e870e33117..f7d01bfa2e4a 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | libertas-y += assoc.o | ||
2 | libertas-y += cfg.o | 1 | libertas-y += cfg.o |
3 | libertas-y += cmd.o | 2 | libertas-y += cmd.o |
4 | libertas-y += cmdresp.o | 3 | libertas-y += cmdresp.o |
@@ -6,9 +5,7 @@ libertas-y += debugfs.o | |||
6 | libertas-y += ethtool.o | 5 | libertas-y += ethtool.o |
7 | libertas-y += main.o | 6 | libertas-y += main.o |
8 | libertas-y += rx.o | 7 | libertas-y += rx.o |
9 | libertas-y += scan.o | ||
10 | libertas-y += tx.o | 8 | libertas-y += tx.o |
11 | libertas-y += wext.o | ||
12 | libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o | 9 | libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o |
13 | 10 | ||
14 | usb8xxx-objs += if_usb.o | 11 | usb8xxx-objs += if_usb.o |
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c deleted file mode 100644 index aa06070e5eab..000000000000 --- a/drivers/net/wireless/libertas/assoc.c +++ /dev/null | |||
@@ -1,2264 +0,0 @@ | |||
1 | /* Copyright (C) 2006, Red Hat, Inc. */ | ||
2 | |||
3 | #include <linux/types.h> | ||
4 | #include <linux/etherdevice.h> | ||
5 | #include <linux/ieee80211.h> | ||
6 | #include <linux/if_arp.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <net/lib80211.h> | ||
9 | |||
10 | #include "assoc.h" | ||
11 | #include "decl.h" | ||
12 | #include "host.h" | ||
13 | #include "scan.h" | ||
14 | #include "cmd.h" | ||
15 | |||
16 | static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = | ||
17 | { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
18 | static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = | ||
19 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
20 | |||
21 | /* The firmware needs the following bits masked out of the beacon-derived | ||
22 | * capability field when associating/joining to a BSS: | ||
23 | * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) | ||
24 | */ | ||
25 | #define CAPINFO_MASK (~(0xda00)) | ||
26 | |||
27 | /** | ||
28 | * 802.11b/g supported bitrates (in 500Kb/s units) | ||
29 | */ | ||
30 | u8 lbs_bg_rates[MAX_RATES] = | ||
31 | { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, | ||
32 | 0x00, 0x00 }; | ||
33 | |||
34 | |||
35 | static int assoc_helper_wep_keys(struct lbs_private *priv, | ||
36 | struct assoc_request *assoc_req); | ||
37 | |||
38 | /** | ||
39 | * @brief This function finds common rates between rates and card rates. | ||
40 | * | ||
41 | * It will fill common rates in rates as output if found. | ||
42 | * | ||
43 | * NOTE: Setting the MSB of the basic rates need to be taken | ||
44 | * care, either before or after calling this function | ||
45 | * | ||
46 | * @param priv A pointer to struct lbs_private structure | ||
47 | * @param rates the buffer which keeps input and output | ||
48 | * @param rates_size the size of rates buffer; new size of buffer on return, | ||
49 | * which will be less than or equal to original rates_size | ||
50 | * | ||
51 | * @return 0 on success, or -1 on error | ||
52 | */ | ||
53 | static int get_common_rates(struct lbs_private *priv, | ||
54 | u8 *rates, | ||
55 | u16 *rates_size) | ||
56 | { | ||
57 | int i, j; | ||
58 | u8 intersection[MAX_RATES]; | ||
59 | u16 intersection_size; | ||
60 | u16 num_rates = 0; | ||
61 | |||
62 | intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection)); | ||
63 | |||
64 | /* Allow each rate from 'rates' that is supported by the hardware */ | ||
65 | for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) { | ||
66 | for (j = 0; j < intersection_size && rates[j]; j++) { | ||
67 | if (rates[j] == lbs_bg_rates[i]) | ||
68 | intersection[num_rates++] = rates[j]; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); | ||
73 | lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates, | ||
74 | ARRAY_SIZE(lbs_bg_rates)); | ||
75 | lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates); | ||
76 | lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); | ||
77 | |||
78 | if (!priv->enablehwauto) { | ||
79 | for (i = 0; i < num_rates; i++) { | ||
80 | if (intersection[i] == priv->cur_rate) | ||
81 | goto done; | ||
82 | } | ||
83 | lbs_pr_alert("Previously set fixed data rate %#x isn't " | ||
84 | "compatible with the network.\n", priv->cur_rate); | ||
85 | return -1; | ||
86 | } | ||
87 | |||
88 | done: | ||
89 | memset(rates, 0, *rates_size); | ||
90 | *rates_size = num_rates; | ||
91 | memcpy(rates, intersection, num_rates); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | |||
96 | /** | ||
97 | * @brief Sets the MSB on basic rates as the firmware requires | ||
98 | * | ||
99 | * Scan through an array and set the MSB for basic data rates. | ||
100 | * | ||
101 | * @param rates buffer of data rates | ||
102 | * @param len size of buffer | ||
103 | */ | ||
104 | static void lbs_set_basic_rate_flags(u8 *rates, size_t len) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < len; i++) { | ||
109 | if (rates[i] == 0x02 || rates[i] == 0x04 || | ||
110 | rates[i] == 0x0b || rates[i] == 0x16) | ||
111 | rates[i] |= 0x80; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | |||
116 | static u8 iw_auth_to_ieee_auth(u8 auth) | ||
117 | { | ||
118 | if (auth == IW_AUTH_ALG_OPEN_SYSTEM) | ||
119 | return 0x00; | ||
120 | else if (auth == IW_AUTH_ALG_SHARED_KEY) | ||
121 | return 0x01; | ||
122 | else if (auth == IW_AUTH_ALG_LEAP) | ||
123 | return 0x80; | ||
124 | |||
125 | lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * @brief This function prepares the authenticate command. AUTHENTICATE only | ||
131 | * sets the authentication suite for future associations, as the firmware | ||
132 | * handles authentication internally during the ASSOCIATE command. | ||
133 | * | ||
134 | * @param priv A pointer to struct lbs_private structure | ||
135 | * @param bssid The peer BSSID with which to authenticate | ||
136 | * @param auth The authentication mode to use (from wireless.h) | ||
137 | * | ||
138 | * @return 0 or -1 | ||
139 | */ | ||
140 | static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) | ||
141 | { | ||
142 | struct cmd_ds_802_11_authenticate cmd; | ||
143 | int ret = -1; | ||
144 | |||
145 | lbs_deb_enter(LBS_DEB_JOIN); | ||
146 | |||
147 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
148 | memcpy(cmd.bssid, bssid, ETH_ALEN); | ||
149 | |||
150 | cmd.authtype = iw_auth_to_ieee_auth(auth); | ||
151 | |||
152 | lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype); | ||
153 | |||
154 | ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); | ||
155 | |||
156 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | |||
161 | int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, | ||
162 | struct assoc_request *assoc) | ||
163 | { | ||
164 | struct cmd_ds_802_11_set_wep cmd; | ||
165 | int ret = 0; | ||
166 | |||
167 | lbs_deb_enter(LBS_DEB_CMD); | ||
168 | |||
169 | memset(&cmd, 0, sizeof(cmd)); | ||
170 | cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP); | ||
171 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
172 | |||
173 | cmd.action = cpu_to_le16(cmd_action); | ||
174 | |||
175 | if (cmd_action == CMD_ACT_ADD) { | ||
176 | int i; | ||
177 | |||
178 | /* default tx key index */ | ||
179 | cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx & | ||
180 | CMD_WEP_KEY_INDEX_MASK); | ||
181 | |||
182 | /* Copy key types and material to host command structure */ | ||
183 | for (i = 0; i < 4; i++) { | ||
184 | struct enc_key *pkey = &assoc->wep_keys[i]; | ||
185 | |||
186 | switch (pkey->len) { | ||
187 | case KEY_LEN_WEP_40: | ||
188 | cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; | ||
189 | memmove(cmd.keymaterial[i], pkey->key, pkey->len); | ||
190 | lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); | ||
191 | break; | ||
192 | case KEY_LEN_WEP_104: | ||
193 | cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; | ||
194 | memmove(cmd.keymaterial[i], pkey->key, pkey->len); | ||
195 | lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); | ||
196 | break; | ||
197 | case 0: | ||
198 | break; | ||
199 | default: | ||
200 | lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", | ||
201 | i, pkey->len); | ||
202 | ret = -1; | ||
203 | goto done; | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | } else if (cmd_action == CMD_ACT_REMOVE) { | ||
208 | /* ACT_REMOVE clears _all_ WEP keys */ | ||
209 | |||
210 | /* default tx key index */ | ||
211 | cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx & | ||
212 | CMD_WEP_KEY_INDEX_MASK); | ||
213 | lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx); | ||
214 | } | ||
215 | |||
216 | ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); | ||
217 | done: | ||
218 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, | ||
223 | uint16_t *enable) | ||
224 | { | ||
225 | struct cmd_ds_802_11_enable_rsn cmd; | ||
226 | int ret; | ||
227 | |||
228 | lbs_deb_enter(LBS_DEB_CMD); | ||
229 | |||
230 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
231 | cmd.action = cpu_to_le16(cmd_action); | ||
232 | |||
233 | if (cmd_action == CMD_ACT_GET) | ||
234 | cmd.enable = 0; | ||
235 | else { | ||
236 | if (*enable) | ||
237 | cmd.enable = cpu_to_le16(CMD_ENABLE_RSN); | ||
238 | else | ||
239 | cmd.enable = cpu_to_le16(CMD_DISABLE_RSN); | ||
240 | lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); | ||
241 | } | ||
242 | |||
243 | ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); | ||
244 | if (!ret && cmd_action == CMD_ACT_GET) | ||
245 | *enable = le16_to_cpu(cmd.enable); | ||
246 | |||
247 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, | ||
252 | struct enc_key *key) | ||
253 | { | ||
254 | lbs_deb_enter(LBS_DEB_CMD); | ||
255 | |||
256 | if (key->flags & KEY_INFO_WPA_ENABLED) | ||
257 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); | ||
258 | if (key->flags & KEY_INFO_WPA_UNICAST) | ||
259 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); | ||
260 | if (key->flags & KEY_INFO_WPA_MCAST) | ||
261 | keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); | ||
262 | |||
263 | keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
264 | keyparam->keytypeid = cpu_to_le16(key->type); | ||
265 | keyparam->keylen = cpu_to_le16(key->len); | ||
266 | memcpy(keyparam->key, key->key, key->len); | ||
267 | |||
268 | /* Length field doesn't include the {type,length} header */ | ||
269 | keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); | ||
270 | lbs_deb_leave(LBS_DEB_CMD); | ||
271 | } | ||
272 | |||
273 | int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, | ||
274 | struct assoc_request *assoc) | ||
275 | { | ||
276 | struct cmd_ds_802_11_key_material cmd; | ||
277 | int ret = 0; | ||
278 | int index = 0; | ||
279 | |||
280 | lbs_deb_enter(LBS_DEB_CMD); | ||
281 | |||
282 | cmd.action = cpu_to_le16(cmd_action); | ||
283 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
284 | |||
285 | if (cmd_action == CMD_ACT_GET) { | ||
286 | cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2); | ||
287 | } else { | ||
288 | memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); | ||
289 | |||
290 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { | ||
291 | set_one_wpa_key(&cmd.keyParamSet[index], | ||
292 | &assoc->wpa_unicast_key); | ||
293 | index++; | ||
294 | } | ||
295 | |||
296 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { | ||
297 | set_one_wpa_key(&cmd.keyParamSet[index], | ||
298 | &assoc->wpa_mcast_key); | ||
299 | index++; | ||
300 | } | ||
301 | |||
302 | /* The common header and as many keys as we included */ | ||
303 | cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), | ||
304 | keyParamSet[index])); | ||
305 | } | ||
306 | ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); | ||
307 | /* Copy the returned key to driver private data */ | ||
308 | if (!ret && cmd_action == CMD_ACT_GET) { | ||
309 | void *buf_ptr = cmd.keyParamSet; | ||
310 | void *resp_end = &(&cmd)[1]; | ||
311 | |||
312 | while (buf_ptr < resp_end) { | ||
313 | struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; | ||
314 | struct enc_key *key; | ||
315 | uint16_t param_set_len = le16_to_cpu(keyparam->length); | ||
316 | uint16_t key_len = le16_to_cpu(keyparam->keylen); | ||
317 | uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); | ||
318 | uint16_t key_type = le16_to_cpu(keyparam->keytypeid); | ||
319 | void *end; | ||
320 | |||
321 | end = (void *)keyparam + sizeof(keyparam->type) | ||
322 | + sizeof(keyparam->length) + param_set_len; | ||
323 | |||
324 | /* Make sure we don't access past the end of the IEs */ | ||
325 | if (end > resp_end) | ||
326 | break; | ||
327 | |||
328 | if (key_flags & KEY_INFO_WPA_UNICAST) | ||
329 | key = &priv->wpa_unicast_key; | ||
330 | else if (key_flags & KEY_INFO_WPA_MCAST) | ||
331 | key = &priv->wpa_mcast_key; | ||
332 | else | ||
333 | break; | ||
334 | |||
335 | /* Copy returned key into driver */ | ||
336 | memset(key, 0, sizeof(struct enc_key)); | ||
337 | if (key_len > sizeof(key->key)) | ||
338 | break; | ||
339 | key->type = key_type; | ||
340 | key->flags = key_flags; | ||
341 | key->len = key_len; | ||
342 | memcpy(key->key, keyparam->key, key->len); | ||
343 | |||
344 | buf_ptr = end + 1; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) | ||
353 | { | ||
354 | /* Bit Rate | ||
355 | * 15:13 Reserved | ||
356 | * 12 54 Mbps | ||
357 | * 11 48 Mbps | ||
358 | * 10 36 Mbps | ||
359 | * 9 24 Mbps | ||
360 | * 8 18 Mbps | ||
361 | * 7 12 Mbps | ||
362 | * 6 9 Mbps | ||
363 | * 5 6 Mbps | ||
364 | * 4 Reserved | ||
365 | * 3 11 Mbps | ||
366 | * 2 5.5 Mbps | ||
367 | * 1 2 Mbps | ||
368 | * 0 1 Mbps | ||
369 | **/ | ||
370 | |||
371 | uint16_t ratemask; | ||
372 | int i = lbs_data_rate_to_fw_index(rate); | ||
373 | if (lower_rates_ok) | ||
374 | ratemask = (0x1fef >> (12 - i)); | ||
375 | else | ||
376 | ratemask = (1 << i); | ||
377 | return cpu_to_le16(ratemask); | ||
378 | } | ||
379 | |||
380 | int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, | ||
381 | uint16_t cmd_action) | ||
382 | { | ||
383 | struct cmd_ds_802_11_rate_adapt_rateset cmd; | ||
384 | int ret; | ||
385 | |||
386 | lbs_deb_enter(LBS_DEB_CMD); | ||
387 | |||
388 | if (!priv->cur_rate && !priv->enablehwauto) | ||
389 | return -EINVAL; | ||
390 | |||
391 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
392 | |||
393 | cmd.action = cpu_to_le16(cmd_action); | ||
394 | cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); | ||
395 | cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); | ||
396 | ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); | ||
397 | if (!ret && cmd_action == CMD_ACT_GET) | ||
398 | priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); | ||
399 | |||
400 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * @brief Set the data rate | ||
406 | * | ||
407 | * @param priv A pointer to struct lbs_private structure | ||
408 | * @param rate The desired data rate, or 0 to clear a locked rate | ||
409 | * | ||
410 | * @return 0 on success, error on failure | ||
411 | */ | ||
412 | int lbs_set_data_rate(struct lbs_private *priv, u8 rate) | ||
413 | { | ||
414 | struct cmd_ds_802_11_data_rate cmd; | ||
415 | int ret = 0; | ||
416 | |||
417 | lbs_deb_enter(LBS_DEB_CMD); | ||
418 | |||
419 | memset(&cmd, 0, sizeof(cmd)); | ||
420 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
421 | |||
422 | if (rate > 0) { | ||
423 | cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE); | ||
424 | cmd.rates[0] = lbs_data_rate_to_fw_index(rate); | ||
425 | if (cmd.rates[0] == 0) { | ||
426 | lbs_deb_cmd("DATA_RATE: invalid requested rate of" | ||
427 | " 0x%02X\n", rate); | ||
428 | ret = 0; | ||
429 | goto out; | ||
430 | } | ||
431 | lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]); | ||
432 | } else { | ||
433 | cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO); | ||
434 | lbs_deb_cmd("DATA_RATE: setting auto\n"); | ||
435 | } | ||
436 | |||
437 | ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); | ||
438 | if (ret) | ||
439 | goto out; | ||
440 | |||
441 | lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd)); | ||
442 | |||
443 | /* FIXME: get actual rates FW can do if this command actually returns | ||
444 | * all data rates supported. | ||
445 | */ | ||
446 | priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]); | ||
447 | lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate); | ||
448 | |||
449 | out: | ||
450 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | |||
455 | int lbs_cmd_802_11_rssi(struct lbs_private *priv, | ||
456 | struct cmd_ds_command *cmd) | ||
457 | { | ||
458 | |||
459 | lbs_deb_enter(LBS_DEB_CMD); | ||
460 | cmd->command = cpu_to_le16(CMD_802_11_RSSI); | ||
461 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + | ||
462 | sizeof(struct cmd_header)); | ||
463 | cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); | ||
464 | |||
465 | /* reset Beacon SNR/NF/RSSI values */ | ||
466 | priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
467 | priv->SNR[TYPE_BEACON][TYPE_AVG] = 0; | ||
468 | priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
469 | priv->NF[TYPE_BEACON][TYPE_AVG] = 0; | ||
470 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
471 | priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0; | ||
472 | |||
473 | lbs_deb_leave(LBS_DEB_CMD); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | int lbs_ret_802_11_rssi(struct lbs_private *priv, | ||
478 | struct cmd_ds_command *resp) | ||
479 | { | ||
480 | struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; | ||
481 | |||
482 | lbs_deb_enter(LBS_DEB_CMD); | ||
483 | |||
484 | /* store the non average value */ | ||
485 | priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); | ||
486 | priv->NF[TYPE_BEACON][TYPE_NOAVG] = | ||
487 | get_unaligned_le16(&rssirsp->noisefloor); | ||
488 | |||
489 | priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); | ||
490 | priv->NF[TYPE_BEACON][TYPE_AVG] = | ||
491 | get_unaligned_le16(&rssirsp->avgnoisefloor); | ||
492 | |||
493 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = | ||
494 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
495 | priv->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
496 | |||
497 | priv->RSSI[TYPE_BEACON][TYPE_AVG] = | ||
498 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, | ||
499 | priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); | ||
500 | |||
501 | lbs_deb_cmd("RSSI: beacon %d, avg %d\n", | ||
502 | priv->RSSI[TYPE_BEACON][TYPE_NOAVG], | ||
503 | priv->RSSI[TYPE_BEACON][TYPE_AVG]); | ||
504 | |||
505 | lbs_deb_leave(LBS_DEB_CMD); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | |||
510 | int lbs_cmd_bcn_ctrl(struct lbs_private *priv, | ||
511 | struct cmd_ds_command *cmd, | ||
512 | u16 cmd_action) | ||
513 | { | ||
514 | struct cmd_ds_802_11_beacon_control | ||
515 | *bcn_ctrl = &cmd->params.bcn_ctrl; | ||
516 | |||
517 | lbs_deb_enter(LBS_DEB_CMD); | ||
518 | cmd->size = | ||
519 | cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) | ||
520 | + sizeof(struct cmd_header)); | ||
521 | cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); | ||
522 | |||
523 | bcn_ctrl->action = cpu_to_le16(cmd_action); | ||
524 | bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable); | ||
525 | bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period); | ||
526 | |||
527 | lbs_deb_leave(LBS_DEB_CMD); | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, | ||
532 | struct cmd_ds_command *resp) | ||
533 | { | ||
534 | struct cmd_ds_802_11_beacon_control *bcn_ctrl = | ||
535 | &resp->params.bcn_ctrl; | ||
536 | |||
537 | lbs_deb_enter(LBS_DEB_CMD); | ||
538 | |||
539 | if (bcn_ctrl->action == CMD_ACT_GET) { | ||
540 | priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); | ||
541 | priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); | ||
542 | } | ||
543 | |||
544 | lbs_deb_enter(LBS_DEB_CMD); | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | |||
549 | |||
550 | static int lbs_assoc_post(struct lbs_private *priv, | ||
551 | struct cmd_ds_802_11_associate_response *resp) | ||
552 | { | ||
553 | int ret = 0; | ||
554 | union iwreq_data wrqu; | ||
555 | struct bss_descriptor *bss; | ||
556 | u16 status_code; | ||
557 | |||
558 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
559 | |||
560 | if (!priv->in_progress_assoc_req) { | ||
561 | lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); | ||
562 | ret = -1; | ||
563 | goto done; | ||
564 | } | ||
565 | bss = &priv->in_progress_assoc_req->bss; | ||
566 | |||
567 | /* | ||
568 | * Older FW versions map the IEEE 802.11 Status Code in the association | ||
569 | * response to the following values returned in resp->statuscode: | ||
570 | * | ||
571 | * IEEE Status Code Marvell Status Code | ||
572 | * 0 -> 0x0000 ASSOC_RESULT_SUCCESS | ||
573 | * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
574 | * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
575 | * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
576 | * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED | ||
577 | * others -> 0x0003 ASSOC_RESULT_REFUSED | ||
578 | * | ||
579 | * Other response codes: | ||
580 | * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) | ||
581 | * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for | ||
582 | * association response from the AP) | ||
583 | */ | ||
584 | |||
585 | status_code = le16_to_cpu(resp->statuscode); | ||
586 | if (priv->fwrelease < 0x09000000) { | ||
587 | switch (status_code) { | ||
588 | case 0x00: | ||
589 | break; | ||
590 | case 0x01: | ||
591 | lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); | ||
592 | break; | ||
593 | case 0x02: | ||
594 | lbs_deb_assoc("ASSOC_RESP: internal timer " | ||
595 | "expired while waiting for the AP\n"); | ||
596 | break; | ||
597 | case 0x03: | ||
598 | lbs_deb_assoc("ASSOC_RESP: association " | ||
599 | "refused by AP\n"); | ||
600 | break; | ||
601 | case 0x04: | ||
602 | lbs_deb_assoc("ASSOC_RESP: authentication " | ||
603 | "refused by AP\n"); | ||
604 | break; | ||
605 | default: | ||
606 | lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " | ||
607 | " unknown\n", status_code); | ||
608 | break; | ||
609 | } | ||
610 | } else { | ||
611 | /* v9+ returns the AP's association response */ | ||
612 | lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); | ||
613 | } | ||
614 | |||
615 | if (status_code) { | ||
616 | lbs_mac_event_disconnected(priv); | ||
617 | ret = status_code; | ||
618 | goto done; | ||
619 | } | ||
620 | |||
621 | lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", | ||
622 | (void *) (resp + sizeof (resp->hdr)), | ||
623 | le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); | ||
624 | |||
625 | /* Send a Media Connected event, according to the Spec */ | ||
626 | priv->connect_status = LBS_CONNECTED; | ||
627 | |||
628 | /* Update current SSID and BSSID */ | ||
629 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); | ||
630 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
631 | memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
632 | |||
633 | priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; | ||
634 | priv->NF[TYPE_RXPD][TYPE_AVG] = 0; | ||
635 | |||
636 | memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); | ||
637 | memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); | ||
638 | priv->nextSNRNF = 0; | ||
639 | priv->numSNRNF = 0; | ||
640 | |||
641 | netif_carrier_on(priv->dev); | ||
642 | if (!priv->tx_pending_len) | ||
643 | netif_wake_queue(priv->dev); | ||
644 | |||
645 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
646 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
647 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
648 | |||
649 | done: | ||
650 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * @brief This function prepares an association-class command. | ||
656 | * | ||
657 | * @param priv A pointer to struct lbs_private structure | ||
658 | * @param assoc_req The association request describing the BSS to associate | ||
659 | * or reassociate with | ||
660 | * @param command The actual command, either CMD_802_11_ASSOCIATE or | ||
661 | * CMD_802_11_REASSOCIATE | ||
662 | * | ||
663 | * @return 0 or -1 | ||
664 | */ | ||
665 | static int lbs_associate(struct lbs_private *priv, | ||
666 | struct assoc_request *assoc_req, | ||
667 | u16 command) | ||
668 | { | ||
669 | struct cmd_ds_802_11_associate cmd; | ||
670 | int ret = 0; | ||
671 | struct bss_descriptor *bss = &assoc_req->bss; | ||
672 | u8 *pos = &(cmd.iebuf[0]); | ||
673 | u16 tmpcap, tmplen, tmpauth; | ||
674 | struct mrvl_ie_ssid_param_set *ssid; | ||
675 | struct mrvl_ie_ds_param_set *ds; | ||
676 | struct mrvl_ie_cf_param_set *cf; | ||
677 | struct mrvl_ie_rates_param_set *rates; | ||
678 | struct mrvl_ie_rsn_param_set *rsn; | ||
679 | struct mrvl_ie_auth_type *auth; | ||
680 | |||
681 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
682 | |||
683 | BUG_ON((command != CMD_802_11_ASSOCIATE) && | ||
684 | (command != CMD_802_11_REASSOCIATE)); | ||
685 | |||
686 | memset(&cmd, 0, sizeof(cmd)); | ||
687 | cmd.hdr.command = cpu_to_le16(command); | ||
688 | |||
689 | /* Fill in static fields */ | ||
690 | memcpy(cmd.bssid, bss->bssid, ETH_ALEN); | ||
691 | cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); | ||
692 | |||
693 | /* Capability info */ | ||
694 | tmpcap = (bss->capability & CAPINFO_MASK); | ||
695 | if (bss->mode == IW_MODE_INFRA) | ||
696 | tmpcap |= WLAN_CAPABILITY_ESS; | ||
697 | cmd.capability = cpu_to_le16(tmpcap); | ||
698 | lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); | ||
699 | |||
700 | /* SSID */ | ||
701 | ssid = (struct mrvl_ie_ssid_param_set *) pos; | ||
702 | ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
703 | tmplen = bss->ssid_len; | ||
704 | ssid->header.len = cpu_to_le16(tmplen); | ||
705 | memcpy(ssid->ssid, bss->ssid, tmplen); | ||
706 | pos += sizeof(ssid->header) + tmplen; | ||
707 | |||
708 | ds = (struct mrvl_ie_ds_param_set *) pos; | ||
709 | ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); | ||
710 | ds->header.len = cpu_to_le16(1); | ||
711 | ds->channel = bss->phy.ds.channel; | ||
712 | pos += sizeof(ds->header) + 1; | ||
713 | |||
714 | cf = (struct mrvl_ie_cf_param_set *) pos; | ||
715 | cf->header.type = cpu_to_le16(TLV_TYPE_CF); | ||
716 | tmplen = sizeof(*cf) - sizeof (cf->header); | ||
717 | cf->header.len = cpu_to_le16(tmplen); | ||
718 | /* IE payload should be zeroed, firmware fills it in for us */ | ||
719 | pos += sizeof(*cf); | ||
720 | |||
721 | rates = (struct mrvl_ie_rates_param_set *) pos; | ||
722 | rates->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
723 | tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES); | ||
724 | memcpy(&rates->rates, &bss->rates, tmplen); | ||
725 | if (get_common_rates(priv, rates->rates, &tmplen)) { | ||
726 | ret = -1; | ||
727 | goto done; | ||
728 | } | ||
729 | pos += sizeof(rates->header) + tmplen; | ||
730 | rates->header.len = cpu_to_le16(tmplen); | ||
731 | lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); | ||
732 | |||
733 | /* Copy the infra. association rates into Current BSS state structure */ | ||
734 | memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); | ||
735 | memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); | ||
736 | |||
737 | /* Set MSB on basic rates as the firmware requires, but _after_ | ||
738 | * copying to current bss rates. | ||
739 | */ | ||
740 | lbs_set_basic_rate_flags(rates->rates, tmplen); | ||
741 | |||
742 | /* Firmware v9+ indicate authentication suites as a TLV */ | ||
743 | if (priv->fwrelease >= 0x09000000) { | ||
744 | auth = (struct mrvl_ie_auth_type *) pos; | ||
745 | auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); | ||
746 | auth->header.len = cpu_to_le16(2); | ||
747 | tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); | ||
748 | auth->auth = cpu_to_le16(tmpauth); | ||
749 | pos += sizeof(auth->header) + 2; | ||
750 | |||
751 | lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", | ||
752 | bss->bssid, priv->secinfo.auth_mode); | ||
753 | } | ||
754 | |||
755 | /* WPA/WPA2 IEs */ | ||
756 | if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { | ||
757 | rsn = (struct mrvl_ie_rsn_param_set *) pos; | ||
758 | /* WPA_IE or WPA2_IE */ | ||
759 | rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); | ||
760 | tmplen = (u16) assoc_req->wpa_ie[1]; | ||
761 | rsn->header.len = cpu_to_le16(tmplen); | ||
762 | memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); | ||
763 | lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, | ||
764 | sizeof(rsn->header) + tmplen); | ||
765 | pos += sizeof(rsn->header) + tmplen; | ||
766 | } | ||
767 | |||
768 | cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + | ||
769 | (u16)(pos - (u8 *) &cmd.iebuf)); | ||
770 | |||
771 | /* update curbssparams */ | ||
772 | priv->channel = bss->phy.ds.channel; | ||
773 | |||
774 | ret = lbs_cmd_with_response(priv, command, &cmd); | ||
775 | if (ret == 0) { | ||
776 | ret = lbs_assoc_post(priv, | ||
777 | (struct cmd_ds_802_11_associate_response *) &cmd); | ||
778 | } | ||
779 | |||
780 | done: | ||
781 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
782 | return ret; | ||
783 | } | ||
784 | |||
785 | /** | ||
786 | * @brief Associate to a specific BSS discovered in a scan | ||
787 | * | ||
788 | * @param priv A pointer to struct lbs_private structure | ||
789 | * @param assoc_req The association request describing the BSS to associate with | ||
790 | * | ||
791 | * @return 0-success, otherwise fail | ||
792 | */ | ||
793 | static int lbs_try_associate(struct lbs_private *priv, | ||
794 | struct assoc_request *assoc_req) | ||
795 | { | ||
796 | int ret; | ||
797 | u8 preamble = RADIO_PREAMBLE_LONG; | ||
798 | |||
799 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
800 | |||
801 | /* FW v9 and higher indicate authentication suites as a TLV in the | ||
802 | * association command, not as a separate authentication command. | ||
803 | */ | ||
804 | if (priv->fwrelease < 0x09000000) { | ||
805 | ret = lbs_set_authentication(priv, assoc_req->bss.bssid, | ||
806 | priv->secinfo.auth_mode); | ||
807 | if (ret) | ||
808 | goto out; | ||
809 | } | ||
810 | |||
811 | /* Use short preamble only when both the BSS and firmware support it */ | ||
812 | if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) | ||
813 | preamble = RADIO_PREAMBLE_SHORT; | ||
814 | |||
815 | ret = lbs_set_radio(priv, preamble, 1); | ||
816 | if (ret) | ||
817 | goto out; | ||
818 | |||
819 | ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); | ||
820 | /* If the association fails with current auth mode, let's | ||
821 | * try by changing the auth mode | ||
822 | */ | ||
823 | if ((priv->authtype_auto) && | ||
824 | (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) && | ||
825 | (assoc_req->secinfo.wep_enabled) && | ||
826 | (priv->connect_status != LBS_CONNECTED)) { | ||
827 | if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM) | ||
828 | priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | ||
829 | else | ||
830 | priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
831 | if (!assoc_helper_wep_keys(priv, assoc_req)) | ||
832 | ret = lbs_associate(priv, assoc_req, | ||
833 | CMD_802_11_ASSOCIATE); | ||
834 | } | ||
835 | |||
836 | if (ret) | ||
837 | ret = -1; | ||
838 | out: | ||
839 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
840 | return ret; | ||
841 | } | ||
842 | |||
843 | static int lbs_adhoc_post(struct lbs_private *priv, | ||
844 | struct cmd_ds_802_11_ad_hoc_result *resp) | ||
845 | { | ||
846 | int ret = 0; | ||
847 | u16 command = le16_to_cpu(resp->hdr.command); | ||
848 | u16 result = le16_to_cpu(resp->hdr.result); | ||
849 | union iwreq_data wrqu; | ||
850 | struct bss_descriptor *bss; | ||
851 | DECLARE_SSID_BUF(ssid); | ||
852 | |||
853 | lbs_deb_enter(LBS_DEB_JOIN); | ||
854 | |||
855 | if (!priv->in_progress_assoc_req) { | ||
856 | lbs_deb_join("ADHOC_RESP: no in-progress association " | ||
857 | "request\n"); | ||
858 | ret = -1; | ||
859 | goto done; | ||
860 | } | ||
861 | bss = &priv->in_progress_assoc_req->bss; | ||
862 | |||
863 | /* | ||
864 | * Join result code 0 --> SUCCESS | ||
865 | */ | ||
866 | if (result) { | ||
867 | lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); | ||
868 | if (priv->connect_status == LBS_CONNECTED) | ||
869 | lbs_mac_event_disconnected(priv); | ||
870 | ret = -1; | ||
871 | goto done; | ||
872 | } | ||
873 | |||
874 | /* Send a Media Connected event, according to the Spec */ | ||
875 | priv->connect_status = LBS_CONNECTED; | ||
876 | |||
877 | if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { | ||
878 | /* Update the created network descriptor with the new BSSID */ | ||
879 | memcpy(bss->bssid, resp->bssid, ETH_ALEN); | ||
880 | } | ||
881 | |||
882 | /* Set the BSSID from the joined/started descriptor */ | ||
883 | memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); | ||
884 | |||
885 | /* Set the new SSID to current SSID */ | ||
886 | memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); | ||
887 | priv->curbssparams.ssid_len = bss->ssid_len; | ||
888 | |||
889 | netif_carrier_on(priv->dev); | ||
890 | if (!priv->tx_pending_len) | ||
891 | netif_wake_queue(priv->dev); | ||
892 | |||
893 | memset(&wrqu, 0, sizeof(wrqu)); | ||
894 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
895 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
896 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
897 | |||
898 | lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", | ||
899 | print_ssid(ssid, bss->ssid, bss->ssid_len), | ||
900 | priv->curbssparams.bssid, | ||
901 | priv->channel); | ||
902 | |||
903 | done: | ||
904 | lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); | ||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * @brief Join an adhoc network found in a previous scan | ||
910 | * | ||
911 | * @param priv A pointer to struct lbs_private structure | ||
912 | * @param assoc_req The association request describing the BSS to join | ||
913 | * | ||
914 | * @return 0 on success, error on failure | ||
915 | */ | ||
916 | static int lbs_adhoc_join(struct lbs_private *priv, | ||
917 | struct assoc_request *assoc_req) | ||
918 | { | ||
919 | struct cmd_ds_802_11_ad_hoc_join cmd; | ||
920 | struct bss_descriptor *bss = &assoc_req->bss; | ||
921 | u8 preamble = RADIO_PREAMBLE_LONG; | ||
922 | DECLARE_SSID_BUF(ssid); | ||
923 | u16 ratesize = 0; | ||
924 | int ret = 0; | ||
925 | |||
926 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
927 | |||
928 | lbs_deb_join("current SSID '%s', ssid length %u\n", | ||
929 | print_ssid(ssid, priv->curbssparams.ssid, | ||
930 | priv->curbssparams.ssid_len), | ||
931 | priv->curbssparams.ssid_len); | ||
932 | lbs_deb_join("requested ssid '%s', ssid length %u\n", | ||
933 | print_ssid(ssid, bss->ssid, bss->ssid_len), | ||
934 | bss->ssid_len); | ||
935 | |||
936 | /* check if the requested SSID is already joined */ | ||
937 | if (priv->curbssparams.ssid_len && | ||
938 | !lbs_ssid_cmp(priv->curbssparams.ssid, | ||
939 | priv->curbssparams.ssid_len, | ||
940 | bss->ssid, bss->ssid_len) && | ||
941 | (priv->mode == IW_MODE_ADHOC) && | ||
942 | (priv->connect_status == LBS_CONNECTED)) { | ||
943 | union iwreq_data wrqu; | ||
944 | |||
945 | lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " | ||
946 | "current, not attempting to re-join"); | ||
947 | |||
948 | /* Send the re-association event though, because the association | ||
949 | * request really was successful, even if just a null-op. | ||
950 | */ | ||
951 | memset(&wrqu, 0, sizeof(wrqu)); | ||
952 | memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, | ||
953 | ETH_ALEN); | ||
954 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
955 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
956 | goto out; | ||
957 | } | ||
958 | |||
959 | /* Use short preamble only when both the BSS and firmware support it */ | ||
960 | if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { | ||
961 | lbs_deb_join("AdhocJoin: Short preamble\n"); | ||
962 | preamble = RADIO_PREAMBLE_SHORT; | ||
963 | } | ||
964 | |||
965 | ret = lbs_set_radio(priv, preamble, 1); | ||
966 | if (ret) | ||
967 | goto out; | ||
968 | |||
969 | lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); | ||
970 | lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); | ||
971 | |||
972 | priv->adhoccreate = 0; | ||
973 | priv->channel = bss->channel; | ||
974 | |||
975 | /* Build the join command */ | ||
976 | memset(&cmd, 0, sizeof(cmd)); | ||
977 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
978 | |||
979 | cmd.bss.type = CMD_BSS_TYPE_IBSS; | ||
980 | cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); | ||
981 | |||
982 | memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); | ||
983 | memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); | ||
984 | |||
985 | memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); | ||
986 | |||
987 | memcpy(&cmd.bss.ibss, &bss->ss.ibss, | ||
988 | sizeof(struct ieee_ie_ibss_param_set)); | ||
989 | |||
990 | cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); | ||
991 | lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", | ||
992 | bss->capability, CAPINFO_MASK); | ||
993 | |||
994 | /* information on BSSID descriptor passed to FW */ | ||
995 | lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n", | ||
996 | cmd.bss.bssid, cmd.bss.ssid); | ||
997 | |||
998 | /* Only v8 and below support setting these */ | ||
999 | if (priv->fwrelease < 0x09000000) { | ||
1000 | /* failtimeout */ | ||
1001 | cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); | ||
1002 | /* probedelay */ | ||
1003 | cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); | ||
1004 | } | ||
1005 | |||
1006 | /* Copy Data rates from the rates recorded in scan response */ | ||
1007 | memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); | ||
1008 | ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates)); | ||
1009 | memcpy(cmd.bss.rates, bss->rates, ratesize); | ||
1010 | if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { | ||
1011 | lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); | ||
1012 | ret = -1; | ||
1013 | goto out; | ||
1014 | } | ||
1015 | |||
1016 | /* Copy the ad-hoc creation rates into Current BSS state structure */ | ||
1017 | memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); | ||
1018 | memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); | ||
1019 | |||
1020 | /* Set MSB on basic rates as the firmware requires, but _after_ | ||
1021 | * copying to current bss rates. | ||
1022 | */ | ||
1023 | lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); | ||
1024 | |||
1025 | cmd.bss.ibss.atimwindow = bss->atimwindow; | ||
1026 | |||
1027 | if (assoc_req->secinfo.wep_enabled) { | ||
1028 | u16 tmp = le16_to_cpu(cmd.bss.capability); | ||
1029 | tmp |= WLAN_CAPABILITY_PRIVACY; | ||
1030 | cmd.bss.capability = cpu_to_le16(tmp); | ||
1031 | } | ||
1032 | |||
1033 | if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { | ||
1034 | __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); | ||
1035 | |||
1036 | /* wake up first */ | ||
1037 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, | ||
1038 | CMD_ACT_SET, 0, 0, | ||
1039 | &local_ps_mode); | ||
1040 | if (ret) { | ||
1041 | ret = -1; | ||
1042 | goto out; | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); | ||
1047 | if (ret == 0) { | ||
1048 | ret = lbs_adhoc_post(priv, | ||
1049 | (struct cmd_ds_802_11_ad_hoc_result *)&cmd); | ||
1050 | } | ||
1051 | |||
1052 | out: | ||
1053 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1054 | return ret; | ||
1055 | } | ||
1056 | |||
1057 | /** | ||
1058 | * @brief Start an Adhoc Network | ||
1059 | * | ||
1060 | * @param priv A pointer to struct lbs_private structure | ||
1061 | * @param assoc_req The association request describing the BSS to start | ||
1062 | * | ||
1063 | * @return 0 on success, error on failure | ||
1064 | */ | ||
1065 | static int lbs_adhoc_start(struct lbs_private *priv, | ||
1066 | struct assoc_request *assoc_req) | ||
1067 | { | ||
1068 | struct cmd_ds_802_11_ad_hoc_start cmd; | ||
1069 | u8 preamble = RADIO_PREAMBLE_SHORT; | ||
1070 | size_t ratesize = 0; | ||
1071 | u16 tmpcap = 0; | ||
1072 | int ret = 0; | ||
1073 | DECLARE_SSID_BUF(ssid); | ||
1074 | |||
1075 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1076 | |||
1077 | ret = lbs_set_radio(priv, preamble, 1); | ||
1078 | if (ret) | ||
1079 | goto out; | ||
1080 | |||
1081 | /* Build the start command */ | ||
1082 | memset(&cmd, 0, sizeof(cmd)); | ||
1083 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1084 | |||
1085 | memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); | ||
1086 | |||
1087 | lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", | ||
1088 | print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), | ||
1089 | assoc_req->ssid_len); | ||
1090 | |||
1091 | cmd.bsstype = CMD_BSS_TYPE_IBSS; | ||
1092 | |||
1093 | if (priv->beacon_period == 0) | ||
1094 | priv->beacon_period = MRVDRV_BEACON_INTERVAL; | ||
1095 | cmd.beaconperiod = cpu_to_le16(priv->beacon_period); | ||
1096 | |||
1097 | WARN_ON(!assoc_req->channel); | ||
1098 | |||
1099 | /* set Physical parameter set */ | ||
1100 | cmd.ds.header.id = WLAN_EID_DS_PARAMS; | ||
1101 | cmd.ds.header.len = 1; | ||
1102 | cmd.ds.channel = assoc_req->channel; | ||
1103 | |||
1104 | /* set IBSS parameter set */ | ||
1105 | cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; | ||
1106 | cmd.ibss.header.len = 2; | ||
1107 | cmd.ibss.atimwindow = cpu_to_le16(0); | ||
1108 | |||
1109 | /* set capability info */ | ||
1110 | tmpcap = WLAN_CAPABILITY_IBSS; | ||
1111 | if (assoc_req->secinfo.wep_enabled || | ||
1112 | assoc_req->secinfo.WPAenabled || | ||
1113 | assoc_req->secinfo.WPA2enabled) { | ||
1114 | lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); | ||
1115 | tmpcap |= WLAN_CAPABILITY_PRIVACY; | ||
1116 | } else | ||
1117 | lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); | ||
1118 | |||
1119 | cmd.capability = cpu_to_le16(tmpcap); | ||
1120 | |||
1121 | /* Only v8 and below support setting probe delay */ | ||
1122 | if (priv->fwrelease < 0x09000000) | ||
1123 | cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); | ||
1124 | |||
1125 | ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); | ||
1126 | memcpy(cmd.rates, lbs_bg_rates, ratesize); | ||
1127 | |||
1128 | /* Copy the ad-hoc creating rates into Current BSS state structure */ | ||
1129 | memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); | ||
1130 | memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); | ||
1131 | |||
1132 | /* Set MSB on basic rates as the firmware requires, but _after_ | ||
1133 | * copying to current bss rates. | ||
1134 | */ | ||
1135 | lbs_set_basic_rate_flags(cmd.rates, ratesize); | ||
1136 | |||
1137 | lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", | ||
1138 | cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); | ||
1139 | |||
1140 | lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", | ||
1141 | assoc_req->channel, assoc_req->band); | ||
1142 | |||
1143 | priv->adhoccreate = 1; | ||
1144 | priv->mode = IW_MODE_ADHOC; | ||
1145 | |||
1146 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); | ||
1147 | if (ret == 0) | ||
1148 | ret = lbs_adhoc_post(priv, | ||
1149 | (struct cmd_ds_802_11_ad_hoc_result *)&cmd); | ||
1150 | |||
1151 | out: | ||
1152 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1153 | return ret; | ||
1154 | } | ||
1155 | |||
1156 | /** | ||
1157 | * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode | ||
1158 | * | ||
1159 | * @param priv A pointer to struct lbs_private structure | ||
1160 | * @return 0 on success, or an error | ||
1161 | */ | ||
1162 | int lbs_adhoc_stop(struct lbs_private *priv) | ||
1163 | { | ||
1164 | struct cmd_ds_802_11_ad_hoc_stop cmd; | ||
1165 | int ret; | ||
1166 | |||
1167 | lbs_deb_enter(LBS_DEB_JOIN); | ||
1168 | |||
1169 | memset(&cmd, 0, sizeof (cmd)); | ||
1170 | cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); | ||
1171 | |||
1172 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); | ||
1173 | |||
1174 | /* Clean up everything even if there was an error */ | ||
1175 | lbs_mac_event_disconnected(priv); | ||
1176 | |||
1177 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1178 | return ret; | ||
1179 | } | ||
1180 | |||
1181 | static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, | ||
1182 | struct bss_descriptor *match_bss) | ||
1183 | { | ||
1184 | if (!secinfo->wep_enabled && | ||
1185 | !secinfo->WPAenabled && !secinfo->WPA2enabled && | ||
1186 | match_bss->wpa_ie[0] != WLAN_EID_GENERIC && | ||
1187 | match_bss->rsn_ie[0] != WLAN_EID_RSN && | ||
1188 | !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) | ||
1189 | return 1; | ||
1190 | else | ||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, | ||
1195 | struct bss_descriptor *match_bss) | ||
1196 | { | ||
1197 | if (secinfo->wep_enabled && | ||
1198 | !secinfo->WPAenabled && !secinfo->WPA2enabled && | ||
1199 | (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) | ||
1200 | return 1; | ||
1201 | else | ||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, | ||
1206 | struct bss_descriptor *match_bss) | ||
1207 | { | ||
1208 | if (!secinfo->wep_enabled && secinfo->WPAenabled && | ||
1209 | (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) | ||
1210 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
1211 | && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ | ||
1212 | ) | ||
1213 | return 1; | ||
1214 | else | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, | ||
1219 | struct bss_descriptor *match_bss) | ||
1220 | { | ||
1221 | if (!secinfo->wep_enabled && secinfo->WPA2enabled && | ||
1222 | (match_bss->rsn_ie[0] == WLAN_EID_RSN) | ||
1223 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
1224 | (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ | ||
1225 | ) | ||
1226 | return 1; | ||
1227 | else | ||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, | ||
1232 | struct bss_descriptor *match_bss) | ||
1233 | { | ||
1234 | if (!secinfo->wep_enabled && | ||
1235 | !secinfo->WPAenabled && !secinfo->WPA2enabled && | ||
1236 | (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) && | ||
1237 | (match_bss->rsn_ie[0] != WLAN_EID_RSN) && | ||
1238 | (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) | ||
1239 | return 1; | ||
1240 | else | ||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | /** | ||
1245 | * @brief Check if a scanned network compatible with the driver settings | ||
1246 | * | ||
1247 | * WEP WPA WPA2 ad-hoc encrypt Network | ||
1248 | * enabled enabled enabled AES mode privacy WPA WPA2 Compatible | ||
1249 | * 0 0 0 0 NONE 0 0 0 yes No security | ||
1250 | * 1 0 0 0 NONE 1 0 0 yes Static WEP | ||
1251 | * 0 1 0 0 x 1x 1 x yes WPA | ||
1252 | * 0 0 1 0 x 1x x 1 yes WPA2 | ||
1253 | * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES | ||
1254 | * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP | ||
1255 | * | ||
1256 | * | ||
1257 | * @param priv A pointer to struct lbs_private | ||
1258 | * @param index Index in scantable to check against current driver settings | ||
1259 | * @param mode Network mode: Infrastructure or IBSS | ||
1260 | * | ||
1261 | * @return Index in scantable, or error code if negative | ||
1262 | */ | ||
1263 | static int is_network_compatible(struct lbs_private *priv, | ||
1264 | struct bss_descriptor *bss, uint8_t mode) | ||
1265 | { | ||
1266 | int matched = 0; | ||
1267 | |||
1268 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1269 | |||
1270 | if (bss->mode != mode) | ||
1271 | goto done; | ||
1272 | |||
1273 | matched = match_bss_no_security(&priv->secinfo, bss); | ||
1274 | if (matched) | ||
1275 | goto done; | ||
1276 | matched = match_bss_static_wep(&priv->secinfo, bss); | ||
1277 | if (matched) | ||
1278 | goto done; | ||
1279 | matched = match_bss_wpa(&priv->secinfo, bss); | ||
1280 | if (matched) { | ||
1281 | lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x " | ||
1282 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " | ||
1283 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], | ||
1284 | priv->secinfo.wep_enabled ? "e" : "d", | ||
1285 | priv->secinfo.WPAenabled ? "e" : "d", | ||
1286 | priv->secinfo.WPA2enabled ? "e" : "d", | ||
1287 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
1288 | goto done; | ||
1289 | } | ||
1290 | matched = match_bss_wpa2(&priv->secinfo, bss); | ||
1291 | if (matched) { | ||
1292 | lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x " | ||
1293 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " | ||
1294 | "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], | ||
1295 | priv->secinfo.wep_enabled ? "e" : "d", | ||
1296 | priv->secinfo.WPAenabled ? "e" : "d", | ||
1297 | priv->secinfo.WPA2enabled ? "e" : "d", | ||
1298 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
1299 | goto done; | ||
1300 | } | ||
1301 | matched = match_bss_dynamic_wep(&priv->secinfo, bss); | ||
1302 | if (matched) { | ||
1303 | lbs_deb_scan("is_network_compatible() dynamic WEP: " | ||
1304 | "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", | ||
1305 | bss->wpa_ie[0], bss->rsn_ie[0], | ||
1306 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
1307 | goto done; | ||
1308 | } | ||
1309 | |||
1310 | /* bss security settings don't match those configured on card */ | ||
1311 | lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x " | ||
1312 | "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", | ||
1313 | bss->wpa_ie[0], bss->rsn_ie[0], | ||
1314 | priv->secinfo.wep_enabled ? "e" : "d", | ||
1315 | priv->secinfo.WPAenabled ? "e" : "d", | ||
1316 | priv->secinfo.WPA2enabled ? "e" : "d", | ||
1317 | (bss->capability & WLAN_CAPABILITY_PRIVACY)); | ||
1318 | |||
1319 | done: | ||
1320 | lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); | ||
1321 | return matched; | ||
1322 | } | ||
1323 | |||
1324 | /** | ||
1325 | * @brief This function finds a specific compatible BSSID in the scan list | ||
1326 | * | ||
1327 | * Used in association code | ||
1328 | * | ||
1329 | * @param priv A pointer to struct lbs_private | ||
1330 | * @param bssid BSSID to find in the scan list | ||
1331 | * @param mode Network mode: Infrastructure or IBSS | ||
1332 | * | ||
1333 | * @return index in BSSID list, or error return code (< 0) | ||
1334 | */ | ||
1335 | static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, | ||
1336 | uint8_t *bssid, uint8_t mode) | ||
1337 | { | ||
1338 | struct bss_descriptor *iter_bss; | ||
1339 | struct bss_descriptor *found_bss = NULL; | ||
1340 | |||
1341 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1342 | |||
1343 | if (!bssid) | ||
1344 | goto out; | ||
1345 | |||
1346 | lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); | ||
1347 | |||
1348 | /* Look through the scan table for a compatible match. The loop will | ||
1349 | * continue past a matched bssid that is not compatible in case there | ||
1350 | * is an AP with multiple SSIDs assigned to the same BSSID | ||
1351 | */ | ||
1352 | mutex_lock(&priv->lock); | ||
1353 | list_for_each_entry(iter_bss, &priv->network_list, list) { | ||
1354 | if (compare_ether_addr(iter_bss->bssid, bssid)) | ||
1355 | continue; /* bssid doesn't match */ | ||
1356 | switch (mode) { | ||
1357 | case IW_MODE_INFRA: | ||
1358 | case IW_MODE_ADHOC: | ||
1359 | if (!is_network_compatible(priv, iter_bss, mode)) | ||
1360 | break; | ||
1361 | found_bss = iter_bss; | ||
1362 | break; | ||
1363 | default: | ||
1364 | found_bss = iter_bss; | ||
1365 | break; | ||
1366 | } | ||
1367 | } | ||
1368 | mutex_unlock(&priv->lock); | ||
1369 | |||
1370 | out: | ||
1371 | lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); | ||
1372 | return found_bss; | ||
1373 | } | ||
1374 | |||
1375 | /** | ||
1376 | * @brief This function finds ssid in ssid list. | ||
1377 | * | ||
1378 | * Used in association code | ||
1379 | * | ||
1380 | * @param priv A pointer to struct lbs_private | ||
1381 | * @param ssid SSID to find in the list | ||
1382 | * @param bssid BSSID to qualify the SSID selection (if provided) | ||
1383 | * @param mode Network mode: Infrastructure or IBSS | ||
1384 | * | ||
1385 | * @return index in BSSID list | ||
1386 | */ | ||
1387 | static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, | ||
1388 | uint8_t *ssid, uint8_t ssid_len, | ||
1389 | uint8_t *bssid, uint8_t mode, | ||
1390 | int channel) | ||
1391 | { | ||
1392 | u32 bestrssi = 0; | ||
1393 | struct bss_descriptor *iter_bss = NULL; | ||
1394 | struct bss_descriptor *found_bss = NULL; | ||
1395 | struct bss_descriptor *tmp_oldest = NULL; | ||
1396 | |||
1397 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1398 | |||
1399 | mutex_lock(&priv->lock); | ||
1400 | |||
1401 | list_for_each_entry(iter_bss, &priv->network_list, list) { | ||
1402 | if (!tmp_oldest || | ||
1403 | (iter_bss->last_scanned < tmp_oldest->last_scanned)) | ||
1404 | tmp_oldest = iter_bss; | ||
1405 | |||
1406 | if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, | ||
1407 | ssid, ssid_len) != 0) | ||
1408 | continue; /* ssid doesn't match */ | ||
1409 | if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) | ||
1410 | continue; /* bssid doesn't match */ | ||
1411 | if ((channel > 0) && (iter_bss->channel != channel)) | ||
1412 | continue; /* channel doesn't match */ | ||
1413 | |||
1414 | switch (mode) { | ||
1415 | case IW_MODE_INFRA: | ||
1416 | case IW_MODE_ADHOC: | ||
1417 | if (!is_network_compatible(priv, iter_bss, mode)) | ||
1418 | break; | ||
1419 | |||
1420 | if (bssid) { | ||
1421 | /* Found requested BSSID */ | ||
1422 | found_bss = iter_bss; | ||
1423 | goto out; | ||
1424 | } | ||
1425 | |||
1426 | if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { | ||
1427 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1428 | found_bss = iter_bss; | ||
1429 | } | ||
1430 | break; | ||
1431 | case IW_MODE_AUTO: | ||
1432 | default: | ||
1433 | if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { | ||
1434 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1435 | found_bss = iter_bss; | ||
1436 | } | ||
1437 | break; | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | out: | ||
1442 | mutex_unlock(&priv->lock); | ||
1443 | lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); | ||
1444 | return found_bss; | ||
1445 | } | ||
1446 | |||
1447 | static int assoc_helper_essid(struct lbs_private *priv, | ||
1448 | struct assoc_request * assoc_req) | ||
1449 | { | ||
1450 | int ret = 0; | ||
1451 | struct bss_descriptor * bss; | ||
1452 | int channel = -1; | ||
1453 | DECLARE_SSID_BUF(ssid); | ||
1454 | |||
1455 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1456 | |||
1457 | /* FIXME: take channel into account when picking SSIDs if a channel | ||
1458 | * is set. | ||
1459 | */ | ||
1460 | |||
1461 | if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) | ||
1462 | channel = assoc_req->channel; | ||
1463 | |||
1464 | lbs_deb_assoc("SSID '%s' requested\n", | ||
1465 | print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len)); | ||
1466 | if (assoc_req->mode == IW_MODE_INFRA) { | ||
1467 | lbs_send_specific_ssid_scan(priv, assoc_req->ssid, | ||
1468 | assoc_req->ssid_len); | ||
1469 | |||
1470 | bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, | ||
1471 | assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); | ||
1472 | if (bss != NULL) { | ||
1473 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); | ||
1474 | ret = lbs_try_associate(priv, assoc_req); | ||
1475 | } else { | ||
1476 | lbs_deb_assoc("SSID not found; cannot associate\n"); | ||
1477 | } | ||
1478 | } else if (assoc_req->mode == IW_MODE_ADHOC) { | ||
1479 | /* Scan for the network, do not save previous results. Stale | ||
1480 | * scan data will cause us to join a non-existant adhoc network | ||
1481 | */ | ||
1482 | lbs_send_specific_ssid_scan(priv, assoc_req->ssid, | ||
1483 | assoc_req->ssid_len); | ||
1484 | |||
1485 | /* Search for the requested SSID in the scan table */ | ||
1486 | bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, | ||
1487 | assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel); | ||
1488 | if (bss != NULL) { | ||
1489 | lbs_deb_assoc("SSID found, will join\n"); | ||
1490 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); | ||
1491 | lbs_adhoc_join(priv, assoc_req); | ||
1492 | } else { | ||
1493 | /* else send START command */ | ||
1494 | lbs_deb_assoc("SSID not found, creating adhoc network\n"); | ||
1495 | memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, | ||
1496 | IEEE80211_MAX_SSID_LEN); | ||
1497 | assoc_req->bss.ssid_len = assoc_req->ssid_len; | ||
1498 | lbs_adhoc_start(priv, assoc_req); | ||
1499 | } | ||
1500 | } | ||
1501 | |||
1502 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1503 | return ret; | ||
1504 | } | ||
1505 | |||
1506 | |||
1507 | static int assoc_helper_bssid(struct lbs_private *priv, | ||
1508 | struct assoc_request * assoc_req) | ||
1509 | { | ||
1510 | int ret = 0; | ||
1511 | struct bss_descriptor * bss; | ||
1512 | |||
1513 | lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid); | ||
1514 | |||
1515 | /* Search for index position in list for requested MAC */ | ||
1516 | bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, | ||
1517 | assoc_req->mode); | ||
1518 | if (bss == NULL) { | ||
1519 | lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, " | ||
1520 | "cannot associate.\n", assoc_req->bssid); | ||
1521 | goto out; | ||
1522 | } | ||
1523 | |||
1524 | memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); | ||
1525 | if (assoc_req->mode == IW_MODE_INFRA) { | ||
1526 | ret = lbs_try_associate(priv, assoc_req); | ||
1527 | lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", | ||
1528 | ret); | ||
1529 | } else if (assoc_req->mode == IW_MODE_ADHOC) { | ||
1530 | lbs_adhoc_join(priv, assoc_req); | ||
1531 | } | ||
1532 | |||
1533 | out: | ||
1534 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1535 | return ret; | ||
1536 | } | ||
1537 | |||
1538 | |||
1539 | static int assoc_helper_associate(struct lbs_private *priv, | ||
1540 | struct assoc_request * assoc_req) | ||
1541 | { | ||
1542 | int ret = 0, done = 0; | ||
1543 | |||
1544 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1545 | |||
1546 | /* If we're given and 'any' BSSID, try associating based on SSID */ | ||
1547 | |||
1548 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
1549 | if (compare_ether_addr(bssid_any, assoc_req->bssid) && | ||
1550 | compare_ether_addr(bssid_off, assoc_req->bssid)) { | ||
1551 | ret = assoc_helper_bssid(priv, assoc_req); | ||
1552 | done = 1; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
1557 | ret = assoc_helper_essid(priv, assoc_req); | ||
1558 | } | ||
1559 | |||
1560 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1561 | return ret; | ||
1562 | } | ||
1563 | |||
1564 | |||
1565 | static int assoc_helper_mode(struct lbs_private *priv, | ||
1566 | struct assoc_request * assoc_req) | ||
1567 | { | ||
1568 | int ret = 0; | ||
1569 | |||
1570 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1571 | |||
1572 | if (assoc_req->mode == priv->mode) | ||
1573 | goto done; | ||
1574 | |||
1575 | if (assoc_req->mode == IW_MODE_INFRA) { | ||
1576 | if (priv->psstate != PS_STATE_FULL_POWER) | ||
1577 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); | ||
1578 | priv->psmode = LBS802_11POWERMODECAM; | ||
1579 | } | ||
1580 | |||
1581 | priv->mode = assoc_req->mode; | ||
1582 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, | ||
1583 | assoc_req->mode == IW_MODE_ADHOC ? 2 : 1); | ||
1584 | |||
1585 | done: | ||
1586 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1587 | return ret; | ||
1588 | } | ||
1589 | |||
1590 | static int assoc_helper_channel(struct lbs_private *priv, | ||
1591 | struct assoc_request * assoc_req) | ||
1592 | { | ||
1593 | int ret = 0; | ||
1594 | |||
1595 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1596 | |||
1597 | ret = lbs_update_channel(priv); | ||
1598 | if (ret) { | ||
1599 | lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); | ||
1600 | goto done; | ||
1601 | } | ||
1602 | |||
1603 | if (assoc_req->channel == priv->channel) | ||
1604 | goto done; | ||
1605 | |||
1606 | if (priv->mesh_dev) { | ||
1607 | /* Change mesh channel first; 21.p21 firmware won't let | ||
1608 | you change channel otherwise (even though it'll return | ||
1609 | an error to this */ | ||
1610 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, | ||
1611 | assoc_req->channel); | ||
1612 | } | ||
1613 | |||
1614 | lbs_deb_assoc("ASSOC: channel: %d -> %d\n", | ||
1615 | priv->channel, assoc_req->channel); | ||
1616 | |||
1617 | ret = lbs_set_channel(priv, assoc_req->channel); | ||
1618 | if (ret < 0) | ||
1619 | lbs_deb_assoc("ASSOC: channel: error setting channel.\n"); | ||
1620 | |||
1621 | /* FIXME: shouldn't need to grab the channel _again_ after setting | ||
1622 | * it since the firmware is supposed to return the new channel, but | ||
1623 | * whatever... */ | ||
1624 | ret = lbs_update_channel(priv); | ||
1625 | if (ret) { | ||
1626 | lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); | ||
1627 | goto done; | ||
1628 | } | ||
1629 | |||
1630 | if (assoc_req->channel != priv->channel) { | ||
1631 | lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", | ||
1632 | assoc_req->channel); | ||
1633 | goto restore_mesh; | ||
1634 | } | ||
1635 | |||
1636 | if (assoc_req->secinfo.wep_enabled && | ||
1637 | (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || | ||
1638 | assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) { | ||
1639 | /* Make sure WEP keys are re-sent to firmware */ | ||
1640 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
1641 | } | ||
1642 | |||
1643 | /* Must restart/rejoin adhoc networks after channel change */ | ||
1644 | set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); | ||
1645 | |||
1646 | restore_mesh: | ||
1647 | if (priv->mesh_dev) | ||
1648 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | ||
1649 | priv->channel); | ||
1650 | |||
1651 | done: | ||
1652 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1653 | return ret; | ||
1654 | } | ||
1655 | |||
1656 | |||
1657 | static int assoc_helper_wep_keys(struct lbs_private *priv, | ||
1658 | struct assoc_request *assoc_req) | ||
1659 | { | ||
1660 | int i; | ||
1661 | int ret = 0; | ||
1662 | |||
1663 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1664 | |||
1665 | /* Set or remove WEP keys */ | ||
1666 | if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || | ||
1667 | assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len) | ||
1668 | ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req); | ||
1669 | else | ||
1670 | ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req); | ||
1671 | |||
1672 | if (ret) | ||
1673 | goto out; | ||
1674 | |||
1675 | /* enable/disable the MAC's WEP packet filter */ | ||
1676 | if (assoc_req->secinfo.wep_enabled) | ||
1677 | priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; | ||
1678 | else | ||
1679 | priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; | ||
1680 | |||
1681 | lbs_set_mac_control(priv); | ||
1682 | |||
1683 | mutex_lock(&priv->lock); | ||
1684 | |||
1685 | /* Copy WEP keys into priv wep key fields */ | ||
1686 | for (i = 0; i < 4; i++) { | ||
1687 | memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i], | ||
1688 | sizeof(struct enc_key)); | ||
1689 | } | ||
1690 | priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx; | ||
1691 | |||
1692 | mutex_unlock(&priv->lock); | ||
1693 | |||
1694 | out: | ||
1695 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1696 | return ret; | ||
1697 | } | ||
1698 | |||
1699 | static int assoc_helper_secinfo(struct lbs_private *priv, | ||
1700 | struct assoc_request * assoc_req) | ||
1701 | { | ||
1702 | int ret = 0; | ||
1703 | uint16_t do_wpa; | ||
1704 | uint16_t rsn = 0; | ||
1705 | |||
1706 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1707 | |||
1708 | memcpy(&priv->secinfo, &assoc_req->secinfo, | ||
1709 | sizeof(struct lbs_802_11_security)); | ||
1710 | |||
1711 | lbs_set_mac_control(priv); | ||
1712 | |||
1713 | /* If RSN is already enabled, don't try to enable it again, since | ||
1714 | * ENABLE_RSN resets internal state machines and will clobber the | ||
1715 | * 4-way WPA handshake. | ||
1716 | */ | ||
1717 | |||
1718 | /* Get RSN enabled/disabled */ | ||
1719 | ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn); | ||
1720 | if (ret) { | ||
1721 | lbs_deb_assoc("Failed to get RSN status: %d\n", ret); | ||
1722 | goto out; | ||
1723 | } | ||
1724 | |||
1725 | /* Don't re-enable RSN if it's already enabled */ | ||
1726 | do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled; | ||
1727 | if (do_wpa == rsn) | ||
1728 | goto out; | ||
1729 | |||
1730 | /* Set RSN enabled/disabled */ | ||
1731 | ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa); | ||
1732 | |||
1733 | out: | ||
1734 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1735 | return ret; | ||
1736 | } | ||
1737 | |||
1738 | |||
1739 | static int assoc_helper_wpa_keys(struct lbs_private *priv, | ||
1740 | struct assoc_request * assoc_req) | ||
1741 | { | ||
1742 | int ret = 0; | ||
1743 | unsigned int flags = assoc_req->flags; | ||
1744 | |||
1745 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1746 | |||
1747 | /* Work around older firmware bug where WPA unicast and multicast | ||
1748 | * keys must be set independently. Seen in SDIO parts with firmware | ||
1749 | * version 5.0.11p0. | ||
1750 | */ | ||
1751 | |||
1752 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | ||
1753 | clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); | ||
1754 | ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); | ||
1755 | assoc_req->flags = flags; | ||
1756 | } | ||
1757 | |||
1758 | if (ret) | ||
1759 | goto out; | ||
1760 | |||
1761 | memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key, | ||
1762 | sizeof(struct enc_key)); | ||
1763 | |||
1764 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { | ||
1765 | clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); | ||
1766 | |||
1767 | ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); | ||
1768 | assoc_req->flags = flags; | ||
1769 | |||
1770 | memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key, | ||
1771 | sizeof(struct enc_key)); | ||
1772 | } | ||
1773 | |||
1774 | out: | ||
1775 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1776 | return ret; | ||
1777 | } | ||
1778 | |||
1779 | |||
1780 | static int assoc_helper_wpa_ie(struct lbs_private *priv, | ||
1781 | struct assoc_request * assoc_req) | ||
1782 | { | ||
1783 | int ret = 0; | ||
1784 | |||
1785 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1786 | |||
1787 | if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { | ||
1788 | memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); | ||
1789 | priv->wpa_ie_len = assoc_req->wpa_ie_len; | ||
1790 | } else { | ||
1791 | memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN); | ||
1792 | priv->wpa_ie_len = 0; | ||
1793 | } | ||
1794 | |||
1795 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1796 | return ret; | ||
1797 | } | ||
1798 | |||
1799 | |||
1800 | static int should_deauth_infrastructure(struct lbs_private *priv, | ||
1801 | struct assoc_request * assoc_req) | ||
1802 | { | ||
1803 | int ret = 0; | ||
1804 | |||
1805 | if (priv->connect_status != LBS_CONNECTED) | ||
1806 | return 0; | ||
1807 | |||
1808 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1809 | if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
1810 | lbs_deb_assoc("Deauthenticating due to new SSID\n"); | ||
1811 | ret = 1; | ||
1812 | goto out; | ||
1813 | } | ||
1814 | |||
1815 | if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
1816 | if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { | ||
1817 | lbs_deb_assoc("Deauthenticating due to new security\n"); | ||
1818 | ret = 1; | ||
1819 | goto out; | ||
1820 | } | ||
1821 | } | ||
1822 | |||
1823 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
1824 | lbs_deb_assoc("Deauthenticating due to new BSSID\n"); | ||
1825 | ret = 1; | ||
1826 | goto out; | ||
1827 | } | ||
1828 | |||
1829 | if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { | ||
1830 | lbs_deb_assoc("Deauthenticating due to channel switch\n"); | ||
1831 | ret = 1; | ||
1832 | goto out; | ||
1833 | } | ||
1834 | |||
1835 | /* FIXME: deal with 'auto' mode somehow */ | ||
1836 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
1837 | if (assoc_req->mode != IW_MODE_INFRA) { | ||
1838 | lbs_deb_assoc("Deauthenticating due to leaving " | ||
1839 | "infra mode\n"); | ||
1840 | ret = 1; | ||
1841 | goto out; | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1845 | out: | ||
1846 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | ||
1847 | return ret; | ||
1848 | } | ||
1849 | |||
1850 | |||
1851 | static int should_stop_adhoc(struct lbs_private *priv, | ||
1852 | struct assoc_request * assoc_req) | ||
1853 | { | ||
1854 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1855 | |||
1856 | if (priv->connect_status != LBS_CONNECTED) | ||
1857 | return 0; | ||
1858 | |||
1859 | if (lbs_ssid_cmp(priv->curbssparams.ssid, | ||
1860 | priv->curbssparams.ssid_len, | ||
1861 | assoc_req->ssid, assoc_req->ssid_len) != 0) | ||
1862 | return 1; | ||
1863 | |||
1864 | /* FIXME: deal with 'auto' mode somehow */ | ||
1865 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
1866 | if (assoc_req->mode != IW_MODE_ADHOC) | ||
1867 | return 1; | ||
1868 | } | ||
1869 | |||
1870 | if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { | ||
1871 | if (assoc_req->channel != priv->channel) | ||
1872 | return 1; | ||
1873 | } | ||
1874 | |||
1875 | lbs_deb_leave(LBS_DEB_ASSOC); | ||
1876 | return 0; | ||
1877 | } | ||
1878 | |||
1879 | |||
1880 | /** | ||
1881 | * @brief This function finds the best SSID in the Scan List | ||
1882 | * | ||
1883 | * Search the scan table for the best SSID that also matches the current | ||
1884 | * adapter network preference (infrastructure or adhoc) | ||
1885 | * | ||
1886 | * @param priv A pointer to struct lbs_private | ||
1887 | * | ||
1888 | * @return index in BSSID list | ||
1889 | */ | ||
1890 | static struct bss_descriptor *lbs_find_best_ssid_in_list( | ||
1891 | struct lbs_private *priv, uint8_t mode) | ||
1892 | { | ||
1893 | uint8_t bestrssi = 0; | ||
1894 | struct bss_descriptor *iter_bss; | ||
1895 | struct bss_descriptor *best_bss = NULL; | ||
1896 | |||
1897 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1898 | |||
1899 | mutex_lock(&priv->lock); | ||
1900 | |||
1901 | list_for_each_entry(iter_bss, &priv->network_list, list) { | ||
1902 | switch (mode) { | ||
1903 | case IW_MODE_INFRA: | ||
1904 | case IW_MODE_ADHOC: | ||
1905 | if (!is_network_compatible(priv, iter_bss, mode)) | ||
1906 | break; | ||
1907 | if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) | ||
1908 | break; | ||
1909 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1910 | best_bss = iter_bss; | ||
1911 | break; | ||
1912 | case IW_MODE_AUTO: | ||
1913 | default: | ||
1914 | if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) | ||
1915 | break; | ||
1916 | bestrssi = SCAN_RSSI(iter_bss->rssi); | ||
1917 | best_bss = iter_bss; | ||
1918 | break; | ||
1919 | } | ||
1920 | } | ||
1921 | |||
1922 | mutex_unlock(&priv->lock); | ||
1923 | lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); | ||
1924 | return best_bss; | ||
1925 | } | ||
1926 | |||
1927 | /** | ||
1928 | * @brief Find the best AP | ||
1929 | * | ||
1930 | * Used from association worker. | ||
1931 | * | ||
1932 | * @param priv A pointer to struct lbs_private structure | ||
1933 | * @param pSSID A pointer to AP's ssid | ||
1934 | * | ||
1935 | * @return 0--success, otherwise--fail | ||
1936 | */ | ||
1937 | static int lbs_find_best_network_ssid(struct lbs_private *priv, | ||
1938 | uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode, | ||
1939 | uint8_t *out_mode) | ||
1940 | { | ||
1941 | int ret = -1; | ||
1942 | struct bss_descriptor *found; | ||
1943 | |||
1944 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1945 | |||
1946 | priv->scan_ssid_len = 0; | ||
1947 | lbs_scan_networks(priv, 1); | ||
1948 | if (priv->surpriseremoved) | ||
1949 | goto out; | ||
1950 | |||
1951 | found = lbs_find_best_ssid_in_list(priv, preferred_mode); | ||
1952 | if (found && (found->ssid_len > 0)) { | ||
1953 | memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN); | ||
1954 | *out_ssid_len = found->ssid_len; | ||
1955 | *out_mode = found->mode; | ||
1956 | ret = 0; | ||
1957 | } | ||
1958 | |||
1959 | out: | ||
1960 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
1961 | return ret; | ||
1962 | } | ||
1963 | |||
1964 | |||
1965 | void lbs_association_worker(struct work_struct *work) | ||
1966 | { | ||
1967 | struct lbs_private *priv = container_of(work, struct lbs_private, | ||
1968 | assoc_work.work); | ||
1969 | struct assoc_request * assoc_req = NULL; | ||
1970 | int ret = 0; | ||
1971 | int find_any_ssid = 0; | ||
1972 | DECLARE_SSID_BUF(ssid); | ||
1973 | |||
1974 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
1975 | |||
1976 | mutex_lock(&priv->lock); | ||
1977 | assoc_req = priv->pending_assoc_req; | ||
1978 | priv->pending_assoc_req = NULL; | ||
1979 | priv->in_progress_assoc_req = assoc_req; | ||
1980 | mutex_unlock(&priv->lock); | ||
1981 | |||
1982 | if (!assoc_req) | ||
1983 | goto done; | ||
1984 | |||
1985 | lbs_deb_assoc( | ||
1986 | "Association Request:\n" | ||
1987 | " flags: 0x%08lx\n" | ||
1988 | " SSID: '%s'\n" | ||
1989 | " chann: %d\n" | ||
1990 | " band: %d\n" | ||
1991 | " mode: %d\n" | ||
1992 | " BSSID: %pM\n" | ||
1993 | " secinfo: %s%s%s\n" | ||
1994 | " auth_mode: %d\n", | ||
1995 | assoc_req->flags, | ||
1996 | print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), | ||
1997 | assoc_req->channel, assoc_req->band, assoc_req->mode, | ||
1998 | assoc_req->bssid, | ||
1999 | assoc_req->secinfo.WPAenabled ? " WPA" : "", | ||
2000 | assoc_req->secinfo.WPA2enabled ? " WPA2" : "", | ||
2001 | assoc_req->secinfo.wep_enabled ? " WEP" : "", | ||
2002 | assoc_req->secinfo.auth_mode); | ||
2003 | |||
2004 | /* If 'any' SSID was specified, find an SSID to associate with */ | ||
2005 | if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) && | ||
2006 | !assoc_req->ssid_len) | ||
2007 | find_any_ssid = 1; | ||
2008 | |||
2009 | /* But don't use 'any' SSID if there's a valid locked BSSID to use */ | ||
2010 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
2011 | if (compare_ether_addr(assoc_req->bssid, bssid_any) && | ||
2012 | compare_ether_addr(assoc_req->bssid, bssid_off)) | ||
2013 | find_any_ssid = 0; | ||
2014 | } | ||
2015 | |||
2016 | if (find_any_ssid) { | ||
2017 | u8 new_mode = assoc_req->mode; | ||
2018 | |||
2019 | ret = lbs_find_best_network_ssid(priv, assoc_req->ssid, | ||
2020 | &assoc_req->ssid_len, assoc_req->mode, &new_mode); | ||
2021 | if (ret) { | ||
2022 | lbs_deb_assoc("Could not find best network\n"); | ||
2023 | ret = -ENETUNREACH; | ||
2024 | goto out; | ||
2025 | } | ||
2026 | |||
2027 | /* Ensure we switch to the mode of the AP */ | ||
2028 | if (assoc_req->mode == IW_MODE_AUTO) { | ||
2029 | set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); | ||
2030 | assoc_req->mode = new_mode; | ||
2031 | } | ||
2032 | } | ||
2033 | |||
2034 | /* | ||
2035 | * Check if the attributes being changing require deauthentication | ||
2036 | * from the currently associated infrastructure access point. | ||
2037 | */ | ||
2038 | if (priv->mode == IW_MODE_INFRA) { | ||
2039 | if (should_deauth_infrastructure(priv, assoc_req)) { | ||
2040 | ret = lbs_cmd_80211_deauthenticate(priv, | ||
2041 | priv->curbssparams.bssid, | ||
2042 | WLAN_REASON_DEAUTH_LEAVING); | ||
2043 | if (ret) { | ||
2044 | lbs_deb_assoc("Deauthentication due to new " | ||
2045 | "configuration request failed: %d\n", | ||
2046 | ret); | ||
2047 | } | ||
2048 | } | ||
2049 | } else if (priv->mode == IW_MODE_ADHOC) { | ||
2050 | if (should_stop_adhoc(priv, assoc_req)) { | ||
2051 | ret = lbs_adhoc_stop(priv); | ||
2052 | if (ret) { | ||
2053 | lbs_deb_assoc("Teardown of AdHoc network due to " | ||
2054 | "new configuration request failed: %d\n", | ||
2055 | ret); | ||
2056 | } | ||
2057 | |||
2058 | } | ||
2059 | } | ||
2060 | |||
2061 | /* Send the various configuration bits to the firmware */ | ||
2062 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
2063 | ret = assoc_helper_mode(priv, assoc_req); | ||
2064 | if (ret) | ||
2065 | goto out; | ||
2066 | } | ||
2067 | |||
2068 | if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { | ||
2069 | ret = assoc_helper_channel(priv, assoc_req); | ||
2070 | if (ret) | ||
2071 | goto out; | ||
2072 | } | ||
2073 | |||
2074 | if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
2075 | ret = assoc_helper_secinfo(priv, assoc_req); | ||
2076 | if (ret) | ||
2077 | goto out; | ||
2078 | } | ||
2079 | |||
2080 | if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { | ||
2081 | ret = assoc_helper_wpa_ie(priv, assoc_req); | ||
2082 | if (ret) | ||
2083 | goto out; | ||
2084 | } | ||
2085 | |||
2086 | /* | ||
2087 | * v10 FW wants WPA keys to be set/cleared before WEP key operations, | ||
2088 | * otherwise it will fail to correctly associate to WEP networks. | ||
2089 | * Other firmware versions don't appear to care. | ||
2090 | */ | ||
2091 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) || | ||
2092 | test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | ||
2093 | ret = assoc_helper_wpa_keys(priv, assoc_req); | ||
2094 | if (ret) | ||
2095 | goto out; | ||
2096 | } | ||
2097 | |||
2098 | if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) || | ||
2099 | test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { | ||
2100 | ret = assoc_helper_wep_keys(priv, assoc_req); | ||
2101 | if (ret) | ||
2102 | goto out; | ||
2103 | } | ||
2104 | |||
2105 | |||
2106 | /* SSID/BSSID should be the _last_ config option set, because they | ||
2107 | * trigger the association attempt. | ||
2108 | */ | ||
2109 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) || | ||
2110 | test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
2111 | int success = 1; | ||
2112 | |||
2113 | ret = assoc_helper_associate(priv, assoc_req); | ||
2114 | if (ret) { | ||
2115 | lbs_deb_assoc("ASSOC: association unsuccessful: %d\n", | ||
2116 | ret); | ||
2117 | success = 0; | ||
2118 | } | ||
2119 | |||
2120 | if (priv->connect_status != LBS_CONNECTED) { | ||
2121 | lbs_deb_assoc("ASSOC: association unsuccessful, " | ||
2122 | "not connected\n"); | ||
2123 | success = 0; | ||
2124 | } | ||
2125 | |||
2126 | if (success) { | ||
2127 | lbs_deb_assoc("associated to %pM\n", | ||
2128 | priv->curbssparams.bssid); | ||
2129 | lbs_prepare_and_send_command(priv, | ||
2130 | CMD_802_11_RSSI, | ||
2131 | 0, CMD_OPTION_WAITFORRSP, 0, NULL); | ||
2132 | } else { | ||
2133 | ret = -1; | ||
2134 | } | ||
2135 | } | ||
2136 | |||
2137 | out: | ||
2138 | if (ret) { | ||
2139 | lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n", | ||
2140 | ret); | ||
2141 | } | ||
2142 | |||
2143 | mutex_lock(&priv->lock); | ||
2144 | priv->in_progress_assoc_req = NULL; | ||
2145 | mutex_unlock(&priv->lock); | ||
2146 | kfree(assoc_req); | ||
2147 | |||
2148 | done: | ||
2149 | lbs_deb_leave(LBS_DEB_ASSOC); | ||
2150 | } | ||
2151 | |||
2152 | |||
2153 | /* | ||
2154 | * Caller MUST hold any necessary locks | ||
2155 | */ | ||
2156 | struct assoc_request *lbs_get_association_request(struct lbs_private *priv) | ||
2157 | { | ||
2158 | struct assoc_request * assoc_req; | ||
2159 | |||
2160 | lbs_deb_enter(LBS_DEB_ASSOC); | ||
2161 | if (!priv->pending_assoc_req) { | ||
2162 | priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request), | ||
2163 | GFP_KERNEL); | ||
2164 | if (!priv->pending_assoc_req) { | ||
2165 | lbs_pr_info("Not enough memory to allocate association" | ||
2166 | " request!\n"); | ||
2167 | return NULL; | ||
2168 | } | ||
2169 | } | ||
2170 | |||
2171 | /* Copy current configuration attributes to the association request, | ||
2172 | * but don't overwrite any that are already set. | ||
2173 | */ | ||
2174 | assoc_req = priv->pending_assoc_req; | ||
2175 | if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
2176 | memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, | ||
2177 | IEEE80211_MAX_SSID_LEN); | ||
2178 | assoc_req->ssid_len = priv->curbssparams.ssid_len; | ||
2179 | } | ||
2180 | |||
2181 | if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) | ||
2182 | assoc_req->channel = priv->channel; | ||
2183 | |||
2184 | if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) | ||
2185 | assoc_req->band = priv->curbssparams.band; | ||
2186 | |||
2187 | if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) | ||
2188 | assoc_req->mode = priv->mode; | ||
2189 | |||
2190 | if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
2191 | memcpy(&assoc_req->bssid, priv->curbssparams.bssid, | ||
2192 | ETH_ALEN); | ||
2193 | } | ||
2194 | |||
2195 | if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { | ||
2196 | int i; | ||
2197 | for (i = 0; i < 4; i++) { | ||
2198 | memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i], | ||
2199 | sizeof(struct enc_key)); | ||
2200 | } | ||
2201 | } | ||
2202 | |||
2203 | if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) | ||
2204 | assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx; | ||
2205 | |||
2206 | if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { | ||
2207 | memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key, | ||
2208 | sizeof(struct enc_key)); | ||
2209 | } | ||
2210 | |||
2211 | if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | ||
2212 | memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key, | ||
2213 | sizeof(struct enc_key)); | ||
2214 | } | ||
2215 | |||
2216 | if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
2217 | memcpy(&assoc_req->secinfo, &priv->secinfo, | ||
2218 | sizeof(struct lbs_802_11_security)); | ||
2219 | } | ||
2220 | |||
2221 | if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { | ||
2222 | memcpy(&assoc_req->wpa_ie, &priv->wpa_ie, | ||
2223 | MAX_WPA_IE_LEN); | ||
2224 | assoc_req->wpa_ie_len = priv->wpa_ie_len; | ||
2225 | } | ||
2226 | |||
2227 | lbs_deb_leave(LBS_DEB_ASSOC); | ||
2228 | return assoc_req; | ||
2229 | } | ||
2230 | |||
2231 | |||
2232 | /** | ||
2233 | * @brief Deauthenticate from a specific BSS | ||
2234 | * | ||
2235 | * @param priv A pointer to struct lbs_private structure | ||
2236 | * @param bssid The specific BSS to deauthenticate from | ||
2237 | * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating | ||
2238 | * | ||
2239 | * @return 0 on success, error on failure | ||
2240 | */ | ||
2241 | int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], | ||
2242 | u16 reason) | ||
2243 | { | ||
2244 | struct cmd_ds_802_11_deauthenticate cmd; | ||
2245 | int ret; | ||
2246 | |||
2247 | lbs_deb_enter(LBS_DEB_JOIN); | ||
2248 | |||
2249 | memset(&cmd, 0, sizeof(cmd)); | ||
2250 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
2251 | memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); | ||
2252 | cmd.reasoncode = cpu_to_le16(reason); | ||
2253 | |||
2254 | ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); | ||
2255 | |||
2256 | /* Clean up everything even if there was an error; can't assume that | ||
2257 | * we're still authenticated to the AP after trying to deauth. | ||
2258 | */ | ||
2259 | lbs_mac_event_disconnected(priv); | ||
2260 | |||
2261 | lbs_deb_leave(LBS_DEB_JOIN); | ||
2262 | return ret; | ||
2263 | } | ||
2264 | |||
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h deleted file mode 100644 index 40621b789fc5..000000000000 --- a/drivers/net/wireless/libertas/assoc.h +++ /dev/null | |||
@@ -1,155 +0,0 @@ | |||
1 | /* Copyright (C) 2006, Red Hat, Inc. */ | ||
2 | |||
3 | #ifndef _LBS_ASSOC_H_ | ||
4 | #define _LBS_ASSOC_H_ | ||
5 | |||
6 | |||
7 | #include "defs.h" | ||
8 | #include "host.h" | ||
9 | |||
10 | |||
11 | struct lbs_private; | ||
12 | |||
13 | /* | ||
14 | * In theory, the IE is limited to the IE length, 255, | ||
15 | * but in practice 64 bytes are enough. | ||
16 | */ | ||
17 | #define MAX_WPA_IE_LEN 64 | ||
18 | |||
19 | |||
20 | |||
21 | struct lbs_802_11_security { | ||
22 | u8 WPAenabled; | ||
23 | u8 WPA2enabled; | ||
24 | u8 wep_enabled; | ||
25 | u8 auth_mode; | ||
26 | u32 key_mgmt; | ||
27 | }; | ||
28 | |||
29 | /** Current Basic Service Set State Structure */ | ||
30 | struct current_bss_params { | ||
31 | /** bssid */ | ||
32 | u8 bssid[ETH_ALEN]; | ||
33 | /** ssid */ | ||
34 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
35 | u8 ssid_len; | ||
36 | |||
37 | /** band */ | ||
38 | u8 band; | ||
39 | /** channel is directly in priv->channel */ | ||
40 | /** zero-terminated array of supported data rates */ | ||
41 | u8 rates[MAX_RATES + 1]; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * @brief Structure used to store information for each beacon/probe response | ||
46 | */ | ||
47 | struct bss_descriptor { | ||
48 | u8 bssid[ETH_ALEN]; | ||
49 | |||
50 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
51 | u8 ssid_len; | ||
52 | |||
53 | u16 capability; | ||
54 | u32 rssi; | ||
55 | u32 channel; | ||
56 | u16 beaconperiod; | ||
57 | __le16 atimwindow; | ||
58 | |||
59 | /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ | ||
60 | u8 mode; | ||
61 | |||
62 | /* zero-terminated array of supported data rates */ | ||
63 | u8 rates[MAX_RATES + 1]; | ||
64 | |||
65 | unsigned long last_scanned; | ||
66 | |||
67 | union ieee_phy_param_set phy; | ||
68 | union ieee_ss_param_set ss; | ||
69 | |||
70 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
71 | size_t wpa_ie_len; | ||
72 | u8 rsn_ie[MAX_WPA_IE_LEN]; | ||
73 | size_t rsn_ie_len; | ||
74 | |||
75 | u8 mesh; | ||
76 | |||
77 | struct list_head list; | ||
78 | }; | ||
79 | |||
80 | /** Association request | ||
81 | * | ||
82 | * Encapsulates all the options that describe a specific assocation request | ||
83 | * or configuration of the wireless card's radio, mode, and security settings. | ||
84 | */ | ||
85 | struct assoc_request { | ||
86 | #define ASSOC_FLAG_SSID 1 | ||
87 | #define ASSOC_FLAG_CHANNEL 2 | ||
88 | #define ASSOC_FLAG_BAND 3 | ||
89 | #define ASSOC_FLAG_MODE 4 | ||
90 | #define ASSOC_FLAG_BSSID 5 | ||
91 | #define ASSOC_FLAG_WEP_KEYS 6 | ||
92 | #define ASSOC_FLAG_WEP_TX_KEYIDX 7 | ||
93 | #define ASSOC_FLAG_WPA_MCAST_KEY 8 | ||
94 | #define ASSOC_FLAG_WPA_UCAST_KEY 9 | ||
95 | #define ASSOC_FLAG_SECINFO 10 | ||
96 | #define ASSOC_FLAG_WPA_IE 11 | ||
97 | unsigned long flags; | ||
98 | |||
99 | u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
100 | u8 ssid_len; | ||
101 | u8 channel; | ||
102 | u8 band; | ||
103 | u8 mode; | ||
104 | u8 bssid[ETH_ALEN] __attribute__ ((aligned (2))); | ||
105 | |||
106 | /** WEP keys */ | ||
107 | struct enc_key wep_keys[4]; | ||
108 | u16 wep_tx_keyidx; | ||
109 | |||
110 | /** WPA keys */ | ||
111 | struct enc_key wpa_mcast_key; | ||
112 | struct enc_key wpa_unicast_key; | ||
113 | |||
114 | struct lbs_802_11_security secinfo; | ||
115 | |||
116 | /** WPA Information Elements*/ | ||
117 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
118 | u8 wpa_ie_len; | ||
119 | |||
120 | /* BSS to associate with for infrastructure of Ad-Hoc join */ | ||
121 | struct bss_descriptor bss; | ||
122 | }; | ||
123 | |||
124 | |||
125 | extern u8 lbs_bg_rates[MAX_RATES]; | ||
126 | |||
127 | void lbs_association_worker(struct work_struct *work); | ||
128 | struct assoc_request *lbs_get_association_request(struct lbs_private *priv); | ||
129 | |||
130 | int lbs_adhoc_stop(struct lbs_private *priv); | ||
131 | |||
132 | int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, | ||
133 | u8 bssid[ETH_ALEN], u16 reason); | ||
134 | |||
135 | int lbs_cmd_802_11_rssi(struct lbs_private *priv, | ||
136 | struct cmd_ds_command *cmd); | ||
137 | int lbs_ret_802_11_rssi(struct lbs_private *priv, | ||
138 | struct cmd_ds_command *resp); | ||
139 | |||
140 | int lbs_cmd_bcn_ctrl(struct lbs_private *priv, | ||
141 | struct cmd_ds_command *cmd, | ||
142 | u16 cmd_action); | ||
143 | int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, | ||
144 | struct cmd_ds_command *resp); | ||
145 | |||
146 | int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, | ||
147 | struct assoc_request *assoc); | ||
148 | |||
149 | int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, | ||
150 | uint16_t *enable); | ||
151 | |||
152 | int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, | ||
153 | struct assoc_request *assoc); | ||
154 | |||
155 | #endif /* _LBS_ASSOC_H */ | ||
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 9d5d3ccf08c8..f36cc970ad1b 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c | |||
@@ -7,8 +7,12 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | #include <linux/if_arp.h> | ||
11 | #include <linux/ieee80211.h> | ||
10 | #include <net/cfg80211.h> | 12 | #include <net/cfg80211.h> |
13 | #include <asm/unaligned.h> | ||
11 | 14 | ||
15 | #include "decl.h" | ||
12 | #include "cfg.h" | 16 | #include "cfg.h" |
13 | #include "cmd.h" | 17 | #include "cmd.h" |
14 | 18 | ||
@@ -39,26 +43,27 @@ static struct ieee80211_channel lbs_2ghz_channels[] = { | |||
39 | CHAN2G(14, 2484, 0), | 43 | CHAN2G(14, 2484, 0), |
40 | }; | 44 | }; |
41 | 45 | ||
42 | #define RATETAB_ENT(_rate, _rateid, _flags) { \ | 46 | #define RATETAB_ENT(_rate, _hw_value, _flags) { \ |
43 | .bitrate = (_rate), \ | 47 | .bitrate = (_rate), \ |
44 | .hw_value = (_rateid), \ | 48 | .hw_value = (_hw_value), \ |
45 | .flags = (_flags), \ | 49 | .flags = (_flags), \ |
46 | } | 50 | } |
47 | 51 | ||
48 | 52 | ||
53 | /* Table 6 in section 3.2.1.1 */ | ||
49 | static struct ieee80211_rate lbs_rates[] = { | 54 | static struct ieee80211_rate lbs_rates[] = { |
50 | RATETAB_ENT(10, 0x1, 0), | 55 | RATETAB_ENT(10, 0, 0), |
51 | RATETAB_ENT(20, 0x2, 0), | 56 | RATETAB_ENT(20, 1, 0), |
52 | RATETAB_ENT(55, 0x4, 0), | 57 | RATETAB_ENT(55, 2, 0), |
53 | RATETAB_ENT(110, 0x8, 0), | 58 | RATETAB_ENT(110, 3, 0), |
54 | RATETAB_ENT(60, 0x10, 0), | 59 | RATETAB_ENT(60, 9, 0), |
55 | RATETAB_ENT(90, 0x20, 0), | 60 | RATETAB_ENT(90, 6, 0), |
56 | RATETAB_ENT(120, 0x40, 0), | 61 | RATETAB_ENT(120, 7, 0), |
57 | RATETAB_ENT(180, 0x80, 0), | 62 | RATETAB_ENT(180, 8, 0), |
58 | RATETAB_ENT(240, 0x100, 0), | 63 | RATETAB_ENT(240, 9, 0), |
59 | RATETAB_ENT(360, 0x200, 0), | 64 | RATETAB_ENT(360, 10, 0), |
60 | RATETAB_ENT(480, 0x400, 0), | 65 | RATETAB_ENT(480, 11, 0), |
61 | RATETAB_ENT(540, 0x800, 0), | 66 | RATETAB_ENT(540, 12, 0), |
62 | }; | 67 | }; |
63 | 68 | ||
64 | static struct ieee80211_supported_band lbs_band_2ghz = { | 69 | static struct ieee80211_supported_band lbs_band_2ghz = { |
@@ -76,22 +81,639 @@ static const u32 cipher_suites[] = { | |||
76 | WLAN_CIPHER_SUITE_CCMP, | 81 | WLAN_CIPHER_SUITE_CCMP, |
77 | }; | 82 | }; |
78 | 83 | ||
84 | /* Time to stay on the channel */ | ||
85 | #define LBS_DWELL_PASSIVE 100 | ||
86 | #define LBS_DWELL_ACTIVE 40 | ||
79 | 87 | ||
80 | 88 | ||
89 | /*************************************************************************** | ||
90 | * Misc utility functions | ||
91 | * | ||
92 | * TLVs are Marvell specific. They are very similar to IEs, they have the | ||
93 | * same structure: type, length, data*. The only difference: for IEs, the | ||
94 | * type and length are u8, but for TLVs they're __le16. | ||
95 | */ | ||
96 | |||
97 | /* | ||
98 | * Convert NL80211's auth_type to the one from Libertas, see chapter 5.9.1 | ||
99 | * in the firmware spec | ||
100 | */ | ||
101 | static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type) | ||
102 | { | ||
103 | int ret = -ENOTSUPP; | ||
104 | |||
105 | switch (auth_type) { | ||
106 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
107 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
108 | ret = auth_type; | ||
109 | break; | ||
110 | case NL80211_AUTHTYPE_AUTOMATIC: | ||
111 | ret = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
112 | break; | ||
113 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
114 | ret = 0x80; | ||
115 | break; | ||
116 | default: | ||
117 | /* silence compiler */ | ||
118 | break; | ||
119 | } | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | |||
124 | /* Various firmware commands need the list of supported rates, but with | ||
125 | the hight-bit set for basic rates */ | ||
126 | static int lbs_add_rates(u8 *rates) | ||
127 | { | ||
128 | size_t i; | ||
129 | |||
130 | for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { | ||
131 | u8 rate = lbs_rates[i].bitrate / 5; | ||
132 | if (rate == 0x02 || rate == 0x04 || | ||
133 | rate == 0x0b || rate == 0x16) | ||
134 | rate |= 0x80; | ||
135 | rates[i] = rate; | ||
136 | } | ||
137 | return ARRAY_SIZE(lbs_rates); | ||
138 | } | ||
139 | |||
140 | |||
141 | /*************************************************************************** | ||
142 | * TLV utility functions | ||
143 | * | ||
144 | * TLVs are Marvell specific. They are very similar to IEs, they have the | ||
145 | * same structure: type, length, data*. The only difference: for IEs, the | ||
146 | * type and length are u8, but for TLVs they're __le16. | ||
147 | */ | ||
148 | |||
149 | |||
150 | /* | ||
151 | * Add ssid TLV | ||
152 | */ | ||
153 | #define LBS_MAX_SSID_TLV_SIZE \ | ||
154 | (sizeof(struct mrvl_ie_header) \ | ||
155 | + IEEE80211_MAX_SSID_LEN) | ||
156 | |||
157 | static int lbs_add_ssid_tlv(u8 *tlv, const u8 *ssid, int ssid_len) | ||
158 | { | ||
159 | struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; | ||
160 | |||
161 | /* | ||
162 | * TLV-ID SSID 00 00 | ||
163 | * length 06 00 | ||
164 | * ssid 4d 4e 54 45 53 54 | ||
165 | */ | ||
166 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
167 | ssid_tlv->header.len = cpu_to_le16(ssid_len); | ||
168 | memcpy(ssid_tlv->ssid, ssid, ssid_len); | ||
169 | return sizeof(ssid_tlv->header) + ssid_len; | ||
170 | } | ||
171 | |||
172 | |||
173 | /* | ||
174 | * Add channel list TLV (section 8.4.2) | ||
175 | * | ||
176 | * Actual channel data comes from priv->wdev->wiphy->channels. | ||
177 | */ | ||
178 | #define LBS_MAX_CHANNEL_LIST_TLV_SIZE \ | ||
179 | (sizeof(struct mrvl_ie_header) \ | ||
180 | + (LBS_SCAN_BEFORE_NAP * sizeof(struct chanscanparamset))) | ||
181 | |||
182 | static int lbs_add_channel_list_tlv(struct lbs_private *priv, u8 *tlv, | ||
183 | int last_channel, int active_scan) | ||
184 | { | ||
185 | int chanscanparamsize = sizeof(struct chanscanparamset) * | ||
186 | (last_channel - priv->scan_channel); | ||
187 | |||
188 | struct mrvl_ie_header *header = (void *) tlv; | ||
189 | |||
190 | /* | ||
191 | * TLV-ID CHANLIST 01 01 | ||
192 | * length 0e 00 | ||
193 | * channel 00 01 00 00 00 64 00 | ||
194 | * radio type 00 | ||
195 | * channel 01 | ||
196 | * scan type 00 | ||
197 | * min scan time 00 00 | ||
198 | * max scan time 64 00 | ||
199 | * channel 2 00 02 00 00 00 64 00 | ||
200 | * | ||
201 | */ | ||
202 | |||
203 | header->type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
204 | header->len = cpu_to_le16(chanscanparamsize); | ||
205 | tlv += sizeof(struct mrvl_ie_header); | ||
206 | |||
207 | /* lbs_deb_scan("scan: channels %d to %d\n", priv->scan_channel, | ||
208 | last_channel); */ | ||
209 | memset(tlv, 0, chanscanparamsize); | ||
210 | |||
211 | while (priv->scan_channel < last_channel) { | ||
212 | struct chanscanparamset *param = (void *) tlv; | ||
213 | |||
214 | param->radiotype = CMD_SCAN_RADIO_TYPE_BG; | ||
215 | param->channumber = | ||
216 | priv->scan_req->channels[priv->scan_channel]->hw_value; | ||
217 | if (active_scan) { | ||
218 | param->maxscantime = cpu_to_le16(LBS_DWELL_ACTIVE); | ||
219 | } else { | ||
220 | param->chanscanmode.passivescan = 1; | ||
221 | param->maxscantime = cpu_to_le16(LBS_DWELL_PASSIVE); | ||
222 | } | ||
223 | tlv += sizeof(struct chanscanparamset); | ||
224 | priv->scan_channel++; | ||
225 | } | ||
226 | return sizeof(struct mrvl_ie_header) + chanscanparamsize; | ||
227 | } | ||
228 | |||
229 | |||
230 | /* | ||
231 | * Add rates TLV | ||
232 | * | ||
233 | * The rates are in lbs_bg_rates[], but for the 802.11b | ||
234 | * rates the high bit is set. We add this TLV only because | ||
235 | * there's a firmware which otherwise doesn't report all | ||
236 | * APs in range. | ||
237 | */ | ||
238 | #define LBS_MAX_RATES_TLV_SIZE \ | ||
239 | (sizeof(struct mrvl_ie_header) \ | ||
240 | + (ARRAY_SIZE(lbs_rates))) | ||
241 | |||
242 | /* Adds a TLV with all rates the hardware supports */ | ||
243 | static int lbs_add_supported_rates_tlv(u8 *tlv) | ||
244 | { | ||
245 | size_t i; | ||
246 | struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; | ||
247 | |||
248 | /* | ||
249 | * TLV-ID RATES 01 00 | ||
250 | * length 0e 00 | ||
251 | * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c | ||
252 | */ | ||
253 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
254 | tlv += sizeof(rate_tlv->header); | ||
255 | i = lbs_add_rates(tlv); | ||
256 | tlv += i; | ||
257 | rate_tlv->header.len = cpu_to_le16(i); | ||
258 | return sizeof(rate_tlv->header) + i; | ||
259 | } | ||
260 | |||
261 | |||
262 | /* | ||
263 | * Adds a TLV with all rates the hardware *and* BSS supports. | ||
264 | */ | ||
265 | static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss) | ||
266 | { | ||
267 | struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; | ||
268 | const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); | ||
269 | int n; | ||
270 | |||
271 | /* | ||
272 | * 01 00 TLV_TYPE_RATES | ||
273 | * 04 00 len | ||
274 | * 82 84 8b 96 rates | ||
275 | */ | ||
276 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
277 | tlv += sizeof(rate_tlv->header); | ||
278 | |||
279 | if (!rates_eid) { | ||
280 | /* Fallback: add basic 802.11b rates */ | ||
281 | *tlv++ = 0x82; | ||
282 | *tlv++ = 0x84; | ||
283 | *tlv++ = 0x8b; | ||
284 | *tlv++ = 0x96; | ||
285 | n = 4; | ||
286 | } else { | ||
287 | int hw, ap; | ||
288 | u8 ap_max = rates_eid[1]; | ||
289 | n = 0; | ||
290 | for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { | ||
291 | u8 hw_rate = lbs_rates[hw].bitrate / 5; | ||
292 | for (ap = 0; ap < ap_max; ap++) { | ||
293 | if (hw_rate == (rates_eid[ap+2] & 0x7f)) { | ||
294 | *tlv++ = rates_eid[ap+2]; | ||
295 | n++; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | rate_tlv->header.len = cpu_to_le16(n); | ||
302 | return sizeof(rate_tlv->header) + n; | ||
303 | } | ||
304 | |||
305 | |||
306 | /* | ||
307 | * Add auth type TLV. | ||
308 | * | ||
309 | * This is only needed for newer firmware (V9 and up). | ||
310 | */ | ||
311 | #define LBS_MAX_AUTH_TYPE_TLV_SIZE \ | ||
312 | sizeof(struct mrvl_ie_auth_type) | ||
313 | |||
314 | static int lbs_add_auth_type_tlv(u8 *tlv, enum nl80211_auth_type auth_type) | ||
315 | { | ||
316 | struct mrvl_ie_auth_type *auth = (void *) tlv; | ||
317 | |||
318 | /* | ||
319 | * 1f 01 TLV_TYPE_AUTH_TYPE | ||
320 | * 01 00 len | ||
321 | * 01 auth type | ||
322 | */ | ||
323 | auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); | ||
324 | auth->header.len = cpu_to_le16(sizeof(*auth)-sizeof(auth->header)); | ||
325 | auth->auth = cpu_to_le16(lbs_auth_to_authtype(auth_type)); | ||
326 | return sizeof(*auth); | ||
327 | } | ||
328 | |||
329 | |||
330 | /* | ||
331 | * Add channel (phy ds) TLV | ||
332 | */ | ||
333 | #define LBS_MAX_CHANNEL_TLV_SIZE \ | ||
334 | sizeof(struct mrvl_ie_header) | ||
335 | |||
336 | static int lbs_add_channel_tlv(u8 *tlv, u8 channel) | ||
337 | { | ||
338 | struct mrvl_ie_ds_param_set *ds = (void *) tlv; | ||
339 | |||
340 | /* | ||
341 | * 03 00 TLV_TYPE_PHY_DS | ||
342 | * 01 00 len | ||
343 | * 06 channel | ||
344 | */ | ||
345 | ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); | ||
346 | ds->header.len = cpu_to_le16(sizeof(*ds)-sizeof(ds->header)); | ||
347 | ds->channel = channel; | ||
348 | return sizeof(*ds); | ||
349 | } | ||
350 | |||
351 | |||
352 | /* | ||
353 | * Add (empty) CF param TLV of the form: | ||
354 | */ | ||
355 | #define LBS_MAX_CF_PARAM_TLV_SIZE \ | ||
356 | sizeof(struct mrvl_ie_header) | ||
357 | |||
358 | static int lbs_add_cf_param_tlv(u8 *tlv) | ||
359 | { | ||
360 | struct mrvl_ie_cf_param_set *cf = (void *)tlv; | ||
361 | |||
362 | /* | ||
363 | * 04 00 TLV_TYPE_CF | ||
364 | * 06 00 len | ||
365 | * 00 cfpcnt | ||
366 | * 00 cfpperiod | ||
367 | * 00 00 cfpmaxduration | ||
368 | * 00 00 cfpdurationremaining | ||
369 | */ | ||
370 | cf->header.type = cpu_to_le16(TLV_TYPE_CF); | ||
371 | cf->header.len = cpu_to_le16(sizeof(*cf)-sizeof(cf->header)); | ||
372 | return sizeof(*cf); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Add WPA TLV | ||
377 | */ | ||
378 | #define LBS_MAX_WPA_TLV_SIZE \ | ||
379 | (sizeof(struct mrvl_ie_header) \ | ||
380 | + 128 /* TODO: I guessed the size */) | ||
381 | |||
382 | static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len) | ||
383 | { | ||
384 | size_t tlv_len; | ||
385 | |||
386 | /* | ||
387 | * We need just convert an IE to an TLV. IEs use u8 for the header, | ||
388 | * u8 type | ||
389 | * u8 len | ||
390 | * u8[] data | ||
391 | * but TLVs use __le16 instead: | ||
392 | * __le16 type | ||
393 | * __le16 len | ||
394 | * u8[] data | ||
395 | */ | ||
396 | *tlv++ = *ie++; | ||
397 | *tlv++ = 0; | ||
398 | tlv_len = *tlv++ = *ie++; | ||
399 | *tlv++ = 0; | ||
400 | while (tlv_len--) | ||
401 | *tlv++ = *ie++; | ||
402 | /* the TLV is two bytes larger than the IE */ | ||
403 | return ie_len + 2; | ||
404 | } | ||
405 | |||
406 | /*************************************************************************** | ||
407 | * Set Channel | ||
408 | */ | ||
409 | |||
81 | static int lbs_cfg_set_channel(struct wiphy *wiphy, | 410 | static int lbs_cfg_set_channel(struct wiphy *wiphy, |
82 | struct net_device *netdev, | 411 | struct net_device *netdev, |
83 | struct ieee80211_channel *chan, | 412 | struct ieee80211_channel *channel, |
84 | enum nl80211_channel_type channel_type) | 413 | enum nl80211_channel_type channel_type) |
85 | { | 414 | { |
86 | struct lbs_private *priv = wiphy_priv(wiphy); | 415 | struct lbs_private *priv = wiphy_priv(wiphy); |
87 | int ret = -ENOTSUPP; | 416 | int ret = -ENOTSUPP; |
88 | 417 | ||
89 | lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type); | 418 | lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", |
419 | channel->center_freq, channel_type); | ||
90 | 420 | ||
91 | if (channel_type != NL80211_CHAN_NO_HT) | 421 | if (channel_type != NL80211_CHAN_NO_HT) |
92 | goto out; | 422 | goto out; |
93 | 423 | ||
94 | ret = lbs_set_channel(priv, chan->hw_value); | 424 | ret = lbs_set_channel(priv, channel->hw_value); |
425 | |||
426 | out: | ||
427 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | |||
432 | |||
433 | /*************************************************************************** | ||
434 | * Scanning | ||
435 | */ | ||
436 | |||
437 | /* | ||
438 | * When scanning, the firmware doesn't send a nul packet with the power-safe | ||
439 | * bit to the AP. So we cannot stay away from our current channel too long, | ||
440 | * otherwise we loose data. So take a "nap" while scanning every other | ||
441 | * while. | ||
442 | */ | ||
443 | #define LBS_SCAN_BEFORE_NAP 4 | ||
444 | |||
445 | |||
446 | /* | ||
447 | * When the firmware reports back a scan-result, it gives us an "u8 rssi", | ||
448 | * which isn't really an RSSI, as it becomes larger when moving away from | ||
449 | * the AP. Anyway, we need to convert that into mBm. | ||
450 | */ | ||
451 | #define LBS_SCAN_RSSI_TO_MBM(rssi) \ | ||
452 | ((-(int)rssi + 3)*100) | ||
453 | |||
454 | static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, | ||
455 | struct cmd_header *resp) | ||
456 | { | ||
457 | struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; | ||
458 | int bsssize; | ||
459 | const u8 *pos; | ||
460 | u16 nr_sets; | ||
461 | const u8 *tsfdesc; | ||
462 | int tsfsize; | ||
463 | int i; | ||
464 | int ret = -EILSEQ; | ||
465 | |||
466 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
467 | |||
468 | bsssize = get_unaligned_le16(&scanresp->bssdescriptsize); | ||
469 | nr_sets = le16_to_cpu(resp->size); | ||
470 | |||
471 | /* | ||
472 | * The general layout of the scan response is described in chapter | ||
473 | * 5.7.1. Basically we have a common part, then any number of BSS | ||
474 | * descriptor sections. Finally we have section with the same number | ||
475 | * of TSFs. | ||
476 | * | ||
477 | * cmd_ds_802_11_scan_rsp | ||
478 | * cmd_header | ||
479 | * pos_size | ||
480 | * nr_sets | ||
481 | * bssdesc 1 | ||
482 | * bssid | ||
483 | * rssi | ||
484 | * timestamp | ||
485 | * intvl | ||
486 | * capa | ||
487 | * IEs | ||
488 | * bssdesc 2 | ||
489 | * bssdesc n | ||
490 | * MrvlIEtypes_TsfFimestamp_t | ||
491 | * TSF for BSS 1 | ||
492 | * TSF for BSS 2 | ||
493 | * TSF for BSS n | ||
494 | */ | ||
495 | |||
496 | pos = scanresp->bssdesc_and_tlvbuffer; | ||
497 | |||
498 | tsfdesc = pos + bsssize; | ||
499 | tsfsize = 4 + 8 * scanresp->nr_sets; | ||
500 | |||
501 | /* Validity check: we expect a Marvell-Local TLV */ | ||
502 | i = get_unaligned_le16(tsfdesc); | ||
503 | tsfdesc += 2; | ||
504 | if (i != TLV_TYPE_TSFTIMESTAMP) | ||
505 | goto done; | ||
506 | /* Validity check: the TLV holds TSF values with 8 bytes each, so | ||
507 | * the size in the TLV must match the nr_sets value */ | ||
508 | i = get_unaligned_le16(tsfdesc); | ||
509 | tsfdesc += 2; | ||
510 | if (i / 8 != scanresp->nr_sets) | ||
511 | goto done; | ||
512 | |||
513 | for (i = 0; i < scanresp->nr_sets; i++) { | ||
514 | const u8 *bssid; | ||
515 | const u8 *ie; | ||
516 | int left; | ||
517 | int ielen; | ||
518 | int rssi; | ||
519 | u16 intvl; | ||
520 | u16 capa; | ||
521 | int chan_no = -1; | ||
522 | const u8 *ssid = NULL; | ||
523 | u8 ssid_len = 0; | ||
524 | DECLARE_SSID_BUF(ssid_buf); | ||
525 | |||
526 | int len = get_unaligned_le16(pos); | ||
527 | pos += 2; | ||
528 | |||
529 | /* BSSID */ | ||
530 | bssid = pos; | ||
531 | pos += ETH_ALEN; | ||
532 | /* RSSI */ | ||
533 | rssi = *pos++; | ||
534 | /* Packet time stamp */ | ||
535 | pos += 8; | ||
536 | /* Beacon interval */ | ||
537 | intvl = get_unaligned_le16(pos); | ||
538 | pos += 2; | ||
539 | /* Capabilities */ | ||
540 | capa = get_unaligned_le16(pos); | ||
541 | pos += 2; | ||
542 | |||
543 | /* To find out the channel, we must parse the IEs */ | ||
544 | ie = pos; | ||
545 | /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon | ||
546 | interval, capabilities */ | ||
547 | ielen = left = len - (6 + 1 + 8 + 2 + 2); | ||
548 | while (left >= 2) { | ||
549 | u8 id, elen; | ||
550 | id = *pos++; | ||
551 | elen = *pos++; | ||
552 | left -= 2; | ||
553 | if (elen > left || elen == 0) | ||
554 | goto done; | ||
555 | if (id == WLAN_EID_DS_PARAMS) | ||
556 | chan_no = *pos; | ||
557 | if (id == WLAN_EID_SSID) { | ||
558 | ssid = pos; | ||
559 | ssid_len = elen; | ||
560 | } | ||
561 | left -= elen; | ||
562 | pos += elen; | ||
563 | } | ||
564 | |||
565 | /* No channel, no luck */ | ||
566 | if (chan_no != -1) { | ||
567 | struct wiphy *wiphy = priv->wdev->wiphy; | ||
568 | int freq = ieee80211_channel_to_frequency(chan_no); | ||
569 | struct ieee80211_channel *channel = | ||
570 | ieee80211_get_channel(wiphy, freq); | ||
571 | |||
572 | lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, " | ||
573 | "%d dBm\n", | ||
574 | bssid, capa, chan_no, | ||
575 | print_ssid(ssid_buf, ssid, ssid_len), | ||
576 | LBS_SCAN_RSSI_TO_MBM(rssi)/100); | ||
577 | |||
578 | if (channel || | ||
579 | !(channel->flags & IEEE80211_CHAN_DISABLED)) | ||
580 | cfg80211_inform_bss(wiphy, channel, | ||
581 | bssid, le64_to_cpu(*(__le64 *)tsfdesc), | ||
582 | capa, intvl, ie, ielen, | ||
583 | LBS_SCAN_RSSI_TO_MBM(rssi), | ||
584 | GFP_KERNEL); | ||
585 | } | ||
586 | tsfdesc += 8; | ||
587 | } | ||
588 | ret = 0; | ||
589 | |||
590 | done: | ||
591 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | |||
596 | /* | ||
597 | * Our scan command contains a TLV, consting of a SSID TLV, a channel list | ||
598 | * TLV and a rates TLV. Determine the maximum size of them: | ||
599 | */ | ||
600 | #define LBS_SCAN_MAX_CMD_SIZE \ | ||
601 | (sizeof(struct cmd_ds_802_11_scan) \ | ||
602 | + LBS_MAX_SSID_TLV_SIZE \ | ||
603 | + LBS_MAX_CHANNEL_LIST_TLV_SIZE \ | ||
604 | + LBS_MAX_RATES_TLV_SIZE) | ||
605 | |||
606 | /* | ||
607 | * Assumes priv->scan_req is initialized and valid | ||
608 | * Assumes priv->scan_channel is initialized | ||
609 | */ | ||
610 | static void lbs_scan_worker(struct work_struct *work) | ||
611 | { | ||
612 | struct lbs_private *priv = | ||
613 | container_of(work, struct lbs_private, scan_work.work); | ||
614 | struct cmd_ds_802_11_scan *scan_cmd; | ||
615 | u8 *tlv; /* pointer into our current, growing TLV storage area */ | ||
616 | int last_channel; | ||
617 | int running, carrier; | ||
618 | |||
619 | lbs_deb_enter(LBS_DEB_SCAN); | ||
620 | |||
621 | scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL); | ||
622 | if (scan_cmd == NULL) | ||
623 | goto out_no_scan_cmd; | ||
624 | |||
625 | /* prepare fixed part of scan command */ | ||
626 | scan_cmd->bsstype = CMD_BSS_TYPE_ANY; | ||
627 | |||
628 | /* stop network while we're away from our main channel */ | ||
629 | running = !netif_queue_stopped(priv->dev); | ||
630 | carrier = netif_carrier_ok(priv->dev); | ||
631 | if (running) | ||
632 | netif_stop_queue(priv->dev); | ||
633 | if (carrier) | ||
634 | netif_carrier_off(priv->dev); | ||
635 | |||
636 | /* prepare fixed part of scan command */ | ||
637 | tlv = scan_cmd->tlvbuffer; | ||
638 | |||
639 | /* add SSID TLV */ | ||
640 | if (priv->scan_req->n_ssids) | ||
641 | tlv += lbs_add_ssid_tlv(tlv, | ||
642 | priv->scan_req->ssids[0].ssid, | ||
643 | priv->scan_req->ssids[0].ssid_len); | ||
644 | |||
645 | /* add channel TLVs */ | ||
646 | last_channel = priv->scan_channel + LBS_SCAN_BEFORE_NAP; | ||
647 | if (last_channel > priv->scan_req->n_channels) | ||
648 | last_channel = priv->scan_req->n_channels; | ||
649 | tlv += lbs_add_channel_list_tlv(priv, tlv, last_channel, | ||
650 | priv->scan_req->n_ssids); | ||
651 | |||
652 | /* add rates TLV */ | ||
653 | tlv += lbs_add_supported_rates_tlv(tlv); | ||
654 | |||
655 | if (priv->scan_channel < priv->scan_req->n_channels) { | ||
656 | cancel_delayed_work(&priv->scan_work); | ||
657 | queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
658 | msecs_to_jiffies(300)); | ||
659 | } | ||
660 | |||
661 | /* This is the final data we are about to send */ | ||
662 | scan_cmd->hdr.size = cpu_to_le16(tlv - (u8 *)scan_cmd); | ||
663 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, | ||
664 | sizeof(*scan_cmd)); | ||
665 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, | ||
666 | tlv - scan_cmd->tlvbuffer); | ||
667 | |||
668 | __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr, | ||
669 | le16_to_cpu(scan_cmd->hdr.size), | ||
670 | lbs_ret_scan, 0); | ||
671 | |||
672 | if (priv->scan_channel >= priv->scan_req->n_channels) { | ||
673 | /* Mark scan done */ | ||
674 | cfg80211_scan_done(priv->scan_req, false); | ||
675 | priv->scan_req = NULL; | ||
676 | } | ||
677 | |||
678 | /* Restart network */ | ||
679 | if (carrier) | ||
680 | netif_carrier_on(priv->dev); | ||
681 | if (running && !priv->tx_pending_len) | ||
682 | netif_wake_queue(priv->dev); | ||
683 | |||
684 | kfree(scan_cmd); | ||
685 | |||
686 | out_no_scan_cmd: | ||
687 | lbs_deb_leave(LBS_DEB_SCAN); | ||
688 | } | ||
689 | |||
690 | |||
691 | static int lbs_cfg_scan(struct wiphy *wiphy, | ||
692 | struct net_device *dev, | ||
693 | struct cfg80211_scan_request *request) | ||
694 | { | ||
695 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
696 | int ret = 0; | ||
697 | |||
698 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
699 | |||
700 | if (priv->scan_req || delayed_work_pending(&priv->scan_work)) { | ||
701 | /* old scan request not yet processed */ | ||
702 | ret = -EAGAIN; | ||
703 | goto out; | ||
704 | } | ||
705 | |||
706 | lbs_deb_scan("scan: ssids %d, channels %d, ie_len %zd\n", | ||
707 | request->n_ssids, request->n_channels, request->ie_len); | ||
708 | |||
709 | priv->scan_channel = 0; | ||
710 | queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
711 | msecs_to_jiffies(50)); | ||
712 | |||
713 | if (priv->surpriseremoved) | ||
714 | ret = -EIO; | ||
715 | |||
716 | priv->scan_req = request; | ||
95 | 717 | ||
96 | out: | 718 | out: |
97 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | 719 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); |
@@ -101,8 +723,1228 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, | |||
101 | 723 | ||
102 | 724 | ||
103 | 725 | ||
726 | /*************************************************************************** | ||
727 | * Events | ||
728 | */ | ||
729 | |||
730 | void lbs_send_disconnect_notification(struct lbs_private *priv) | ||
731 | { | ||
732 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
733 | |||
734 | cfg80211_disconnected(priv->dev, | ||
735 | 0, | ||
736 | NULL, 0, | ||
737 | GFP_KERNEL); | ||
738 | |||
739 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
740 | } | ||
741 | |||
742 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) | ||
743 | { | ||
744 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
745 | |||
746 | cfg80211_michael_mic_failure(priv->dev, | ||
747 | priv->assoc_bss, | ||
748 | event == MACREG_INT_CODE_MIC_ERR_MULTICAST ? | ||
749 | NL80211_KEYTYPE_GROUP : | ||
750 | NL80211_KEYTYPE_PAIRWISE, | ||
751 | -1, | ||
752 | NULL, | ||
753 | GFP_KERNEL); | ||
754 | |||
755 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
756 | } | ||
757 | |||
758 | |||
759 | |||
760 | |||
761 | /*************************************************************************** | ||
762 | * Connect/disconnect | ||
763 | */ | ||
764 | |||
765 | |||
766 | /* | ||
767 | * This removes all WEP keys | ||
768 | */ | ||
769 | static int lbs_remove_wep_keys(struct lbs_private *priv) | ||
770 | { | ||
771 | struct cmd_ds_802_11_set_wep cmd; | ||
772 | int ret; | ||
773 | |||
774 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
775 | |||
776 | memset(&cmd, 0, sizeof(cmd)); | ||
777 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
778 | cmd.keyindex = cpu_to_le16(priv->wep_tx_key); | ||
779 | cmd.action = cpu_to_le16(CMD_ACT_REMOVE); | ||
780 | |||
781 | ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); | ||
782 | |||
783 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | /* | ||
788 | * Set WEP keys | ||
789 | */ | ||
790 | static int lbs_set_wep_keys(struct lbs_private *priv) | ||
791 | { | ||
792 | struct cmd_ds_802_11_set_wep cmd; | ||
793 | int i; | ||
794 | int ret; | ||
795 | |||
796 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
797 | |||
798 | /* | ||
799 | * command 13 00 | ||
800 | * size 50 00 | ||
801 | * sequence xx xx | ||
802 | * result 00 00 | ||
803 | * action 02 00 ACT_ADD | ||
804 | * transmit key 00 00 | ||
805 | * type for key 1 01 WEP40 | ||
806 | * type for key 2 00 | ||
807 | * type for key 3 00 | ||
808 | * type for key 4 00 | ||
809 | * key 1 39 39 39 39 39 00 00 00 | ||
810 | * 00 00 00 00 00 00 00 00 | ||
811 | * key 2 00 00 00 00 00 00 00 00 | ||
812 | * 00 00 00 00 00 00 00 00 | ||
813 | * key 3 00 00 00 00 00 00 00 00 | ||
814 | * 00 00 00 00 00 00 00 00 | ||
815 | * key 4 00 00 00 00 00 00 00 00 | ||
816 | */ | ||
817 | if (priv->wep_key_len[0] || priv->wep_key_len[1] || | ||
818 | priv->wep_key_len[2] || priv->wep_key_len[3]) { | ||
819 | /* Only set wep keys if we have at least one of them */ | ||
820 | memset(&cmd, 0, sizeof(cmd)); | ||
821 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
822 | cmd.keyindex = cpu_to_le16(priv->wep_tx_key); | ||
823 | cmd.action = cpu_to_le16(CMD_ACT_ADD); | ||
824 | |||
825 | for (i = 0; i < 4; i++) { | ||
826 | switch (priv->wep_key_len[i]) { | ||
827 | case WLAN_KEY_LEN_WEP40: | ||
828 | cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; | ||
829 | break; | ||
830 | case WLAN_KEY_LEN_WEP104: | ||
831 | cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; | ||
832 | break; | ||
833 | default: | ||
834 | cmd.keytype[i] = 0; | ||
835 | break; | ||
836 | } | ||
837 | memcpy(cmd.keymaterial[i], priv->wep_key[i], | ||
838 | priv->wep_key_len[i]); | ||
839 | } | ||
840 | |||
841 | ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); | ||
842 | } else { | ||
843 | /* Otherwise remove all wep keys */ | ||
844 | ret = lbs_remove_wep_keys(priv); | ||
845 | } | ||
846 | |||
847 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | |||
852 | /* | ||
853 | * Enable/Disable RSN status | ||
854 | */ | ||
855 | static int lbs_enable_rsn(struct lbs_private *priv, int enable) | ||
856 | { | ||
857 | struct cmd_ds_802_11_enable_rsn cmd; | ||
858 | int ret; | ||
859 | |||
860 | lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable); | ||
861 | |||
862 | /* | ||
863 | * cmd 2f 00 | ||
864 | * size 0c 00 | ||
865 | * sequence xx xx | ||
866 | * result 00 00 | ||
867 | * action 01 00 ACT_SET | ||
868 | * enable 01 00 | ||
869 | */ | ||
870 | memset(&cmd, 0, sizeof(cmd)); | ||
871 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
872 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
873 | cmd.enable = cpu_to_le16(enable); | ||
874 | |||
875 | ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); | ||
876 | |||
877 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
878 | return ret; | ||
879 | } | ||
880 | |||
881 | |||
882 | /* | ||
883 | * Set WPA/WPA key material | ||
884 | */ | ||
885 | |||
886 | /* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we | ||
887 | * get rid of WEXT, this should go into host.h */ | ||
888 | |||
889 | struct cmd_key_material { | ||
890 | struct cmd_header hdr; | ||
891 | |||
892 | __le16 action; | ||
893 | struct MrvlIEtype_keyParamSet param; | ||
894 | } __attribute__ ((packed)); | ||
895 | |||
896 | static int lbs_set_key_material(struct lbs_private *priv, | ||
897 | int key_type, | ||
898 | int key_info, | ||
899 | u8 *key, u16 key_len) | ||
900 | { | ||
901 | struct cmd_key_material cmd; | ||
902 | int ret; | ||
903 | |||
904 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
905 | |||
906 | /* | ||
907 | * Example for WPA (TKIP): | ||
908 | * | ||
909 | * cmd 5e 00 | ||
910 | * size 34 00 | ||
911 | * sequence xx xx | ||
912 | * result 00 00 | ||
913 | * action 01 00 | ||
914 | * TLV type 00 01 key param | ||
915 | * length 00 26 | ||
916 | * key type 01 00 TKIP | ||
917 | * key info 06 00 UNICAST | ENABLED | ||
918 | * key len 20 00 | ||
919 | * key 32 bytes | ||
920 | */ | ||
921 | memset(&cmd, 0, sizeof(cmd)); | ||
922 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
923 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
924 | cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
925 | cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4); | ||
926 | cmd.param.keytypeid = cpu_to_le16(key_type); | ||
927 | cmd.param.keyinfo = cpu_to_le16(key_info); | ||
928 | cmd.param.keylen = cpu_to_le16(key_len); | ||
929 | if (key && key_len) | ||
930 | memcpy(cmd.param.key, key, key_len); | ||
931 | |||
932 | ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); | ||
933 | |||
934 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
935 | return ret; | ||
936 | } | ||
937 | |||
938 | |||
939 | /* | ||
940 | * Sets the auth type (open, shared, etc) in the firmware. That | ||
941 | * we use CMD_802_11_AUTHENTICATE is misleading, this firmware | ||
942 | * command doesn't send an authentication frame at all, it just | ||
943 | * stores the auth_type. | ||
944 | */ | ||
945 | static int lbs_set_authtype(struct lbs_private *priv, | ||
946 | struct cfg80211_connect_params *sme) | ||
947 | { | ||
948 | struct cmd_ds_802_11_authenticate cmd; | ||
949 | int ret; | ||
950 | |||
951 | lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type); | ||
952 | |||
953 | /* | ||
954 | * cmd 11 00 | ||
955 | * size 19 00 | ||
956 | * sequence xx xx | ||
957 | * result 00 00 | ||
958 | * BSS id 00 13 19 80 da 30 | ||
959 | * auth type 00 | ||
960 | * reserved 00 00 00 00 00 00 00 00 00 00 | ||
961 | */ | ||
962 | memset(&cmd, 0, sizeof(cmd)); | ||
963 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
964 | if (sme->bssid) | ||
965 | memcpy(cmd.bssid, sme->bssid, ETH_ALEN); | ||
966 | /* convert auth_type */ | ||
967 | ret = lbs_auth_to_authtype(sme->auth_type); | ||
968 | if (ret < 0) | ||
969 | goto done; | ||
970 | |||
971 | cmd.authtype = ret; | ||
972 | ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); | ||
973 | |||
974 | done: | ||
975 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
976 | return ret; | ||
977 | } | ||
978 | |||
979 | |||
980 | /* | ||
981 | * Create association request | ||
982 | */ | ||
983 | #define LBS_ASSOC_MAX_CMD_SIZE \ | ||
984 | (sizeof(struct cmd_ds_802_11_associate) \ | ||
985 | - 512 /* cmd_ds_802_11_associate.iebuf */ \ | ||
986 | + LBS_MAX_SSID_TLV_SIZE \ | ||
987 | + LBS_MAX_CHANNEL_TLV_SIZE \ | ||
988 | + LBS_MAX_CF_PARAM_TLV_SIZE \ | ||
989 | + LBS_MAX_AUTH_TYPE_TLV_SIZE \ | ||
990 | + LBS_MAX_WPA_TLV_SIZE) | ||
991 | |||
992 | static int lbs_associate(struct lbs_private *priv, | ||
993 | struct cfg80211_bss *bss, | ||
994 | struct cfg80211_connect_params *sme) | ||
995 | { | ||
996 | struct cmd_ds_802_11_associate_response *resp; | ||
997 | struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE, | ||
998 | GFP_KERNEL); | ||
999 | const u8 *ssid_eid; | ||
1000 | size_t len, resp_ie_len; | ||
1001 | int status; | ||
1002 | int ret; | ||
1003 | u8 *pos = &(cmd->iebuf[0]); | ||
1004 | |||
1005 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1006 | |||
1007 | if (!cmd) { | ||
1008 | ret = -ENOMEM; | ||
1009 | goto done; | ||
1010 | } | ||
1011 | |||
1012 | /* | ||
1013 | * cmd 50 00 | ||
1014 | * length 34 00 | ||
1015 | * sequence xx xx | ||
1016 | * result 00 00 | ||
1017 | * BSS id 00 13 19 80 da 30 | ||
1018 | * capabilities 11 00 | ||
1019 | * listen interval 0a 00 | ||
1020 | * beacon interval 00 00 | ||
1021 | * DTIM period 00 | ||
1022 | * TLVs xx (up to 512 bytes) | ||
1023 | */ | ||
1024 | cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE); | ||
1025 | |||
1026 | /* Fill in static fields */ | ||
1027 | memcpy(cmd->bssid, bss->bssid, ETH_ALEN); | ||
1028 | cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); | ||
1029 | cmd->capability = cpu_to_le16(bss->capability); | ||
1030 | |||
1031 | /* add SSID TLV */ | ||
1032 | ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | ||
1033 | if (ssid_eid) | ||
1034 | pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); | ||
1035 | else | ||
1036 | lbs_deb_assoc("no SSID\n"); | ||
1037 | |||
1038 | /* add DS param TLV */ | ||
1039 | if (bss->channel) | ||
1040 | pos += lbs_add_channel_tlv(pos, bss->channel->hw_value); | ||
1041 | else | ||
1042 | lbs_deb_assoc("no channel\n"); | ||
1043 | |||
1044 | /* add (empty) CF param TLV */ | ||
1045 | pos += lbs_add_cf_param_tlv(pos); | ||
1046 | |||
1047 | /* add rates TLV */ | ||
1048 | pos += lbs_add_common_rates_tlv(pos, bss); | ||
1049 | |||
1050 | /* add auth type TLV */ | ||
1051 | if (priv->fwrelease >= 0x09000000) | ||
1052 | pos += lbs_add_auth_type_tlv(pos, sme->auth_type); | ||
1053 | |||
1054 | /* add WPA/WPA2 TLV */ | ||
1055 | if (sme->ie && sme->ie_len) | ||
1056 | pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len); | ||
1057 | |||
1058 | len = (sizeof(*cmd) - sizeof(cmd->iebuf)) + | ||
1059 | (u16)(pos - (u8 *) &cmd->iebuf); | ||
1060 | cmd->hdr.size = cpu_to_le16(len); | ||
1061 | |||
1062 | /* store for later use */ | ||
1063 | memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN); | ||
1064 | |||
1065 | ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd); | ||
1066 | if (ret) | ||
1067 | goto done; | ||
1068 | |||
1069 | |||
1070 | /* generate connect message to cfg80211 */ | ||
1071 | |||
1072 | resp = (void *) cmd; /* recast for easier field access */ | ||
1073 | status = le16_to_cpu(resp->statuscode); | ||
1074 | |||
1075 | /* Convert statis code of old firmware */ | ||
1076 | if (priv->fwrelease < 0x09000000) | ||
1077 | switch (status) { | ||
1078 | case 0: | ||
1079 | break; | ||
1080 | case 1: | ||
1081 | lbs_deb_assoc("invalid association parameters\n"); | ||
1082 | status = WLAN_STATUS_CAPS_UNSUPPORTED; | ||
1083 | break; | ||
1084 | case 2: | ||
1085 | lbs_deb_assoc("timer expired while waiting for AP\n"); | ||
1086 | status = WLAN_STATUS_AUTH_TIMEOUT; | ||
1087 | break; | ||
1088 | case 3: | ||
1089 | lbs_deb_assoc("association refused by AP\n"); | ||
1090 | status = WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||
1091 | break; | ||
1092 | case 4: | ||
1093 | lbs_deb_assoc("authentication refused by AP\n"); | ||
1094 | status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; | ||
1095 | break; | ||
1096 | default: | ||
1097 | lbs_deb_assoc("association failure %d\n", status); | ||
1098 | status = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||
1099 | } | ||
1100 | |||
1101 | lbs_deb_assoc("status %d, capability 0x%04x\n", status, | ||
1102 | le16_to_cpu(resp->capability)); | ||
1103 | |||
1104 | resp_ie_len = le16_to_cpu(resp->hdr.size) | ||
1105 | - sizeof(resp->hdr) | ||
1106 | - 6; | ||
1107 | cfg80211_connect_result(priv->dev, | ||
1108 | priv->assoc_bss, | ||
1109 | sme->ie, sme->ie_len, | ||
1110 | resp->iebuf, resp_ie_len, | ||
1111 | status, | ||
1112 | GFP_KERNEL); | ||
1113 | |||
1114 | if (status == 0) { | ||
1115 | /* TODO: get rid of priv->connect_status */ | ||
1116 | priv->connect_status = LBS_CONNECTED; | ||
1117 | netif_carrier_on(priv->dev); | ||
1118 | if (!priv->tx_pending_len) | ||
1119 | netif_tx_wake_all_queues(priv->dev); | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | done: | ||
1124 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1125 | return ret; | ||
1126 | } | ||
1127 | |||
1128 | |||
1129 | |||
1130 | static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, | ||
1131 | struct cfg80211_connect_params *sme) | ||
1132 | { | ||
1133 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1134 | struct cfg80211_bss *bss = NULL; | ||
1135 | int ret = 0; | ||
1136 | u8 preamble = RADIO_PREAMBLE_SHORT; | ||
1137 | |||
1138 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1139 | |||
1140 | if (sme->bssid) { | ||
1141 | bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, | ||
1142 | sme->ssid, sme->ssid_len, | ||
1143 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
1144 | } else { | ||
1145 | /* | ||
1146 | * Here we have an impedance mismatch. The firmware command | ||
1147 | * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot | ||
1148 | * connect otherwise. However, for the connect-API of | ||
1149 | * cfg80211 the bssid is purely optional. We don't get one, | ||
1150 | * except the user specifies one on the "iw" command line. | ||
1151 | * | ||
1152 | * If we don't got one, we could initiate a scan and look | ||
1153 | * for the best matching cfg80211_bss entry. | ||
1154 | * | ||
1155 | * Or, better yet, net/wireless/sme.c get's rewritten into | ||
1156 | * something more generally useful. | ||
1157 | */ | ||
1158 | lbs_pr_err("TODO: no BSS specified\n"); | ||
1159 | ret = -ENOTSUPP; | ||
1160 | goto done; | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | if (!bss) { | ||
1165 | lbs_pr_err("assicate: bss %pM not in scan results\n", | ||
1166 | sme->bssid); | ||
1167 | ret = -ENOENT; | ||
1168 | goto done; | ||
1169 | } | ||
1170 | lbs_deb_assoc("trying %pM", sme->bssid); | ||
1171 | lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n", | ||
1172 | sme->crypto.cipher_group, | ||
1173 | sme->key_idx, sme->key_len); | ||
1174 | |||
1175 | /* As this is a new connection, clear locally stored WEP keys */ | ||
1176 | priv->wep_tx_key = 0; | ||
1177 | memset(priv->wep_key, 0, sizeof(priv->wep_key)); | ||
1178 | memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); | ||
1179 | |||
1180 | /* set/remove WEP keys */ | ||
1181 | switch (sme->crypto.cipher_group) { | ||
1182 | case WLAN_CIPHER_SUITE_WEP40: | ||
1183 | case WLAN_CIPHER_SUITE_WEP104: | ||
1184 | /* Store provided WEP keys in priv-> */ | ||
1185 | priv->wep_tx_key = sme->key_idx; | ||
1186 | priv->wep_key_len[sme->key_idx] = sme->key_len; | ||
1187 | memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len); | ||
1188 | /* Set WEP keys and WEP mode */ | ||
1189 | lbs_set_wep_keys(priv); | ||
1190 | priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; | ||
1191 | lbs_set_mac_control(priv); | ||
1192 | /* No RSN mode for WEP */ | ||
1193 | lbs_enable_rsn(priv, 0); | ||
1194 | break; | ||
1195 | case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */ | ||
1196 | /* | ||
1197 | * If we don't have no WEP, no WPA and no WPA2, | ||
1198 | * we remove all keys like in the WPA/WPA2 setup, | ||
1199 | * we just don't set RSN. | ||
1200 | * | ||
1201 | * Therefore: fall-throught | ||
1202 | */ | ||
1203 | case WLAN_CIPHER_SUITE_TKIP: | ||
1204 | case WLAN_CIPHER_SUITE_CCMP: | ||
1205 | /* Remove WEP keys and WEP mode */ | ||
1206 | lbs_remove_wep_keys(priv); | ||
1207 | priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; | ||
1208 | lbs_set_mac_control(priv); | ||
1209 | |||
1210 | /* clear the WPA/WPA2 keys */ | ||
1211 | lbs_set_key_material(priv, | ||
1212 | KEY_TYPE_ID_WEP, /* doesn't matter */ | ||
1213 | KEY_INFO_WPA_UNICAST, | ||
1214 | NULL, 0); | ||
1215 | lbs_set_key_material(priv, | ||
1216 | KEY_TYPE_ID_WEP, /* doesn't matter */ | ||
1217 | KEY_INFO_WPA_MCAST, | ||
1218 | NULL, 0); | ||
1219 | /* RSN mode for WPA/WPA2 */ | ||
1220 | lbs_enable_rsn(priv, sme->crypto.cipher_group != 0); | ||
1221 | break; | ||
1222 | default: | ||
1223 | lbs_pr_err("unsupported cipher group 0x%x\n", | ||
1224 | sme->crypto.cipher_group); | ||
1225 | ret = -ENOTSUPP; | ||
1226 | goto done; | ||
1227 | } | ||
1228 | |||
1229 | lbs_set_authtype(priv, sme); | ||
1230 | lbs_set_radio(priv, preamble, 1); | ||
1231 | |||
1232 | /* Do the actual association */ | ||
1233 | lbs_associate(priv, bss, sme); | ||
1234 | |||
1235 | done: | ||
1236 | if (bss) | ||
1237 | cfg80211_put_bss(bss); | ||
1238 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1239 | return ret; | ||
1240 | } | ||
1241 | |||
1242 | static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
1243 | u16 reason_code) | ||
1244 | { | ||
1245 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1246 | struct cmd_ds_802_11_deauthenticate cmd; | ||
1247 | |||
1248 | lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); | ||
1249 | |||
1250 | /* store for lbs_cfg_ret_disconnect() */ | ||
1251 | priv->disassoc_reason = reason_code; | ||
1252 | |||
1253 | memset(&cmd, 0, sizeof(cmd)); | ||
1254 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1255 | /* Mildly ugly to use a locally store my own BSSID ... */ | ||
1256 | memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); | ||
1257 | cmd.reasoncode = cpu_to_le16(reason_code); | ||
1258 | |||
1259 | if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd)) | ||
1260 | return -EFAULT; | ||
1261 | |||
1262 | cfg80211_disconnected(priv->dev, | ||
1263 | priv->disassoc_reason, | ||
1264 | NULL, 0, | ||
1265 | GFP_KERNEL); | ||
1266 | priv->connect_status = LBS_DISCONNECTED; | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | static int lbs_cfg_set_default_key(struct wiphy *wiphy, | ||
1273 | struct net_device *netdev, | ||
1274 | u8 key_index) | ||
1275 | { | ||
1276 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1277 | |||
1278 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1279 | |||
1280 | if (key_index != priv->wep_tx_key) { | ||
1281 | lbs_deb_assoc("set_default_key: to %d\n", key_index); | ||
1282 | priv->wep_tx_key = key_index; | ||
1283 | lbs_set_wep_keys(priv); | ||
1284 | } | ||
1285 | |||
1286 | return 0; | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, | ||
1291 | u8 idx, const u8 *mac_addr, | ||
1292 | struct key_params *params) | ||
1293 | { | ||
1294 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1295 | u16 key_info; | ||
1296 | u16 key_type; | ||
1297 | int ret = 0; | ||
1298 | |||
1299 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1300 | |||
1301 | lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", | ||
1302 | params->cipher, mac_addr); | ||
1303 | lbs_deb_assoc("add_key: key index %d, key len %d\n", | ||
1304 | idx, params->key_len); | ||
1305 | if (params->key_len) | ||
1306 | lbs_deb_hex(LBS_DEB_CFG80211, "KEY", | ||
1307 | params->key, params->key_len); | ||
1308 | |||
1309 | lbs_deb_assoc("add_key: seq len %d\n", params->seq_len); | ||
1310 | if (params->seq_len) | ||
1311 | lbs_deb_hex(LBS_DEB_CFG80211, "SEQ", | ||
1312 | params->seq, params->seq_len); | ||
1313 | |||
1314 | switch (params->cipher) { | ||
1315 | case WLAN_CIPHER_SUITE_WEP40: | ||
1316 | case WLAN_CIPHER_SUITE_WEP104: | ||
1317 | /* actually compare if something has changed ... */ | ||
1318 | if ((priv->wep_key_len[idx] != params->key_len) || | ||
1319 | memcmp(priv->wep_key[idx], | ||
1320 | params->key, params->key_len) != 0) { | ||
1321 | priv->wep_key_len[idx] = params->key_len; | ||
1322 | memcpy(priv->wep_key[idx], | ||
1323 | params->key, params->key_len); | ||
1324 | lbs_set_wep_keys(priv); | ||
1325 | } | ||
1326 | break; | ||
1327 | case WLAN_CIPHER_SUITE_TKIP: | ||
1328 | case WLAN_CIPHER_SUITE_CCMP: | ||
1329 | key_info = KEY_INFO_WPA_ENABLED | ((idx == 0) | ||
1330 | ? KEY_INFO_WPA_UNICAST | ||
1331 | : KEY_INFO_WPA_MCAST); | ||
1332 | key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
1333 | ? KEY_TYPE_ID_TKIP | ||
1334 | : KEY_TYPE_ID_AES; | ||
1335 | lbs_set_key_material(priv, | ||
1336 | key_type, | ||
1337 | key_info, | ||
1338 | params->key, params->key_len); | ||
1339 | break; | ||
1340 | default: | ||
1341 | lbs_pr_err("unhandled cipher 0x%x\n", params->cipher); | ||
1342 | ret = -ENOTSUPP; | ||
1343 | break; | ||
1344 | } | ||
1345 | |||
1346 | return ret; | ||
1347 | } | ||
1348 | |||
1349 | |||
1350 | static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, | ||
1351 | u8 key_index, const u8 *mac_addr) | ||
1352 | { | ||
1353 | |||
1354 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1355 | |||
1356 | lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n", | ||
1357 | key_index, mac_addr); | ||
1358 | |||
1359 | #ifdef TODO | ||
1360 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1361 | /* | ||
1362 | * I think can keep this a NO-OP, because: | ||
1363 | |||
1364 | * - we clear all keys whenever we do lbs_cfg_connect() anyway | ||
1365 | * - neither "iw" nor "wpa_supplicant" won't call this during | ||
1366 | * an ongoing connection | ||
1367 | * - TODO: but I have to check if this is still true when | ||
1368 | * I set the AP to periodic re-keying | ||
1369 | * - we've not kzallec() something when we've added a key at | ||
1370 | * lbs_cfg_connect() or lbs_cfg_add_key(). | ||
1371 | * | ||
1372 | * This causes lbs_cfg_del_key() only called at disconnect time, | ||
1373 | * where we'd just waste time deleting a key that is not going | ||
1374 | * to be used anyway. | ||
1375 | */ | ||
1376 | if (key_index < 3 && priv->wep_key_len[key_index]) { | ||
1377 | priv->wep_key_len[key_index] = 0; | ||
1378 | lbs_set_wep_keys(priv); | ||
1379 | } | ||
1380 | #endif | ||
1381 | |||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | |||
1386 | |||
1387 | /*************************************************************************** | ||
1388 | * Monitor mode | ||
1389 | */ | ||
1390 | |||
1391 | /* like "struct cmd_ds_802_11_monitor_mode", but with cmd_header. Once we | ||
1392 | * get rid of WEXT, this should go into host.h */ | ||
1393 | struct cmd_monitor_mode { | ||
1394 | struct cmd_header hdr; | ||
1395 | |||
1396 | __le16 action; | ||
1397 | __le16 mode; | ||
1398 | } __attribute__ ((packed)); | ||
1399 | |||
1400 | static int lbs_enable_monitor_mode(struct lbs_private *priv, int mode) | ||
1401 | { | ||
1402 | struct cmd_monitor_mode cmd; | ||
1403 | int ret; | ||
1404 | |||
1405 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1406 | |||
1407 | /* | ||
1408 | * cmd 98 00 | ||
1409 | * size 0c 00 | ||
1410 | * sequence xx xx | ||
1411 | * result 00 00 | ||
1412 | * action 01 00 ACT_SET | ||
1413 | * enable 01 00 | ||
1414 | */ | ||
1415 | memset(&cmd, 0, sizeof(cmd)); | ||
1416 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1417 | cmd.action = cpu_to_le16(CMD_ACT_SET); | ||
1418 | cmd.mode = cpu_to_le16(mode); | ||
1419 | |||
1420 | ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd); | ||
1421 | |||
1422 | if (ret == 0) | ||
1423 | priv->dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
1424 | else | ||
1425 | priv->dev->type = ARPHRD_ETHER; | ||
1426 | |||
1427 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
1428 | return ret; | ||
1429 | } | ||
1430 | |||
1431 | |||
1432 | |||
1433 | |||
1434 | |||
1435 | |||
1436 | /*************************************************************************** | ||
1437 | * Get station | ||
1438 | */ | ||
1439 | |||
1440 | /* | ||
1441 | * Returns the signal or 0 in case of an error. | ||
1442 | */ | ||
1443 | |||
1444 | /* like "struct cmd_ds_802_11_rssi", but with cmd_header. Once we get rid | ||
1445 | * of WEXT, this should go into host.h */ | ||
1446 | struct cmd_rssi { | ||
1447 | struct cmd_header hdr; | ||
1448 | |||
1449 | __le16 n_or_snr; | ||
1450 | __le16 nf; | ||
1451 | __le16 avg_snr; | ||
1452 | __le16 avg_nf; | ||
1453 | } __attribute__ ((packed)); | ||
1454 | |||
1455 | static int lbs_get_signal(struct lbs_private *priv, s8 *signal, s8 *noise) | ||
1456 | { | ||
1457 | struct cmd_rssi cmd; | ||
1458 | int ret; | ||
1459 | |||
1460 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1461 | cmd.n_or_snr = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); | ||
1462 | ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd); | ||
1463 | |||
1464 | if (ret == 0) { | ||
1465 | *signal = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), | ||
1466 | le16_to_cpu(cmd.nf)); | ||
1467 | *noise = CAL_NF(le16_to_cpu(cmd.nf)); | ||
1468 | } | ||
1469 | return ret; | ||
1470 | } | ||
1471 | |||
1472 | |||
1473 | static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, | ||
1474 | u8 *mac, struct station_info *sinfo) | ||
1475 | { | ||
1476 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1477 | s8 signal, noise; | ||
1478 | int ret; | ||
1479 | size_t i; | ||
1480 | |||
1481 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1482 | |||
1483 | sinfo->filled |= STATION_INFO_TX_BYTES | | ||
1484 | STATION_INFO_TX_PACKETS | | ||
1485 | STATION_INFO_RX_BYTES | | ||
1486 | STATION_INFO_RX_PACKETS; | ||
1487 | sinfo->tx_bytes = priv->dev->stats.tx_bytes; | ||
1488 | sinfo->tx_packets = priv->dev->stats.tx_packets; | ||
1489 | sinfo->rx_bytes = priv->dev->stats.rx_bytes; | ||
1490 | sinfo->rx_packets = priv->dev->stats.rx_packets; | ||
1491 | |||
1492 | /* Get current RSSI */ | ||
1493 | ret = lbs_get_signal(priv, &signal, &noise); | ||
1494 | if (ret == 0) { | ||
1495 | sinfo->signal = signal; | ||
1496 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
1497 | } | ||
1498 | |||
1499 | /* Convert priv->cur_rate from hw_value to NL80211 value */ | ||
1500 | for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { | ||
1501 | if (priv->cur_rate == lbs_rates[i].hw_value) { | ||
1502 | sinfo->txrate.legacy = lbs_rates[i].bitrate; | ||
1503 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
1504 | break; | ||
1505 | } | ||
1506 | } | ||
1507 | |||
1508 | return 0; | ||
1509 | } | ||
1510 | |||
1511 | |||
1512 | |||
1513 | |||
1514 | /*************************************************************************** | ||
1515 | * "Site survey", here just current channel and noise level | ||
1516 | */ | ||
1517 | |||
1518 | static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, | ||
1519 | int idx, struct survey_info *survey) | ||
1520 | { | ||
1521 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1522 | s8 signal, noise; | ||
1523 | int ret; | ||
1524 | |||
1525 | if (idx != 0) | ||
1526 | ret = -ENOENT; | ||
1527 | |||
1528 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1529 | |||
1530 | survey->channel = ieee80211_get_channel(wiphy, | ||
1531 | ieee80211_channel_to_frequency(priv->channel)); | ||
1532 | |||
1533 | ret = lbs_get_signal(priv, &signal, &noise); | ||
1534 | if (ret == 0) { | ||
1535 | survey->filled = SURVEY_INFO_NOISE_DBM; | ||
1536 | survey->noise = noise; | ||
1537 | } | ||
1538 | |||
1539 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1540 | return ret; | ||
1541 | } | ||
1542 | |||
1543 | |||
1544 | |||
1545 | |||
1546 | /*************************************************************************** | ||
1547 | * Change interface | ||
1548 | */ | ||
1549 | |||
1550 | static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, | ||
1551 | enum nl80211_iftype type, u32 *flags, | ||
1552 | struct vif_params *params) | ||
1553 | { | ||
1554 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1555 | int ret = 0; | ||
1556 | |||
1557 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1558 | |||
1559 | switch (type) { | ||
1560 | case NL80211_IFTYPE_MONITOR: | ||
1561 | ret = lbs_enable_monitor_mode(priv, 1); | ||
1562 | break; | ||
1563 | case NL80211_IFTYPE_STATION: | ||
1564 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) | ||
1565 | ret = lbs_enable_monitor_mode(priv, 0); | ||
1566 | if (!ret) | ||
1567 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1); | ||
1568 | break; | ||
1569 | case NL80211_IFTYPE_ADHOC: | ||
1570 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) | ||
1571 | ret = lbs_enable_monitor_mode(priv, 0); | ||
1572 | if (!ret) | ||
1573 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2); | ||
1574 | break; | ||
1575 | default: | ||
1576 | ret = -ENOTSUPP; | ||
1577 | } | ||
1578 | |||
1579 | if (!ret) | ||
1580 | priv->wdev->iftype = type; | ||
1581 | |||
1582 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1583 | return ret; | ||
1584 | } | ||
1585 | |||
1586 | |||
1587 | |||
1588 | /*************************************************************************** | ||
1589 | * IBSS (Ad-Hoc) | ||
1590 | */ | ||
1591 | |||
1592 | /* The firmware needs the following bits masked out of the beacon-derived | ||
1593 | * capability field when associating/joining to a BSS: | ||
1594 | * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) | ||
1595 | */ | ||
1596 | #define CAPINFO_MASK (~(0xda00)) | ||
1597 | |||
1598 | |||
1599 | static void lbs_join_post(struct lbs_private *priv, | ||
1600 | struct cfg80211_ibss_params *params, | ||
1601 | u8 *bssid, u16 capability) | ||
1602 | { | ||
1603 | u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */ | ||
1604 | 2 + 4 + /* basic rates */ | ||
1605 | 2 + 1 + /* DS parameter */ | ||
1606 | 2 + 2 + /* atim */ | ||
1607 | 2 + 8]; /* extended rates */ | ||
1608 | u8 *fake = fake_ie; | ||
1609 | |||
1610 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1611 | |||
1612 | /* | ||
1613 | * For cfg80211_inform_bss, we'll need a fake IE, as we can't get | ||
1614 | * the real IE from the firmware. So we fabricate a fake IE based on | ||
1615 | * what the firmware actually sends (sniffed with wireshark). | ||
1616 | */ | ||
1617 | /* Fake SSID IE */ | ||
1618 | *fake++ = WLAN_EID_SSID; | ||
1619 | *fake++ = params->ssid_len; | ||
1620 | memcpy(fake, params->ssid, params->ssid_len); | ||
1621 | fake += params->ssid_len; | ||
1622 | /* Fake supported basic rates IE */ | ||
1623 | *fake++ = WLAN_EID_SUPP_RATES; | ||
1624 | *fake++ = 4; | ||
1625 | *fake++ = 0x82; | ||
1626 | *fake++ = 0x84; | ||
1627 | *fake++ = 0x8b; | ||
1628 | *fake++ = 0x96; | ||
1629 | /* Fake DS channel IE */ | ||
1630 | *fake++ = WLAN_EID_DS_PARAMS; | ||
1631 | *fake++ = 1; | ||
1632 | *fake++ = params->channel->hw_value; | ||
1633 | /* Fake IBSS params IE */ | ||
1634 | *fake++ = WLAN_EID_IBSS_PARAMS; | ||
1635 | *fake++ = 2; | ||
1636 | *fake++ = 0; /* ATIM=0 */ | ||
1637 | *fake++ = 0; | ||
1638 | /* Fake extended rates IE, TODO: don't add this for 802.11b only, | ||
1639 | * but I don't know how this could be checked */ | ||
1640 | *fake++ = WLAN_EID_EXT_SUPP_RATES; | ||
1641 | *fake++ = 8; | ||
1642 | *fake++ = 0x0c; | ||
1643 | *fake++ = 0x12; | ||
1644 | *fake++ = 0x18; | ||
1645 | *fake++ = 0x24; | ||
1646 | *fake++ = 0x30; | ||
1647 | *fake++ = 0x48; | ||
1648 | *fake++ = 0x60; | ||
1649 | *fake++ = 0x6c; | ||
1650 | lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie); | ||
1651 | |||
1652 | cfg80211_inform_bss(priv->wdev->wiphy, | ||
1653 | params->channel, | ||
1654 | bssid, | ||
1655 | 0, | ||
1656 | capability, | ||
1657 | params->beacon_interval, | ||
1658 | fake_ie, fake - fake_ie, | ||
1659 | 0, GFP_KERNEL); | ||
1660 | |||
1661 | memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); | ||
1662 | priv->wdev->ssid_len = params->ssid_len; | ||
1663 | |||
1664 | cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL); | ||
1665 | |||
1666 | /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */ | ||
1667 | priv->connect_status = LBS_CONNECTED; | ||
1668 | netif_carrier_on(priv->dev); | ||
1669 | if (!priv->tx_pending_len) | ||
1670 | netif_wake_queue(priv->dev); | ||
1671 | |||
1672 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
1673 | } | ||
1674 | |||
1675 | static int lbs_ibss_join_existing(struct lbs_private *priv, | ||
1676 | struct cfg80211_ibss_params *params, | ||
1677 | struct cfg80211_bss *bss) | ||
1678 | { | ||
1679 | const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); | ||
1680 | struct cmd_ds_802_11_ad_hoc_join cmd; | ||
1681 | u8 preamble = RADIO_PREAMBLE_SHORT; | ||
1682 | int ret = 0; | ||
1683 | |||
1684 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1685 | |||
1686 | /* TODO: set preamble based on scan result */ | ||
1687 | ret = lbs_set_radio(priv, preamble, 1); | ||
1688 | if (ret) | ||
1689 | goto out; | ||
1690 | |||
1691 | /* | ||
1692 | * Example CMD_802_11_AD_HOC_JOIN command: | ||
1693 | * | ||
1694 | * command 2c 00 CMD_802_11_AD_HOC_JOIN | ||
1695 | * size 65 00 | ||
1696 | * sequence xx xx | ||
1697 | * result 00 00 | ||
1698 | * bssid 02 27 27 97 2f 96 | ||
1699 | * ssid 49 42 53 53 00 00 00 00 | ||
1700 | * 00 00 00 00 00 00 00 00 | ||
1701 | * 00 00 00 00 00 00 00 00 | ||
1702 | * 00 00 00 00 00 00 00 00 | ||
1703 | * type 02 CMD_BSS_TYPE_IBSS | ||
1704 | * beacon period 64 00 | ||
1705 | * dtim period 00 | ||
1706 | * timestamp 00 00 00 00 00 00 00 00 | ||
1707 | * localtime 00 00 00 00 00 00 00 00 | ||
1708 | * IE DS 03 | ||
1709 | * IE DS len 01 | ||
1710 | * IE DS channel 01 | ||
1711 | * reserveed 00 00 00 00 | ||
1712 | * IE IBSS 06 | ||
1713 | * IE IBSS len 02 | ||
1714 | * IE IBSS atim 00 00 | ||
1715 | * reserved 00 00 00 00 | ||
1716 | * capability 02 00 | ||
1717 | * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c 00 | ||
1718 | * fail timeout ff 00 | ||
1719 | * probe delay 00 00 | ||
1720 | */ | ||
1721 | memset(&cmd, 0, sizeof(cmd)); | ||
1722 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1723 | |||
1724 | memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN); | ||
1725 | memcpy(cmd.bss.ssid, params->ssid, params->ssid_len); | ||
1726 | cmd.bss.type = CMD_BSS_TYPE_IBSS; | ||
1727 | cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval); | ||
1728 | cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS; | ||
1729 | cmd.bss.ds.header.len = 1; | ||
1730 | cmd.bss.ds.channel = params->channel->hw_value; | ||
1731 | cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS; | ||
1732 | cmd.bss.ibss.header.len = 2; | ||
1733 | cmd.bss.ibss.atimwindow = 0; | ||
1734 | cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); | ||
1735 | |||
1736 | /* set rates to the intersection of our rates and the rates in the | ||
1737 | bss */ | ||
1738 | if (!rates_eid) { | ||
1739 | lbs_add_rates(cmd.bss.rates); | ||
1740 | } else { | ||
1741 | int hw, i; | ||
1742 | u8 rates_max = rates_eid[1]; | ||
1743 | u8 *rates = cmd.bss.rates; | ||
1744 | for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { | ||
1745 | u8 hw_rate = lbs_rates[hw].bitrate / 5; | ||
1746 | for (i = 0; i < rates_max; i++) { | ||
1747 | if (hw_rate == (rates_eid[i+2] & 0x7f)) { | ||
1748 | u8 rate = rates_eid[i+2]; | ||
1749 | if (rate == 0x02 || rate == 0x04 || | ||
1750 | rate == 0x0b || rate == 0x16) | ||
1751 | rate |= 0x80; | ||
1752 | *rates++ = rate; | ||
1753 | } | ||
1754 | } | ||
1755 | } | ||
1756 | } | ||
1757 | |||
1758 | /* Only v8 and below support setting this */ | ||
1759 | if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) { | ||
1760 | cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); | ||
1761 | cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); | ||
1762 | } | ||
1763 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); | ||
1764 | if (ret) | ||
1765 | goto out; | ||
1766 | |||
1767 | /* | ||
1768 | * This is a sample response to CMD_802_11_AD_HOC_JOIN: | ||
1769 | * | ||
1770 | * response 2c 80 | ||
1771 | * size 09 00 | ||
1772 | * sequence xx xx | ||
1773 | * result 00 00 | ||
1774 | * reserved 00 | ||
1775 | */ | ||
1776 | lbs_join_post(priv, params, bss->bssid, bss->capability); | ||
1777 | |||
1778 | out: | ||
1779 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1780 | return ret; | ||
1781 | } | ||
1782 | |||
1783 | |||
1784 | |||
1785 | static int lbs_ibss_start_new(struct lbs_private *priv, | ||
1786 | struct cfg80211_ibss_params *params) | ||
1787 | { | ||
1788 | struct cmd_ds_802_11_ad_hoc_start cmd; | ||
1789 | struct cmd_ds_802_11_ad_hoc_result *resp = | ||
1790 | (struct cmd_ds_802_11_ad_hoc_result *) &cmd; | ||
1791 | u8 preamble = RADIO_PREAMBLE_SHORT; | ||
1792 | int ret = 0; | ||
1793 | u16 capability; | ||
1794 | |||
1795 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1796 | |||
1797 | ret = lbs_set_radio(priv, preamble, 1); | ||
1798 | if (ret) | ||
1799 | goto out; | ||
1800 | |||
1801 | /* | ||
1802 | * Example CMD_802_11_AD_HOC_START command: | ||
1803 | * | ||
1804 | * command 2b 00 CMD_802_11_AD_HOC_START | ||
1805 | * size b1 00 | ||
1806 | * sequence xx xx | ||
1807 | * result 00 00 | ||
1808 | * ssid 54 45 53 54 00 00 00 00 | ||
1809 | * 00 00 00 00 00 00 00 00 | ||
1810 | * 00 00 00 00 00 00 00 00 | ||
1811 | * 00 00 00 00 00 00 00 00 | ||
1812 | * bss type 02 | ||
1813 | * beacon period 64 00 | ||
1814 | * dtim period 00 | ||
1815 | * IE IBSS 06 | ||
1816 | * IE IBSS len 02 | ||
1817 | * IE IBSS atim 00 00 | ||
1818 | * reserved 00 00 00 00 | ||
1819 | * IE DS 03 | ||
1820 | * IE DS len 01 | ||
1821 | * IE DS channel 01 | ||
1822 | * reserved 00 00 00 00 | ||
1823 | * probe delay 00 00 | ||
1824 | * capability 02 00 | ||
1825 | * rates 82 84 8b 96 (basic rates with have bit 7 set) | ||
1826 | * 0c 12 18 24 30 48 60 6c | ||
1827 | * padding 100 bytes | ||
1828 | */ | ||
1829 | memset(&cmd, 0, sizeof(cmd)); | ||
1830 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1831 | memcpy(cmd.ssid, params->ssid, params->ssid_len); | ||
1832 | cmd.bsstype = CMD_BSS_TYPE_IBSS; | ||
1833 | cmd.beaconperiod = cpu_to_le16(params->beacon_interval); | ||
1834 | cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; | ||
1835 | cmd.ibss.header.len = 2; | ||
1836 | cmd.ibss.atimwindow = 0; | ||
1837 | cmd.ds.header.id = WLAN_EID_DS_PARAMS; | ||
1838 | cmd.ds.header.len = 1; | ||
1839 | cmd.ds.channel = params->channel->hw_value; | ||
1840 | /* Only v8 and below support setting probe delay */ | ||
1841 | if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) | ||
1842 | cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); | ||
1843 | /* TODO: mix in WLAN_CAPABILITY_PRIVACY */ | ||
1844 | capability = WLAN_CAPABILITY_IBSS; | ||
1845 | cmd.capability = cpu_to_le16(capability); | ||
1846 | lbs_add_rates(cmd.rates); | ||
1847 | |||
1848 | |||
1849 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); | ||
1850 | if (ret) | ||
1851 | goto out; | ||
1852 | |||
1853 | /* | ||
1854 | * This is a sample response to CMD_802_11_AD_HOC_JOIN: | ||
1855 | * | ||
1856 | * response 2b 80 | ||
1857 | * size 14 00 | ||
1858 | * sequence xx xx | ||
1859 | * result 00 00 | ||
1860 | * reserved 00 | ||
1861 | * bssid 02 2b 7b 0f 86 0e | ||
1862 | */ | ||
1863 | lbs_join_post(priv, params, resp->bssid, capability); | ||
1864 | |||
1865 | out: | ||
1866 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1867 | return ret; | ||
1868 | } | ||
1869 | |||
1870 | |||
1871 | static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
1872 | struct cfg80211_ibss_params *params) | ||
1873 | { | ||
1874 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1875 | int ret = 0; | ||
1876 | struct cfg80211_bss *bss; | ||
1877 | DECLARE_SSID_BUF(ssid_buf); | ||
1878 | |||
1879 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1880 | |||
1881 | if (!params->channel) { | ||
1882 | ret = -ENOTSUPP; | ||
1883 | goto out; | ||
1884 | } | ||
1885 | |||
1886 | ret = lbs_set_channel(priv, params->channel->hw_value); | ||
1887 | if (ret) | ||
1888 | goto out; | ||
1889 | |||
1890 | /* Search if someone is beaconing. This assumes that the | ||
1891 | * bss list is populated already */ | ||
1892 | bss = cfg80211_get_bss(wiphy, params->channel, params->bssid, | ||
1893 | params->ssid, params->ssid_len, | ||
1894 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); | ||
1895 | |||
1896 | if (bss) { | ||
1897 | ret = lbs_ibss_join_existing(priv, params, bss); | ||
1898 | cfg80211_put_bss(bss); | ||
1899 | } else | ||
1900 | ret = lbs_ibss_start_new(priv, params); | ||
1901 | |||
1902 | |||
1903 | out: | ||
1904 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1905 | return ret; | ||
1906 | } | ||
1907 | |||
1908 | |||
1909 | static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
1910 | { | ||
1911 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
1912 | struct cmd_ds_802_11_ad_hoc_stop cmd; | ||
1913 | int ret = 0; | ||
1914 | |||
1915 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
1916 | |||
1917 | memset(&cmd, 0, sizeof(cmd)); | ||
1918 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | ||
1919 | ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); | ||
1920 | |||
1921 | /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */ | ||
1922 | lbs_mac_event_disconnected(priv); | ||
1923 | |||
1924 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | ||
1925 | return ret; | ||
1926 | } | ||
1927 | |||
1928 | |||
1929 | |||
1930 | |||
1931 | /*************************************************************************** | ||
1932 | * Initialization | ||
1933 | */ | ||
1934 | |||
104 | static struct cfg80211_ops lbs_cfg80211_ops = { | 1935 | static struct cfg80211_ops lbs_cfg80211_ops = { |
105 | .set_channel = lbs_cfg_set_channel, | 1936 | .set_channel = lbs_cfg_set_channel, |
1937 | .scan = lbs_cfg_scan, | ||
1938 | .connect = lbs_cfg_connect, | ||
1939 | .disconnect = lbs_cfg_disconnect, | ||
1940 | .add_key = lbs_cfg_add_key, | ||
1941 | .del_key = lbs_cfg_del_key, | ||
1942 | .set_default_key = lbs_cfg_set_default_key, | ||
1943 | .get_station = lbs_cfg_get_station, | ||
1944 | .dump_survey = lbs_get_survey, | ||
1945 | .change_virtual_intf = lbs_change_intf, | ||
1946 | .join_ibss = lbs_join_ibss, | ||
1947 | .leave_ibss = lbs_leave_ibss, | ||
106 | }; | 1948 | }; |
107 | 1949 | ||
108 | 1950 | ||
@@ -142,6 +1984,36 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev) | |||
142 | } | 1984 | } |
143 | 1985 | ||
144 | 1986 | ||
1987 | static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) | ||
1988 | { | ||
1989 | struct region_code_mapping { | ||
1990 | const char *cn; | ||
1991 | int code; | ||
1992 | }; | ||
1993 | |||
1994 | /* Section 5.17.2 */ | ||
1995 | static struct region_code_mapping regmap[] = { | ||
1996 | {"US ", 0x10}, /* US FCC */ | ||
1997 | {"CA ", 0x20}, /* Canada */ | ||
1998 | {"EU ", 0x30}, /* ETSI */ | ||
1999 | {"ES ", 0x31}, /* Spain */ | ||
2000 | {"FR ", 0x32}, /* France */ | ||
2001 | {"JP ", 0x40}, /* Japan */ | ||
2002 | }; | ||
2003 | size_t i; | ||
2004 | |||
2005 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
2006 | |||
2007 | for (i = 0; i < ARRAY_SIZE(regmap); i++) | ||
2008 | if (regmap[i].code == priv->regioncode) { | ||
2009 | regulatory_hint(priv->wdev->wiphy, regmap[i].cn); | ||
2010 | break; | ||
2011 | } | ||
2012 | |||
2013 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
2014 | } | ||
2015 | |||
2016 | |||
145 | /* | 2017 | /* |
146 | * This function get's called after lbs_setup_firmware() determined the | 2018 | * This function get's called after lbs_setup_firmware() determined the |
147 | * firmware capabities. So we can setup the wiphy according to our | 2019 | * firmware capabities. So we can setup the wiphy according to our |
@@ -157,10 +2029,12 @@ int lbs_cfg_register(struct lbs_private *priv) | |||
157 | wdev->wiphy->max_scan_ssids = 1; | 2029 | wdev->wiphy->max_scan_ssids = 1; |
158 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 2030 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
159 | 2031 | ||
160 | /* TODO: BIT(NL80211_IFTYPE_ADHOC); */ | 2032 | wdev->wiphy->interface_modes = |
161 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 2033 | BIT(NL80211_IFTYPE_STATION) | |
2034 | BIT(NL80211_IFTYPE_ADHOC); | ||
2035 | if (lbs_rtap_supported(priv)) | ||
2036 | wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | ||
162 | 2037 | ||
163 | /* TODO: honor priv->regioncode */ | ||
164 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; | 2038 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; |
165 | 2039 | ||
166 | /* | 2040 | /* |
@@ -169,6 +2043,7 @@ int lbs_cfg_register(struct lbs_private *priv) | |||
169 | */ | 2043 | */ |
170 | wdev->wiphy->cipher_suites = cipher_suites; | 2044 | wdev->wiphy->cipher_suites = cipher_suites; |
171 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 2045 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
2046 | wdev->wiphy->reg_notifier = lbs_reg_notifier; | ||
172 | 2047 | ||
173 | ret = wiphy_register(wdev->wiphy); | 2048 | ret = wiphy_register(wdev->wiphy); |
174 | if (ret < 0) | 2049 | if (ret < 0) |
@@ -180,10 +2055,129 @@ int lbs_cfg_register(struct lbs_private *priv) | |||
180 | if (ret) | 2055 | if (ret) |
181 | lbs_pr_err("cannot register network device\n"); | 2056 | lbs_pr_err("cannot register network device\n"); |
182 | 2057 | ||
2058 | INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); | ||
2059 | |||
2060 | lbs_cfg_set_regulatory_hint(priv); | ||
2061 | |||
183 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); | 2062 | lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); |
184 | return ret; | 2063 | return ret; |
185 | } | 2064 | } |
186 | 2065 | ||
2066 | /** | ||
2067 | * @brief This function sets DOMAIN INFO to FW | ||
2068 | * @param priv pointer to struct lbs_private | ||
2069 | * @return 0; -1 | ||
2070 | */ | ||
2071 | static int lbs_11d_set_domain_info(struct lbs_private *priv) | ||
2072 | { | ||
2073 | int ret; | ||
2074 | |||
2075 | ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, | ||
2076 | CMD_ACT_SET, | ||
2077 | CMD_OPTION_WAITFORRSP, 0, NULL); | ||
2078 | if (ret) | ||
2079 | lbs_deb_11d("fail to dnld domain info\n"); | ||
2080 | |||
2081 | return ret; | ||
2082 | } | ||
2083 | |||
2084 | static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy, | ||
2085 | struct regulatory_request *request) | ||
2086 | { | ||
2087 | u8 no_of_triplet = 0; | ||
2088 | u8 no_of_parsed_chan = 0; | ||
2089 | u8 first_channel = 0, next_chan = 0, max_pwr = 0; | ||
2090 | u8 i, flag = 0; | ||
2091 | enum ieee80211_band band; | ||
2092 | struct ieee80211_supported_band *sband; | ||
2093 | struct ieee80211_channel *ch; | ||
2094 | struct lbs_private *priv = wiphy_priv(wiphy); | ||
2095 | struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg; | ||
2096 | int ret = 0; | ||
2097 | |||
2098 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
2099 | |||
2100 | /* Set country code */ | ||
2101 | domain_info->country_code[0] = request->alpha2[0]; | ||
2102 | domain_info->country_code[1] = request->alpha2[1]; | ||
2103 | domain_info->country_code[2] = ' '; | ||
2104 | |||
2105 | for (band = 0; band < IEEE80211_NUM_BANDS ; band++) { | ||
2106 | |||
2107 | if (!wiphy->bands[band]) | ||
2108 | continue; | ||
2109 | |||
2110 | sband = wiphy->bands[band]; | ||
2111 | |||
2112 | for (i = 0; i < sband->n_channels ; i++) { | ||
2113 | ch = &sband->channels[i]; | ||
2114 | if (ch->flags & IEEE80211_CHAN_DISABLED) | ||
2115 | continue; | ||
2116 | |||
2117 | if (!flag) { | ||
2118 | flag = 1; | ||
2119 | next_chan = first_channel = (u32) ch->hw_value; | ||
2120 | max_pwr = ch->max_power; | ||
2121 | no_of_parsed_chan = 1; | ||
2122 | continue; | ||
2123 | } | ||
2124 | |||
2125 | if (ch->hw_value == next_chan + 1 && | ||
2126 | ch->max_power == max_pwr) { | ||
2127 | next_chan++; | ||
2128 | no_of_parsed_chan++; | ||
2129 | } else { | ||
2130 | domain_info->triplet[no_of_triplet] | ||
2131 | .chans.first_channel = first_channel; | ||
2132 | domain_info->triplet[no_of_triplet] | ||
2133 | .chans.num_channels = no_of_parsed_chan; | ||
2134 | domain_info->triplet[no_of_triplet] | ||
2135 | .chans.max_power = max_pwr; | ||
2136 | no_of_triplet++; | ||
2137 | flag = 0; | ||
2138 | } | ||
2139 | } | ||
2140 | if (flag) { | ||
2141 | domain_info->triplet[no_of_triplet] | ||
2142 | .chans.first_channel = first_channel; | ||
2143 | domain_info->triplet[no_of_triplet] | ||
2144 | .chans.num_channels = no_of_parsed_chan; | ||
2145 | domain_info->triplet[no_of_triplet] | ||
2146 | .chans.max_power = max_pwr; | ||
2147 | no_of_triplet++; | ||
2148 | } | ||
2149 | } | ||
2150 | |||
2151 | domain_info->no_triplet = no_of_triplet; | ||
2152 | |||
2153 | /* Set domain info */ | ||
2154 | ret = lbs_11d_set_domain_info(priv); | ||
2155 | if (ret) | ||
2156 | lbs_pr_err("11D: error setting domain info in FW\n"); | ||
2157 | |||
2158 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
2159 | } | ||
2160 | |||
2161 | int lbs_reg_notifier(struct wiphy *wiphy, | ||
2162 | struct regulatory_request *request) | ||
2163 | { | ||
2164 | lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " | ||
2165 | "callback for domain %c%c\n", request->alpha2[0], | ||
2166 | request->alpha2[1]); | ||
2167 | |||
2168 | lbs_send_domain_info_cmd_fw(wiphy, request); | ||
2169 | |||
2170 | lbs_deb_leave(LBS_DEB_CFG80211); | ||
2171 | |||
2172 | return 0; | ||
2173 | } | ||
2174 | |||
2175 | void lbs_scan_deinit(struct lbs_private *priv) | ||
2176 | { | ||
2177 | lbs_deb_enter(LBS_DEB_CFG80211); | ||
2178 | cancel_delayed_work_sync(&priv->scan_work); | ||
2179 | } | ||
2180 | |||
187 | 2181 | ||
188 | void lbs_cfg_free(struct lbs_private *priv) | 2182 | void lbs_cfg_free(struct lbs_private *priv) |
189 | { | 2183 | { |
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h index e09a193a34d6..756fb98f9f05 100644 --- a/drivers/net/wireless/libertas/cfg.h +++ b/drivers/net/wireless/libertas/cfg.h | |||
@@ -1,16 +1,27 @@ | |||
1 | #ifndef __LBS_CFG80211_H__ | 1 | #ifndef __LBS_CFG80211_H__ |
2 | #define __LBS_CFG80211_H__ | 2 | #define __LBS_CFG80211_H__ |
3 | 3 | ||
4 | #include "dev.h" | 4 | struct device; |
5 | struct lbs_private; | ||
6 | struct regulatory_request; | ||
7 | struct wiphy; | ||
5 | 8 | ||
6 | struct wireless_dev *lbs_cfg_alloc(struct device *dev); | 9 | struct wireless_dev *lbs_cfg_alloc(struct device *dev); |
7 | int lbs_cfg_register(struct lbs_private *priv); | 10 | int lbs_cfg_register(struct lbs_private *priv); |
8 | void lbs_cfg_free(struct lbs_private *priv); | 11 | void lbs_cfg_free(struct lbs_private *priv); |
9 | 12 | ||
10 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, | 13 | int lbs_reg_notifier(struct wiphy *wiphy, |
11 | u8 ssid_len); | 14 | struct regulatory_request *request); |
12 | int lbs_scan_networks(struct lbs_private *priv, int full_scan); | ||
13 | void lbs_cfg_scan_worker(struct work_struct *work); | ||
14 | 15 | ||
16 | /* All of those are TODOs: */ | ||
17 | #define lbs_cmd_802_11_rssi(priv, cmdptr) (0) | ||
18 | #define lbs_ret_802_11_rssi(priv, resp) (0) | ||
19 | #define lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action) (0) | ||
20 | #define lbs_ret_802_11_bcn_ctrl(priv, resp) (0) | ||
21 | |||
22 | void lbs_send_disconnect_notification(struct lbs_private *priv); | ||
23 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); | ||
24 | |||
25 | void lbs_scan_deinit(struct lbs_private *priv); | ||
15 | 26 | ||
16 | #endif | 27 | #endif |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 0fa6b0e59ea5..6c8a9d952a01 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -7,13 +7,8 @@ | |||
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | 9 | ||
10 | #include "host.h" | ||
11 | #include "decl.h" | 10 | #include "decl.h" |
12 | #include "defs.h" | 11 | #include "cfg.h" |
13 | #include "dev.h" | ||
14 | #include "assoc.h" | ||
15 | #include "wext.h" | ||
16 | #include "scan.h" | ||
17 | #include "cmd.h" | 12 | #include "cmd.h" |
18 | 13 | ||
19 | 14 | ||
@@ -177,11 +172,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) | |||
177 | if (priv->mesh_dev) | 172 | if (priv->mesh_dev) |
178 | memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); | 173 | memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); |
179 | 174 | ||
180 | if (lbs_set_regiontable(priv, priv->regioncode, 0)) { | ||
181 | ret = -1; | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | out: | 175 | out: |
186 | lbs_deb_leave(LBS_DEB_CMD); | 176 | lbs_deb_leave(LBS_DEB_CMD); |
187 | return ret; | 177 | return ret; |
@@ -909,6 +899,66 @@ void lbs_set_mac_control(struct lbs_private *priv) | |||
909 | } | 899 | } |
910 | 900 | ||
911 | /** | 901 | /** |
902 | * @brief This function implements command CMD_802_11D_DOMAIN_INFO | ||
903 | * @param priv pointer to struct lbs_private | ||
904 | * @param cmd pointer to cmd buffer | ||
905 | * @param cmdno cmd ID | ||
906 | * @param cmdOption cmd action | ||
907 | * @return 0 | ||
908 | */ | ||
909 | int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, | ||
910 | struct cmd_ds_command *cmd, | ||
911 | u16 cmdoption) | ||
912 | { | ||
913 | struct cmd_ds_802_11d_domain_info *pdomaininfo = | ||
914 | &cmd->params.domaininfo; | ||
915 | struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; | ||
916 | u8 nr_triplet = priv->domain_reg.no_triplet; | ||
917 | |||
918 | lbs_deb_enter(LBS_DEB_11D); | ||
919 | |||
920 | lbs_deb_11d("nr_triplet=%x\n", nr_triplet); | ||
921 | |||
922 | pdomaininfo->action = cpu_to_le16(cmdoption); | ||
923 | if (cmdoption == CMD_ACT_GET) { | ||
924 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + | ||
925 | sizeof(struct cmd_header)); | ||
926 | lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, | ||
927 | le16_to_cpu(cmd->size)); | ||
928 | goto done; | ||
929 | } | ||
930 | |||
931 | domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); | ||
932 | memcpy(domain->countrycode, priv->domain_reg.country_code, | ||
933 | sizeof(domain->countrycode)); | ||
934 | |||
935 | domain->header.len = cpu_to_le16(nr_triplet | ||
936 | * sizeof(struct ieee80211_country_ie_triplet) | ||
937 | + sizeof(domain->countrycode)); | ||
938 | |||
939 | if (nr_triplet) { | ||
940 | memcpy(domain->triplet, priv->domain_reg.triplet, | ||
941 | nr_triplet * | ||
942 | sizeof(struct ieee80211_country_ie_triplet)); | ||
943 | |||
944 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + | ||
945 | le16_to_cpu(domain->header.len) + | ||
946 | sizeof(struct mrvl_ie_header) + | ||
947 | sizeof(struct cmd_header)); | ||
948 | } else { | ||
949 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + | ||
950 | sizeof(struct cmd_header)); | ||
951 | } | ||
952 | |||
953 | lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, | ||
954 | le16_to_cpu(cmd->size)); | ||
955 | |||
956 | done: | ||
957 | lbs_deb_enter(LBS_DEB_11D); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | /** | ||
912 | * @brief This function prepare the command before send to firmware. | 962 | * @brief This function prepare the command before send to firmware. |
913 | * | 963 | * |
914 | * @param priv A pointer to struct lbs_private structure | 964 | * @param priv A pointer to struct lbs_private structure |
@@ -1006,6 +1056,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, | |||
1006 | ret = 0; | 1056 | ret = 0; |
1007 | goto done; | 1057 | goto done; |
1008 | 1058 | ||
1059 | case CMD_802_11D_DOMAIN_INFO: | ||
1060 | cmdptr->command = cpu_to_le16(cmd_no); | ||
1061 | ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action); | ||
1062 | break; | ||
1063 | |||
1009 | case CMD_802_11_TPC_CFG: | 1064 | case CMD_802_11_TPC_CFG: |
1010 | cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); | 1065 | cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); |
1011 | cmdptr->size = | 1066 | cmdptr->size = |
@@ -1325,6 +1380,15 @@ int lbs_execute_next_command(struct lbs_private *priv) | |||
1325 | * check if in power save mode, if yes, put the device back | 1380 | * check if in power save mode, if yes, put the device back |
1326 | * to PS mode | 1381 | * to PS mode |
1327 | */ | 1382 | */ |
1383 | #ifdef TODO | ||
1384 | /* | ||
1385 | * This was the old code for libertas+wext. Someone that | ||
1386 | * understands this beast should re-code it in a sane way. | ||
1387 | * | ||
1388 | * I actually don't understand why this is related to WPA | ||
1389 | * and to connection status, shouldn't powering should be | ||
1390 | * independ of such things? | ||
1391 | */ | ||
1328 | if ((priv->psmode != LBS802_11POWERMODECAM) && | 1392 | if ((priv->psmode != LBS802_11POWERMODECAM) && |
1329 | (priv->psstate == PS_STATE_FULL_POWER) && | 1393 | (priv->psstate == PS_STATE_FULL_POWER) && |
1330 | ((priv->connect_status == LBS_CONNECTED) || | 1394 | ((priv->connect_status == LBS_CONNECTED) || |
@@ -1346,6 +1410,7 @@ int lbs_execute_next_command(struct lbs_private *priv) | |||
1346 | lbs_ps_sleep(priv, 0); | 1410 | lbs_ps_sleep(priv, 0); |
1347 | } | 1411 | } |
1348 | } | 1412 | } |
1413 | #endif | ||
1349 | } | 1414 | } |
1350 | 1415 | ||
1351 | ret = 0; | 1416 | ret = 0; |
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index d6c306353640..a0d9482ef5e2 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -5,18 +5,10 @@ | |||
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/delay.h> | 6 | #include <linux/delay.h> |
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/if_arp.h> | ||
9 | #include <linux/netdevice.h> | ||
10 | #include <asm/unaligned.h> | 8 | #include <asm/unaligned.h> |
11 | #include <net/iw_handler.h> | 9 | #include <net/cfg80211.h> |
12 | 10 | ||
13 | #include "host.h" | 11 | #include "cfg.h" |
14 | #include "decl.h" | ||
15 | #include "cmd.h" | ||
16 | #include "defs.h" | ||
17 | #include "dev.h" | ||
18 | #include "assoc.h" | ||
19 | #include "wext.h" | ||
20 | #include "cmd.h" | 12 | #include "cmd.h" |
21 | 13 | ||
22 | /** | 14 | /** |
@@ -39,7 +31,9 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) | |||
39 | * It causes problem in the Supplicant | 31 | * It causes problem in the Supplicant |
40 | */ | 32 | */ |
41 | msleep_interruptible(1000); | 33 | msleep_interruptible(1000); |
42 | lbs_send_disconnect_notification(priv); | 34 | |
35 | if (priv->wdev->iftype == NL80211_IFTYPE_STATION) | ||
36 | lbs_send_disconnect_notification(priv); | ||
43 | 37 | ||
44 | /* report disconnect to upper layer */ | 38 | /* report disconnect to upper layer */ |
45 | netif_stop_queue(priv->dev); | 39 | netif_stop_queue(priv->dev); |
@@ -50,23 +44,8 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) | |||
50 | priv->currenttxskb = NULL; | 44 | priv->currenttxskb = NULL; |
51 | priv->tx_pending_len = 0; | 45 | priv->tx_pending_len = 0; |
52 | 46 | ||
53 | /* reset SNR/NF/RSSI values */ | ||
54 | memset(priv->SNR, 0x00, sizeof(priv->SNR)); | ||
55 | memset(priv->NF, 0x00, sizeof(priv->NF)); | ||
56 | memset(priv->RSSI, 0x00, sizeof(priv->RSSI)); | ||
57 | memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); | ||
58 | memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); | ||
59 | priv->nextSNRNF = 0; | ||
60 | priv->numSNRNF = 0; | ||
61 | priv->connect_status = LBS_DISCONNECTED; | 47 | priv->connect_status = LBS_DISCONNECTED; |
62 | 48 | ||
63 | /* Clear out associated SSID and BSSID since connection is | ||
64 | * no longer valid. | ||
65 | */ | ||
66 | memset(&priv->curbssparams.bssid, 0, ETH_ALEN); | ||
67 | memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN); | ||
68 | priv->curbssparams.ssid_len = 0; | ||
69 | |||
70 | if (priv->psstate != PS_STATE_FULL_POWER) { | 49 | if (priv->psstate != PS_STATE_FULL_POWER) { |
71 | /* make firmware to exit PS mode */ | 50 | /* make firmware to exit PS mode */ |
72 | lbs_deb_cmd("disconnected, so exit PS mode\n"); | 51 | lbs_deb_cmd("disconnected, so exit PS mode\n"); |
@@ -118,6 +97,52 @@ static int lbs_ret_reg_access(struct lbs_private *priv, | |||
118 | return ret; | 97 | return ret; |
119 | } | 98 | } |
120 | 99 | ||
100 | /** | ||
101 | * @brief This function parses countryinfo from AP and download country info to FW | ||
102 | * @param priv pointer to struct lbs_private | ||
103 | * @param resp pointer to command response buffer | ||
104 | * @return 0; -1 | ||
105 | */ | ||
106 | static int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) | ||
107 | { | ||
108 | struct cmd_ds_802_11d_domain_info *domaininfo = | ||
109 | &resp->params.domaininforesp; | ||
110 | struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; | ||
111 | u16 action = le16_to_cpu(domaininfo->action); | ||
112 | s16 ret = 0; | ||
113 | u8 nr_triplet = 0; | ||
114 | |||
115 | lbs_deb_enter(LBS_DEB_11D); | ||
116 | |||
117 | lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, | ||
118 | (int)le16_to_cpu(resp->size)); | ||
119 | |||
120 | nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / | ||
121 | sizeof(struct ieee80211_country_ie_triplet); | ||
122 | |||
123 | lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet); | ||
124 | |||
125 | if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) { | ||
126 | lbs_deb_11d("invalid number of triplets returned!!\n"); | ||
127 | return -1; | ||
128 | } | ||
129 | |||
130 | switch (action) { | ||
131 | case CMD_ACT_SET: /*Proc set action */ | ||
132 | break; | ||
133 | |||
134 | case CMD_ACT_GET: | ||
135 | break; | ||
136 | default: | ||
137 | lbs_deb_11d("invalid action:%d\n", domaininfo->action); | ||
138 | ret = -1; | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
121 | static inline int handle_cmd_response(struct lbs_private *priv, | 146 | static inline int handle_cmd_response(struct lbs_private *priv, |
122 | struct cmd_header *cmd_response) | 147 | struct cmd_header *cmd_response) |
123 | { | 148 | { |
@@ -151,6 +176,10 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
151 | ret = lbs_ret_802_11_rssi(priv, resp); | 176 | ret = lbs_ret_802_11_rssi(priv, resp); |
152 | break; | 177 | break; |
153 | 178 | ||
179 | case CMD_RET(CMD_802_11D_DOMAIN_INFO): | ||
180 | ret = lbs_ret_802_11d_domain_info(resp); | ||
181 | break; | ||
182 | |||
154 | case CMD_RET(CMD_802_11_TPC_CFG): | 183 | case CMD_RET(CMD_802_11_TPC_CFG): |
155 | spin_lock_irqsave(&priv->driver_lock, flags); | 184 | spin_lock_irqsave(&priv->driver_lock, flags); |
156 | memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, | 185 | memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, |
@@ -262,7 +291,7 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) | |||
262 | * ad-hoc mode. It takes place in | 291 | * ad-hoc mode. It takes place in |
263 | * lbs_execute_next_command(). | 292 | * lbs_execute_next_command(). |
264 | */ | 293 | */ |
265 | if (priv->mode == IW_MODE_ADHOC && | 294 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR && |
266 | action == CMD_SUBCMD_ENTER_PS) | 295 | action == CMD_SUBCMD_ENTER_PS) |
267 | priv->psmode = LBS802_11POWERMODECAM; | 296 | priv->psmode = LBS802_11POWERMODECAM; |
268 | } else if (action == CMD_SUBCMD_ENTER_PS) { | 297 | } else if (action == CMD_SUBCMD_ENTER_PS) { |
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index de2caac11dd6..17367463c855 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c | |||
@@ -1,18 +1,13 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/dcache.h> | 1 | #include <linux/dcache.h> |
3 | #include <linux/debugfs.h> | 2 | #include <linux/debugfs.h> |
4 | #include <linux/delay.h> | 3 | #include <linux/delay.h> |
5 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
6 | #include <linux/string.h> | 5 | #include <linux/string.h> |
7 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
8 | #include <net/iw_handler.h> | ||
9 | #include <net/lib80211.h> | ||
10 | 7 | ||
11 | #include "dev.h" | ||
12 | #include "decl.h" | 8 | #include "decl.h" |
13 | #include "host.h" | ||
14 | #include "debugfs.h" | ||
15 | #include "cmd.h" | 9 | #include "cmd.h" |
10 | #include "debugfs.h" | ||
16 | 11 | ||
17 | static struct dentry *lbs_dir; | 12 | static struct dentry *lbs_dir; |
18 | static char *szStates[] = { | 13 | static char *szStates[] = { |
@@ -60,51 +55,6 @@ static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, | |||
60 | return res; | 55 | return res; |
61 | } | 56 | } |
62 | 57 | ||
63 | |||
64 | static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, | ||
65 | size_t count, loff_t *ppos) | ||
66 | { | ||
67 | struct lbs_private *priv = file->private_data; | ||
68 | size_t pos = 0; | ||
69 | int numscansdone = 0, res; | ||
70 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
71 | char *buf = (char *)addr; | ||
72 | DECLARE_SSID_BUF(ssid); | ||
73 | struct bss_descriptor * iter_bss; | ||
74 | if (!buf) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | pos += snprintf(buf+pos, len-pos, | ||
78 | "# | ch | rssi | bssid | cap | Qual | SSID\n"); | ||
79 | |||
80 | mutex_lock(&priv->lock); | ||
81 | list_for_each_entry (iter_bss, &priv->network_list, list) { | ||
82 | u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); | ||
83 | u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); | ||
84 | u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); | ||
85 | |||
86 | pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", | ||
87 | numscansdone, iter_bss->channel, iter_bss->rssi, | ||
88 | iter_bss->bssid); | ||
89 | pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); | ||
90 | pos += snprintf(buf+pos, len-pos, "%c%c%c |", | ||
91 | ibss ? 'A' : 'I', privacy ? 'P' : ' ', | ||
92 | spectrum_mgmt ? 'S' : ' '); | ||
93 | pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); | ||
94 | pos += snprintf(buf+pos, len-pos, " %s\n", | ||
95 | print_ssid(ssid, iter_bss->ssid, | ||
96 | iter_bss->ssid_len)); | ||
97 | |||
98 | numscansdone++; | ||
99 | } | ||
100 | mutex_unlock(&priv->lock); | ||
101 | |||
102 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
103 | |||
104 | free_page(addr); | ||
105 | return res; | ||
106 | } | ||
107 | |||
108 | static ssize_t lbs_sleepparams_write(struct file *file, | 58 | static ssize_t lbs_sleepparams_write(struct file *file, |
109 | const char __user *user_buf, size_t count, | 59 | const char __user *user_buf, size_t count, |
110 | loff_t *ppos) | 60 | loff_t *ppos) |
@@ -723,8 +673,6 @@ struct lbs_debugfs_files { | |||
723 | 673 | ||
724 | static const struct lbs_debugfs_files debugfs_files[] = { | 674 | static const struct lbs_debugfs_files debugfs_files[] = { |
725 | { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, | 675 | { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, |
726 | { "getscantable", 0444, FOPS(lbs_getscantable, | ||
727 | write_file_dummy), }, | ||
728 | { "sleepparams", 0644, FOPS(lbs_sleepparams_read, | 676 | { "sleepparams", 0644, FOPS(lbs_sleepparams_read, |
729 | lbs_sleepparams_write), }, | 677 | lbs_sleepparams_write), }, |
730 | }; | 678 | }; |
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 61db8bc62b3c..ba5438a7ba17 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | /** | 2 | /** |
2 | * This file contains declaration referring to | 3 | * This file contains declaration referring to |
3 | * functions defined in other source files | 4 | * functions defined in other source files |
@@ -12,6 +13,7 @@ | |||
12 | struct lbs_private; | 13 | struct lbs_private; |
13 | struct sk_buff; | 14 | struct sk_buff; |
14 | struct net_device; | 15 | struct net_device; |
16 | struct cmd_ds_command; | ||
15 | 17 | ||
16 | 18 | ||
17 | /* ethtool.c */ | 19 | /* ethtool.c */ |
@@ -34,6 +36,8 @@ int lbs_start_card(struct lbs_private *priv); | |||
34 | void lbs_stop_card(struct lbs_private *priv); | 36 | void lbs_stop_card(struct lbs_private *priv); |
35 | void lbs_host_to_card_done(struct lbs_private *priv); | 37 | void lbs_host_to_card_done(struct lbs_private *priv); |
36 | 38 | ||
39 | int lbs_rtap_supported(struct lbs_private *priv); | ||
40 | |||
37 | int lbs_set_mac_address(struct net_device *dev, void *addr); | 41 | int lbs_set_mac_address(struct net_device *dev, void *addr); |
38 | void lbs_set_multicast_list(struct net_device *dev); | 42 | void lbs_set_multicast_list(struct net_device *dev); |
39 | 43 | ||
@@ -49,5 +53,9 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv); | |||
49 | u32 lbs_fw_index_to_data_rate(u8 index); | 53 | u32 lbs_fw_index_to_data_rate(u8 index); |
50 | u8 lbs_data_rate_to_fw_index(u32 rate); | 54 | u8 lbs_data_rate_to_fw_index(u32 rate); |
51 | 55 | ||
56 | int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, | ||
57 | struct cmd_ds_command *cmd, u16 cmdoption); | ||
58 | |||
59 | int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp); | ||
52 | 60 | ||
53 | #endif | 61 | #endif |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 71c5ad46ebf6..4536d9c0ad87 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -7,8 +7,8 @@ | |||
7 | #define _LBS_DEV_H_ | 7 | #define _LBS_DEV_H_ |
8 | 8 | ||
9 | #include "mesh.h" | 9 | #include "mesh.h" |
10 | #include "scan.h" | 10 | #include "defs.h" |
11 | #include "assoc.h" | 11 | #include "host.h" |
12 | 12 | ||
13 | #include <linux/kfifo.h> | 13 | #include <linux/kfifo.h> |
14 | 14 | ||
@@ -29,7 +29,6 @@ struct lbs_private { | |||
29 | /* Basic networking */ | 29 | /* Basic networking */ |
30 | struct net_device *dev; | 30 | struct net_device *dev; |
31 | u32 connect_status; | 31 | u32 connect_status; |
32 | int infra_open; | ||
33 | struct work_struct mcast_work; | 32 | struct work_struct mcast_work; |
34 | u32 nr_of_multicastmacaddr; | 33 | u32 nr_of_multicastmacaddr; |
35 | u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; | 34 | u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; |
@@ -37,6 +36,9 @@ struct lbs_private { | |||
37 | /* CFG80211 */ | 36 | /* CFG80211 */ |
38 | struct wireless_dev *wdev; | 37 | struct wireless_dev *wdev; |
39 | bool wiphy_registered; | 38 | bool wiphy_registered; |
39 | struct cfg80211_scan_request *scan_req; | ||
40 | u8 assoc_bss[ETH_ALEN]; | ||
41 | u8 disassoc_reason; | ||
40 | 42 | ||
41 | /* Mesh */ | 43 | /* Mesh */ |
42 | struct net_device *mesh_dev; /* Virtual device */ | 44 | struct net_device *mesh_dev; /* Virtual device */ |
@@ -49,10 +51,6 @@ struct lbs_private { | |||
49 | u8 mesh_ssid_len; | 51 | u8 mesh_ssid_len; |
50 | #endif | 52 | #endif |
51 | 53 | ||
52 | /* Monitor mode */ | ||
53 | struct net_device *rtap_net_dev; | ||
54 | u32 monitormode; | ||
55 | |||
56 | /* Debugfs */ | 54 | /* Debugfs */ |
57 | struct dentry *debugfs_dir; | 55 | struct dentry *debugfs_dir; |
58 | struct dentry *debugfs_debug; | 56 | struct dentry *debugfs_debug; |
@@ -62,6 +60,9 @@ struct lbs_private { | |||
62 | struct dentry *regs_dir; | 60 | struct dentry *regs_dir; |
63 | struct dentry *debugfs_regs_files[6]; | 61 | struct dentry *debugfs_regs_files[6]; |
64 | 62 | ||
63 | /** 11D and domain regulatory data */ | ||
64 | struct lbs_802_11d_domain_reg domain_reg; | ||
65 | |||
65 | /* Hardware debugging */ | 66 | /* Hardware debugging */ |
66 | u32 mac_offset; | 67 | u32 mac_offset; |
67 | u32 bbp_offset; | 68 | u32 bbp_offset; |
@@ -133,14 +134,10 @@ struct lbs_private { | |||
133 | struct workqueue_struct *work_thread; | 134 | struct workqueue_struct *work_thread; |
134 | 135 | ||
135 | /** Encryption stuff */ | 136 | /** Encryption stuff */ |
136 | struct lbs_802_11_security secinfo; | ||
137 | struct enc_key wpa_mcast_key; | ||
138 | struct enc_key wpa_unicast_key; | ||
139 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
140 | u8 wpa_ie_len; | ||
141 | u16 wep_tx_keyidx; | ||
142 | struct enc_key wep_keys[4]; | ||
143 | u8 authtype_auto; | 137 | u8 authtype_auto; |
138 | u8 wep_tx_key; | ||
139 | u8 wep_key[4][WLAN_KEY_LEN_WEP104]; | ||
140 | u8 wep_key_len[4]; | ||
144 | 141 | ||
145 | /* Wake On LAN */ | 142 | /* Wake On LAN */ |
146 | uint32_t wol_criteria; | 143 | uint32_t wol_criteria; |
@@ -161,6 +158,7 @@ struct lbs_private { | |||
161 | /* NIC/link operation characteristics */ | 158 | /* NIC/link operation characteristics */ |
162 | u16 mac_control; | 159 | u16 mac_control; |
163 | u8 radio_on; | 160 | u8 radio_on; |
161 | u8 cur_rate; | ||
164 | u8 channel; | 162 | u8 channel; |
165 | s16 txpower_cur; | 163 | s16 txpower_cur; |
166 | s16 txpower_min; | 164 | s16 txpower_min; |
@@ -169,42 +167,6 @@ struct lbs_private { | |||
169 | /** Scanning */ | 167 | /** Scanning */ |
170 | struct delayed_work scan_work; | 168 | struct delayed_work scan_work; |
171 | int scan_channel; | 169 | int scan_channel; |
172 | /* remember which channel was scanned last, != 0 if currently scanning */ | ||
173 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1]; | ||
174 | u8 scan_ssid_len; | ||
175 | |||
176 | /* Associating */ | ||
177 | struct delayed_work assoc_work; | ||
178 | struct current_bss_params curbssparams; | ||
179 | u8 mode; | ||
180 | struct list_head network_list; | ||
181 | struct list_head network_free_list; | ||
182 | struct bss_descriptor *networks; | ||
183 | struct assoc_request * pending_assoc_req; | ||
184 | struct assoc_request * in_progress_assoc_req; | ||
185 | uint16_t enablehwauto; | ||
186 | |||
187 | /* ADHOC */ | ||
188 | u16 beacon_period; | ||
189 | u8 beacon_enable; | ||
190 | u8 adhoccreate; | ||
191 | |||
192 | /* WEXT */ | ||
193 | char name[DEV_NAME_LEN]; | ||
194 | u8 nodename[16]; | ||
195 | struct iw_statistics wstats; | ||
196 | u8 cur_rate; | ||
197 | #define MAX_REGION_CHANNEL_NUM 2 | ||
198 | struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; | ||
199 | |||
200 | /** Requested Signal Strength*/ | ||
201 | u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
202 | u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
203 | u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
204 | u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; | ||
205 | u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; | ||
206 | u16 nextSNRNF; | ||
207 | u16 numSNRNF; | ||
208 | }; | 170 | }; |
209 | 171 | ||
210 | extern struct cmd_confirm_sleep confirm_sleep; | 172 | extern struct cmd_confirm_sleep confirm_sleep; |
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 0cf31bbf6567..50193aac679e 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c | |||
@@ -2,13 +2,8 @@ | |||
2 | #include <linux/ethtool.h> | 2 | #include <linux/ethtool.h> |
3 | #include <linux/delay.h> | 3 | #include <linux/delay.h> |
4 | 4 | ||
5 | #include "host.h" | ||
6 | #include "decl.h" | 5 | #include "decl.h" |
7 | #include "defs.h" | ||
8 | #include "dev.h" | ||
9 | #include "wext.h" | ||
10 | #include "cmd.h" | 6 | #include "cmd.h" |
11 | #include "mesh.h" | ||
12 | 7 | ||
13 | 8 | ||
14 | static void lbs_ethtool_get_drvinfo(struct net_device *dev, | 9 | static void lbs_ethtool_get_drvinfo(struct net_device *dev, |
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 3bd5d3b6037a..db8e209878c1 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -389,6 +389,30 @@ struct lbs_offset_value { | |||
389 | u32 value; | 389 | u32 value; |
390 | } __packed; | 390 | } __packed; |
391 | 391 | ||
392 | #define MRVDRV_MAX_TRIPLET_802_11D 83 | ||
393 | |||
394 | #define COUNTRY_CODE_LEN 3 | ||
395 | |||
396 | struct mrvl_ie_domain_param_set { | ||
397 | struct mrvl_ie_header header; | ||
398 | |||
399 | u8 countrycode[COUNTRY_CODE_LEN]; | ||
400 | struct ieee80211_country_ie_triplet triplet[1]; | ||
401 | } __attribute__ ((packed)); | ||
402 | |||
403 | struct cmd_ds_802_11d_domain_info { | ||
404 | __le16 action; | ||
405 | struct mrvl_ie_domain_param_set domain; | ||
406 | } __attribute__ ((packed)); | ||
407 | |||
408 | struct lbs_802_11d_domain_reg { | ||
409 | /** Country code*/ | ||
410 | u8 country_code[COUNTRY_CODE_LEN]; | ||
411 | /** No. of triplet*/ | ||
412 | u8 no_triplet; | ||
413 | struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D]; | ||
414 | } __attribute__ ((packed)); | ||
415 | |||
392 | /* | 416 | /* |
393 | * Define data structure for CMD_GET_HW_SPEC | 417 | * Define data structure for CMD_GET_HW_SPEC |
394 | * This structure defines the response for the GET_HW_SPEC command | 418 | * This structure defines the response for the GET_HW_SPEC command |
@@ -949,6 +973,9 @@ struct cmd_ds_command { | |||
949 | struct cmd_ds_bbp_reg_access bbpreg; | 973 | struct cmd_ds_bbp_reg_access bbpreg; |
950 | struct cmd_ds_rf_reg_access rfreg; | 974 | struct cmd_ds_rf_reg_access rfreg; |
951 | 975 | ||
976 | struct cmd_ds_802_11d_domain_info domaininfo; | ||
977 | struct cmd_ds_802_11d_domain_info domaininforesp; | ||
978 | |||
952 | struct cmd_ds_802_11_tpc_cfg tpccfg; | 979 | struct cmd_ds_802_11_tpc_cfg tpccfg; |
953 | struct cmd_ds_802_11_afc afc; | 980 | struct cmd_ds_802_11_afc afc; |
954 | struct cmd_ds_802_11_led_ctrl ledgpio; | 981 | struct cmd_ds_802_11_led_ctrl ledgpio; |
@@ -958,5 +985,4 @@ struct cmd_ds_command { | |||
958 | struct cmd_ds_802_11_beacon_control bcn_ctrl; | 985 | struct cmd_ds_802_11_beacon_control bcn_ctrl; |
959 | } params; | 986 | } params; |
960 | } __packed; | 987 | } __packed; |
961 | |||
962 | #endif | 988 | #endif |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index abfecc4814b4..b519fc70f04f 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -11,20 +11,14 @@ | |||
11 | #include <linux/if_arp.h> | 11 | #include <linux/if_arp.h> |
12 | #include <linux/kthread.h> | 12 | #include <linux/kthread.h> |
13 | #include <linux/kfifo.h> | 13 | #include <linux/kfifo.h> |
14 | #include <linux/stddef.h> | ||
15 | #include <linux/ieee80211.h> | ||
16 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
17 | #include <net/iw_handler.h> | ||
18 | #include <net/cfg80211.h> | 15 | #include <net/cfg80211.h> |
19 | 16 | ||
20 | #include "host.h" | 17 | #include "host.h" |
21 | #include "decl.h" | 18 | #include "decl.h" |
22 | #include "dev.h" | 19 | #include "dev.h" |
23 | #include "wext.h" | ||
24 | #include "cfg.h" | 20 | #include "cfg.h" |
25 | #include "debugfs.h" | 21 | #include "debugfs.h" |
26 | #include "scan.h" | ||
27 | #include "assoc.h" | ||
28 | #include "cmd.h" | 22 | #include "cmd.h" |
29 | 23 | ||
30 | #define DRIVER_RELEASE_VERSION "323.p0" | 24 | #define DRIVER_RELEASE_VERSION "323.p0" |
@@ -96,72 +90,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate) | |||
96 | } | 90 | } |
97 | 91 | ||
98 | 92 | ||
99 | static int lbs_add_rtap(struct lbs_private *priv); | ||
100 | static void lbs_remove_rtap(struct lbs_private *priv); | ||
101 | |||
102 | |||
103 | /** | ||
104 | * Get function for sysfs attribute rtap | ||
105 | */ | ||
106 | static ssize_t lbs_rtap_get(struct device *dev, | ||
107 | struct device_attribute *attr, char * buf) | ||
108 | { | ||
109 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
110 | return snprintf(buf, 5, "0x%X\n", priv->monitormode); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * Set function for sysfs attribute rtap | ||
115 | */ | ||
116 | static ssize_t lbs_rtap_set(struct device *dev, | ||
117 | struct device_attribute *attr, const char * buf, size_t count) | ||
118 | { | ||
119 | int monitor_mode; | ||
120 | struct lbs_private *priv = to_net_dev(dev)->ml_priv; | ||
121 | |||
122 | sscanf(buf, "%x", &monitor_mode); | ||
123 | if (monitor_mode) { | ||
124 | if (priv->monitormode == monitor_mode) | ||
125 | return strlen(buf); | ||
126 | if (!priv->monitormode) { | ||
127 | if (priv->infra_open || lbs_mesh_open(priv)) | ||
128 | return -EBUSY; | ||
129 | if (priv->mode == IW_MODE_INFRA) | ||
130 | lbs_cmd_80211_deauthenticate(priv, | ||
131 | priv->curbssparams.bssid, | ||
132 | WLAN_REASON_DEAUTH_LEAVING); | ||
133 | else if (priv->mode == IW_MODE_ADHOC) | ||
134 | lbs_adhoc_stop(priv); | ||
135 | lbs_add_rtap(priv); | ||
136 | } | ||
137 | priv->monitormode = monitor_mode; | ||
138 | } else { | ||
139 | if (!priv->monitormode) | ||
140 | return strlen(buf); | ||
141 | priv->monitormode = 0; | ||
142 | lbs_remove_rtap(priv); | ||
143 | |||
144 | if (priv->currenttxskb) { | ||
145 | dev_kfree_skb_any(priv->currenttxskb); | ||
146 | priv->currenttxskb = NULL; | ||
147 | } | ||
148 | |||
149 | /* Wake queues, command thread, etc. */ | ||
150 | lbs_host_to_card_done(priv); | ||
151 | } | ||
152 | |||
153 | lbs_prepare_and_send_command(priv, | ||
154 | CMD_802_11_MONITOR_MODE, CMD_ACT_SET, | ||
155 | CMD_OPTION_WAITFORRSP, 0, &priv->monitormode); | ||
156 | return strlen(buf); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * lbs_rtap attribute to be exported per ethX interface | ||
161 | * through sysfs (/sys/class/net/ethX/lbs_rtap) | ||
162 | */ | ||
163 | static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); | ||
164 | |||
165 | /** | 93 | /** |
166 | * @brief This function opens the ethX interface | 94 | * @brief This function opens the ethX interface |
167 | * | 95 | * |
@@ -177,13 +105,6 @@ static int lbs_dev_open(struct net_device *dev) | |||
177 | 105 | ||
178 | spin_lock_irq(&priv->driver_lock); | 106 | spin_lock_irq(&priv->driver_lock); |
179 | 107 | ||
180 | if (priv->monitormode) { | ||
181 | ret = -EBUSY; | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | priv->infra_open = 1; | ||
186 | |||
187 | if (priv->connect_status == LBS_CONNECTED) | 108 | if (priv->connect_status == LBS_CONNECTED) |
188 | netif_carrier_on(dev); | 109 | netif_carrier_on(dev); |
189 | else | 110 | else |
@@ -191,7 +112,6 @@ static int lbs_dev_open(struct net_device *dev) | |||
191 | 112 | ||
192 | if (!priv->tx_pending_len) | 113 | if (!priv->tx_pending_len) |
193 | netif_wake_queue(dev); | 114 | netif_wake_queue(dev); |
194 | out: | ||
195 | 115 | ||
196 | spin_unlock_irq(&priv->driver_lock); | 116 | spin_unlock_irq(&priv->driver_lock); |
197 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); | 117 | lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); |
@@ -211,7 +131,6 @@ static int lbs_eth_stop(struct net_device *dev) | |||
211 | lbs_deb_enter(LBS_DEB_NET); | 131 | lbs_deb_enter(LBS_DEB_NET); |
212 | 132 | ||
213 | spin_lock_irq(&priv->driver_lock); | 133 | spin_lock_irq(&priv->driver_lock); |
214 | priv->infra_open = 0; | ||
215 | netif_stop_queue(dev); | 134 | netif_stop_queue(dev); |
216 | spin_unlock_irq(&priv->driver_lock); | 135 | spin_unlock_irq(&priv->driver_lock); |
217 | 136 | ||
@@ -733,6 +652,9 @@ static int lbs_setup_firmware(struct lbs_private *priv) | |||
733 | priv->txpower_max = maxlevel; | 652 | priv->txpower_max = maxlevel; |
734 | } | 653 | } |
735 | 654 | ||
655 | /* Send cmd to FW to enable 11D function */ | ||
656 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); | ||
657 | |||
736 | lbs_set_mac_control(priv); | 658 | lbs_set_mac_control(priv); |
737 | done: | 659 | done: |
738 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); | 660 | lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); |
@@ -822,37 +744,16 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv) | |||
822 | 744 | ||
823 | static int lbs_init_adapter(struct lbs_private *priv) | 745 | static int lbs_init_adapter(struct lbs_private *priv) |
824 | { | 746 | { |
825 | size_t bufsize; | 747 | int ret; |
826 | int i, ret = 0; | ||
827 | 748 | ||
828 | lbs_deb_enter(LBS_DEB_MAIN); | 749 | lbs_deb_enter(LBS_DEB_MAIN); |
829 | 750 | ||
830 | /* Allocate buffer to store the BSSID list */ | ||
831 | bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); | ||
832 | priv->networks = kzalloc(bufsize, GFP_KERNEL); | ||
833 | if (!priv->networks) { | ||
834 | lbs_pr_err("Out of memory allocating beacons\n"); | ||
835 | ret = -1; | ||
836 | goto out; | ||
837 | } | ||
838 | |||
839 | /* Initialize scan result lists */ | ||
840 | INIT_LIST_HEAD(&priv->network_free_list); | ||
841 | INIT_LIST_HEAD(&priv->network_list); | ||
842 | for (i = 0; i < MAX_NETWORK_COUNT; i++) { | ||
843 | list_add_tail(&priv->networks[i].list, | ||
844 | &priv->network_free_list); | ||
845 | } | ||
846 | |||
847 | memset(priv->current_addr, 0xff, ETH_ALEN); | 751 | memset(priv->current_addr, 0xff, ETH_ALEN); |
848 | 752 | ||
849 | priv->connect_status = LBS_DISCONNECTED; | 753 | priv->connect_status = LBS_DISCONNECTED; |
850 | priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
851 | priv->mode = IW_MODE_INFRA; | ||
852 | priv->channel = DEFAULT_AD_HOC_CHANNEL; | 754 | priv->channel = DEFAULT_AD_HOC_CHANNEL; |
853 | priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; | 755 | priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; |
854 | priv->radio_on = 1; | 756 | priv->radio_on = 1; |
855 | priv->enablehwauto = 1; | ||
856 | priv->psmode = LBS802_11POWERMODECAM; | 757 | priv->psmode = LBS802_11POWERMODECAM; |
857 | priv->psstate = PS_STATE_FULL_POWER; | 758 | priv->psstate = PS_STATE_FULL_POWER; |
858 | priv->is_deep_sleep = 0; | 759 | priv->is_deep_sleep = 0; |
@@ -907,8 +808,6 @@ static void lbs_free_adapter(struct lbs_private *priv) | |||
907 | kfifo_free(&priv->event_fifo); | 808 | kfifo_free(&priv->event_fifo); |
908 | del_timer(&priv->command_timer); | 809 | del_timer(&priv->command_timer); |
909 | del_timer(&priv->auto_deepsleep_timer); | 810 | del_timer(&priv->auto_deepsleep_timer); |
910 | kfree(priv->networks); | ||
911 | priv->networks = NULL; | ||
912 | 811 | ||
913 | lbs_deb_leave(LBS_DEB_MAIN); | 812 | lbs_deb_leave(LBS_DEB_MAIN); |
914 | } | 813 | } |
@@ -945,7 +844,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
945 | lbs_pr_err("cfg80211 init failed\n"); | 844 | lbs_pr_err("cfg80211 init failed\n"); |
946 | goto done; | 845 | goto done; |
947 | } | 846 | } |
948 | /* TODO? */ | 847 | |
949 | wdev->iftype = NL80211_IFTYPE_STATION; | 848 | wdev->iftype = NL80211_IFTYPE_STATION; |
950 | priv = wdev_priv(wdev); | 849 | priv = wdev_priv(wdev); |
951 | priv->wdev = wdev; | 850 | priv->wdev = wdev; |
@@ -955,7 +854,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
955 | goto err_wdev; | 854 | goto err_wdev; |
956 | } | 855 | } |
957 | 856 | ||
958 | //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); | ||
959 | dev = alloc_netdev(0, "wlan%d", ether_setup); | 857 | dev = alloc_netdev(0, "wlan%d", ether_setup); |
960 | if (!dev) { | 858 | if (!dev) { |
961 | dev_err(dmdev, "no memory for network device instance\n"); | 859 | dev_err(dmdev, "no memory for network device instance\n"); |
@@ -971,20 +869,10 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
971 | dev->netdev_ops = &lbs_netdev_ops; | 869 | dev->netdev_ops = &lbs_netdev_ops; |
972 | dev->watchdog_timeo = 5 * HZ; | 870 | dev->watchdog_timeo = 5 * HZ; |
973 | dev->ethtool_ops = &lbs_ethtool_ops; | 871 | dev->ethtool_ops = &lbs_ethtool_ops; |
974 | #ifdef WIRELESS_EXT | ||
975 | dev->wireless_handlers = &lbs_handler_def; | ||
976 | #endif | ||
977 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | 872 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; |
978 | 873 | ||
979 | |||
980 | // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ?? | ||
981 | |||
982 | |||
983 | priv->card = card; | 874 | priv->card = card; |
984 | priv->infra_open = 0; | ||
985 | |||
986 | 875 | ||
987 | priv->rtap_net_dev = NULL; | ||
988 | strcpy(dev->name, "wlan%d"); | 876 | strcpy(dev->name, "wlan%d"); |
989 | 877 | ||
990 | lbs_deb_thread("Starting main thread...\n"); | 878 | lbs_deb_thread("Starting main thread...\n"); |
@@ -996,8 +884,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
996 | } | 884 | } |
997 | 885 | ||
998 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); | 886 | priv->work_thread = create_singlethread_workqueue("lbs_worker"); |
999 | INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); | ||
1000 | INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); | ||
1001 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); | 887 | INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); |
1002 | 888 | ||
1003 | priv->wol_criteria = 0xffffffff; | 889 | priv->wol_criteria = 0xffffffff; |
@@ -1031,12 +917,10 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1031 | lbs_deb_enter(LBS_DEB_MAIN); | 917 | lbs_deb_enter(LBS_DEB_MAIN); |
1032 | 918 | ||
1033 | lbs_remove_mesh(priv); | 919 | lbs_remove_mesh(priv); |
1034 | lbs_remove_rtap(priv); | 920 | lbs_scan_deinit(priv); |
1035 | 921 | ||
1036 | dev = priv->dev; | 922 | dev = priv->dev; |
1037 | 923 | ||
1038 | cancel_delayed_work_sync(&priv->scan_work); | ||
1039 | cancel_delayed_work_sync(&priv->assoc_work); | ||
1040 | cancel_work_sync(&priv->mcast_work); | 924 | cancel_work_sync(&priv->mcast_work); |
1041 | 925 | ||
1042 | /* worker thread destruction blocks on the in-flight command which | 926 | /* worker thread destruction blocks on the in-flight command which |
@@ -1051,8 +935,6 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1051 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); | 935 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); |
1052 | } | 936 | } |
1053 | 937 | ||
1054 | lbs_send_disconnect_notification(priv); | ||
1055 | |||
1056 | if (priv->is_deep_sleep) { | 938 | if (priv->is_deep_sleep) { |
1057 | priv->is_deep_sleep = 0; | 939 | priv->is_deep_sleep = 0; |
1058 | wake_up_interruptible(&priv->ds_awake_q); | 940 | wake_up_interruptible(&priv->ds_awake_q); |
@@ -1077,7 +959,7 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1077 | EXPORT_SYMBOL_GPL(lbs_remove_card); | 959 | EXPORT_SYMBOL_GPL(lbs_remove_card); |
1078 | 960 | ||
1079 | 961 | ||
1080 | static int lbs_rtap_supported(struct lbs_private *priv) | 962 | int lbs_rtap_supported(struct lbs_private *priv) |
1081 | { | 963 | { |
1082 | if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) | 964 | if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) |
1083 | return 1; | 965 | return 1; |
@@ -1109,16 +991,6 @@ int lbs_start_card(struct lbs_private *priv) | |||
1109 | 991 | ||
1110 | lbs_init_mesh(priv); | 992 | lbs_init_mesh(priv); |
1111 | 993 | ||
1112 | /* | ||
1113 | * While rtap isn't related to mesh, only mesh-enabled | ||
1114 | * firmware implements the rtap functionality via | ||
1115 | * CMD_802_11_MONITOR_MODE. | ||
1116 | */ | ||
1117 | if (lbs_rtap_supported(priv)) { | ||
1118 | if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) | ||
1119 | lbs_pr_err("cannot register lbs_rtap attribute\n"); | ||
1120 | } | ||
1121 | |||
1122 | lbs_debugfs_init_one(priv, dev); | 994 | lbs_debugfs_init_one(priv, dev); |
1123 | 995 | ||
1124 | lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); | 996 | lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); |
@@ -1150,9 +1022,6 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1150 | lbs_debugfs_remove_one(priv); | 1022 | lbs_debugfs_remove_one(priv); |
1151 | lbs_deinit_mesh(priv); | 1023 | lbs_deinit_mesh(priv); |
1152 | 1024 | ||
1153 | if (lbs_rtap_supported(priv)) | ||
1154 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); | ||
1155 | |||
1156 | /* Delete the timeout of the currently processing command */ | 1025 | /* Delete the timeout of the currently processing command */ |
1157 | del_timer_sync(&priv->command_timer); | 1026 | del_timer_sync(&priv->command_timer); |
1158 | del_timer_sync(&priv->auto_deepsleep_timer); | 1027 | del_timer_sync(&priv->auto_deepsleep_timer); |
@@ -1239,87 +1108,6 @@ static void __exit lbs_exit_module(void) | |||
1239 | lbs_deb_leave(LBS_DEB_MAIN); | 1108 | lbs_deb_leave(LBS_DEB_MAIN); |
1240 | } | 1109 | } |
1241 | 1110 | ||
1242 | /* | ||
1243 | * rtap interface support fuctions | ||
1244 | */ | ||
1245 | |||
1246 | static int lbs_rtap_open(struct net_device *dev) | ||
1247 | { | ||
1248 | /* Yes, _stop_ the queue. Because we don't support injection */ | ||
1249 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1250 | netif_carrier_off(dev); | ||
1251 | netif_stop_queue(dev); | ||
1252 | lbs_deb_leave(LBS_DEB_LEAVE); | ||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int lbs_rtap_stop(struct net_device *dev) | ||
1257 | { | ||
1258 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1259 | lbs_deb_leave(LBS_DEB_MAIN); | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb, | ||
1264 | struct net_device *dev) | ||
1265 | { | ||
1266 | netif_stop_queue(dev); | ||
1267 | return NETDEV_TX_BUSY; | ||
1268 | } | ||
1269 | |||
1270 | static void lbs_remove_rtap(struct lbs_private *priv) | ||
1271 | { | ||
1272 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1273 | if (priv->rtap_net_dev == NULL) | ||
1274 | goto out; | ||
1275 | unregister_netdev(priv->rtap_net_dev); | ||
1276 | free_netdev(priv->rtap_net_dev); | ||
1277 | priv->rtap_net_dev = NULL; | ||
1278 | out: | ||
1279 | lbs_deb_leave(LBS_DEB_MAIN); | ||
1280 | } | ||
1281 | |||
1282 | static const struct net_device_ops rtap_netdev_ops = { | ||
1283 | .ndo_open = lbs_rtap_open, | ||
1284 | .ndo_stop = lbs_rtap_stop, | ||
1285 | .ndo_start_xmit = lbs_rtap_hard_start_xmit, | ||
1286 | }; | ||
1287 | |||
1288 | static int lbs_add_rtap(struct lbs_private *priv) | ||
1289 | { | ||
1290 | int ret = 0; | ||
1291 | struct net_device *rtap_dev; | ||
1292 | |||
1293 | lbs_deb_enter(LBS_DEB_MAIN); | ||
1294 | if (priv->rtap_net_dev) { | ||
1295 | ret = -EPERM; | ||
1296 | goto out; | ||
1297 | } | ||
1298 | |||
1299 | rtap_dev = alloc_netdev(0, "rtap%d", ether_setup); | ||
1300 | if (rtap_dev == NULL) { | ||
1301 | ret = -ENOMEM; | ||
1302 | goto out; | ||
1303 | } | ||
1304 | |||
1305 | memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN); | ||
1306 | rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
1307 | rtap_dev->netdev_ops = &rtap_netdev_ops; | ||
1308 | rtap_dev->ml_priv = priv; | ||
1309 | SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); | ||
1310 | |||
1311 | ret = register_netdev(rtap_dev); | ||
1312 | if (ret) { | ||
1313 | free_netdev(rtap_dev); | ||
1314 | goto out; | ||
1315 | } | ||
1316 | priv->rtap_net_dev = rtap_dev; | ||
1317 | |||
1318 | out: | ||
1319 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); | ||
1320 | return ret; | ||
1321 | } | ||
1322 | |||
1323 | module_init(lbs_init_module); | 1111 | module_init(lbs_init_module); |
1324 | module_exit(lbs_exit_module); | 1112 | module_exit(lbs_exit_module); |
1325 | 1113 | ||
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index e385af1f4583..bc5bc1384c35 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/if_arp.h> | 5 | #include <linux/if_arp.h> |
6 | #include <linux/kthread.h> | 6 | #include <linux/kthread.h> |
7 | #include <linux/kfifo.h> | 7 | #include <linux/kfifo.h> |
8 | #include <net/cfg80211.h> | ||
8 | 9 | ||
9 | #include "mesh.h" | 10 | #include "mesh.h" |
10 | #include "decl.h" | 11 | #include "decl.h" |
@@ -314,7 +315,7 @@ static int lbs_mesh_dev_open(struct net_device *dev) | |||
314 | 315 | ||
315 | spin_lock_irq(&priv->driver_lock); | 316 | spin_lock_irq(&priv->driver_lock); |
316 | 317 | ||
317 | if (priv->monitormode) { | 318 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { |
318 | ret = -EBUSY; | 319 | ret = -EBUSY; |
319 | goto out; | 320 | goto out; |
320 | } | 321 | } |
@@ -369,9 +370,6 @@ int lbs_add_mesh(struct lbs_private *priv) | |||
369 | 370 | ||
370 | SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); | 371 | SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); |
371 | 372 | ||
372 | #ifdef WIRELESS_EXT | ||
373 | mesh_dev->wireless_handlers = &mesh_handler_def; | ||
374 | #endif | ||
375 | mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | 373 | mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; |
376 | /* Register virtual mesh interface */ | 374 | /* Register virtual mesh interface */ |
377 | ret = register_netdev(mesh_dev); | 375 | ret = register_netdev(mesh_dev); |
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index e2573303a328..84ea2481ff20 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h | |||
@@ -70,11 +70,6 @@ void lbs_persist_config_init(struct net_device *net); | |||
70 | void lbs_persist_config_remove(struct net_device *net); | 70 | void lbs_persist_config_remove(struct net_device *net); |
71 | 71 | ||
72 | 72 | ||
73 | /* WEXT handler */ | ||
74 | |||
75 | extern struct iw_handler_def mesh_handler_def; | ||
76 | |||
77 | |||
78 | /* Ethtool statistics */ | 73 | /* Ethtool statistics */ |
79 | 74 | ||
80 | struct ethtool_stats; | 75 | struct ethtool_stats; |
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 1c63f8ce7349..a4d0bca9ef2c 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c | |||
@@ -4,12 +4,13 @@ | |||
4 | #include <linux/etherdevice.h> | 4 | #include <linux/etherdevice.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/types.h> | 6 | #include <linux/types.h> |
7 | #include <net/cfg80211.h> | ||
7 | 8 | ||
9 | #include "defs.h" | ||
8 | #include "host.h" | 10 | #include "host.h" |
9 | #include "radiotap.h" | 11 | #include "radiotap.h" |
10 | #include "decl.h" | 12 | #include "decl.h" |
11 | #include "dev.h" | 13 | #include "dev.h" |
12 | #include "wext.h" | ||
13 | 14 | ||
14 | struct eth803hdr { | 15 | struct eth803hdr { |
15 | u8 dest_addr[6]; | 16 | u8 dest_addr[6]; |
@@ -39,98 +40,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, | |||
39 | struct sk_buff *skb); | 40 | struct sk_buff *skb); |
40 | 41 | ||
41 | /** | 42 | /** |
42 | * @brief This function computes the avgSNR . | ||
43 | * | ||
44 | * @param priv A pointer to struct lbs_private structure | ||
45 | * @return avgSNR | ||
46 | */ | ||
47 | static u8 lbs_getavgsnr(struct lbs_private *priv) | ||
48 | { | ||
49 | u8 i; | ||
50 | u16 temp = 0; | ||
51 | if (priv->numSNRNF == 0) | ||
52 | return 0; | ||
53 | for (i = 0; i < priv->numSNRNF; i++) | ||
54 | temp += priv->rawSNR[i]; | ||
55 | return (u8) (temp / priv->numSNRNF); | ||
56 | |||
57 | } | ||
58 | |||
59 | /** | ||
60 | * @brief This function computes the AvgNF | ||
61 | * | ||
62 | * @param priv A pointer to struct lbs_private structure | ||
63 | * @return AvgNF | ||
64 | */ | ||
65 | static u8 lbs_getavgnf(struct lbs_private *priv) | ||
66 | { | ||
67 | u8 i; | ||
68 | u16 temp = 0; | ||
69 | if (priv->numSNRNF == 0) | ||
70 | return 0; | ||
71 | for (i = 0; i < priv->numSNRNF; i++) | ||
72 | temp += priv->rawNF[i]; | ||
73 | return (u8) (temp / priv->numSNRNF); | ||
74 | |||
75 | } | ||
76 | |||
77 | /** | ||
78 | * @brief This function save the raw SNR/NF to our internel buffer | ||
79 | * | ||
80 | * @param priv A pointer to struct lbs_private structure | ||
81 | * @param prxpd A pointer to rxpd structure of received packet | ||
82 | * @return n/a | ||
83 | */ | ||
84 | static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd) | ||
85 | { | ||
86 | if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR) | ||
87 | priv->numSNRNF++; | ||
88 | priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr; | ||
89 | priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf; | ||
90 | priv->nextSNRNF++; | ||
91 | if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) | ||
92 | priv->nextSNRNF = 0; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * @brief This function computes the RSSI in received packet. | ||
97 | * | ||
98 | * @param priv A pointer to struct lbs_private structure | ||
99 | * @param prxpd A pointer to rxpd structure of received packet | ||
100 | * @return n/a | ||
101 | */ | ||
102 | static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd) | ||
103 | { | ||
104 | |||
105 | lbs_deb_enter(LBS_DEB_RX); | ||
106 | |||
107 | lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf); | ||
108 | lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n", | ||
109 | priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
110 | priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
111 | |||
112 | priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; | ||
113 | priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; | ||
114 | lbs_save_rawSNRNF(priv, p_rx_pd); | ||
115 | |||
116 | priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE; | ||
117 | priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE; | ||
118 | lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n", | ||
119 | priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
120 | priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
121 | |||
122 | priv->RSSI[TYPE_RXPD][TYPE_NOAVG] = | ||
123 | CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG], | ||
124 | priv->NF[TYPE_RXPD][TYPE_NOAVG]); | ||
125 | |||
126 | priv->RSSI[TYPE_RXPD][TYPE_AVG] = | ||
127 | CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
128 | priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
129 | |||
130 | lbs_deb_leave(LBS_DEB_RX); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * @brief This function processes received packet and forwards it | 43 | * @brief This function processes received packet and forwards it |
135 | * to kernel/upper layer | 44 | * to kernel/upper layer |
136 | * | 45 | * |
@@ -154,7 +63,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) | |||
154 | 63 | ||
155 | skb->ip_summed = CHECKSUM_NONE; | 64 | skb->ip_summed = CHECKSUM_NONE; |
156 | 65 | ||
157 | if (priv->monitormode) | 66 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) |
158 | return process_rxed_802_11_packet(priv, skb); | 67 | return process_rxed_802_11_packet(priv, skb); |
159 | 68 | ||
160 | p_rx_pd = (struct rxpd *) skb->data; | 69 | p_rx_pd = (struct rxpd *) skb->data; |
@@ -225,13 +134,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) | |||
225 | */ | 134 | */ |
226 | skb_pull(skb, hdrchop); | 135 | skb_pull(skb, hdrchop); |
227 | 136 | ||
228 | /* Take the data rate from the rxpd structure | 137 | priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); |
229 | * only if the rate is auto | ||
230 | */ | ||
231 | if (priv->enablehwauto) | ||
232 | priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); | ||
233 | |||
234 | lbs_compute_rssi(priv, p_rx_pd); | ||
235 | 138 | ||
236 | lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); | 139 | lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); |
237 | dev->stats.rx_bytes += skb->len; | 140 | dev->stats.rx_bytes += skb->len; |
@@ -352,20 +255,18 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, | |||
352 | pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); | 255 | pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); |
353 | memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); | 256 | memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); |
354 | 257 | ||
355 | /* Take the data rate from the rxpd structure | 258 | priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); |
356 | * only if the rate is auto | ||
357 | */ | ||
358 | if (priv->enablehwauto) | ||
359 | priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); | ||
360 | |||
361 | lbs_compute_rssi(priv, prxpd); | ||
362 | 259 | ||
363 | lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); | 260 | lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); |
364 | dev->stats.rx_bytes += skb->len; | 261 | dev->stats.rx_bytes += skb->len; |
365 | dev->stats.rx_packets++; | 262 | dev->stats.rx_packets++; |
366 | 263 | ||
367 | skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); | 264 | skb->protocol = eth_type_trans(skb, priv->dev); |
368 | netif_rx(skb); | 265 | |
266 | if (in_interrupt()) | ||
267 | netif_rx(skb); | ||
268 | else | ||
269 | netif_rx_ni(skb); | ||
369 | 270 | ||
370 | ret = 0; | 271 | ret = 0; |
371 | 272 | ||
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c deleted file mode 100644 index 7d82f13bdf1d..000000000000 --- a/drivers/net/wireless/libertas/scan.c +++ /dev/null | |||
@@ -1,1354 +0,0 @@ | |||
1 | /** | ||
2 | * Functions implementing wlan scan IOCTL and firmware command APIs | ||
3 | * | ||
4 | * IOCTL handlers as well as command preperation and response routines | ||
5 | * for sending scan commands to the firmware. | ||
6 | */ | ||
7 | #include <linux/slab.h> | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/etherdevice.h> | ||
11 | #include <linux/if_arp.h> | ||
12 | #include <asm/unaligned.h> | ||
13 | #include <net/lib80211.h> | ||
14 | |||
15 | #include "host.h" | ||
16 | #include "dev.h" | ||
17 | #include "scan.h" | ||
18 | #include "assoc.h" | ||
19 | #include "wext.h" | ||
20 | #include "cmd.h" | ||
21 | |||
22 | //! Approximate amount of data needed to pass a scan result back to iwlist | ||
23 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ | ||
24 | + IEEE80211_MAX_SSID_LEN \ | ||
25 | + IW_EV_UINT_LEN \ | ||
26 | + IW_EV_FREQ_LEN \ | ||
27 | + IW_EV_QUAL_LEN \ | ||
28 | + IEEE80211_MAX_SSID_LEN \ | ||
29 | + IW_EV_PARAM_LEN \ | ||
30 | + 40) /* 40 for WPAIE */ | ||
31 | |||
32 | //! Memory needed to store a max sized channel List TLV for a firmware scan | ||
33 | #define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ | ||
34 | + (MRVDRV_MAX_CHANNELS_PER_SCAN \ | ||
35 | * sizeof(struct chanscanparamset))) | ||
36 | |||
37 | //! Memory needed to store a max number/size SSID TLV for a firmware scan | ||
38 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) | ||
39 | |||
40 | //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max | ||
41 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ | ||
42 | + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE) | ||
43 | |||
44 | //! The maximum number of channels the firmware can scan per command | ||
45 | #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 | ||
46 | |||
47 | /** | ||
48 | * @brief Number of channels to scan per firmware scan command issuance. | ||
49 | * | ||
50 | * Number restricted to prevent hitting the limit on the amount of scan data | ||
51 | * returned in a single firmware scan command. | ||
52 | */ | ||
53 | #define MRVDRV_CHANNELS_PER_SCAN_CMD 4 | ||
54 | |||
55 | //! Scan time specified in the channel TLV for each channel for passive scans | ||
56 | #define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 | ||
57 | |||
58 | //! Scan time specified in the channel TLV for each channel for active scans | ||
59 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 | ||
60 | |||
61 | #define DEFAULT_MAX_SCAN_AGE (15 * HZ) | ||
62 | |||
63 | static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, | ||
64 | struct cmd_header *resp); | ||
65 | |||
66 | /*********************************************************************/ | ||
67 | /* */ | ||
68 | /* Misc helper functions */ | ||
69 | /* */ | ||
70 | /*********************************************************************/ | ||
71 | |||
72 | /** | ||
73 | * @brief Unsets the MSB on basic rates | ||
74 | * | ||
75 | * Scan through an array and unset the MSB for basic data rates. | ||
76 | * | ||
77 | * @param rates buffer of data rates | ||
78 | * @param len size of buffer | ||
79 | */ | ||
80 | static void lbs_unset_basic_rate_flags(u8 *rates, size_t len) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < len; i++) | ||
85 | rates[i] &= 0x7f; | ||
86 | } | ||
87 | |||
88 | |||
89 | static inline void clear_bss_descriptor(struct bss_descriptor *bss) | ||
90 | { | ||
91 | /* Don't blow away ->list, just BSS data */ | ||
92 | memset(bss, 0, offsetof(struct bss_descriptor, list)); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * @brief Compare two SSIDs | ||
97 | * | ||
98 | * @param ssid1 A pointer to ssid to compare | ||
99 | * @param ssid2 A pointer to ssid to compare | ||
100 | * | ||
101 | * @return 0: ssid is same, otherwise is different | ||
102 | */ | ||
103 | int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2, | ||
104 | uint8_t ssid2_len) | ||
105 | { | ||
106 | if (ssid1_len != ssid2_len) | ||
107 | return -1; | ||
108 | |||
109 | return memcmp(ssid1, ssid2, ssid1_len); | ||
110 | } | ||
111 | |||
112 | static inline int is_same_network(struct bss_descriptor *src, | ||
113 | struct bss_descriptor *dst) | ||
114 | { | ||
115 | /* A network is only a duplicate if the channel, BSSID, and ESSID | ||
116 | * all match. We treat all <hidden> with the same BSSID and channel | ||
117 | * as one network */ | ||
118 | return ((src->ssid_len == dst->ssid_len) && | ||
119 | (src->channel == dst->channel) && | ||
120 | !compare_ether_addr(src->bssid, dst->bssid) && | ||
121 | !memcmp(src->ssid, dst->ssid, src->ssid_len)); | ||
122 | } | ||
123 | |||
124 | |||
125 | |||
126 | /*********************************************************************/ | ||
127 | /* */ | ||
128 | /* Region channel support */ | ||
129 | /* */ | ||
130 | /*********************************************************************/ | ||
131 | |||
132 | #define LBS_TX_PWR_DEFAULT 20 /*100mW */ | ||
133 | #define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ | ||
134 | #define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ | ||
135 | #define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ | ||
136 | #define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ | ||
137 | |||
138 | /* Format { channel, frequency (MHz), maxtxpower } */ | ||
139 | /* band: 'B/G', region: USA FCC/Canada IC */ | ||
140 | static struct chan_freq_power channel_freq_power_US_BG[] = { | ||
141 | {1, 2412, LBS_TX_PWR_US_DEFAULT}, | ||
142 | {2, 2417, LBS_TX_PWR_US_DEFAULT}, | ||
143 | {3, 2422, LBS_TX_PWR_US_DEFAULT}, | ||
144 | {4, 2427, LBS_TX_PWR_US_DEFAULT}, | ||
145 | {5, 2432, LBS_TX_PWR_US_DEFAULT}, | ||
146 | {6, 2437, LBS_TX_PWR_US_DEFAULT}, | ||
147 | {7, 2442, LBS_TX_PWR_US_DEFAULT}, | ||
148 | {8, 2447, LBS_TX_PWR_US_DEFAULT}, | ||
149 | {9, 2452, LBS_TX_PWR_US_DEFAULT}, | ||
150 | {10, 2457, LBS_TX_PWR_US_DEFAULT}, | ||
151 | {11, 2462, LBS_TX_PWR_US_DEFAULT} | ||
152 | }; | ||
153 | |||
154 | /* band: 'B/G', region: Europe ETSI */ | ||
155 | static struct chan_freq_power channel_freq_power_EU_BG[] = { | ||
156 | {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, | ||
157 | {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, | ||
158 | {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, | ||
159 | {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, | ||
160 | {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, | ||
161 | {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, | ||
162 | {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, | ||
163 | {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, | ||
164 | {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, | ||
165 | {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, | ||
166 | {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, | ||
167 | {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, | ||
168 | {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} | ||
169 | }; | ||
170 | |||
171 | /* band: 'B/G', region: Spain */ | ||
172 | static struct chan_freq_power channel_freq_power_SPN_BG[] = { | ||
173 | {10, 2457, LBS_TX_PWR_DEFAULT}, | ||
174 | {11, 2462, LBS_TX_PWR_DEFAULT} | ||
175 | }; | ||
176 | |||
177 | /* band: 'B/G', region: France */ | ||
178 | static struct chan_freq_power channel_freq_power_FR_BG[] = { | ||
179 | {10, 2457, LBS_TX_PWR_FR_DEFAULT}, | ||
180 | {11, 2462, LBS_TX_PWR_FR_DEFAULT}, | ||
181 | {12, 2467, LBS_TX_PWR_FR_DEFAULT}, | ||
182 | {13, 2472, LBS_TX_PWR_FR_DEFAULT} | ||
183 | }; | ||
184 | |||
185 | /* band: 'B/G', region: Japan */ | ||
186 | static struct chan_freq_power channel_freq_power_JPN_BG[] = { | ||
187 | {1, 2412, LBS_TX_PWR_JP_DEFAULT}, | ||
188 | {2, 2417, LBS_TX_PWR_JP_DEFAULT}, | ||
189 | {3, 2422, LBS_TX_PWR_JP_DEFAULT}, | ||
190 | {4, 2427, LBS_TX_PWR_JP_DEFAULT}, | ||
191 | {5, 2432, LBS_TX_PWR_JP_DEFAULT}, | ||
192 | {6, 2437, LBS_TX_PWR_JP_DEFAULT}, | ||
193 | {7, 2442, LBS_TX_PWR_JP_DEFAULT}, | ||
194 | {8, 2447, LBS_TX_PWR_JP_DEFAULT}, | ||
195 | {9, 2452, LBS_TX_PWR_JP_DEFAULT}, | ||
196 | {10, 2457, LBS_TX_PWR_JP_DEFAULT}, | ||
197 | {11, 2462, LBS_TX_PWR_JP_DEFAULT}, | ||
198 | {12, 2467, LBS_TX_PWR_JP_DEFAULT}, | ||
199 | {13, 2472, LBS_TX_PWR_JP_DEFAULT}, | ||
200 | {14, 2484, LBS_TX_PWR_JP_DEFAULT} | ||
201 | }; | ||
202 | |||
203 | /** | ||
204 | * the structure for channel, frequency and power | ||
205 | */ | ||
206 | struct region_cfp_table { | ||
207 | u8 region; | ||
208 | struct chan_freq_power *cfp_BG; | ||
209 | int cfp_no_BG; | ||
210 | }; | ||
211 | |||
212 | /** | ||
213 | * the structure for the mapping between region and CFP | ||
214 | */ | ||
215 | static struct region_cfp_table region_cfp_table[] = { | ||
216 | {0x10, /*US FCC */ | ||
217 | channel_freq_power_US_BG, | ||
218 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
219 | } | ||
220 | , | ||
221 | {0x20, /*CANADA IC */ | ||
222 | channel_freq_power_US_BG, | ||
223 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
224 | } | ||
225 | , | ||
226 | {0x30, /*EU*/ channel_freq_power_EU_BG, | ||
227 | ARRAY_SIZE(channel_freq_power_EU_BG), | ||
228 | } | ||
229 | , | ||
230 | {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, | ||
231 | ARRAY_SIZE(channel_freq_power_SPN_BG), | ||
232 | } | ||
233 | , | ||
234 | {0x32, /*FRANCE*/ channel_freq_power_FR_BG, | ||
235 | ARRAY_SIZE(channel_freq_power_FR_BG), | ||
236 | } | ||
237 | , | ||
238 | {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, | ||
239 | ARRAY_SIZE(channel_freq_power_JPN_BG), | ||
240 | } | ||
241 | , | ||
242 | /*Add new region here */ | ||
243 | }; | ||
244 | |||
245 | /** | ||
246 | * @brief This function finds the CFP in | ||
247 | * region_cfp_table based on region and band parameter. | ||
248 | * | ||
249 | * @param region The region code | ||
250 | * @param band The band | ||
251 | * @param cfp_no A pointer to CFP number | ||
252 | * @return A pointer to CFP | ||
253 | */ | ||
254 | static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) | ||
255 | { | ||
256 | int i, end; | ||
257 | |||
258 | lbs_deb_enter(LBS_DEB_MAIN); | ||
259 | |||
260 | end = ARRAY_SIZE(region_cfp_table); | ||
261 | |||
262 | for (i = 0; i < end ; i++) { | ||
263 | lbs_deb_main("region_cfp_table[i].region=%d\n", | ||
264 | region_cfp_table[i].region); | ||
265 | if (region_cfp_table[i].region == region) { | ||
266 | *cfp_no = region_cfp_table[i].cfp_no_BG; | ||
267 | lbs_deb_leave(LBS_DEB_MAIN); | ||
268 | return region_cfp_table[i].cfp_BG; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); | ||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) | ||
277 | { | ||
278 | int ret = 0; | ||
279 | int i = 0; | ||
280 | |||
281 | struct chan_freq_power *cfp; | ||
282 | int cfp_no; | ||
283 | |||
284 | lbs_deb_enter(LBS_DEB_MAIN); | ||
285 | |||
286 | memset(priv->region_channel, 0, sizeof(priv->region_channel)); | ||
287 | |||
288 | cfp = lbs_get_region_cfp_table(region, &cfp_no); | ||
289 | if (cfp != NULL) { | ||
290 | priv->region_channel[i].nrcfp = cfp_no; | ||
291 | priv->region_channel[i].CFP = cfp; | ||
292 | } else { | ||
293 | lbs_deb_main("wrong region code %#x in band B/G\n", | ||
294 | region); | ||
295 | ret = -1; | ||
296 | goto out; | ||
297 | } | ||
298 | priv->region_channel[i].valid = 1; | ||
299 | priv->region_channel[i].region = region; | ||
300 | priv->region_channel[i].band = band; | ||
301 | i++; | ||
302 | out: | ||
303 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | |||
308 | |||
309 | |||
310 | /*********************************************************************/ | ||
311 | /* */ | ||
312 | /* Main scanning support */ | ||
313 | /* */ | ||
314 | /*********************************************************************/ | ||
315 | |||
316 | /** | ||
317 | * @brief Create a channel list for the driver to scan based on region info | ||
318 | * | ||
319 | * Only used from lbs_scan_setup_scan_config() | ||
320 | * | ||
321 | * Use the driver region/band information to construct a comprehensive list | ||
322 | * of channels to scan. This routine is used for any scan that is not | ||
323 | * provided a specific channel list to scan. | ||
324 | * | ||
325 | * @param priv A pointer to struct lbs_private structure | ||
326 | * @param scanchanlist Output parameter: resulting channel list to scan | ||
327 | * | ||
328 | * @return void | ||
329 | */ | ||
330 | static int lbs_scan_create_channel_list(struct lbs_private *priv, | ||
331 | struct chanscanparamset *scanchanlist) | ||
332 | { | ||
333 | struct region_channel *scanregion; | ||
334 | struct chan_freq_power *cfp; | ||
335 | int rgnidx; | ||
336 | int chanidx; | ||
337 | int nextchan; | ||
338 | uint8_t scantype; | ||
339 | |||
340 | chanidx = 0; | ||
341 | |||
342 | /* Set the default scan type to the user specified type, will later | ||
343 | * be changed to passive on a per channel basis if restricted by | ||
344 | * regulatory requirements (11d or 11h) | ||
345 | */ | ||
346 | scantype = CMD_SCAN_TYPE_ACTIVE; | ||
347 | |||
348 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { | ||
349 | if (!priv->region_channel[rgnidx].valid) | ||
350 | continue; | ||
351 | scanregion = &priv->region_channel[rgnidx]; | ||
352 | |||
353 | for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { | ||
354 | struct chanscanparamset *chan = &scanchanlist[chanidx]; | ||
355 | |||
356 | cfp = scanregion->CFP + nextchan; | ||
357 | |||
358 | if (scanregion->band == BAND_B || scanregion->band == BAND_G) | ||
359 | chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; | ||
360 | |||
361 | if (scantype == CMD_SCAN_TYPE_PASSIVE) { | ||
362 | chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); | ||
363 | chan->chanscanmode.passivescan = 1; | ||
364 | } else { | ||
365 | chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); | ||
366 | chan->chanscanmode.passivescan = 0; | ||
367 | } | ||
368 | |||
369 | chan->channumber = cfp->channel; | ||
370 | } | ||
371 | } | ||
372 | return chanidx; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Add SSID TLV of the form: | ||
377 | * | ||
378 | * TLV-ID SSID 00 00 | ||
379 | * length 06 00 | ||
380 | * ssid 4d 4e 54 45 53 54 | ||
381 | */ | ||
382 | static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) | ||
383 | { | ||
384 | struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; | ||
385 | |||
386 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
387 | ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); | ||
388 | memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len); | ||
389 | return sizeof(ssid_tlv->header) + priv->scan_ssid_len; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Add CHANLIST TLV of the form | ||
394 | * | ||
395 | * TLV-ID CHANLIST 01 01 | ||
396 | * length 5b 00 | ||
397 | * channel 1 00 01 00 00 00 64 00 | ||
398 | * radio type 00 | ||
399 | * channel 01 | ||
400 | * scan type 00 | ||
401 | * min scan time 00 00 | ||
402 | * max scan time 64 00 | ||
403 | * channel 2 00 02 00 00 00 64 00 | ||
404 | * channel 3 00 03 00 00 00 64 00 | ||
405 | * channel 4 00 04 00 00 00 64 00 | ||
406 | * channel 5 00 05 00 00 00 64 00 | ||
407 | * channel 6 00 06 00 00 00 64 00 | ||
408 | * channel 7 00 07 00 00 00 64 00 | ||
409 | * channel 8 00 08 00 00 00 64 00 | ||
410 | * channel 9 00 09 00 00 00 64 00 | ||
411 | * channel 10 00 0a 00 00 00 64 00 | ||
412 | * channel 11 00 0b 00 00 00 64 00 | ||
413 | * channel 12 00 0c 00 00 00 64 00 | ||
414 | * channel 13 00 0d 00 00 00 64 00 | ||
415 | * | ||
416 | */ | ||
417 | static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, | ||
418 | struct chanscanparamset *chan_list, | ||
419 | int chan_count) | ||
420 | { | ||
421 | size_t size = sizeof(struct chanscanparamset) *chan_count; | ||
422 | struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; | ||
423 | |||
424 | chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
425 | memcpy(chan_tlv->chanscanparam, chan_list, size); | ||
426 | chan_tlv->header.len = cpu_to_le16(size); | ||
427 | return sizeof(chan_tlv->header) + size; | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * Add RATES TLV of the form | ||
432 | * | ||
433 | * TLV-ID RATES 01 00 | ||
434 | * length 0e 00 | ||
435 | * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c | ||
436 | * | ||
437 | * The rates are in lbs_bg_rates[], but for the 802.11b | ||
438 | * rates the high bit isn't set. | ||
439 | */ | ||
440 | static int lbs_scan_add_rates_tlv(uint8_t *tlv) | ||
441 | { | ||
442 | int i; | ||
443 | struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; | ||
444 | |||
445 | rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
446 | tlv += sizeof(rate_tlv->header); | ||
447 | for (i = 0; i < MAX_RATES; i++) { | ||
448 | *tlv = lbs_bg_rates[i]; | ||
449 | if (*tlv == 0) | ||
450 | break; | ||
451 | /* This code makes sure that the 802.11b rates (1 MBit/s, 2 | ||
452 | MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set. | ||
453 | Note that the values are MBit/s * 2, to mark them as | ||
454 | basic rates so that the firmware likes it better */ | ||
455 | if (*tlv == 0x02 || *tlv == 0x04 || | ||
456 | *tlv == 0x0b || *tlv == 0x16) | ||
457 | *tlv |= 0x80; | ||
458 | tlv++; | ||
459 | } | ||
460 | rate_tlv->header.len = cpu_to_le16(i); | ||
461 | return sizeof(rate_tlv->header) + i; | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * Generate the CMD_802_11_SCAN command with the proper tlv | ||
466 | * for a bunch of channels. | ||
467 | */ | ||
468 | static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, | ||
469 | struct chanscanparamset *chan_list, int chan_count) | ||
470 | { | ||
471 | int ret = -ENOMEM; | ||
472 | struct cmd_ds_802_11_scan *scan_cmd; | ||
473 | uint8_t *tlv; /* pointer into our current, growing TLV storage area */ | ||
474 | |||
475 | lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d", | ||
476 | bsstype, chan_list ? chan_list[0].channumber : -1, | ||
477 | chan_count); | ||
478 | |||
479 | /* create the fixed part for scan command */ | ||
480 | scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); | ||
481 | if (scan_cmd == NULL) | ||
482 | goto out; | ||
483 | |||
484 | tlv = scan_cmd->tlvbuffer; | ||
485 | /* TODO: do we need to scan for a specific BSSID? | ||
486 | memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */ | ||
487 | scan_cmd->bsstype = bsstype; | ||
488 | |||
489 | /* add TLVs */ | ||
490 | if (priv->scan_ssid_len) | ||
491 | tlv += lbs_scan_add_ssid_tlv(priv, tlv); | ||
492 | if (chan_list && chan_count) | ||
493 | tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); | ||
494 | tlv += lbs_scan_add_rates_tlv(tlv); | ||
495 | |||
496 | /* This is the final data we are about to send */ | ||
497 | scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd); | ||
498 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, | ||
499 | sizeof(*scan_cmd)); | ||
500 | lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, | ||
501 | tlv - scan_cmd->tlvbuffer); | ||
502 | |||
503 | ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr, | ||
504 | le16_to_cpu(scan_cmd->hdr.size), | ||
505 | lbs_ret_80211_scan, 0); | ||
506 | |||
507 | out: | ||
508 | kfree(scan_cmd); | ||
509 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | /** | ||
514 | * @brief Internal function used to start a scan based on an input config | ||
515 | * | ||
516 | * Use the input user scan configuration information when provided in | ||
517 | * order to send the appropriate scan commands to firmware to populate or | ||
518 | * update the internal driver scan table | ||
519 | * | ||
520 | * @param priv A pointer to struct lbs_private structure | ||
521 | * @param full_scan Do a full-scan (blocking) | ||
522 | * | ||
523 | * @return 0 or < 0 if error | ||
524 | */ | ||
525 | int lbs_scan_networks(struct lbs_private *priv, int full_scan) | ||
526 | { | ||
527 | int ret = -ENOMEM; | ||
528 | struct chanscanparamset *chan_list; | ||
529 | struct chanscanparamset *curr_chans; | ||
530 | int chan_count; | ||
531 | uint8_t bsstype = CMD_BSS_TYPE_ANY; | ||
532 | int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; | ||
533 | union iwreq_data wrqu; | ||
534 | #ifdef CONFIG_LIBERTAS_DEBUG | ||
535 | struct bss_descriptor *iter; | ||
536 | int i = 0; | ||
537 | DECLARE_SSID_BUF(ssid); | ||
538 | #endif | ||
539 | |||
540 | lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); | ||
541 | |||
542 | /* Cancel any partial outstanding partial scans if this scan | ||
543 | * is a full scan. | ||
544 | */ | ||
545 | if (full_scan && delayed_work_pending(&priv->scan_work)) | ||
546 | cancel_delayed_work(&priv->scan_work); | ||
547 | |||
548 | /* User-specified bsstype or channel list | ||
549 | TODO: this can be implemented if some user-space application | ||
550 | need the feature. Formerly, it was accessible from debugfs, | ||
551 | but then nowhere used. | ||
552 | if (user_cfg) { | ||
553 | if (user_cfg->bsstype) | ||
554 | bsstype = user_cfg->bsstype; | ||
555 | } */ | ||
556 | |||
557 | lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype); | ||
558 | |||
559 | /* Create list of channels to scan */ | ||
560 | chan_list = kzalloc(sizeof(struct chanscanparamset) * | ||
561 | LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); | ||
562 | if (!chan_list) { | ||
563 | lbs_pr_alert("SCAN: chan_list empty\n"); | ||
564 | goto out; | ||
565 | } | ||
566 | |||
567 | /* We want to scan all channels */ | ||
568 | chan_count = lbs_scan_create_channel_list(priv, chan_list); | ||
569 | |||
570 | netif_stop_queue(priv->dev); | ||
571 | if (priv->mesh_dev) | ||
572 | netif_stop_queue(priv->mesh_dev); | ||
573 | |||
574 | /* Prepare to continue an interrupted scan */ | ||
575 | lbs_deb_scan("chan_count %d, scan_channel %d\n", | ||
576 | chan_count, priv->scan_channel); | ||
577 | curr_chans = chan_list; | ||
578 | /* advance channel list by already-scanned-channels */ | ||
579 | if (priv->scan_channel > 0) { | ||
580 | curr_chans += priv->scan_channel; | ||
581 | chan_count -= priv->scan_channel; | ||
582 | } | ||
583 | |||
584 | /* Send scan command(s) | ||
585 | * numchannels contains the number of channels we should maximally scan | ||
586 | * chan_count is the total number of channels to scan | ||
587 | */ | ||
588 | |||
589 | while (chan_count) { | ||
590 | int to_scan = min(numchannels, chan_count); | ||
591 | lbs_deb_scan("scanning %d of %d channels\n", | ||
592 | to_scan, chan_count); | ||
593 | ret = lbs_do_scan(priv, bsstype, curr_chans, | ||
594 | to_scan); | ||
595 | if (ret) { | ||
596 | lbs_pr_err("SCAN_CMD failed\n"); | ||
597 | goto out2; | ||
598 | } | ||
599 | curr_chans += to_scan; | ||
600 | chan_count -= to_scan; | ||
601 | |||
602 | /* somehow schedule the next part of the scan */ | ||
603 | if (chan_count && !full_scan && | ||
604 | !priv->surpriseremoved) { | ||
605 | /* -1 marks just that we're currently scanning */ | ||
606 | if (priv->scan_channel < 0) | ||
607 | priv->scan_channel = to_scan; | ||
608 | else | ||
609 | priv->scan_channel += to_scan; | ||
610 | cancel_delayed_work(&priv->scan_work); | ||
611 | queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
612 | msecs_to_jiffies(300)); | ||
613 | /* skip over GIWSCAN event */ | ||
614 | goto out; | ||
615 | } | ||
616 | |||
617 | } | ||
618 | memset(&wrqu, 0, sizeof(union iwreq_data)); | ||
619 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
620 | |||
621 | #ifdef CONFIG_LIBERTAS_DEBUG | ||
622 | /* Dump the scan table */ | ||
623 | mutex_lock(&priv->lock); | ||
624 | lbs_deb_scan("scan table:\n"); | ||
625 | list_for_each_entry(iter, &priv->network_list, list) | ||
626 | lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", | ||
627 | i++, iter->bssid, iter->rssi, | ||
628 | print_ssid(ssid, iter->ssid, iter->ssid_len)); | ||
629 | mutex_unlock(&priv->lock); | ||
630 | #endif | ||
631 | |||
632 | out2: | ||
633 | priv->scan_channel = 0; | ||
634 | |||
635 | out: | ||
636 | if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len) | ||
637 | netif_wake_queue(priv->dev); | ||
638 | |||
639 | if (priv->mesh_dev && lbs_mesh_connected(priv) && | ||
640 | !priv->tx_pending_len) | ||
641 | netif_wake_queue(priv->mesh_dev); | ||
642 | |||
643 | kfree(chan_list); | ||
644 | |||
645 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | void lbs_scan_worker(struct work_struct *work) | ||
650 | { | ||
651 | struct lbs_private *priv = | ||
652 | container_of(work, struct lbs_private, scan_work.work); | ||
653 | |||
654 | lbs_deb_enter(LBS_DEB_SCAN); | ||
655 | lbs_scan_networks(priv, 0); | ||
656 | lbs_deb_leave(LBS_DEB_SCAN); | ||
657 | } | ||
658 | |||
659 | |||
660 | /*********************************************************************/ | ||
661 | /* */ | ||
662 | /* Result interpretation */ | ||
663 | /* */ | ||
664 | /*********************************************************************/ | ||
665 | |||
666 | /** | ||
667 | * @brief Interpret a BSS scan response returned from the firmware | ||
668 | * | ||
669 | * Parse the various fixed fields and IEs passed back for a BSS probe | ||
670 | * response or beacon from the scan command. Record information as needed | ||
671 | * in the scan table struct bss_descriptor for that entry. | ||
672 | * | ||
673 | * @param bss Output parameter: Pointer to the BSS Entry | ||
674 | * | ||
675 | * @return 0 or -1 | ||
676 | */ | ||
677 | static int lbs_process_bss(struct bss_descriptor *bss, | ||
678 | uint8_t **pbeaconinfo, int *bytesleft) | ||
679 | { | ||
680 | struct ieee_ie_fh_param_set *fh; | ||
681 | struct ieee_ie_ds_param_set *ds; | ||
682 | struct ieee_ie_cf_param_set *cf; | ||
683 | struct ieee_ie_ibss_param_set *ibss; | ||
684 | DECLARE_SSID_BUF(ssid); | ||
685 | uint8_t *pos, *end, *p; | ||
686 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; | ||
687 | uint16_t beaconsize = 0; | ||
688 | int ret; | ||
689 | |||
690 | lbs_deb_enter(LBS_DEB_SCAN); | ||
691 | |||
692 | if (*bytesleft >= sizeof(beaconsize)) { | ||
693 | /* Extract & convert beacon size from the command buffer */ | ||
694 | beaconsize = get_unaligned_le16(*pbeaconinfo); | ||
695 | *bytesleft -= sizeof(beaconsize); | ||
696 | *pbeaconinfo += sizeof(beaconsize); | ||
697 | } | ||
698 | |||
699 | if (beaconsize == 0 || beaconsize > *bytesleft) { | ||
700 | *pbeaconinfo += *bytesleft; | ||
701 | *bytesleft = 0; | ||
702 | ret = -1; | ||
703 | goto done; | ||
704 | } | ||
705 | |||
706 | /* Initialize the current working beacon pointer for this BSS iteration */ | ||
707 | pos = *pbeaconinfo; | ||
708 | end = pos + beaconsize; | ||
709 | |||
710 | /* Advance the return beacon pointer past the current beacon */ | ||
711 | *pbeaconinfo += beaconsize; | ||
712 | *bytesleft -= beaconsize; | ||
713 | |||
714 | memcpy(bss->bssid, pos, ETH_ALEN); | ||
715 | lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid); | ||
716 | pos += ETH_ALEN; | ||
717 | |||
718 | if ((end - pos) < 12) { | ||
719 | lbs_deb_scan("process_bss: Not enough bytes left\n"); | ||
720 | ret = -1; | ||
721 | goto done; | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * next 4 fields are RSSI, time stamp, beacon interval, | ||
726 | * and capability information | ||
727 | */ | ||
728 | |||
729 | /* RSSI is 1 byte long */ | ||
730 | bss->rssi = *pos; | ||
731 | lbs_deb_scan("process_bss: RSSI %d\n", *pos); | ||
732 | pos++; | ||
733 | |||
734 | /* time stamp is 8 bytes long */ | ||
735 | pos += 8; | ||
736 | |||
737 | /* beacon interval is 2 bytes long */ | ||
738 | bss->beaconperiod = get_unaligned_le16(pos); | ||
739 | pos += 2; | ||
740 | |||
741 | /* capability information is 2 bytes long */ | ||
742 | bss->capability = get_unaligned_le16(pos); | ||
743 | lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability); | ||
744 | pos += 2; | ||
745 | |||
746 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
747 | lbs_deb_scan("process_bss: WEP enabled\n"); | ||
748 | if (bss->capability & WLAN_CAPABILITY_IBSS) | ||
749 | bss->mode = IW_MODE_ADHOC; | ||
750 | else | ||
751 | bss->mode = IW_MODE_INFRA; | ||
752 | |||
753 | /* rest of the current buffer are IE's */ | ||
754 | lbs_deb_scan("process_bss: IE len %zd\n", end - pos); | ||
755 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); | ||
756 | |||
757 | /* process variable IE */ | ||
758 | while (pos <= end - 2) { | ||
759 | if (pos + pos[1] > end) { | ||
760 | lbs_deb_scan("process_bss: error in processing IE, " | ||
761 | "bytes left < IE length\n"); | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | switch (pos[0]) { | ||
766 | case WLAN_EID_SSID: | ||
767 | bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); | ||
768 | memcpy(bss->ssid, pos + 2, bss->ssid_len); | ||
769 | lbs_deb_scan("got SSID IE: '%s', len %u\n", | ||
770 | print_ssid(ssid, bss->ssid, bss->ssid_len), | ||
771 | bss->ssid_len); | ||
772 | break; | ||
773 | |||
774 | case WLAN_EID_SUPP_RATES: | ||
775 | n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); | ||
776 | memcpy(bss->rates, pos + 2, n_basic_rates); | ||
777 | got_basic_rates = 1; | ||
778 | lbs_deb_scan("got RATES IE\n"); | ||
779 | break; | ||
780 | |||
781 | case WLAN_EID_FH_PARAMS: | ||
782 | fh = (struct ieee_ie_fh_param_set *) pos; | ||
783 | memcpy(&bss->phy.fh, fh, sizeof(*fh)); | ||
784 | lbs_deb_scan("got FH IE\n"); | ||
785 | break; | ||
786 | |||
787 | case WLAN_EID_DS_PARAMS: | ||
788 | ds = (struct ieee_ie_ds_param_set *) pos; | ||
789 | bss->channel = ds->channel; | ||
790 | memcpy(&bss->phy.ds, ds, sizeof(*ds)); | ||
791 | lbs_deb_scan("got DS IE, channel %d\n", bss->channel); | ||
792 | break; | ||
793 | |||
794 | case WLAN_EID_CF_PARAMS: | ||
795 | cf = (struct ieee_ie_cf_param_set *) pos; | ||
796 | memcpy(&bss->ss.cf, cf, sizeof(*cf)); | ||
797 | lbs_deb_scan("got CF IE\n"); | ||
798 | break; | ||
799 | |||
800 | case WLAN_EID_IBSS_PARAMS: | ||
801 | ibss = (struct ieee_ie_ibss_param_set *) pos; | ||
802 | bss->atimwindow = ibss->atimwindow; | ||
803 | memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); | ||
804 | lbs_deb_scan("got IBSS IE\n"); | ||
805 | break; | ||
806 | |||
807 | case WLAN_EID_EXT_SUPP_RATES: | ||
808 | /* only process extended supported rate if data rate is | ||
809 | * already found. Data rate IE should come before | ||
810 | * extended supported rate IE | ||
811 | */ | ||
812 | lbs_deb_scan("got RATESEX IE\n"); | ||
813 | if (!got_basic_rates) { | ||
814 | lbs_deb_scan("... but ignoring it\n"); | ||
815 | break; | ||
816 | } | ||
817 | |||
818 | n_ex_rates = pos[1]; | ||
819 | if (n_basic_rates + n_ex_rates > MAX_RATES) | ||
820 | n_ex_rates = MAX_RATES - n_basic_rates; | ||
821 | |||
822 | p = bss->rates + n_basic_rates; | ||
823 | memcpy(p, pos + 2, n_ex_rates); | ||
824 | break; | ||
825 | |||
826 | case WLAN_EID_GENERIC: | ||
827 | if (pos[1] >= 4 && | ||
828 | pos[2] == 0x00 && pos[3] == 0x50 && | ||
829 | pos[4] == 0xf2 && pos[5] == 0x01) { | ||
830 | bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); | ||
831 | memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); | ||
832 | lbs_deb_scan("got WPA IE\n"); | ||
833 | lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, | ||
834 | bss->wpa_ie_len); | ||
835 | } else if (pos[1] >= MARVELL_MESH_IE_LENGTH && | ||
836 | pos[2] == 0x00 && pos[3] == 0x50 && | ||
837 | pos[4] == 0x43 && pos[5] == 0x04) { | ||
838 | lbs_deb_scan("got mesh IE\n"); | ||
839 | bss->mesh = 1; | ||
840 | } else { | ||
841 | lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", | ||
842 | pos[2], pos[3], | ||
843 | pos[4], pos[5], | ||
844 | pos[1]); | ||
845 | } | ||
846 | break; | ||
847 | |||
848 | case WLAN_EID_RSN: | ||
849 | lbs_deb_scan("got RSN IE\n"); | ||
850 | bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); | ||
851 | memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); | ||
852 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", | ||
853 | bss->rsn_ie, bss->rsn_ie_len); | ||
854 | break; | ||
855 | |||
856 | default: | ||
857 | lbs_deb_scan("got IE 0x%04x, len %d\n", | ||
858 | pos[0], pos[1]); | ||
859 | break; | ||
860 | } | ||
861 | |||
862 | pos += pos[1] + 2; | ||
863 | } | ||
864 | |||
865 | /* Timestamp */ | ||
866 | bss->last_scanned = jiffies; | ||
867 | lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); | ||
868 | |||
869 | ret = 0; | ||
870 | |||
871 | done: | ||
872 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | /** | ||
877 | * @brief Send a scan command for all available channels filtered on a spec | ||
878 | * | ||
879 | * Used in association code and from debugfs | ||
880 | * | ||
881 | * @param priv A pointer to struct lbs_private structure | ||
882 | * @param ssid A pointer to the SSID to scan for | ||
883 | * @param ssid_len Length of the SSID | ||
884 | * | ||
885 | * @return 0-success, otherwise fail | ||
886 | */ | ||
887 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, | ||
888 | uint8_t ssid_len) | ||
889 | { | ||
890 | DECLARE_SSID_BUF(ssid_buf); | ||
891 | int ret = 0; | ||
892 | |||
893 | lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", | ||
894 | print_ssid(ssid_buf, ssid, ssid_len)); | ||
895 | |||
896 | if (!ssid_len) | ||
897 | goto out; | ||
898 | |||
899 | memcpy(priv->scan_ssid, ssid, ssid_len); | ||
900 | priv->scan_ssid_len = ssid_len; | ||
901 | |||
902 | lbs_scan_networks(priv, 1); | ||
903 | if (priv->surpriseremoved) { | ||
904 | ret = -1; | ||
905 | goto out; | ||
906 | } | ||
907 | |||
908 | out: | ||
909 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
910 | return ret; | ||
911 | } | ||
912 | |||
913 | |||
914 | |||
915 | |||
916 | /*********************************************************************/ | ||
917 | /* */ | ||
918 | /* Support for Wireless Extensions */ | ||
919 | /* */ | ||
920 | /*********************************************************************/ | ||
921 | |||
922 | |||
923 | #define MAX_CUSTOM_LEN 64 | ||
924 | |||
925 | static inline char *lbs_translate_scan(struct lbs_private *priv, | ||
926 | struct iw_request_info *info, | ||
927 | char *start, char *stop, | ||
928 | struct bss_descriptor *bss) | ||
929 | { | ||
930 | struct chan_freq_power *cfp; | ||
931 | char *current_val; /* For rates */ | ||
932 | struct iw_event iwe; /* Temporary buffer */ | ||
933 | int j; | ||
934 | #define PERFECT_RSSI ((uint8_t)50) | ||
935 | #define WORST_RSSI ((uint8_t)0) | ||
936 | #define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI)) | ||
937 | uint8_t rssi; | ||
938 | |||
939 | lbs_deb_enter(LBS_DEB_SCAN); | ||
940 | |||
941 | cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel); | ||
942 | if (!cfp) { | ||
943 | lbs_deb_scan("Invalid channel number %d\n", bss->channel); | ||
944 | start = NULL; | ||
945 | goto out; | ||
946 | } | ||
947 | |||
948 | /* First entry *MUST* be the BSSID */ | ||
949 | iwe.cmd = SIOCGIWAP; | ||
950 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
951 | memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); | ||
952 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); | ||
953 | |||
954 | /* SSID */ | ||
955 | iwe.cmd = SIOCGIWESSID; | ||
956 | iwe.u.data.flags = 1; | ||
957 | iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN); | ||
958 | start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); | ||
959 | |||
960 | /* Mode */ | ||
961 | iwe.cmd = SIOCGIWMODE; | ||
962 | iwe.u.mode = bss->mode; | ||
963 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); | ||
964 | |||
965 | /* Frequency */ | ||
966 | iwe.cmd = SIOCGIWFREQ; | ||
967 | iwe.u.freq.m = (long)cfp->freq * 100000; | ||
968 | iwe.u.freq.e = 1; | ||
969 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); | ||
970 | |||
971 | /* Add quality statistics */ | ||
972 | iwe.cmd = IWEVQUAL; | ||
973 | iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; | ||
974 | iwe.u.qual.level = SCAN_RSSI(bss->rssi); | ||
975 | |||
976 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
977 | iwe.u.qual.qual = | ||
978 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * | ||
979 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / | ||
980 | (RSSI_DIFF * RSSI_DIFF); | ||
981 | if (iwe.u.qual.qual > 100) | ||
982 | iwe.u.qual.qual = 100; | ||
983 | |||
984 | if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
985 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
986 | } else { | ||
987 | iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
988 | } | ||
989 | |||
990 | /* Locally created ad-hoc BSSs won't have beacons if this is the | ||
991 | * only station in the adhoc network; so get signal strength | ||
992 | * from receive statistics. | ||
993 | */ | ||
994 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate | ||
995 | && !lbs_ssid_cmp(priv->curbssparams.ssid, | ||
996 | priv->curbssparams.ssid_len, | ||
997 | bss->ssid, bss->ssid_len)) { | ||
998 | int snr, nf; | ||
999 | snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
1000 | nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
1001 | iwe.u.qual.level = CAL_RSSI(snr, nf); | ||
1002 | } | ||
1003 | start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); | ||
1004 | |||
1005 | /* Add encryption capability */ | ||
1006 | iwe.cmd = SIOCGIWENCODE; | ||
1007 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) { | ||
1008 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1009 | } else { | ||
1010 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1011 | } | ||
1012 | iwe.u.data.length = 0; | ||
1013 | start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); | ||
1014 | |||
1015 | current_val = start + iwe_stream_lcp_len(info); | ||
1016 | |||
1017 | iwe.cmd = SIOCGIWRATE; | ||
1018 | iwe.u.bitrate.fixed = 0; | ||
1019 | iwe.u.bitrate.disabled = 0; | ||
1020 | iwe.u.bitrate.value = 0; | ||
1021 | |||
1022 | for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) { | ||
1023 | /* Bit rate given in 500 kb/s units */ | ||
1024 | iwe.u.bitrate.value = bss->rates[j] * 500000; | ||
1025 | current_val = iwe_stream_add_value(info, start, current_val, | ||
1026 | stop, &iwe, IW_EV_PARAM_LEN); | ||
1027 | } | ||
1028 | if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate | ||
1029 | && !lbs_ssid_cmp(priv->curbssparams.ssid, | ||
1030 | priv->curbssparams.ssid_len, | ||
1031 | bss->ssid, bss->ssid_len)) { | ||
1032 | iwe.u.bitrate.value = 22 * 500000; | ||
1033 | current_val = iwe_stream_add_value(info, start, current_val, | ||
1034 | stop, &iwe, IW_EV_PARAM_LEN); | ||
1035 | } | ||
1036 | /* Check if we added any event */ | ||
1037 | if ((current_val - start) > iwe_stream_lcp_len(info)) | ||
1038 | start = current_val; | ||
1039 | |||
1040 | memset(&iwe, 0, sizeof(iwe)); | ||
1041 | if (bss->wpa_ie_len) { | ||
1042 | char buf[MAX_WPA_IE_LEN]; | ||
1043 | memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); | ||
1044 | iwe.cmd = IWEVGENIE; | ||
1045 | iwe.u.data.length = bss->wpa_ie_len; | ||
1046 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); | ||
1047 | } | ||
1048 | |||
1049 | memset(&iwe, 0, sizeof(iwe)); | ||
1050 | if (bss->rsn_ie_len) { | ||
1051 | char buf[MAX_WPA_IE_LEN]; | ||
1052 | memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); | ||
1053 | iwe.cmd = IWEVGENIE; | ||
1054 | iwe.u.data.length = bss->rsn_ie_len; | ||
1055 | start = iwe_stream_add_point(info, start, stop, &iwe, buf); | ||
1056 | } | ||
1057 | |||
1058 | if (bss->mesh) { | ||
1059 | char custom[MAX_CUSTOM_LEN]; | ||
1060 | char *p = custom; | ||
1061 | |||
1062 | iwe.cmd = IWEVCUSTOM; | ||
1063 | p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc"); | ||
1064 | iwe.u.data.length = p - custom; | ||
1065 | if (iwe.u.data.length) | ||
1066 | start = iwe_stream_add_point(info, start, stop, | ||
1067 | &iwe, custom); | ||
1068 | } | ||
1069 | |||
1070 | out: | ||
1071 | lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start); | ||
1072 | return start; | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | /** | ||
1077 | * @brief Handle Scan Network ioctl | ||
1078 | * | ||
1079 | * @param dev A pointer to net_device structure | ||
1080 | * @param info A pointer to iw_request_info structure | ||
1081 | * @param vwrq A pointer to iw_param structure | ||
1082 | * @param extra A pointer to extra data buf | ||
1083 | * | ||
1084 | * @return 0 --success, otherwise fail | ||
1085 | */ | ||
1086 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
1087 | union iwreq_data *wrqu, char *extra) | ||
1088 | { | ||
1089 | DECLARE_SSID_BUF(ssid); | ||
1090 | struct lbs_private *priv = dev->ml_priv; | ||
1091 | int ret = 0; | ||
1092 | |||
1093 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1094 | |||
1095 | if (!priv->radio_on) { | ||
1096 | ret = -EINVAL; | ||
1097 | goto out; | ||
1098 | } | ||
1099 | |||
1100 | if (!netif_running(dev)) { | ||
1101 | ret = -ENETDOWN; | ||
1102 | goto out; | ||
1103 | } | ||
1104 | |||
1105 | /* mac80211 does this: | ||
1106 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1107 | if (sdata->type != IEEE80211_IF_TYPE_xxx) { | ||
1108 | ret = -EOPNOTSUPP; | ||
1109 | goto out; | ||
1110 | } | ||
1111 | */ | ||
1112 | |||
1113 | if (wrqu->data.length == sizeof(struct iw_scan_req) && | ||
1114 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||
1115 | struct iw_scan_req *req = (struct iw_scan_req *)extra; | ||
1116 | priv->scan_ssid_len = req->essid_len; | ||
1117 | memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); | ||
1118 | lbs_deb_wext("set_scan, essid '%s'\n", | ||
1119 | print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); | ||
1120 | } else { | ||
1121 | priv->scan_ssid_len = 0; | ||
1122 | } | ||
1123 | |||
1124 | if (!delayed_work_pending(&priv->scan_work)) | ||
1125 | queue_delayed_work(priv->work_thread, &priv->scan_work, | ||
1126 | msecs_to_jiffies(50)); | ||
1127 | /* set marker that currently a scan is taking place */ | ||
1128 | priv->scan_channel = -1; | ||
1129 | |||
1130 | if (priv->surpriseremoved) | ||
1131 | ret = -EIO; | ||
1132 | |||
1133 | out: | ||
1134 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1135 | return ret; | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /** | ||
1140 | * @brief Handle Retrieve scan table ioctl | ||
1141 | * | ||
1142 | * @param dev A pointer to net_device structure | ||
1143 | * @param info A pointer to iw_request_info structure | ||
1144 | * @param dwrq A pointer to iw_point structure | ||
1145 | * @param extra A pointer to extra data buf | ||
1146 | * | ||
1147 | * @return 0 --success, otherwise fail | ||
1148 | */ | ||
1149 | int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
1150 | struct iw_point *dwrq, char *extra) | ||
1151 | { | ||
1152 | #define SCAN_ITEM_SIZE 128 | ||
1153 | struct lbs_private *priv = dev->ml_priv; | ||
1154 | int err = 0; | ||
1155 | char *ev = extra; | ||
1156 | char *stop = ev + dwrq->length; | ||
1157 | struct bss_descriptor *iter_bss; | ||
1158 | struct bss_descriptor *safe; | ||
1159 | |||
1160 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1161 | |||
1162 | /* iwlist should wait until the current scan is finished */ | ||
1163 | if (priv->scan_channel) | ||
1164 | return -EAGAIN; | ||
1165 | |||
1166 | /* Update RSSI if current BSS is a locally created ad-hoc BSS */ | ||
1167 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { | ||
1168 | err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, | ||
1169 | CMD_OPTION_WAITFORRSP, 0, NULL); | ||
1170 | if (err) | ||
1171 | goto out; | ||
1172 | } | ||
1173 | |||
1174 | mutex_lock(&priv->lock); | ||
1175 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { | ||
1176 | char *next_ev; | ||
1177 | unsigned long stale_time; | ||
1178 | |||
1179 | if (stop - ev < SCAN_ITEM_SIZE) { | ||
1180 | err = -E2BIG; | ||
1181 | break; | ||
1182 | } | ||
1183 | |||
1184 | /* For mesh device, list only mesh networks */ | ||
1185 | if (dev == priv->mesh_dev && !iter_bss->mesh) | ||
1186 | continue; | ||
1187 | |||
1188 | /* Prune old an old scan result */ | ||
1189 | stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; | ||
1190 | if (time_after(jiffies, stale_time)) { | ||
1191 | list_move_tail(&iter_bss->list, &priv->network_free_list); | ||
1192 | clear_bss_descriptor(iter_bss); | ||
1193 | continue; | ||
1194 | } | ||
1195 | |||
1196 | /* Translate to WE format this entry */ | ||
1197 | next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss); | ||
1198 | if (next_ev == NULL) | ||
1199 | continue; | ||
1200 | ev = next_ev; | ||
1201 | } | ||
1202 | mutex_unlock(&priv->lock); | ||
1203 | |||
1204 | dwrq->length = (ev - extra); | ||
1205 | dwrq->flags = 0; | ||
1206 | out: | ||
1207 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); | ||
1208 | return err; | ||
1209 | } | ||
1210 | |||
1211 | |||
1212 | |||
1213 | |||
1214 | /*********************************************************************/ | ||
1215 | /* */ | ||
1216 | /* Command execution */ | ||
1217 | /* */ | ||
1218 | /*********************************************************************/ | ||
1219 | |||
1220 | |||
1221 | /** | ||
1222 | * @brief This function handles the command response of scan | ||
1223 | * | ||
1224 | * Called from handle_cmd_response() in cmdrespc. | ||
1225 | * | ||
1226 | * The response buffer for the scan command has the following | ||
1227 | * memory layout: | ||
1228 | * | ||
1229 | * .-----------------------------------------------------------. | ||
1230 | * | header (4 * sizeof(u16)): Standard command response hdr | | ||
1231 | * .-----------------------------------------------------------. | ||
1232 | * | bufsize (u16) : sizeof the BSS Description data | | ||
1233 | * .-----------------------------------------------------------. | ||
1234 | * | NumOfSet (u8) : Number of BSS Descs returned | | ||
1235 | * .-----------------------------------------------------------. | ||
1236 | * | BSSDescription data (variable, size given in bufsize) | | ||
1237 | * .-----------------------------------------------------------. | ||
1238 | * | TLV data (variable, size calculated using header->size, | | ||
1239 | * | bufsize and sizeof the fixed fields above) | | ||
1240 | * .-----------------------------------------------------------. | ||
1241 | * | ||
1242 | * @param priv A pointer to struct lbs_private structure | ||
1243 | * @param resp A pointer to cmd_ds_command | ||
1244 | * | ||
1245 | * @return 0 or -1 | ||
1246 | */ | ||
1247 | static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, | ||
1248 | struct cmd_header *resp) | ||
1249 | { | ||
1250 | struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; | ||
1251 | struct bss_descriptor *iter_bss; | ||
1252 | struct bss_descriptor *safe; | ||
1253 | uint8_t *bssinfo; | ||
1254 | uint16_t scanrespsize; | ||
1255 | int bytesleft; | ||
1256 | int idx; | ||
1257 | int tlvbufsize; | ||
1258 | int ret; | ||
1259 | |||
1260 | lbs_deb_enter(LBS_DEB_SCAN); | ||
1261 | |||
1262 | /* Prune old entries from scan table */ | ||
1263 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { | ||
1264 | unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; | ||
1265 | if (time_before(jiffies, stale_time)) | ||
1266 | continue; | ||
1267 | list_move_tail (&iter_bss->list, &priv->network_free_list); | ||
1268 | clear_bss_descriptor(iter_bss); | ||
1269 | } | ||
1270 | |||
1271 | if (scanresp->nr_sets > MAX_NETWORK_COUNT) { | ||
1272 | lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n", | ||
1273 | scanresp->nr_sets, MAX_NETWORK_COUNT); | ||
1274 | ret = -1; | ||
1275 | goto done; | ||
1276 | } | ||
1277 | |||
1278 | bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); | ||
1279 | lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); | ||
1280 | |||
1281 | scanrespsize = le16_to_cpu(resp->size); | ||
1282 | lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets); | ||
1283 | |||
1284 | bssinfo = scanresp->bssdesc_and_tlvbuffer; | ||
1285 | |||
1286 | /* The size of the TLV buffer is equal to the entire command response | ||
1287 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the | ||
1288 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command | ||
1289 | * response header (sizeof(struct cmd_header)) | ||
1290 | */ | ||
1291 | tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) | ||
1292 | + sizeof(scanresp->nr_sets) | ||
1293 | + sizeof(struct cmd_header)); | ||
1294 | |||
1295 | /* | ||
1296 | * Process each scan response returned (scanresp->nr_sets). Save | ||
1297 | * the information in the newbssentry and then insert into the | ||
1298 | * driver scan table either as an update to an existing entry | ||
1299 | * or as an addition at the end of the table | ||
1300 | */ | ||
1301 | for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) { | ||
1302 | struct bss_descriptor new; | ||
1303 | struct bss_descriptor *found = NULL; | ||
1304 | struct bss_descriptor *oldest = NULL; | ||
1305 | |||
1306 | /* Process the data fields and IEs returned for this BSS */ | ||
1307 | memset(&new, 0, sizeof (struct bss_descriptor)); | ||
1308 | if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) { | ||
1309 | /* error parsing the scan response, skipped */ | ||
1310 | lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); | ||
1311 | continue; | ||
1312 | } | ||
1313 | |||
1314 | /* Try to find this bss in the scan table */ | ||
1315 | list_for_each_entry (iter_bss, &priv->network_list, list) { | ||
1316 | if (is_same_network(iter_bss, &new)) { | ||
1317 | found = iter_bss; | ||
1318 | break; | ||
1319 | } | ||
1320 | |||
1321 | if ((oldest == NULL) || | ||
1322 | (iter_bss->last_scanned < oldest->last_scanned)) | ||
1323 | oldest = iter_bss; | ||
1324 | } | ||
1325 | |||
1326 | if (found) { | ||
1327 | /* found, clear it */ | ||
1328 | clear_bss_descriptor(found); | ||
1329 | } else if (!list_empty(&priv->network_free_list)) { | ||
1330 | /* Pull one from the free list */ | ||
1331 | found = list_entry(priv->network_free_list.next, | ||
1332 | struct bss_descriptor, list); | ||
1333 | list_move_tail(&found->list, &priv->network_list); | ||
1334 | } else if (oldest) { | ||
1335 | /* If there are no more slots, expire the oldest */ | ||
1336 | found = oldest; | ||
1337 | clear_bss_descriptor(found); | ||
1338 | list_move_tail(&found->list, &priv->network_list); | ||
1339 | } else { | ||
1340 | continue; | ||
1341 | } | ||
1342 | |||
1343 | lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid); | ||
1344 | |||
1345 | /* Copy the locally created newbssentry to the scan table */ | ||
1346 | memcpy(found, &new, offsetof(struct bss_descriptor, list)); | ||
1347 | } | ||
1348 | |||
1349 | ret = 0; | ||
1350 | |||
1351 | done: | ||
1352 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||
1353 | return ret; | ||
1354 | } | ||
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h deleted file mode 100644 index 8fb1706d7526..000000000000 --- a/drivers/net/wireless/libertas/scan.h +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /** | ||
2 | * Interface for the wlan network scan routines | ||
3 | * | ||
4 | * Driver interface functions and type declarations for the scan module | ||
5 | * implemented in scan.c. | ||
6 | */ | ||
7 | #ifndef _LBS_SCAN_H | ||
8 | #define _LBS_SCAN_H | ||
9 | |||
10 | #include <net/iw_handler.h> | ||
11 | |||
12 | struct lbs_private; | ||
13 | |||
14 | #define MAX_NETWORK_COUNT 128 | ||
15 | |||
16 | /** Chan-freq-TxPower mapping table*/ | ||
17 | struct chan_freq_power { | ||
18 | /** channel Number */ | ||
19 | u16 channel; | ||
20 | /** frequency of this channel */ | ||
21 | u32 freq; | ||
22 | /** Max allowed Tx power level */ | ||
23 | u16 maxtxpower; | ||
24 | /** TRUE:channel unsupported; FLASE:supported*/ | ||
25 | u8 unsupported; | ||
26 | }; | ||
27 | |||
28 | /** region-band mapping table*/ | ||
29 | struct region_channel { | ||
30 | /** TRUE if this entry is valid */ | ||
31 | u8 valid; | ||
32 | /** region code for US, Japan ... */ | ||
33 | u8 region; | ||
34 | /** band B/G/A, used for BAND_CONFIG cmd */ | ||
35 | u8 band; | ||
36 | /** Actual No. of elements in the array below */ | ||
37 | u8 nrcfp; | ||
38 | /** chan-freq-txpower mapping table*/ | ||
39 | struct chan_freq_power *CFP; | ||
40 | }; | ||
41 | |||
42 | /** | ||
43 | * @brief Maximum number of channels that can be sent in a setuserscan ioctl | ||
44 | */ | ||
45 | #define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 | ||
46 | |||
47 | int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); | ||
48 | |||
49 | int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); | ||
50 | |||
51 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, | ||
52 | u8 ssid_len); | ||
53 | |||
54 | int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
55 | struct iw_point *dwrq, char *extra); | ||
56 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
57 | union iwreq_data *wrqu, char *extra); | ||
58 | |||
59 | int lbs_scan_networks(struct lbs_private *priv, int full_scan); | ||
60 | |||
61 | void lbs_scan_worker(struct work_struct *work); | ||
62 | |||
63 | #endif | ||
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a9bf658659eb..411a3bbf035e 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c | |||
@@ -4,13 +4,13 @@ | |||
4 | #include <linux/netdevice.h> | 4 | #include <linux/netdevice.h> |
5 | #include <linux/etherdevice.h> | 5 | #include <linux/etherdevice.h> |
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <net/cfg80211.h> | ||
7 | 8 | ||
8 | #include "host.h" | 9 | #include "host.h" |
9 | #include "radiotap.h" | 10 | #include "radiotap.h" |
10 | #include "decl.h" | 11 | #include "decl.h" |
11 | #include "defs.h" | 12 | #include "defs.h" |
12 | #include "dev.h" | 13 | #include "dev.h" |
13 | #include "wext.h" | ||
14 | 14 | ||
15 | /** | 15 | /** |
16 | * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE | 16 | * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE |
@@ -111,7 +111,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
111 | p802x_hdr = skb->data; | 111 | p802x_hdr = skb->data; |
112 | pkt_len = skb->len; | 112 | pkt_len = skb->len; |
113 | 113 | ||
114 | if (dev == priv->rtap_net_dev) { | 114 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { |
115 | struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; | 115 | struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; |
116 | 116 | ||
117 | /* set txpd fields from the radiotap header */ | 117 | /* set txpd fields from the radiotap header */ |
@@ -147,7 +147,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
147 | dev->stats.tx_packets++; | 147 | dev->stats.tx_packets++; |
148 | dev->stats.tx_bytes += skb->len; | 148 | dev->stats.tx_bytes += skb->len; |
149 | 149 | ||
150 | if (priv->monitormode) { | 150 | if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { |
151 | /* Keep the skb to echo it back once Tx feedback is | 151 | /* Keep the skb to echo it back once Tx feedback is |
152 | received from FW */ | 152 | received from FW */ |
153 | skb_orphan(skb); | 153 | skb_orphan(skb); |
@@ -158,6 +158,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
158 | free: | 158 | free: |
159 | dev_kfree_skb_any(skb); | 159 | dev_kfree_skb_any(skb); |
160 | } | 160 | } |
161 | |||
161 | unlock: | 162 | unlock: |
162 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 163 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
163 | wake_up(&priv->waitq); | 164 | wake_up(&priv->waitq); |
@@ -179,7 +180,8 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) | |||
179 | { | 180 | { |
180 | struct tx_radiotap_hdr *radiotap_hdr; | 181 | struct tx_radiotap_hdr *radiotap_hdr; |
181 | 182 | ||
182 | if (!priv->monitormode || priv->currenttxskb == NULL) | 183 | if (!priv->wdev->iftype == NL80211_IFTYPE_MONITOR || |
184 | priv->currenttxskb == NULL) | ||
183 | return; | 185 | return; |
184 | 186 | ||
185 | radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; | 187 | radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; |
@@ -188,7 +190,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) | |||
188 | (1 + priv->txretrycount - try_count) : 0; | 190 | (1 + priv->txretrycount - try_count) : 0; |
189 | 191 | ||
190 | priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, | 192 | priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, |
191 | priv->rtap_net_dev); | 193 | priv->dev); |
192 | netif_rx(priv->currenttxskb); | 194 | netif_rx(priv->currenttxskb); |
193 | 195 | ||
194 | priv->currenttxskb = NULL; | 196 | priv->currenttxskb = NULL; |
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c deleted file mode 100644 index f96a96031a50..000000000000 --- a/drivers/net/wireless/libertas/wext.c +++ /dev/null | |||
@@ -1,2353 +0,0 @@ | |||
1 | /** | ||
2 | * This file contains ioctl functions | ||
3 | */ | ||
4 | #include <linux/ctype.h> | ||
5 | #include <linux/slab.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/if.h> | ||
8 | #include <linux/if_arp.h> | ||
9 | #include <linux/wireless.h> | ||
10 | #include <linux/bitops.h> | ||
11 | |||
12 | #include <net/lib80211.h> | ||
13 | #include <net/iw_handler.h> | ||
14 | |||
15 | #include "host.h" | ||
16 | #include "radiotap.h" | ||
17 | #include "decl.h" | ||
18 | #include "defs.h" | ||
19 | #include "dev.h" | ||
20 | #include "wext.h" | ||
21 | #include "scan.h" | ||
22 | #include "assoc.h" | ||
23 | #include "cmd.h" | ||
24 | |||
25 | |||
26 | static inline void lbs_postpone_association_work(struct lbs_private *priv) | ||
27 | { | ||
28 | if (priv->surpriseremoved) | ||
29 | return; | ||
30 | cancel_delayed_work(&priv->assoc_work); | ||
31 | queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); | ||
32 | } | ||
33 | |||
34 | static inline void lbs_do_association_work(struct lbs_private *priv) | ||
35 | { | ||
36 | if (priv->surpriseremoved) | ||
37 | return; | ||
38 | cancel_delayed_work(&priv->assoc_work); | ||
39 | queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); | ||
40 | } | ||
41 | |||
42 | static inline void lbs_cancel_association_work(struct lbs_private *priv) | ||
43 | { | ||
44 | cancel_delayed_work(&priv->assoc_work); | ||
45 | kfree(priv->pending_assoc_req); | ||
46 | priv->pending_assoc_req = NULL; | ||
47 | } | ||
48 | |||
49 | void lbs_send_disconnect_notification(struct lbs_private *priv) | ||
50 | { | ||
51 | union iwreq_data wrqu; | ||
52 | |||
53 | memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); | ||
54 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
55 | wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | ||
56 | } | ||
57 | |||
58 | static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) | ||
59 | { | ||
60 | union iwreq_data iwrq; | ||
61 | u8 buf[50]; | ||
62 | |||
63 | lbs_deb_enter(LBS_DEB_WEXT); | ||
64 | |||
65 | memset(&iwrq, 0, sizeof(union iwreq_data)); | ||
66 | memset(buf, 0, sizeof(buf)); | ||
67 | |||
68 | snprintf(buf, sizeof(buf) - 1, "%s", str); | ||
69 | |||
70 | iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; | ||
71 | |||
72 | /* Send Event to upper layer */ | ||
73 | lbs_deb_wext("event indication string %s\n", (char *)buf); | ||
74 | lbs_deb_wext("event indication length %d\n", iwrq.data.length); | ||
75 | lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); | ||
76 | |||
77 | wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); | ||
78 | |||
79 | lbs_deb_leave(LBS_DEB_WEXT); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * @brief This function handles MIC failure event. | ||
84 | * | ||
85 | * @param priv A pointer to struct lbs_private structure | ||
86 | * @para event the event id | ||
87 | * @return n/a | ||
88 | */ | ||
89 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) | ||
90 | { | ||
91 | char buf[50]; | ||
92 | |||
93 | lbs_deb_enter(LBS_DEB_CMD); | ||
94 | memset(buf, 0, sizeof(buf)); | ||
95 | |||
96 | sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); | ||
97 | |||
98 | if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) | ||
99 | strcat(buf, "unicast "); | ||
100 | else | ||
101 | strcat(buf, "multicast "); | ||
102 | |||
103 | lbs_send_iwevcustom_event(priv, buf); | ||
104 | lbs_deb_leave(LBS_DEB_CMD); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * @brief Find the channel frequency power info with specific channel | ||
109 | * | ||
110 | * @param priv A pointer to struct lbs_private structure | ||
111 | * @param band it can be BAND_A, BAND_G or BAND_B | ||
112 | * @param channel the channel for looking | ||
113 | * @return A pointer to struct chan_freq_power structure or NULL if not find. | ||
114 | */ | ||
115 | struct chan_freq_power *lbs_find_cfp_by_band_and_channel( | ||
116 | struct lbs_private *priv, | ||
117 | u8 band, | ||
118 | u16 channel) | ||
119 | { | ||
120 | struct chan_freq_power *cfp = NULL; | ||
121 | struct region_channel *rc; | ||
122 | int i, j; | ||
123 | |||
124 | for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { | ||
125 | rc = &priv->region_channel[j]; | ||
126 | |||
127 | if (!rc->valid || !rc->CFP) | ||
128 | continue; | ||
129 | if (rc->band != band) | ||
130 | continue; | ||
131 | for (i = 0; i < rc->nrcfp; i++) { | ||
132 | if (rc->CFP[i].channel == channel) { | ||
133 | cfp = &rc->CFP[i]; | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | if (!cfp && channel) | ||
140 | lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find " | ||
141 | "cfp by band %d / channel %d\n", band, channel); | ||
142 | |||
143 | return cfp; | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * @brief Find the channel frequency power info with specific frequency | ||
148 | * | ||
149 | * @param priv A pointer to struct lbs_private structure | ||
150 | * @param band it can be BAND_A, BAND_G or BAND_B | ||
151 | * @param freq the frequency for looking | ||
152 | * @return A pointer to struct chan_freq_power structure or NULL if not find. | ||
153 | */ | ||
154 | static struct chan_freq_power *find_cfp_by_band_and_freq( | ||
155 | struct lbs_private *priv, | ||
156 | u8 band, | ||
157 | u32 freq) | ||
158 | { | ||
159 | struct chan_freq_power *cfp = NULL; | ||
160 | struct region_channel *rc; | ||
161 | int i, j; | ||
162 | |||
163 | for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { | ||
164 | rc = &priv->region_channel[j]; | ||
165 | |||
166 | if (!rc->valid || !rc->CFP) | ||
167 | continue; | ||
168 | if (rc->band != band) | ||
169 | continue; | ||
170 | for (i = 0; i < rc->nrcfp; i++) { | ||
171 | if (rc->CFP[i].freq == freq) { | ||
172 | cfp = &rc->CFP[i]; | ||
173 | break; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | if (!cfp && freq) | ||
179 | lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by " | ||
180 | "band %d / freq %d\n", band, freq); | ||
181 | |||
182 | return cfp; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @brief Copy active data rates based on adapter mode and status | ||
187 | * | ||
188 | * @param priv A pointer to struct lbs_private structure | ||
189 | * @param rate The buf to return the active rates | ||
190 | */ | ||
191 | static void copy_active_data_rates(struct lbs_private *priv, u8 *rates) | ||
192 | { | ||
193 | lbs_deb_enter(LBS_DEB_WEXT); | ||
194 | |||
195 | if ((priv->connect_status != LBS_CONNECTED) && | ||
196 | !lbs_mesh_connected(priv)) | ||
197 | memcpy(rates, lbs_bg_rates, MAX_RATES); | ||
198 | else | ||
199 | memcpy(rates, priv->curbssparams.rates, MAX_RATES); | ||
200 | |||
201 | lbs_deb_leave(LBS_DEB_WEXT); | ||
202 | } | ||
203 | |||
204 | static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, | ||
205 | char *cwrq, char *extra) | ||
206 | { | ||
207 | |||
208 | lbs_deb_enter(LBS_DEB_WEXT); | ||
209 | |||
210 | /* We could add support for 802.11n here as needed. Jean II */ | ||
211 | snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); | ||
212 | |||
213 | lbs_deb_leave(LBS_DEB_WEXT); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, | ||
218 | struct iw_freq *fwrq, char *extra) | ||
219 | { | ||
220 | struct lbs_private *priv = dev->ml_priv; | ||
221 | struct chan_freq_power *cfp; | ||
222 | |||
223 | lbs_deb_enter(LBS_DEB_WEXT); | ||
224 | |||
225 | cfp = lbs_find_cfp_by_band_and_channel(priv, 0, | ||
226 | priv->channel); | ||
227 | |||
228 | if (!cfp) { | ||
229 | if (priv->channel) | ||
230 | lbs_deb_wext("invalid channel %d\n", | ||
231 | priv->channel); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | fwrq->m = (long)cfp->freq * 100000; | ||
236 | fwrq->e = 1; | ||
237 | |||
238 | lbs_deb_wext("freq %u\n", fwrq->m); | ||
239 | lbs_deb_leave(LBS_DEB_WEXT); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, | ||
244 | struct sockaddr *awrq, char *extra) | ||
245 | { | ||
246 | struct lbs_private *priv = dev->ml_priv; | ||
247 | |||
248 | lbs_deb_enter(LBS_DEB_WEXT); | ||
249 | |||
250 | if (priv->connect_status == LBS_CONNECTED) { | ||
251 | memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); | ||
252 | } else { | ||
253 | memset(awrq->sa_data, 0, ETH_ALEN); | ||
254 | } | ||
255 | awrq->sa_family = ARPHRD_ETHER; | ||
256 | |||
257 | lbs_deb_leave(LBS_DEB_WEXT); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, | ||
262 | struct iw_point *dwrq, char *extra) | ||
263 | { | ||
264 | struct lbs_private *priv = dev->ml_priv; | ||
265 | |||
266 | lbs_deb_enter(LBS_DEB_WEXT); | ||
267 | |||
268 | /* | ||
269 | * Check the size of the string | ||
270 | */ | ||
271 | |||
272 | if (dwrq->length > 16) { | ||
273 | return -E2BIG; | ||
274 | } | ||
275 | |||
276 | mutex_lock(&priv->lock); | ||
277 | memset(priv->nodename, 0, sizeof(priv->nodename)); | ||
278 | memcpy(priv->nodename, extra, dwrq->length); | ||
279 | mutex_unlock(&priv->lock); | ||
280 | |||
281 | lbs_deb_leave(LBS_DEB_WEXT); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, | ||
286 | struct iw_point *dwrq, char *extra) | ||
287 | { | ||
288 | struct lbs_private *priv = dev->ml_priv; | ||
289 | |||
290 | lbs_deb_enter(LBS_DEB_WEXT); | ||
291 | |||
292 | dwrq->length = strlen(priv->nodename); | ||
293 | memcpy(extra, priv->nodename, dwrq->length); | ||
294 | extra[dwrq->length] = '\0'; | ||
295 | |||
296 | dwrq->flags = 1; /* active */ | ||
297 | |||
298 | lbs_deb_leave(LBS_DEB_WEXT); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | #ifdef CONFIG_LIBERTAS_MESH | ||
303 | static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, | ||
304 | struct iw_point *dwrq, char *extra) | ||
305 | { | ||
306 | struct lbs_private *priv = dev->ml_priv; | ||
307 | |||
308 | lbs_deb_enter(LBS_DEB_WEXT); | ||
309 | |||
310 | /* Use nickname to indicate that mesh is on */ | ||
311 | |||
312 | if (lbs_mesh_connected(priv)) { | ||
313 | strncpy(extra, "Mesh", 12); | ||
314 | extra[12] = '\0'; | ||
315 | dwrq->length = strlen(extra); | ||
316 | } | ||
317 | |||
318 | else { | ||
319 | extra[0] = '\0'; | ||
320 | dwrq->length = 0; | ||
321 | } | ||
322 | |||
323 | lbs_deb_leave(LBS_DEB_WEXT); | ||
324 | return 0; | ||
325 | } | ||
326 | #endif | ||
327 | |||
328 | static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, | ||
329 | struct iw_param *vwrq, char *extra) | ||
330 | { | ||
331 | int ret = 0; | ||
332 | struct lbs_private *priv = dev->ml_priv; | ||
333 | u32 val = vwrq->value; | ||
334 | |||
335 | lbs_deb_enter(LBS_DEB_WEXT); | ||
336 | |||
337 | if (vwrq->disabled) | ||
338 | val = MRVDRV_RTS_MAX_VALUE; | ||
339 | |||
340 | if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */ | ||
341 | return -EINVAL; | ||
342 | |||
343 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); | ||
344 | |||
345 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, | ||
350 | struct iw_param *vwrq, char *extra) | ||
351 | { | ||
352 | struct lbs_private *priv = dev->ml_priv; | ||
353 | int ret = 0; | ||
354 | u16 val = 0; | ||
355 | |||
356 | lbs_deb_enter(LBS_DEB_WEXT); | ||
357 | |||
358 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); | ||
359 | if (ret) | ||
360 | goto out; | ||
361 | |||
362 | vwrq->value = val; | ||
363 | vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */ | ||
364 | vwrq->fixed = 1; | ||
365 | |||
366 | out: | ||
367 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, | ||
372 | struct iw_param *vwrq, char *extra) | ||
373 | { | ||
374 | struct lbs_private *priv = dev->ml_priv; | ||
375 | int ret = 0; | ||
376 | u32 val = vwrq->value; | ||
377 | |||
378 | lbs_deb_enter(LBS_DEB_WEXT); | ||
379 | |||
380 | if (vwrq->disabled) | ||
381 | val = MRVDRV_FRAG_MAX_VALUE; | ||
382 | |||
383 | if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE) | ||
384 | return -EINVAL; | ||
385 | |||
386 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val); | ||
387 | |||
388 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, | ||
393 | struct iw_param *vwrq, char *extra) | ||
394 | { | ||
395 | struct lbs_private *priv = dev->ml_priv; | ||
396 | int ret = 0; | ||
397 | u16 val = 0; | ||
398 | |||
399 | lbs_deb_enter(LBS_DEB_WEXT); | ||
400 | |||
401 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); | ||
402 | if (ret) | ||
403 | goto out; | ||
404 | |||
405 | vwrq->value = val; | ||
406 | vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE) | ||
407 | || (val > MRVDRV_FRAG_MAX_VALUE)); | ||
408 | vwrq->fixed = 1; | ||
409 | |||
410 | out: | ||
411 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int lbs_get_mode(struct net_device *dev, | ||
416 | struct iw_request_info *info, u32 * uwrq, char *extra) | ||
417 | { | ||
418 | struct lbs_private *priv = dev->ml_priv; | ||
419 | |||
420 | lbs_deb_enter(LBS_DEB_WEXT); | ||
421 | |||
422 | *uwrq = priv->mode; | ||
423 | |||
424 | lbs_deb_leave(LBS_DEB_WEXT); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | #ifdef CONFIG_LIBERTAS_MESH | ||
429 | static int mesh_wlan_get_mode(struct net_device *dev, | ||
430 | struct iw_request_info *info, u32 * uwrq, | ||
431 | char *extra) | ||
432 | { | ||
433 | lbs_deb_enter(LBS_DEB_WEXT); | ||
434 | |||
435 | *uwrq = IW_MODE_REPEAT; | ||
436 | |||
437 | lbs_deb_leave(LBS_DEB_WEXT); | ||
438 | return 0; | ||
439 | } | ||
440 | #endif | ||
441 | |||
442 | static int lbs_get_txpow(struct net_device *dev, | ||
443 | struct iw_request_info *info, | ||
444 | struct iw_param *vwrq, char *extra) | ||
445 | { | ||
446 | struct lbs_private *priv = dev->ml_priv; | ||
447 | s16 curlevel = 0; | ||
448 | int ret = 0; | ||
449 | |||
450 | lbs_deb_enter(LBS_DEB_WEXT); | ||
451 | |||
452 | if (!priv->radio_on) { | ||
453 | lbs_deb_wext("tx power off\n"); | ||
454 | vwrq->value = 0; | ||
455 | vwrq->disabled = 1; | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); | ||
460 | if (ret) | ||
461 | goto out; | ||
462 | |||
463 | lbs_deb_wext("tx power level %d dbm\n", curlevel); | ||
464 | priv->txpower_cur = curlevel; | ||
465 | |||
466 | vwrq->value = curlevel; | ||
467 | vwrq->fixed = 1; | ||
468 | vwrq->disabled = 0; | ||
469 | vwrq->flags = IW_TXPOW_DBM; | ||
470 | |||
471 | out: | ||
472 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, | ||
477 | struct iw_param *vwrq, char *extra) | ||
478 | { | ||
479 | struct lbs_private *priv = dev->ml_priv; | ||
480 | int ret = 0; | ||
481 | u16 slimit = 0, llimit = 0; | ||
482 | |||
483 | lbs_deb_enter(LBS_DEB_WEXT); | ||
484 | |||
485 | if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) | ||
486 | return -EOPNOTSUPP; | ||
487 | |||
488 | /* The MAC has a 4-bit Total_Tx_Count register | ||
489 | Total_Tx_Count = 1 + Tx_Retry_Count */ | ||
490 | #define TX_RETRY_MIN 0 | ||
491 | #define TX_RETRY_MAX 14 | ||
492 | if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) | ||
493 | return -EINVAL; | ||
494 | |||
495 | /* Add 1 to convert retry count to try count */ | ||
496 | if (vwrq->flags & IW_RETRY_SHORT) | ||
497 | slimit = (u16) (vwrq->value + 1); | ||
498 | else if (vwrq->flags & IW_RETRY_LONG) | ||
499 | llimit = (u16) (vwrq->value + 1); | ||
500 | else | ||
501 | slimit = llimit = (u16) (vwrq->value + 1); /* set both */ | ||
502 | |||
503 | if (llimit) { | ||
504 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, | ||
505 | llimit); | ||
506 | if (ret) | ||
507 | goto out; | ||
508 | } | ||
509 | |||
510 | if (slimit) { | ||
511 | /* txretrycount follows the short retry limit */ | ||
512 | priv->txretrycount = slimit; | ||
513 | ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, | ||
514 | slimit); | ||
515 | if (ret) | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | out: | ||
520 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, | ||
525 | struct iw_param *vwrq, char *extra) | ||
526 | { | ||
527 | struct lbs_private *priv = dev->ml_priv; | ||
528 | int ret = 0; | ||
529 | u16 val = 0; | ||
530 | |||
531 | lbs_deb_enter(LBS_DEB_WEXT); | ||
532 | |||
533 | vwrq->disabled = 0; | ||
534 | |||
535 | if (vwrq->flags & IW_RETRY_LONG) { | ||
536 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val); | ||
537 | if (ret) | ||
538 | goto out; | ||
539 | |||
540 | /* Subtract 1 to convert try count to retry count */ | ||
541 | vwrq->value = val - 1; | ||
542 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | ||
543 | } else { | ||
544 | ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val); | ||
545 | if (ret) | ||
546 | goto out; | ||
547 | |||
548 | /* txretry count follows the short retry limit */ | ||
549 | priv->txretrycount = val; | ||
550 | /* Subtract 1 to convert try count to retry count */ | ||
551 | vwrq->value = val - 1; | ||
552 | vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; | ||
553 | } | ||
554 | |||
555 | out: | ||
556 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | static inline void sort_channels(struct iw_freq *freq, int num) | ||
561 | { | ||
562 | int i, j; | ||
563 | struct iw_freq temp; | ||
564 | |||
565 | for (i = 0; i < num; i++) | ||
566 | for (j = i + 1; j < num; j++) | ||
567 | if (freq[i].i > freq[j].i) { | ||
568 | temp.i = freq[i].i; | ||
569 | temp.m = freq[i].m; | ||
570 | |||
571 | freq[i].i = freq[j].i; | ||
572 | freq[i].m = freq[j].m; | ||
573 | |||
574 | freq[j].i = temp.i; | ||
575 | freq[j].m = temp.m; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | /* data rate listing | ||
580 | MULTI_BANDS: | ||
581 | abg a b b/g | ||
582 | Infra G(12) A(8) B(4) G(12) | ||
583 | Adhoc A+B(12) A(8) B(4) B(4) | ||
584 | |||
585 | non-MULTI_BANDS: | ||
586 | b b/g | ||
587 | Infra B(4) G(12) | ||
588 | Adhoc B(4) B(4) | ||
589 | */ | ||
590 | /** | ||
591 | * @brief Get Range Info | ||
592 | * | ||
593 | * @param dev A pointer to net_device structure | ||
594 | * @param info A pointer to iw_request_info structure | ||
595 | * @param vwrq A pointer to iw_param structure | ||
596 | * @param extra A pointer to extra data buf | ||
597 | * @return 0 --success, otherwise fail | ||
598 | */ | ||
599 | static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, | ||
600 | struct iw_point *dwrq, char *extra) | ||
601 | { | ||
602 | int i, j; | ||
603 | struct lbs_private *priv = dev->ml_priv; | ||
604 | struct iw_range *range = (struct iw_range *)extra; | ||
605 | struct chan_freq_power *cfp; | ||
606 | u8 rates[MAX_RATES + 1]; | ||
607 | |||
608 | lbs_deb_enter(LBS_DEB_WEXT); | ||
609 | |||
610 | dwrq->length = sizeof(struct iw_range); | ||
611 | memset(range, 0, sizeof(struct iw_range)); | ||
612 | |||
613 | range->min_nwid = 0; | ||
614 | range->max_nwid = 0; | ||
615 | |||
616 | memset(rates, 0, sizeof(rates)); | ||
617 | copy_active_data_rates(priv, rates); | ||
618 | range->num_bitrates = strnlen(rates, IW_MAX_BITRATES); | ||
619 | for (i = 0; i < range->num_bitrates; i++) | ||
620 | range->bitrate[i] = rates[i] * 500000; | ||
621 | range->num_bitrates = i; | ||
622 | lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES, | ||
623 | range->num_bitrates); | ||
624 | |||
625 | range->num_frequency = 0; | ||
626 | |||
627 | range->scan_capa = IW_SCAN_CAPA_ESSID; | ||
628 | |||
629 | for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) | ||
630 | && (j < ARRAY_SIZE(priv->region_channel)); j++) { | ||
631 | cfp = priv->region_channel[j].CFP; | ||
632 | for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) | ||
633 | && priv->region_channel[j].valid | ||
634 | && cfp | ||
635 | && (i < priv->region_channel[j].nrcfp); i++) { | ||
636 | range->freq[range->num_frequency].i = | ||
637 | (long)cfp->channel; | ||
638 | range->freq[range->num_frequency].m = | ||
639 | (long)cfp->freq * 100000; | ||
640 | range->freq[range->num_frequency].e = 1; | ||
641 | cfp++; | ||
642 | range->num_frequency++; | ||
643 | } | ||
644 | } | ||
645 | |||
646 | lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n", | ||
647 | IW_MAX_FREQUENCIES, range->num_frequency); | ||
648 | |||
649 | range->num_channels = range->num_frequency; | ||
650 | |||
651 | sort_channels(&range->freq[0], range->num_frequency); | ||
652 | |||
653 | /* | ||
654 | * Set an indication of the max TCP throughput in bit/s that we can | ||
655 | * expect using this interface | ||
656 | */ | ||
657 | if (i > 2) | ||
658 | range->throughput = 5000 * 1000; | ||
659 | else | ||
660 | range->throughput = 1500 * 1000; | ||
661 | |||
662 | range->min_rts = MRVDRV_RTS_MIN_VALUE; | ||
663 | range->max_rts = MRVDRV_RTS_MAX_VALUE; | ||
664 | range->min_frag = MRVDRV_FRAG_MIN_VALUE; | ||
665 | range->max_frag = MRVDRV_FRAG_MAX_VALUE; | ||
666 | |||
667 | range->encoding_size[0] = 5; | ||
668 | range->encoding_size[1] = 13; | ||
669 | range->num_encoding_sizes = 2; | ||
670 | range->max_encoding_tokens = 4; | ||
671 | |||
672 | /* | ||
673 | * Right now we support only "iwconfig ethX power on|off" | ||
674 | */ | ||
675 | range->pm_capa = IW_POWER_ON; | ||
676 | |||
677 | /* | ||
678 | * Minimum version we recommend | ||
679 | */ | ||
680 | range->we_version_source = 15; | ||
681 | |||
682 | /* | ||
683 | * Version we are compiled with | ||
684 | */ | ||
685 | range->we_version_compiled = WIRELESS_EXT; | ||
686 | |||
687 | range->retry_capa = IW_RETRY_LIMIT; | ||
688 | range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
689 | |||
690 | range->min_retry = TX_RETRY_MIN; | ||
691 | range->max_retry = TX_RETRY_MAX; | ||
692 | |||
693 | /* | ||
694 | * Set the qual, level and noise range values | ||
695 | */ | ||
696 | range->max_qual.qual = 100; | ||
697 | range->max_qual.level = 0; | ||
698 | range->max_qual.noise = 0; | ||
699 | range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
700 | |||
701 | range->avg_qual.qual = 70; | ||
702 | /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ | ||
703 | range->avg_qual.level = 0; | ||
704 | range->avg_qual.noise = 0; | ||
705 | range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
706 | |||
707 | range->sensitivity = 0; | ||
708 | |||
709 | /* Setup the supported power level ranges */ | ||
710 | memset(range->txpower, 0, sizeof(range->txpower)); | ||
711 | range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; | ||
712 | range->txpower[0] = priv->txpower_min; | ||
713 | range->txpower[1] = priv->txpower_max; | ||
714 | range->num_txpower = 2; | ||
715 | |||
716 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
717 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
718 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
719 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
720 | |||
721 | if (priv->fwcapinfo & FW_CAPINFO_WPA) { | ||
722 | range->enc_capa = IW_ENC_CAPA_WPA | ||
723 | | IW_ENC_CAPA_WPA2 | ||
724 | | IW_ENC_CAPA_CIPHER_TKIP | ||
725 | | IW_ENC_CAPA_CIPHER_CCMP; | ||
726 | } | ||
727 | |||
728 | lbs_deb_leave(LBS_DEB_WEXT); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, | ||
733 | struct iw_param *vwrq, char *extra) | ||
734 | { | ||
735 | struct lbs_private *priv = dev->ml_priv; | ||
736 | int ret = 0; | ||
737 | |||
738 | lbs_deb_enter(LBS_DEB_WEXT); | ||
739 | |||
740 | if (!(priv->fwcapinfo & FW_CAPINFO_PS)) { | ||
741 | if (vwrq->disabled) | ||
742 | return 0; | ||
743 | else | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | /* PS is currently supported only in Infrastructure mode | ||
748 | * Remove this check if it is to be supported in IBSS mode also | ||
749 | */ | ||
750 | |||
751 | if (vwrq->disabled) { | ||
752 | priv->psmode = LBS802_11POWERMODECAM; | ||
753 | if (priv->psstate != PS_STATE_FULL_POWER) { | ||
754 | lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); | ||
755 | } | ||
756 | |||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
761 | lbs_deb_wext( | ||
762 | "setting power timeout is not supported\n"); | ||
763 | return -EINVAL; | ||
764 | } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { | ||
765 | vwrq->value = vwrq->value / 1000; | ||
766 | if (!priv->enter_deep_sleep) { | ||
767 | lbs_pr_err("deep sleep feature is not implemented " | ||
768 | "for this interface driver\n"); | ||
769 | return -EINVAL; | ||
770 | } | ||
771 | |||
772 | if (priv->connect_status == LBS_CONNECTED) { | ||
773 | if ((priv->is_auto_deep_sleep_enabled) && | ||
774 | (vwrq->value == -1000)) { | ||
775 | lbs_exit_auto_deep_sleep(priv); | ||
776 | return 0; | ||
777 | } else { | ||
778 | lbs_pr_err("can't use deep sleep cmd in " | ||
779 | "connected state\n"); | ||
780 | return -EINVAL; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | if ((vwrq->value < 0) && (vwrq->value != -1000)) { | ||
785 | lbs_pr_err("unknown option\n"); | ||
786 | return -EINVAL; | ||
787 | } | ||
788 | |||
789 | if (vwrq->value > 0) { | ||
790 | if (!priv->is_auto_deep_sleep_enabled) { | ||
791 | priv->is_activity_detected = 0; | ||
792 | priv->auto_deep_sleep_timeout = vwrq->value; | ||
793 | lbs_enter_auto_deep_sleep(priv); | ||
794 | } else { | ||
795 | priv->auto_deep_sleep_timeout = vwrq->value; | ||
796 | lbs_deb_debugfs("auto deep sleep: " | ||
797 | "already enabled\n"); | ||
798 | } | ||
799 | return 0; | ||
800 | } else { | ||
801 | if (priv->is_auto_deep_sleep_enabled) { | ||
802 | lbs_exit_auto_deep_sleep(priv); | ||
803 | /* Try to exit deep sleep if auto */ | ||
804 | /*deep sleep disabled */ | ||
805 | ret = lbs_set_deep_sleep(priv, 0); | ||
806 | } | ||
807 | if (vwrq->value == 0) | ||
808 | ret = lbs_set_deep_sleep(priv, 1); | ||
809 | else if (vwrq->value == -1000) | ||
810 | ret = lbs_set_deep_sleep(priv, 0); | ||
811 | return ret; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | if (priv->psmode != LBS802_11POWERMODECAM) { | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | priv->psmode = LBS802_11POWERMODEMAX_PSP; | ||
820 | |||
821 | if (priv->connect_status == LBS_CONNECTED) { | ||
822 | lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP); | ||
823 | } | ||
824 | |||
825 | lbs_deb_leave(LBS_DEB_WEXT); | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, | ||
831 | struct iw_param *vwrq, char *extra) | ||
832 | { | ||
833 | struct lbs_private *priv = dev->ml_priv; | ||
834 | |||
835 | lbs_deb_enter(LBS_DEB_WEXT); | ||
836 | |||
837 | vwrq->value = 0; | ||
838 | vwrq->flags = 0; | ||
839 | vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM | ||
840 | || priv->connect_status == LBS_DISCONNECTED; | ||
841 | |||
842 | lbs_deb_leave(LBS_DEB_WEXT); | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) | ||
847 | { | ||
848 | enum { | ||
849 | POOR = 30, | ||
850 | FAIR = 60, | ||
851 | GOOD = 80, | ||
852 | VERY_GOOD = 90, | ||
853 | EXCELLENT = 95, | ||
854 | PERFECT = 100 | ||
855 | }; | ||
856 | struct lbs_private *priv = dev->ml_priv; | ||
857 | u32 rssi_qual; | ||
858 | u32 tx_qual; | ||
859 | u32 quality = 0; | ||
860 | int ret, stats_valid = 0; | ||
861 | u8 rssi; | ||
862 | u32 tx_retries; | ||
863 | struct cmd_ds_802_11_get_log log; | ||
864 | |||
865 | lbs_deb_enter(LBS_DEB_WEXT); | ||
866 | |||
867 | priv->wstats.status = priv->mode; | ||
868 | |||
869 | /* If we're not associated, all quality values are meaningless */ | ||
870 | if ((priv->connect_status != LBS_CONNECTED) && | ||
871 | !lbs_mesh_connected(priv)) | ||
872 | goto out; | ||
873 | |||
874 | /* Quality by RSSI */ | ||
875 | priv->wstats.qual.level = | ||
876 | CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
877 | priv->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
878 | |||
879 | if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
880 | priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
881 | } else { | ||
882 | priv->wstats.qual.noise = | ||
883 | CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
884 | } | ||
885 | |||
886 | lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level); | ||
887 | lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise); | ||
888 | |||
889 | rssi = priv->wstats.qual.level - priv->wstats.qual.noise; | ||
890 | if (rssi < 15) | ||
891 | rssi_qual = rssi * POOR / 10; | ||
892 | else if (rssi < 20) | ||
893 | rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; | ||
894 | else if (rssi < 30) | ||
895 | rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; | ||
896 | else if (rssi < 40) | ||
897 | rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / | ||
898 | 10 + GOOD; | ||
899 | else | ||
900 | rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / | ||
901 | 10 + VERY_GOOD; | ||
902 | quality = rssi_qual; | ||
903 | |||
904 | /* Quality by TX errors */ | ||
905 | priv->wstats.discard.retries = dev->stats.tx_errors; | ||
906 | |||
907 | memset(&log, 0, sizeof(log)); | ||
908 | log.hdr.size = cpu_to_le16(sizeof(log)); | ||
909 | ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); | ||
910 | if (ret) | ||
911 | goto out; | ||
912 | |||
913 | tx_retries = le32_to_cpu(log.retry); | ||
914 | |||
915 | if (tx_retries > 75) | ||
916 | tx_qual = (90 - tx_retries) * POOR / 15; | ||
917 | else if (tx_retries > 70) | ||
918 | tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; | ||
919 | else if (tx_retries > 65) | ||
920 | tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; | ||
921 | else if (tx_retries > 50) | ||
922 | tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / | ||
923 | 15 + GOOD; | ||
924 | else | ||
925 | tx_qual = (50 - tx_retries) * | ||
926 | (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; | ||
927 | quality = min(quality, tx_qual); | ||
928 | |||
929 | priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable); | ||
930 | priv->wstats.discard.retries = tx_retries; | ||
931 | priv->wstats.discard.misc = le32_to_cpu(log.ackfailure); | ||
932 | |||
933 | /* Calculate quality */ | ||
934 | priv->wstats.qual.qual = min_t(u8, quality, 100); | ||
935 | priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
936 | stats_valid = 1; | ||
937 | |||
938 | /* update stats asynchronously for future calls */ | ||
939 | ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, | ||
940 | 0, 0, NULL); | ||
941 | if (ret) | ||
942 | lbs_pr_err("RSSI command failed\n"); | ||
943 | out: | ||
944 | if (!stats_valid) { | ||
945 | priv->wstats.miss.beacon = 0; | ||
946 | priv->wstats.discard.retries = 0; | ||
947 | priv->wstats.qual.qual = 0; | ||
948 | priv->wstats.qual.level = 0; | ||
949 | priv->wstats.qual.noise = 0; | ||
950 | priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; | ||
951 | priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | | ||
952 | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; | ||
953 | } | ||
954 | |||
955 | lbs_deb_leave(LBS_DEB_WEXT); | ||
956 | return &priv->wstats; | ||
957 | |||
958 | |||
959 | } | ||
960 | |||
961 | static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, | ||
962 | struct iw_freq *fwrq, char *extra) | ||
963 | { | ||
964 | int ret = -EINVAL; | ||
965 | struct lbs_private *priv = dev->ml_priv; | ||
966 | struct chan_freq_power *cfp; | ||
967 | struct assoc_request * assoc_req; | ||
968 | |||
969 | lbs_deb_enter(LBS_DEB_WEXT); | ||
970 | |||
971 | mutex_lock(&priv->lock); | ||
972 | assoc_req = lbs_get_association_request(priv); | ||
973 | if (!assoc_req) { | ||
974 | ret = -ENOMEM; | ||
975 | goto out; | ||
976 | } | ||
977 | |||
978 | /* If setting by frequency, convert to a channel */ | ||
979 | if (fwrq->e == 1) { | ||
980 | long f = fwrq->m / 100000; | ||
981 | |||
982 | cfp = find_cfp_by_band_and_freq(priv, 0, f); | ||
983 | if (!cfp) { | ||
984 | lbs_deb_wext("invalid freq %ld\n", f); | ||
985 | goto out; | ||
986 | } | ||
987 | |||
988 | fwrq->e = 0; | ||
989 | fwrq->m = (int) cfp->channel; | ||
990 | } | ||
991 | |||
992 | /* Setting by channel number */ | ||
993 | if (fwrq->m > 1000 || fwrq->e > 0) { | ||
994 | goto out; | ||
995 | } | ||
996 | |||
997 | cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); | ||
998 | if (!cfp) { | ||
999 | goto out; | ||
1000 | } | ||
1001 | |||
1002 | assoc_req->channel = fwrq->m; | ||
1003 | ret = 0; | ||
1004 | |||
1005 | out: | ||
1006 | if (ret == 0) { | ||
1007 | set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags); | ||
1008 | lbs_postpone_association_work(priv); | ||
1009 | } else { | ||
1010 | lbs_cancel_association_work(priv); | ||
1011 | } | ||
1012 | mutex_unlock(&priv->lock); | ||
1013 | |||
1014 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1015 | return ret; | ||
1016 | } | ||
1017 | |||
1018 | #ifdef CONFIG_LIBERTAS_MESH | ||
1019 | static int lbs_mesh_set_freq(struct net_device *dev, | ||
1020 | struct iw_request_info *info, | ||
1021 | struct iw_freq *fwrq, char *extra) | ||
1022 | { | ||
1023 | struct lbs_private *priv = dev->ml_priv; | ||
1024 | struct chan_freq_power *cfp; | ||
1025 | int ret = -EINVAL; | ||
1026 | |||
1027 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1028 | |||
1029 | /* If setting by frequency, convert to a channel */ | ||
1030 | if (fwrq->e == 1) { | ||
1031 | long f = fwrq->m / 100000; | ||
1032 | |||
1033 | cfp = find_cfp_by_band_and_freq(priv, 0, f); | ||
1034 | if (!cfp) { | ||
1035 | lbs_deb_wext("invalid freq %ld\n", f); | ||
1036 | goto out; | ||
1037 | } | ||
1038 | |||
1039 | fwrq->e = 0; | ||
1040 | fwrq->m = (int) cfp->channel; | ||
1041 | } | ||
1042 | |||
1043 | /* Setting by channel number */ | ||
1044 | if (fwrq->m > 1000 || fwrq->e > 0) { | ||
1045 | goto out; | ||
1046 | } | ||
1047 | |||
1048 | cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); | ||
1049 | if (!cfp) { | ||
1050 | goto out; | ||
1051 | } | ||
1052 | |||
1053 | if (fwrq->m != priv->channel) { | ||
1054 | lbs_deb_wext("mesh channel change forces eth disconnect\n"); | ||
1055 | if (priv->mode == IW_MODE_INFRA) | ||
1056 | lbs_cmd_80211_deauthenticate(priv, | ||
1057 | priv->curbssparams.bssid, | ||
1058 | WLAN_REASON_DEAUTH_LEAVING); | ||
1059 | else if (priv->mode == IW_MODE_ADHOC) | ||
1060 | lbs_adhoc_stop(priv); | ||
1061 | } | ||
1062 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); | ||
1063 | lbs_update_channel(priv); | ||
1064 | ret = 0; | ||
1065 | |||
1066 | out: | ||
1067 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1068 | return ret; | ||
1069 | } | ||
1070 | #endif | ||
1071 | |||
1072 | static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, | ||
1073 | struct iw_param *vwrq, char *extra) | ||
1074 | { | ||
1075 | struct lbs_private *priv = dev->ml_priv; | ||
1076 | u8 new_rate = 0; | ||
1077 | int ret = -EINVAL; | ||
1078 | u8 rates[MAX_RATES + 1]; | ||
1079 | |||
1080 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1081 | |||
1082 | lbs_deb_wext("vwrq->value %d\n", vwrq->value); | ||
1083 | lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); | ||
1084 | |||
1085 | if (vwrq->fixed && vwrq->value == -1) | ||
1086 | goto out; | ||
1087 | |||
1088 | /* Auto rate? */ | ||
1089 | priv->enablehwauto = !vwrq->fixed; | ||
1090 | |||
1091 | if (vwrq->value == -1) | ||
1092 | priv->cur_rate = 0; | ||
1093 | else { | ||
1094 | if (vwrq->value % 100000) | ||
1095 | goto out; | ||
1096 | |||
1097 | new_rate = vwrq->value / 500000; | ||
1098 | priv->cur_rate = new_rate; | ||
1099 | /* the rest is only needed for lbs_set_data_rate() */ | ||
1100 | memset(rates, 0, sizeof(rates)); | ||
1101 | copy_active_data_rates(priv, rates); | ||
1102 | if (!memchr(rates, new_rate, sizeof(rates))) { | ||
1103 | lbs_pr_alert("fixed data rate 0x%X out of range\n", | ||
1104 | new_rate); | ||
1105 | goto out; | ||
1106 | } | ||
1107 | if (priv->fwrelease < 0x09000000) { | ||
1108 | ret = lbs_set_power_adapt_cfg(priv, 0, | ||
1109 | POW_ADAPT_DEFAULT_P0, | ||
1110 | POW_ADAPT_DEFAULT_P1, | ||
1111 | POW_ADAPT_DEFAULT_P2); | ||
1112 | if (ret) | ||
1113 | goto out; | ||
1114 | } | ||
1115 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1116 | TPC_DEFAULT_P2, 1); | ||
1117 | if (ret) | ||
1118 | goto out; | ||
1119 | } | ||
1120 | |||
1121 | /* Try the newer command first (Firmware Spec 5.1 and above) */ | ||
1122 | ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET); | ||
1123 | |||
1124 | /* Fallback to older version */ | ||
1125 | if (ret) | ||
1126 | ret = lbs_set_data_rate(priv, new_rate); | ||
1127 | |||
1128 | out: | ||
1129 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1130 | return ret; | ||
1131 | } | ||
1132 | |||
1133 | static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, | ||
1134 | struct iw_param *vwrq, char *extra) | ||
1135 | { | ||
1136 | struct lbs_private *priv = dev->ml_priv; | ||
1137 | |||
1138 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1139 | |||
1140 | if (priv->connect_status == LBS_CONNECTED) { | ||
1141 | vwrq->value = priv->cur_rate * 500000; | ||
1142 | |||
1143 | if (priv->enablehwauto) | ||
1144 | vwrq->fixed = 0; | ||
1145 | else | ||
1146 | vwrq->fixed = 1; | ||
1147 | |||
1148 | } else { | ||
1149 | vwrq->fixed = 0; | ||
1150 | vwrq->value = 0; | ||
1151 | } | ||
1152 | |||
1153 | lbs_deb_leave(LBS_DEB_WEXT); | ||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static int lbs_set_mode(struct net_device *dev, | ||
1158 | struct iw_request_info *info, u32 * uwrq, char *extra) | ||
1159 | { | ||
1160 | int ret = 0; | ||
1161 | struct lbs_private *priv = dev->ml_priv; | ||
1162 | struct assoc_request * assoc_req; | ||
1163 | |||
1164 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1165 | |||
1166 | if ( (*uwrq != IW_MODE_ADHOC) | ||
1167 | && (*uwrq != IW_MODE_INFRA) | ||
1168 | && (*uwrq != IW_MODE_AUTO)) { | ||
1169 | lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq); | ||
1170 | ret = -EINVAL; | ||
1171 | goto out; | ||
1172 | } | ||
1173 | |||
1174 | mutex_lock(&priv->lock); | ||
1175 | assoc_req = lbs_get_association_request(priv); | ||
1176 | if (!assoc_req) { | ||
1177 | ret = -ENOMEM; | ||
1178 | lbs_cancel_association_work(priv); | ||
1179 | } else { | ||
1180 | assoc_req->mode = *uwrq; | ||
1181 | set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); | ||
1182 | lbs_postpone_association_work(priv); | ||
1183 | lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq); | ||
1184 | } | ||
1185 | mutex_unlock(&priv->lock); | ||
1186 | |||
1187 | out: | ||
1188 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1192 | |||
1193 | /** | ||
1194 | * @brief Get Encryption key | ||
1195 | * | ||
1196 | * @param dev A pointer to net_device structure | ||
1197 | * @param info A pointer to iw_request_info structure | ||
1198 | * @param vwrq A pointer to iw_param structure | ||
1199 | * @param extra A pointer to extra data buf | ||
1200 | * @return 0 --success, otherwise fail | ||
1201 | */ | ||
1202 | static int lbs_get_encode(struct net_device *dev, | ||
1203 | struct iw_request_info *info, | ||
1204 | struct iw_point *dwrq, u8 * extra) | ||
1205 | { | ||
1206 | struct lbs_private *priv = dev->ml_priv; | ||
1207 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1208 | |||
1209 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1210 | |||
1211 | lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n", | ||
1212 | dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx); | ||
1213 | |||
1214 | dwrq->flags = 0; | ||
1215 | |||
1216 | /* Authentication method */ | ||
1217 | switch (priv->secinfo.auth_mode) { | ||
1218 | case IW_AUTH_ALG_OPEN_SYSTEM: | ||
1219 | dwrq->flags = IW_ENCODE_OPEN; | ||
1220 | break; | ||
1221 | |||
1222 | case IW_AUTH_ALG_SHARED_KEY: | ||
1223 | case IW_AUTH_ALG_LEAP: | ||
1224 | dwrq->flags = IW_ENCODE_RESTRICTED; | ||
1225 | break; | ||
1226 | default: | ||
1227 | dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; | ||
1228 | break; | ||
1229 | } | ||
1230 | |||
1231 | memset(extra, 0, 16); | ||
1232 | |||
1233 | mutex_lock(&priv->lock); | ||
1234 | |||
1235 | /* Default to returning current transmit key */ | ||
1236 | if (index < 0) | ||
1237 | index = priv->wep_tx_keyidx; | ||
1238 | |||
1239 | if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) { | ||
1240 | memcpy(extra, priv->wep_keys[index].key, | ||
1241 | priv->wep_keys[index].len); | ||
1242 | dwrq->length = priv->wep_keys[index].len; | ||
1243 | |||
1244 | dwrq->flags |= (index + 1); | ||
1245 | /* Return WEP enabled */ | ||
1246 | dwrq->flags &= ~IW_ENCODE_DISABLED; | ||
1247 | } else if ((priv->secinfo.WPAenabled) | ||
1248 | || (priv->secinfo.WPA2enabled)) { | ||
1249 | /* return WPA enabled */ | ||
1250 | dwrq->flags &= ~IW_ENCODE_DISABLED; | ||
1251 | dwrq->flags |= IW_ENCODE_NOKEY; | ||
1252 | } else { | ||
1253 | dwrq->flags |= IW_ENCODE_DISABLED; | ||
1254 | } | ||
1255 | |||
1256 | mutex_unlock(&priv->lock); | ||
1257 | |||
1258 | lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n", | ||
1259 | extra[0], extra[1], extra[2], | ||
1260 | extra[3], extra[4], extra[5], dwrq->length); | ||
1261 | |||
1262 | lbs_deb_wext("return flags 0x%x\n", dwrq->flags); | ||
1263 | |||
1264 | lbs_deb_leave(LBS_DEB_WEXT); | ||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | /** | ||
1269 | * @brief Set Encryption key (internal) | ||
1270 | * | ||
1271 | * @param priv A pointer to private card structure | ||
1272 | * @param key_material A pointer to key material | ||
1273 | * @param key_length length of key material | ||
1274 | * @param index key index to set | ||
1275 | * @param set_tx_key Force set TX key (1 = yes, 0 = no) | ||
1276 | * @return 0 --success, otherwise fail | ||
1277 | */ | ||
1278 | static int lbs_set_wep_key(struct assoc_request *assoc_req, | ||
1279 | const char *key_material, | ||
1280 | u16 key_length, | ||
1281 | u16 index, | ||
1282 | int set_tx_key) | ||
1283 | { | ||
1284 | int ret = 0; | ||
1285 | struct enc_key *pkey; | ||
1286 | |||
1287 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1288 | |||
1289 | /* Paranoid validation of key index */ | ||
1290 | if (index > 3) { | ||
1291 | ret = -EINVAL; | ||
1292 | goto out; | ||
1293 | } | ||
1294 | |||
1295 | /* validate max key length */ | ||
1296 | if (key_length > KEY_LEN_WEP_104) { | ||
1297 | ret = -EINVAL; | ||
1298 | goto out; | ||
1299 | } | ||
1300 | |||
1301 | pkey = &assoc_req->wep_keys[index]; | ||
1302 | |||
1303 | if (key_length > 0) { | ||
1304 | memset(pkey, 0, sizeof(struct enc_key)); | ||
1305 | pkey->type = KEY_TYPE_ID_WEP; | ||
1306 | |||
1307 | /* Standardize the key length */ | ||
1308 | pkey->len = (key_length > KEY_LEN_WEP_40) ? | ||
1309 | KEY_LEN_WEP_104 : KEY_LEN_WEP_40; | ||
1310 | memcpy(pkey->key, key_material, key_length); | ||
1311 | } | ||
1312 | |||
1313 | if (set_tx_key) { | ||
1314 | /* Ensure the chosen key is valid */ | ||
1315 | if (!pkey->len) { | ||
1316 | lbs_deb_wext("key not set, so cannot enable it\n"); | ||
1317 | ret = -EINVAL; | ||
1318 | goto out; | ||
1319 | } | ||
1320 | assoc_req->wep_tx_keyidx = index; | ||
1321 | } | ||
1322 | |||
1323 | assoc_req->secinfo.wep_enabled = 1; | ||
1324 | |||
1325 | out: | ||
1326 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1327 | return ret; | ||
1328 | } | ||
1329 | |||
1330 | static int validate_key_index(u16 def_index, u16 raw_index, | ||
1331 | u16 *out_index, u16 *is_default) | ||
1332 | { | ||
1333 | if (!out_index || !is_default) | ||
1334 | return -EINVAL; | ||
1335 | |||
1336 | /* Verify index if present, otherwise use default TX key index */ | ||
1337 | if (raw_index > 0) { | ||
1338 | if (raw_index > 4) | ||
1339 | return -EINVAL; | ||
1340 | *out_index = raw_index - 1; | ||
1341 | } else { | ||
1342 | *out_index = def_index; | ||
1343 | *is_default = 1; | ||
1344 | } | ||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | static void disable_wep(struct assoc_request *assoc_req) | ||
1349 | { | ||
1350 | int i; | ||
1351 | |||
1352 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1353 | |||
1354 | /* Set Open System auth mode */ | ||
1355 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1356 | |||
1357 | /* Clear WEP keys and mark WEP as disabled */ | ||
1358 | assoc_req->secinfo.wep_enabled = 0; | ||
1359 | for (i = 0; i < 4; i++) | ||
1360 | assoc_req->wep_keys[i].len = 0; | ||
1361 | |||
1362 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1363 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
1364 | |||
1365 | lbs_deb_leave(LBS_DEB_WEXT); | ||
1366 | } | ||
1367 | |||
1368 | static void disable_wpa(struct assoc_request *assoc_req) | ||
1369 | { | ||
1370 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1371 | |||
1372 | memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key)); | ||
1373 | assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; | ||
1374 | set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); | ||
1375 | |||
1376 | memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key)); | ||
1377 | assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; | ||
1378 | set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); | ||
1379 | |||
1380 | assoc_req->secinfo.WPAenabled = 0; | ||
1381 | assoc_req->secinfo.WPA2enabled = 0; | ||
1382 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1383 | |||
1384 | lbs_deb_leave(LBS_DEB_WEXT); | ||
1385 | } | ||
1386 | |||
1387 | /** | ||
1388 | * @brief Set Encryption key | ||
1389 | * | ||
1390 | * @param dev A pointer to net_device structure | ||
1391 | * @param info A pointer to iw_request_info structure | ||
1392 | * @param vwrq A pointer to iw_param structure | ||
1393 | * @param extra A pointer to extra data buf | ||
1394 | * @return 0 --success, otherwise fail | ||
1395 | */ | ||
1396 | static int lbs_set_encode(struct net_device *dev, | ||
1397 | struct iw_request_info *info, | ||
1398 | struct iw_point *dwrq, char *extra) | ||
1399 | { | ||
1400 | int ret = 0; | ||
1401 | struct lbs_private *priv = dev->ml_priv; | ||
1402 | struct assoc_request * assoc_req; | ||
1403 | u16 is_default = 0, index = 0, set_tx_key = 0; | ||
1404 | |||
1405 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1406 | |||
1407 | mutex_lock(&priv->lock); | ||
1408 | assoc_req = lbs_get_association_request(priv); | ||
1409 | if (!assoc_req) { | ||
1410 | ret = -ENOMEM; | ||
1411 | goto out; | ||
1412 | } | ||
1413 | |||
1414 | if (dwrq->flags & IW_ENCODE_DISABLED) { | ||
1415 | disable_wep (assoc_req); | ||
1416 | disable_wpa (assoc_req); | ||
1417 | goto out; | ||
1418 | } | ||
1419 | |||
1420 | ret = validate_key_index(assoc_req->wep_tx_keyidx, | ||
1421 | (dwrq->flags & IW_ENCODE_INDEX), | ||
1422 | &index, &is_default); | ||
1423 | if (ret) { | ||
1424 | ret = -EINVAL; | ||
1425 | goto out; | ||
1426 | } | ||
1427 | |||
1428 | /* If WEP isn't enabled, or if there is no key data but a valid | ||
1429 | * index, set the TX key. | ||
1430 | */ | ||
1431 | if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default)) | ||
1432 | set_tx_key = 1; | ||
1433 | |||
1434 | ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); | ||
1435 | if (ret) | ||
1436 | goto out; | ||
1437 | |||
1438 | if (dwrq->length) | ||
1439 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
1440 | if (set_tx_key) | ||
1441 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); | ||
1442 | |||
1443 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | ||
1444 | priv->authtype_auto = 0; | ||
1445 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | ||
1446 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | ||
1447 | priv->authtype_auto = 0; | ||
1448 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1449 | } | ||
1450 | |||
1451 | out: | ||
1452 | if (ret == 0) { | ||
1453 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1454 | lbs_postpone_association_work(priv); | ||
1455 | } else { | ||
1456 | lbs_cancel_association_work(priv); | ||
1457 | } | ||
1458 | mutex_unlock(&priv->lock); | ||
1459 | |||
1460 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1461 | return ret; | ||
1462 | } | ||
1463 | |||
1464 | /** | ||
1465 | * @brief Get Extended Encryption key (WPA/802.1x and WEP) | ||
1466 | * | ||
1467 | * @param dev A pointer to net_device structure | ||
1468 | * @param info A pointer to iw_request_info structure | ||
1469 | * @param vwrq A pointer to iw_param structure | ||
1470 | * @param extra A pointer to extra data buf | ||
1471 | * @return 0 on success, otherwise failure | ||
1472 | */ | ||
1473 | static int lbs_get_encodeext(struct net_device *dev, | ||
1474 | struct iw_request_info *info, | ||
1475 | struct iw_point *dwrq, | ||
1476 | char *extra) | ||
1477 | { | ||
1478 | int ret = -EINVAL; | ||
1479 | struct lbs_private *priv = dev->ml_priv; | ||
1480 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1481 | int index, max_key_len; | ||
1482 | |||
1483 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1484 | |||
1485 | max_key_len = dwrq->length - sizeof(*ext); | ||
1486 | if (max_key_len < 0) | ||
1487 | goto out; | ||
1488 | |||
1489 | index = dwrq->flags & IW_ENCODE_INDEX; | ||
1490 | if (index) { | ||
1491 | if (index < 1 || index > 4) | ||
1492 | goto out; | ||
1493 | index--; | ||
1494 | } else { | ||
1495 | index = priv->wep_tx_keyidx; | ||
1496 | } | ||
1497 | |||
1498 | if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && | ||
1499 | ext->alg != IW_ENCODE_ALG_WEP) { | ||
1500 | if (index != 0 || priv->mode != IW_MODE_INFRA) | ||
1501 | goto out; | ||
1502 | } | ||
1503 | |||
1504 | dwrq->flags = index + 1; | ||
1505 | memset(ext, 0, sizeof(*ext)); | ||
1506 | |||
1507 | if ( !priv->secinfo.wep_enabled | ||
1508 | && !priv->secinfo.WPAenabled | ||
1509 | && !priv->secinfo.WPA2enabled) { | ||
1510 | ext->alg = IW_ENCODE_ALG_NONE; | ||
1511 | ext->key_len = 0; | ||
1512 | dwrq->flags |= IW_ENCODE_DISABLED; | ||
1513 | } else { | ||
1514 | u8 *key = NULL; | ||
1515 | |||
1516 | if ( priv->secinfo.wep_enabled | ||
1517 | && !priv->secinfo.WPAenabled | ||
1518 | && !priv->secinfo.WPA2enabled) { | ||
1519 | /* WEP */ | ||
1520 | ext->alg = IW_ENCODE_ALG_WEP; | ||
1521 | ext->key_len = priv->wep_keys[index].len; | ||
1522 | key = &priv->wep_keys[index].key[0]; | ||
1523 | } else if ( !priv->secinfo.wep_enabled | ||
1524 | && (priv->secinfo.WPAenabled || | ||
1525 | priv->secinfo.WPA2enabled)) { | ||
1526 | /* WPA */ | ||
1527 | struct enc_key * pkey = NULL; | ||
1528 | |||
1529 | if ( priv->wpa_mcast_key.len | ||
1530 | && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) | ||
1531 | pkey = &priv->wpa_mcast_key; | ||
1532 | else if ( priv->wpa_unicast_key.len | ||
1533 | && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED)) | ||
1534 | pkey = &priv->wpa_unicast_key; | ||
1535 | |||
1536 | if (pkey) { | ||
1537 | if (pkey->type == KEY_TYPE_ID_AES) { | ||
1538 | ext->alg = IW_ENCODE_ALG_CCMP; | ||
1539 | } else { | ||
1540 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
1541 | } | ||
1542 | ext->key_len = pkey->len; | ||
1543 | key = &pkey->key[0]; | ||
1544 | } else { | ||
1545 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
1546 | ext->key_len = 0; | ||
1547 | } | ||
1548 | } else { | ||
1549 | goto out; | ||
1550 | } | ||
1551 | |||
1552 | if (ext->key_len > max_key_len) { | ||
1553 | ret = -E2BIG; | ||
1554 | goto out; | ||
1555 | } | ||
1556 | |||
1557 | if (ext->key_len) | ||
1558 | memcpy(ext->key, key, ext->key_len); | ||
1559 | else | ||
1560 | dwrq->flags |= IW_ENCODE_NOKEY; | ||
1561 | dwrq->flags |= IW_ENCODE_ENABLED; | ||
1562 | } | ||
1563 | ret = 0; | ||
1564 | |||
1565 | out: | ||
1566 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1567 | return ret; | ||
1568 | } | ||
1569 | |||
1570 | /** | ||
1571 | * @brief Set Encryption key Extended (WPA/802.1x and WEP) | ||
1572 | * | ||
1573 | * @param dev A pointer to net_device structure | ||
1574 | * @param info A pointer to iw_request_info structure | ||
1575 | * @param vwrq A pointer to iw_param structure | ||
1576 | * @param extra A pointer to extra data buf | ||
1577 | * @return 0 --success, otherwise fail | ||
1578 | */ | ||
1579 | static int lbs_set_encodeext(struct net_device *dev, | ||
1580 | struct iw_request_info *info, | ||
1581 | struct iw_point *dwrq, | ||
1582 | char *extra) | ||
1583 | { | ||
1584 | int ret = 0; | ||
1585 | struct lbs_private *priv = dev->ml_priv; | ||
1586 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1587 | int alg = ext->alg; | ||
1588 | struct assoc_request * assoc_req; | ||
1589 | |||
1590 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1591 | |||
1592 | mutex_lock(&priv->lock); | ||
1593 | assoc_req = lbs_get_association_request(priv); | ||
1594 | if (!assoc_req) { | ||
1595 | ret = -ENOMEM; | ||
1596 | goto out; | ||
1597 | } | ||
1598 | |||
1599 | if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { | ||
1600 | disable_wep (assoc_req); | ||
1601 | disable_wpa (assoc_req); | ||
1602 | } else if (alg == IW_ENCODE_ALG_WEP) { | ||
1603 | u16 is_default = 0, index, set_tx_key = 0; | ||
1604 | |||
1605 | ret = validate_key_index(assoc_req->wep_tx_keyidx, | ||
1606 | (dwrq->flags & IW_ENCODE_INDEX), | ||
1607 | &index, &is_default); | ||
1608 | if (ret) | ||
1609 | goto out; | ||
1610 | |||
1611 | /* If WEP isn't enabled, or if there is no key data but a valid | ||
1612 | * index, or if the set-TX-key flag was passed, set the TX key. | ||
1613 | */ | ||
1614 | if ( !assoc_req->secinfo.wep_enabled | ||
1615 | || (dwrq->length == 0 && !is_default) | ||
1616 | || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) | ||
1617 | set_tx_key = 1; | ||
1618 | |||
1619 | /* Copy key to driver */ | ||
1620 | ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index, | ||
1621 | set_tx_key); | ||
1622 | if (ret) | ||
1623 | goto out; | ||
1624 | |||
1625 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | ||
1626 | priv->authtype_auto = 0; | ||
1627 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | ||
1628 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | ||
1629 | priv->authtype_auto = 0; | ||
1630 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1631 | } | ||
1632 | |||
1633 | /* Mark the various WEP bits as modified */ | ||
1634 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1635 | if (dwrq->length) | ||
1636 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
1637 | if (set_tx_key) | ||
1638 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); | ||
1639 | } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { | ||
1640 | struct enc_key * pkey; | ||
1641 | |||
1642 | /* validate key length */ | ||
1643 | if (((alg == IW_ENCODE_ALG_TKIP) | ||
1644 | && (ext->key_len != KEY_LEN_WPA_TKIP)) | ||
1645 | || ((alg == IW_ENCODE_ALG_CCMP) | ||
1646 | && (ext->key_len != KEY_LEN_WPA_AES))) { | ||
1647 | lbs_deb_wext("invalid size %d for key of alg " | ||
1648 | "type %d\n", | ||
1649 | ext->key_len, | ||
1650 | alg); | ||
1651 | ret = -EINVAL; | ||
1652 | goto out; | ||
1653 | } | ||
1654 | |||
1655 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | ||
1656 | pkey = &assoc_req->wpa_mcast_key; | ||
1657 | set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); | ||
1658 | } else { | ||
1659 | pkey = &assoc_req->wpa_unicast_key; | ||
1660 | set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); | ||
1661 | } | ||
1662 | |||
1663 | memset(pkey, 0, sizeof (struct enc_key)); | ||
1664 | memcpy(pkey->key, ext->key, ext->key_len); | ||
1665 | pkey->len = ext->key_len; | ||
1666 | if (pkey->len) | ||
1667 | pkey->flags |= KEY_INFO_WPA_ENABLED; | ||
1668 | |||
1669 | /* Do this after zeroing key structure */ | ||
1670 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | ||
1671 | pkey->flags |= KEY_INFO_WPA_MCAST; | ||
1672 | } else { | ||
1673 | pkey->flags |= KEY_INFO_WPA_UNICAST; | ||
1674 | } | ||
1675 | |||
1676 | if (alg == IW_ENCODE_ALG_TKIP) { | ||
1677 | pkey->type = KEY_TYPE_ID_TKIP; | ||
1678 | } else if (alg == IW_ENCODE_ALG_CCMP) { | ||
1679 | pkey->type = KEY_TYPE_ID_AES; | ||
1680 | } | ||
1681 | |||
1682 | /* If WPA isn't enabled yet, do that now */ | ||
1683 | if ( assoc_req->secinfo.WPAenabled == 0 | ||
1684 | && assoc_req->secinfo.WPA2enabled == 0) { | ||
1685 | assoc_req->secinfo.WPAenabled = 1; | ||
1686 | assoc_req->secinfo.WPA2enabled = 1; | ||
1687 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1688 | } | ||
1689 | |||
1690 | /* Only disable wep if necessary: can't waste time here. */ | ||
1691 | if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) | ||
1692 | disable_wep(assoc_req); | ||
1693 | } | ||
1694 | |||
1695 | out: | ||
1696 | if (ret == 0) { | ||
1697 | /* 802.1x and WPA rekeying must happen as quickly as possible, | ||
1698 | * especially during the 4-way handshake; thus if in | ||
1699 | * infrastructure mode, and either (a) 802.1x is enabled or | ||
1700 | * (b) WPA is being used, set the key right away. | ||
1701 | */ | ||
1702 | if (assoc_req->mode == IW_MODE_INFRA && | ||
1703 | ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) || | ||
1704 | (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) || | ||
1705 | assoc_req->secinfo.WPAenabled || | ||
1706 | assoc_req->secinfo.WPA2enabled)) { | ||
1707 | lbs_do_association_work(priv); | ||
1708 | } else | ||
1709 | lbs_postpone_association_work(priv); | ||
1710 | } else { | ||
1711 | lbs_cancel_association_work(priv); | ||
1712 | } | ||
1713 | mutex_unlock(&priv->lock); | ||
1714 | |||
1715 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1716 | return ret; | ||
1717 | } | ||
1718 | |||
1719 | |||
1720 | static int lbs_set_genie(struct net_device *dev, | ||
1721 | struct iw_request_info *info, | ||
1722 | struct iw_point *dwrq, | ||
1723 | char *extra) | ||
1724 | { | ||
1725 | struct lbs_private *priv = dev->ml_priv; | ||
1726 | int ret = 0; | ||
1727 | struct assoc_request * assoc_req; | ||
1728 | |||
1729 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1730 | |||
1731 | mutex_lock(&priv->lock); | ||
1732 | assoc_req = lbs_get_association_request(priv); | ||
1733 | if (!assoc_req) { | ||
1734 | ret = -ENOMEM; | ||
1735 | goto out; | ||
1736 | } | ||
1737 | |||
1738 | if (dwrq->length > MAX_WPA_IE_LEN || | ||
1739 | (dwrq->length && extra == NULL)) { | ||
1740 | ret = -EINVAL; | ||
1741 | goto out; | ||
1742 | } | ||
1743 | |||
1744 | if (dwrq->length) { | ||
1745 | memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); | ||
1746 | assoc_req->wpa_ie_len = dwrq->length; | ||
1747 | } else { | ||
1748 | memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie)); | ||
1749 | assoc_req->wpa_ie_len = 0; | ||
1750 | } | ||
1751 | |||
1752 | out: | ||
1753 | if (ret == 0) { | ||
1754 | set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); | ||
1755 | lbs_postpone_association_work(priv); | ||
1756 | } else { | ||
1757 | lbs_cancel_association_work(priv); | ||
1758 | } | ||
1759 | mutex_unlock(&priv->lock); | ||
1760 | |||
1761 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1762 | return ret; | ||
1763 | } | ||
1764 | |||
1765 | static int lbs_get_genie(struct net_device *dev, | ||
1766 | struct iw_request_info *info, | ||
1767 | struct iw_point *dwrq, | ||
1768 | char *extra) | ||
1769 | { | ||
1770 | int ret = 0; | ||
1771 | struct lbs_private *priv = dev->ml_priv; | ||
1772 | |||
1773 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1774 | |||
1775 | if (priv->wpa_ie_len == 0) { | ||
1776 | dwrq->length = 0; | ||
1777 | goto out; | ||
1778 | } | ||
1779 | |||
1780 | if (dwrq->length < priv->wpa_ie_len) { | ||
1781 | ret = -E2BIG; | ||
1782 | goto out; | ||
1783 | } | ||
1784 | |||
1785 | dwrq->length = priv->wpa_ie_len; | ||
1786 | memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); | ||
1787 | |||
1788 | out: | ||
1789 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1790 | return ret; | ||
1791 | } | ||
1792 | |||
1793 | |||
1794 | static int lbs_set_auth(struct net_device *dev, | ||
1795 | struct iw_request_info *info, | ||
1796 | struct iw_param *dwrq, | ||
1797 | char *extra) | ||
1798 | { | ||
1799 | struct lbs_private *priv = dev->ml_priv; | ||
1800 | struct assoc_request * assoc_req; | ||
1801 | int ret = 0; | ||
1802 | int updated = 0; | ||
1803 | |||
1804 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1805 | |||
1806 | mutex_lock(&priv->lock); | ||
1807 | assoc_req = lbs_get_association_request(priv); | ||
1808 | if (!assoc_req) { | ||
1809 | ret = -ENOMEM; | ||
1810 | goto out; | ||
1811 | } | ||
1812 | |||
1813 | switch (dwrq->flags & IW_AUTH_INDEX) { | ||
1814 | case IW_AUTH_PRIVACY_INVOKED: | ||
1815 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
1816 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
1817 | case IW_AUTH_CIPHER_PAIRWISE: | ||
1818 | case IW_AUTH_CIPHER_GROUP: | ||
1819 | case IW_AUTH_DROP_UNENCRYPTED: | ||
1820 | /* | ||
1821 | * libertas does not use these parameters | ||
1822 | */ | ||
1823 | break; | ||
1824 | |||
1825 | case IW_AUTH_KEY_MGMT: | ||
1826 | assoc_req->secinfo.key_mgmt = dwrq->value; | ||
1827 | updated = 1; | ||
1828 | break; | ||
1829 | |||
1830 | case IW_AUTH_WPA_VERSION: | ||
1831 | if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { | ||
1832 | assoc_req->secinfo.WPAenabled = 0; | ||
1833 | assoc_req->secinfo.WPA2enabled = 0; | ||
1834 | disable_wpa (assoc_req); | ||
1835 | } | ||
1836 | if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { | ||
1837 | assoc_req->secinfo.WPAenabled = 1; | ||
1838 | assoc_req->secinfo.wep_enabled = 0; | ||
1839 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1840 | } | ||
1841 | if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { | ||
1842 | assoc_req->secinfo.WPA2enabled = 1; | ||
1843 | assoc_req->secinfo.wep_enabled = 0; | ||
1844 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1845 | } | ||
1846 | updated = 1; | ||
1847 | break; | ||
1848 | |||
1849 | case IW_AUTH_80211_AUTH_ALG: | ||
1850 | if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { | ||
1851 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | ||
1852 | } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { | ||
1853 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1854 | } else if (dwrq->value & IW_AUTH_ALG_LEAP) { | ||
1855 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP; | ||
1856 | } else { | ||
1857 | ret = -EINVAL; | ||
1858 | } | ||
1859 | updated = 1; | ||
1860 | break; | ||
1861 | |||
1862 | case IW_AUTH_WPA_ENABLED: | ||
1863 | if (dwrq->value) { | ||
1864 | if (!assoc_req->secinfo.WPAenabled && | ||
1865 | !assoc_req->secinfo.WPA2enabled) { | ||
1866 | assoc_req->secinfo.WPAenabled = 1; | ||
1867 | assoc_req->secinfo.WPA2enabled = 1; | ||
1868 | assoc_req->secinfo.wep_enabled = 0; | ||
1869 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1870 | } | ||
1871 | } else { | ||
1872 | assoc_req->secinfo.WPAenabled = 0; | ||
1873 | assoc_req->secinfo.WPA2enabled = 0; | ||
1874 | disable_wpa (assoc_req); | ||
1875 | } | ||
1876 | updated = 1; | ||
1877 | break; | ||
1878 | |||
1879 | default: | ||
1880 | ret = -EOPNOTSUPP; | ||
1881 | break; | ||
1882 | } | ||
1883 | |||
1884 | out: | ||
1885 | if (ret == 0) { | ||
1886 | if (updated) | ||
1887 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1888 | lbs_postpone_association_work(priv); | ||
1889 | } else if (ret != -EOPNOTSUPP) { | ||
1890 | lbs_cancel_association_work(priv); | ||
1891 | } | ||
1892 | mutex_unlock(&priv->lock); | ||
1893 | |||
1894 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1895 | return ret; | ||
1896 | } | ||
1897 | |||
1898 | static int lbs_get_auth(struct net_device *dev, | ||
1899 | struct iw_request_info *info, | ||
1900 | struct iw_param *dwrq, | ||
1901 | char *extra) | ||
1902 | { | ||
1903 | int ret = 0; | ||
1904 | struct lbs_private *priv = dev->ml_priv; | ||
1905 | |||
1906 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1907 | |||
1908 | switch (dwrq->flags & IW_AUTH_INDEX) { | ||
1909 | case IW_AUTH_KEY_MGMT: | ||
1910 | dwrq->value = priv->secinfo.key_mgmt; | ||
1911 | break; | ||
1912 | |||
1913 | case IW_AUTH_WPA_VERSION: | ||
1914 | dwrq->value = 0; | ||
1915 | if (priv->secinfo.WPAenabled) | ||
1916 | dwrq->value |= IW_AUTH_WPA_VERSION_WPA; | ||
1917 | if (priv->secinfo.WPA2enabled) | ||
1918 | dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; | ||
1919 | if (!dwrq->value) | ||
1920 | dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; | ||
1921 | break; | ||
1922 | |||
1923 | case IW_AUTH_80211_AUTH_ALG: | ||
1924 | dwrq->value = priv->secinfo.auth_mode; | ||
1925 | break; | ||
1926 | |||
1927 | case IW_AUTH_WPA_ENABLED: | ||
1928 | if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) | ||
1929 | dwrq->value = 1; | ||
1930 | break; | ||
1931 | |||
1932 | default: | ||
1933 | ret = -EOPNOTSUPP; | ||
1934 | } | ||
1935 | |||
1936 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
1937 | return ret; | ||
1938 | } | ||
1939 | |||
1940 | |||
1941 | static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, | ||
1942 | struct iw_param *vwrq, char *extra) | ||
1943 | { | ||
1944 | int ret = 0; | ||
1945 | struct lbs_private *priv = dev->ml_priv; | ||
1946 | s16 dbm = (s16) vwrq->value; | ||
1947 | |||
1948 | lbs_deb_enter(LBS_DEB_WEXT); | ||
1949 | |||
1950 | if (vwrq->disabled) { | ||
1951 | lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); | ||
1952 | goto out; | ||
1953 | } | ||
1954 | |||
1955 | if (vwrq->fixed == 0) { | ||
1956 | /* User requests automatic tx power control, however there are | ||
1957 | * many auto tx settings. For now use firmware defaults until | ||
1958 | * we come up with a good way to expose these to the user. */ | ||
1959 | if (priv->fwrelease < 0x09000000) { | ||
1960 | ret = lbs_set_power_adapt_cfg(priv, 1, | ||
1961 | POW_ADAPT_DEFAULT_P0, | ||
1962 | POW_ADAPT_DEFAULT_P1, | ||
1963 | POW_ADAPT_DEFAULT_P2); | ||
1964 | if (ret) | ||
1965 | goto out; | ||
1966 | } | ||
1967 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
1968 | TPC_DEFAULT_P2, 1); | ||
1969 | if (ret) | ||
1970 | goto out; | ||
1971 | dbm = priv->txpower_max; | ||
1972 | } else { | ||
1973 | /* Userspace check in iwrange if it should use dBm or mW, | ||
1974 | * therefore this should never happen... Jean II */ | ||
1975 | if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { | ||
1976 | ret = -EOPNOTSUPP; | ||
1977 | goto out; | ||
1978 | } | ||
1979 | |||
1980 | /* Validate requested power level against firmware allowed | ||
1981 | * levels */ | ||
1982 | if (priv->txpower_min && (dbm < priv->txpower_min)) { | ||
1983 | ret = -EINVAL; | ||
1984 | goto out; | ||
1985 | } | ||
1986 | |||
1987 | if (priv->txpower_max && (dbm > priv->txpower_max)) { | ||
1988 | ret = -EINVAL; | ||
1989 | goto out; | ||
1990 | } | ||
1991 | if (priv->fwrelease < 0x09000000) { | ||
1992 | ret = lbs_set_power_adapt_cfg(priv, 0, | ||
1993 | POW_ADAPT_DEFAULT_P0, | ||
1994 | POW_ADAPT_DEFAULT_P1, | ||
1995 | POW_ADAPT_DEFAULT_P2); | ||
1996 | if (ret) | ||
1997 | goto out; | ||
1998 | } | ||
1999 | ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, | ||
2000 | TPC_DEFAULT_P2, 1); | ||
2001 | if (ret) | ||
2002 | goto out; | ||
2003 | } | ||
2004 | |||
2005 | /* If the radio was off, turn it on */ | ||
2006 | if (!priv->radio_on) { | ||
2007 | ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); | ||
2008 | if (ret) | ||
2009 | goto out; | ||
2010 | } | ||
2011 | |||
2012 | lbs_deb_wext("txpower set %d dBm\n", dbm); | ||
2013 | |||
2014 | ret = lbs_set_tx_power(priv, dbm); | ||
2015 | |||
2016 | out: | ||
2017 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
2018 | return ret; | ||
2019 | } | ||
2020 | |||
2021 | static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, | ||
2022 | struct iw_point *dwrq, char *extra) | ||
2023 | { | ||
2024 | struct lbs_private *priv = dev->ml_priv; | ||
2025 | |||
2026 | lbs_deb_enter(LBS_DEB_WEXT); | ||
2027 | |||
2028 | /* | ||
2029 | * Note : if dwrq->flags != 0, we should get the relevant SSID from | ||
2030 | * the SSID list... | ||
2031 | */ | ||
2032 | |||
2033 | /* | ||
2034 | * Get the current SSID | ||
2035 | */ | ||
2036 | if (priv->connect_status == LBS_CONNECTED) { | ||
2037 | memcpy(extra, priv->curbssparams.ssid, | ||
2038 | priv->curbssparams.ssid_len); | ||
2039 | } else { | ||
2040 | memset(extra, 0, 32); | ||
2041 | } | ||
2042 | /* | ||
2043 | * If none, we may want to get the one that was set | ||
2044 | */ | ||
2045 | |||
2046 | dwrq->length = priv->curbssparams.ssid_len; | ||
2047 | |||
2048 | dwrq->flags = 1; /* active */ | ||
2049 | |||
2050 | lbs_deb_leave(LBS_DEB_WEXT); | ||
2051 | return 0; | ||
2052 | } | ||
2053 | |||
2054 | static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, | ||
2055 | struct iw_point *dwrq, char *extra) | ||
2056 | { | ||
2057 | struct lbs_private *priv = dev->ml_priv; | ||
2058 | int ret = 0; | ||
2059 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
2060 | u8 ssid_len = 0; | ||
2061 | struct assoc_request * assoc_req; | ||
2062 | int in_ssid_len = dwrq->length; | ||
2063 | DECLARE_SSID_BUF(ssid_buf); | ||
2064 | |||
2065 | lbs_deb_enter(LBS_DEB_WEXT); | ||
2066 | |||
2067 | if (!priv->radio_on) { | ||
2068 | ret = -EINVAL; | ||
2069 | goto out; | ||
2070 | } | ||
2071 | |||
2072 | /* Check the size of the string */ | ||
2073 | if (in_ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
2074 | ret = -E2BIG; | ||
2075 | goto out; | ||
2076 | } | ||
2077 | |||
2078 | memset(&ssid, 0, sizeof(ssid)); | ||
2079 | |||
2080 | if (!dwrq->flags || !in_ssid_len) { | ||
2081 | /* "any" SSID requested; leave SSID blank */ | ||
2082 | } else { | ||
2083 | /* Specific SSID requested */ | ||
2084 | memcpy(&ssid, extra, in_ssid_len); | ||
2085 | ssid_len = in_ssid_len; | ||
2086 | } | ||
2087 | |||
2088 | if (!ssid_len) { | ||
2089 | lbs_deb_wext("requested any SSID\n"); | ||
2090 | } else { | ||
2091 | lbs_deb_wext("requested SSID '%s'\n", | ||
2092 | print_ssid(ssid_buf, ssid, ssid_len)); | ||
2093 | } | ||
2094 | |||
2095 | out: | ||
2096 | mutex_lock(&priv->lock); | ||
2097 | if (ret == 0) { | ||
2098 | /* Get or create the current association request */ | ||
2099 | assoc_req = lbs_get_association_request(priv); | ||
2100 | if (!assoc_req) { | ||
2101 | ret = -ENOMEM; | ||
2102 | } else { | ||
2103 | /* Copy the SSID to the association request */ | ||
2104 | memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN); | ||
2105 | assoc_req->ssid_len = ssid_len; | ||
2106 | set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); | ||
2107 | lbs_postpone_association_work(priv); | ||
2108 | } | ||
2109 | } | ||
2110 | |||
2111 | /* Cancel the association request if there was an error */ | ||
2112 | if (ret != 0) { | ||
2113 | lbs_cancel_association_work(priv); | ||
2114 | } | ||
2115 | |||
2116 | mutex_unlock(&priv->lock); | ||
2117 | |||
2118 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
2119 | return ret; | ||
2120 | } | ||
2121 | |||
2122 | #ifdef CONFIG_LIBERTAS_MESH | ||
2123 | static int lbs_mesh_get_essid(struct net_device *dev, | ||
2124 | struct iw_request_info *info, | ||
2125 | struct iw_point *dwrq, char *extra) | ||
2126 | { | ||
2127 | struct lbs_private *priv = dev->ml_priv; | ||
2128 | |||
2129 | lbs_deb_enter(LBS_DEB_WEXT); | ||
2130 | |||
2131 | memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len); | ||
2132 | |||
2133 | dwrq->length = priv->mesh_ssid_len; | ||
2134 | |||
2135 | dwrq->flags = 1; /* active */ | ||
2136 | |||
2137 | lbs_deb_leave(LBS_DEB_WEXT); | ||
2138 | return 0; | ||
2139 | } | ||
2140 | |||
2141 | static int lbs_mesh_set_essid(struct net_device *dev, | ||
2142 | struct iw_request_info *info, | ||
2143 | struct iw_point *dwrq, char *extra) | ||
2144 | { | ||
2145 | struct lbs_private *priv = dev->ml_priv; | ||
2146 | int ret = 0; | ||
2147 | |||
2148 | lbs_deb_enter(LBS_DEB_WEXT); | ||
2149 | |||
2150 | if (!priv->radio_on) { | ||
2151 | ret = -EINVAL; | ||
2152 | goto out; | ||
2153 | } | ||
2154 | |||
2155 | /* Check the size of the string */ | ||
2156 | if (dwrq->length > IEEE80211_MAX_SSID_LEN) { | ||
2157 | ret = -E2BIG; | ||
2158 | goto out; | ||
2159 | } | ||
2160 | |||
2161 | if (!dwrq->flags || !dwrq->length) { | ||
2162 | ret = -EINVAL; | ||
2163 | goto out; | ||
2164 | } else { | ||
2165 | /* Specific SSID requested */ | ||
2166 | memcpy(priv->mesh_ssid, extra, dwrq->length); | ||
2167 | priv->mesh_ssid_len = dwrq->length; | ||
2168 | } | ||
2169 | |||
2170 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, | ||
2171 | priv->channel); | ||
2172 | out: | ||
2173 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | ||
2174 | return ret; | ||
2175 | } | ||
2176 | #endif | ||
2177 | |||
2178 | /** | ||
2179 | * @brief Connect to the AP or Ad-hoc Network with specific bssid | ||
2180 | * | ||
2181 | * @param dev A pointer to net_device structure | ||
2182 | * @param info A pointer to iw_request_info structure | ||
2183 | * @param awrq A pointer to iw_param structure | ||
2184 | * @param extra A pointer to extra data buf | ||
2185 | * @return 0 --success, otherwise fail | ||
2186 | */ | ||
2187 | static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, | ||
2188 | struct sockaddr *awrq, char *extra) | ||
2189 | { | ||
2190 | struct lbs_private *priv = dev->ml_priv; | ||
2191 | struct assoc_request * assoc_req; | ||
2192 | int ret = 0; | ||
2193 | |||
2194 | lbs_deb_enter(LBS_DEB_WEXT); | ||
2195 | |||
2196 | if (!priv->radio_on) | ||
2197 | return -EINVAL; | ||
2198 | |||
2199 | if (awrq->sa_family != ARPHRD_ETHER) | ||
2200 | return -EINVAL; | ||
2201 | |||
2202 | lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data); | ||
2203 | |||
2204 | mutex_lock(&priv->lock); | ||
2205 | |||
2206 | /* Get or create the current association request */ | ||
2207 | assoc_req = lbs_get_association_request(priv); | ||
2208 | if (!assoc_req) { | ||
2209 | lbs_cancel_association_work(priv); | ||
2210 | ret = -ENOMEM; | ||
2211 | } else { | ||
2212 | /* Copy the BSSID to the association request */ | ||
2213 | memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); | ||
2214 | set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); | ||
2215 | lbs_postpone_association_work(priv); | ||
2216 | } | ||
2217 | |||
2218 | mutex_unlock(&priv->lock); | ||
2219 | |||
2220 | return ret; | ||
2221 | } | ||
2222 | |||
2223 | /* | ||
2224 | * iwconfig settable callbacks | ||
2225 | */ | ||
2226 | static const iw_handler lbs_handler[] = { | ||
2227 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
2228 | (iw_handler) lbs_get_name, /* SIOCGIWNAME */ | ||
2229 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
2230 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
2231 | (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */ | ||
2232 | (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ | ||
2233 | (iw_handler) lbs_set_mode, /* SIOCSIWMODE */ | ||
2234 | (iw_handler) lbs_get_mode, /* SIOCGIWMODE */ | ||
2235 | (iw_handler) NULL, /* SIOCSIWSENS */ | ||
2236 | (iw_handler) NULL, /* SIOCGIWSENS */ | ||
2237 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
2238 | (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ | ||
2239 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
2240 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
2241 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
2242 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
2243 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2244 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2245 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2246 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2247 | (iw_handler) lbs_set_wap, /* SIOCSIWAP */ | ||
2248 | (iw_handler) lbs_get_wap, /* SIOCGIWAP */ | ||
2249 | (iw_handler) NULL, /* SIOCSIWMLME */ | ||
2250 | (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ | ||
2251 | (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ | ||
2252 | (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ | ||
2253 | (iw_handler) lbs_set_essid, /* SIOCSIWESSID */ | ||
2254 | (iw_handler) lbs_get_essid, /* SIOCGIWESSID */ | ||
2255 | (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */ | ||
2256 | (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */ | ||
2257 | (iw_handler) NULL, /* -- hole -- */ | ||
2258 | (iw_handler) NULL, /* -- hole -- */ | ||
2259 | (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ | ||
2260 | (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ | ||
2261 | (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ | ||
2262 | (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ | ||
2263 | (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ | ||
2264 | (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ | ||
2265 | (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ | ||
2266 | (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ | ||
2267 | (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ | ||
2268 | (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ | ||
2269 | (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ | ||
2270 | (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ | ||
2271 | (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ | ||
2272 | (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ | ||
2273 | (iw_handler) NULL, /* -- hole -- */ | ||
2274 | (iw_handler) NULL, /* -- hole -- */ | ||
2275 | (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ | ||
2276 | (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ | ||
2277 | (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ | ||
2278 | (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ | ||
2279 | (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ | ||
2280 | (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ | ||
2281 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
2282 | }; | ||
2283 | struct iw_handler_def lbs_handler_def = { | ||
2284 | .num_standard = ARRAY_SIZE(lbs_handler), | ||
2285 | .standard = (iw_handler *) lbs_handler, | ||
2286 | .get_wireless_stats = lbs_get_wireless_stats, | ||
2287 | }; | ||
2288 | |||
2289 | #ifdef CONFIG_LIBERTAS_MESH | ||
2290 | static const iw_handler mesh_wlan_handler[] = { | ||
2291 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
2292 | (iw_handler) lbs_get_name, /* SIOCGIWNAME */ | ||
2293 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
2294 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
2295 | (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */ | ||
2296 | (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ | ||
2297 | (iw_handler) NULL, /* SIOCSIWMODE */ | ||
2298 | (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */ | ||
2299 | (iw_handler) NULL, /* SIOCSIWSENS */ | ||
2300 | (iw_handler) NULL, /* SIOCGIWSENS */ | ||
2301 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
2302 | (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ | ||
2303 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
2304 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
2305 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
2306 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
2307 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2308 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2309 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2310 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2311 | (iw_handler) NULL, /* SIOCSIWAP */ | ||
2312 | (iw_handler) NULL, /* SIOCGIWAP */ | ||
2313 | (iw_handler) NULL, /* SIOCSIWMLME */ | ||
2314 | (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ | ||
2315 | (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ | ||
2316 | (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ | ||
2317 | (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */ | ||
2318 | (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */ | ||
2319 | (iw_handler) NULL, /* SIOCSIWNICKN */ | ||
2320 | (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */ | ||
2321 | (iw_handler) NULL, /* -- hole -- */ | ||
2322 | (iw_handler) NULL, /* -- hole -- */ | ||
2323 | (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ | ||
2324 | (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ | ||
2325 | (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ | ||
2326 | (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ | ||
2327 | (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ | ||
2328 | (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ | ||
2329 | (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ | ||
2330 | (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ | ||
2331 | (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ | ||
2332 | (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ | ||
2333 | (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ | ||
2334 | (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ | ||
2335 | (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ | ||
2336 | (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ | ||
2337 | (iw_handler) NULL, /* -- hole -- */ | ||
2338 | (iw_handler) NULL, /* -- hole -- */ | ||
2339 | (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ | ||
2340 | (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ | ||
2341 | (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ | ||
2342 | (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ | ||
2343 | (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ | ||
2344 | (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ | ||
2345 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
2346 | }; | ||
2347 | |||
2348 | struct iw_handler_def mesh_handler_def = { | ||
2349 | .num_standard = ARRAY_SIZE(mesh_wlan_handler), | ||
2350 | .standard = (iw_handler *) mesh_wlan_handler, | ||
2351 | .get_wireless_stats = lbs_get_wireless_stats, | ||
2352 | }; | ||
2353 | #endif | ||
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h deleted file mode 100644 index f3f19fe8c6c6..000000000000 --- a/drivers/net/wireless/libertas/wext.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | /** | ||
2 | * This file contains definition for IOCTL call. | ||
3 | */ | ||
4 | #ifndef _LBS_WEXT_H_ | ||
5 | #define _LBS_WEXT_H_ | ||
6 | |||
7 | void lbs_send_disconnect_notification(struct lbs_private *priv); | ||
8 | void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); | ||
9 | |||
10 | struct chan_freq_power *lbs_find_cfp_by_band_and_channel( | ||
11 | struct lbs_private *priv, | ||
12 | u8 band, | ||
13 | u16 channel); | ||
14 | |||
15 | extern struct iw_handler_def lbs_handler_def; | ||
16 | |||
17 | #endif | ||
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 49a7dfb4809a..e7f299dc9ef5 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -1291,6 +1291,11 @@ static int __init init_mac80211_hwsim(void) | |||
1291 | hw->wiphy->n_addresses = 2; | 1291 | hw->wiphy->n_addresses = 2; |
1292 | hw->wiphy->addresses = data->addresses; | 1292 | hw->wiphy->addresses = data->addresses; |
1293 | 1293 | ||
1294 | if (fake_hw_scan) { | ||
1295 | hw->wiphy->max_scan_ssids = 255; | ||
1296 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
1297 | } | ||
1298 | |||
1294 | hw->channel_change_time = 1; | 1299 | hw->channel_change_time = 1; |
1295 | hw->queues = 4; | 1300 | hw->queues = 4; |
1296 | hw->wiphy->interface_modes = | 1301 | hw->wiphy->interface_modes = |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 5e7f344b000d..719573bbbf81 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -520,8 +520,9 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, | |||
520 | 520 | ||
521 | static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); | 521 | static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); |
522 | 522 | ||
523 | static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, | 523 | static int rndis_set_tx_power(struct wiphy *wiphy, |
524 | int dbm); | 524 | enum nl80211_tx_power_setting type, |
525 | int mbm); | ||
525 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); | 526 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); |
526 | 527 | ||
527 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, | 528 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, |
@@ -1856,20 +1857,25 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1856 | return 0; | 1857 | return 0; |
1857 | } | 1858 | } |
1858 | 1859 | ||
1859 | static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, | 1860 | static int rndis_set_tx_power(struct wiphy *wiphy, |
1860 | int dbm) | 1861 | enum nl80211_tx_power_setting type, |
1862 | int mbm) | ||
1861 | { | 1863 | { |
1862 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | 1864 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); |
1863 | struct usbnet *usbdev = priv->usbdev; | 1865 | struct usbnet *usbdev = priv->usbdev; |
1864 | 1866 | ||
1865 | netdev_dbg(usbdev->net, "%s(): type:0x%x dbm:%i\n", | 1867 | netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n", |
1866 | __func__, type, dbm); | 1868 | __func__, type, mbm); |
1869 | |||
1870 | if (mbm < 0 || (mbm % 100)) | ||
1871 | return -ENOTSUPP; | ||
1867 | 1872 | ||
1868 | /* Device doesn't support changing txpower after initialization, only | 1873 | /* Device doesn't support changing txpower after initialization, only |
1869 | * turn off/on radio. Support 'auto' mode and setting same dBm that is | 1874 | * turn off/on radio. Support 'auto' mode and setting same dBm that is |
1870 | * currently used. | 1875 | * currently used. |
1871 | */ | 1876 | */ |
1872 | if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) { | 1877 | if (type == NL80211_TX_POWER_AUTOMATIC || |
1878 | MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) { | ||
1873 | if (!priv->radio_on) | 1879 | if (!priv->radio_on) |
1874 | disassociate(usbdev, true); /* turn on radio */ | 1880 | disassociate(usbdev, true); /* turn on radio */ |
1875 | 1881 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 1eb882e15fb4..3bedf566c8ee 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -1229,7 +1229,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1229 | } | 1229 | } |
1230 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); | 1230 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); |
1231 | 1231 | ||
1232 | rt2x00pci_txdone(entry, &txdesc); | 1232 | rt2x00lib_txdone(entry, &txdesc); |
1233 | } | 1233 | } |
1234 | } | 1234 | } |
1235 | 1235 | ||
@@ -1588,7 +1588,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { | |||
1588 | .reset_tuner = rt2400pci_reset_tuner, | 1588 | .reset_tuner = rt2400pci_reset_tuner, |
1589 | .link_tuner = rt2400pci_link_tuner, | 1589 | .link_tuner = rt2400pci_link_tuner, |
1590 | .write_tx_desc = rt2400pci_write_tx_desc, | 1590 | .write_tx_desc = rt2400pci_write_tx_desc, |
1591 | .write_tx_data = rt2x00pci_write_tx_data, | ||
1592 | .write_beacon = rt2400pci_write_beacon, | 1591 | .write_beacon = rt2400pci_write_beacon, |
1593 | .kick_tx_queue = rt2400pci_kick_tx_queue, | 1592 | .kick_tx_queue = rt2400pci_kick_tx_queue, |
1594 | .kill_tx_queue = rt2400pci_kill_tx_queue, | 1593 | .kill_tx_queue = rt2400pci_kill_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index a29cb212f89a..69d231d83952 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1365,7 +1365,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1365 | } | 1365 | } |
1366 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); | 1366 | txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); |
1367 | 1367 | ||
1368 | rt2x00pci_txdone(entry, &txdesc); | 1368 | rt2x00lib_txdone(entry, &txdesc); |
1369 | } | 1369 | } |
1370 | } | 1370 | } |
1371 | 1371 | ||
@@ -1886,7 +1886,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { | |||
1886 | .reset_tuner = rt2500pci_reset_tuner, | 1886 | .reset_tuner = rt2500pci_reset_tuner, |
1887 | .link_tuner = rt2500pci_link_tuner, | 1887 | .link_tuner = rt2500pci_link_tuner, |
1888 | .write_tx_desc = rt2500pci_write_tx_desc, | 1888 | .write_tx_desc = rt2500pci_write_tx_desc, |
1889 | .write_tx_data = rt2x00pci_write_tx_data, | ||
1890 | .write_beacon = rt2500pci_write_beacon, | 1889 | .write_beacon = rt2500pci_write_beacon, |
1891 | .kick_tx_queue = rt2500pci_kick_tx_queue, | 1890 | .kick_tx_queue = rt2500pci_kick_tx_queue, |
1892 | .kill_tx_queue = rt2500pci_kill_tx_queue, | 1891 | .kill_tx_queue = rt2500pci_kill_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 002db646ae0b..44205526013f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -347,6 +347,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, | |||
347 | { | 347 | { |
348 | u32 mask; | 348 | u32 mask; |
349 | u16 reg; | 349 | u16 reg; |
350 | enum cipher curr_cipher; | ||
350 | 351 | ||
351 | if (crypto->cmd == SET_KEY) { | 352 | if (crypto->cmd == SET_KEY) { |
352 | /* | 353 | /* |
@@ -357,6 +358,7 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, | |||
357 | mask = TXRX_CSR0_KEY_ID.bit_mask; | 358 | mask = TXRX_CSR0_KEY_ID.bit_mask; |
358 | 359 | ||
359 | rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); | 360 | rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); |
361 | curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM); | ||
360 | reg &= mask; | 362 | reg &= mask; |
361 | 363 | ||
362 | if (reg && reg == mask) | 364 | if (reg && reg == mask) |
@@ -365,6 +367,14 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, | |||
365 | reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); | 367 | reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); |
366 | 368 | ||
367 | key->hw_key_idx += reg ? ffz(reg) : 0; | 369 | key->hw_key_idx += reg ? ffz(reg) : 0; |
370 | /* | ||
371 | * Hardware requires that all keys use the same cipher | ||
372 | * (e.g. TKIP-only, AES-only, but not TKIP+AES). | ||
373 | * If this is not the first key, compare the cipher with the | ||
374 | * first one and fall back to SW crypto if not the same. | ||
375 | */ | ||
376 | if (key->hw_key_idx > 0 && crypto->cipher != curr_cipher) | ||
377 | return -EOPNOTSUPP; | ||
368 | 378 | ||
369 | rt2500usb_register_multiwrite(rt2x00dev, reg, | 379 | rt2500usb_register_multiwrite(rt2x00dev, reg, |
370 | crypto->key, sizeof(crypto->key)); | 380 | crypto->key, sizeof(crypto->key)); |
@@ -1769,7 +1779,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { | |||
1769 | .link_stats = rt2500usb_link_stats, | 1779 | .link_stats = rt2500usb_link_stats, |
1770 | .reset_tuner = rt2500usb_reset_tuner, | 1780 | .reset_tuner = rt2500usb_reset_tuner, |
1771 | .write_tx_desc = rt2500usb_write_tx_desc, | 1781 | .write_tx_desc = rt2500usb_write_tx_desc, |
1772 | .write_tx_data = rt2x00usb_write_tx_data, | ||
1773 | .write_beacon = rt2500usb_write_beacon, | 1782 | .write_beacon = rt2500usb_write_beacon, |
1774 | .get_tx_data_len = rt2500usb_get_tx_data_len, | 1783 | .get_tx_data_len = rt2500usb_get_tx_data_len, |
1775 | .kick_tx_queue = rt2x00usb_kick_tx_queue, | 1784 | .kick_tx_queue = rt2x00usb_kick_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 14c361ae87be..d3cf0cc39500 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -99,8 +99,7 @@ static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, | |||
99 | rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); | 99 | rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); |
100 | rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); | 100 | rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); |
101 | rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); | 101 | rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); |
102 | if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) | 102 | rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); |
103 | rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); | ||
104 | 103 | ||
105 | rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); | 104 | rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); |
106 | } | 105 | } |
@@ -128,8 +127,7 @@ static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, | |||
128 | rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); | 127 | rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); |
129 | rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); | 128 | rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); |
130 | rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); | 129 | rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); |
131 | if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) | 130 | rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); |
132 | rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); | ||
133 | 131 | ||
134 | rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); | 132 | rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); |
135 | 133 | ||
@@ -432,6 +430,20 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) | |||
432 | } | 430 | } |
433 | EXPORT_SYMBOL(rt2800_write_beacon); | 431 | EXPORT_SYMBOL(rt2800_write_beacon); |
434 | 432 | ||
433 | static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, | ||
434 | unsigned int beacon_base) | ||
435 | { | ||
436 | int i; | ||
437 | |||
438 | /* | ||
439 | * For the Beacon base registers we only need to clear | ||
440 | * the whole TXWI which (when set to 0) will invalidate | ||
441 | * the entire beacon. | ||
442 | */ | ||
443 | for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32)) | ||
444 | rt2800_register_write(rt2x00dev, beacon_base + i, 0); | ||
445 | } | ||
446 | |||
435 | #ifdef CONFIG_RT2X00_LIB_DEBUGFS | 447 | #ifdef CONFIG_RT2X00_LIB_DEBUGFS |
436 | const struct rt2x00debug rt2800_rt2x00debug = { | 448 | const struct rt2x00debug rt2800_rt2x00debug = { |
437 | .owner = THIS_MODULE, | 449 | .owner = THIS_MODULE, |
@@ -733,19 +745,14 @@ EXPORT_SYMBOL_GPL(rt2800_config_filter); | |||
733 | void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | 745 | void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, |
734 | struct rt2x00intf_conf *conf, const unsigned int flags) | 746 | struct rt2x00intf_conf *conf, const unsigned int flags) |
735 | { | 747 | { |
736 | unsigned int beacon_base; | ||
737 | u32 reg; | 748 | u32 reg; |
738 | 749 | ||
739 | if (flags & CONFIG_UPDATE_TYPE) { | 750 | if (flags & CONFIG_UPDATE_TYPE) { |
740 | /* | 751 | /* |
741 | * Clear current synchronisation setup. | 752 | * Clear current synchronisation setup. |
742 | * For the Beacon base registers we only need to clear | ||
743 | * the first byte since that byte contains the VALID and OWNER | ||
744 | * bits which (when set to 0) will invalidate the entire beacon. | ||
745 | */ | 753 | */ |
746 | beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); | 754 | rt2800_clear_beacon(rt2x00dev, |
747 | rt2800_register_write(rt2x00dev, beacon_base, 0); | 755 | HW_BEACON_OFFSET(intf->beacon->entry_idx)); |
748 | |||
749 | /* | 756 | /* |
750 | * Enable synchronisation. | 757 | * Enable synchronisation. |
751 | */ | 758 | */ |
@@ -768,8 +775,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | |||
768 | 775 | ||
769 | if (flags & CONFIG_UPDATE_BSSID) { | 776 | if (flags & CONFIG_UPDATE_BSSID) { |
770 | reg = le32_to_cpu(conf->bssid[1]); | 777 | reg = le32_to_cpu(conf->bssid[1]); |
771 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); | 778 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); |
772 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); | 779 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); |
773 | conf->bssid[1] = cpu_to_le32(reg); | 780 | conf->bssid[1] = cpu_to_le32(reg); |
774 | 781 | ||
775 | rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, | 782 | rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, |
@@ -827,14 +834,12 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) | |||
827 | switch ((int)ant->tx) { | 834 | switch ((int)ant->tx) { |
828 | case 1: | 835 | case 1: |
829 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); | 836 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); |
830 | if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) | ||
831 | rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); | ||
832 | break; | 837 | break; |
833 | case 2: | 838 | case 2: |
834 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); | 839 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); |
835 | break; | 840 | break; |
836 | case 3: | 841 | case 3: |
837 | /* Do nothing */ | 842 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); |
838 | break; | 843 | break; |
839 | } | 844 | } |
840 | 845 | ||
@@ -1565,18 +1570,15 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | |||
1565 | 1570 | ||
1566 | /* | 1571 | /* |
1567 | * Clear all beacons | 1572 | * Clear all beacons |
1568 | * For the Beacon base registers we only need to clear | ||
1569 | * the first byte since that byte contains the VALID and OWNER | ||
1570 | * bits which (when set to 0) will invalidate the entire beacon. | ||
1571 | */ | 1573 | */ |
1572 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); | 1574 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0); |
1573 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); | 1575 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1); |
1574 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); | 1576 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2); |
1575 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); | 1577 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3); |
1576 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); | 1578 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4); |
1577 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); | 1579 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5); |
1578 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); | 1580 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6); |
1579 | rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); | 1581 | rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7); |
1580 | 1582 | ||
1581 | if (rt2x00_is_usb(rt2x00dev)) { | 1583 | if (rt2x00_is_usb(rt2x00dev)) { |
1582 | rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); | 1584 | rt2800_register_read(rt2x00dev, US_CYC_CNT, ®); |
@@ -2185,6 +2187,8 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2185 | rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); | 2187 | rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); |
2186 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); | 2188 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); |
2187 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); | 2189 | rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); |
2190 | rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0); | ||
2191 | rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0); | ||
2188 | rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); | 2192 | rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); |
2189 | EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); | 2193 | EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); |
2190 | } | 2194 | } |
@@ -2192,6 +2196,10 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2192 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); | 2196 | rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); |
2193 | if ((word & 0x00ff) == 0x00ff) { | 2197 | if ((word & 0x00ff) == 0x00ff) { |
2194 | rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); | 2198 | rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); |
2199 | rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); | ||
2200 | EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); | ||
2201 | } | ||
2202 | if ((word & 0xff00) == 0xff00) { | ||
2195 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, | 2203 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, |
2196 | LED_MODE_TXRX_ACTIVITY); | 2204 | LED_MODE_TXRX_ACTIVITY); |
2197 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); | 2205 | rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); |
@@ -2199,7 +2207,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | |||
2199 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); | 2207 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); |
2200 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); | 2208 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); |
2201 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); | 2209 | rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); |
2202 | EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); | 2210 | EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word); |
2203 | } | 2211 | } |
2204 | 2212 | ||
2205 | /* | 2213 | /* |
@@ -2499,7 +2507,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2499 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 2507 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
2500 | IEEE80211_HW_SIGNAL_DBM | | 2508 | IEEE80211_HW_SIGNAL_DBM | |
2501 | IEEE80211_HW_SUPPORTS_PS | | 2509 | IEEE80211_HW_SUPPORTS_PS | |
2502 | IEEE80211_HW_PS_NULLFUNC_STACK; | 2510 | IEEE80211_HW_PS_NULLFUNC_STACK | |
2511 | IEEE80211_HW_AMPDU_AGGREGATION; | ||
2503 | 2512 | ||
2504 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); | 2513 | SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); |
2505 | SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, | 2514 | SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, |
@@ -2559,12 +2568,15 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2559 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 2568 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
2560 | IEEE80211_HT_CAP_GRN_FLD | | 2569 | IEEE80211_HT_CAP_GRN_FLD | |
2561 | IEEE80211_HT_CAP_SGI_20 | | 2570 | IEEE80211_HT_CAP_SGI_20 | |
2562 | IEEE80211_HT_CAP_SGI_40 | | 2571 | IEEE80211_HT_CAP_SGI_40; |
2563 | IEEE80211_HT_CAP_RX_STBC; | ||
2564 | 2572 | ||
2565 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2) | 2573 | if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2) |
2566 | spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC; | 2574 | spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC; |
2567 | 2575 | ||
2576 | spec->ht.cap |= | ||
2577 | rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) << | ||
2578 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | ||
2579 | |||
2568 | spec->ht.ampdu_factor = 3; | 2580 | spec->ht.ampdu_factor = 3; |
2569 | spec->ht.ampdu_density = 4; | 2581 | spec->ht.ampdu_density = 4; |
2570 | spec->ht.mcs.tx_params = | 2582 | spec->ht.mcs.tx_params = |
@@ -2751,6 +2763,35 @@ static u64 rt2800_get_tsf(struct ieee80211_hw *hw) | |||
2751 | return tsf; | 2763 | return tsf; |
2752 | } | 2764 | } |
2753 | 2765 | ||
2766 | static int rt2800_ampdu_action(struct ieee80211_hw *hw, | ||
2767 | struct ieee80211_vif *vif, | ||
2768 | enum ieee80211_ampdu_mlme_action action, | ||
2769 | struct ieee80211_sta *sta, | ||
2770 | u16 tid, u16 *ssn) | ||
2771 | { | ||
2772 | int ret = 0; | ||
2773 | |||
2774 | switch (action) { | ||
2775 | case IEEE80211_AMPDU_RX_START: | ||
2776 | case IEEE80211_AMPDU_RX_STOP: | ||
2777 | /* we don't support RX aggregation yet */ | ||
2778 | ret = -ENOTSUPP; | ||
2779 | break; | ||
2780 | case IEEE80211_AMPDU_TX_START: | ||
2781 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
2782 | break; | ||
2783 | case IEEE80211_AMPDU_TX_STOP: | ||
2784 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||
2785 | break; | ||
2786 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
2787 | break; | ||
2788 | default: | ||
2789 | WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n"); | ||
2790 | } | ||
2791 | |||
2792 | return ret; | ||
2793 | } | ||
2794 | |||
2754 | const struct ieee80211_ops rt2800_mac80211_ops = { | 2795 | const struct ieee80211_ops rt2800_mac80211_ops = { |
2755 | .tx = rt2x00mac_tx, | 2796 | .tx = rt2x00mac_tx, |
2756 | .start = rt2x00mac_start, | 2797 | .start = rt2x00mac_start, |
@@ -2768,6 +2809,7 @@ const struct ieee80211_ops rt2800_mac80211_ops = { | |||
2768 | .conf_tx = rt2800_conf_tx, | 2809 | .conf_tx = rt2800_conf_tx, |
2769 | .get_tsf = rt2800_get_tsf, | 2810 | .get_tsf = rt2800_get_tsf, |
2770 | .rfkill_poll = rt2x00mac_rfkill_poll, | 2811 | .rfkill_poll = rt2x00mac_rfkill_poll, |
2812 | .ampdu_action = rt2800_ampdu_action, | ||
2771 | }; | 2813 | }; |
2772 | EXPORT_SYMBOL_GPL(rt2800_mac80211_ops); | 2814 | EXPORT_SYMBOL_GPL(rt2800_mac80211_ops); |
2773 | 2815 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index e5ea670a18db..6f11760117da 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -139,8 +139,18 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) | |||
139 | eeprom.data = rt2x00dev; | 139 | eeprom.data = rt2x00dev; |
140 | eeprom.register_read = rt2800pci_eepromregister_read; | 140 | eeprom.register_read = rt2800pci_eepromregister_read; |
141 | eeprom.register_write = rt2800pci_eepromregister_write; | 141 | eeprom.register_write = rt2800pci_eepromregister_write; |
142 | eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ? | 142 | switch (rt2x00_get_field32(reg, E2PROM_CSR_TYPE)) |
143 | PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; | 143 | { |
144 | case 0: | ||
145 | eeprom.width = PCI_EEPROM_WIDTH_93C46; | ||
146 | break; | ||
147 | case 1: | ||
148 | eeprom.width = PCI_EEPROM_WIDTH_93C66; | ||
149 | break; | ||
150 | default: | ||
151 | eeprom.width = PCI_EEPROM_WIDTH_93C86; | ||
152 | break; | ||
153 | } | ||
144 | eeprom.reg_data_in = 0; | 154 | eeprom.reg_data_in = 0; |
145 | eeprom.reg_data_out = 0; | 155 | eeprom.reg_data_out = 0; |
146 | eeprom.reg_data_clock = 0; | 156 | eeprom.reg_data_clock = 0; |
@@ -645,10 +655,12 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
645 | /* | 655 | /* |
646 | * TX descriptor initialization | 656 | * TX descriptor initialization |
647 | */ | 657 | */ |
648 | static void rt2800pci_write_tx_datadesc(struct queue_entry* entry, | 658 | static void rt2800pci_write_tx_data(struct queue_entry* entry, |
649 | struct txentry_desc *txdesc) | 659 | struct txentry_desc *txdesc) |
650 | { | 660 | { |
651 | rt2800_write_txwi((__le32 *) entry->skb->data, txdesc); | 661 | __le32 *txwi = (__le32 *) entry->skb->data; |
662 | |||
663 | rt2800_write_txwi(txwi, txdesc); | ||
652 | } | 664 | } |
653 | 665 | ||
654 | 666 | ||
@@ -905,7 +917,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
905 | if (txdesc.retry) | 917 | if (txdesc.retry) |
906 | __set_bit(TXDONE_FALLBACK, &txdesc.flags); | 918 | __set_bit(TXDONE_FALLBACK, &txdesc.flags); |
907 | 919 | ||
908 | rt2x00pci_txdone(entry, &txdesc); | 920 | rt2x00lib_txdone(entry, &txdesc); |
909 | } | 921 | } |
910 | } | 922 | } |
911 | 923 | ||
@@ -941,6 +953,12 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) | |||
941 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) | 953 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) |
942 | rt2800pci_txdone(rt2x00dev); | 954 | rt2800pci_txdone(rt2x00dev); |
943 | 955 | ||
956 | /* | ||
957 | * Current beacon was sent out, fetch the next one | ||
958 | */ | ||
959 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT)) | ||
960 | rt2x00lib_beacondone(rt2x00dev); | ||
961 | |||
944 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) | 962 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) |
945 | rt2800pci_wakeup(rt2x00dev); | 963 | rt2800pci_wakeup(rt2x00dev); |
946 | 964 | ||
@@ -1044,8 +1062,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { | |||
1044 | .reset_tuner = rt2800_reset_tuner, | 1062 | .reset_tuner = rt2800_reset_tuner, |
1045 | .link_tuner = rt2800_link_tuner, | 1063 | .link_tuner = rt2800_link_tuner, |
1046 | .write_tx_desc = rt2800pci_write_tx_desc, | 1064 | .write_tx_desc = rt2800pci_write_tx_desc, |
1047 | .write_tx_data = rt2x00pci_write_tx_data, | 1065 | .write_tx_data = rt2800pci_write_tx_data, |
1048 | .write_tx_datadesc = rt2800pci_write_tx_datadesc, | ||
1049 | .write_beacon = rt2800_write_beacon, | 1066 | .write_beacon = rt2800_write_beacon, |
1050 | .kick_tx_queue = rt2800pci_kick_tx_queue, | 1067 | .kick_tx_queue = rt2800pci_kick_tx_queue, |
1051 | .kill_tx_queue = rt2800pci_kill_tx_queue, | 1068 | .kill_tx_queue = rt2800pci_kill_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f18c12a19cc9..4f85f7b42441 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -430,21 +430,24 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
430 | /* | 430 | /* |
431 | * TX descriptor initialization | 431 | * TX descriptor initialization |
432 | */ | 432 | */ |
433 | static void rt2800usb_write_tx_data(struct queue_entry* entry, | ||
434 | struct txentry_desc *txdesc) | ||
435 | { | ||
436 | __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE); | ||
437 | |||
438 | rt2800_write_txwi(txwi, txdesc); | ||
439 | } | ||
440 | |||
441 | |||
433 | static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, | 442 | static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, |
434 | struct sk_buff *skb, | 443 | struct sk_buff *skb, |
435 | struct txentry_desc *txdesc) | 444 | struct txentry_desc *txdesc) |
436 | { | 445 | { |
437 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | 446 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); |
438 | __le32 *txi = (__le32 *) skb->data; | 447 | __le32 *txi = (__le32 *) skb->data; |
439 | __le32 *txwi = (__le32 *) (skb->data + TXINFO_DESC_SIZE); | ||
440 | u32 word; | 448 | u32 word; |
441 | 449 | ||
442 | /* | 450 | /* |
443 | * Initialize TXWI descriptor | ||
444 | */ | ||
445 | rt2800_write_txwi(txwi, txdesc); | ||
446 | |||
447 | /* | ||
448 | * Initialize TXINFO descriptor | 451 | * Initialize TXINFO descriptor |
449 | */ | 452 | */ |
450 | rt2x00_desc_read(txi, 0, &word); | 453 | rt2x00_desc_read(txi, 0, &word); |
@@ -652,7 +655,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { | |||
652 | .reset_tuner = rt2800_reset_tuner, | 655 | .reset_tuner = rt2800_reset_tuner, |
653 | .link_tuner = rt2800_link_tuner, | 656 | .link_tuner = rt2800_link_tuner, |
654 | .write_tx_desc = rt2800usb_write_tx_desc, | 657 | .write_tx_desc = rt2800usb_write_tx_desc, |
655 | .write_tx_data = rt2x00usb_write_tx_data, | 658 | .write_tx_data = rt2800usb_write_tx_data, |
656 | .write_beacon = rt2800_write_beacon, | 659 | .write_beacon = rt2800_write_beacon, |
657 | .get_tx_data_len = rt2800usb_get_tx_data_len, | 660 | .get_tx_data_len = rt2800usb_get_tx_data_len, |
658 | .kick_tx_queue = rt2x00usb_kick_tx_queue, | 661 | .kick_tx_queue = rt2x00usb_kick_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e7acc6abfd89..788b0e452cc7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -550,10 +550,8 @@ struct rt2x00lib_ops { | |||
550 | void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, | 550 | void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, |
551 | struct sk_buff *skb, | 551 | struct sk_buff *skb, |
552 | struct txentry_desc *txdesc); | 552 | struct txentry_desc *txdesc); |
553 | int (*write_tx_data) (struct queue_entry *entry, | 553 | void (*write_tx_data) (struct queue_entry *entry, |
554 | struct txentry_desc *txdesc); | 554 | struct txentry_desc *txdesc); |
555 | void (*write_tx_datadesc) (struct queue_entry *entry, | ||
556 | struct txentry_desc *txdesc); | ||
557 | void (*write_beacon) (struct queue_entry *entry, | 555 | void (*write_beacon) (struct queue_entry *entry, |
558 | struct txentry_desc *txdesc); | 556 | struct txentry_desc *txdesc); |
559 | int (*get_tx_data_len) (struct queue_entry *entry); | 557 | int (*get_tx_data_len) (struct queue_entry *entry); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 339cc84bf4fb..12ee7bdedd02 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -211,6 +211,21 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
211 | bool success; | 211 | bool success; |
212 | 212 | ||
213 | /* | 213 | /* |
214 | * Unmap the skb. | ||
215 | */ | ||
216 | rt2x00queue_unmap_skb(rt2x00dev, entry->skb); | ||
217 | |||
218 | /* | ||
219 | * Remove the extra tx headroom from the skb. | ||
220 | */ | ||
221 | skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom); | ||
222 | |||
223 | /* | ||
224 | * Signal that the TX descriptor is no longer in the skb. | ||
225 | */ | ||
226 | skbdesc->flags &= ~SKBDESC_DESC_IN_SKB; | ||
227 | |||
228 | /* | ||
214 | * Remove L2 padding which was added during | 229 | * Remove L2 padding which was added during |
215 | */ | 230 | */ |
216 | if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) | 231 | if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) |
@@ -286,6 +301,21 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
286 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; | 301 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; |
287 | } | 302 | } |
288 | 303 | ||
304 | /* | ||
305 | * Every single frame has it's own tx status, hence report | ||
306 | * every frame as ampdu of size 1. | ||
307 | * | ||
308 | * TODO: if we can find out how many frames were aggregated | ||
309 | * by the hw we could provide the real ampdu_len to mac80211 | ||
310 | * which would allow the rc algorithm to better decide on | ||
311 | * which rates are suitable. | ||
312 | */ | ||
313 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | ||
314 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU; | ||
315 | tx_info->status.ampdu_len = 1; | ||
316 | tx_info->status.ampdu_ack_len = success ? 1 : 0; | ||
317 | } | ||
318 | |||
289 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | 319 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { |
290 | if (success) | 320 | if (success) |
291 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; | 321 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 0efbf5a6c254..2f8136cab7d8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -271,11 +271,11 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) | |||
271 | 271 | ||
272 | /* | 272 | /* |
273 | * Link tuning should only be performed when | 273 | * Link tuning should only be performed when |
274 | * an active sta or master interface exists. | 274 | * an active sta interface exists. AP interfaces |
275 | * Single monitor mode interfaces should never have | 275 | * don't need link tuning and monitor mode interfaces |
276 | * work with link tuners. | 276 | * should never have to work with link tuners. |
277 | */ | 277 | */ |
278 | if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count) | 278 | if (!rt2x00dev->intf_sta_count) |
279 | return; | 279 | return; |
280 | 280 | ||
281 | rt2x00link_reset_tuner(rt2x00dev, false); | 281 | rt2x00link_reset_tuner(rt2x00dev, false); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index abbd857ec759..3b838c0bf59f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -282,7 +282,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | |||
282 | * has been initialized. Otherwise the device can reset | 282 | * has been initialized. Otherwise the device can reset |
283 | * the MAC registers. | 283 | * the MAC registers. |
284 | */ | 284 | */ |
285 | rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL); | 285 | rt2x00lib_config_intf(rt2x00dev, intf, vif->type, |
286 | intf->mac, intf->bssid); | ||
286 | 287 | ||
287 | /* | 288 | /* |
288 | * Some filters depend on the current working mode. We can force | 289 | * Some filters depend on the current working mode. We can force |
@@ -562,7 +563,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
562 | { | 563 | { |
563 | struct rt2x00_dev *rt2x00dev = hw->priv; | 564 | struct rt2x00_dev *rt2x00dev = hw->priv; |
564 | struct rt2x00_intf *intf = vif_to_intf(vif); | 565 | struct rt2x00_intf *intf = vif_to_intf(vif); |
565 | int update_bssid = 0; | ||
566 | 566 | ||
567 | /* | 567 | /* |
568 | * mac80211 might be calling this function while we are trying | 568 | * mac80211 might be calling this function while we are trying |
@@ -577,10 +577,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
577 | * conf->bssid can be NULL if coming from the internal | 577 | * conf->bssid can be NULL if coming from the internal |
578 | * beacon update routine. | 578 | * beacon update routine. |
579 | */ | 579 | */ |
580 | if (changes & BSS_CHANGED_BSSID) { | 580 | if (changes & BSS_CHANGED_BSSID) |
581 | update_bssid = 1; | ||
582 | memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN); | 581 | memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN); |
583 | } | ||
584 | 582 | ||
585 | spin_unlock(&intf->lock); | 583 | spin_unlock(&intf->lock); |
586 | 584 | ||
@@ -592,7 +590,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, | |||
592 | */ | 590 | */ |
593 | if (changes & BSS_CHANGED_BSSID) | 591 | if (changes & BSS_CHANGED_BSSID) |
594 | rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, | 592 | rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, |
595 | update_bssid ? bss_conf->bssid : NULL); | 593 | bss_conf->bssid); |
596 | 594 | ||
597 | /* | 595 | /* |
598 | * Update the beacon. | 596 | * Update the beacon. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 10eaffd12b1b..fc9da8358784 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c | |||
@@ -60,80 +60,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
60 | } | 60 | } |
61 | EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); | 61 | EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); |
62 | 62 | ||
63 | /* | ||
64 | * TX data handlers. | ||
65 | */ | ||
66 | int rt2x00pci_write_tx_data(struct queue_entry *entry, | ||
67 | struct txentry_desc *txdesc) | ||
68 | { | ||
69 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
70 | |||
71 | /* | ||
72 | * This should not happen, we already checked the entry | ||
73 | * was ours. When the hardware disagrees there has been | ||
74 | * a queue corruption! | ||
75 | */ | ||
76 | if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) { | ||
77 | ERROR(rt2x00dev, | ||
78 | "Corrupt queue %d, accessing entry which is not ours.\n" | ||
79 | "Please file bug report to %s.\n", | ||
80 | entry->queue->qid, DRV_PROJECT); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Add the requested extra tx headroom in front of the skb. | ||
86 | */ | ||
87 | skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom); | ||
88 | memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom); | ||
89 | |||
90 | /* | ||
91 | * Call the driver's write_tx_datadesc function, if it exists. | ||
92 | */ | ||
93 | if (rt2x00dev->ops->lib->write_tx_datadesc) | ||
94 | rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc); | ||
95 | |||
96 | /* | ||
97 | * Map the skb to DMA. | ||
98 | */ | ||
99 | if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) | ||
100 | rt2x00queue_map_txskb(rt2x00dev, entry->skb); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); | ||
105 | |||
106 | /* | ||
107 | * TX/RX data handlers. | ||
108 | */ | ||
109 | void rt2x00pci_txdone(struct queue_entry *entry, | ||
110 | struct txdone_entry_desc *txdesc) | ||
111 | { | ||
112 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
113 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); | ||
114 | |||
115 | /* | ||
116 | * Unmap the skb. | ||
117 | */ | ||
118 | rt2x00queue_unmap_skb(rt2x00dev, entry->skb); | ||
119 | |||
120 | /* | ||
121 | * Remove the extra tx headroom from the skb. | ||
122 | */ | ||
123 | skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom); | ||
124 | |||
125 | /* | ||
126 | * Signal that the TX descriptor is no longer in the skb. | ||
127 | */ | ||
128 | skbdesc->flags &= ~SKBDESC_DESC_IN_SKB; | ||
129 | |||
130 | /* | ||
131 | * Pass on to rt2x00lib. | ||
132 | */ | ||
133 | rt2x00lib_txdone(entry, txdesc); | ||
134 | } | ||
135 | EXPORT_SYMBOL_GPL(rt2x00pci_txdone); | ||
136 | |||
137 | void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) | 63 | void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) |
138 | { | 64 | { |
139 | struct data_queue *queue = rt2x00dev->rx; | 65 | struct data_queue *queue = rt2x00dev->rx; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 00528b8a754d..b854d62ff99b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h | |||
@@ -86,16 +86,6 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
86 | u32 *reg); | 86 | u32 *reg); |
87 | 87 | ||
88 | /** | 88 | /** |
89 | * rt2x00pci_write_tx_data - Initialize data for TX operation | ||
90 | * @entry: The entry where the frame is located | ||
91 | * | ||
92 | * This function will initialize the DMA and skb descriptor | ||
93 | * to prepare the entry for the actual TX operation. | ||
94 | */ | ||
95 | int rt2x00pci_write_tx_data(struct queue_entry *entry, | ||
96 | struct txentry_desc *txdesc); | ||
97 | |||
98 | /** | ||
99 | * struct queue_entry_priv_pci: Per entry PCI specific information | 89 | * struct queue_entry_priv_pci: Per entry PCI specific information |
100 | * | 90 | * |
101 | * @desc: Pointer to device descriptor | 91 | * @desc: Pointer to device descriptor |
@@ -109,14 +99,6 @@ struct queue_entry_priv_pci { | |||
109 | }; | 99 | }; |
110 | 100 | ||
111 | /** | 101 | /** |
112 | * rt2x00pci_txdone - Handle TX done events. | ||
113 | * @entry: The queue entry for which a TX done event was received. | ||
114 | * @txdesc: The TX done descriptor for the entry. | ||
115 | */ | ||
116 | void rt2x00pci_txdone(struct queue_entry *entry, | ||
117 | struct txdone_entry_desc *txdesc); | ||
118 | |||
119 | /** | ||
120 | * rt2x00pci_rxdone - Handle RX done events | 102 | * rt2x00pci_rxdone - Handle RX done events |
121 | * @rt2x00dev: Device pointer, see &struct rt2x00_dev. | 103 | * @rt2x00dev: Device pointer, see &struct rt2x00_dev. |
122 | */ | 104 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index f91637147116..5097fe0f9f51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -404,6 +404,46 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
404 | rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); | 404 | rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); |
405 | } | 405 | } |
406 | 406 | ||
407 | static int rt2x00queue_write_tx_data(struct queue_entry *entry, | ||
408 | struct txentry_desc *txdesc) | ||
409 | { | ||
410 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
411 | |||
412 | /* | ||
413 | * This should not happen, we already checked the entry | ||
414 | * was ours. When the hardware disagrees there has been | ||
415 | * a queue corruption! | ||
416 | */ | ||
417 | if (unlikely(rt2x00dev->ops->lib->get_entry_state && | ||
418 | rt2x00dev->ops->lib->get_entry_state(entry))) { | ||
419 | ERROR(rt2x00dev, | ||
420 | "Corrupt queue %d, accessing entry which is not ours.\n" | ||
421 | "Please file bug report to %s.\n", | ||
422 | entry->queue->qid, DRV_PROJECT); | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Add the requested extra tx headroom in front of the skb. | ||
428 | */ | ||
429 | skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom); | ||
430 | memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom); | ||
431 | |||
432 | /* | ||
433 | * Call the driver's write_tx_data function, if it exists. | ||
434 | */ | ||
435 | if (rt2x00dev->ops->lib->write_tx_data) | ||
436 | rt2x00dev->ops->lib->write_tx_data(entry, txdesc); | ||
437 | |||
438 | /* | ||
439 | * Map the skb to DMA. | ||
440 | */ | ||
441 | if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) | ||
442 | rt2x00queue_map_txskb(rt2x00dev, entry->skb); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
407 | static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, | 447 | static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, |
408 | struct txentry_desc *txdesc) | 448 | struct txentry_desc *txdesc) |
409 | { | 449 | { |
@@ -515,8 +555,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, | |||
515 | * call failed. Since we always return NETDEV_TX_OK to mac80211, | 555 | * call failed. Since we always return NETDEV_TX_OK to mac80211, |
516 | * this frame will simply be dropped. | 556 | * this frame will simply be dropped. |
517 | */ | 557 | */ |
518 | if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry, | 558 | if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) { |
519 | &txdesc))) { | ||
520 | clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); | 559 | clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); |
521 | entry->skb = NULL; | 560 | entry->skb = NULL; |
522 | return -EIO; | 561 | return -EIO; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index b45bc24c3dae..a22837c560fd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -178,11 +178,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
178 | return; | 178 | return; |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * Remove the descriptor from the front of the skb. | ||
182 | */ | ||
183 | skb_pull(entry->skb, entry->queue->desc_size); | ||
184 | |||
185 | /* | ||
186 | * Obtain the status about this packet. | 181 | * Obtain the status about this packet. |
187 | * Note that when the status is 0 it does not mean the | 182 | * Note that when the status is 0 it does not mean the |
188 | * frame was send out correctly. It only means the frame | 183 | * frame was send out correctly. It only means the frame |
@@ -201,48 +196,28 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
201 | rt2x00lib_txdone(entry, &txdesc); | 196 | rt2x00lib_txdone(entry, &txdesc); |
202 | } | 197 | } |
203 | 198 | ||
204 | int rt2x00usb_write_tx_data(struct queue_entry *entry, | 199 | static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) |
205 | struct txentry_desc *txdesc) | ||
206 | { | 200 | { |
207 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 201 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
208 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | 202 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); |
209 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | 203 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; |
210 | u32 length; | 204 | u32 length; |
211 | 205 | ||
212 | /* | 206 | if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) { |
213 | * Add the descriptor in front of the skb. | 207 | /* |
214 | */ | 208 | * USB devices cannot blindly pass the skb->len as the |
215 | skb_push(entry->skb, entry->queue->desc_size); | 209 | * length of the data to usb_fill_bulk_urb. Pass the skb |
216 | memset(entry->skb->data, 0, entry->queue->desc_size); | 210 | * to the driver to determine what the length should be. |
217 | 211 | */ | |
218 | /* | 212 | length = rt2x00dev->ops->lib->get_tx_data_len(entry); |
219 | * USB devices cannot blindly pass the skb->len as the | ||
220 | * length of the data to usb_fill_bulk_urb. Pass the skb | ||
221 | * to the driver to determine what the length should be. | ||
222 | */ | ||
223 | length = rt2x00dev->ops->lib->get_tx_data_len(entry); | ||
224 | |||
225 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, | ||
226 | usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), | ||
227 | entry->skb->data, length, | ||
228 | rt2x00usb_interrupt_txdone, entry); | ||
229 | |||
230 | /* | ||
231 | * Call the driver's write_tx_datadesc function, if it exists. | ||
232 | */ | ||
233 | if (rt2x00dev->ops->lib->write_tx_datadesc) | ||
234 | rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); | ||
239 | 213 | ||
240 | static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) | 214 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, |
241 | { | 215 | usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), |
242 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | 216 | entry->skb->data, length, |
217 | rt2x00usb_interrupt_txdone, entry); | ||
243 | 218 | ||
244 | if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) | ||
245 | usb_submit_urb(entry_priv->urb, GFP_ATOMIC); | 219 | usb_submit_urb(entry_priv->urb, GFP_ATOMIC); |
220 | } | ||
246 | } | 221 | } |
247 | 222 | ||
248 | void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, | 223 | void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 255b81ef9530..2b7a1889e72f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h | |||
@@ -351,16 +351,6 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, | |||
351 | void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); | 351 | void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); |
352 | 352 | ||
353 | /** | 353 | /** |
354 | * rt2x00usb_write_tx_data - Initialize URB for TX operation | ||
355 | * @entry: The entry where the frame is located | ||
356 | * | ||
357 | * This function will initialize the URB and skb descriptor | ||
358 | * to prepare the entry for the actual TX operation. | ||
359 | */ | ||
360 | int rt2x00usb_write_tx_data(struct queue_entry *entry, | ||
361 | struct txentry_desc *txdesc); | ||
362 | |||
363 | /** | ||
364 | * struct queue_entry_priv_usb: Per entry USB specific information | 354 | * struct queue_entry_priv_usb: Per entry USB specific information |
365 | * | 355 | * |
366 | * @urb: Urb structure used for device communication. | 356 | * @urb: Urb structure used for device communication. |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 7ca383478eeb..0123fbc22ca2 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2108,7 +2108,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
2108 | __set_bit(TXDONE_UNKNOWN, &txdesc.flags); | 2108 | __set_bit(TXDONE_UNKNOWN, &txdesc.flags); |
2109 | txdesc.retry = 0; | 2109 | txdesc.retry = 0; |
2110 | 2110 | ||
2111 | rt2x00pci_txdone(entry_done, &txdesc); | 2111 | rt2x00lib_txdone(entry_done, &txdesc); |
2112 | entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | 2112 | entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); |
2113 | } | 2113 | } |
2114 | 2114 | ||
@@ -2135,7 +2135,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
2135 | if (txdesc.retry) | 2135 | if (txdesc.retry) |
2136 | __set_bit(TXDONE_FALLBACK, &txdesc.flags); | 2136 | __set_bit(TXDONE_FALLBACK, &txdesc.flags); |
2137 | 2137 | ||
2138 | rt2x00pci_txdone(entry, &txdesc); | 2138 | rt2x00lib_txdone(entry, &txdesc); |
2139 | } | 2139 | } |
2140 | } | 2140 | } |
2141 | 2141 | ||
@@ -2200,6 +2200,12 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) | |||
2200 | if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) | 2200 | if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) |
2201 | rt61pci_wakeup(rt2x00dev); | 2201 | rt61pci_wakeup(rt2x00dev); |
2202 | 2202 | ||
2203 | /* | ||
2204 | * 5 - Beacon done interrupt. | ||
2205 | */ | ||
2206 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) | ||
2207 | rt2x00lib_beacondone(rt2x00dev); | ||
2208 | |||
2203 | return IRQ_HANDLED; | 2209 | return IRQ_HANDLED; |
2204 | } | 2210 | } |
2205 | 2211 | ||
@@ -2800,7 +2806,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { | |||
2800 | .reset_tuner = rt61pci_reset_tuner, | 2806 | .reset_tuner = rt61pci_reset_tuner, |
2801 | .link_tuner = rt61pci_link_tuner, | 2807 | .link_tuner = rt61pci_link_tuner, |
2802 | .write_tx_desc = rt61pci_write_tx_desc, | 2808 | .write_tx_desc = rt61pci_write_tx_desc, |
2803 | .write_tx_data = rt2x00pci_write_tx_data, | ||
2804 | .write_beacon = rt61pci_write_beacon, | 2809 | .write_beacon = rt61pci_write_beacon, |
2805 | .kick_tx_queue = rt61pci_kick_tx_queue, | 2810 | .kick_tx_queue = rt61pci_kick_tx_queue, |
2806 | .kill_tx_queue = rt61pci_kill_tx_queue, | 2811 | .kill_tx_queue = rt61pci_kill_tx_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d06d90f003e7..286dd97e51d8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -2249,7 +2249,6 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { | |||
2249 | .reset_tuner = rt73usb_reset_tuner, | 2249 | .reset_tuner = rt73usb_reset_tuner, |
2250 | .link_tuner = rt73usb_link_tuner, | 2250 | .link_tuner = rt73usb_link_tuner, |
2251 | .write_tx_desc = rt73usb_write_tx_desc, | 2251 | .write_tx_desc = rt73usb_write_tx_desc, |
2252 | .write_tx_data = rt2x00usb_write_tx_data, | ||
2253 | .write_beacon = rt73usb_write_beacon, | 2252 | .write_beacon = rt73usb_write_beacon, |
2254 | .get_tx_data_len = rt73usb_get_tx_data_len, | 2253 | .get_tx_data_len = rt73usb_get_tx_data_len, |
2255 | .kick_tx_queue = rt2x00usb_kick_tx_queue, | 2254 | .kick_tx_queue = rt2x00usb_kick_tx_queue, |
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 515817de2905..42705028751d 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c | |||
@@ -671,7 +671,7 @@ static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) | |||
671 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; | 671 | (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32; |
672 | } | 672 | } |
673 | 673 | ||
674 | void rtl8180_beacon_work(struct work_struct *work) | 674 | static void rtl8180_beacon_work(struct work_struct *work) |
675 | { | 675 | { |
676 | struct rtl8180_vif *vif_priv = | 676 | struct rtl8180_vif *vif_priv = |
677 | container_of(work, struct rtl8180_vif, beacon_work.work); | 677 | container_of(work, struct rtl8180_vif, beacon_work.work); |
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h index a55c873e8b66..c4627cbdb8e0 100644 --- a/include/linux/eeprom_93cx6.h +++ b/include/linux/eeprom_93cx6.h | |||
@@ -30,6 +30,7 @@ | |||
30 | #define PCI_EEPROM_WIDTH_93C46 6 | 30 | #define PCI_EEPROM_WIDTH_93C46 6 |
31 | #define PCI_EEPROM_WIDTH_93C56 8 | 31 | #define PCI_EEPROM_WIDTH_93C56 8 |
32 | #define PCI_EEPROM_WIDTH_93C66 8 | 32 | #define PCI_EEPROM_WIDTH_93C66 8 |
33 | #define PCI_EEPROM_WIDTH_93C86 8 | ||
33 | #define PCI_EEPROM_WIDTH_OPCODE 3 | 34 | #define PCI_EEPROM_WIDTH_OPCODE 3 |
34 | #define PCI_EEPROM_WRITE_OPCODE 0x05 | 35 | #define PCI_EEPROM_WRITE_OPCODE 0x05 |
35 | #define PCI_EEPROM_READ_OPCODE 0x06 | 36 | #define PCI_EEPROM_READ_OPCODE 0x06 |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 64fb32b93a28..2c8701687336 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -725,6 +725,12 @@ enum nl80211_commands { | |||
725 | * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations | 725 | * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations |
726 | * connected to this BSS. | 726 | * connected to this BSS. |
727 | * | 727 | * |
728 | * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See | ||
729 | * &enum nl80211_tx_power_setting for possible values. | ||
730 | * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units. | ||
731 | * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING | ||
732 | * for non-automatic settings. | ||
733 | * | ||
728 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 734 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
729 | * @__NL80211_ATTR_AFTER_LAST: internal use | 735 | * @__NL80211_ATTR_AFTER_LAST: internal use |
730 | */ | 736 | */ |
@@ -882,6 +888,9 @@ enum nl80211_attrs { | |||
882 | 888 | ||
883 | NL80211_ATTR_AP_ISOLATE, | 889 | NL80211_ATTR_AP_ISOLATE, |
884 | 890 | ||
891 | NL80211_ATTR_WIPHY_TX_POWER_SETTING, | ||
892 | NL80211_ATTR_WIPHY_TX_POWER_LEVEL, | ||
893 | |||
885 | /* add attributes here, update the policy in nl80211.c */ | 894 | /* add attributes here, update the policy in nl80211.c */ |
886 | 895 | ||
887 | __NL80211_ATTR_AFTER_LAST, | 896 | __NL80211_ATTR_AFTER_LAST, |
@@ -1659,4 +1668,17 @@ enum nl80211_cqm_rssi_threshold_event { | |||
1659 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | 1668 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, |
1660 | }; | 1669 | }; |
1661 | 1670 | ||
1671 | |||
1672 | /** | ||
1673 | * enum nl80211_tx_power_setting - TX power adjustment | ||
1674 | * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power | ||
1675 | * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter | ||
1676 | * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter | ||
1677 | */ | ||
1678 | enum nl80211_tx_power_setting { | ||
1679 | NL80211_TX_POWER_AUTOMATIC, | ||
1680 | NL80211_TX_POWER_LIMITED, | ||
1681 | NL80211_TX_POWER_FIXED, | ||
1682 | }; | ||
1683 | |||
1662 | #endif /* __LINUX_NL80211_H */ | 1684 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9c45b905aefc..168fe530b214 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -875,19 +875,6 @@ enum wiphy_params_flags { | |||
875 | WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, | 875 | WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, |
876 | }; | 876 | }; |
877 | 877 | ||
878 | /** | ||
879 | * enum tx_power_setting - TX power adjustment | ||
880 | * | ||
881 | * @TX_POWER_AUTOMATIC: the dbm parameter is ignored | ||
882 | * @TX_POWER_LIMITED: limit TX power by the dbm parameter | ||
883 | * @TX_POWER_FIXED: fix TX power to the dbm parameter | ||
884 | */ | ||
885 | enum tx_power_setting { | ||
886 | TX_POWER_AUTOMATIC, | ||
887 | TX_POWER_LIMITED, | ||
888 | TX_POWER_FIXED, | ||
889 | }; | ||
890 | |||
891 | /* | 878 | /* |
892 | * cfg80211_bitrate_mask - masks for bitrate control | 879 | * cfg80211_bitrate_mask - masks for bitrate control |
893 | */ | 880 | */ |
@@ -1149,7 +1136,7 @@ struct cfg80211_ops { | |||
1149 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); | 1136 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); |
1150 | 1137 | ||
1151 | int (*set_tx_power)(struct wiphy *wiphy, | 1138 | int (*set_tx_power)(struct wiphy *wiphy, |
1152 | enum tx_power_setting type, int dbm); | 1139 | enum nl80211_tx_power_setting type, int mbm); |
1153 | int (*get_tx_power)(struct wiphy *wiphy, int *dbm); | 1140 | int (*get_tx_power)(struct wiphy *wiphy, int *dbm); |
1154 | 1141 | ||
1155 | int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, | 1142 | int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index fe1a3a603375..7f256e23c57f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1271,6 +1271,15 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
1271 | * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS | 1271 | * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS |
1272 | * enabled whenever user has enabled powersave. | 1272 | * enabled whenever user has enabled powersave. |
1273 | * | 1273 | * |
1274 | * Some hardware need to toggle a single shared antenna between WLAN and | ||
1275 | * Bluetooth to facilitate co-existence. These types of hardware set | ||
1276 | * limitations on the use of host controlled dynamic powersave whenever there | ||
1277 | * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the | ||
1278 | * driver may request temporarily going into full power save, in order to | ||
1279 | * enable toggling the antenna between BT and WLAN. If the driver requests | ||
1280 | * disabling dynamic powersave, the @dynamic_ps_timeout value will be | ||
1281 | * temporarily set to zero until the driver re-enables dynamic powersave. | ||
1282 | * | ||
1274 | * Driver informs U-APSD client support by enabling | 1283 | * Driver informs U-APSD client support by enabling |
1275 | * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the | 1284 | * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the |
1276 | * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS | 1285 | * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS |
@@ -2447,6 +2456,36 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); | |||
2447 | void ieee80211_connection_loss(struct ieee80211_vif *vif); | 2456 | void ieee80211_connection_loss(struct ieee80211_vif *vif); |
2448 | 2457 | ||
2449 | /** | 2458 | /** |
2459 | * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm | ||
2460 | * | ||
2461 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
2462 | * | ||
2463 | * Some hardware require full power save to manage simultaneous BT traffic | ||
2464 | * on the WLAN frequency. Full PSM is required periodically, whenever there are | ||
2465 | * burst of BT traffic. The hardware gets information of BT traffic via | ||
2466 | * hardware co-existence lines, and consequentially requests mac80211 to | ||
2467 | * (temporarily) enter full psm. | ||
2468 | * This function will only temporarily disable dynamic PS, not enable PSM if | ||
2469 | * it was not already enabled. | ||
2470 | * The driver must make sure to re-enable dynamic PS using | ||
2471 | * ieee80211_enable_dyn_ps() if the driver has disabled it. | ||
2472 | * | ||
2473 | */ | ||
2474 | void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif); | ||
2475 | |||
2476 | /** | ||
2477 | * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled | ||
2478 | * | ||
2479 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
2480 | * | ||
2481 | * This function restores dynamic PS after being temporarily disabled via | ||
2482 | * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must | ||
2483 | * be coupled with an eventual call to this function. | ||
2484 | * | ||
2485 | */ | ||
2486 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif); | ||
2487 | |||
2488 | /** | ||
2450 | * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring | 2489 | * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring |
2451 | * rssi threshold triggered | 2490 | * rssi threshold triggered |
2452 | * | 2491 | * |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 83eec7a8bd1f..4d6f8653ec88 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -69,6 +69,7 @@ endchoice | |||
69 | 69 | ||
70 | config MAC80211_RC_DEFAULT | 70 | config MAC80211_RC_DEFAULT |
71 | string | 71 | string |
72 | default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT | ||
72 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL | 73 | default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL |
73 | default "pid" if MAC80211_RC_DEFAULT_PID | 74 | default "pid" if MAC80211_RC_DEFAULT_PID |
74 | default "" | 75 | default "" |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ed8c9f5be94f..9eb02a340889 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -413,9 +413,6 @@ static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, | |||
413 | { | 413 | { |
414 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 414 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
415 | 415 | ||
416 | if (!local->ops->get_survey) | ||
417 | return -EOPNOTSUPP; | ||
418 | |||
419 | return drv_get_survey(local, idx, survey); | 416 | return drv_get_survey(local, idx, survey); |
420 | } | 417 | } |
421 | 418 | ||
@@ -1329,28 +1326,28 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1329 | } | 1326 | } |
1330 | 1327 | ||
1331 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | 1328 | static int ieee80211_set_tx_power(struct wiphy *wiphy, |
1332 | enum tx_power_setting type, int dbm) | 1329 | enum nl80211_tx_power_setting type, int mbm) |
1333 | { | 1330 | { |
1334 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1331 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1335 | struct ieee80211_channel *chan = local->hw.conf.channel; | 1332 | struct ieee80211_channel *chan = local->hw.conf.channel; |
1336 | u32 changes = 0; | 1333 | u32 changes = 0; |
1337 | 1334 | ||
1338 | switch (type) { | 1335 | switch (type) { |
1339 | case TX_POWER_AUTOMATIC: | 1336 | case NL80211_TX_POWER_AUTOMATIC: |
1340 | local->user_power_level = -1; | 1337 | local->user_power_level = -1; |
1341 | break; | 1338 | break; |
1342 | case TX_POWER_LIMITED: | 1339 | case NL80211_TX_POWER_LIMITED: |
1343 | if (dbm < 0) | 1340 | if (mbm < 0 || (mbm % 100)) |
1344 | return -EINVAL; | 1341 | return -EOPNOTSUPP; |
1345 | local->user_power_level = dbm; | 1342 | local->user_power_level = MBM_TO_DBM(mbm); |
1346 | break; | 1343 | break; |
1347 | case TX_POWER_FIXED: | 1344 | case NL80211_TX_POWER_FIXED: |
1348 | if (dbm < 0) | 1345 | if (mbm < 0 || (mbm % 100)) |
1349 | return -EINVAL; | 1346 | return -EOPNOTSUPP; |
1350 | /* TODO: move to cfg80211 when it knows the channel */ | 1347 | /* TODO: move to cfg80211 when it knows the channel */ |
1351 | if (dbm > chan->max_power) | 1348 | if (MBM_TO_DBM(mbm) > chan->max_power) |
1352 | return -EINVAL; | 1349 | return -EINVAL; |
1353 | local->user_power_level = dbm; | 1350 | local->user_power_level = MBM_TO_DBM(mbm); |
1354 | break; | 1351 | break; |
1355 | } | 1352 | } |
1356 | 1353 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c33317320eee..14123dce544b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -375,9 +375,14 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx, | |||
375 | struct survey_info *survey) | 375 | struct survey_info *survey) |
376 | { | 376 | { |
377 | int ret = -EOPNOTSUPP; | 377 | int ret = -EOPNOTSUPP; |
378 | |||
379 | trace_drv_get_survey(local, idx, survey); | ||
380 | |||
378 | if (local->ops->get_survey) | 381 | if (local->ops->get_survey) |
379 | ret = local->ops->get_survey(&local->hw, idx, survey); | 382 | ret = local->ops->get_survey(&local->hw, idx, survey); |
380 | /* trace_drv_get_survey(local, idx, survey, ret); */ | 383 | |
384 | trace_drv_return_int(local, ret); | ||
385 | |||
381 | return ret; | 386 | return ret; |
382 | } | 387 | } |
383 | 388 | ||
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 8da31caff931..5d5d2a974668 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -761,6 +761,28 @@ TRACE_EVENT(drv_ampdu_action, | |||
761 | ) | 761 | ) |
762 | ); | 762 | ); |
763 | 763 | ||
764 | TRACE_EVENT(drv_get_survey, | ||
765 | TP_PROTO(struct ieee80211_local *local, int idx, | ||
766 | struct survey_info *survey), | ||
767 | |||
768 | TP_ARGS(local, idx, survey), | ||
769 | |||
770 | TP_STRUCT__entry( | ||
771 | LOCAL_ENTRY | ||
772 | __field(int, idx) | ||
773 | ), | ||
774 | |||
775 | TP_fast_assign( | ||
776 | LOCAL_ASSIGN; | ||
777 | __entry->idx = idx; | ||
778 | ), | ||
779 | |||
780 | TP_printk( | ||
781 | LOCAL_PR_FMT " idx:%d", | ||
782 | LOCAL_PR_ARG, __entry->idx | ||
783 | ) | ||
784 | ); | ||
785 | |||
764 | TRACE_EVENT(drv_flush, | 786 | TRACE_EVENT(drv_flush, |
765 | TP_PROTO(struct ieee80211_local *local, bool drop), | 787 | TP_PROTO(struct ieee80211_local *local, bool drop), |
766 | 788 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f905f153ed7..a3649a86a784 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -855,6 +855,8 @@ struct ieee80211_local { | |||
855 | * this will override whatever chosen by mac80211 internally. | 855 | * this will override whatever chosen by mac80211 internally. |
856 | */ | 856 | */ |
857 | int dynamic_ps_forced_timeout; | 857 | int dynamic_ps_forced_timeout; |
858 | int dynamic_ps_user_timeout; | ||
859 | bool disable_dynamic_ps; | ||
858 | 860 | ||
859 | int user_power_level; /* in dBm */ | 861 | int user_power_level; /* in dBm */ |
860 | int power_constr_level; /* in dBm */ | 862 | int power_constr_level; /* in dBm */ |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3cd5f7b5d693..ea13a80a476c 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -65,7 +65,6 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
65 | { | 65 | { |
66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
67 | mesh_accept_plinks_update(sdata); | 67 | mesh_accept_plinks_update(sdata); |
68 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
69 | } | 68 | } |
70 | 69 | ||
71 | static inline | 70 | static inline |
@@ -73,7 +72,6 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
73 | { | 72 | { |
74 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
75 | mesh_accept_plinks_update(sdata); | 74 | mesh_accept_plinks_update(sdata); |
76 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
77 | } | 75 | } |
78 | 76 | ||
79 | /** | 77 | /** |
@@ -115,7 +113,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
115 | } | 113 | } |
116 | 114 | ||
117 | /** | 115 | /** |
118 | * mesh_plink_deactivate - deactivate mesh peer link | 116 | * __mesh_plink_deactivate - deactivate mesh peer link |
119 | * | 117 | * |
120 | * @sta: mesh peer link to deactivate | 118 | * @sta: mesh peer link to deactivate |
121 | * | 119 | * |
@@ -123,18 +121,23 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
123 | * | 121 | * |
124 | * Locking: the caller must hold sta->lock | 122 | * Locking: the caller must hold sta->lock |
125 | */ | 123 | */ |
126 | static void __mesh_plink_deactivate(struct sta_info *sta) | 124 | static bool __mesh_plink_deactivate(struct sta_info *sta) |
127 | { | 125 | { |
128 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 126 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
127 | bool deactivated = false; | ||
129 | 128 | ||
130 | if (sta->plink_state == PLINK_ESTAB) | 129 | if (sta->plink_state == PLINK_ESTAB) { |
131 | mesh_plink_dec_estab_count(sdata); | 130 | mesh_plink_dec_estab_count(sdata); |
131 | deactivated = true; | ||
132 | } | ||
132 | sta->plink_state = PLINK_BLOCKED; | 133 | sta->plink_state = PLINK_BLOCKED; |
133 | mesh_path_flush_by_nexthop(sta); | 134 | mesh_path_flush_by_nexthop(sta); |
135 | |||
136 | return deactivated; | ||
134 | } | 137 | } |
135 | 138 | ||
136 | /** | 139 | /** |
137 | * __mesh_plink_deactivate - deactivate mesh peer link | 140 | * mesh_plink_deactivate - deactivate mesh peer link |
138 | * | 141 | * |
139 | * @sta: mesh peer link to deactivate | 142 | * @sta: mesh peer link to deactivate |
140 | * | 143 | * |
@@ -142,9 +145,15 @@ static void __mesh_plink_deactivate(struct sta_info *sta) | |||
142 | */ | 145 | */ |
143 | void mesh_plink_deactivate(struct sta_info *sta) | 146 | void mesh_plink_deactivate(struct sta_info *sta) |
144 | { | 147 | { |
148 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
149 | bool deactivated; | ||
150 | |||
145 | spin_lock_bh(&sta->lock); | 151 | spin_lock_bh(&sta->lock); |
146 | __mesh_plink_deactivate(sta); | 152 | deactivated = __mesh_plink_deactivate(sta); |
147 | spin_unlock_bh(&sta->lock); | 153 | spin_unlock_bh(&sta->lock); |
154 | |||
155 | if (deactivated) | ||
156 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
148 | } | 157 | } |
149 | 158 | ||
150 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 159 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
@@ -381,10 +390,16 @@ int mesh_plink_open(struct sta_info *sta) | |||
381 | 390 | ||
382 | void mesh_plink_block(struct sta_info *sta) | 391 | void mesh_plink_block(struct sta_info *sta) |
383 | { | 392 | { |
393 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
394 | bool deactivated; | ||
395 | |||
384 | spin_lock_bh(&sta->lock); | 396 | spin_lock_bh(&sta->lock); |
385 | __mesh_plink_deactivate(sta); | 397 | deactivated = __mesh_plink_deactivate(sta); |
386 | sta->plink_state = PLINK_BLOCKED; | 398 | sta->plink_state = PLINK_BLOCKED; |
387 | spin_unlock_bh(&sta->lock); | 399 | spin_unlock_bh(&sta->lock); |
400 | |||
401 | if (deactivated) | ||
402 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
388 | } | 403 | } |
389 | 404 | ||
390 | 405 | ||
@@ -397,6 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
397 | enum plink_event event; | 412 | enum plink_event event; |
398 | enum plink_frame_type ftype; | 413 | enum plink_frame_type ftype; |
399 | size_t baselen; | 414 | size_t baselen; |
415 | bool deactivated; | ||
400 | u8 ie_len; | 416 | u8 ie_len; |
401 | u8 *baseaddr; | 417 | u8 *baseaddr; |
402 | __le16 plid, llid, reason; | 418 | __le16 plid, llid, reason; |
@@ -651,8 +667,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
651 | case CNF_ACPT: | 667 | case CNF_ACPT: |
652 | del_timer(&sta->plink_timer); | 668 | del_timer(&sta->plink_timer); |
653 | sta->plink_state = PLINK_ESTAB; | 669 | sta->plink_state = PLINK_ESTAB; |
654 | mesh_plink_inc_estab_count(sdata); | ||
655 | spin_unlock_bh(&sta->lock); | 670 | spin_unlock_bh(&sta->lock); |
671 | mesh_plink_inc_estab_count(sdata); | ||
672 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
656 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 673 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
657 | sta->sta.addr); | 674 | sta->sta.addr); |
658 | break; | 675 | break; |
@@ -684,8 +701,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
684 | case OPN_ACPT: | 701 | case OPN_ACPT: |
685 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
686 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = PLINK_ESTAB; |
687 | mesh_plink_inc_estab_count(sdata); | ||
688 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
705 | mesh_plink_inc_estab_count(sdata); | ||
706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
689 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 707 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
690 | sta->sta.addr); | 708 | sta->sta.addr); |
691 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, | 709 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, |
@@ -702,11 +720,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
702 | case CLS_ACPT: | 720 | case CLS_ACPT: |
703 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 721 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
704 | sta->reason = reason; | 722 | sta->reason = reason; |
705 | __mesh_plink_deactivate(sta); | 723 | deactivated = __mesh_plink_deactivate(sta); |
706 | sta->plink_state = PLINK_HOLDING; | 724 | sta->plink_state = PLINK_HOLDING; |
707 | llid = sta->llid; | 725 | llid = sta->llid; |
708 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 726 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
709 | spin_unlock_bh(&sta->lock); | 727 | spin_unlock_bh(&sta->lock); |
728 | if (deactivated) | ||
729 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
710 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, | 730 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, |
711 | plid, reason); | 731 | plid, reason); |
712 | break; | 732 | break; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 85c3ca33333e..d1962650b254 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -478,6 +478,39 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
478 | } | 478 | } |
479 | } | 479 | } |
480 | 480 | ||
481 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | ||
482 | { | ||
483 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
484 | struct ieee80211_local *local = sdata->local; | ||
485 | struct ieee80211_conf *conf = &local->hw.conf; | ||
486 | |||
487 | WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION || | ||
488 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) || | ||
489 | (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)); | ||
490 | |||
491 | local->disable_dynamic_ps = false; | ||
492 | conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout; | ||
493 | } | ||
494 | EXPORT_SYMBOL(ieee80211_enable_dyn_ps); | ||
495 | |||
496 | void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif) | ||
497 | { | ||
498 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
499 | struct ieee80211_local *local = sdata->local; | ||
500 | struct ieee80211_conf *conf = &local->hw.conf; | ||
501 | |||
502 | WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION || | ||
503 | !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) || | ||
504 | (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)); | ||
505 | |||
506 | local->disable_dynamic_ps = true; | ||
507 | conf->dynamic_ps_timeout = 0; | ||
508 | del_timer_sync(&local->dynamic_ps_timer); | ||
509 | ieee80211_queue_work(&local->hw, | ||
510 | &local->dynamic_ps_enable_work); | ||
511 | } | ||
512 | EXPORT_SYMBOL(ieee80211_disable_dyn_ps); | ||
513 | |||
481 | /* powersave */ | 514 | /* powersave */ |
482 | static void ieee80211_enable_ps(struct ieee80211_local *local, | 515 | static void ieee80211_enable_ps(struct ieee80211_local *local, |
483 | struct ieee80211_sub_if_data *sdata) | 516 | struct ieee80211_sub_if_data *sdata) |
@@ -553,6 +586,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
553 | found->u.mgd.associated->beacon_ies && | 586 | found->u.mgd.associated->beacon_ies && |
554 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 587 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
555 | IEEE80211_STA_CONNECTION_POLL))) { | 588 | IEEE80211_STA_CONNECTION_POLL))) { |
589 | struct ieee80211_conf *conf = &local->hw.conf; | ||
556 | s32 beaconint_us; | 590 | s32 beaconint_us; |
557 | 591 | ||
558 | if (latency < 0) | 592 | if (latency < 0) |
@@ -575,7 +609,10 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
575 | else | 609 | else |
576 | timeout = 100; | 610 | timeout = 100; |
577 | } | 611 | } |
578 | local->hw.conf.dynamic_ps_timeout = timeout; | 612 | local->dynamic_ps_user_timeout = timeout; |
613 | if (!local->disable_dynamic_ps) | ||
614 | conf->dynamic_ps_timeout = | ||
615 | local->dynamic_ps_user_timeout; | ||
579 | 616 | ||
580 | if (beaconint_us > latency) { | 617 | if (beaconint_us > latency) { |
581 | local->ps_sdata = NULL; | 618 | local->ps_sdata = NULL; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 7a04951fcb1f..52c85036660d 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -328,7 +328,8 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi) | |||
328 | } | 328 | } |
329 | 329 | ||
330 | static void | 330 | static void |
331 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary) | 331 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx, |
332 | bool primary) | ||
332 | { | 333 | { |
333 | int group, orig_group; | 334 | int group, orig_group; |
334 | 335 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 696c0fc6e0b7..462d2b227ed5 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -29,6 +29,8 @@ struct mcs_group { | |||
29 | unsigned int duration[MCS_GROUP_RATES]; | 29 | unsigned int duration[MCS_GROUP_RATES]; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | extern const struct mcs_group minstrel_mcs_groups[]; | ||
33 | |||
32 | struct minstrel_rate_stats { | 34 | struct minstrel_rate_stats { |
33 | /* current / last sampling period attempts/success counters */ | 35 | /* current / last sampling period attempts/success counters */ |
34 | unsigned int attempts, last_attempts; | 36 | unsigned int attempts, last_attempts; |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 4fb3ccbd8b40..4a5a4b3e7799 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -14,8 +14,6 @@ | |||
14 | #include "rc80211_minstrel.h" | 14 | #include "rc80211_minstrel.h" |
15 | #include "rc80211_minstrel_ht.h" | 15 | #include "rc80211_minstrel_ht.h" |
16 | 16 | ||
17 | extern const struct mcs_group minstrel_mcs_groups[]; | ||
18 | |||
19 | static int | 17 | static int |
20 | minstrel_ht_stats_open(struct inode *inode, struct file *file) | 18 | minstrel_ht_stats_open(struct inode *inode, struct file *file) |
21 | { | 19 | { |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a8aa0f2411a2..fa0f37e4afe4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -293,7 +293,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
293 | skb2 = skb_clone(skb, GFP_ATOMIC); | 293 | skb2 = skb_clone(skb, GFP_ATOMIC); |
294 | if (skb2) { | 294 | if (skb2) { |
295 | skb2->dev = prev_dev; | 295 | skb2->dev = prev_dev; |
296 | netif_rx(skb2); | 296 | netif_receive_skb(skb2); |
297 | } | 297 | } |
298 | } | 298 | } |
299 | 299 | ||
@@ -304,7 +304,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
304 | 304 | ||
305 | if (prev_dev) { | 305 | if (prev_dev) { |
306 | skb->dev = prev_dev; | 306 | skb->dev = prev_dev; |
307 | netif_rx(skb); | 307 | netif_receive_skb(skb); |
308 | } else | 308 | } else |
309 | dev_kfree_skb(skb); | 309 | dev_kfree_skb(skb); |
310 | 310 | ||
@@ -1578,7 +1578,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1578 | /* deliver to local stack */ | 1578 | /* deliver to local stack */ |
1579 | skb->protocol = eth_type_trans(skb, dev); | 1579 | skb->protocol = eth_type_trans(skb, dev); |
1580 | memset(skb->cb, 0, sizeof(skb->cb)); | 1580 | memset(skb->cb, 0, sizeof(skb->cb)); |
1581 | netif_rx(skb); | 1581 | netif_receive_skb(skb); |
1582 | } | 1582 | } |
1583 | } | 1583 | } |
1584 | 1584 | ||
@@ -2056,11 +2056,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2056 | nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, | 2056 | nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0, |
2057 | GFP_ATOMIC); | 2057 | GFP_ATOMIC); |
2058 | if (nskb) { | 2058 | if (nskb) { |
2059 | struct ieee80211_mgmt *mgmt = (void *)nskb->data; | 2059 | struct ieee80211_mgmt *nmgmt = (void *)nskb->data; |
2060 | 2060 | ||
2061 | mgmt->u.action.category |= 0x80; | 2061 | nmgmt->u.action.category |= 0x80; |
2062 | memcpy(mgmt->da, mgmt->sa, ETH_ALEN); | 2062 | memcpy(nmgmt->da, nmgmt->sa, ETH_ALEN); |
2063 | memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN); | 2063 | memcpy(nmgmt->sa, rx->sdata->vif.addr, ETH_ALEN); |
2064 | 2064 | ||
2065 | memset(nskb->cb, 0, sizeof(nskb->cb)); | 2065 | memset(nskb->cb, 0, sizeof(nskb->cb)); |
2066 | 2066 | ||
@@ -2244,7 +2244,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2244 | skb2 = skb_clone(skb, GFP_ATOMIC); | 2244 | skb2 = skb_clone(skb, GFP_ATOMIC); |
2245 | if (skb2) { | 2245 | if (skb2) { |
2246 | skb2->dev = prev_dev; | 2246 | skb2->dev = prev_dev; |
2247 | netif_rx(skb2); | 2247 | netif_receive_skb(skb2); |
2248 | } | 2248 | } |
2249 | } | 2249 | } |
2250 | 2250 | ||
@@ -2255,7 +2255,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2255 | 2255 | ||
2256 | if (prev_dev) { | 2256 | if (prev_dev) { |
2257 | skb->dev = prev_dev; | 2257 | skb->dev = prev_dev; |
2258 | netif_rx(skb); | 2258 | netif_receive_skb(skb); |
2259 | skb = NULL; | 2259 | skb = NULL; |
2260 | } else | 2260 | } else |
2261 | goto out_free_skb; | 2261 | goto out_free_skb; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e1b0be7a57b9..439c98d93a79 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -286,6 +286,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
286 | local->scanning = 0; | 286 | local->scanning = 0; |
287 | local->scan_channel = NULL; | 287 | local->scan_channel = NULL; |
288 | 288 | ||
289 | drv_sw_scan_complete(local); | ||
290 | |||
289 | /* we only have to protect scan_req and hw/sw scan */ | 291 | /* we only have to protect scan_req and hw/sw scan */ |
290 | mutex_unlock(&local->scan_mtx); | 292 | mutex_unlock(&local->scan_mtx); |
291 | 293 | ||
@@ -295,8 +297,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
295 | 297 | ||
296 | ieee80211_configure_filter(local); | 298 | ieee80211_configure_filter(local); |
297 | 299 | ||
298 | drv_sw_scan_complete(local); | ||
299 | |||
300 | ieee80211_offchannel_return(local, true); | 300 | ieee80211_offchannel_return(local, true); |
301 | 301 | ||
302 | done: | 302 | done: |
@@ -734,7 +734,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
734 | { | 734 | { |
735 | struct ieee80211_local *local = sdata->local; | 735 | struct ieee80211_local *local = sdata->local; |
736 | int ret = -EBUSY; | 736 | int ret = -EBUSY; |
737 | enum nl80211_band band; | 737 | enum ieee80211_band band; |
738 | 738 | ||
739 | mutex_lock(&local->scan_mtx); | 739 | mutex_lock(&local->scan_mtx); |
740 | 740 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 10d0fcb417ae..54262e72376d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -427,20 +427,20 @@ void for_each_sta_info_type_check(struct ieee80211_local *local, | |||
427 | { | 427 | { |
428 | } | 428 | } |
429 | 429 | ||
430 | #define for_each_sta_info(local, _addr, sta, nxt) \ | 430 | #define for_each_sta_info(local, _addr, _sta, nxt) \ |
431 | for ( /* initialise loop */ \ | 431 | for ( /* initialise loop */ \ |
432 | sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ | 432 | _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ |
433 | nxt = sta ? rcu_dereference(sta->hnext) : NULL; \ | 433 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ |
434 | /* typecheck */ \ | 434 | /* typecheck */ \ |
435 | for_each_sta_info_type_check(local, (_addr), sta, nxt), \ | 435 | for_each_sta_info_type_check(local, (_addr), _sta, nxt),\ |
436 | /* continue condition */ \ | 436 | /* continue condition */ \ |
437 | sta; \ | 437 | _sta; \ |
438 | /* advance loop */ \ | 438 | /* advance loop */ \ |
439 | sta = nxt, \ | 439 | _sta = nxt, \ |
440 | nxt = sta ? rcu_dereference(sta->hnext) : NULL \ | 440 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ |
441 | ) \ | 441 | ) \ |
442 | /* compare address and run code only if it matches */ \ | 442 | /* compare address and run code only if it matches */ \ |
443 | if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0) | 443 | if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0) |
444 | 444 | ||
445 | /* | 445 | /* |
446 | * Get STA info by index, BROKEN! | 446 | * Get STA info by index, BROKEN! |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 34da67995d94..10caec5ea8fa 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
377 | skb2 = skb_clone(skb, GFP_ATOMIC); | 377 | skb2 = skb_clone(skb, GFP_ATOMIC); |
378 | if (skb2) { | 378 | if (skb2) { |
379 | skb2->dev = prev_dev; | 379 | skb2->dev = prev_dev; |
380 | netif_rx(skb2); | 380 | netif_receive_skb(skb2); |
381 | } | 381 | } |
382 | } | 382 | } |
383 | 383 | ||
@@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
386 | } | 386 | } |
387 | if (prev_dev) { | 387 | if (prev_dev) { |
388 | skb->dev = prev_dev; | 388 | skb->dev = prev_dev; |
389 | netif_rx(skb); | 389 | netif_receive_skb(skb); |
390 | skb = NULL; | 390 | skb = NULL; |
391 | } | 391 | } |
392 | rcu_read_unlock(); | 392 | rcu_read_unlock(); |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 37d0e0ab4432..47fcfd0eebc2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -894,7 +894,7 @@ out_fail_pernet: | |||
894 | } | 894 | } |
895 | subsys_initcall(cfg80211_init); | 895 | subsys_initcall(cfg80211_init); |
896 | 896 | ||
897 | static void cfg80211_exit(void) | 897 | static void __exit cfg80211_exit(void) |
898 | { | 898 | { |
899 | debugfs_remove(ieee80211_debugfs_dir); | 899 | debugfs_remove(ieee80211_debugfs_dir); |
900 | nl80211_exit(); | 900 | nl80211_exit(); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6b41d15c4a05..85285b43d374 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -153,6 +153,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, | 153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, |
154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, | 154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, |
155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, | 155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, |
156 | |||
157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | ||
158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | ||
156 | }; | 159 | }; |
157 | 160 | ||
158 | /* policy for the attributes */ | 161 | /* policy for the attributes */ |
@@ -869,6 +872,34 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
869 | goto bad_res; | 872 | goto bad_res; |
870 | } | 873 | } |
871 | 874 | ||
875 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | ||
876 | enum nl80211_tx_power_setting type; | ||
877 | int idx, mbm = 0; | ||
878 | |||
879 | if (!rdev->ops->set_tx_power) { | ||
880 | return -EOPNOTSUPP; | ||
881 | goto bad_res; | ||
882 | } | ||
883 | |||
884 | idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; | ||
885 | type = nla_get_u32(info->attrs[idx]); | ||
886 | |||
887 | if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && | ||
888 | (type != NL80211_TX_POWER_AUTOMATIC)) { | ||
889 | result = -EINVAL; | ||
890 | goto bad_res; | ||
891 | } | ||
892 | |||
893 | if (type != NL80211_TX_POWER_AUTOMATIC) { | ||
894 | idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; | ||
895 | mbm = nla_get_u32(info->attrs[idx]); | ||
896 | } | ||
897 | |||
898 | result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); | ||
899 | if (result) | ||
900 | goto bad_res; | ||
901 | } | ||
902 | |||
872 | changed = 0; | 903 | changed = 0; |
873 | 904 | ||
874 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 905 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8f0d97dd3109..1ac2bdd46ecf 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -80,7 +80,7 @@ static const struct ieee80211_regdomain *country_ie_regdomain; | |||
80 | * - country_ie_regdomain | 80 | * - country_ie_regdomain |
81 | * - last_request | 81 | * - last_request |
82 | */ | 82 | */ |
83 | DEFINE_MUTEX(reg_mutex); | 83 | static DEFINE_MUTEX(reg_mutex); |
84 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | 84 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) |
85 | 85 | ||
86 | /* Used to queue up regulatory hints */ | 86 | /* Used to queue up regulatory hints */ |
@@ -2630,7 +2630,7 @@ out: | |||
2630 | mutex_unlock(®_mutex); | 2630 | mutex_unlock(®_mutex); |
2631 | } | 2631 | } |
2632 | 2632 | ||
2633 | int regulatory_init(void) | 2633 | int __init regulatory_init(void) |
2634 | { | 2634 | { |
2635 | int err = 0; | 2635 | int err = 0; |
2636 | 2636 | ||
@@ -2676,7 +2676,7 @@ int regulatory_init(void) | |||
2676 | return 0; | 2676 | return 0; |
2677 | } | 2677 | } |
2678 | 2678 | ||
2679 | void regulatory_exit(void) | 2679 | void /* __init_or_exit */ regulatory_exit(void) |
2680 | { | 2680 | { |
2681 | struct regulatory_request *reg_request, *tmp; | 2681 | struct regulatory_request *reg_request, *tmp; |
2682 | struct reg_beacon *reg_beacon, *btmp; | 2682 | struct reg_beacon *reg_beacon, *btmp; |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index b26224a9f3bc..c4695d07af23 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -10,7 +10,7 @@ int regulatory_hint_user(const char *alpha2); | |||
10 | 10 | ||
11 | void reg_device_remove(struct wiphy *wiphy); | 11 | void reg_device_remove(struct wiphy *wiphy); |
12 | 12 | ||
13 | int regulatory_init(void); | 13 | int __init regulatory_init(void); |
14 | void regulatory_exit(void); | 14 | void regulatory_exit(void); |
15 | 15 | ||
16 | int set_regdom(const struct ieee80211_regdomain *rd); | 16 | int set_regdom(const struct ieee80211_regdomain *rd); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 96342993cf93..1ff1e9f49136 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -829,7 +829,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
829 | { | 829 | { |
830 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 830 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
831 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 831 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
832 | enum tx_power_setting type; | 832 | enum nl80211_tx_power_setting type; |
833 | int dbm = 0; | 833 | int dbm = 0; |
834 | 834 | ||
835 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 835 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
@@ -852,7 +852,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
852 | if (data->txpower.value < 0) | 852 | if (data->txpower.value < 0) |
853 | return -EINVAL; | 853 | return -EINVAL; |
854 | dbm = data->txpower.value; | 854 | dbm = data->txpower.value; |
855 | type = TX_POWER_FIXED; | 855 | type = NL80211_TX_POWER_FIXED; |
856 | /* TODO: do regulatory check! */ | 856 | /* TODO: do regulatory check! */ |
857 | } else { | 857 | } else { |
858 | /* | 858 | /* |
@@ -860,10 +860,10 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
860 | * passed in from userland. | 860 | * passed in from userland. |
861 | */ | 861 | */ |
862 | if (data->txpower.value < 0) { | 862 | if (data->txpower.value < 0) { |
863 | type = TX_POWER_AUTOMATIC; | 863 | type = NL80211_TX_POWER_AUTOMATIC; |
864 | } else { | 864 | } else { |
865 | dbm = data->txpower.value; | 865 | dbm = data->txpower.value; |
866 | type = TX_POWER_LIMITED; | 866 | type = NL80211_TX_POWER_LIMITED; |
867 | } | 867 | } |
868 | } | 868 | } |
869 | } else { | 869 | } else { |
@@ -872,7 +872,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
872 | return 0; | 872 | return 0; |
873 | } | 873 | } |
874 | 874 | ||
875 | return rdev->ops->set_tx_power(wdev->wiphy, type, dbm); | 875 | return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); |
876 | } | 876 | } |
877 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); | 877 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); |
878 | 878 | ||