Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[deliverable/linux.git] / net / mac80211 / mlme.c
index 30259a73195c5ea01896e8a118c29be839f46269..03f93f958fa41cb5948f11375fd6392faf16d37d 100644 (file)
@@ -180,51 +180,48 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
-       enum nl80211_channel_type channel_type;
+       bool disable_40 = false;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-       channel_type = local->hw.conf.channel_type;
 
-       if (WARN_ON_ONCE(channel_type == NL80211_CHAN_NO_HT))
-               return 0;
-
-       channel_type = ieee80211_get_tx_channel_type(local, channel_type);
+       switch (sdata->vif.bss_conf.channel_type) {
+       case NL80211_CHAN_HT40PLUS:
+               if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+                       disable_40 = true;
+               break;
+       case NL80211_CHAN_HT40MINUS:
+               if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+                       disable_40 = true;
+               break;
+       default:
+               break;
+       }
 
        /* This can change during the lifetime of the BSS */
        if (!(ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
-               channel_type = NL80211_CHAN_HT20;
+               disable_40 = true;
 
-       if (!reconfig || (sdata->u.mgd.tx_chantype != channel_type)) {
-               if (reconfig) {
-                       /*
-                        * Whenever the AP announces the HT mode changed
-                        * (e.g. 40 MHz intolerant) stop queues to avoid
-                        * sending out frames while the rate control is
-                        * reconfiguring.
-                        */
-                       ieee80211_stop_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+       mutex_lock(&local->sta_mtx);
+       sta = sta_info_get(sdata, bssid);
 
-                       /* flush out all packets */
-                       synchronize_net();
+       WARN_ON_ONCE(!sta);
 
-                       drv_flush(local, false);
-               }
+       if (sta && !sta->supports_40mhz)
+               disable_40 = true;
 
-               rcu_read_lock();
-               sta = sta_info_get(sdata, bssid);
-               if (sta)
-                       rate_control_rate_update(local, sband, sta,
-                                                IEEE80211_RC_HT_CHANGED,
-                                                channel_type);
-               rcu_read_unlock();
+       if (sta && (!reconfig ||
+                   (disable_40 != !!(sta->sta.ht_cap.cap &
+                                       IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) {
 
-               sdata->u.mgd.tx_chantype = channel_type;
+               if (disable_40)
+                       sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               else
+                       sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
-               if (reconfig)
-                       ieee80211_wake_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+               rate_control_rate_update(local, sband, sta,
+                                        IEEE80211_RC_BW_CHANGED);
        }
+       mutex_unlock(&local->sta_mtx);
 
        ht_opmode = le16_to_cpu(ht_oper->operation_mode);
 
@@ -1137,7 +1134,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        if (!local->ops->conf_tx)
                return;
 
-       if (local->hw.queues < 4)
+       if (local->hw.queues < IEEE80211_NUM_ACS)
                return;
 
        if (!wmm_param)
@@ -1450,19 +1447,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = sdata->local;
 
+       mutex_lock(&local->mtx);
        if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                             IEEE80211_STA_CONNECTION_POLL)))
-           return;
+                             IEEE80211_STA_CONNECTION_POLL))) {
+               mutex_unlock(&local->mtx);
+               return;
+       }
 
        ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                          IEEE80211_STA_BEACON_POLL);
-       mutex_lock(&sdata->local->iflist_mtx);
-       ieee80211_recalc_ps(sdata->local, -1);
-       mutex_unlock(&sdata->local->iflist_mtx);
+
+       mutex_lock(&local->iflist_mtx);
+       ieee80211_recalc_ps(local, -1);
+       mutex_unlock(&local->iflist_mtx);
 
        if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
-               return;
+               goto out;
 
        /*
         * We've received a probe response, but are not sure whether
@@ -1474,6 +1476,9 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
        mod_timer(&ifmgd->conn_mon_timer,
                  round_jiffies_up(jiffies +
                                   IEEE80211_CONNECTION_IDLE_TIME));
+out:
+       ieee80211_run_deferred_scan(local);
+       mutex_unlock(&local->mtx);
 }
 
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1521,9 +1526,16 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
                ifmgd->nullfunc_failed = false;
                ieee80211_send_nullfunc(sdata->local, sdata, 0);
        } else {
+               int ssid_len;
+
                ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
-               ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
-                                        (u32) -1, true, false);
+               if (WARN_ON_ONCE(ssid == NULL))
+                       ssid_len = 0;
+               else
+                       ssid_len = ssid[1];
+
+               ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
+                                        0, (u32) -1, true, false);
        }
 
        ifmgd->probe_send_count++;
@@ -1542,17 +1554,18 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       if (sdata->local->scanning)
-               return;
-
-       if (sdata->local->tmp_channel)
-               return;
-
        mutex_lock(&ifmgd->mtx);
 
        if (!ifmgd->associated)
                goto out;
 
+       mutex_lock(&sdata->local->mtx);
+
+       if (sdata->local->tmp_channel || sdata->local->scanning) {
+               mutex_unlock(&sdata->local->mtx);
+               goto out;
+       }
+
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (beacon && net_ratelimit())
                printk(KERN_DEBUG "%s: detected beacon loss from AP "
@@ -1579,6 +1592,8 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        else
                ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
 
+       mutex_unlock(&sdata->local->mtx);
+
        if (already)
                goto out;
 
@@ -1599,6 +1614,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct sk_buff *skb;
        const u8 *ssid;
+       int ssid_len;
 
        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return NULL;
@@ -1609,8 +1625,13 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
                return NULL;
 
        ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
+       if (WARN_ON_ONCE(ssid == NULL))
+               ssid_len = 0;
+       else
+               ssid_len = ssid[1];
+
        skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid,
-                                       (u32) -1, ssid + 2, ssid[1],
+                                       (u32) -1, ssid + 2, ssid_len,
                                        NULL, 0, true);
 
        return skb;
@@ -2006,6 +2027,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
 
+       sta->supports_40mhz =
+               sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
        rate_control_rate_init(sta);
 
        if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
@@ -3312,7 +3336,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        /* Also disable HT if we don't support it or the AP doesn't use WMM */
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
-           local->hw.queues < 4 || !bss->wmm_used)
+           local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used)
                ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 
        memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
@@ -3335,7 +3359,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                ifmgd->ap_smps = ifmgd->req_smps;
 
        assoc_data->capability = req->bss->capability;
-       assoc_data->wmm = bss->wmm_used && (local->hw.queues >= 4);
+       assoc_data->wmm = bss->wmm_used &&
+                         (local->hw.queues >= IEEE80211_NUM_ACS);
        assoc_data->supp_rates = bss->supp_rates;
        assoc_data->supp_rates_len = bss->supp_rates_len;
        assoc_data->ht_operation_ie =
@@ -3388,8 +3413,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                 */
                printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
                       sdata->name, ifmgd->bssid);
-               assoc_data->timeout = jiffies +
-                               TU_TO_EXP_TIME(req->bss->beacon_interval);
+               assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
        } else {
                assoc_data->have_beacon = true;
                assoc_data->sent_assoc = false;
@@ -3499,7 +3523,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-void ieee80211_mgd_teardown(struct ieee80211_sub_if_data *sdata)
+void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
This page took 0.029767 seconds and 5 git commands to generate.