mac80211: Fix HT channel selection
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index 29fafbe..e4d1fca 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
-#include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/random.h>
@@ -803,6 +802,10 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
        mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
+/*
+ * The disassoc 'reason' argument can be either our own reason
+ * if self disconnected or a reason code from the AP.
+ */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
                                   struct ieee80211_if_sta *ifsta, bool deauth,
                                   bool self_disconnected, u16 reason)
@@ -849,19 +852,30 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_sta_send_apinfo(sdata, ifsta);
 
-       if (self_disconnected)
+       if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT)
                ifsta->state = IEEE80211_STA_MLME_DISABLED;
 
-       sta_info_unlink(&sta);
-
        rcu_read_unlock();
 
-       sta_info_destroy(sta);
-
        local->hw.conf.ht.enabled = false;
+       local->oper_channel_type = NL80211_CHAN_NO_HT;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
 
        ieee80211_bss_info_change_notify(sdata, changed);
+
+       rcu_read_lock();
+
+       sta = sta_info_get(local, ifsta->bssid);
+       if (!sta) {
+               rcu_read_unlock();
+               return;
+       }
+
+       sta_info_unlink(&sta);
+
+       rcu_read_unlock();
+
+       sta_info_destroy(sta);
 }
 
 static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
@@ -1123,7 +1137,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
        if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
-               printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name);
+               printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
+                               sdata->dev->name, reason_code);
 
        if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
            ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
@@ -1154,7 +1169,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
        if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
-               printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name);
+               printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+                               sdata->dev->name, reason_code);
 
        if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
                ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
@@ -1162,7 +1178,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
                                      IEEE80211_RETRY_AUTH_INTERVAL);
        }
 
-       ieee80211_set_disassoc(sdata, ifsta, false, false, 0);
+       ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);
 }
 
 
@@ -1289,29 +1305,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        for (i = 0; i < elems.supp_rates_len; i++) {
                int rate = (elems.supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
                if (rate > 110)
                        have_higher_than_11mbit = true;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate)
+                       if (sband->bitrates[j].bitrate == rate) {
                                rates |= BIT(j);
-                       if (elems.supp_rates[i] & 0x80)
-                               basic_rates |= BIT(j);
+                               if (is_basic)
+                                       basic_rates |= BIT(j);
+                               break;
+                       }
                }
        }
 
        for (i = 0; i < elems.ext_supp_rates_len; i++) {
                int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
                if (rate > 110)
                        have_higher_than_11mbit = true;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate)
+                       if (sband->bitrates[j].bitrate == rate) {
                                rates |= BIT(j);
-                       if (elems.ext_supp_rates[i] & 0x80)
-                               basic_rates |= BIT(j);
+                               if (is_basic)
+                                       basic_rates |= BIT(j);
+                               break;
+                       }
                }
        }
 
@@ -1544,8 +1566,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                    (unsigned long long) sta->sta.supp_rates[band]);
 #endif
                } else {
-                       ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
-                                              mgmt->sa, supp_rates);
+                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
                }
 
                rcu_read_unlock();
@@ -1617,9 +1638,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                               sdata->dev->name, mgmt->bssid);
 #endif
                        ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
-                       ieee80211_ibss_add_sta(sdata, NULL,
-                                              mgmt->bssid, mgmt->sa,
-                                              supp_rates);
+                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
                }
        }
 
@@ -1729,6 +1748,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                               ap_ht_cap_flags);
        }
 
+       if (elems.country_elem) {
+               /* Note we are only reviewing this on beacons
+                * for the BSSID we are associated to */
+               regulatory_hint_11d(local->hw.wiphy,
+                       elems.country_elem, elems.country_elem_len);
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 }
 
@@ -1984,7 +2010,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
                }
        }
 
-       if (hidden_ssid && ifsta->ssid_len == ssid_len)
+       if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0))
                return 1;
 
        if (ssid_len == 1 && ssid[0] == ' ')
@@ -2345,8 +2371,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
  * must be callable in atomic context.
  */
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-                                       struct sk_buff *skb, u8 *bssid,
-                                       u8 *addr, u64 supp_rates)
+                                       u8 *bssid,u8 *addr, u64 supp_rates)
 {
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
@@ -2414,7 +2439,6 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
 int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
 {
        struct ieee80211_if_sta *ifsta;
-       int res;
 
        if (len > IEEE80211_MAX_SSID_LEN)
                return -EINVAL;
@@ -2426,19 +2450,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
                memcpy(ifsta->ssid, ssid, len);
                ifsta->ssid_len = len;
                ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-
-               res = 0;
-               /*
-                * Hack! MLME code needs to be cleaned up to have different
-                * entry points for configuration and internal selection change
-                */
-               if (netif_running(sdata->dev))
-                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
-               if (res) {
-                       printk(KERN_DEBUG "%s: Failed to config new SSID to "
-                              "the low-level driver\n", sdata->dev->name);
-                       return res;
-               }
        }
 
        if (len)
@@ -2566,25 +2577,3 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
                ieee80211_restart_sta_timer(sdata);
        rcu_read_unlock();
 }
-
-/* driver notification call */
-void ieee80211_notify_mac(struct ieee80211_hw *hw,
-                         enum ieee80211_notification_types  notif_type)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata;
-
-       switch (notif_type) {
-       case IEEE80211_NOTIFY_RE_ASSOC:
-               rcu_read_lock();
-               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-                       if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                               continue;
-
-                       ieee80211_sta_req_auth(sdata, &sdata->u.sta);
-               }
-               rcu_read_unlock();
-               break;
-       }
-}
-EXPORT_SYMBOL(ieee80211_notify_mac);