mac80211: track AP and peer STA TDLS chan-switch support
authorArik Nemtsov <arik@wizery.com>
Sun, 9 Nov 2014 16:50:15 +0000 (18:50 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 19 Nov 2014 17:45:04 +0000 (18:45 +0100)
The AP or peer can prohibit TDLS channel switch via a bit in the
extended capabilities IE. Parse the IE and track this bit. Set an
appropriate STA flag if both the AP and peer STA support TDLS
channel-switching.

Add the new STA flag and the missing TDLS_INITIATOR to debugfs.

Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/sta_info.h
net/mac80211/util.c

index 3ecbf68dadf1ffb51d2f358bac99c98e6050877c..8195e65d8a91b2241ec4b4f0508681254ef41588 100644 (file)
@@ -1042,6 +1042,13 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                        clear_sta_flag(sta, WLAN_STA_TDLS_PEER);
        }
 
+       /* mark TDLS channel switch support, if the AP allows it */
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !sdata->u.mgd.tdls_chan_switch_prohibited &&
+           params->ext_capab_len >= 4 &&
+           params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)
+               set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
+
        if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) {
                sta->sta.uapsd_queues = params->uapsd_queues;
                sta->sta.max_sp = params->max_sp;
index bafe489162298ec2d2df67b359985da691785258..2ba7f53746da285f0b042f4afb88b42d0de8ec8b 100644 (file)
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
        test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
 
        int res = scnprintf(buf, sizeof(buf),
-                           "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                           "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                            TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
                            TEST(PS_DRIVER), TEST(AUTHORIZED),
                            TEST(SHORT_PREAMBLE),
@@ -82,7 +82,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
                            TEST(WDS), TEST(CLEAR_PS_FILT),
                            TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
                            TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
-                           TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
+                           TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR),
+                           TEST(TDLS_CHAN_SWITCH), TEST(4ADDR_EVENT),
                            TEST(INSERTED), TEST(RATE_CONTROL),
                            TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER),
                            TEST(MPSP_RECIPIENT));
index 53eb41fad0338c1d2d662304fe792940d404f927..4b3a7e7ec2a0c080c0f2b6cff2743e20a2f487f2 100644 (file)
@@ -531,6 +531,7 @@ struct ieee80211_if_managed {
        struct sk_buff *orig_teardown_skb; /* The original teardown skb */
        struct sk_buff *teardown_skb; /* A copy to send through the AP */
        spinlock_t teardown_lock; /* To lock changing teardown_skb */
+       bool tdls_chan_switch_prohibited;
 
        /* WMM-AC TSPEC support */
        struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
@@ -1399,6 +1400,7 @@ struct ieee802_11_elems {
        size_t total_len;
 
        /* pointers to IEs */
+       const u8 *ext_capab;
        const u8 *ssid;
        const u8 *supp_rates;
        const u8 *ds_params;
@@ -1433,6 +1435,7 @@ struct ieee802_11_elems {
        const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
 
        /* length of them, respectively */
+       u8 ext_capab_len;
        u8 ssid_len;
        u8 supp_rates_len;
        u8 tim_len;
index 11a937f3fdeb2fa56935faa1d65c8a0d8f29584c..45490a202d9cda8e4e6ab9acff814b4b5a124e2f 100644 (file)
@@ -2802,6 +2802,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        }
 
        ifmgd->aid = aid;
+       ifmgd->tdls_chan_switch_prohibited =
+               elems.ext_capab && elems.ext_capab_len >= 5 &&
+               (elems.ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
 
        /*
         * Some APs are erroneously not including some information in their
index bcda2ac7d84402f83d03f24390f22f2f32ea701e..b6702c810ad39dc3eb17c4b41df0591e54bece83 100644 (file)
@@ -49,6 +49,7 @@
  *     packets. This means the link is enabled.
  * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this
  *     station.
+ * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching
  * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was
  *     keeping station in power-save mode, reply when the driver
  *     unblocks the station.
@@ -78,6 +79,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_TDLS_PEER,
        WLAN_STA_TDLS_PEER_AUTH,
        WLAN_STA_TDLS_INITIATOR,
+       WLAN_STA_TDLS_CHAN_SWITCH,
        WLAN_STA_UAPSD,
        WLAN_STA_SP,
        WLAN_STA_4ADDR_EVENT,
index f9319a5dca642c26a52b465bb2f0657e950c7486..3ca0c2e725ff4998d3ae0330adde21578b2e4d19 100644 (file)
@@ -831,6 +831,7 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
                case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
                case WLAN_EID_CHAN_SWITCH_PARAM:
+               case WLAN_EID_EXT_CAPABILITY:
                /*
                 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
                 * that if the content gets bigger it might be needed more than once
@@ -850,6 +851,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                elem_parse_failed = false;
 
                switch (id) {
+               case WLAN_EID_EXT_CAPABILITY:
+                       elems->ext_capab = pos;
+                       elems->ext_capab_len = elen;
+                       break;
                case WLAN_EID_SSID:
                        elems->ssid = pos;
                        elems->ssid_len = elen;