Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[cascardo/linux.git] / net / mac80211 / work.c
index c22a71c..81d4ad6 100644 (file)
@@ -560,6 +560,22 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
        return WORK_ACT_TIMEOUT;
 }
 
+static enum work_action __must_check
+ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
+{
+       if (wk->started)
+               return WORK_ACT_TIMEOUT;
+
+       /*
+        * Wait up to one beacon interval ...
+        * should this be more if we miss one?
+        */
+       printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
+              wk->sdata->name, wk->filter_ta);
+       wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
+       return WORK_ACT_NONE;
+}
+
 static void ieee80211_auth_challenge(struct ieee80211_work *wk,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len)
@@ -709,6 +725,25 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
        return WORK_ACT_DONE;
 }
 
+static enum work_action __must_check
+ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
+                        struct ieee80211_mgmt *mgmt, size_t len)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       ASSERT_WORK_MTX(local);
+
+       if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
+               return WORK_ACT_MISMATCH;
+
+       if (len < 24 + 12)
+               return WORK_ACT_NONE;
+
+       printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
+       return WORK_ACT_DONE;
+}
+
 static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                                          struct sk_buff *skb)
 {
@@ -731,6 +766,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                case IEEE80211_WORK_DIRECT_PROBE:
                case IEEE80211_WORK_AUTH:
                case IEEE80211_WORK_ASSOC:
+               case IEEE80211_WORK_ASSOC_BEACON_WAIT:
                        bssid = wk->filter_ta;
                        break;
                default:
@@ -745,6 +781,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                        continue;
 
                switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_BEACON:
+                       rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
+                       break;
                case IEEE80211_STYPE_PROBE_RESP:
                        rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
                                                           rx_status);
@@ -916,6 +955,9 @@ static void ieee80211_work_work(struct work_struct *work)
                case IEEE80211_WORK_REMAIN_ON_CHANNEL:
                        rma = ieee80211_remain_on_channel_timeout(wk);
                        break;
+               case IEEE80211_WORK_ASSOC_BEACON_WAIT:
+                       rma = ieee80211_assoc_beacon_wait(wk);
+                       break;
                }
 
                wk->started = started;
@@ -1065,6 +1107,7 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
                case IEEE80211_STYPE_PROBE_RESP:
                case IEEE80211_STYPE_ASSOC_RESP:
                case IEEE80211_STYPE_REASSOC_RESP:
+               case IEEE80211_STYPE_BEACON:
                        skb_queue_tail(&local->work_skb_queue, skb);
                        ieee80211_queue_work(&local->hw, &local->work_work);
                        return RX_QUEUED;