Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[sfrench/cifs-2.6.git] / net / mac80211 / ibss.c
index b3d76b756cd55e4c8e513bfa506c336ab77e667b..7b3a0b0aa246cf5ad9f57fea7fc196959c2e9ef3 100644 (file)
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
 
-static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_mgmt *mgmt,
-                                       size_t len)
-{
-       u16 auth_alg, auth_transaction;
-
-       lockdep_assert_held(&sdata->u.ibss.mtx);
-
-       if (len < 24 + 6)
-               return;
-
-       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
-       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
-
-       /*
-        * IEEE 802.11 standard does not require authentication in IBSS
-        * networks and most implementations do not seem to use it.
-        * However, try to reply to authentication attempts if someone
-        * has actually implemented this.
-        */
-       if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
-               ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
-                                   sdata->u.ibss.bssid, NULL, 0, 0);
-}
-
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                      const u8 *bssid, const int beacon_int,
                                      struct ieee80211_channel *chan,
@@ -106,6 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
+       local->oper_channel = chan;
        channel_type = ifibss->channel_type;
        if (channel_type > NL80211_CHAN_HT20 &&
            !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
@@ -275,7 +251,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                  cbss->tsf);
 }
 
-static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
+static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
+                                                 bool auth)
        __acquires(RCU)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -289,22 +266,31 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
                    addr, sdata->name);
 #endif
 
-       sta_info_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-       sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
        rate_control_rate_init(sta);
 
        /* If it fails, maybe we raced another insertion? */
        if (sta_info_insert_rcu(sta))
                return sta_info_get(sdata, addr);
+       if (auth) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+               printk(KERN_DEBUG "TX Auth SA=%pM DA=%pM BSSID=%pM"
+                      "(auth_transaction=1)\n", sdata->vif.addr,
+                      sdata->u.ibss.bssid, addr);
+#endif
+               ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0,
+                                   addr, sdata->u.ibss.bssid, NULL, 0, 0);
+       }
        return sta;
 }
 
 static struct sta_info *
 ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                       const u8 *bssid, const u8 *addr,
-                      u32 supp_rates)
+                      u32 supp_rates, bool auth)
        __acquires(RCU)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
@@ -346,7 +332,42 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
        sta->sta.supp_rates[band] = supp_rates |
                        ieee80211_mandatory_rates(local, band);
 
-       return ieee80211_ibss_finish_sta(sta);
+       return ieee80211_ibss_finish_sta(sta, auth);
+}
+
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_mgmt *mgmt,
+                                       size_t len)
+{
+       u16 auth_alg, auth_transaction;
+
+       lockdep_assert_held(&sdata->u.ibss.mtx);
+
+       if (len < 24 + 6)
+               return;
+
+       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+
+       if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
+               return;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "%s: RX Auth SA=%pM DA=%pM BSSID=%pM."
+              "(auth_transaction=%d)\n",
+              sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
+#endif
+       sta_info_destroy_addr(sdata, mgmt->sa);
+       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
+       rcu_read_unlock();
+
+       /*
+        * IEEE 802.11 standard does not require authentication in IBSS
+        * networks and most implementations do not seem to use it.
+        * However, try to reply to authentication attempts if someone
+        * has actually implemented this.
+        */
+       ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
+                           mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -411,7 +432,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                        } else {
                                rcu_read_unlock();
                                sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
-                                               mgmt->sa, supp_rates);
+                                               mgmt->sa, supp_rates, true);
                        }
                }
 
@@ -539,7 +560,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                ieee80211_sta_join_ibss(sdata, bss);
                supp_rates = ieee80211_sta_get_rates(local, elems, band);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
-                                      supp_rates);
+                                      supp_rates, true);
                rcu_read_unlock();
        }
 
@@ -642,8 +663,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
               "IBSS networks with same SSID (merge)\n", sdata->name);
 
        ieee80211_request_internal_scan(sdata,
-                       ifibss->ssid, ifibss->ssid_len,
-                       ifibss->fixed_channel ? ifibss->channel : NULL);
+                       ifibss->ssid, ifibss->ssid_len, NULL);
 }
 
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -854,9 +874,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        size_t baselen;
        struct ieee802_11_elems elems;
 
-       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
-               return; /* ignore ProbeResp to foreign address */
-
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
        if (baselen > len)
                return;
@@ -944,7 +961,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
                list_del(&sta->list);
                spin_unlock_bh(&ifibss->incomplete_lock);
 
-               ieee80211_ibss_finish_sta(sta);
+               ieee80211_ibss_finish_sta(sta, true);
                rcu_read_unlock();
                spin_lock_bh(&ifibss->incomplete_lock);
        }