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) |
