diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 284 |
1 files changed, 116 insertions, 168 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f803f8b72a93..b6c163ac22da 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) |
@@ -561,25 +595,24 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
561 | beaconint_us = ieee80211_tu_to_usec( | 595 | beaconint_us = ieee80211_tu_to_usec( |
562 | found->vif.bss_conf.beacon_int); | 596 | found->vif.bss_conf.beacon_int); |
563 | 597 | ||
564 | timeout = local->hw.conf.dynamic_ps_forced_timeout; | 598 | timeout = local->dynamic_ps_forced_timeout; |
565 | if (timeout < 0) { | 599 | if (timeout < 0) { |
566 | /* | 600 | /* |
601 | * Go to full PSM if the user configures a very low | ||
602 | * latency requirement. | ||
567 | * The 2 second value is there for compatibility until | 603 | * The 2 second value is there for compatibility until |
568 | * the PM_QOS_NETWORK_LATENCY is configured with real | 604 | * the PM_QOS_NETWORK_LATENCY is configured with real |
569 | * values. | 605 | * values. |
570 | */ | 606 | */ |
571 | if (latency == 2000000000) | 607 | if (latency > 1900000000 && latency != 2000000000) |
572 | timeout = 100; | ||
573 | else if (latency <= 50000) | ||
574 | timeout = 300; | ||
575 | else if (latency <= 100000) | ||
576 | timeout = 100; | ||
577 | else if (latency <= 500000) | ||
578 | timeout = 50; | ||
579 | else | ||
580 | timeout = 0; | 608 | timeout = 0; |
609 | else | ||
610 | timeout = 100; | ||
581 | } | 611 | } |
582 | 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; | ||
583 | 616 | ||
584 | if (beaconint_us > latency) { | 617 | if (beaconint_us > latency) { |
585 | local->ps_sdata = NULL; | 618 | local->ps_sdata = NULL; |
@@ -665,10 +698,11 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
665 | 698 | ||
666 | /* MLME */ | 699 | /* MLME */ |
667 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 700 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
668 | struct ieee80211_if_managed *ifmgd, | 701 | struct ieee80211_sub_if_data *sdata, |
669 | u8 *wmm_param, size_t wmm_param_len) | 702 | u8 *wmm_param, size_t wmm_param_len) |
670 | { | 703 | { |
671 | struct ieee80211_tx_queue_params params; | 704 | struct ieee80211_tx_queue_params params; |
705 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
672 | size_t left; | 706 | size_t left; |
673 | int count; | 707 | int count; |
674 | u8 *pos, uapsd_queues = 0; | 708 | u8 *pos, uapsd_queues = 0; |
@@ -757,8 +791,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
757 | } | 791 | } |
758 | 792 | ||
759 | /* enable WMM or activate new settings */ | 793 | /* enable WMM or activate new settings */ |
760 | local->hw.conf.flags |= IEEE80211_CONF_QOS; | 794 | sdata->vif.bss_conf.qos = true; |
761 | drv_config(local, IEEE80211_CONF_CHANGE_QOS); | 795 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); |
762 | } | 796 | } |
763 | 797 | ||
764 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 798 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
@@ -806,11 +840,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
806 | { | 840 | { |
807 | struct ieee80211_bss *bss = (void *)cbss->priv; | 841 | struct ieee80211_bss *bss = (void *)cbss->priv; |
808 | struct ieee80211_local *local = sdata->local; | 842 | struct ieee80211_local *local = sdata->local; |
843 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | ||
809 | 844 | ||
810 | bss_info_changed |= BSS_CHANGED_ASSOC; | 845 | bss_info_changed |= BSS_CHANGED_ASSOC; |
811 | /* set timing information */ | 846 | /* set timing information */ |
812 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; | 847 | bss_conf->beacon_int = cbss->beacon_interval; |
813 | sdata->vif.bss_conf.timestamp = cbss->tsf; | 848 | bss_conf->timestamp = cbss->tsf; |
814 | 849 | ||
815 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | 850 | bss_info_changed |= BSS_CHANGED_BEACON_INT; |
816 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 851 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
@@ -835,7 +870,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
835 | 870 | ||
836 | ieee80211_led_assoc(local, 1); | 871 | ieee80211_led_assoc(local, 1); |
837 | 872 | ||
838 | sdata->vif.bss_conf.assoc = 1; | 873 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) |
874 | bss_conf->dtim_period = bss->dtim_period; | ||
875 | else | ||
876 | bss_conf->dtim_period = 0; | ||
877 | |||
878 | bss_conf->assoc = 1; | ||
839 | /* | 879 | /* |
840 | * For now just always ask the driver to update the basic rateset | 880 | * For now just always ask the driver to update the basic rateset |
841 | * when we have associated, we aren't checking whether it actually | 881 | * when we have associated, we aren't checking whether it actually |
@@ -848,9 +888,15 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
848 | 888 | ||
849 | /* Tell the driver to monitor connection quality (if supported) */ | 889 | /* Tell the driver to monitor connection quality (if supported) */ |
850 | if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) && | 890 | if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) && |
851 | sdata->vif.bss_conf.cqm_rssi_thold) | 891 | bss_conf->cqm_rssi_thold) |
852 | bss_info_changed |= BSS_CHANGED_CQM; | 892 | bss_info_changed |= BSS_CHANGED_CQM; |
853 | 893 | ||
894 | /* Enable ARP filtering */ | ||
895 | if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) { | ||
896 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
897 | bss_info_changed |= BSS_CHANGED_ARP_FILTER; | ||
898 | } | ||
899 | |||
854 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 900 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
855 | 901 | ||
856 | mutex_lock(&local->iflist_mtx); | 902 | mutex_lock(&local->iflist_mtx); |
@@ -898,13 +944,13 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
898 | netif_tx_stop_all_queues(sdata->dev); | 944 | netif_tx_stop_all_queues(sdata->dev); |
899 | netif_carrier_off(sdata->dev); | 945 | netif_carrier_off(sdata->dev); |
900 | 946 | ||
901 | rcu_read_lock(); | 947 | mutex_lock(&local->sta_mtx); |
902 | sta = sta_info_get(sdata, bssid); | 948 | sta = sta_info_get(sdata, bssid); |
903 | if (sta) { | 949 | if (sta) { |
904 | set_sta_flags(sta, WLAN_STA_DISASSOC); | 950 | set_sta_flags(sta, WLAN_STA_BLOCK_BA); |
905 | ieee80211_sta_tear_down_BA_sessions(sta); | 951 | ieee80211_sta_tear_down_BA_sessions(sta); |
906 | } | 952 | } |
907 | rcu_read_unlock(); | 953 | mutex_unlock(&local->sta_mtx); |
908 | 954 | ||
909 | changed |= ieee80211_reset_erp_info(sdata); | 955 | changed |= ieee80211_reset_erp_info(sdata); |
910 | 956 | ||
@@ -932,6 +978,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
932 | 978 | ||
933 | ieee80211_hw_config(local, config_changed); | 979 | ieee80211_hw_config(local, config_changed); |
934 | 980 | ||
981 | /* Disable ARP filtering */ | ||
982 | if (sdata->vif.bss_conf.arp_filter_enabled) { | ||
983 | sdata->vif.bss_conf.arp_filter_enabled = false; | ||
984 | changed |= BSS_CHANGED_ARP_FILTER; | ||
985 | } | ||
986 | |||
935 | /* The BSSID (not really interesting) and HT changed */ | 987 | /* The BSSID (not really interesting) and HT changed */ |
936 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; | 988 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; |
937 | ieee80211_bss_info_change_notify(sdata, changed); | 989 | ieee80211_bss_info_change_notify(sdata, changed); |
@@ -1279,7 +1331,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1279 | } | 1331 | } |
1280 | 1332 | ||
1281 | if (elems.wmm_param) | 1333 | if (elems.wmm_param) |
1282 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | 1334 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, |
1283 | elems.wmm_param_len); | 1335 | elems.wmm_param_len); |
1284 | else | 1336 | else |
1285 | ieee80211_set_wmm_default(sdata); | 1337 | ieee80211_set_wmm_default(sdata); |
@@ -1551,7 +1603,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1551 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, | 1603 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, |
1552 | true); | 1604 | true); |
1553 | 1605 | ||
1554 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | 1606 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, |
1555 | elems.wmm_param_len); | 1607 | elems.wmm_param_len); |
1556 | } | 1608 | } |
1557 | 1609 | ||
@@ -1633,35 +1685,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1633 | ieee80211_bss_info_change_notify(sdata, changed); | 1685 | ieee80211_bss_info_change_notify(sdata, changed); |
1634 | } | 1686 | } |
1635 | 1687 | ||
1636 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | 1688 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1637 | struct sk_buff *skb) | 1689 | struct sk_buff *skb) |
1638 | { | ||
1639 | struct ieee80211_local *local = sdata->local; | ||
1640 | struct ieee80211_mgmt *mgmt; | ||
1641 | u16 fc; | ||
1642 | |||
1643 | if (skb->len < 24) | ||
1644 | return RX_DROP_MONITOR; | ||
1645 | |||
1646 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
1647 | fc = le16_to_cpu(mgmt->frame_control); | ||
1648 | |||
1649 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1650 | case IEEE80211_STYPE_PROBE_RESP: | ||
1651 | case IEEE80211_STYPE_BEACON: | ||
1652 | case IEEE80211_STYPE_DEAUTH: | ||
1653 | case IEEE80211_STYPE_DISASSOC: | ||
1654 | case IEEE80211_STYPE_ACTION: | ||
1655 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); | ||
1656 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); | ||
1657 | return RX_QUEUED; | ||
1658 | } | ||
1659 | |||
1660 | return RX_DROP_MONITOR; | ||
1661 | } | ||
1662 | |||
1663 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | ||
1664 | struct sk_buff *skb) | ||
1665 | { | 1690 | { |
1666 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1691 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1667 | struct ieee80211_rx_status *rx_status; | 1692 | struct ieee80211_rx_status *rx_status; |
@@ -1693,44 +1718,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1693 | break; | 1718 | break; |
1694 | case IEEE80211_STYPE_ACTION: | 1719 | case IEEE80211_STYPE_ACTION: |
1695 | switch (mgmt->u.action.category) { | 1720 | switch (mgmt->u.action.category) { |
1696 | case WLAN_CATEGORY_BACK: { | ||
1697 | struct ieee80211_local *local = sdata->local; | ||
1698 | int len = skb->len; | ||
1699 | struct sta_info *sta; | ||
1700 | |||
1701 | rcu_read_lock(); | ||
1702 | sta = sta_info_get(sdata, mgmt->sa); | ||
1703 | if (!sta) { | ||
1704 | rcu_read_unlock(); | ||
1705 | break; | ||
1706 | } | ||
1707 | |||
1708 | local_bh_disable(); | ||
1709 | |||
1710 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
1711 | case WLAN_ACTION_ADDBA_REQ: | ||
1712 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1713 | sizeof(mgmt->u.action.u.addba_req))) | ||
1714 | break; | ||
1715 | ieee80211_process_addba_request(local, sta, mgmt, len); | ||
1716 | break; | ||
1717 | case WLAN_ACTION_ADDBA_RESP: | ||
1718 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1719 | sizeof(mgmt->u.action.u.addba_resp))) | ||
1720 | break; | ||
1721 | ieee80211_process_addba_resp(local, sta, mgmt, len); | ||
1722 | break; | ||
1723 | case WLAN_ACTION_DELBA: | ||
1724 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
1725 | sizeof(mgmt->u.action.u.delba))) | ||
1726 | break; | ||
1727 | ieee80211_process_delba(sdata, sta, mgmt, len); | ||
1728 | break; | ||
1729 | } | ||
1730 | local_bh_enable(); | ||
1731 | rcu_read_unlock(); | ||
1732 | break; | ||
1733 | } | ||
1734 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 1721 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
1735 | ieee80211_sta_process_chanswitch(sdata, | 1722 | ieee80211_sta_process_chanswitch(sdata, |
1736 | &mgmt->u.action.u.chan_switch.sw_elem, | 1723 | &mgmt->u.action.u.chan_switch.sw_elem, |
@@ -1754,7 +1741,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1754 | default: | 1741 | default: |
1755 | WARN(1, "unexpected: %d", rma); | 1742 | WARN(1, "unexpected: %d", rma); |
1756 | } | 1743 | } |
1757 | goto out; | 1744 | return; |
1758 | } | 1745 | } |
1759 | 1746 | ||
1760 | mutex_unlock(&ifmgd->mtx); | 1747 | mutex_unlock(&ifmgd->mtx); |
@@ -1769,7 +1756,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1769 | if (wk->sdata != sdata) | 1756 | if (wk->sdata != sdata) |
1770 | continue; | 1757 | continue; |
1771 | 1758 | ||
1772 | if (wk->type != IEEE80211_WORK_ASSOC) | 1759 | if (wk->type != IEEE80211_WORK_ASSOC && |
1760 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
1773 | continue; | 1761 | continue; |
1774 | 1762 | ||
1775 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) | 1763 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) |
@@ -1799,8 +1787,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1799 | 1787 | ||
1800 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1788 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
1801 | } | 1789 | } |
1802 | out: | ||
1803 | kfree_skb(skb); | ||
1804 | } | 1790 | } |
1805 | 1791 | ||
1806 | static void ieee80211_sta_timer(unsigned long data) | 1792 | static void ieee80211_sta_timer(unsigned long data) |
@@ -1815,39 +1801,13 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1815 | return; | 1801 | return; |
1816 | } | 1802 | } |
1817 | 1803 | ||
1818 | ieee80211_queue_work(&local->hw, &ifmgd->work); | 1804 | ieee80211_queue_work(&local->hw, &sdata->work); |
1819 | } | 1805 | } |
1820 | 1806 | ||
1821 | static void ieee80211_sta_work(struct work_struct *work) | 1807 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
1822 | { | 1808 | { |
1823 | struct ieee80211_sub_if_data *sdata = | ||
1824 | container_of(work, struct ieee80211_sub_if_data, u.mgd.work); | ||
1825 | struct ieee80211_local *local = sdata->local; | 1809 | struct ieee80211_local *local = sdata->local; |
1826 | struct ieee80211_if_managed *ifmgd; | 1810 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1827 | struct sk_buff *skb; | ||
1828 | |||
1829 | if (!ieee80211_sdata_running(sdata)) | ||
1830 | return; | ||
1831 | |||
1832 | if (local->scanning) | ||
1833 | return; | ||
1834 | |||
1835 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
1836 | return; | ||
1837 | |||
1838 | /* | ||
1839 | * ieee80211_queue_work() should have picked up most cases, | ||
1840 | * here we'll pick the the rest. | ||
1841 | */ | ||
1842 | if (WARN(local->suspended, "STA MLME work scheduled while " | ||
1843 | "going to suspend\n")) | ||
1844 | return; | ||
1845 | |||
1846 | ifmgd = &sdata->u.mgd; | ||
1847 | |||
1848 | /* first process frames to avoid timing out while a frame is pending */ | ||
1849 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) | ||
1850 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
1851 | 1811 | ||
1852 | /* then process the rest of the work */ | 1812 | /* then process the rest of the work */ |
1853 | mutex_lock(&ifmgd->mtx); | 1813 | mutex_lock(&ifmgd->mtx); |
@@ -1942,8 +1902,7 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
1942 | ieee80211_queue_work(&sdata->local->hw, | 1902 | ieee80211_queue_work(&sdata->local->hw, |
1943 | &sdata->u.mgd.monitor_work); | 1903 | &sdata->u.mgd.monitor_work); |
1944 | /* and do all the other regular work too */ | 1904 | /* and do all the other regular work too */ |
1945 | ieee80211_queue_work(&sdata->local->hw, | 1905 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
1946 | &sdata->u.mgd.work); | ||
1947 | } | 1906 | } |
1948 | } | 1907 | } |
1949 | 1908 | ||
@@ -1958,7 +1917,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
1958 | * time -- the code here is properly synchronised. | 1917 | * time -- the code here is properly synchronised. |
1959 | */ | 1918 | */ |
1960 | 1919 | ||
1961 | cancel_work_sync(&ifmgd->work); | ||
1962 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 1920 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
1963 | if (del_timer_sync(&ifmgd->timer)) | 1921 | if (del_timer_sync(&ifmgd->timer)) |
1964 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 1922 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
@@ -1990,7 +1948,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1990 | struct ieee80211_if_managed *ifmgd; | 1948 | struct ieee80211_if_managed *ifmgd; |
1991 | 1949 | ||
1992 | ifmgd = &sdata->u.mgd; | 1950 | ifmgd = &sdata->u.mgd; |
1993 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | ||
1994 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); | 1951 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); |
1995 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1952 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1996 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 1953 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
@@ -2003,7 +1960,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2003 | (unsigned long) sdata); | 1960 | (unsigned long) sdata); |
2004 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 1961 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
2005 | (unsigned long) sdata); | 1962 | (unsigned long) sdata); |
2006 | skb_queue_head_init(&ifmgd->skb_queue); | ||
2007 | 1963 | ||
2008 | ifmgd->flags = 0; | 1964 | ifmgd->flags = 0; |
2009 | 1965 | ||
@@ -2081,6 +2037,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2081 | auth_alg = WLAN_AUTH_OPEN; | 2037 | auth_alg = WLAN_AUTH_OPEN; |
2082 | break; | 2038 | break; |
2083 | case NL80211_AUTHTYPE_SHARED_KEY: | 2039 | case NL80211_AUTHTYPE_SHARED_KEY: |
2040 | if (IS_ERR(sdata->local->wep_tx_tfm)) | ||
2041 | return -EOPNOTSUPP; | ||
2084 | auth_alg = WLAN_AUTH_SHARED_KEY; | 2042 | auth_alg = WLAN_AUTH_SHARED_KEY; |
2085 | break; | 2043 | break; |
2086 | case NL80211_AUTHTYPE_FT: | 2044 | case NL80211_AUTHTYPE_FT: |
@@ -2134,6 +2092,8 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2134 | struct sk_buff *skb) | 2092 | struct sk_buff *skb) |
2135 | { | 2093 | { |
2136 | struct ieee80211_mgmt *mgmt; | 2094 | struct ieee80211_mgmt *mgmt; |
2095 | struct ieee80211_rx_status *rx_status; | ||
2096 | struct ieee802_11_elems elems; | ||
2137 | u16 status; | 2097 | u16 status; |
2138 | 2098 | ||
2139 | if (!skb) { | 2099 | if (!skb) { |
@@ -2141,6 +2101,19 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2141 | return WORK_DONE_DESTROY; | 2101 | return WORK_DONE_DESTROY; |
2142 | } | 2102 | } |
2143 | 2103 | ||
2104 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | ||
2105 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
2106 | rx_status = (void *) skb->cb; | ||
2107 | ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems); | ||
2108 | ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status, | ||
2109 | &elems, true); | ||
2110 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2111 | |||
2112 | wk->type = IEEE80211_WORK_ASSOC; | ||
2113 | /* not really done yet */ | ||
2114 | return WORK_DONE_REQUEUE; | ||
2115 | } | ||
2116 | |||
2144 | mgmt = (void *)skb->data; | 2117 | mgmt = (void *)skb->data; |
2145 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 2118 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
2146 | 2119 | ||
@@ -2153,6 +2126,7 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2153 | wk->filter_ta); | 2126 | wk->filter_ta); |
2154 | return WORK_DONE_DESTROY; | 2127 | return WORK_DONE_DESTROY; |
2155 | } | 2128 | } |
2129 | |||
2156 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 2130 | mutex_unlock(&wk->sdata->u.mgd.mtx); |
2157 | } | 2131 | } |
2158 | 2132 | ||
@@ -2253,10 +2227,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2253 | if (req->prev_bssid) | 2227 | if (req->prev_bssid) |
2254 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 2228 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
2255 | 2229 | ||
2256 | wk->type = IEEE80211_WORK_ASSOC; | ||
2257 | wk->chan = req->bss->channel; | 2230 | wk->chan = req->bss->channel; |
2258 | wk->sdata = sdata; | 2231 | wk->sdata = sdata; |
2259 | wk->done = ieee80211_assoc_done; | 2232 | wk->done = ieee80211_assoc_done; |
2233 | if (!bss->dtim_period && | ||
2234 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
2235 | wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT; | ||
2236 | else | ||
2237 | wk->type = IEEE80211_WORK_ASSOC; | ||
2260 | 2238 | ||
2261 | if (req->use_mfp) { | 2239 | if (req->use_mfp) { |
2262 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 2240 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
@@ -2282,14 +2260,16 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2282 | struct ieee80211_local *local = sdata->local; | 2260 | struct ieee80211_local *local = sdata->local; |
2283 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2261 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2284 | struct ieee80211_work *wk; | 2262 | struct ieee80211_work *wk; |
2285 | const u8 *bssid = req->bss->bssid; | 2263 | u8 bssid[ETH_ALEN]; |
2264 | bool assoc_bss = false; | ||
2286 | 2265 | ||
2287 | mutex_lock(&ifmgd->mtx); | 2266 | mutex_lock(&ifmgd->mtx); |
2288 | 2267 | ||
2268 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | ||
2289 | if (ifmgd->associated == req->bss) { | 2269 | if (ifmgd->associated == req->bss) { |
2290 | bssid = req->bss->bssid; | 2270 | ieee80211_set_disassoc(sdata, false); |
2291 | ieee80211_set_disassoc(sdata, true); | ||
2292 | mutex_unlock(&ifmgd->mtx); | 2271 | mutex_unlock(&ifmgd->mtx); |
2272 | assoc_bss = true; | ||
2293 | } else { | 2273 | } else { |
2294 | bool not_auth_yet = false; | 2274 | bool not_auth_yet = false; |
2295 | 2275 | ||
@@ -2302,7 +2282,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2302 | 2282 | ||
2303 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | 2283 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && |
2304 | wk->type != IEEE80211_WORK_AUTH && | 2284 | wk->type != IEEE80211_WORK_AUTH && |
2305 | wk->type != IEEE80211_WORK_ASSOC) | 2285 | wk->type != IEEE80211_WORK_ASSOC && |
2286 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
2306 | continue; | 2287 | continue; |
2307 | 2288 | ||
2308 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | 2289 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) |
@@ -2335,6 +2316,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2335 | ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, | 2316 | ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, |
2336 | req->reason_code, cookie, | 2317 | req->reason_code, cookie, |
2337 | !req->local_state_change); | 2318 | !req->local_state_change); |
2319 | if (assoc_bss) | ||
2320 | sta_info_destroy_addr(sdata, bssid); | ||
2338 | 2321 | ||
2339 | ieee80211_recalc_idle(sdata->local); | 2322 | ieee80211_recalc_idle(sdata->local); |
2340 | 2323 | ||
@@ -2379,41 +2362,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2379 | return 0; | 2362 | return 0; |
2380 | } | 2363 | } |
2381 | 2364 | ||
2382 | int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, | ||
2383 | struct ieee80211_channel *chan, | ||
2384 | enum nl80211_channel_type channel_type, | ||
2385 | const u8 *buf, size_t len, u64 *cookie) | ||
2386 | { | ||
2387 | struct ieee80211_local *local = sdata->local; | ||
2388 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2389 | struct sk_buff *skb; | ||
2390 | |||
2391 | /* Check that we are on the requested channel for transmission */ | ||
2392 | if ((chan != local->tmp_channel || | ||
2393 | channel_type != local->tmp_channel_type) && | ||
2394 | (chan != local->oper_channel || | ||
2395 | channel_type != local->_oper_channel_type)) | ||
2396 | return -EBUSY; | ||
2397 | |||
2398 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); | ||
2399 | if (!skb) | ||
2400 | return -ENOMEM; | ||
2401 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2402 | |||
2403 | memcpy(skb_put(skb, len), buf, len); | ||
2404 | |||
2405 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | ||
2406 | IEEE80211_SKB_CB(skb)->flags |= | ||
2407 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
2408 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX | | ||
2409 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
2410 | skb->dev = sdata->dev; | ||
2411 | ieee80211_tx_skb(sdata, skb); | ||
2412 | |||
2413 | *cookie = (unsigned long) skb; | ||
2414 | return 0; | ||
2415 | } | ||
2416 | |||
2417 | void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | 2365 | void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, |
2418 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 2366 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
2419 | gfp_t gfp) | 2367 | gfp_t gfp) |