net: add a noref bit on skb dst
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index 461167d..3093e46 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/pm_qos_params.h>
 #include <linux/crc32.h>
+#include <linux/slab.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
 
@@ -136,11 +137,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
-       bool enable_ht = true, ht_changed;
+       bool enable_ht = true;
+       enum nl80211_channel_type prev_chantype;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
+       prev_chantype = sdata->vif.bss_conf.channel_type;
+
        /* HT is not supported */
        if (!sband->ht_cap.ht_supported)
                enable_ht = false;
@@ -171,36 +175,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
-                    channel_type != local->hw.conf.channel_type;
+       if (local->tmp_channel)
+               local->tmp_channel_type = channel_type;
 
-       local->oper_channel_type = channel_type;
+       if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
+               /* can only fail due to HT40+/- mismatch */
+               channel_type = NL80211_CHAN_HT20;
+               WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
+       }
 
-       if (ht_changed) {
-                /* channel_type change automatically detected */
-               ieee80211_hw_config(local, 0);
+       /* channel_type change automatically detected */
+       ieee80211_hw_config(local, 0);
 
+       if (prev_chantype != channel_type) {
                rcu_read_lock();
                sta = sta_info_get(sdata, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED,
-                                                local->oper_channel_type);
+                                                channel_type);
                rcu_read_unlock();
-        }
-
-       /* disable HT */
-       if (!enable_ht)
-               return 0;
+       }
 
        ht_opmode = le16_to_cpu(hti->operation_mode);
 
        /* if bss configuration changed store the new one */
-       if (!sdata->ht_opmode_valid ||
-           sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
+       if (sdata->ht_opmode_valid != enable_ht ||
+           sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
+           prev_chantype != channel_type) {
                changed |= BSS_CHANGED_HT;
                sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
-               sdata->ht_opmode_valid = true;
+               sdata->ht_opmode_valid = enable_ht;
        }
 
        return changed;
@@ -475,6 +480,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 {
        struct ieee80211_sub_if_data *sdata, *found = NULL;
        int count = 0;
+       int timeout;
 
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
                local->ps_sdata = NULL;
@@ -508,6 +514,26 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                beaconint_us = ieee80211_tu_to_usec(
                                        found->vif.bss_conf.beacon_int);
 
+               timeout = local->hw.conf.dynamic_ps_forced_timeout;
+               if (timeout < 0) {
+                       /*
+                        * The 2 second value is there for compatibility until
+                        * the PM_QOS_NETWORK_LATENCY is configured with real
+                        * values.
+                        */
+                       if (latency == 2000000000)
+                               timeout = 100;
+                       else if (latency <= 50000)
+                               timeout = 300;
+                       else if (latency <= 100000)
+                               timeout = 100;
+                       else if (latency <= 500000)
+                               timeout = 50;
+                       else
+                               timeout = 0;
+               }
+               local->hw.conf.dynamic_ps_timeout = timeout;
+
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
                } else {
@@ -842,7 +868,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_wmm_default(sdata);
 
        /* channel(_type) changes are handled by ieee80211_hw_config */
-       local->oper_channel_type = NL80211_CHAN_NO_HT;
+       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
 
        /* on the next assoc, re-program HT parameters */
        sdata->ht_opmode_valid = false;
@@ -859,8 +885,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_hw_config(local, config_changed);
 
-       /* And the BSSID changed -- not very interesting here */
-       changed |= BSS_CHANGED_BSSID;
+       /* The BSSID (not really interesting) and HT changed */
+       changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
        if (remove_sta)
@@ -1007,6 +1033,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_beacon_loss(sdata);
+
        WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -1017,6 +1045,8 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_connection_loss(sdata);
+
        WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -1326,12 +1356,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_ps(sdata->local, -1);
                mutex_unlock(&sdata->local->iflist_mtx);
+
+               if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+                       return;
+
                /*
                 * We've received a probe response, but are not sure whether
                 * we have or will be receiving any beacons or data, so let's
                 * schedule the timers again, just in case.
                 */
                mod_beacon_timer(sdata);
+
                mod_timer(&ifmgd->conn_mon_timer,
                          round_jiffies_up(jiffies +
                                           IEEE80211_CONNECTION_IDLE_TIME));
@@ -2143,7 +2178,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                                continue;
 
                        if (wk->type != IEEE80211_WORK_DIRECT_PROBE &&
-                           wk->type != IEEE80211_WORK_AUTH)
+                           wk->type != IEEE80211_WORK_AUTH &&
+                           wk->type != IEEE80211_WORK_ASSOC)
                                continue;
 
                        if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
@@ -2233,7 +2269,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
        if ((chan != local->tmp_channel ||
             channel_type != local->tmp_channel_type) &&
            (chan != local->oper_channel ||
-            channel_type != local->oper_channel_type))
+            channel_type != local->_oper_channel_type))
                return -EBUSY;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
@@ -2261,6 +2297,8 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
+       trace_api_cqm_rssi_notify(sdata, rssi_event);
+
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);