mac80211: allow station add/remove to sleep
[safe/jmp/linux-2.6] / net / mac80211 / ibss.c
index 5bcde4c..f3e9424 100644 (file)
@@ -275,10 +275,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                    (unsigned long long) supp_rates,
                                    (unsigned long long) sta->sta.supp_rates[band]);
 #endif
-               } else
-                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
-
-               rcu_read_unlock();
+                       rcu_read_unlock();
+               } else {
+                       rcu_read_unlock();
+                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
+                                              supp_rates, GFP_KERNEL);
+               }
        }
 
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
@@ -293,12 +295,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        /* check if we need to merge IBSS */
 
-       /* merge only on beacons (???) */
-       if (!beacon)
-               goto put_bss;
-
        /* we use a fixed BSSID */
-       if (sdata->u.ibss.bssid)
+       if (sdata->u.ibss.fixed_bssid)
                goto put_bss;
 
        /* not an IBSS */
@@ -372,7 +370,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                       sdata->name, mgmt->bssid);
 #endif
                ieee80211_sta_join_ibss(sdata, bss);
-               ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
+               ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
+                                      supp_rates, GFP_KERNEL);
        }
 
  put_bss:
@@ -385,7 +384,8 @@ static void ieee80211_rx_bss_info(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,
-                                       u8 *bssid,u8 *addr, u32 supp_rates)
+                                       u8 *bssid,u8 *addr, u32 supp_rates,
+                                       gfp_t gfp)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
@@ -414,7 +414,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
               wiphy_name(local->hw.wiphy), addr, sdata->name);
 #endif
 
-       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+       sta = sta_info_alloc(sdata, addr, gfp);
        if (!sta)
                return NULL;
 
@@ -426,9 +426,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 
        rate_control_rate_init(sta);
 
+       /* If it fails, maybe we raced another insertion? */
        if (sta_info_insert(sta))
-               return NULL;
-
+               return sta_info_get(sdata, addr);
        return sta;
 }
 
@@ -454,6 +454,9 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
        return active;
 }
 
+/*
+ * This function is called with state == IEEE80211_IBSS_MLME_JOINED
+ */
 
 static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
 {
@@ -519,6 +522,10 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
                                  capability, 0);
 }
 
+/*
+ * This function is called with state == IEEE80211_IBSS_MLME_SEARCH
+ */
+
 static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
@@ -575,18 +582,14 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
        /* Selected IBSS not found in current scan results - try to scan */
-       if (ifibss->state == IEEE80211_IBSS_MLME_JOINED &&
-           !ieee80211_sta_active_ibss(sdata)) {
-               mod_timer(&ifibss->timer,
-                         round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
-       } else if (time_after(jiffies, ifibss->last_scan_completed +
+       if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
                       "join\n", sdata->name);
 
                ieee80211_request_internal_scan(sdata, ifibss->ssid,
                                                ifibss->ssid_len);
-       } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
+       } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
                if (time_after(jiffies, ifibss->ibss_join_req +
@@ -604,7 +607,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                        interval = IEEE80211_SCAN_INTERVAL_SLOW;
                }
 
-               ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
                mod_timer(&ifibss->timer,
                          round_jiffies(jiffies + interval));
        }
@@ -654,7 +656,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        }
        if (pos[1] != 0 &&
            (pos[1] != ifibss->ssid_len ||
-            !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) {
+            memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) {
                /* Ignore ProbeReq for foreign SSID */
                return;
        }