mac80211: implement a timer to send RANN action frames
[safe/jmp/linux-2.6] / net / mac80211 / mlme.c
index ccd5c7a..dcc14e9 100644 (file)
  * Time the connection can be idle before we probe
  * it to see if we can still talk to the AP.
  */
-#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ)
+#define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ)
 /*
  * Time we wait for a probe response after sending
  * a probe request because of beacon loss or for
  * checking the connection still works.
  */
-#define IEEE80211_PROBE_WAIT           (HZ / 5)
+#define IEEE80211_PROBE_WAIT           (HZ / 2)
 
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
@@ -458,9 +458,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        mgmt->u.deauth.reason_code = cpu_to_le16(reason);
 
        if (stype == IEEE80211_STYPE_DEAUTH)
-               cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie);
+               if (cookie)
+                       __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
+               else
+                       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
        else
-               cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie);
+               if (cookie)
+                       __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
+               else
+                       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
        ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
 }
 
@@ -880,10 +886,11 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
 }
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_bss *bss,
+                                    struct ieee80211_mgd_work *wk,
                                     u32 bss_info_changed)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_bss *bss = wk->bss;
 
        bss_info_changed |= BSS_CHANGED_ASSOC;
        /* set timing information */
@@ -896,6 +903,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
                bss->cbss.capability, bss->has_erp_value, bss->erp_value);
 
        sdata->u.mgd.associated = bss;
+       sdata->u.mgd.old_associate_work = wk;
        memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
 
        /* just to be sure */
@@ -921,7 +929,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_ps(local, -1);
        mutex_unlock(&local->iflist_mtx);
 
-       netif_tx_start_all_queues(sdata->dev);
+       netif_start_queue(sdata->dev);
        netif_carrier_on(sdata->dev);
 }
 
@@ -1010,7 +1018,8 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
        return RX_MGMT_NONE;
 }
 
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+                                  bool deauth)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -1028,6 +1037,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
        ifmgd->associated = NULL;
        memset(ifmgd->bssid, 0, ETH_ALEN);
 
+       if (deauth) {
+               kfree(ifmgd->old_associate_work);
+               ifmgd->old_associate_work = NULL;
+       } else {
+               struct ieee80211_mgd_work *wk = ifmgd->old_associate_work;
+
+               wk->state = IEEE80211_MGD_STATE_IDLE;
+               list_add(&wk->list, &ifmgd->work_list);
+       }
+
        /*
         * we need to commit the associated = NULL change because the
         * scan code uses that to determine whether this iface should
@@ -1042,7 +1061,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
         * time -- we don't want the scan code to enable queues.
         */
 
-       netif_tx_stop_all_queues(sdata->dev);
+       netif_stop_queue(sdata->dev);
        netif_carrier_off(sdata->dev);
 
        rcu_read_lock();
@@ -1345,7 +1364,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                        sdata->dev->name, bssid, reason_code);
 
        if (!wk) {
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
        } else {
                list_del(&wk->list);
                kfree(wk);
@@ -1375,10 +1394,10 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
-                       sdata->dev->name, reason_code);
+       printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
+                       sdata->dev->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, false);
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
@@ -1444,8 +1463,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        if (status_code != WLAN_STATUS_SUCCESS) {
                printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
                       sdata->dev->name, status_code);
-               list_del(&wk->list);
-               kfree(wk);
+               wk->state = IEEE80211_MGD_STATE_IDLE;
                return RX_MGMT_CFG80211_ASSOC;
        }
 
@@ -1581,7 +1599,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
         * ieee80211_set_associated() will tell the driver */
        bss_conf->aid = aid;
        bss_conf->assoc_capability = capab_info;
-       ieee80211_set_associated(sdata, wk->bss, changed);
+       /* this will take ownership of wk */
+       ieee80211_set_associated(sdata, wk, changed);
 
        /*
         * Start timer to probe the connection to the AP now.
@@ -1590,7 +1609,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
        mod_beacon_timer(sdata);
 
-       kfree(wk);
        return RX_MGMT_CFG80211_ASSOC;
 }
 
@@ -1662,7 +1680,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        /* direct probe may be part of the association flow */
        if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
-               printk(KERN_DEBUG "%s direct probe responded\n",
+               printk(KERN_DEBUG "%s: direct probe responded\n",
                       sdata->dev->name);
                wk->tries = 0;
                wk->state = IEEE80211_MGD_STATE_AUTH;
@@ -1946,12 +1964,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                        /* no action */
                        break;
                case RX_MGMT_CFG80211_DEAUTH:
-                       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len,
-                                            NULL);
+                       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
                        break;
                case RX_MGMT_CFG80211_DISASSOC:
-                       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len,
-                                              NULL);
+                       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
                        break;
                default:
                        WARN(1, "unexpected: %d", rma);
@@ -2006,7 +2022,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
                break;
        case RX_MGMT_CFG80211_DEAUTH:
-               cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL);
+               cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
                break;
        default:
                WARN(1, "unexpected: %d", rma);
@@ -2096,7 +2112,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        printk(KERN_DEBUG "No probe response from AP %pM"
                                " after %dms, disconnecting.\n",
                                bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
-                       ieee80211_set_disassoc(sdata);
+                       ieee80211_set_disassoc(sdata, true);
                        mutex_unlock(&ifmgd->mtx);
                        /*
                         * must be outside lock due to cfg80211,
@@ -2110,25 +2126,9 @@ static void ieee80211_sta_work(struct work_struct *work)
                }
        }
 
-       list_for_each_entry(wk, &ifmgd->work_list, list) {
-               if (wk->state != IEEE80211_MGD_STATE_IDLE) {
-                       anybusy = true;
-                       break;
-               }
-       }
 
        ieee80211_recalc_idle(local);
 
-       if (!anybusy) {
-               mutex_unlock(&ifmgd->mtx);
-
-               if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
-                       ieee80211_queue_delayed_work(&local->hw,
-                                                    &local->scan_work,
-                                                    round_jiffies_relative(0));
-               return;
-       }
-
        list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
                if (time_is_after_jiffies(wk->timeout)) {
                        /*
@@ -2174,6 +2174,18 @@ static void ieee80211_sta_work(struct work_struct *work)
                }
        }
 
+       list_for_each_entry(wk, &ifmgd->work_list, list) {
+               if (wk->state != IEEE80211_MGD_STATE_IDLE) {
+                       anybusy = true;
+                       break;
+               }
+       }
+       if (!anybusy &&
+           test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
+               ieee80211_queue_delayed_work(&local->hw,
+                                            &local->scan_work,
+                                            round_jiffies_relative(0));
+
        mutex_unlock(&ifmgd->mtx);
 
        list_for_each_entry_safe(wk, tmp, &free_work, list) {
@@ -2493,14 +2505,11 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgd_work *wk;
        const u8 *bssid = NULL;
 
-       printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
-              sdata->dev->name, req->reason_code);
-
        mutex_lock(&ifmgd->mtx);
 
        if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
        } else list_for_each_entry(wk, &ifmgd->work_list, list) {
                if (&wk->bss->cbss == req->bss) {
                        bssid = req->bss->bssid;
@@ -2523,6 +2532,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        mutex_unlock(&ifmgd->mtx);
 
+       printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
+              sdata->dev->name, bssid, req->reason_code);
+
        ieee80211_send_deauth_disassoc(sdata, bssid,
                        IEEE80211_STYPE_DEAUTH, req->reason_code,
                        cookie);
@@ -2536,9 +2548,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
-              sdata->dev->name, req->reason_code);
-
        mutex_lock(&ifmgd->mtx);
 
        /*
@@ -2552,7 +2561,10 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                return -ENOLINK;
        }
 
-       ieee80211_set_disassoc(sdata);
+       printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
+              sdata->dev->name, req->bss->bssid, req->reason_code);
+
+       ieee80211_set_disassoc(sdata, false);
 
        mutex_unlock(&ifmgd->mtx);