mac80211: Support multiple CSA counters
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Fri, 9 May 2014 11:11:47 +0000 (14:11 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 15 May 2014 13:00:58 +0000 (15:00 +0200)
Support up to IEEE80211_MAX_CSA_COUNTERS_NUM csa counters.
This is defined to be 2 now, to support both CSA and eCSA
counters.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/tx.c

index 7a6f8aba5c466b0a38f8081f08a72ce66f207947..d44dca56b8ff7e052a4f2db7f3cd02f2ee1ba76b 100644 (file)
@@ -3191,14 +3191,24 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
                if (params->count <= 1)
                        break;
 
-               sdata->csa_counter_offset_beacon =
-                       params->counter_offsets_beacon[0];
+               if ((params->n_counter_offsets_beacon >
+                    IEEE80211_MAX_CSA_COUNTERS_NUM) ||
+                   (params->n_counter_offsets_presp >
+                    IEEE80211_MAX_CSA_COUNTERS_NUM))
+                       return -EINVAL;
 
-               if (params->n_counter_offsets_presp)
-                       sdata->csa_counter_offset_presp =
-                               params->counter_offsets_presp[0];
-               else
-                       sdata->csa_counter_offset_presp = 0;
+               /* make sure we don't have garbage in other counters */
+               memset(sdata->csa_counter_offset_beacon, 0,
+                      sizeof(sdata->csa_counter_offset_beacon));
+               memset(sdata->csa_counter_offset_presp, 0,
+                      sizeof(sdata->csa_counter_offset_presp));
+
+               memcpy(sdata->csa_counter_offset_beacon,
+                      params->counter_offsets_beacon,
+                      params->n_counter_offsets_beacon * sizeof(u16));
+               memcpy(sdata->csa_counter_offset_presp,
+                      params->counter_offsets_presp,
+                      params->n_counter_offsets_presp * sizeof(u16));
 
                err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
                if (err < 0) {
index ff4d4155a84d26f982d820858dddf206a49dbba7..1bbac94da58d6a33218e8dc7eb474a7a5d26122a 100644 (file)
@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
                *pos++ = csa_settings->block_tx ? 1 : 0;
                *pos++ = ieee80211_frequency_to_channel(
                                csa_settings->chandef.chan->center_freq);
-               sdata->csa_counter_offset_beacon = (pos - presp->head);
+               sdata->csa_counter_offset_beacon[0] = (pos - presp->head);
                *pos++ = csa_settings->count;
        }
 
index fb2d9e7551584f223e446311580f7c27c468ad92..05ed592d8bbedc9c615cec23ddc87be21cfbe721 100644 (file)
@@ -70,6 +70,8 @@ struct ieee80211_local;
 
 #define IEEE80211_DEAUTH_FRAME_LEN     (24 /* hdr */ + 2 /* reason */)
 
+#define IEEE80211_MAX_CSA_COUNTERS_NUM 2
+
 struct ieee80211_fragment_entry {
        unsigned long first_frag_time;
        unsigned int seq;
@@ -753,8 +755,8 @@ struct ieee80211_sub_if_data {
        struct mac80211_qos_map __rcu *qos_map;
 
        struct work_struct csa_finalize_work;
-       int csa_counter_offset_beacon;
-       int csa_counter_offset_presp;
+       u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM];
+       u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM];
        bool csa_radar_required;
        bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
        struct cfg80211_chan_def csa_chandef;
index 69175f1539b7669f1f267f4857a4585a6958b835..767335f0ca2f6aa65a8888847e02e03f60aee905 100644 (file)
@@ -954,6 +954,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
                local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
 
+       local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                goto fail_wiphy_register;
index b06ddc9519ce07a4464a6a8460108031abc2c4a9..6495a3f0428dae6a93bafea04da26b7390f45599 100644 (file)
@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                *pos++ = 0x0;
                *pos++ = ieee80211_frequency_to_channel(
                                csa->settings.chandef.chan->center_freq);
-               sdata->csa_counter_offset_beacon = hdr_len + 6;
+               sdata->csa_counter_offset_beacon[0] = hdr_len + 6;
                *pos++ = csa->settings.count;
                *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
                *pos++ = 6;
index 263dea5a5cbb920a7a51a48c1e3f826e6e8ee8d5..0d1a42d4b6de14564ce5e0adb14c4e76a505118f 100644 (file)
@@ -2417,10 +2417,9 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
                                 struct beacon_data *beacon)
 {
        struct probe_resp *resp;
-       int counter_offset_beacon = sdata->csa_counter_offset_beacon;
-       int counter_offset_presp = sdata->csa_counter_offset_presp;
        u8 *beacon_data;
        size_t beacon_data_len;
+       int i;
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
@@ -2438,32 +2437,47 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
        default:
                return;
        }
-       if (WARN_ON(counter_offset_beacon >= beacon_data_len))
-               return;
 
-       /* Warn if the driver did not check for/react to csa
-        * completeness.  A beacon with CSA counter set to 0 should
-        * never occur, because a counter of 1 means switch just
-        * before the next beacon.
-        */
-       if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
-               return;
+       for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
+               u16 counter_offset_beacon =
+                       sdata->csa_counter_offset_beacon[i];
+               u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
 
-       sdata->csa_current_counter--;
-       beacon_data[counter_offset_beacon] = sdata->csa_current_counter;
+               if (counter_offset_beacon) {
+                       if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+                               return;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
-               rcu_read_lock();
-               resp = rcu_dereference(sdata->u.ap.probe_resp);
+                       /* Warn if the driver did not check for/react to csa
+                        * completeness.  A beacon with CSA counter set to 0
+                        * should never occur, because a counter of 1 means
+                        * switch just before the next beacon.
+                        */
+                       if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
+                               return;
 
-               /* if nl80211 accepted the offset, this should not happen. */
-               if (WARN_ON(!resp)) {
+                       beacon_data[counter_offset_beacon] =
+                               sdata->csa_current_counter - 1;
+               }
+
+               if (sdata->vif.type == NL80211_IFTYPE_AP &&
+                   counter_offset_presp) {
+                       rcu_read_lock();
+                       resp = rcu_dereference(sdata->u.ap.probe_resp);
+
+                       /* If nl80211 accepted the offset, this should
+                        * not happen.
+                        */
+                       if (WARN_ON(!resp)) {
+                               rcu_read_unlock();
+                               return;
+                       }
+                       resp->data[counter_offset_presp] =
+                               sdata->csa_current_counter - 1;
                        rcu_read_unlock();
-                       return;
                }
-               resp->data[counter_offset_presp] = sdata->csa_current_counter;
-               rcu_read_unlock();
        }
+
+       sdata->csa_current_counter--;
 }
 
 bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
@@ -2472,7 +2486,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
        struct beacon_data *beacon = NULL;
        u8 *beacon_data;
        size_t beacon_data_len;
-       int counter_beacon = sdata->csa_counter_offset_beacon;
+       int counter_beacon = sdata->csa_counter_offset_beacon[0];
        int ret = false;
 
        if (!ieee80211_sdata_running(sdata))