195224fe8SArik Nemtsov /* 295224fe8SArik Nemtsov * mac80211 TDLS handling code 395224fe8SArik Nemtsov * 495224fe8SArik Nemtsov * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> 595224fe8SArik Nemtsov * Copyright 2014, Intel Corporation 6d98ad83eSJohannes Berg * Copyright 2014 Intel Mobile Communications GmbH 7*59021c67SArik Nemtsov * Copyright 2015 - 2016 Intel Deutschland GmbH 895224fe8SArik Nemtsov * 995224fe8SArik Nemtsov * This file is GPLv2 as found in COPYING. 1095224fe8SArik Nemtsov */ 1195224fe8SArik Nemtsov 1295224fe8SArik Nemtsov #include <linux/ieee80211.h> 136f7eaa47SArik Nemtsov #include <linux/log2.h> 14c887f0d3SArik Nemtsov #include <net/cfg80211.h> 15c8ff71e6SArik Nemtsov #include <linux/rtnetlink.h> 1695224fe8SArik Nemtsov #include "ieee80211_i.h" 17ee10f2c7SArik Nemtsov #include "driver-ops.h" 18*59021c67SArik Nemtsov #include "rate.h" 1995224fe8SArik Nemtsov 2017e6a59aSArik Nemtsov /* give usermode some time for retries in setting up the TDLS session */ 2117e6a59aSArik Nemtsov #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ) 2217e6a59aSArik Nemtsov 2317e6a59aSArik Nemtsov void ieee80211_tdls_peer_del_work(struct work_struct *wk) 2417e6a59aSArik Nemtsov { 2517e6a59aSArik Nemtsov struct ieee80211_sub_if_data *sdata; 2617e6a59aSArik Nemtsov struct ieee80211_local *local; 2717e6a59aSArik Nemtsov 2817e6a59aSArik Nemtsov sdata = container_of(wk, struct ieee80211_sub_if_data, 2981dd2b88SArik Nemtsov u.mgd.tdls_peer_del_work.work); 3017e6a59aSArik Nemtsov local = sdata->local; 3117e6a59aSArik Nemtsov 3217e6a59aSArik Nemtsov mutex_lock(&local->mtx); 3381dd2b88SArik Nemtsov if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer)) { 3481dd2b88SArik Nemtsov tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->u.mgd.tdls_peer); 3581dd2b88SArik Nemtsov sta_info_destroy_addr(sdata, sdata->u.mgd.tdls_peer); 3681dd2b88SArik Nemtsov eth_zero_addr(sdata->u.mgd.tdls_peer); 3717e6a59aSArik Nemtsov } 3817e6a59aSArik Nemtsov mutex_unlock(&local->mtx); 3917e6a59aSArik Nemtsov } 4017e6a59aSArik Nemtsov 41b98fb44fSArik Nemtsov static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, 4278632a17SArik Nemtsov struct sk_buff *skb) 4395224fe8SArik Nemtsov { 44b98fb44fSArik Nemtsov struct ieee80211_local *local = sdata->local; 4582c0cc90SArik Nemtsov struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 4678632a17SArik Nemtsov bool chan_switch = local->hw.wiphy->features & 4778632a17SArik Nemtsov NL80211_FEATURE_TDLS_CHANNEL_SWITCH; 4882c0cc90SArik Nemtsov bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) && 4982c0cc90SArik Nemtsov !ifmgd->tdls_wider_bw_prohibited; 50b98fb44fSArik Nemtsov enum ieee80211_band band = ieee80211_get_sdata_band(sdata); 51b98fb44fSArik Nemtsov struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; 52b98fb44fSArik Nemtsov bool vht = sband && sband->vht_cap.vht_supported; 53b98fb44fSArik Nemtsov u8 *pos = (void *)skb_put(skb, 10); 5495224fe8SArik Nemtsov 5595224fe8SArik Nemtsov *pos++ = WLAN_EID_EXT_CAPABILITY; 56b98fb44fSArik Nemtsov *pos++ = 8; /* len */ 5795224fe8SArik Nemtsov *pos++ = 0x0; 5895224fe8SArik Nemtsov *pos++ = 0x0; 5995224fe8SArik Nemtsov *pos++ = 0x0; 6078632a17SArik Nemtsov *pos++ = chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0; 6195224fe8SArik Nemtsov *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; 62b98fb44fSArik Nemtsov *pos++ = 0; 63b98fb44fSArik Nemtsov *pos++ = 0; 64b98fb44fSArik Nemtsov *pos++ = (vht && wider_band) ? WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED : 0; 6595224fe8SArik Nemtsov } 6695224fe8SArik Nemtsov 67f0d29cb9SArik Nemtsov static u8 68f0d29cb9SArik Nemtsov ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, 69f0d29cb9SArik Nemtsov struct sk_buff *skb, u16 start, u16 end, 70f0d29cb9SArik Nemtsov u16 spacing) 71f0d29cb9SArik Nemtsov { 72f0d29cb9SArik Nemtsov u8 subband_cnt = 0, ch_cnt = 0; 73f0d29cb9SArik Nemtsov struct ieee80211_channel *ch; 74f0d29cb9SArik Nemtsov struct cfg80211_chan_def chandef; 75f0d29cb9SArik Nemtsov int i, subband_start; 76923b352fSArik Nemtsov struct wiphy *wiphy = sdata->local->hw.wiphy; 77f0d29cb9SArik Nemtsov 78f0d29cb9SArik Nemtsov for (i = start; i <= end; i += spacing) { 79f0d29cb9SArik Nemtsov if (!ch_cnt) 80f0d29cb9SArik Nemtsov subband_start = i; 81f0d29cb9SArik Nemtsov 82f0d29cb9SArik Nemtsov ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); 83f0d29cb9SArik Nemtsov if (ch) { 84f0d29cb9SArik Nemtsov /* we will be active on the channel */ 85f0d29cb9SArik Nemtsov cfg80211_chandef_create(&chandef, ch, 8650075892SArik Nemtsov NL80211_CHAN_NO_HT); 87923b352fSArik Nemtsov if (cfg80211_reg_can_beacon_relax(wiphy, &chandef, 8850075892SArik Nemtsov sdata->wdev.iftype)) { 89f0d29cb9SArik Nemtsov ch_cnt++; 9050075892SArik Nemtsov /* 9150075892SArik Nemtsov * check if the next channel is also part of 9250075892SArik Nemtsov * this allowed range 9350075892SArik Nemtsov */ 94f0d29cb9SArik Nemtsov continue; 95f0d29cb9SArik Nemtsov } 96f0d29cb9SArik Nemtsov } 97f0d29cb9SArik Nemtsov 9850075892SArik Nemtsov /* 9950075892SArik Nemtsov * we've reached the end of a range, with allowed channels 10050075892SArik Nemtsov * found 10150075892SArik Nemtsov */ 102f0d29cb9SArik Nemtsov if (ch_cnt) { 103f0d29cb9SArik Nemtsov u8 *pos = skb_put(skb, 2); 104f0d29cb9SArik Nemtsov *pos++ = ieee80211_frequency_to_channel(subband_start); 105f0d29cb9SArik Nemtsov *pos++ = ch_cnt; 106f0d29cb9SArik Nemtsov 107f0d29cb9SArik Nemtsov subband_cnt++; 108f0d29cb9SArik Nemtsov ch_cnt = 0; 109f0d29cb9SArik Nemtsov } 110f0d29cb9SArik Nemtsov } 111f0d29cb9SArik Nemtsov 11250075892SArik Nemtsov /* all channels in the requested range are allowed - add them here */ 11350075892SArik Nemtsov if (ch_cnt) { 11450075892SArik Nemtsov u8 *pos = skb_put(skb, 2); 11550075892SArik Nemtsov *pos++ = ieee80211_frequency_to_channel(subband_start); 11650075892SArik Nemtsov *pos++ = ch_cnt; 11750075892SArik Nemtsov 11850075892SArik Nemtsov subband_cnt++; 11950075892SArik Nemtsov } 12050075892SArik Nemtsov 121f0d29cb9SArik Nemtsov return subband_cnt; 122f0d29cb9SArik Nemtsov } 123f0d29cb9SArik Nemtsov 124f0d29cb9SArik Nemtsov static void 125f0d29cb9SArik Nemtsov ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, 126f0d29cb9SArik Nemtsov struct sk_buff *skb) 127f0d29cb9SArik Nemtsov { 128f0d29cb9SArik Nemtsov /* 129f0d29cb9SArik Nemtsov * Add possible channels for TDLS. These are channels that are allowed 130f0d29cb9SArik Nemtsov * to be active. 131f0d29cb9SArik Nemtsov */ 132f0d29cb9SArik Nemtsov u8 subband_cnt; 133f0d29cb9SArik Nemtsov u8 *pos = skb_put(skb, 2); 134f0d29cb9SArik Nemtsov 135f0d29cb9SArik Nemtsov *pos++ = WLAN_EID_SUPPORTED_CHANNELS; 136f0d29cb9SArik Nemtsov 137f0d29cb9SArik Nemtsov /* 138f0d29cb9SArik Nemtsov * 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as 139f0d29cb9SArik Nemtsov * this doesn't happen in real world scenarios. 140f0d29cb9SArik Nemtsov */ 141f0d29cb9SArik Nemtsov 142f0d29cb9SArik Nemtsov /* 2GHz, with 5MHz spacing */ 143f0d29cb9SArik Nemtsov subband_cnt = ieee80211_tdls_add_subband(sdata, skb, 2412, 2472, 5); 144f0d29cb9SArik Nemtsov 145f0d29cb9SArik Nemtsov /* 5GHz, with 20MHz spacing */ 146f0d29cb9SArik Nemtsov subband_cnt += ieee80211_tdls_add_subband(sdata, skb, 5000, 5825, 20); 147f0d29cb9SArik Nemtsov 148f0d29cb9SArik Nemtsov /* length */ 149f0d29cb9SArik Nemtsov *pos = 2 * subband_cnt; 150f0d29cb9SArik Nemtsov } 151f0d29cb9SArik Nemtsov 152a38700ddSArik Nemtsov static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata, 153a38700ddSArik Nemtsov struct sk_buff *skb) 154a38700ddSArik Nemtsov { 155a38700ddSArik Nemtsov u8 *pos; 156a38700ddSArik Nemtsov u8 op_class; 157a38700ddSArik Nemtsov 158a38700ddSArik Nemtsov if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef, 159a38700ddSArik Nemtsov &op_class)) 160a38700ddSArik Nemtsov return; 161a38700ddSArik Nemtsov 162a38700ddSArik Nemtsov pos = skb_put(skb, 4); 163a38700ddSArik Nemtsov *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; 164a38700ddSArik Nemtsov *pos++ = 2; /* len */ 165a38700ddSArik Nemtsov 166a38700ddSArik Nemtsov *pos++ = op_class; 167a38700ddSArik Nemtsov *pos++ = op_class; /* give current operating class as alternate too */ 168a38700ddSArik Nemtsov } 169a38700ddSArik Nemtsov 1702cedd879SArik Nemtsov static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) 1712cedd879SArik Nemtsov { 1722cedd879SArik Nemtsov u8 *pos = (void *)skb_put(skb, 3); 1732cedd879SArik Nemtsov 1742cedd879SArik Nemtsov *pos++ = WLAN_EID_BSS_COEX_2040; 1752cedd879SArik Nemtsov *pos++ = 1; /* len */ 1762cedd879SArik Nemtsov 1772cedd879SArik Nemtsov *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; 1782cedd879SArik Nemtsov } 1792cedd879SArik Nemtsov 180dd8c0b03SArik Nemtsov static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, 181dd8c0b03SArik Nemtsov u16 status_code) 18295224fe8SArik Nemtsov { 183dd8c0b03SArik Nemtsov /* The capability will be 0 when sending a failure code */ 184dd8c0b03SArik Nemtsov if (status_code != 0) 185dd8c0b03SArik Nemtsov return 0; 186dd8c0b03SArik Nemtsov 187ea1b2b45SJohannes Berg if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_2GHZ) { 188ea1b2b45SJohannes Berg return WLAN_CAPABILITY_SHORT_SLOT_TIME | 189ea1b2b45SJohannes Berg WLAN_CAPABILITY_SHORT_PREAMBLE; 190ea1b2b45SJohannes Berg } 19195224fe8SArik Nemtsov 192ea1b2b45SJohannes Berg return 0; 19395224fe8SArik Nemtsov } 19495224fe8SArik Nemtsov 1951606ef4aSArik Nemtsov static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, 1961606ef4aSArik Nemtsov struct sk_buff *skb, const u8 *peer, 1971606ef4aSArik Nemtsov bool initiator) 19895224fe8SArik Nemtsov { 19995224fe8SArik Nemtsov struct ieee80211_tdls_lnkie *lnkid; 2001606ef4aSArik Nemtsov const u8 *init_addr, *rsp_addr; 2011606ef4aSArik Nemtsov 2021606ef4aSArik Nemtsov if (initiator) { 2031606ef4aSArik Nemtsov init_addr = sdata->vif.addr; 2041606ef4aSArik Nemtsov rsp_addr = peer; 2051606ef4aSArik Nemtsov } else { 2061606ef4aSArik Nemtsov init_addr = peer; 2071606ef4aSArik Nemtsov rsp_addr = sdata->vif.addr; 2081606ef4aSArik Nemtsov } 20995224fe8SArik Nemtsov 21095224fe8SArik Nemtsov lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); 21195224fe8SArik Nemtsov 21295224fe8SArik Nemtsov lnkid->ie_type = WLAN_EID_LINK_ID; 21395224fe8SArik Nemtsov lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; 21495224fe8SArik Nemtsov 2151606ef4aSArik Nemtsov memcpy(lnkid->bssid, sdata->u.mgd.bssid, ETH_ALEN); 2161606ef4aSArik Nemtsov memcpy(lnkid->init_sta, init_addr, ETH_ALEN); 2171606ef4aSArik Nemtsov memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); 21895224fe8SArik Nemtsov } 21995224fe8SArik Nemtsov 220fb28ec0cSArik Nemtsov static void 221fb28ec0cSArik Nemtsov ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) 222fb28ec0cSArik Nemtsov { 223fb28ec0cSArik Nemtsov struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 224fb28ec0cSArik Nemtsov u8 *pos = (void *)skb_put(skb, 4); 225fb28ec0cSArik Nemtsov 226fb28ec0cSArik Nemtsov *pos++ = WLAN_EID_AID; 227fb28ec0cSArik Nemtsov *pos++ = 2; /* len */ 228fb28ec0cSArik Nemtsov put_unaligned_le16(ifmgd->aid, pos); 229fb28ec0cSArik Nemtsov } 230fb28ec0cSArik Nemtsov 2316f7eaa47SArik Nemtsov /* translate numbering in the WMM parameter IE to the mac80211 notation */ 2326f7eaa47SArik Nemtsov static enum ieee80211_ac_numbers ieee80211_ac_from_wmm(int ac) 2336f7eaa47SArik Nemtsov { 2346f7eaa47SArik Nemtsov switch (ac) { 2356f7eaa47SArik Nemtsov default: 2366f7eaa47SArik Nemtsov WARN_ON_ONCE(1); 2376f7eaa47SArik Nemtsov case 0: 2386f7eaa47SArik Nemtsov return IEEE80211_AC_BE; 2396f7eaa47SArik Nemtsov case 1: 2406f7eaa47SArik Nemtsov return IEEE80211_AC_BK; 2416f7eaa47SArik Nemtsov case 2: 2426f7eaa47SArik Nemtsov return IEEE80211_AC_VI; 2436f7eaa47SArik Nemtsov case 3: 2446f7eaa47SArik Nemtsov return IEEE80211_AC_VO; 2456f7eaa47SArik Nemtsov } 2466f7eaa47SArik Nemtsov } 2476f7eaa47SArik Nemtsov 2486f7eaa47SArik Nemtsov static u8 ieee80211_wmm_aci_aifsn(int aifsn, bool acm, int aci) 2496f7eaa47SArik Nemtsov { 2506f7eaa47SArik Nemtsov u8 ret; 2516f7eaa47SArik Nemtsov 2526f7eaa47SArik Nemtsov ret = aifsn & 0x0f; 2536f7eaa47SArik Nemtsov if (acm) 2546f7eaa47SArik Nemtsov ret |= 0x10; 2556f7eaa47SArik Nemtsov ret |= (aci << 5) & 0x60; 2566f7eaa47SArik Nemtsov return ret; 2576f7eaa47SArik Nemtsov } 2586f7eaa47SArik Nemtsov 2596f7eaa47SArik Nemtsov static u8 ieee80211_wmm_ecw(u16 cw_min, u16 cw_max) 2606f7eaa47SArik Nemtsov { 2616f7eaa47SArik Nemtsov return ((ilog2(cw_min + 1) << 0x0) & 0x0f) | 2626f7eaa47SArik Nemtsov ((ilog2(cw_max + 1) << 0x4) & 0xf0); 2636f7eaa47SArik Nemtsov } 2646f7eaa47SArik Nemtsov 2656f7eaa47SArik Nemtsov static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, 2666f7eaa47SArik Nemtsov struct sk_buff *skb) 2676f7eaa47SArik Nemtsov { 2686f7eaa47SArik Nemtsov struct ieee80211_wmm_param_ie *wmm; 2696f7eaa47SArik Nemtsov struct ieee80211_tx_queue_params *txq; 2706f7eaa47SArik Nemtsov int i; 2716f7eaa47SArik Nemtsov 2726f7eaa47SArik Nemtsov wmm = (void *)skb_put(skb, sizeof(*wmm)); 2736f7eaa47SArik Nemtsov memset(wmm, 0, sizeof(*wmm)); 2746f7eaa47SArik Nemtsov 2756f7eaa47SArik Nemtsov wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; 2766f7eaa47SArik Nemtsov wmm->len = sizeof(*wmm) - 2; 2776f7eaa47SArik Nemtsov 2786f7eaa47SArik Nemtsov wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ 2796f7eaa47SArik Nemtsov wmm->oui[1] = 0x50; 2806f7eaa47SArik Nemtsov wmm->oui[2] = 0xf2; 2816f7eaa47SArik Nemtsov wmm->oui_type = 2; /* WME */ 2826f7eaa47SArik Nemtsov wmm->oui_subtype = 1; /* WME param */ 2836f7eaa47SArik Nemtsov wmm->version = 1; /* WME ver */ 2846f7eaa47SArik Nemtsov wmm->qos_info = 0; /* U-APSD not in use */ 2856f7eaa47SArik Nemtsov 2866f7eaa47SArik Nemtsov /* 2876f7eaa47SArik Nemtsov * Use the EDCA parameters defined for the BSS, or default if the AP 2886f7eaa47SArik Nemtsov * doesn't support it, as mandated by 802.11-2012 section 10.22.4 2896f7eaa47SArik Nemtsov */ 2906f7eaa47SArik Nemtsov for (i = 0; i < IEEE80211_NUM_ACS; i++) { 2916f7eaa47SArik Nemtsov txq = &sdata->tx_conf[ieee80211_ac_from_wmm(i)]; 2926f7eaa47SArik Nemtsov wmm->ac[i].aci_aifsn = ieee80211_wmm_aci_aifsn(txq->aifs, 2936f7eaa47SArik Nemtsov txq->acm, i); 2946f7eaa47SArik Nemtsov wmm->ac[i].cw = ieee80211_wmm_ecw(txq->cw_min, txq->cw_max); 2956f7eaa47SArik Nemtsov wmm->ac[i].txop_limit = cpu_to_le16(txq->txop); 2966f7eaa47SArik Nemtsov } 2976f7eaa47SArik Nemtsov } 2986f7eaa47SArik Nemtsov 299f09a87d2SArik Nemtsov static void 3000fabfaafSArik Nemtsov ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, 3010fabfaafSArik Nemtsov struct sta_info *sta) 3020fabfaafSArik Nemtsov { 3030fabfaafSArik Nemtsov /* IEEE802.11ac-2013 Table E-4 */ 3040fabfaafSArik Nemtsov u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; 3050fabfaafSArik Nemtsov struct cfg80211_chan_def uc = sta->tdls_chandef; 306*59021c67SArik Nemtsov enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta); 3070fabfaafSArik Nemtsov int i; 3080fabfaafSArik Nemtsov 3090fabfaafSArik Nemtsov /* only support upgrading non-narrow channels up to 80Mhz */ 3100fabfaafSArik Nemtsov if (max_width == NL80211_CHAN_WIDTH_5 || 3110fabfaafSArik Nemtsov max_width == NL80211_CHAN_WIDTH_10) 3120fabfaafSArik Nemtsov return; 3130fabfaafSArik Nemtsov 3140fabfaafSArik Nemtsov if (max_width > NL80211_CHAN_WIDTH_80) 3150fabfaafSArik Nemtsov max_width = NL80211_CHAN_WIDTH_80; 3160fabfaafSArik Nemtsov 3170fabfaafSArik Nemtsov if (uc.width == max_width) 3180fabfaafSArik Nemtsov return; 3190fabfaafSArik Nemtsov /* 3200fabfaafSArik Nemtsov * Channel usage constrains in the IEEE802.11ac-2013 specification only 3210fabfaafSArik Nemtsov * allow expanding a 20MHz channel to 80MHz in a single way. In 3220fabfaafSArik Nemtsov * addition, there are no 40MHz allowed channels that are not part of 3230fabfaafSArik Nemtsov * the allowed 80MHz range in the 5GHz spectrum (the relevant one here). 3240fabfaafSArik Nemtsov */ 3250fabfaafSArik Nemtsov for (i = 0; i < ARRAY_SIZE(centers_80mhz); i++) 3260fabfaafSArik Nemtsov if (abs(uc.chan->center_freq - centers_80mhz[i]) <= 30) { 3270fabfaafSArik Nemtsov uc.center_freq1 = centers_80mhz[i]; 3280fabfaafSArik Nemtsov uc.width = NL80211_CHAN_WIDTH_80; 3290fabfaafSArik Nemtsov break; 3300fabfaafSArik Nemtsov } 3310fabfaafSArik Nemtsov 3320fabfaafSArik Nemtsov if (!uc.center_freq1) 3330fabfaafSArik Nemtsov return; 3340fabfaafSArik Nemtsov 3350fabfaafSArik Nemtsov /* proceed to downgrade the chandef until usable or the same */ 336db8d9977SArik Nemtsov while (uc.width > max_width || 337dd55ab59SArik Nemtsov !cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc, 338dd55ab59SArik Nemtsov sdata->wdev.iftype)) 3390fabfaafSArik Nemtsov ieee80211_chandef_downgrade(&uc); 3400fabfaafSArik Nemtsov 3410fabfaafSArik Nemtsov if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) { 3420fabfaafSArik Nemtsov tdls_dbg(sdata, "TDLS ch width upgraded %d -> %d\n", 3430fabfaafSArik Nemtsov sta->tdls_chandef.width, uc.width); 3440fabfaafSArik Nemtsov 3450fabfaafSArik Nemtsov /* 3460fabfaafSArik Nemtsov * the station is not yet authorized when BW upgrade is done, 3470fabfaafSArik Nemtsov * locking is not required 3480fabfaafSArik Nemtsov */ 3490fabfaafSArik Nemtsov sta->tdls_chandef = uc; 3500fabfaafSArik Nemtsov } 3510fabfaafSArik Nemtsov } 3520fabfaafSArik Nemtsov 3530fabfaafSArik Nemtsov static void 354f09a87d2SArik Nemtsov ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, 355f09a87d2SArik Nemtsov struct sk_buff *skb, const u8 *peer, 3561606ef4aSArik Nemtsov u8 action_code, bool initiator, 3571606ef4aSArik Nemtsov const u8 *extra_ies, size_t extra_ies_len) 358f09a87d2SArik Nemtsov { 359f09a87d2SArik Nemtsov enum ieee80211_band band = ieee80211_get_sdata_band(sdata); 36040b861a0SArik Nemtsov struct ieee80211_local *local = sdata->local; 36113cc8a4aSArik Nemtsov struct ieee80211_supported_band *sband; 36213cc8a4aSArik Nemtsov struct ieee80211_sta_ht_cap ht_cap; 363fb28ec0cSArik Nemtsov struct ieee80211_sta_vht_cap vht_cap; 36413cc8a4aSArik Nemtsov struct sta_info *sta = NULL; 365f09a87d2SArik Nemtsov size_t offset = 0, noffset; 366f09a87d2SArik Nemtsov u8 *pos; 367f09a87d2SArik Nemtsov 368f09a87d2SArik Nemtsov ieee80211_add_srates_ie(sdata, skb, false, band); 369f09a87d2SArik Nemtsov ieee80211_add_ext_srates_ie(sdata, skb, false, band); 370f0d29cb9SArik Nemtsov ieee80211_tdls_add_supp_channels(sdata, skb); 371f09a87d2SArik Nemtsov 372f09a87d2SArik Nemtsov /* add any custom IEs that go before Extended Capabilities */ 373f09a87d2SArik Nemtsov if (extra_ies_len) { 374f09a87d2SArik Nemtsov static const u8 before_ext_cap[] = { 375f09a87d2SArik Nemtsov WLAN_EID_SUPP_RATES, 376f09a87d2SArik Nemtsov WLAN_EID_COUNTRY, 377f09a87d2SArik Nemtsov WLAN_EID_EXT_SUPP_RATES, 378f09a87d2SArik Nemtsov WLAN_EID_SUPPORTED_CHANNELS, 379f09a87d2SArik Nemtsov WLAN_EID_RSN, 380f09a87d2SArik Nemtsov }; 381f09a87d2SArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 382f09a87d2SArik Nemtsov before_ext_cap, 383f09a87d2SArik Nemtsov ARRAY_SIZE(before_ext_cap), 384f09a87d2SArik Nemtsov offset); 385f09a87d2SArik Nemtsov pos = skb_put(skb, noffset - offset); 386f09a87d2SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 387f09a87d2SArik Nemtsov offset = noffset; 388f09a87d2SArik Nemtsov } 389f09a87d2SArik Nemtsov 390b98fb44fSArik Nemtsov ieee80211_tdls_add_ext_capab(sdata, skb); 391f09a87d2SArik Nemtsov 39240b861a0SArik Nemtsov /* add the QoS element if we support it */ 39340b861a0SArik Nemtsov if (local->hw.queues >= IEEE80211_NUM_ACS && 39440b861a0SArik Nemtsov action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) 39540b861a0SArik Nemtsov ieee80211_add_wmm_info_ie(skb_put(skb, 9), 0); /* no U-APSD */ 39640b861a0SArik Nemtsov 397f09a87d2SArik Nemtsov /* add any custom IEs that go before HT capabilities */ 398f09a87d2SArik Nemtsov if (extra_ies_len) { 399f09a87d2SArik Nemtsov static const u8 before_ht_cap[] = { 400f09a87d2SArik Nemtsov WLAN_EID_SUPP_RATES, 401f09a87d2SArik Nemtsov WLAN_EID_COUNTRY, 402f09a87d2SArik Nemtsov WLAN_EID_EXT_SUPP_RATES, 403f09a87d2SArik Nemtsov WLAN_EID_SUPPORTED_CHANNELS, 404f09a87d2SArik Nemtsov WLAN_EID_RSN, 405f09a87d2SArik Nemtsov WLAN_EID_EXT_CAPABILITY, 406f09a87d2SArik Nemtsov WLAN_EID_QOS_CAPA, 407f09a87d2SArik Nemtsov WLAN_EID_FAST_BSS_TRANSITION, 408f09a87d2SArik Nemtsov WLAN_EID_TIMEOUT_INTERVAL, 409f09a87d2SArik Nemtsov WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 410f09a87d2SArik Nemtsov }; 411f09a87d2SArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 412f09a87d2SArik Nemtsov before_ht_cap, 413f09a87d2SArik Nemtsov ARRAY_SIZE(before_ht_cap), 414f09a87d2SArik Nemtsov offset); 415f09a87d2SArik Nemtsov pos = skb_put(skb, noffset - offset); 416f09a87d2SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 417f09a87d2SArik Nemtsov offset = noffset; 418f09a87d2SArik Nemtsov } 419f09a87d2SArik Nemtsov 4200fabfaafSArik Nemtsov mutex_lock(&local->sta_mtx); 421ae2e9fbaSArik Nemtsov 422ae2e9fbaSArik Nemtsov /* we should have the peer STA if we're already responding */ 423ae2e9fbaSArik Nemtsov if (action_code == WLAN_TDLS_SETUP_RESPONSE) { 424ae2e9fbaSArik Nemtsov sta = sta_info_get(sdata, peer); 425ae2e9fbaSArik Nemtsov if (WARN_ON_ONCE(!sta)) { 4260fabfaafSArik Nemtsov mutex_unlock(&local->sta_mtx); 427ae2e9fbaSArik Nemtsov return; 428ae2e9fbaSArik Nemtsov } 4290fabfaafSArik Nemtsov 4300fabfaafSArik Nemtsov sta->tdls_chandef = sdata->vif.bss_conf.chandef; 431ae2e9fbaSArik Nemtsov } 432ae2e9fbaSArik Nemtsov 433a38700ddSArik Nemtsov ieee80211_tdls_add_oper_classes(sdata, skb); 434a38700ddSArik Nemtsov 43513cc8a4aSArik Nemtsov /* 43613cc8a4aSArik Nemtsov * with TDLS we can switch channels, and HT-caps are not necessarily 43713cc8a4aSArik Nemtsov * the same on all bands. The specification limits the setup to a 43813cc8a4aSArik Nemtsov * single HT-cap, so use the current band for now. 43913cc8a4aSArik Nemtsov */ 44013cc8a4aSArik Nemtsov sband = local->hw.wiphy->bands[band]; 44113cc8a4aSArik Nemtsov memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); 442c5309ba7SJohannes Berg 443070e176aSArik Nemtsov if ((action_code == WLAN_TDLS_SETUP_REQUEST || 444070e176aSArik Nemtsov action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) && 445070e176aSArik Nemtsov ht_cap.ht_supported) { 44613cc8a4aSArik Nemtsov ieee80211_apply_htcap_overrides(sdata, &ht_cap); 44713cc8a4aSArik Nemtsov 44813cc8a4aSArik Nemtsov /* disable SMPS in TDLS initiator */ 449c5309ba7SJohannes Berg ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED 450c5309ba7SJohannes Berg << IEEE80211_HT_CAP_SM_PS_SHIFT; 451c5309ba7SJohannes Berg 452c5309ba7SJohannes Berg pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); 453c5309ba7SJohannes Berg ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); 454c5309ba7SJohannes Berg } else if (action_code == WLAN_TDLS_SETUP_RESPONSE && 455c5309ba7SJohannes Berg ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { 45613cc8a4aSArik Nemtsov /* the peer caps are already intersected with our own */ 45713cc8a4aSArik Nemtsov memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); 45813cc8a4aSArik Nemtsov 45913cc8a4aSArik Nemtsov pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); 46013cc8a4aSArik Nemtsov ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); 46113cc8a4aSArik Nemtsov } 46213cc8a4aSArik Nemtsov 4632cedd879SArik Nemtsov if (ht_cap.ht_supported && 4642cedd879SArik Nemtsov (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 4652cedd879SArik Nemtsov ieee80211_tdls_add_bss_coex_ie(skb); 4662cedd879SArik Nemtsov 467fb28ec0cSArik Nemtsov ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 468fb28ec0cSArik Nemtsov 469fb28ec0cSArik Nemtsov /* add any custom IEs that go before VHT capabilities */ 470fb28ec0cSArik Nemtsov if (extra_ies_len) { 471fb28ec0cSArik Nemtsov static const u8 before_vht_cap[] = { 472fb28ec0cSArik Nemtsov WLAN_EID_SUPP_RATES, 473fb28ec0cSArik Nemtsov WLAN_EID_COUNTRY, 474fb28ec0cSArik Nemtsov WLAN_EID_EXT_SUPP_RATES, 475fb28ec0cSArik Nemtsov WLAN_EID_SUPPORTED_CHANNELS, 476fb28ec0cSArik Nemtsov WLAN_EID_RSN, 477fb28ec0cSArik Nemtsov WLAN_EID_EXT_CAPABILITY, 478fb28ec0cSArik Nemtsov WLAN_EID_QOS_CAPA, 479fb28ec0cSArik Nemtsov WLAN_EID_FAST_BSS_TRANSITION, 480fb28ec0cSArik Nemtsov WLAN_EID_TIMEOUT_INTERVAL, 481fb28ec0cSArik Nemtsov WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 482fb28ec0cSArik Nemtsov WLAN_EID_MULTI_BAND, 483fb28ec0cSArik Nemtsov }; 484fb28ec0cSArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 485fb28ec0cSArik Nemtsov before_vht_cap, 486fb28ec0cSArik Nemtsov ARRAY_SIZE(before_vht_cap), 487fb28ec0cSArik Nemtsov offset); 488fb28ec0cSArik Nemtsov pos = skb_put(skb, noffset - offset); 489fb28ec0cSArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 490fb28ec0cSArik Nemtsov offset = noffset; 491fb28ec0cSArik Nemtsov } 492fb28ec0cSArik Nemtsov 493fb28ec0cSArik Nemtsov /* build the VHT-cap similarly to the HT-cap */ 494fb28ec0cSArik Nemtsov memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); 495070e176aSArik Nemtsov if ((action_code == WLAN_TDLS_SETUP_REQUEST || 496070e176aSArik Nemtsov action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) && 497070e176aSArik Nemtsov vht_cap.vht_supported) { 498fb28ec0cSArik Nemtsov ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); 499fb28ec0cSArik Nemtsov 500fb28ec0cSArik Nemtsov /* the AID is present only when VHT is implemented */ 501070e176aSArik Nemtsov if (action_code == WLAN_TDLS_SETUP_REQUEST) 502fb28ec0cSArik Nemtsov ieee80211_tdls_add_aid(sdata, skb); 503fb28ec0cSArik Nemtsov 504fb28ec0cSArik Nemtsov pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); 505fb28ec0cSArik Nemtsov ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); 506fb28ec0cSArik Nemtsov } else if (action_code == WLAN_TDLS_SETUP_RESPONSE && 507fb28ec0cSArik Nemtsov vht_cap.vht_supported && sta->sta.vht_cap.vht_supported) { 508fb28ec0cSArik Nemtsov /* the peer caps are already intersected with our own */ 509fb28ec0cSArik Nemtsov memcpy(&vht_cap, &sta->sta.vht_cap, sizeof(vht_cap)); 510fb28ec0cSArik Nemtsov 511fb28ec0cSArik Nemtsov /* the AID is present only when VHT is implemented */ 512fb28ec0cSArik Nemtsov ieee80211_tdls_add_aid(sdata, skb); 513fb28ec0cSArik Nemtsov 514fb28ec0cSArik Nemtsov pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); 515fb28ec0cSArik Nemtsov ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); 5160fabfaafSArik Nemtsov 5170fabfaafSArik Nemtsov /* 5180fabfaafSArik Nemtsov * if both peers support WIDER_BW, we can expand the chandef to 5190fabfaafSArik Nemtsov * a wider compatible one, up to 80MHz 5200fabfaafSArik Nemtsov */ 5210fabfaafSArik Nemtsov if (test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) 5220fabfaafSArik Nemtsov ieee80211_tdls_chandef_vht_upgrade(sdata, sta); 523fb28ec0cSArik Nemtsov } 524fb28ec0cSArik Nemtsov 5250fabfaafSArik Nemtsov mutex_unlock(&local->sta_mtx); 526fb28ec0cSArik Nemtsov 527f09a87d2SArik Nemtsov /* add any remaining IEs */ 528f09a87d2SArik Nemtsov if (extra_ies_len) { 529f09a87d2SArik Nemtsov noffset = extra_ies_len; 530f09a87d2SArik Nemtsov pos = skb_put(skb, noffset - offset); 531f09a87d2SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 532f09a87d2SArik Nemtsov } 5331606ef4aSArik Nemtsov 534f09a87d2SArik Nemtsov } 535f09a87d2SArik Nemtsov 5366f7eaa47SArik Nemtsov static void 5376f7eaa47SArik Nemtsov ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, 5386f7eaa47SArik Nemtsov struct sk_buff *skb, const u8 *peer, 5396f7eaa47SArik Nemtsov bool initiator, const u8 *extra_ies, 5406f7eaa47SArik Nemtsov size_t extra_ies_len) 5416f7eaa47SArik Nemtsov { 5426f7eaa47SArik Nemtsov struct ieee80211_local *local = sdata->local; 54313cc8a4aSArik Nemtsov struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 5446f7eaa47SArik Nemtsov size_t offset = 0, noffset; 54513cc8a4aSArik Nemtsov struct sta_info *sta, *ap_sta; 546fb28ec0cSArik Nemtsov enum ieee80211_band band = ieee80211_get_sdata_band(sdata); 5476f7eaa47SArik Nemtsov u8 *pos; 5486f7eaa47SArik Nemtsov 5490fabfaafSArik Nemtsov mutex_lock(&local->sta_mtx); 5506f7eaa47SArik Nemtsov 5516f7eaa47SArik Nemtsov sta = sta_info_get(sdata, peer); 55213cc8a4aSArik Nemtsov ap_sta = sta_info_get(sdata, ifmgd->bssid); 55313cc8a4aSArik Nemtsov if (WARN_ON_ONCE(!sta || !ap_sta)) { 5540fabfaafSArik Nemtsov mutex_unlock(&local->sta_mtx); 5556f7eaa47SArik Nemtsov return; 5566f7eaa47SArik Nemtsov } 5576f7eaa47SArik Nemtsov 5580fabfaafSArik Nemtsov sta->tdls_chandef = sdata->vif.bss_conf.chandef; 5590fabfaafSArik Nemtsov 5606f7eaa47SArik Nemtsov /* add any custom IEs that go before the QoS IE */ 5616f7eaa47SArik Nemtsov if (extra_ies_len) { 5626f7eaa47SArik Nemtsov static const u8 before_qos[] = { 5636f7eaa47SArik Nemtsov WLAN_EID_RSN, 5646f7eaa47SArik Nemtsov }; 5656f7eaa47SArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 5666f7eaa47SArik Nemtsov before_qos, 5676f7eaa47SArik Nemtsov ARRAY_SIZE(before_qos), 5686f7eaa47SArik Nemtsov offset); 5696f7eaa47SArik Nemtsov pos = skb_put(skb, noffset - offset); 5706f7eaa47SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 5716f7eaa47SArik Nemtsov offset = noffset; 5726f7eaa47SArik Nemtsov } 5736f7eaa47SArik Nemtsov 5746f7eaa47SArik Nemtsov /* add the QoS param IE if both the peer and we support it */ 575a74a8c84SJohannes Berg if (local->hw.queues >= IEEE80211_NUM_ACS && sta->sta.wme) 5766f7eaa47SArik Nemtsov ieee80211_tdls_add_wmm_param_ie(sdata, skb); 5776f7eaa47SArik Nemtsov 57813cc8a4aSArik Nemtsov /* add any custom IEs that go before HT operation */ 57913cc8a4aSArik Nemtsov if (extra_ies_len) { 58013cc8a4aSArik Nemtsov static const u8 before_ht_op[] = { 58113cc8a4aSArik Nemtsov WLAN_EID_RSN, 58213cc8a4aSArik Nemtsov WLAN_EID_QOS_CAPA, 58313cc8a4aSArik Nemtsov WLAN_EID_FAST_BSS_TRANSITION, 58413cc8a4aSArik Nemtsov WLAN_EID_TIMEOUT_INTERVAL, 58513cc8a4aSArik Nemtsov }; 58613cc8a4aSArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 58713cc8a4aSArik Nemtsov before_ht_op, 58813cc8a4aSArik Nemtsov ARRAY_SIZE(before_ht_op), 58913cc8a4aSArik Nemtsov offset); 59013cc8a4aSArik Nemtsov pos = skb_put(skb, noffset - offset); 59113cc8a4aSArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 59213cc8a4aSArik Nemtsov offset = noffset; 59313cc8a4aSArik Nemtsov } 59413cc8a4aSArik Nemtsov 59557f255f5SArik Nemtsov /* 59657f255f5SArik Nemtsov * if HT support is only added in TDLS, we need an HT-operation IE. 59757f255f5SArik Nemtsov * add the IE as required by IEEE802.11-2012 9.23.3.2. 59857f255f5SArik Nemtsov */ 59913cc8a4aSArik Nemtsov if (!ap_sta->sta.ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { 60057f255f5SArik Nemtsov u16 prot = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED | 60157f255f5SArik Nemtsov IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT | 60257f255f5SArik Nemtsov IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; 60357f255f5SArik Nemtsov 604890b7878SArik Nemtsov pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); 60513cc8a4aSArik Nemtsov ieee80211_ie_build_ht_oper(pos, &sta->sta.ht_cap, 60657f255f5SArik Nemtsov &sdata->vif.bss_conf.chandef, prot, 60757f255f5SArik Nemtsov true); 60813cc8a4aSArik Nemtsov } 60913cc8a4aSArik Nemtsov 610fb28ec0cSArik Nemtsov ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 611fb28ec0cSArik Nemtsov 612fb28ec0cSArik Nemtsov /* only include VHT-operation if not on the 2.4GHz band */ 613890b7878SArik Nemtsov if (band != IEEE80211_BAND_2GHZ && sta->sta.vht_cap.vht_supported) { 6140fabfaafSArik Nemtsov /* 6150fabfaafSArik Nemtsov * if both peers support WIDER_BW, we can expand the chandef to 6160fabfaafSArik Nemtsov * a wider compatible one, up to 80MHz 6170fabfaafSArik Nemtsov */ 6180fabfaafSArik Nemtsov if (test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) 6190fabfaafSArik Nemtsov ieee80211_tdls_chandef_vht_upgrade(sdata, sta); 6200fabfaafSArik Nemtsov 621890b7878SArik Nemtsov pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); 622fb28ec0cSArik Nemtsov ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap, 6230fabfaafSArik Nemtsov &sta->tdls_chandef); 624fb28ec0cSArik Nemtsov } 625fb28ec0cSArik Nemtsov 6260fabfaafSArik Nemtsov mutex_unlock(&local->sta_mtx); 62713cc8a4aSArik Nemtsov 6286f7eaa47SArik Nemtsov /* add any remaining IEs */ 6296f7eaa47SArik Nemtsov if (extra_ies_len) { 6306f7eaa47SArik Nemtsov noffset = extra_ies_len; 6316f7eaa47SArik Nemtsov pos = skb_put(skb, noffset - offset); 6326f7eaa47SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 6336f7eaa47SArik Nemtsov } 6346f7eaa47SArik Nemtsov } 6356f7eaa47SArik Nemtsov 636a7a6bdd0SArik Nemtsov static void 637a7a6bdd0SArik Nemtsov ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, 638a7a6bdd0SArik Nemtsov struct sk_buff *skb, const u8 *peer, 639a7a6bdd0SArik Nemtsov bool initiator, const u8 *extra_ies, 640a7a6bdd0SArik Nemtsov size_t extra_ies_len, u8 oper_class, 641a7a6bdd0SArik Nemtsov struct cfg80211_chan_def *chandef) 642a7a6bdd0SArik Nemtsov { 643a7a6bdd0SArik Nemtsov struct ieee80211_tdls_data *tf; 644a7a6bdd0SArik Nemtsov size_t offset = 0, noffset; 645a7a6bdd0SArik Nemtsov u8 *pos; 646a7a6bdd0SArik Nemtsov 647a7a6bdd0SArik Nemtsov if (WARN_ON_ONCE(!chandef)) 648a7a6bdd0SArik Nemtsov return; 649a7a6bdd0SArik Nemtsov 650a7a6bdd0SArik Nemtsov tf = (void *)skb->data; 651a7a6bdd0SArik Nemtsov tf->u.chan_switch_req.target_channel = 652a7a6bdd0SArik Nemtsov ieee80211_frequency_to_channel(chandef->chan->center_freq); 653a7a6bdd0SArik Nemtsov tf->u.chan_switch_req.oper_class = oper_class; 654a7a6bdd0SArik Nemtsov 655a7a6bdd0SArik Nemtsov if (extra_ies_len) { 656a7a6bdd0SArik Nemtsov static const u8 before_lnkie[] = { 657a7a6bdd0SArik Nemtsov WLAN_EID_SECONDARY_CHANNEL_OFFSET, 658a7a6bdd0SArik Nemtsov }; 659a7a6bdd0SArik Nemtsov noffset = ieee80211_ie_split(extra_ies, extra_ies_len, 660a7a6bdd0SArik Nemtsov before_lnkie, 661a7a6bdd0SArik Nemtsov ARRAY_SIZE(before_lnkie), 662a7a6bdd0SArik Nemtsov offset); 663a7a6bdd0SArik Nemtsov pos = skb_put(skb, noffset - offset); 664a7a6bdd0SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 665a7a6bdd0SArik Nemtsov offset = noffset; 666a7a6bdd0SArik Nemtsov } 667a7a6bdd0SArik Nemtsov 668a7a6bdd0SArik Nemtsov ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 669a7a6bdd0SArik Nemtsov 670a7a6bdd0SArik Nemtsov /* add any remaining IEs */ 671a7a6bdd0SArik Nemtsov if (extra_ies_len) { 672a7a6bdd0SArik Nemtsov noffset = extra_ies_len; 673a7a6bdd0SArik Nemtsov pos = skb_put(skb, noffset - offset); 674a7a6bdd0SArik Nemtsov memcpy(pos, extra_ies + offset, noffset - offset); 675a7a6bdd0SArik Nemtsov } 676a7a6bdd0SArik Nemtsov } 677a7a6bdd0SArik Nemtsov 6788a4d32f3SArik Nemtsov static void 6798a4d32f3SArik Nemtsov ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, 6808a4d32f3SArik Nemtsov struct sk_buff *skb, const u8 *peer, 6818a4d32f3SArik Nemtsov u16 status_code, bool initiator, 6828a4d32f3SArik Nemtsov const u8 *extra_ies, 6838a4d32f3SArik Nemtsov size_t extra_ies_len) 6848a4d32f3SArik Nemtsov { 6858a4d32f3SArik Nemtsov if (status_code == 0) 6868a4d32f3SArik Nemtsov ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 6878a4d32f3SArik Nemtsov 6888a4d32f3SArik Nemtsov if (extra_ies_len) 6898a4d32f3SArik Nemtsov memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); 6908a4d32f3SArik Nemtsov } 6918a4d32f3SArik Nemtsov 69246792a2dSArik Nemtsov static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, 69346792a2dSArik Nemtsov struct sk_buff *skb, const u8 *peer, 6941606ef4aSArik Nemtsov u8 action_code, u16 status_code, 6951606ef4aSArik Nemtsov bool initiator, const u8 *extra_ies, 696c2733905SArik Nemtsov size_t extra_ies_len, u8 oper_class, 697c2733905SArik Nemtsov struct cfg80211_chan_def *chandef) 69846792a2dSArik Nemtsov { 69946792a2dSArik Nemtsov switch (action_code) { 70046792a2dSArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 70146792a2dSArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 70246792a2dSArik Nemtsov case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 7031606ef4aSArik Nemtsov if (status_code == 0) 704f09a87d2SArik Nemtsov ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, 7051606ef4aSArik Nemtsov action_code, 7061606ef4aSArik Nemtsov initiator, 7071606ef4aSArik Nemtsov extra_ies, 708f09a87d2SArik Nemtsov extra_ies_len); 70946792a2dSArik Nemtsov break; 71046792a2dSArik Nemtsov case WLAN_TDLS_SETUP_CONFIRM: 7116f7eaa47SArik Nemtsov if (status_code == 0) 7126f7eaa47SArik Nemtsov ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, 7136f7eaa47SArik Nemtsov initiator, extra_ies, 7146f7eaa47SArik Nemtsov extra_ies_len); 7156f7eaa47SArik Nemtsov break; 71646792a2dSArik Nemtsov case WLAN_TDLS_TEARDOWN: 71746792a2dSArik Nemtsov case WLAN_TDLS_DISCOVERY_REQUEST: 718f09a87d2SArik Nemtsov if (extra_ies_len) 719f09a87d2SArik Nemtsov memcpy(skb_put(skb, extra_ies_len), extra_ies, 720f09a87d2SArik Nemtsov extra_ies_len); 7211606ef4aSArik Nemtsov if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) 7221606ef4aSArik Nemtsov ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); 72346792a2dSArik Nemtsov break; 724a7a6bdd0SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: 725a7a6bdd0SArik Nemtsov ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, 726a7a6bdd0SArik Nemtsov initiator, extra_ies, 727a7a6bdd0SArik Nemtsov extra_ies_len, 728a7a6bdd0SArik Nemtsov oper_class, chandef); 729a7a6bdd0SArik Nemtsov break; 7308a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: 7318a4d32f3SArik Nemtsov ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, 7328a4d32f3SArik Nemtsov status_code, 7338a4d32f3SArik Nemtsov initiator, extra_ies, 7348a4d32f3SArik Nemtsov extra_ies_len); 7358a4d32f3SArik Nemtsov break; 73646792a2dSArik Nemtsov } 73746792a2dSArik Nemtsov 73846792a2dSArik Nemtsov } 73946792a2dSArik Nemtsov 74095224fe8SArik Nemtsov static int 74195224fe8SArik Nemtsov ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, 7423b3a0162SJohannes Berg const u8 *peer, u8 action_code, u8 dialog_token, 74395224fe8SArik Nemtsov u16 status_code, struct sk_buff *skb) 74495224fe8SArik Nemtsov { 74595224fe8SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 74695224fe8SArik Nemtsov struct ieee80211_tdls_data *tf; 74795224fe8SArik Nemtsov 74895224fe8SArik Nemtsov tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); 74995224fe8SArik Nemtsov 75095224fe8SArik Nemtsov memcpy(tf->da, peer, ETH_ALEN); 75195224fe8SArik Nemtsov memcpy(tf->sa, sdata->vif.addr, ETH_ALEN); 75295224fe8SArik Nemtsov tf->ether_type = cpu_to_be16(ETH_P_TDLS); 75395224fe8SArik Nemtsov tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; 75495224fe8SArik Nemtsov 75559cd85cbSArik Nemtsov /* network header is after the ethernet header */ 75659cd85cbSArik Nemtsov skb_set_network_header(skb, ETH_HLEN); 75759cd85cbSArik Nemtsov 75895224fe8SArik Nemtsov switch (action_code) { 75995224fe8SArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 76095224fe8SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 76195224fe8SArik Nemtsov tf->action_code = WLAN_TDLS_SETUP_REQUEST; 76295224fe8SArik Nemtsov 76395224fe8SArik Nemtsov skb_put(skb, sizeof(tf->u.setup_req)); 76495224fe8SArik Nemtsov tf->u.setup_req.dialog_token = dialog_token; 76595224fe8SArik Nemtsov tf->u.setup_req.capability = 766dd8c0b03SArik Nemtsov cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, 767dd8c0b03SArik Nemtsov status_code)); 76895224fe8SArik Nemtsov break; 76995224fe8SArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 77095224fe8SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 77195224fe8SArik Nemtsov tf->action_code = WLAN_TDLS_SETUP_RESPONSE; 77295224fe8SArik Nemtsov 77395224fe8SArik Nemtsov skb_put(skb, sizeof(tf->u.setup_resp)); 77495224fe8SArik Nemtsov tf->u.setup_resp.status_code = cpu_to_le16(status_code); 77595224fe8SArik Nemtsov tf->u.setup_resp.dialog_token = dialog_token; 77695224fe8SArik Nemtsov tf->u.setup_resp.capability = 777dd8c0b03SArik Nemtsov cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, 778dd8c0b03SArik Nemtsov status_code)); 77995224fe8SArik Nemtsov break; 78095224fe8SArik Nemtsov case WLAN_TDLS_SETUP_CONFIRM: 78195224fe8SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 78295224fe8SArik Nemtsov tf->action_code = WLAN_TDLS_SETUP_CONFIRM; 78395224fe8SArik Nemtsov 78495224fe8SArik Nemtsov skb_put(skb, sizeof(tf->u.setup_cfm)); 78595224fe8SArik Nemtsov tf->u.setup_cfm.status_code = cpu_to_le16(status_code); 78695224fe8SArik Nemtsov tf->u.setup_cfm.dialog_token = dialog_token; 78795224fe8SArik Nemtsov break; 78895224fe8SArik Nemtsov case WLAN_TDLS_TEARDOWN: 78995224fe8SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 79095224fe8SArik Nemtsov tf->action_code = WLAN_TDLS_TEARDOWN; 79195224fe8SArik Nemtsov 79295224fe8SArik Nemtsov skb_put(skb, sizeof(tf->u.teardown)); 79395224fe8SArik Nemtsov tf->u.teardown.reason_code = cpu_to_le16(status_code); 79495224fe8SArik Nemtsov break; 79595224fe8SArik Nemtsov case WLAN_TDLS_DISCOVERY_REQUEST: 79695224fe8SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 79795224fe8SArik Nemtsov tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST; 79895224fe8SArik Nemtsov 79995224fe8SArik Nemtsov skb_put(skb, sizeof(tf->u.discover_req)); 80095224fe8SArik Nemtsov tf->u.discover_req.dialog_token = dialog_token; 80195224fe8SArik Nemtsov break; 802a7a6bdd0SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: 803a7a6bdd0SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 804a7a6bdd0SArik Nemtsov tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; 805a7a6bdd0SArik Nemtsov 806a7a6bdd0SArik Nemtsov skb_put(skb, sizeof(tf->u.chan_switch_req)); 807a7a6bdd0SArik Nemtsov break; 8088a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: 8098a4d32f3SArik Nemtsov tf->category = WLAN_CATEGORY_TDLS; 8108a4d32f3SArik Nemtsov tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; 8118a4d32f3SArik Nemtsov 8128a4d32f3SArik Nemtsov skb_put(skb, sizeof(tf->u.chan_switch_resp)); 8138a4d32f3SArik Nemtsov tf->u.chan_switch_resp.status_code = cpu_to_le16(status_code); 8148a4d32f3SArik Nemtsov break; 81595224fe8SArik Nemtsov default: 81695224fe8SArik Nemtsov return -EINVAL; 81795224fe8SArik Nemtsov } 81895224fe8SArik Nemtsov 81995224fe8SArik Nemtsov return 0; 82095224fe8SArik Nemtsov } 82195224fe8SArik Nemtsov 82295224fe8SArik Nemtsov static int 82395224fe8SArik Nemtsov ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, 8243b3a0162SJohannes Berg const u8 *peer, u8 action_code, u8 dialog_token, 82595224fe8SArik Nemtsov u16 status_code, struct sk_buff *skb) 82695224fe8SArik Nemtsov { 82795224fe8SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 82895224fe8SArik Nemtsov struct ieee80211_mgmt *mgmt; 82995224fe8SArik Nemtsov 83095224fe8SArik Nemtsov mgmt = (void *)skb_put(skb, 24); 83195224fe8SArik Nemtsov memset(mgmt, 0, 24); 83295224fe8SArik Nemtsov memcpy(mgmt->da, peer, ETH_ALEN); 83395224fe8SArik Nemtsov memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 83495224fe8SArik Nemtsov memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); 83595224fe8SArik Nemtsov 83695224fe8SArik Nemtsov mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 83795224fe8SArik Nemtsov IEEE80211_STYPE_ACTION); 83895224fe8SArik Nemtsov 83995224fe8SArik Nemtsov switch (action_code) { 84095224fe8SArik Nemtsov case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 84195224fe8SArik Nemtsov skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp)); 84295224fe8SArik Nemtsov mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; 84395224fe8SArik Nemtsov mgmt->u.action.u.tdls_discover_resp.action_code = 84495224fe8SArik Nemtsov WLAN_PUB_ACTION_TDLS_DISCOVER_RES; 84595224fe8SArik Nemtsov mgmt->u.action.u.tdls_discover_resp.dialog_token = 84695224fe8SArik Nemtsov dialog_token; 84795224fe8SArik Nemtsov mgmt->u.action.u.tdls_discover_resp.capability = 848dd8c0b03SArik Nemtsov cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, 849dd8c0b03SArik Nemtsov status_code)); 85095224fe8SArik Nemtsov break; 85195224fe8SArik Nemtsov default: 85295224fe8SArik Nemtsov return -EINVAL; 85395224fe8SArik Nemtsov } 85495224fe8SArik Nemtsov 85595224fe8SArik Nemtsov return 0; 85695224fe8SArik Nemtsov } 85795224fe8SArik Nemtsov 858c2733905SArik Nemtsov static struct sk_buff * 859c2733905SArik Nemtsov ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, 86017e6a59aSArik Nemtsov const u8 *peer, u8 action_code, 86117e6a59aSArik Nemtsov u8 dialog_token, u16 status_code, 862c2733905SArik Nemtsov bool initiator, const u8 *extra_ies, 863c2733905SArik Nemtsov size_t extra_ies_len, u8 oper_class, 864c2733905SArik Nemtsov struct cfg80211_chan_def *chandef) 86595224fe8SArik Nemtsov { 86695224fe8SArik Nemtsov struct ieee80211_local *local = sdata->local; 867c2733905SArik Nemtsov struct sk_buff *skb; 86895224fe8SArik Nemtsov int ret; 86995224fe8SArik Nemtsov 870c2733905SArik Nemtsov skb = netdev_alloc_skb(sdata->dev, 8711277b4a9SLiad Kaufman local->hw.extra_tx_headroom + 87295224fe8SArik Nemtsov max(sizeof(struct ieee80211_mgmt), 87395224fe8SArik Nemtsov sizeof(struct ieee80211_tdls_data)) + 87495224fe8SArik Nemtsov 50 + /* supported rates */ 875b98fb44fSArik Nemtsov 10 + /* ext capab */ 87640b861a0SArik Nemtsov 26 + /* max(WMM-info, WMM-param) */ 87713cc8a4aSArik Nemtsov 2 + max(sizeof(struct ieee80211_ht_cap), 87813cc8a4aSArik Nemtsov sizeof(struct ieee80211_ht_operation)) + 879fb28ec0cSArik Nemtsov 2 + max(sizeof(struct ieee80211_vht_cap), 880fb28ec0cSArik Nemtsov sizeof(struct ieee80211_vht_operation)) + 881f0d29cb9SArik Nemtsov 50 + /* supported channels */ 8822cedd879SArik Nemtsov 3 + /* 40/20 BSS coex */ 883fb28ec0cSArik Nemtsov 4 + /* AID */ 884a38700ddSArik Nemtsov 4 + /* oper classes */ 88595224fe8SArik Nemtsov extra_ies_len + 88695224fe8SArik Nemtsov sizeof(struct ieee80211_tdls_lnkie)); 88795224fe8SArik Nemtsov if (!skb) 888c2733905SArik Nemtsov return NULL; 88995224fe8SArik Nemtsov 89095224fe8SArik Nemtsov skb_reserve(skb, local->hw.extra_tx_headroom); 89195224fe8SArik Nemtsov 89295224fe8SArik Nemtsov switch (action_code) { 89395224fe8SArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 89495224fe8SArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 89595224fe8SArik Nemtsov case WLAN_TDLS_SETUP_CONFIRM: 89695224fe8SArik Nemtsov case WLAN_TDLS_TEARDOWN: 89795224fe8SArik Nemtsov case WLAN_TDLS_DISCOVERY_REQUEST: 898a7a6bdd0SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: 8998a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: 900c2733905SArik Nemtsov ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, 901c2733905SArik Nemtsov sdata->dev, peer, 90295224fe8SArik Nemtsov action_code, dialog_token, 90395224fe8SArik Nemtsov status_code, skb); 90495224fe8SArik Nemtsov break; 90595224fe8SArik Nemtsov case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 906c2733905SArik Nemtsov ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, 907c2733905SArik Nemtsov peer, action_code, 90895224fe8SArik Nemtsov dialog_token, status_code, 90995224fe8SArik Nemtsov skb); 91095224fe8SArik Nemtsov break; 91195224fe8SArik Nemtsov default: 91295224fe8SArik Nemtsov ret = -ENOTSUPP; 91395224fe8SArik Nemtsov break; 91495224fe8SArik Nemtsov } 91595224fe8SArik Nemtsov 91695224fe8SArik Nemtsov if (ret < 0) 91795224fe8SArik Nemtsov goto fail; 91895224fe8SArik Nemtsov 919c2733905SArik Nemtsov ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, 920c2733905SArik Nemtsov initiator, extra_ies, extra_ies_len, oper_class, 921c2733905SArik Nemtsov chandef); 922c2733905SArik Nemtsov return skb; 923c2733905SArik Nemtsov 924c2733905SArik Nemtsov fail: 925c2733905SArik Nemtsov dev_kfree_skb(skb); 926c2733905SArik Nemtsov return NULL; 927c2733905SArik Nemtsov } 928c2733905SArik Nemtsov 929c2733905SArik Nemtsov static int 930c2733905SArik Nemtsov ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, 931c2733905SArik Nemtsov const u8 *peer, u8 action_code, u8 dialog_token, 932c2733905SArik Nemtsov u16 status_code, u32 peer_capability, 933c2733905SArik Nemtsov bool initiator, const u8 *extra_ies, 934c2733905SArik Nemtsov size_t extra_ies_len, u8 oper_class, 935c2733905SArik Nemtsov struct cfg80211_chan_def *chandef) 936c2733905SArik Nemtsov { 937c2733905SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 938c2733905SArik Nemtsov struct sk_buff *skb = NULL; 939c2733905SArik Nemtsov struct sta_info *sta; 940c2733905SArik Nemtsov u32 flags = 0; 941c2733905SArik Nemtsov int ret = 0; 942c2733905SArik Nemtsov 943626911ccSArik Nemtsov rcu_read_lock(); 944626911ccSArik Nemtsov sta = sta_info_get(sdata, peer); 945626911ccSArik Nemtsov 946626911ccSArik Nemtsov /* infer the initiator if we can, to support old userspace */ 94795224fe8SArik Nemtsov switch (action_code) { 94895224fe8SArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 9498b94148cSArik Nemtsov if (sta) { 950626911ccSArik Nemtsov set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); 9518b94148cSArik Nemtsov sta->sta.tdls_initiator = false; 9528b94148cSArik Nemtsov } 953626911ccSArik Nemtsov /* fall-through */ 95495224fe8SArik Nemtsov case WLAN_TDLS_SETUP_CONFIRM: 95595224fe8SArik Nemtsov case WLAN_TDLS_DISCOVERY_REQUEST: 956626911ccSArik Nemtsov initiator = true; 95795224fe8SArik Nemtsov break; 95895224fe8SArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 959626911ccSArik Nemtsov /* 960626911ccSArik Nemtsov * In some testing scenarios, we send a request and response. 961626911ccSArik Nemtsov * Make the last packet sent take effect for the initiator 962626911ccSArik Nemtsov * value. 963626911ccSArik Nemtsov */ 9648b94148cSArik Nemtsov if (sta) { 965626911ccSArik Nemtsov clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); 9668b94148cSArik Nemtsov sta->sta.tdls_initiator = true; 9678b94148cSArik Nemtsov } 968626911ccSArik Nemtsov /* fall-through */ 96995224fe8SArik Nemtsov case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 970626911ccSArik Nemtsov initiator = false; 9712fb6b9b8SArik Nemtsov break; 9722fb6b9b8SArik Nemtsov case WLAN_TDLS_TEARDOWN: 973a7a6bdd0SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: 9748a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: 9752fb6b9b8SArik Nemtsov /* any value is ok */ 97695224fe8SArik Nemtsov break; 97795224fe8SArik Nemtsov default: 97895224fe8SArik Nemtsov ret = -ENOTSUPP; 979626911ccSArik Nemtsov break; 98095224fe8SArik Nemtsov } 98195224fe8SArik Nemtsov 98246792a2dSArik Nemtsov if (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR)) 98346792a2dSArik Nemtsov initiator = true; 9842fb6b9b8SArik Nemtsov 985626911ccSArik Nemtsov rcu_read_unlock(); 986626911ccSArik Nemtsov if (ret < 0) 987626911ccSArik Nemtsov goto fail; 988626911ccSArik Nemtsov 989c2733905SArik Nemtsov skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, 990c2733905SArik Nemtsov dialog_token, status_code, 991c2733905SArik Nemtsov initiator, extra_ies, 992c2733905SArik Nemtsov extra_ies_len, oper_class, 993c2733905SArik Nemtsov chandef); 994c2733905SArik Nemtsov if (!skb) { 995c2733905SArik Nemtsov ret = -EINVAL; 996c2733905SArik Nemtsov goto fail; 997c2733905SArik Nemtsov } 998c2733905SArik Nemtsov 999c2733905SArik Nemtsov if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { 100095224fe8SArik Nemtsov ieee80211_tx_skb(sdata, skb); 100195224fe8SArik Nemtsov return 0; 100295224fe8SArik Nemtsov } 100395224fe8SArik Nemtsov 100495224fe8SArik Nemtsov /* 100595224fe8SArik Nemtsov * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise 100695224fe8SArik Nemtsov * we should default to AC_VI. 100795224fe8SArik Nemtsov */ 100895224fe8SArik Nemtsov switch (action_code) { 100995224fe8SArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 101095224fe8SArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 101195224fe8SArik Nemtsov skb_set_queue_mapping(skb, IEEE80211_AC_BK); 101295224fe8SArik Nemtsov skb->priority = 2; 101395224fe8SArik Nemtsov break; 101495224fe8SArik Nemtsov default: 101595224fe8SArik Nemtsov skb_set_queue_mapping(skb, IEEE80211_AC_VI); 101695224fe8SArik Nemtsov skb->priority = 5; 101795224fe8SArik Nemtsov break; 101895224fe8SArik Nemtsov } 101995224fe8SArik Nemtsov 10201277b4a9SLiad Kaufman /* 10211277b4a9SLiad Kaufman * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress. 10221277b4a9SLiad Kaufman * Later, if no ACK is returned from peer, we will re-send the teardown 10231277b4a9SLiad Kaufman * packet through the AP. 10241277b4a9SLiad Kaufman */ 10251277b4a9SLiad Kaufman if ((action_code == WLAN_TDLS_TEARDOWN) && 102630686bf7SJohannes Berg ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) { 10271277b4a9SLiad Kaufman bool try_resend; /* Should we keep skb for possible resend */ 10281277b4a9SLiad Kaufman 10291277b4a9SLiad Kaufman /* If not sending directly to peer - no point in keeping skb */ 10301277b4a9SLiad Kaufman rcu_read_lock(); 10311277b4a9SLiad Kaufman sta = sta_info_get(sdata, peer); 10321277b4a9SLiad Kaufman try_resend = sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); 10331277b4a9SLiad Kaufman rcu_read_unlock(); 10341277b4a9SLiad Kaufman 10351277b4a9SLiad Kaufman spin_lock_bh(&sdata->u.mgd.teardown_lock); 10361277b4a9SLiad Kaufman if (try_resend && !sdata->u.mgd.teardown_skb) { 10371277b4a9SLiad Kaufman /* Mark it as requiring TX status callback */ 10381277b4a9SLiad Kaufman flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | 10391277b4a9SLiad Kaufman IEEE80211_TX_INTFL_MLME_CONN_TX; 10401277b4a9SLiad Kaufman 10411277b4a9SLiad Kaufman /* 10421277b4a9SLiad Kaufman * skb is copied since mac80211 will later set 10431277b4a9SLiad Kaufman * properties that might not be the same as the AP, 10441277b4a9SLiad Kaufman * such as encryption, QoS, addresses, etc. 10451277b4a9SLiad Kaufman * 10461277b4a9SLiad Kaufman * No problem if skb_copy() fails, so no need to check. 10471277b4a9SLiad Kaufman */ 10481277b4a9SLiad Kaufman sdata->u.mgd.teardown_skb = skb_copy(skb, GFP_ATOMIC); 10491277b4a9SLiad Kaufman sdata->u.mgd.orig_teardown_skb = skb; 10501277b4a9SLiad Kaufman } 10511277b4a9SLiad Kaufman spin_unlock_bh(&sdata->u.mgd.teardown_lock); 10521277b4a9SLiad Kaufman } 10531277b4a9SLiad Kaufman 105495224fe8SArik Nemtsov /* disable bottom halves when entering the Tx path */ 105595224fe8SArik Nemtsov local_bh_disable(); 10561277b4a9SLiad Kaufman __ieee80211_subif_start_xmit(skb, dev, flags); 105795224fe8SArik Nemtsov local_bh_enable(); 105895224fe8SArik Nemtsov 105995224fe8SArik Nemtsov return ret; 106095224fe8SArik Nemtsov 106195224fe8SArik Nemtsov fail: 106295224fe8SArik Nemtsov dev_kfree_skb(skb); 106395224fe8SArik Nemtsov return ret; 106495224fe8SArik Nemtsov } 106595224fe8SArik Nemtsov 1066191dd469SArik Nemtsov static int 1067191dd469SArik Nemtsov ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, 106817e6a59aSArik Nemtsov const u8 *peer, u8 action_code, u8 dialog_token, 1069191dd469SArik Nemtsov u16 status_code, u32 peer_capability, bool initiator, 1070191dd469SArik Nemtsov const u8 *extra_ies, size_t extra_ies_len) 107117e6a59aSArik Nemtsov { 107217e6a59aSArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 107317e6a59aSArik Nemtsov struct ieee80211_local *local = sdata->local; 1074d51c2ea3SArik Nemtsov enum ieee80211_smps_mode smps_mode = sdata->u.mgd.driver_smps_mode; 107517e6a59aSArik Nemtsov int ret; 107617e6a59aSArik Nemtsov 1077d51c2ea3SArik Nemtsov /* don't support setup with forced SMPS mode that's not off */ 1078d51c2ea3SArik Nemtsov if (smps_mode != IEEE80211_SMPS_AUTOMATIC && 1079d51c2ea3SArik Nemtsov smps_mode != IEEE80211_SMPS_OFF) { 1080d51c2ea3SArik Nemtsov tdls_dbg(sdata, "Aborting TDLS setup due to SMPS mode %d\n", 1081d51c2ea3SArik Nemtsov smps_mode); 1082d51c2ea3SArik Nemtsov return -ENOTSUPP; 1083d51c2ea3SArik Nemtsov } 1084d51c2ea3SArik Nemtsov 108517e6a59aSArik Nemtsov mutex_lock(&local->mtx); 108617e6a59aSArik Nemtsov 108717e6a59aSArik Nemtsov /* we don't support concurrent TDLS peer setups */ 108881dd2b88SArik Nemtsov if (!is_zero_ether_addr(sdata->u.mgd.tdls_peer) && 108981dd2b88SArik Nemtsov !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { 109017e6a59aSArik Nemtsov ret = -EBUSY; 1091ae2e9fbaSArik Nemtsov goto out_unlock; 109217e6a59aSArik Nemtsov } 109317e6a59aSArik Nemtsov 10947adc3e46SArik Nemtsov /* 10957adc3e46SArik Nemtsov * make sure we have a STA representing the peer so we drop or buffer 10967adc3e46SArik Nemtsov * non-TDLS-setup frames to the peer. We can't send other packets 10976ae32e5dSArik Nemtsov * during setup through the AP path. 10986ae32e5dSArik Nemtsov * Allow error packets to be sent - sometimes we don't even add a STA 10996ae32e5dSArik Nemtsov * before failing the setup. 11007adc3e46SArik Nemtsov */ 11016ae32e5dSArik Nemtsov if (status_code == 0) { 11027adc3e46SArik Nemtsov rcu_read_lock(); 11037adc3e46SArik Nemtsov if (!sta_info_get(sdata, peer)) { 11047adc3e46SArik Nemtsov rcu_read_unlock(); 11057adc3e46SArik Nemtsov ret = -ENOLINK; 1106ae2e9fbaSArik Nemtsov goto out_unlock; 11077adc3e46SArik Nemtsov } 11087adc3e46SArik Nemtsov rcu_read_unlock(); 11096ae32e5dSArik Nemtsov } 11107adc3e46SArik Nemtsov 11113b24f4c6SEmmanuel Grumbach ieee80211_flush_queues(local, sdata, false); 1112ae2e9fbaSArik Nemtsov memcpy(sdata->u.mgd.tdls_peer, peer, ETH_ALEN); 1113ae2e9fbaSArik Nemtsov mutex_unlock(&local->mtx); 1114db67d661SArik Nemtsov 1115ae2e9fbaSArik Nemtsov /* we cannot take the mutex while preparing the setup packet */ 111617e6a59aSArik Nemtsov ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, 111717e6a59aSArik Nemtsov dialog_token, status_code, 11182fb6b9b8SArik Nemtsov peer_capability, initiator, 1119c2733905SArik Nemtsov extra_ies, extra_ies_len, 0, 1120c2733905SArik Nemtsov NULL); 1121ae2e9fbaSArik Nemtsov if (ret < 0) { 1122ae2e9fbaSArik Nemtsov mutex_lock(&local->mtx); 1123ae2e9fbaSArik Nemtsov eth_zero_addr(sdata->u.mgd.tdls_peer); 1124ae2e9fbaSArik Nemtsov mutex_unlock(&local->mtx); 1125ae2e9fbaSArik Nemtsov return ret; 1126ae2e9fbaSArik Nemtsov } 112717e6a59aSArik Nemtsov 112817e6a59aSArik Nemtsov ieee80211_queue_delayed_work(&sdata->local->hw, 112981dd2b88SArik Nemtsov &sdata->u.mgd.tdls_peer_del_work, 113017e6a59aSArik Nemtsov TDLS_PEER_SETUP_TIMEOUT); 1131ae2e9fbaSArik Nemtsov return 0; 113217e6a59aSArik Nemtsov 1133ae2e9fbaSArik Nemtsov out_unlock: 113417e6a59aSArik Nemtsov mutex_unlock(&local->mtx); 1135191dd469SArik Nemtsov return ret; 1136191dd469SArik Nemtsov } 1137191dd469SArik Nemtsov 1138db67d661SArik Nemtsov static int 1139db67d661SArik Nemtsov ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, 1140db67d661SArik Nemtsov const u8 *peer, u8 action_code, u8 dialog_token, 1141db67d661SArik Nemtsov u16 status_code, u32 peer_capability, 1142db67d661SArik Nemtsov bool initiator, const u8 *extra_ies, 1143db67d661SArik Nemtsov size_t extra_ies_len) 1144db67d661SArik Nemtsov { 1145db67d661SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1146db67d661SArik Nemtsov struct ieee80211_local *local = sdata->local; 1147db67d661SArik Nemtsov struct sta_info *sta; 1148db67d661SArik Nemtsov int ret; 1149db67d661SArik Nemtsov 1150db67d661SArik Nemtsov /* 1151db67d661SArik Nemtsov * No packets can be transmitted to the peer via the AP during setup - 1152db67d661SArik Nemtsov * the STA is set as a TDLS peer, but is not authorized. 1153db67d661SArik Nemtsov * During teardown, we prevent direct transmissions by stopping the 1154db67d661SArik Nemtsov * queues and flushing all direct packets. 1155db67d661SArik Nemtsov */ 1156db67d661SArik Nemtsov ieee80211_stop_vif_queues(local, sdata, 1157db67d661SArik Nemtsov IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); 11583b24f4c6SEmmanuel Grumbach ieee80211_flush_queues(local, sdata, false); 1159db67d661SArik Nemtsov 1160db67d661SArik Nemtsov ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, 1161db67d661SArik Nemtsov dialog_token, status_code, 1162db67d661SArik Nemtsov peer_capability, initiator, 1163c2733905SArik Nemtsov extra_ies, extra_ies_len, 0, 1164c2733905SArik Nemtsov NULL); 1165db67d661SArik Nemtsov if (ret < 0) 1166db67d661SArik Nemtsov sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", 1167db67d661SArik Nemtsov ret); 1168db67d661SArik Nemtsov 1169db67d661SArik Nemtsov /* 1170db67d661SArik Nemtsov * Remove the STA AUTH flag to force further traffic through the AP. If 1171db67d661SArik Nemtsov * the STA was unreachable, it was already removed. 1172db67d661SArik Nemtsov */ 1173db67d661SArik Nemtsov rcu_read_lock(); 1174db67d661SArik Nemtsov sta = sta_info_get(sdata, peer); 1175db67d661SArik Nemtsov if (sta) 1176db67d661SArik Nemtsov clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); 1177db67d661SArik Nemtsov rcu_read_unlock(); 1178db67d661SArik Nemtsov 1179db67d661SArik Nemtsov ieee80211_wake_vif_queues(local, sdata, 1180db67d661SArik Nemtsov IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); 1181db67d661SArik Nemtsov 1182db67d661SArik Nemtsov return 0; 1183db67d661SArik Nemtsov } 1184db67d661SArik Nemtsov 1185191dd469SArik Nemtsov int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, 1186191dd469SArik Nemtsov const u8 *peer, u8 action_code, u8 dialog_token, 1187191dd469SArik Nemtsov u16 status_code, u32 peer_capability, 1188191dd469SArik Nemtsov bool initiator, const u8 *extra_ies, 1189191dd469SArik Nemtsov size_t extra_ies_len) 1190191dd469SArik Nemtsov { 1191191dd469SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1192191dd469SArik Nemtsov int ret; 1193191dd469SArik Nemtsov 1194191dd469SArik Nemtsov if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) 1195191dd469SArik Nemtsov return -ENOTSUPP; 1196191dd469SArik Nemtsov 1197191dd469SArik Nemtsov /* make sure we are in managed mode, and associated */ 1198191dd469SArik Nemtsov if (sdata->vif.type != NL80211_IFTYPE_STATION || 1199191dd469SArik Nemtsov !sdata->u.mgd.associated) 1200191dd469SArik Nemtsov return -EINVAL; 1201191dd469SArik Nemtsov 1202191dd469SArik Nemtsov switch (action_code) { 1203191dd469SArik Nemtsov case WLAN_TDLS_SETUP_REQUEST: 1204191dd469SArik Nemtsov case WLAN_TDLS_SETUP_RESPONSE: 1205191dd469SArik Nemtsov ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, 1206191dd469SArik Nemtsov dialog_token, status_code, 1207191dd469SArik Nemtsov peer_capability, initiator, 1208191dd469SArik Nemtsov extra_ies, extra_ies_len); 1209191dd469SArik Nemtsov break; 1210191dd469SArik Nemtsov case WLAN_TDLS_TEARDOWN: 1211db67d661SArik Nemtsov ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, 1212db67d661SArik Nemtsov action_code, dialog_token, 1213db67d661SArik Nemtsov status_code, 1214db67d661SArik Nemtsov peer_capability, initiator, 1215db67d661SArik Nemtsov extra_ies, extra_ies_len); 1216db67d661SArik Nemtsov break; 1217191dd469SArik Nemtsov case WLAN_TDLS_DISCOVERY_REQUEST: 1218ee10f2c7SArik Nemtsov /* 1219ee10f2c7SArik Nemtsov * Protect the discovery so we can hear the TDLS discovery 1220ee10f2c7SArik Nemtsov * response frame. It is transmitted directly and not buffered 1221ee10f2c7SArik Nemtsov * by the AP. 1222ee10f2c7SArik Nemtsov */ 1223ee10f2c7SArik Nemtsov drv_mgd_protect_tdls_discover(sdata->local, sdata); 1224ee10f2c7SArik Nemtsov /* fall-through */ 1225ee10f2c7SArik Nemtsov case WLAN_TDLS_SETUP_CONFIRM: 1226191dd469SArik Nemtsov case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: 1227191dd469SArik Nemtsov /* no special handling */ 1228191dd469SArik Nemtsov ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, 1229191dd469SArik Nemtsov action_code, 1230191dd469SArik Nemtsov dialog_token, 1231191dd469SArik Nemtsov status_code, 1232191dd469SArik Nemtsov peer_capability, 1233191dd469SArik Nemtsov initiator, extra_ies, 1234c2733905SArik Nemtsov extra_ies_len, 0, NULL); 1235191dd469SArik Nemtsov break; 1236191dd469SArik Nemtsov default: 1237191dd469SArik Nemtsov ret = -EOPNOTSUPP; 1238191dd469SArik Nemtsov break; 1239191dd469SArik Nemtsov } 124017e6a59aSArik Nemtsov 124117e6a59aSArik Nemtsov tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", 124217e6a59aSArik Nemtsov action_code, peer, ret); 124317e6a59aSArik Nemtsov return ret; 124417e6a59aSArik Nemtsov } 124517e6a59aSArik Nemtsov 1246*59021c67SArik Nemtsov static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, 1247*59021c67SArik Nemtsov struct sta_info *sta) 12480fabfaafSArik Nemtsov { 12490fabfaafSArik Nemtsov struct ieee80211_local *local = sdata->local; 12500fabfaafSArik Nemtsov struct ieee80211_chanctx_conf *conf; 12510fabfaafSArik Nemtsov struct ieee80211_chanctx *ctx; 1252*59021c67SArik Nemtsov enum nl80211_chan_width width; 1253*59021c67SArik Nemtsov struct ieee80211_supported_band *sband; 12540fabfaafSArik Nemtsov 12550fabfaafSArik Nemtsov mutex_lock(&local->chanctx_mtx); 12560fabfaafSArik Nemtsov conf = rcu_dereference_protected(sdata->vif.chanctx_conf, 12570fabfaafSArik Nemtsov lockdep_is_held(&local->chanctx_mtx)); 12580fabfaafSArik Nemtsov if (conf) { 1259*59021c67SArik Nemtsov width = conf->def.width; 1260*59021c67SArik Nemtsov sband = local->hw.wiphy->bands[conf->def.chan->band]; 12610fabfaafSArik Nemtsov ctx = container_of(conf, struct ieee80211_chanctx, conf); 12620fabfaafSArik Nemtsov ieee80211_recalc_chanctx_chantype(local, ctx); 1263*59021c67SArik Nemtsov 1264*59021c67SArik Nemtsov /* if width changed and a peer is given, update its BW */ 1265*59021c67SArik Nemtsov if (width != conf->def.width && sta && 1266*59021c67SArik Nemtsov test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) { 1267*59021c67SArik Nemtsov enum ieee80211_sta_rx_bandwidth bw; 1268*59021c67SArik Nemtsov 1269*59021c67SArik Nemtsov bw = ieee80211_chan_width_to_rx_bw(conf->def.width); 1270*59021c67SArik Nemtsov bw = min(bw, ieee80211_sta_cap_rx_bw(sta)); 1271*59021c67SArik Nemtsov if (bw != sta->sta.bandwidth) { 1272*59021c67SArik Nemtsov sta->sta.bandwidth = bw; 1273*59021c67SArik Nemtsov rate_control_rate_update(local, sband, sta, 1274*59021c67SArik Nemtsov IEEE80211_RC_BW_CHANGED); 1275*59021c67SArik Nemtsov /* 1276*59021c67SArik Nemtsov * if a TDLS peer BW was updated, we need to 1277*59021c67SArik Nemtsov * recalc the chandef width again, to get the 1278*59021c67SArik Nemtsov * correct chanctx min_def 1279*59021c67SArik Nemtsov */ 1280*59021c67SArik Nemtsov ieee80211_recalc_chanctx_chantype(local, ctx); 1281*59021c67SArik Nemtsov } 1282*59021c67SArik Nemtsov } 1283*59021c67SArik Nemtsov 12840fabfaafSArik Nemtsov } 12850fabfaafSArik Nemtsov mutex_unlock(&local->chanctx_mtx); 12860fabfaafSArik Nemtsov } 12870fabfaafSArik Nemtsov 128822f66895SAvri Altman static int iee80211_tdls_have_ht_peers(struct ieee80211_sub_if_data *sdata) 128922f66895SAvri Altman { 129022f66895SAvri Altman struct sta_info *sta; 129122f66895SAvri Altman bool result = false; 129222f66895SAvri Altman 129322f66895SAvri Altman rcu_read_lock(); 129422f66895SAvri Altman list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { 129522f66895SAvri Altman if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || 129622f66895SAvri Altman !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || 129722f66895SAvri Altman !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH) || 129822f66895SAvri Altman !sta->sta.ht_cap.ht_supported) 129922f66895SAvri Altman continue; 130022f66895SAvri Altman result = true; 130122f66895SAvri Altman break; 130222f66895SAvri Altman } 130322f66895SAvri Altman rcu_read_unlock(); 130422f66895SAvri Altman 130522f66895SAvri Altman return result; 130622f66895SAvri Altman } 130722f66895SAvri Altman 130822f66895SAvri Altman static void 130922f66895SAvri Altman iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, 131022f66895SAvri Altman struct sta_info *sta) 131122f66895SAvri Altman { 131222f66895SAvri Altman struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 131322f66895SAvri Altman bool tdls_ht; 131422f66895SAvri Altman u16 protection = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED | 131522f66895SAvri Altman IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT | 131622f66895SAvri Altman IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; 131722f66895SAvri Altman u16 opmode; 131822f66895SAvri Altman 131922f66895SAvri Altman /* Nothing to do if the BSS connection uses HT */ 132022f66895SAvri Altman if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) 132122f66895SAvri Altman return; 132222f66895SAvri Altman 132322f66895SAvri Altman tdls_ht = (sta && sta->sta.ht_cap.ht_supported) || 132422f66895SAvri Altman iee80211_tdls_have_ht_peers(sdata); 132522f66895SAvri Altman 132622f66895SAvri Altman opmode = sdata->vif.bss_conf.ht_operation_mode; 132722f66895SAvri Altman 132822f66895SAvri Altman if (tdls_ht) 132922f66895SAvri Altman opmode |= protection; 133022f66895SAvri Altman else 133122f66895SAvri Altman opmode &= ~protection; 133222f66895SAvri Altman 133322f66895SAvri Altman if (opmode == sdata->vif.bss_conf.ht_operation_mode) 133422f66895SAvri Altman return; 133522f66895SAvri Altman 133622f66895SAvri Altman sdata->vif.bss_conf.ht_operation_mode = opmode; 133722f66895SAvri Altman ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); 133822f66895SAvri Altman } 133922f66895SAvri Altman 134095224fe8SArik Nemtsov int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, 13413b3a0162SJohannes Berg const u8 *peer, enum nl80211_tdls_operation oper) 134295224fe8SArik Nemtsov { 134395224fe8SArik Nemtsov struct sta_info *sta; 134495224fe8SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 134517e6a59aSArik Nemtsov struct ieee80211_local *local = sdata->local; 134617e6a59aSArik Nemtsov int ret; 134795224fe8SArik Nemtsov 134895224fe8SArik Nemtsov if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) 134995224fe8SArik Nemtsov return -ENOTSUPP; 135095224fe8SArik Nemtsov 135195224fe8SArik Nemtsov if (sdata->vif.type != NL80211_IFTYPE_STATION) 135295224fe8SArik Nemtsov return -EINVAL; 135395224fe8SArik Nemtsov 135417e6a59aSArik Nemtsov switch (oper) { 135517e6a59aSArik Nemtsov case NL80211_TDLS_ENABLE_LINK: 135617e6a59aSArik Nemtsov case NL80211_TDLS_DISABLE_LINK: 135717e6a59aSArik Nemtsov break; 135817e6a59aSArik Nemtsov case NL80211_TDLS_TEARDOWN: 135917e6a59aSArik Nemtsov case NL80211_TDLS_SETUP: 136017e6a59aSArik Nemtsov case NL80211_TDLS_DISCOVERY_REQ: 136117e6a59aSArik Nemtsov /* We don't support in-driver setup/teardown/discovery */ 136217e6a59aSArik Nemtsov return -ENOTSUPP; 136317e6a59aSArik Nemtsov } 136417e6a59aSArik Nemtsov 136522f66895SAvri Altman /* protect possible bss_conf changes and avoid concurrency in 136622f66895SAvri Altman * ieee80211_bss_info_change_notify() 136722f66895SAvri Altman */ 136822f66895SAvri Altman sdata_lock(sdata); 136917e6a59aSArik Nemtsov mutex_lock(&local->mtx); 137095224fe8SArik Nemtsov tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); 137195224fe8SArik Nemtsov 137295224fe8SArik Nemtsov switch (oper) { 137395224fe8SArik Nemtsov case NL80211_TDLS_ENABLE_LINK: 1374c5a71688SArik Nemtsov if (sdata->vif.csa_active) { 1375c5a71688SArik Nemtsov tdls_dbg(sdata, "TDLS: disallow link during CSA\n"); 1376c5a71688SArik Nemtsov ret = -EBUSY; 1377c5a71688SArik Nemtsov break; 1378c5a71688SArik Nemtsov } 1379c5a71688SArik Nemtsov 138022f66895SAvri Altman mutex_lock(&local->sta_mtx); 138195224fe8SArik Nemtsov sta = sta_info_get(sdata, peer); 138295224fe8SArik Nemtsov if (!sta) { 138322f66895SAvri Altman mutex_unlock(&local->sta_mtx); 138417e6a59aSArik Nemtsov ret = -ENOLINK; 138517e6a59aSArik Nemtsov break; 138695224fe8SArik Nemtsov } 138795224fe8SArik Nemtsov 1388*59021c67SArik Nemtsov iee80211_tdls_recalc_chanctx(sdata, sta); 138922f66895SAvri Altman iee80211_tdls_recalc_ht_protection(sdata, sta); 139022f66895SAvri Altman 139195224fe8SArik Nemtsov set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); 139222f66895SAvri Altman mutex_unlock(&local->sta_mtx); 139317e6a59aSArik Nemtsov 139481dd2b88SArik Nemtsov WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || 139581dd2b88SArik Nemtsov !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); 139617e6a59aSArik Nemtsov ret = 0; 139795224fe8SArik Nemtsov break; 139895224fe8SArik Nemtsov case NL80211_TDLS_DISABLE_LINK: 1399bb3f8486SLiad Kaufman /* 1400bb3f8486SLiad Kaufman * The teardown message in ieee80211_tdls_mgmt_teardown() was 1401bb3f8486SLiad Kaufman * created while the queues were stopped, so it might still be 1402bb3f8486SLiad Kaufman * pending. Before flushing the queues we need to be sure the 1403bb3f8486SLiad Kaufman * message is handled by the tasklet handling pending messages, 1404bb3f8486SLiad Kaufman * otherwise we might start destroying the station before 1405bb3f8486SLiad Kaufman * sending the teardown packet. 1406bb3f8486SLiad Kaufman * Note that this only forces the tasklet to flush pendings - 1407bb3f8486SLiad Kaufman * not to stop the tasklet from rescheduling itself. 1408bb3f8486SLiad Kaufman */ 1409bb3f8486SLiad Kaufman tasklet_kill(&local->tx_pending_tasklet); 1410db67d661SArik Nemtsov /* flush a potentially queued teardown packet */ 14113b24f4c6SEmmanuel Grumbach ieee80211_flush_queues(local, sdata, false); 1412db67d661SArik Nemtsov 141317e6a59aSArik Nemtsov ret = sta_info_destroy_addr(sdata, peer); 141422f66895SAvri Altman 141522f66895SAvri Altman mutex_lock(&local->sta_mtx); 141622f66895SAvri Altman iee80211_tdls_recalc_ht_protection(sdata, NULL); 141722f66895SAvri Altman mutex_unlock(&local->sta_mtx); 141822f66895SAvri Altman 1419*59021c67SArik Nemtsov iee80211_tdls_recalc_chanctx(sdata, NULL); 142017e6a59aSArik Nemtsov break; 142195224fe8SArik Nemtsov default: 142217e6a59aSArik Nemtsov ret = -ENOTSUPP; 142317e6a59aSArik Nemtsov break; 142495224fe8SArik Nemtsov } 142595224fe8SArik Nemtsov 142681dd2b88SArik Nemtsov if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) { 142781dd2b88SArik Nemtsov cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work); 142881dd2b88SArik Nemtsov eth_zero_addr(sdata->u.mgd.tdls_peer); 142917e6a59aSArik Nemtsov } 143017e6a59aSArik Nemtsov 1431d51c2ea3SArik Nemtsov if (ret == 0) 1432d51c2ea3SArik Nemtsov ieee80211_queue_work(&sdata->local->hw, 1433d51c2ea3SArik Nemtsov &sdata->u.mgd.request_smps_work); 1434d51c2ea3SArik Nemtsov 143517e6a59aSArik Nemtsov mutex_unlock(&local->mtx); 143622f66895SAvri Altman sdata_unlock(sdata); 143717e6a59aSArik Nemtsov return ret; 143895224fe8SArik Nemtsov } 1439c887f0d3SArik Nemtsov 1440c887f0d3SArik Nemtsov void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, 1441c887f0d3SArik Nemtsov enum nl80211_tdls_operation oper, 1442c887f0d3SArik Nemtsov u16 reason_code, gfp_t gfp) 1443c887f0d3SArik Nemtsov { 1444c887f0d3SArik Nemtsov struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1445c887f0d3SArik Nemtsov 1446c887f0d3SArik Nemtsov if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { 1447c887f0d3SArik Nemtsov sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", 1448c887f0d3SArik Nemtsov oper); 1449c887f0d3SArik Nemtsov return; 1450c887f0d3SArik Nemtsov } 1451c887f0d3SArik Nemtsov 1452c887f0d3SArik Nemtsov cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); 1453c887f0d3SArik Nemtsov } 1454c887f0d3SArik Nemtsov EXPORT_SYMBOL(ieee80211_tdls_oper_request); 1455a7a6bdd0SArik Nemtsov 1456a7a6bdd0SArik Nemtsov static void 1457a7a6bdd0SArik Nemtsov iee80211_tdls_add_ch_switch_timing(u8 *buf, u16 switch_time, u16 switch_timeout) 1458a7a6bdd0SArik Nemtsov { 1459a7a6bdd0SArik Nemtsov struct ieee80211_ch_switch_timing *ch_sw; 1460a7a6bdd0SArik Nemtsov 1461a7a6bdd0SArik Nemtsov *buf++ = WLAN_EID_CHAN_SWITCH_TIMING; 1462a7a6bdd0SArik Nemtsov *buf++ = sizeof(struct ieee80211_ch_switch_timing); 1463a7a6bdd0SArik Nemtsov 1464a7a6bdd0SArik Nemtsov ch_sw = (void *)buf; 1465a7a6bdd0SArik Nemtsov ch_sw->switch_time = cpu_to_le16(switch_time); 1466a7a6bdd0SArik Nemtsov ch_sw->switch_timeout = cpu_to_le16(switch_timeout); 1467a7a6bdd0SArik Nemtsov } 1468a7a6bdd0SArik Nemtsov 1469a7a6bdd0SArik Nemtsov /* find switch timing IE in SKB ready for Tx */ 1470a7a6bdd0SArik Nemtsov static const u8 *ieee80211_tdls_find_sw_timing_ie(struct sk_buff *skb) 1471a7a6bdd0SArik Nemtsov { 1472a7a6bdd0SArik Nemtsov struct ieee80211_tdls_data *tf; 1473a7a6bdd0SArik Nemtsov const u8 *ie_start; 1474a7a6bdd0SArik Nemtsov 1475a7a6bdd0SArik Nemtsov /* 1476a7a6bdd0SArik Nemtsov * Get the offset for the new location of the switch timing IE. 1477a7a6bdd0SArik Nemtsov * The SKB network header will now point to the "payload_type" 1478a7a6bdd0SArik Nemtsov * element of the TDLS data frame struct. 1479a7a6bdd0SArik Nemtsov */ 1480a7a6bdd0SArik Nemtsov tf = container_of(skb->data + skb_network_offset(skb), 1481a7a6bdd0SArik Nemtsov struct ieee80211_tdls_data, payload_type); 1482a7a6bdd0SArik Nemtsov ie_start = tf->u.chan_switch_req.variable; 1483a7a6bdd0SArik Nemtsov return cfg80211_find_ie(WLAN_EID_CHAN_SWITCH_TIMING, ie_start, 1484a7a6bdd0SArik Nemtsov skb->len - (ie_start - skb->data)); 1485a7a6bdd0SArik Nemtsov } 1486a7a6bdd0SArik Nemtsov 1487a7a6bdd0SArik Nemtsov static struct sk_buff * 1488a7a6bdd0SArik Nemtsov ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, 1489a7a6bdd0SArik Nemtsov struct cfg80211_chan_def *chandef, 1490a7a6bdd0SArik Nemtsov u32 *ch_sw_tm_ie_offset) 1491a7a6bdd0SArik Nemtsov { 1492a7a6bdd0SArik Nemtsov struct ieee80211_sub_if_data *sdata = sta->sdata; 1493a7a6bdd0SArik Nemtsov u8 extra_ies[2 + sizeof(struct ieee80211_sec_chan_offs_ie) + 1494a7a6bdd0SArik Nemtsov 2 + sizeof(struct ieee80211_ch_switch_timing)]; 1495a7a6bdd0SArik Nemtsov int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); 1496a7a6bdd0SArik Nemtsov u8 *pos = extra_ies; 1497a7a6bdd0SArik Nemtsov struct sk_buff *skb; 1498a7a6bdd0SArik Nemtsov 1499a7a6bdd0SArik Nemtsov /* 1500a7a6bdd0SArik Nemtsov * if chandef points to a wide channel add a Secondary-Channel 1501a7a6bdd0SArik Nemtsov * Offset information element 1502a7a6bdd0SArik Nemtsov */ 1503a7a6bdd0SArik Nemtsov if (chandef->width == NL80211_CHAN_WIDTH_40) { 1504a7a6bdd0SArik Nemtsov struct ieee80211_sec_chan_offs_ie *sec_chan_ie; 1505a7a6bdd0SArik Nemtsov bool ht40plus; 1506a7a6bdd0SArik Nemtsov 1507a7a6bdd0SArik Nemtsov *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; 1508a7a6bdd0SArik Nemtsov *pos++ = sizeof(*sec_chan_ie); 1509a7a6bdd0SArik Nemtsov sec_chan_ie = (void *)pos; 1510a7a6bdd0SArik Nemtsov 1511a7a6bdd0SArik Nemtsov ht40plus = cfg80211_get_chandef_type(chandef) == 1512a7a6bdd0SArik Nemtsov NL80211_CHAN_HT40PLUS; 1513a7a6bdd0SArik Nemtsov sec_chan_ie->sec_chan_offs = ht40plus ? 1514a7a6bdd0SArik Nemtsov IEEE80211_HT_PARAM_CHA_SEC_ABOVE : 1515a7a6bdd0SArik Nemtsov IEEE80211_HT_PARAM_CHA_SEC_BELOW; 1516a7a6bdd0SArik Nemtsov pos += sizeof(*sec_chan_ie); 1517a7a6bdd0SArik Nemtsov 1518a7a6bdd0SArik Nemtsov extra_ies_len += 2 + sizeof(struct ieee80211_sec_chan_offs_ie); 1519a7a6bdd0SArik Nemtsov } 1520a7a6bdd0SArik Nemtsov 1521a7a6bdd0SArik Nemtsov /* just set the values to 0, this is a template */ 1522a7a6bdd0SArik Nemtsov iee80211_tdls_add_ch_switch_timing(pos, 0, 0); 1523a7a6bdd0SArik Nemtsov 1524a7a6bdd0SArik Nemtsov skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, 1525a7a6bdd0SArik Nemtsov WLAN_TDLS_CHANNEL_SWITCH_REQUEST, 1526a7a6bdd0SArik Nemtsov 0, 0, !sta->sta.tdls_initiator, 1527a7a6bdd0SArik Nemtsov extra_ies, extra_ies_len, 1528a7a6bdd0SArik Nemtsov oper_class, chandef); 1529a7a6bdd0SArik Nemtsov if (!skb) 1530a7a6bdd0SArik Nemtsov return NULL; 1531a7a6bdd0SArik Nemtsov 1532a7a6bdd0SArik Nemtsov skb = ieee80211_build_data_template(sdata, skb, 0); 1533a7a6bdd0SArik Nemtsov if (IS_ERR(skb)) { 1534a7a6bdd0SArik Nemtsov tdls_dbg(sdata, "Failed building TDLS channel switch frame\n"); 1535a7a6bdd0SArik Nemtsov return NULL; 1536a7a6bdd0SArik Nemtsov } 1537a7a6bdd0SArik Nemtsov 1538a7a6bdd0SArik Nemtsov if (ch_sw_tm_ie_offset) { 1539a7a6bdd0SArik Nemtsov const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); 1540a7a6bdd0SArik Nemtsov 1541a7a6bdd0SArik Nemtsov if (!tm_ie) { 1542a7a6bdd0SArik Nemtsov tdls_dbg(sdata, "No switch timing IE in TDLS switch\n"); 1543a7a6bdd0SArik Nemtsov dev_kfree_skb_any(skb); 1544a7a6bdd0SArik Nemtsov return NULL; 1545a7a6bdd0SArik Nemtsov } 1546a7a6bdd0SArik Nemtsov 1547a7a6bdd0SArik Nemtsov *ch_sw_tm_ie_offset = tm_ie - skb->data; 1548a7a6bdd0SArik Nemtsov } 1549a7a6bdd0SArik Nemtsov 1550a7a6bdd0SArik Nemtsov tdls_dbg(sdata, 1551a7a6bdd0SArik Nemtsov "TDLS channel switch request template for %pM ch %d width %d\n", 1552a7a6bdd0SArik Nemtsov sta->sta.addr, chandef->chan->center_freq, chandef->width); 1553a7a6bdd0SArik Nemtsov return skb; 1554a7a6bdd0SArik Nemtsov } 1555a7a6bdd0SArik Nemtsov 1556a7a6bdd0SArik Nemtsov int 1557a7a6bdd0SArik Nemtsov ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, 1558a7a6bdd0SArik Nemtsov const u8 *addr, u8 oper_class, 1559a7a6bdd0SArik Nemtsov struct cfg80211_chan_def *chandef) 1560a7a6bdd0SArik Nemtsov { 1561a7a6bdd0SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1562a7a6bdd0SArik Nemtsov struct ieee80211_local *local = sdata->local; 1563a7a6bdd0SArik Nemtsov struct sta_info *sta; 1564a7a6bdd0SArik Nemtsov struct sk_buff *skb = NULL; 1565a7a6bdd0SArik Nemtsov u32 ch_sw_tm_ie; 1566a7a6bdd0SArik Nemtsov int ret; 1567a7a6bdd0SArik Nemtsov 1568a7a6bdd0SArik Nemtsov mutex_lock(&local->sta_mtx); 1569a7a6bdd0SArik Nemtsov sta = sta_info_get(sdata, addr); 1570a7a6bdd0SArik Nemtsov if (!sta) { 1571a7a6bdd0SArik Nemtsov tdls_dbg(sdata, 1572a7a6bdd0SArik Nemtsov "Invalid TDLS peer %pM for channel switch request\n", 1573a7a6bdd0SArik Nemtsov addr); 1574a7a6bdd0SArik Nemtsov ret = -ENOENT; 1575a7a6bdd0SArik Nemtsov goto out; 1576a7a6bdd0SArik Nemtsov } 1577a7a6bdd0SArik Nemtsov 1578a7a6bdd0SArik Nemtsov if (!test_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH)) { 1579a7a6bdd0SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch unsupported by %pM\n", 1580a7a6bdd0SArik Nemtsov addr); 1581a7a6bdd0SArik Nemtsov ret = -ENOTSUPP; 1582a7a6bdd0SArik Nemtsov goto out; 1583a7a6bdd0SArik Nemtsov } 1584a7a6bdd0SArik Nemtsov 1585a7a6bdd0SArik Nemtsov skb = ieee80211_tdls_ch_sw_tmpl_get(sta, oper_class, chandef, 1586a7a6bdd0SArik Nemtsov &ch_sw_tm_ie); 1587a7a6bdd0SArik Nemtsov if (!skb) { 1588a7a6bdd0SArik Nemtsov ret = -ENOENT; 1589a7a6bdd0SArik Nemtsov goto out; 1590a7a6bdd0SArik Nemtsov } 1591a7a6bdd0SArik Nemtsov 1592a7a6bdd0SArik Nemtsov ret = drv_tdls_channel_switch(local, sdata, &sta->sta, oper_class, 1593a7a6bdd0SArik Nemtsov chandef, skb, ch_sw_tm_ie); 1594a7a6bdd0SArik Nemtsov if (!ret) 1595a7a6bdd0SArik Nemtsov set_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); 1596a7a6bdd0SArik Nemtsov 1597a7a6bdd0SArik Nemtsov out: 1598a7a6bdd0SArik Nemtsov mutex_unlock(&local->sta_mtx); 1599a7a6bdd0SArik Nemtsov dev_kfree_skb_any(skb); 1600a7a6bdd0SArik Nemtsov return ret; 1601a7a6bdd0SArik Nemtsov } 1602a7a6bdd0SArik Nemtsov 1603a7a6bdd0SArik Nemtsov void 1604a7a6bdd0SArik Nemtsov ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, 1605a7a6bdd0SArik Nemtsov struct net_device *dev, 1606a7a6bdd0SArik Nemtsov const u8 *addr) 1607a7a6bdd0SArik Nemtsov { 1608a7a6bdd0SArik Nemtsov struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1609a7a6bdd0SArik Nemtsov struct ieee80211_local *local = sdata->local; 1610a7a6bdd0SArik Nemtsov struct sta_info *sta; 1611a7a6bdd0SArik Nemtsov 1612a7a6bdd0SArik Nemtsov mutex_lock(&local->sta_mtx); 1613a7a6bdd0SArik Nemtsov sta = sta_info_get(sdata, addr); 1614a7a6bdd0SArik Nemtsov if (!sta) { 1615a7a6bdd0SArik Nemtsov tdls_dbg(sdata, 1616a7a6bdd0SArik Nemtsov "Invalid TDLS peer %pM for channel switch cancel\n", 1617a7a6bdd0SArik Nemtsov addr); 1618a7a6bdd0SArik Nemtsov goto out; 1619a7a6bdd0SArik Nemtsov } 1620a7a6bdd0SArik Nemtsov 1621a7a6bdd0SArik Nemtsov if (!test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { 1622a7a6bdd0SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch not initiated by %pM\n", 1623a7a6bdd0SArik Nemtsov addr); 1624a7a6bdd0SArik Nemtsov goto out; 1625a7a6bdd0SArik Nemtsov } 1626a7a6bdd0SArik Nemtsov 1627a7a6bdd0SArik Nemtsov drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); 1628a7a6bdd0SArik Nemtsov clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); 1629a7a6bdd0SArik Nemtsov 1630a7a6bdd0SArik Nemtsov out: 1631a7a6bdd0SArik Nemtsov mutex_unlock(&local->sta_mtx); 1632a7a6bdd0SArik Nemtsov } 16338a4d32f3SArik Nemtsov 16348a4d32f3SArik Nemtsov static struct sk_buff * 16358a4d32f3SArik Nemtsov ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, 16368a4d32f3SArik Nemtsov u32 *ch_sw_tm_ie_offset) 16378a4d32f3SArik Nemtsov { 16388a4d32f3SArik Nemtsov struct ieee80211_sub_if_data *sdata = sta->sdata; 16398a4d32f3SArik Nemtsov struct sk_buff *skb; 16408a4d32f3SArik Nemtsov u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; 16418a4d32f3SArik Nemtsov 16428a4d32f3SArik Nemtsov /* initial timing are always zero in the template */ 16438a4d32f3SArik Nemtsov iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); 16448a4d32f3SArik Nemtsov 16458a4d32f3SArik Nemtsov skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, 16468a4d32f3SArik Nemtsov WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, 16478a4d32f3SArik Nemtsov 0, 0, !sta->sta.tdls_initiator, 16488a4d32f3SArik Nemtsov extra_ies, sizeof(extra_ies), 0, NULL); 16498a4d32f3SArik Nemtsov if (!skb) 16508a4d32f3SArik Nemtsov return NULL; 16518a4d32f3SArik Nemtsov 16528a4d32f3SArik Nemtsov skb = ieee80211_build_data_template(sdata, skb, 0); 16538a4d32f3SArik Nemtsov if (IS_ERR(skb)) { 16548a4d32f3SArik Nemtsov tdls_dbg(sdata, 16558a4d32f3SArik Nemtsov "Failed building TDLS channel switch resp frame\n"); 16568a4d32f3SArik Nemtsov return NULL; 16578a4d32f3SArik Nemtsov } 16588a4d32f3SArik Nemtsov 16598a4d32f3SArik Nemtsov if (ch_sw_tm_ie_offset) { 16608a4d32f3SArik Nemtsov const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); 16618a4d32f3SArik Nemtsov 16628a4d32f3SArik Nemtsov if (!tm_ie) { 16638a4d32f3SArik Nemtsov tdls_dbg(sdata, 16648a4d32f3SArik Nemtsov "No switch timing IE in TDLS switch resp\n"); 16658a4d32f3SArik Nemtsov dev_kfree_skb_any(skb); 16668a4d32f3SArik Nemtsov return NULL; 16678a4d32f3SArik Nemtsov } 16688a4d32f3SArik Nemtsov 16698a4d32f3SArik Nemtsov *ch_sw_tm_ie_offset = tm_ie - skb->data; 16708a4d32f3SArik Nemtsov } 16718a4d32f3SArik Nemtsov 16728a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS get channel switch response template for %pM\n", 16738a4d32f3SArik Nemtsov sta->sta.addr); 16748a4d32f3SArik Nemtsov return skb; 16758a4d32f3SArik Nemtsov } 16768a4d32f3SArik Nemtsov 16778a4d32f3SArik Nemtsov static int 16788a4d32f3SArik Nemtsov ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, 16798a4d32f3SArik Nemtsov struct sk_buff *skb) 16808a4d32f3SArik Nemtsov { 16818a4d32f3SArik Nemtsov struct ieee80211_local *local = sdata->local; 16828a4d32f3SArik Nemtsov struct ieee802_11_elems elems; 16838a4d32f3SArik Nemtsov struct sta_info *sta; 16848a4d32f3SArik Nemtsov struct ieee80211_tdls_data *tf = (void *)skb->data; 16858a4d32f3SArik Nemtsov bool local_initiator; 16868a4d32f3SArik Nemtsov struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 16878a4d32f3SArik Nemtsov int baselen = offsetof(typeof(*tf), u.chan_switch_resp.variable); 16888a4d32f3SArik Nemtsov struct ieee80211_tdls_ch_sw_params params = {}; 16898a4d32f3SArik Nemtsov int ret; 16908a4d32f3SArik Nemtsov 16918a4d32f3SArik Nemtsov params.action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; 16928a4d32f3SArik Nemtsov params.timestamp = rx_status->device_timestamp; 16938a4d32f3SArik Nemtsov 16948a4d32f3SArik Nemtsov if (skb->len < baselen) { 16958a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch resp too short: %d\n", 16968a4d32f3SArik Nemtsov skb->len); 16978a4d32f3SArik Nemtsov return -EINVAL; 16988a4d32f3SArik Nemtsov } 16998a4d32f3SArik Nemtsov 17008a4d32f3SArik Nemtsov mutex_lock(&local->sta_mtx); 17018a4d32f3SArik Nemtsov sta = sta_info_get(sdata, tf->sa); 17028a4d32f3SArik Nemtsov if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { 17038a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", 17048a4d32f3SArik Nemtsov tf->sa); 17058a4d32f3SArik Nemtsov ret = -EINVAL; 17068a4d32f3SArik Nemtsov goto out; 17078a4d32f3SArik Nemtsov } 17088a4d32f3SArik Nemtsov 17098a4d32f3SArik Nemtsov params.sta = &sta->sta; 17108a4d32f3SArik Nemtsov params.status = le16_to_cpu(tf->u.chan_switch_resp.status_code); 17118a4d32f3SArik Nemtsov if (params.status != 0) { 17128a4d32f3SArik Nemtsov ret = 0; 17138a4d32f3SArik Nemtsov goto call_drv; 17148a4d32f3SArik Nemtsov } 17158a4d32f3SArik Nemtsov 17168a4d32f3SArik Nemtsov ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, 17178a4d32f3SArik Nemtsov skb->len - baselen, false, &elems); 17188a4d32f3SArik Nemtsov if (elems.parse_error) { 17198a4d32f3SArik Nemtsov tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); 17208a4d32f3SArik Nemtsov ret = -EINVAL; 17218a4d32f3SArik Nemtsov goto out; 17228a4d32f3SArik Nemtsov } 17238a4d32f3SArik Nemtsov 17248a4d32f3SArik Nemtsov if (!elems.ch_sw_timing || !elems.lnk_id) { 17258a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); 17268a4d32f3SArik Nemtsov ret = -EINVAL; 17278a4d32f3SArik Nemtsov goto out; 17288a4d32f3SArik Nemtsov } 17298a4d32f3SArik Nemtsov 17308a4d32f3SArik Nemtsov /* validate the initiator is set correctly */ 17318a4d32f3SArik Nemtsov local_initiator = 17328a4d32f3SArik Nemtsov !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); 17338a4d32f3SArik Nemtsov if (local_initiator == sta->sta.tdls_initiator) { 17348a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); 17358a4d32f3SArik Nemtsov ret = -EINVAL; 17368a4d32f3SArik Nemtsov goto out; 17378a4d32f3SArik Nemtsov } 17388a4d32f3SArik Nemtsov 17398a4d32f3SArik Nemtsov params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); 17408a4d32f3SArik Nemtsov params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); 17418a4d32f3SArik Nemtsov 17428a4d32f3SArik Nemtsov params.tmpl_skb = 17438a4d32f3SArik Nemtsov ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); 17448a4d32f3SArik Nemtsov if (!params.tmpl_skb) { 17458a4d32f3SArik Nemtsov ret = -ENOENT; 17468a4d32f3SArik Nemtsov goto out; 17478a4d32f3SArik Nemtsov } 17488a4d32f3SArik Nemtsov 17498a4d32f3SArik Nemtsov call_drv: 17508a4d32f3SArik Nemtsov drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); 17518a4d32f3SArik Nemtsov 17528a4d32f3SArik Nemtsov tdls_dbg(sdata, 17538a4d32f3SArik Nemtsov "TDLS channel switch response received from %pM status %d\n", 17548a4d32f3SArik Nemtsov tf->sa, params.status); 17558a4d32f3SArik Nemtsov 17568a4d32f3SArik Nemtsov out: 17578a4d32f3SArik Nemtsov mutex_unlock(&local->sta_mtx); 17588a4d32f3SArik Nemtsov dev_kfree_skb_any(params.tmpl_skb); 17598a4d32f3SArik Nemtsov return ret; 17608a4d32f3SArik Nemtsov } 17618a4d32f3SArik Nemtsov 17628a4d32f3SArik Nemtsov static int 17638a4d32f3SArik Nemtsov ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, 17648a4d32f3SArik Nemtsov struct sk_buff *skb) 17658a4d32f3SArik Nemtsov { 17668a4d32f3SArik Nemtsov struct ieee80211_local *local = sdata->local; 17678a4d32f3SArik Nemtsov struct ieee802_11_elems elems; 17688a4d32f3SArik Nemtsov struct cfg80211_chan_def chandef; 17698a4d32f3SArik Nemtsov struct ieee80211_channel *chan; 17708a4d32f3SArik Nemtsov enum nl80211_channel_type chan_type; 17718a4d32f3SArik Nemtsov int freq; 17728a4d32f3SArik Nemtsov u8 target_channel, oper_class; 17738a4d32f3SArik Nemtsov bool local_initiator; 17748a4d32f3SArik Nemtsov struct sta_info *sta; 17758a4d32f3SArik Nemtsov enum ieee80211_band band; 17768a4d32f3SArik Nemtsov struct ieee80211_tdls_data *tf = (void *)skb->data; 17778a4d32f3SArik Nemtsov struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 17788a4d32f3SArik Nemtsov int baselen = offsetof(typeof(*tf), u.chan_switch_req.variable); 17798a4d32f3SArik Nemtsov struct ieee80211_tdls_ch_sw_params params = {}; 17808a4d32f3SArik Nemtsov int ret = 0; 17818a4d32f3SArik Nemtsov 17828a4d32f3SArik Nemtsov params.action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; 17838a4d32f3SArik Nemtsov params.timestamp = rx_status->device_timestamp; 17848a4d32f3SArik Nemtsov 17858a4d32f3SArik Nemtsov if (skb->len < baselen) { 17868a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch req too short: %d\n", 17878a4d32f3SArik Nemtsov skb->len); 17888a4d32f3SArik Nemtsov return -EINVAL; 17898a4d32f3SArik Nemtsov } 17908a4d32f3SArik Nemtsov 17918a4d32f3SArik Nemtsov target_channel = tf->u.chan_switch_req.target_channel; 17928a4d32f3SArik Nemtsov oper_class = tf->u.chan_switch_req.oper_class; 17938a4d32f3SArik Nemtsov 17948a4d32f3SArik Nemtsov /* 17958a4d32f3SArik Nemtsov * We can't easily infer the channel band. The operating class is 17968a4d32f3SArik Nemtsov * ambiguous - there are multiple tables (US/Europe/JP/Global). The 17978a4d32f3SArik Nemtsov * solution here is to treat channels with number >14 as 5GHz ones, 17988a4d32f3SArik Nemtsov * and specifically check for the (oper_class, channel) combinations 17998a4d32f3SArik Nemtsov * where this doesn't hold. These are thankfully unique according to 18008a4d32f3SArik Nemtsov * IEEE802.11-2012. 18018a4d32f3SArik Nemtsov * We consider only the 2GHz and 5GHz bands and 20MHz+ channels as 18028a4d32f3SArik Nemtsov * valid here. 18038a4d32f3SArik Nemtsov */ 18048a4d32f3SArik Nemtsov if ((oper_class == 112 || oper_class == 2 || oper_class == 3 || 18058a4d32f3SArik Nemtsov oper_class == 4 || oper_class == 5 || oper_class == 6) && 18068a4d32f3SArik Nemtsov target_channel < 14) 18078a4d32f3SArik Nemtsov band = IEEE80211_BAND_5GHZ; 18088a4d32f3SArik Nemtsov else 18098a4d32f3SArik Nemtsov band = target_channel < 14 ? IEEE80211_BAND_2GHZ : 18108a4d32f3SArik Nemtsov IEEE80211_BAND_5GHZ; 18118a4d32f3SArik Nemtsov 18128a4d32f3SArik Nemtsov freq = ieee80211_channel_to_frequency(target_channel, band); 18138a4d32f3SArik Nemtsov if (freq == 0) { 18148a4d32f3SArik Nemtsov tdls_dbg(sdata, "Invalid channel in TDLS chan switch: %d\n", 18158a4d32f3SArik Nemtsov target_channel); 18168a4d32f3SArik Nemtsov return -EINVAL; 18178a4d32f3SArik Nemtsov } 18188a4d32f3SArik Nemtsov 18198a4d32f3SArik Nemtsov chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); 18208a4d32f3SArik Nemtsov if (!chan) { 18218a4d32f3SArik Nemtsov tdls_dbg(sdata, 18228a4d32f3SArik Nemtsov "Unsupported channel for TDLS chan switch: %d\n", 18238a4d32f3SArik Nemtsov target_channel); 18248a4d32f3SArik Nemtsov return -EINVAL; 18258a4d32f3SArik Nemtsov } 18268a4d32f3SArik Nemtsov 18278a4d32f3SArik Nemtsov ieee802_11_parse_elems(tf->u.chan_switch_req.variable, 18288a4d32f3SArik Nemtsov skb->len - baselen, false, &elems); 18298a4d32f3SArik Nemtsov if (elems.parse_error) { 18308a4d32f3SArik Nemtsov tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); 18318a4d32f3SArik Nemtsov return -EINVAL; 18328a4d32f3SArik Nemtsov } 18338a4d32f3SArik Nemtsov 18348a4d32f3SArik Nemtsov if (!elems.ch_sw_timing || !elems.lnk_id) { 18358a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); 18368a4d32f3SArik Nemtsov return -EINVAL; 18378a4d32f3SArik Nemtsov } 18388a4d32f3SArik Nemtsov 183942d8d789SArik Nemtsov if (!elems.sec_chan_offs) { 184042d8d789SArik Nemtsov chan_type = NL80211_CHAN_HT20; 184142d8d789SArik Nemtsov } else { 184242d8d789SArik Nemtsov switch (elems.sec_chan_offs->sec_chan_offs) { 184342d8d789SArik Nemtsov case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 184442d8d789SArik Nemtsov chan_type = NL80211_CHAN_HT40PLUS; 184542d8d789SArik Nemtsov break; 184642d8d789SArik Nemtsov case IEEE80211_HT_PARAM_CHA_SEC_BELOW: 184742d8d789SArik Nemtsov chan_type = NL80211_CHAN_HT40MINUS; 184842d8d789SArik Nemtsov break; 184942d8d789SArik Nemtsov default: 185042d8d789SArik Nemtsov chan_type = NL80211_CHAN_HT20; 185142d8d789SArik Nemtsov break; 185242d8d789SArik Nemtsov } 185342d8d789SArik Nemtsov } 185442d8d789SArik Nemtsov 185542d8d789SArik Nemtsov cfg80211_chandef_create(&chandef, chan, chan_type); 185642d8d789SArik Nemtsov 185742d8d789SArik Nemtsov /* we will be active on the TDLS link */ 185842d8d789SArik Nemtsov if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, 185942d8d789SArik Nemtsov sdata->wdev.iftype)) { 186042d8d789SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); 186142d8d789SArik Nemtsov return -EINVAL; 186242d8d789SArik Nemtsov } 186342d8d789SArik Nemtsov 18648a4d32f3SArik Nemtsov mutex_lock(&local->sta_mtx); 18658a4d32f3SArik Nemtsov sta = sta_info_get(sdata, tf->sa); 18668a4d32f3SArik Nemtsov if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { 18678a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", 18688a4d32f3SArik Nemtsov tf->sa); 18698a4d32f3SArik Nemtsov ret = -EINVAL; 18708a4d32f3SArik Nemtsov goto out; 18718a4d32f3SArik Nemtsov } 18728a4d32f3SArik Nemtsov 18738a4d32f3SArik Nemtsov params.sta = &sta->sta; 18748a4d32f3SArik Nemtsov 18758a4d32f3SArik Nemtsov /* validate the initiator is set correctly */ 18768a4d32f3SArik Nemtsov local_initiator = 18778a4d32f3SArik Nemtsov !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); 18788a4d32f3SArik Nemtsov if (local_initiator == sta->sta.tdls_initiator) { 18798a4d32f3SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); 18808a4d32f3SArik Nemtsov ret = -EINVAL; 18818a4d32f3SArik Nemtsov goto out; 18828a4d32f3SArik Nemtsov } 18838a4d32f3SArik Nemtsov 188442d8d789SArik Nemtsov /* peer should have known better */ 188542d8d789SArik Nemtsov if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && 188642d8d789SArik Nemtsov elems.sec_chan_offs->sec_chan_offs) { 188742d8d789SArik Nemtsov tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); 188842d8d789SArik Nemtsov ret = -ENOTSUPP; 188942d8d789SArik Nemtsov goto out; 18908a4d32f3SArik Nemtsov } 18918a4d32f3SArik Nemtsov 18928a4d32f3SArik Nemtsov params.chandef = &chandef; 18938a4d32f3SArik Nemtsov params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); 18948a4d32f3SArik Nemtsov params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); 18958a4d32f3SArik Nemtsov 18968a4d32f3SArik Nemtsov params.tmpl_skb = 18978a4d32f3SArik Nemtsov ieee80211_tdls_ch_sw_resp_tmpl_get(sta, 18988a4d32f3SArik Nemtsov ¶ms.ch_sw_tm_ie); 18998a4d32f3SArik Nemtsov if (!params.tmpl_skb) { 19008a4d32f3SArik Nemtsov ret = -ENOENT; 19018a4d32f3SArik Nemtsov goto out; 19028a4d32f3SArik Nemtsov } 19038a4d32f3SArik Nemtsov 19048a4d32f3SArik Nemtsov drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); 19058a4d32f3SArik Nemtsov 19068a4d32f3SArik Nemtsov tdls_dbg(sdata, 19078a4d32f3SArik Nemtsov "TDLS ch switch request received from %pM ch %d width %d\n", 19088a4d32f3SArik Nemtsov tf->sa, params.chandef->chan->center_freq, 19098a4d32f3SArik Nemtsov params.chandef->width); 19108a4d32f3SArik Nemtsov out: 19118a4d32f3SArik Nemtsov mutex_unlock(&local->sta_mtx); 19128a4d32f3SArik Nemtsov dev_kfree_skb_any(params.tmpl_skb); 19138a4d32f3SArik Nemtsov return ret; 19148a4d32f3SArik Nemtsov } 19158a4d32f3SArik Nemtsov 1916c8ff71e6SArik Nemtsov static void 1917c8ff71e6SArik Nemtsov ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, 19188a4d32f3SArik Nemtsov struct sk_buff *skb) 19198a4d32f3SArik Nemtsov { 19208a4d32f3SArik Nemtsov struct ieee80211_tdls_data *tf = (void *)skb->data; 19218a4d32f3SArik Nemtsov struct wiphy *wiphy = sdata->local->hw.wiphy; 19228a4d32f3SArik Nemtsov 1923c8ff71e6SArik Nemtsov ASSERT_RTNL(); 1924c8ff71e6SArik Nemtsov 19258a4d32f3SArik Nemtsov /* make sure the driver supports it */ 19268a4d32f3SArik Nemtsov if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) 19278a4d32f3SArik Nemtsov return; 19288a4d32f3SArik Nemtsov 19298a4d32f3SArik Nemtsov /* we want to access the entire packet */ 19308a4d32f3SArik Nemtsov if (skb_linearize(skb)) 19318a4d32f3SArik Nemtsov return; 19328a4d32f3SArik Nemtsov /* 19338a4d32f3SArik Nemtsov * The packet/size was already validated by mac80211 Rx path, only look 19348a4d32f3SArik Nemtsov * at the action type. 19358a4d32f3SArik Nemtsov */ 19368a4d32f3SArik Nemtsov switch (tf->action_code) { 19378a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: 19388a4d32f3SArik Nemtsov ieee80211_process_tdls_channel_switch_req(sdata, skb); 19398a4d32f3SArik Nemtsov break; 19408a4d32f3SArik Nemtsov case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: 19418a4d32f3SArik Nemtsov ieee80211_process_tdls_channel_switch_resp(sdata, skb); 19428a4d32f3SArik Nemtsov break; 19438a4d32f3SArik Nemtsov default: 19448a4d32f3SArik Nemtsov WARN_ON_ONCE(1); 19458a4d32f3SArik Nemtsov return; 19468a4d32f3SArik Nemtsov } 19478a4d32f3SArik Nemtsov } 1948d51c2ea3SArik Nemtsov 1949d51c2ea3SArik Nemtsov void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) 1950d51c2ea3SArik Nemtsov { 1951d51c2ea3SArik Nemtsov struct sta_info *sta; 1952d51c2ea3SArik Nemtsov u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; 1953d51c2ea3SArik Nemtsov 1954d51c2ea3SArik Nemtsov rcu_read_lock(); 1955d51c2ea3SArik Nemtsov list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { 1956d51c2ea3SArik Nemtsov if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || 1957d51c2ea3SArik Nemtsov !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) 1958d51c2ea3SArik Nemtsov continue; 1959d51c2ea3SArik Nemtsov 1960d51c2ea3SArik Nemtsov ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr, 1961d51c2ea3SArik Nemtsov NL80211_TDLS_TEARDOWN, reason, 1962d51c2ea3SArik Nemtsov GFP_ATOMIC); 1963d51c2ea3SArik Nemtsov } 1964d51c2ea3SArik Nemtsov rcu_read_unlock(); 1965d51c2ea3SArik Nemtsov } 1966c8ff71e6SArik Nemtsov 1967c8ff71e6SArik Nemtsov void ieee80211_tdls_chsw_work(struct work_struct *wk) 1968c8ff71e6SArik Nemtsov { 1969c8ff71e6SArik Nemtsov struct ieee80211_local *local = 1970c8ff71e6SArik Nemtsov container_of(wk, struct ieee80211_local, tdls_chsw_work); 1971c8ff71e6SArik Nemtsov struct ieee80211_sub_if_data *sdata; 1972c8ff71e6SArik Nemtsov struct sk_buff *skb; 1973c8ff71e6SArik Nemtsov struct ieee80211_tdls_data *tf; 1974c8ff71e6SArik Nemtsov 1975c8ff71e6SArik Nemtsov rtnl_lock(); 1976c8ff71e6SArik Nemtsov while ((skb = skb_dequeue(&local->skb_queue_tdls_chsw))) { 1977c8ff71e6SArik Nemtsov tf = (struct ieee80211_tdls_data *)skb->data; 1978c8ff71e6SArik Nemtsov list_for_each_entry(sdata, &local->interfaces, list) { 1979c8ff71e6SArik Nemtsov if (!ieee80211_sdata_running(sdata) || 1980c8ff71e6SArik Nemtsov sdata->vif.type != NL80211_IFTYPE_STATION || 1981c8ff71e6SArik Nemtsov !ether_addr_equal(tf->da, sdata->vif.addr)) 1982c8ff71e6SArik Nemtsov continue; 1983c8ff71e6SArik Nemtsov 1984c8ff71e6SArik Nemtsov ieee80211_process_tdls_channel_switch(sdata, skb); 1985c8ff71e6SArik Nemtsov break; 1986c8ff71e6SArik Nemtsov } 1987c8ff71e6SArik Nemtsov 1988c8ff71e6SArik Nemtsov kfree_skb(skb); 1989c8ff71e6SArik Nemtsov } 1990c8ff71e6SArik Nemtsov rtnl_unlock(); 1991c8ff71e6SArik Nemtsov } 1992