xref: /openbmc/linux/net/mac80211/tdls.c (revision 59021c675995281d453eee45b3e2e1e3edbc0ec2)
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, &params.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, &params);
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 						   &params.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, &params);
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