]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/mac80211/mlme.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[karo-tx-linux.git] / net / mac80211 / mlme.c
index 71ff42a0465bd8b8158ffb9b05c11116acf4d82d..35d850223a75f9a16af592a2659a035d70c8258d 100644 (file)
  */
 #define IEEE80211_PROBE_WAIT           (HZ / 2)
 
+/*
+ * Weight given to the latest Beacon frame when calculating average signal
+ * strength for Beacon frames received in the current BSS. This must be
+ * between 1 and 15.
+ */
+#define IEEE80211_SIGNAL_AVE_WEIGHT    3
+
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
@@ -204,7 +211,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                                           const u8 *bssid, u16 stype, u16 reason,
-                                          void *cookie)
+                                          void *cookie, bool send_frame)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -241,7 +248,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                        cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
        if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-       ieee80211_tx_skb(sdata, skb);
+
+       if (send_frame)
+               ieee80211_tx_skb(sdata, skb);
+       else
+               kfree_skb(skb);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -590,6 +601,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        int count;
        u8 *pos, uapsd_queues = 0;
 
+       if (!local->ops->conf_tx)
+               return;
+
        if (local->hw.queues < 4)
                return;
 
@@ -664,11 +678,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                       params.aifs, params.cw_min, params.cw_max, params.txop,
                       params.uapsd);
 #endif
-               if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
+               if (drv_conf_tx(local, queue, &params))
                        printk(KERN_DEBUG "%s: failed to set TX queue "
                               "parameters for queue %d\n",
                               wiphy_name(local->hw.wiphy), queue);
        }
+
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
 }
 
 static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -729,6 +747,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        sdata->u.mgd.associated = cbss;
        memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
 
+       sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
+
        /* just to be sure */
        sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                                IEEE80211_STA_BEACON_POLL);
@@ -770,7 +790,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        netif_carrier_on(sdata->dev);
 }
 
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+                                  bool remove_sta)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -843,7 +864,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
        changed |= BSS_CHANGED_BSSID;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       sta_info_destroy_addr(sdata, bssid);
+       if (remove_sta)
+               sta_info_destroy_addr(sdata, bssid);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -956,7 +978,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
 
        printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(local);
        mutex_unlock(&ifmgd->mtx);
        /*
@@ -966,7 +988,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
        ieee80211_send_deauth_disassoc(sdata, bssid,
                                       IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                      NULL);
+                                      NULL, true);
 }
 
 void ieee80211_beacon_connection_loss_work(struct work_struct *work)
@@ -986,6 +1008,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_beacon_loss(sdata);
+
        WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -996,6 +1020,8 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif)
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_hw *hw = &sdata->local->hw;
 
+       trace_api_connection_loss(sdata);
+
        WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
        ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
@@ -1022,7 +1048,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
                        sdata->name, bssid, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
 
        return RX_MGMT_CFG80211_DEAUTH;
@@ -1052,7 +1078,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
                        sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
        return RX_MGMT_CFG80211_DISASSOC;
 }
@@ -1344,6 +1370,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
@@ -1379,6 +1406,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
+       /* Track average RSSI from the Beacon frames of the current AP */
+       ifmgd->last_beacon_signal = rx_status->signal;
+       if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
+               ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
+               ifmgd->ave_beacon_signal = rx_status->signal;
+               ifmgd->last_cqm_event_signal = 0;
+       } else {
+               ifmgd->ave_beacon_signal =
+                       (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
+                        (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
+                        ifmgd->ave_beacon_signal) / 16;
+       }
+       if (bss_conf->cqm_rssi_thold &&
+           !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               int sig = ifmgd->ave_beacon_signal / 16;
+               int last_event = ifmgd->last_cqm_event_signal;
+               int thold = bss_conf->cqm_rssi_thold;
+               int hyst = bss_conf->cqm_rssi_hyst;
+               if (sig < thold &&
+                   (last_event == 0 || sig < last_event - hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+                               GFP_KERNEL);
+               } else if (sig > thold &&
+                          (last_event == 0 || sig > last_event + hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+                               GFP_KERNEL);
+               }
+       }
+
        if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
@@ -1664,7 +1726,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);
                        ieee80211_recalc_idle(local);
                        mutex_unlock(&ifmgd->mtx);
                        /*
@@ -1674,7 +1736,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        ieee80211_send_deauth_disassoc(sdata, bssid,
                                        IEEE80211_STYPE_DEAUTH,
                                        WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                       NULL);
+                                       NULL, true);
                        mutex_lock(&ifmgd->mtx);
                }
        }
@@ -1858,6 +1920,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_work *wk;
        u16 auth_alg;
 
+       if (req->local_state_change)
+               return 0; /* no need to update mac80211 state */
+
        switch (req->auth_type) {
        case NL80211_AUTHTYPE_OPEN_SYSTEM:
                auth_alg = WLAN_AUTH_OPEN;
@@ -1966,7 +2031,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
 
                /* Trying to reassociate - clear previous association state */
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
        }
        mutex_unlock(&ifmgd->mtx);
 
@@ -2070,7 +2135,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->associated == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
                mutex_unlock(&ifmgd->mtx);
        } else {
                bool not_auth_yet = false;
@@ -2113,9 +2178,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
               sdata->name, bssid, req->reason_code);
 
-       ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH, req->reason_code,
-                       cookie);
+       ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
+                                      req->reason_code, cookie,
+                                      !req->local_state_change);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2127,6 +2192,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                           void *cookie)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 bssid[ETH_ALEN];
 
        mutex_lock(&ifmgd->mtx);
 
@@ -2144,13 +2210,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
               sdata->name, req->bss->bssid, req->reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       memcpy(bssid, req->bss->bssid, ETH_ALEN);
+       ieee80211_set_disassoc(sdata, false);
 
        mutex_unlock(&ifmgd->mtx);
 
        ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
                        IEEE80211_STYPE_DISASSOC, req->reason_code,
-                       cookie);
+                       cookie, !req->local_state_change);
+       sta_info_destroy_addr(sdata, bssid);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2198,6 +2266,8 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
+       trace_api_cqm_rssi_notify(sdata, rssi_event);
+
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);