brintos

brintos / linux-shallow public Read only

0
0
Text · 43.8 KiB · 7823e67 Raw
1563 lines · c
1/*2 * NXP Wireless LAN device driver: TDLS handling3 *4 * Copyright 2011-2020 NXP5 *6 * This software file (the "File") is distributed by NXP7 * under the terms of the GNU General Public License Version 2, June 19918 * (the "License").  You may use, redistribute and/or modify this File in9 * accordance with the terms and conditions of the License, a copy of which10 * is available on the worldwide web at11 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.12 *13 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE14 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE15 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about16 * this warranty disclaimer.17 */18 19#include "main.h"20#include "wmm.h"21#include "11n.h"22#include "11n_rxreorder.h"23#include "11ac.h"24 25#define TDLS_REQ_FIX_LEN      626#define TDLS_RESP_FIX_LEN     827#define TDLS_CONFIRM_FIX_LEN  628#define MWIFIEX_TDLS_WMM_INFO_SIZE 729 30static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,31					 const u8 *mac, u8 status)32{33	struct mwifiex_ra_list_tbl *ra_list;34	struct list_head *tid_list;35	struct sk_buff *skb, *tmp;36	struct mwifiex_txinfo *tx_info;37	u32 tid;38	u8 tid_down;39 40	mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);41	spin_lock_bh(&priv->wmm.ra_list_spinlock);42 43	skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {44		if (!ether_addr_equal(mac, skb->data))45			continue;46 47		__skb_unlink(skb, &priv->tdls_txq);48		tx_info = MWIFIEX_SKB_TXCB(skb);49		tid = skb->priority;50		tid_down = mwifiex_wmm_downgrade_tid(priv, tid);51 52		if (mwifiex_is_tdls_link_setup(status)) {53			ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);54			ra_list->tdls_link = true;55			tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;56		} else {57			tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;58			ra_list = list_first_entry_or_null(tid_list,59					struct mwifiex_ra_list_tbl, list);60			tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;61		}62 63		if (!ra_list) {64			mwifiex_write_data_complete(priv->adapter, skb, 0, -1);65			continue;66		}67 68		skb_queue_tail(&ra_list->skb_head, skb);69 70		ra_list->ba_pkt_count++;71		ra_list->total_pkt_count++;72 73		if (atomic_read(&priv->wmm.highest_queued_prio) <74						       tos_to_tid_inv[tid_down])75			atomic_set(&priv->wmm.highest_queued_prio,76				   tos_to_tid_inv[tid_down]);77 78		atomic_inc(&priv->wmm.tx_pkts_queued);79	}80 81	spin_unlock_bh(&priv->wmm.ra_list_spinlock);82	return;83}84 85static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,86				      const u8 *mac)87{88	struct mwifiex_ra_list_tbl *ra_list;89	struct list_head *ra_list_head;90	struct sk_buff *skb, *tmp;91	int i;92 93	mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);94	spin_lock_bh(&priv->wmm.ra_list_spinlock);95 96	for (i = 0; i < MAX_NUM_TID; i++) {97		if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {98			ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;99			list_for_each_entry(ra_list, ra_list_head, list) {100				skb_queue_walk_safe(&ra_list->skb_head, skb,101						    tmp) {102					if (!ether_addr_equal(mac, skb->data))103						continue;104					__skb_unlink(skb, &ra_list->skb_head);105					atomic_dec(&priv->wmm.tx_pkts_queued);106					ra_list->total_pkt_count--;107					skb_queue_tail(&priv->tdls_txq, skb);108				}109			}110		}111	}112 113	spin_unlock_bh(&priv->wmm.ra_list_spinlock);114	return;115}116 117/* This function appends rate TLV to scan config command. */118static int119mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,120			     struct sk_buff *skb)121{122	u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;123	u16 rates_size, supp_rates_size, ext_rates_size;124 125	memset(rates, 0, sizeof(rates));126	rates_size = mwifiex_get_supported_rates(priv, rates);127 128	supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);129 130	if (skb_tailroom(skb) < rates_size + 4) {131		mwifiex_dbg(priv->adapter, ERROR,132			    "Insufficient space while adding rates\n");133		return -ENOMEM;134	}135 136	pos = skb_put(skb, supp_rates_size + 2);137	*pos++ = WLAN_EID_SUPP_RATES;138	*pos++ = supp_rates_size;139	memcpy(pos, rates, supp_rates_size);140 141	if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {142		ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;143		pos = skb_put(skb, ext_rates_size + 2);144		*pos++ = WLAN_EID_EXT_SUPP_RATES;145		*pos++ = ext_rates_size;146		memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,147		       ext_rates_size);148	}149 150	return 0;151}152 153static void mwifiex_tdls_add_aid(struct mwifiex_private *priv,154				struct sk_buff *skb)155{156	struct ieee_types_assoc_rsp *assoc_rsp;157	u8 *pos;158 159	assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf;160	pos = skb_put(skb, 4);161	*pos++ = WLAN_EID_AID;162	*pos++ = 2;163	memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id));164 165	return;166}167 168static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,169				      struct sk_buff *skb)170{171	struct ieee80211_vht_cap vht_cap;172	u8 *pos;173 174	pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);175	*pos++ = WLAN_EID_VHT_CAPABILITY;176	*pos++ = sizeof(struct ieee80211_vht_cap);177 178	memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));179 180	mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);181	memcpy(pos, &vht_cap, sizeof(vht_cap));182 183	return 0;184}185 186static int187mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,188			 u8 vht_enabled, struct sk_buff *skb)189{190	struct ieee80211_ht_operation *ht_oper;191	struct mwifiex_sta_node *sta_ptr;192	struct mwifiex_bssdescriptor *bss_desc =193					&priv->curr_bss_params.bss_descriptor;194	u8 *pos;195 196	sta_ptr = mwifiex_get_sta_entry(priv, mac);197	if (unlikely(!sta_ptr)) {198		mwifiex_dbg(priv->adapter, ERROR,199			    "TDLS peer station not found in list\n");200		return -1;201	}202 203	if (!(le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info))) {204		mwifiex_dbg(priv->adapter, WARN,205			    "TDLS peer doesn't support ht capabilities\n");206		return 0;207	}208 209	pos = skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2);210	*pos++ = WLAN_EID_HT_OPERATION;211	*pos++ = sizeof(struct ieee80211_ht_operation);212	ht_oper = (void *)pos;213 214	ht_oper->primary_chan = bss_desc->channel;215 216	/* follow AP's channel bandwidth */217	if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&218	    bss_desc->bcn_ht_cap &&219	    ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))220		ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;221 222	if (vht_enabled) {223		ht_oper->ht_param =224			  mwifiex_get_sec_chan_offset(bss_desc->channel);225		ht_oper->ht_param |= BIT(2);226	}227 228	memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper,229	       sizeof(struct ieee80211_ht_operation));230 231	return 0;232}233 234static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,235				     const u8 *mac, struct sk_buff *skb)236{237	struct mwifiex_bssdescriptor *bss_desc;238	struct ieee80211_vht_operation *vht_oper;239	struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL;240	struct mwifiex_sta_node *sta_ptr;241	struct mwifiex_adapter *adapter = priv->adapter;242	u8 supp_chwd_set, peer_supp_chwd_set;243	u8 *pos, ap_supp_chwd_set, chan_bw;244	u16 mcs_map_user, mcs_map_resp, mcs_map_result;245	u16 mcs_user, mcs_resp, nss;246	u32 usr_vht_cap_info;247 248	bss_desc = &priv->curr_bss_params.bss_descriptor;249 250	sta_ptr = mwifiex_get_sta_entry(priv, mac);251	if (unlikely(!sta_ptr)) {252		mwifiex_dbg(adapter, ERROR,253			    "TDLS peer station not found in list\n");254		return -1;255	}256 257	if (!(le32_to_cpu(sta_ptr->tdls_cap.vhtcap.vht_cap_info))) {258		mwifiex_dbg(adapter, WARN,259			    "TDLS peer doesn't support vht capabilities\n");260		return 0;261	}262 263	if (!mwifiex_is_bss_in_11ac_mode(priv)) {264		if (sta_ptr->tdls_cap.extcap.ext_capab[7] &265		   WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {266			mwifiex_dbg(adapter, WARN,267				    "TDLS peer doesn't support wider bandwidth\n");268			return 0;269		}270	} else {271		ap_vht_cap = bss_desc->bcn_vht_cap;272	}273 274	pos = skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2);275	*pos++ = WLAN_EID_VHT_OPERATION;276	*pos++ = sizeof(struct ieee80211_vht_operation);277	vht_oper = (struct ieee80211_vht_operation *)pos;278 279	if (bss_desc->bss_band & BAND_A)280		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;281	else282		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;283 284	/* find the minimum bandwidth between AP/TDLS peers */285	vht_cap = &sta_ptr->tdls_cap.vhtcap;286	supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);287	peer_supp_chwd_set =288			 GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info));289	supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set);290 291	/* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */292 293	if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] &294	    WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {295		ap_supp_chwd_set =296		      GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info));297		supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set);298	}299 300	switch (supp_chwd_set) {301	case IEEE80211_VHT_CHANWIDTH_80MHZ:302		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;303		break;304	case IEEE80211_VHT_CHANWIDTH_160MHZ:305		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;306		break;307	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:308		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;309		break;310	default:311		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;312		break;313	}314 315	mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);316	mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);317	mcs_map_result = 0;318 319	for (nss = 1; nss <= 8; nss++) {320		mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);321		mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);322 323		if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||324		    (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))325			SET_VHTNSSMCS(mcs_map_result, nss,326				      IEEE80211_VHT_MCS_NOT_SUPPORTED);327		else328			SET_VHTNSSMCS(mcs_map_result, nss,329				      min_t(u16, mcs_user, mcs_resp));330	}331 332	vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result);333 334	switch (vht_oper->chan_width) {335	case IEEE80211_VHT_CHANWIDTH_80MHZ:336		chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;337		break;338	case IEEE80211_VHT_CHANWIDTH_160MHZ:339		chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ;340		break;341	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:342		chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;343		break;344	default:345		chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;346		break;347	}348	vht_oper->center_freq_seg0_idx =349			mwifiex_get_center_freq_index(priv, BAND_AAC,350						      bss_desc->channel,351						      chan_bw);352 353	return 0;354}355 356static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,357				       struct sk_buff *skb)358{359	struct ieee_types_extcap *extcap;360 361	extcap = skb_put(skb, sizeof(struct ieee_types_extcap));362	extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;363	extcap->ieee_hdr.len = 8;364	memset(extcap->ext_capab, 0, 8);365	extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;366	extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH;367 368	if (priv->adapter->is_hw_11ac_capable)369		extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED;370}371 372static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)373{374	u8 *pos = skb_put(skb, 3);375 376	*pos++ = WLAN_EID_QOS_CAPA;377	*pos++ = 1;378	*pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;379}380 381static void382mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb)383{384	struct ieee80211_wmm_param_ie *wmm;385	u8 ac_vi[] = {0x42, 0x43, 0x5e, 0x00};386	u8 ac_vo[] = {0x62, 0x32, 0x2f, 0x00};387	u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00};388	u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00};389 390	wmm = skb_put_zero(skb, sizeof(*wmm));391 392	wmm->element_id = WLAN_EID_VENDOR_SPECIFIC;393	wmm->len = sizeof(*wmm) - 2;394	wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */395	wmm->oui[1] = 0x50;396	wmm->oui[2] = 0xf2;397	wmm->oui_type = 2; /* WME */398	wmm->oui_subtype = 1; /* WME param */399	wmm->version = 1; /* WME ver */400	wmm->qos_info = 0; /* U-APSD not in use */401 402	/* use default WMM AC parameters for TDLS link*/403	memcpy(&wmm->ac[0], ac_be, sizeof(ac_be));404	memcpy(&wmm->ac[1], ac_bk, sizeof(ac_bk));405	memcpy(&wmm->ac[2], ac_vi, sizeof(ac_vi));406	memcpy(&wmm->ac[3], ac_vo, sizeof(ac_vo));407}408 409static void410mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb,411			u8 qosinfo)412{413	u8 *buf;414 415	buf = skb_put(skb,416		      MWIFIEX_TDLS_WMM_INFO_SIZE + sizeof(struct ieee_types_header));417 418	*buf++ = WLAN_EID_VENDOR_SPECIFIC;419	*buf++ = 7; /* len */420	*buf++ = 0x00; /* Microsoft OUI 00:50:F2 */421	*buf++ = 0x50;422	*buf++ = 0xf2;423	*buf++ = 2; /* WME */424	*buf++ = 0; /* WME info */425	*buf++ = 1; /* WME ver */426	*buf++ = qosinfo; /* U-APSD no in use */427}428 429static void mwifiex_tdls_add_bss_co_2040(struct sk_buff *skb)430{431	struct ieee_types_bss_co_2040 *bssco;432 433	bssco = skb_put(skb, sizeof(struct ieee_types_bss_co_2040));434	bssco->ieee_hdr.element_id = WLAN_EID_BSS_COEX_2040;435	bssco->ieee_hdr.len = sizeof(struct ieee_types_bss_co_2040) -436			      sizeof(struct ieee_types_header);437	bssco->bss_2040co = 0x01;438}439 440static void mwifiex_tdls_add_supported_chan(struct sk_buff *skb)441{442	struct ieee_types_generic *supp_chan;443	u8 chan_supp[] = {1, 11};444 445	supp_chan = skb_put(skb,446			    (sizeof(struct ieee_types_header) + sizeof(chan_supp)));447	supp_chan->ieee_hdr.element_id = WLAN_EID_SUPPORTED_CHANNELS;448	supp_chan->ieee_hdr.len = sizeof(chan_supp);449	memcpy(supp_chan->data, chan_supp, sizeof(chan_supp));450}451 452static void mwifiex_tdls_add_oper_class(struct sk_buff *skb)453{454	struct ieee_types_generic *reg_class;455	u8 rc_list[] = {1,456		1, 2, 3, 4, 12, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33};457	reg_class = skb_put(skb,458			    (sizeof(struct ieee_types_header) + sizeof(rc_list)));459	reg_class->ieee_hdr.element_id = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;460	reg_class->ieee_hdr.len = sizeof(rc_list);461	memcpy(reg_class->data, rc_list, sizeof(rc_list));462}463 464static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,465					const u8 *peer, u8 action_code,466					u8 dialog_token,467					u16 status_code, struct sk_buff *skb)468{469	struct ieee80211_tdls_data *tf;470	int ret;471	u16 capab;472	struct ieee80211_ht_cap *ht_cap;473	u8 radio, *pos;474 475	capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;476 477	tf = skb_put(skb, offsetof(struct ieee80211_tdls_data, u));478	memcpy(tf->da, peer, ETH_ALEN);479	memcpy(tf->sa, priv->curr_addr, ETH_ALEN);480	tf->ether_type = cpu_to_be16(ETH_P_TDLS);481	tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;482 483	switch (action_code) {484	case WLAN_TDLS_SETUP_REQUEST:485		tf->category = WLAN_CATEGORY_TDLS;486		tf->action_code = WLAN_TDLS_SETUP_REQUEST;487		skb_put(skb, sizeof(tf->u.setup_req));488		tf->u.setup_req.dialog_token = dialog_token;489		tf->u.setup_req.capability = cpu_to_le16(capab);490		ret = mwifiex_tdls_append_rates_ie(priv, skb);491		if (ret) {492			dev_kfree_skb_any(skb);493			return ret;494		}495 496		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);497		*pos++ = WLAN_EID_HT_CAPABILITY;498		*pos++ = sizeof(struct ieee80211_ht_cap);499		ht_cap = (void *)pos;500		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);501		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);502		if (ret) {503			dev_kfree_skb_any(skb);504			return ret;505		}506 507		if (priv->adapter->is_hw_11ac_capable) {508			ret = mwifiex_tdls_add_vht_capab(priv, skb);509			if (ret) {510				dev_kfree_skb_any(skb);511				return ret;512			}513			mwifiex_tdls_add_aid(priv, skb);514		}515 516		mwifiex_tdls_add_ext_capab(priv, skb);517		mwifiex_tdls_add_bss_co_2040(skb);518		mwifiex_tdls_add_supported_chan(skb);519		mwifiex_tdls_add_oper_class(skb);520		mwifiex_add_wmm_info_ie(priv, skb, 0);521		break;522 523	case WLAN_TDLS_SETUP_RESPONSE:524		tf->category = WLAN_CATEGORY_TDLS;525		tf->action_code = WLAN_TDLS_SETUP_RESPONSE;526		skb_put(skb, sizeof(tf->u.setup_resp));527		tf->u.setup_resp.status_code = cpu_to_le16(status_code);528		tf->u.setup_resp.dialog_token = dialog_token;529		tf->u.setup_resp.capability = cpu_to_le16(capab);530		ret = mwifiex_tdls_append_rates_ie(priv, skb);531		if (ret) {532			dev_kfree_skb_any(skb);533			return ret;534		}535 536		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);537		*pos++ = WLAN_EID_HT_CAPABILITY;538		*pos++ = sizeof(struct ieee80211_ht_cap);539		ht_cap = (void *)pos;540		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);541		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);542		if (ret) {543			dev_kfree_skb_any(skb);544			return ret;545		}546 547		if (priv->adapter->is_hw_11ac_capable) {548			ret = mwifiex_tdls_add_vht_capab(priv, skb);549			if (ret) {550				dev_kfree_skb_any(skb);551				return ret;552			}553			mwifiex_tdls_add_aid(priv, skb);554		}555 556		mwifiex_tdls_add_ext_capab(priv, skb);557		mwifiex_tdls_add_bss_co_2040(skb);558		mwifiex_tdls_add_supported_chan(skb);559		mwifiex_tdls_add_oper_class(skb);560		mwifiex_add_wmm_info_ie(priv, skb, 0);561		break;562 563	case WLAN_TDLS_SETUP_CONFIRM:564		tf->category = WLAN_CATEGORY_TDLS;565		tf->action_code = WLAN_TDLS_SETUP_CONFIRM;566		skb_put(skb, sizeof(tf->u.setup_cfm));567		tf->u.setup_cfm.status_code = cpu_to_le16(status_code);568		tf->u.setup_cfm.dialog_token = dialog_token;569 570		mwifiex_tdls_add_wmm_param_ie(priv, skb);571		if (priv->adapter->is_hw_11ac_capable) {572			ret = mwifiex_tdls_add_vht_oper(priv, peer, skb);573			if (ret) {574				dev_kfree_skb_any(skb);575				return ret;576			}577			ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb);578			if (ret) {579				dev_kfree_skb_any(skb);580				return ret;581			}582		} else {583			ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb);584			if (ret) {585				dev_kfree_skb_any(skb);586				return ret;587			}588		}589		break;590 591	case WLAN_TDLS_TEARDOWN:592		tf->category = WLAN_CATEGORY_TDLS;593		tf->action_code = WLAN_TDLS_TEARDOWN;594		skb_put(skb, sizeof(tf->u.teardown));595		tf->u.teardown.reason_code = cpu_to_le16(status_code);596		break;597 598	case WLAN_TDLS_DISCOVERY_REQUEST:599		tf->category = WLAN_CATEGORY_TDLS;600		tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;601		skb_put(skb, sizeof(tf->u.discover_req));602		tf->u.discover_req.dialog_token = dialog_token;603		break;604	default:605		mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");606		return -EINVAL;607	}608 609	return 0;610}611 612static void613mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,614			 const u8 *peer, const u8 *bssid)615{616	struct ieee80211_tdls_lnkie *lnkid;617 618	lnkid = skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));619	lnkid->ie_type = WLAN_EID_LINK_ID;620	lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -621			sizeof(struct ieee_types_header);622 623	memcpy(lnkid->bssid, bssid, ETH_ALEN);624	memcpy(lnkid->init_sta, src_addr, ETH_ALEN);625	memcpy(lnkid->resp_sta, peer, ETH_ALEN);626}627 628int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,629				 u8 action_code, u8 dialog_token,630				 u16 status_code, const u8 *extra_ies,631				 size_t extra_ies_len)632{633	struct sk_buff *skb;634	struct mwifiex_txinfo *tx_info;635	int ret;636	u16 skb_len;637 638	skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +639		  max(sizeof(struct ieee80211_mgmt),640		      sizeof(struct ieee80211_tdls_data)) +641		  MWIFIEX_MGMT_FRAME_HEADER_SIZE +642		  MWIFIEX_SUPPORTED_RATES +643		  3 + /* Qos Info */644		  sizeof(struct ieee_types_extcap) +645		  sizeof(struct ieee80211_ht_cap) +646		  sizeof(struct ieee_types_bss_co_2040) +647		  sizeof(struct ieee80211_ht_operation) +648		  sizeof(struct ieee80211_tdls_lnkie) +649		  (2 * (sizeof(struct ieee_types_header))) +650		   MWIFIEX_SUPPORTED_CHANNELS +651		   MWIFIEX_OPERATING_CLASSES +652		  sizeof(struct ieee80211_wmm_param_ie) +653		  extra_ies_len;654 655	if (priv->adapter->is_hw_11ac_capable)656		skb_len += sizeof(struct ieee_types_vht_cap) +657			   sizeof(struct ieee_types_vht_oper) +658			   sizeof(struct ieee_types_aid);659 660	skb = dev_alloc_skb(skb_len);661	if (!skb) {662		mwifiex_dbg(priv->adapter, ERROR,663			    "allocate skb failed for management frame\n");664		return -ENOMEM;665	}666	skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);667 668	switch (action_code) {669	case WLAN_TDLS_SETUP_REQUEST:670	case WLAN_TDLS_SETUP_CONFIRM:671	case WLAN_TDLS_TEARDOWN:672	case WLAN_TDLS_DISCOVERY_REQUEST:673		ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,674						   dialog_token, status_code,675						   skb);676		if (ret) {677			dev_kfree_skb_any(skb);678			return ret;679		}680		if (extra_ies_len)681			skb_put_data(skb, extra_ies, extra_ies_len);682		mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,683					 priv->cfg_bssid);684		break;685	case WLAN_TDLS_SETUP_RESPONSE:686		ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,687						   dialog_token, status_code,688						   skb);689		if (ret) {690			dev_kfree_skb_any(skb);691			return ret;692		}693		if (extra_ies_len)694			skb_put_data(skb, extra_ies, extra_ies_len);695		mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,696					 priv->cfg_bssid);697		break;698	}699 700	switch (action_code) {701	case WLAN_TDLS_SETUP_REQUEST:702	case WLAN_TDLS_SETUP_RESPONSE:703		skb->priority = MWIFIEX_PRIO_BK;704		break;705	default:706		skb->priority = MWIFIEX_PRIO_VI;707		break;708	}709 710	tx_info = MWIFIEX_SKB_TXCB(skb);711	memset(tx_info, 0, sizeof(*tx_info));712	tx_info->bss_num = priv->bss_num;713	tx_info->bss_type = priv->bss_type;714 715	__net_timestamp(skb);716	mwifiex_queue_tx_pkt(priv, skb);717 718	/* Delay 10ms to make sure tdls setup confirm/teardown frame719	 * is received by peer720	*/721	if (action_code == WLAN_TDLS_SETUP_CONFIRM ||722	    action_code == WLAN_TDLS_TEARDOWN)723		msleep_interruptible(10);724 725	return 0;726}727 728static int729mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,730				    const u8 *peer,731				    u8 action_code, u8 dialog_token,732				    u16 status_code, struct sk_buff *skb)733{734	struct ieee80211_mgmt *mgmt;735	int ret;736	u16 capab;737	struct ieee80211_ht_cap *ht_cap;738	unsigned int extra;739	u8 radio, *pos;740 741	capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;742 743	mgmt = skb_put(skb, offsetof(struct ieee80211_mgmt, u));744 745	memset(mgmt, 0, 24);746	memcpy(mgmt->da, peer, ETH_ALEN);747	memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);748	memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);749	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |750					  IEEE80211_STYPE_ACTION);751 752	/* add address 4 */753	pos = skb_put(skb, ETH_ALEN);754 755	switch (action_code) {756	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:757		/* See the layout of 'struct ieee80211_mgmt'. */758		extra = sizeof(mgmt->u.action.u.tdls_discover_resp) +759			sizeof(mgmt->u.action.category);760		skb_put(skb, extra);761		mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;762		mgmt->u.action.u.tdls_discover_resp.action_code =763					      WLAN_PUB_ACTION_TDLS_DISCOVER_RES;764		mgmt->u.action.u.tdls_discover_resp.dialog_token =765								   dialog_token;766		mgmt->u.action.u.tdls_discover_resp.capability =767							     cpu_to_le16(capab);768		/* move back for addr4 */769		memmove(pos + ETH_ALEN, &mgmt->u.action, extra);770		/* init address 4 */771		eth_broadcast_addr(pos);772 773		ret = mwifiex_tdls_append_rates_ie(priv, skb);774		if (ret) {775			dev_kfree_skb_any(skb);776			return ret;777		}778 779		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);780		*pos++ = WLAN_EID_HT_CAPABILITY;781		*pos++ = sizeof(struct ieee80211_ht_cap);782		ht_cap = (void *)pos;783		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);784		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);785		if (ret) {786			dev_kfree_skb_any(skb);787			return ret;788		}789 790		if (priv->adapter->is_hw_11ac_capable) {791			ret = mwifiex_tdls_add_vht_capab(priv, skb);792			if (ret) {793				dev_kfree_skb_any(skb);794				return ret;795			}796			mwifiex_tdls_add_aid(priv, skb);797		}798 799		mwifiex_tdls_add_ext_capab(priv, skb);800		mwifiex_tdls_add_bss_co_2040(skb);801		mwifiex_tdls_add_supported_chan(skb);802		mwifiex_tdls_add_qos_capab(skb);803		mwifiex_tdls_add_oper_class(skb);804		break;805	default:806		mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n");807		return -EINVAL;808	}809 810	return 0;811}812 813int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,814				   u8 action_code, u8 dialog_token,815				   u16 status_code, const u8 *extra_ies,816				   size_t extra_ies_len)817{818	struct sk_buff *skb;819	struct mwifiex_txinfo *tx_info;820	u8 *pos;821	u32 pkt_type, tx_control;822	u16 pkt_len, skb_len;823 824	skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +825		  max(sizeof(struct ieee80211_mgmt),826		      sizeof(struct ieee80211_tdls_data)) +827		  MWIFIEX_MGMT_FRAME_HEADER_SIZE +828		  MWIFIEX_SUPPORTED_RATES +829		  sizeof(struct ieee_types_extcap) +830		  sizeof(struct ieee80211_ht_cap) +831		  sizeof(struct ieee_types_bss_co_2040) +832		  sizeof(struct ieee80211_ht_operation) +833		  sizeof(struct ieee80211_tdls_lnkie) +834		  extra_ies_len +835		  3 + /* Qos Info */836		  ETH_ALEN; /* Address4 */837 838	if (priv->adapter->is_hw_11ac_capable)839		skb_len += sizeof(struct ieee_types_vht_cap) +840			   sizeof(struct ieee_types_vht_oper) +841			   sizeof(struct ieee_types_aid);842 843	skb = dev_alloc_skb(skb_len);844	if (!skb) {845		mwifiex_dbg(priv->adapter, ERROR,846			    "allocate skb failed for management frame\n");847		return -ENOMEM;848	}849 850	skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);851 852	pkt_type = PKT_TYPE_MGMT;853	tx_control = 0;854	pos = skb_put_zero(skb,855			   MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));856	memcpy(pos, &pkt_type, sizeof(pkt_type));857	memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));858 859	if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,860						dialog_token, status_code,861						skb)) {862		dev_kfree_skb_any(skb);863		return -EINVAL;864	}865 866	if (extra_ies_len)867		skb_put_data(skb, extra_ies, extra_ies_len);868 869	/* the TDLS link IE is always added last we are the responder */870 871	mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,872				 priv->cfg_bssid);873 874	skb->priority = MWIFIEX_PRIO_VI;875 876	tx_info = MWIFIEX_SKB_TXCB(skb);877	memset(tx_info, 0, sizeof(*tx_info));878	tx_info->bss_num = priv->bss_num;879	tx_info->bss_type = priv->bss_type;880	tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;881 882	pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);883	memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,884	       sizeof(pkt_len));885	__net_timestamp(skb);886	mwifiex_queue_tx_pkt(priv, skb);887 888	return 0;889}890 891/* This function process tdls action frame from peer.892 * Peer capabilities are stored into station node structure.893 */894void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,895				       u8 *buf, int len)896{897	struct mwifiex_sta_node *sta_ptr;898	u8 *peer, *pos, *end;899	u8 i, action, basic;900	u16 cap = 0;901	int ies_len = 0;902 903	if (len < (sizeof(struct ethhdr) + 3))904		return;905	if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)906		return;907	if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)908		return;909 910	peer = buf + ETH_ALEN;911	action = *(buf + sizeof(struct ethhdr) + 2);912	mwifiex_dbg(priv->adapter, DATA,913		    "rx:tdls action: peer=%pM, action=%d\n", peer, action);914 915	switch (action) {916	case WLAN_TDLS_SETUP_REQUEST:917		if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))918			return;919 920		pos = buf + sizeof(struct ethhdr) + 4;921		/* payload 1+ category 1 + action 1 + dialog 1 */922		cap = get_unaligned_le16(pos);923		ies_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;924		pos += 2;925		break;926 927	case WLAN_TDLS_SETUP_RESPONSE:928		if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))929			return;930		/* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/931		pos = buf + sizeof(struct ethhdr) + 6;932		cap = get_unaligned_le16(pos);933		ies_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;934		pos += 2;935		break;936 937	case WLAN_TDLS_SETUP_CONFIRM:938		if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))939			return;940		pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;941		ies_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;942		break;943	default:944		mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");945		return;946	}947 948	sta_ptr = mwifiex_add_sta_entry(priv, peer);949	if (!sta_ptr)950		return;951 952	sta_ptr->tdls_cap.capab = cpu_to_le16(cap);953 954	for (end = pos + ies_len; pos + 1 < end; pos += 2 + pos[1]) {955		u8 ie_len = pos[1];956 957		if (pos + 2 + ie_len > end)958			break;959 960		switch (*pos) {961		case WLAN_EID_SUPP_RATES:962			if (ie_len > sizeof(sta_ptr->tdls_cap.rates))963				return;964			sta_ptr->tdls_cap.rates_len = ie_len;965			for (i = 0; i < ie_len; i++)966				sta_ptr->tdls_cap.rates[i] = pos[i + 2];967			break;968 969		case WLAN_EID_EXT_SUPP_RATES:970			if (ie_len > sizeof(sta_ptr->tdls_cap.rates))971				return;972			basic = sta_ptr->tdls_cap.rates_len;973			if (ie_len > sizeof(sta_ptr->tdls_cap.rates) - basic)974				return;975			for (i = 0; i < ie_len; i++)976				sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];977			sta_ptr->tdls_cap.rates_len += ie_len;978			break;979		case WLAN_EID_HT_CAPABILITY:980			if (ie_len != sizeof(struct ieee80211_ht_cap))981				return;982			/* copy the ie's value into ht_capb*/983			memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2,984			       sizeof(struct ieee80211_ht_cap));985			sta_ptr->is_11n_enabled = 1;986			break;987		case WLAN_EID_HT_OPERATION:988			if (ie_len != sizeof(struct ieee80211_ht_operation))989				return;990			/* copy the ie's value into ht_oper*/991			memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2,992			       sizeof(struct ieee80211_ht_operation));993			break;994		case WLAN_EID_BSS_COEX_2040:995			if (ie_len != sizeof(pos[2]))996				return;997			sta_ptr->tdls_cap.coex_2040 = pos[2];998			break;999		case WLAN_EID_EXT_CAPABILITY:1000			if (ie_len < sizeof(struct ieee_types_header))1001				return;1002			if (ie_len > 8)1003				return;1004			memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,1005			       sizeof(struct ieee_types_header) +1006			       min_t(u8, ie_len, 8));1007			break;1008		case WLAN_EID_RSN:1009			if (ie_len < sizeof(struct ieee_types_header))1010				return;1011			if (ie_len > IEEE_MAX_IE_SIZE -1012			    sizeof(struct ieee_types_header))1013				return;1014			memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,1015			       sizeof(struct ieee_types_header) +1016			       min_t(u8, ie_len, IEEE_MAX_IE_SIZE -1017				     sizeof(struct ieee_types_header)));1018			break;1019		case WLAN_EID_QOS_CAPA:1020			if (ie_len != sizeof(pos[2]))1021				return;1022			sta_ptr->tdls_cap.qos_info = pos[2];1023			break;1024		case WLAN_EID_VHT_OPERATION:1025			if (priv->adapter->is_hw_11ac_capable) {1026				if (ie_len !=1027				    sizeof(struct ieee80211_vht_operation))1028					return;1029				/* copy the ie's value into vhtoper*/1030				memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2,1031				       sizeof(struct ieee80211_vht_operation));1032			}1033			break;1034		case WLAN_EID_VHT_CAPABILITY:1035			if (priv->adapter->is_hw_11ac_capable) {1036				if (ie_len != sizeof(struct ieee80211_vht_cap))1037					return;1038				/* copy the ie's value into vhtcap*/1039				memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2,1040				       sizeof(struct ieee80211_vht_cap));1041				sta_ptr->is_11ac_enabled = 1;1042			}1043			break;1044		case WLAN_EID_AID:1045			if (priv->adapter->is_hw_11ac_capable) {1046				if (ie_len != sizeof(u16))1047					return;1048				sta_ptr->tdls_cap.aid =1049					get_unaligned_le16((pos + 2));1050			}1051			break;1052		default:1053			break;1054		}1055	}1056 1057	return;1058}1059 1060static int1061mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)1062{1063	struct mwifiex_sta_node *sta_ptr;1064	struct mwifiex_ds_tdls_oper tdls_oper;1065 1066	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));1067	sta_ptr = mwifiex_get_sta_entry(priv, peer);1068 1069	if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {1070		mwifiex_dbg(priv->adapter, ERROR,1071			    "link absent for peer %pM; cannot config\n", peer);1072		return -EINVAL;1073	}1074 1075	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);1076	tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;1077	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,1078				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);1079}1080 1081static int1082mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)1083{1084	struct mwifiex_sta_node *sta_ptr;1085	struct mwifiex_ds_tdls_oper tdls_oper;1086 1087	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));1088	sta_ptr = mwifiex_get_sta_entry(priv, peer);1089 1090	if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {1091		mwifiex_dbg(priv->adapter, WARN,1092			    "Setup already in progress for peer %pM\n", peer);1093		return 0;1094	}1095 1096	sta_ptr = mwifiex_add_sta_entry(priv, peer);1097	if (!sta_ptr)1098		return -ENOMEM;1099 1100	sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;1101	mwifiex_hold_tdls_packets(priv, peer);1102	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);1103	tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;1104	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,1105				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);1106}1107 1108static int1109mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)1110{1111	struct mwifiex_sta_node *sta_ptr;1112	struct mwifiex_ds_tdls_oper tdls_oper;1113 1114	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));1115	sta_ptr = mwifiex_get_sta_entry(priv, peer);1116 1117	if (sta_ptr) {1118		if (sta_ptr->is_11n_enabled) {1119			mwifiex_11n_cleanup_reorder_tbl(priv);1120			spin_lock_bh(&priv->wmm.ra_list_spinlock);1121			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);1122			spin_unlock_bh(&priv->wmm.ra_list_spinlock);1123		}1124		mwifiex_del_sta_entry(priv, peer);1125	}1126 1127	mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);1128	mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP);1129	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);1130	tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;1131	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,1132				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);1133}1134 1135static int1136mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)1137{1138	struct mwifiex_sta_node *sta_ptr;1139	struct ieee80211_mcs_info mcs;1140	int i;1141 1142	sta_ptr = mwifiex_get_sta_entry(priv, peer);1143 1144	if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {1145		mwifiex_dbg(priv->adapter, MSG,1146			    "tdls: enable link %pM success\n", peer);1147 1148		sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;1149 1150		mcs = sta_ptr->tdls_cap.ht_capb.mcs;1151		if (mcs.rx_mask[0] != 0xff)1152			sta_ptr->is_11n_enabled = true;1153		if (sta_ptr->is_11n_enabled) {1154			if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &1155			    IEEE80211_HT_CAP_MAX_AMSDU)1156				sta_ptr->max_amsdu =1157					MWIFIEX_TX_DATA_BUF_SIZE_8K;1158			else1159				sta_ptr->max_amsdu =1160					MWIFIEX_TX_DATA_BUF_SIZE_4K;1161 1162			for (i = 0; i < MAX_NUM_TID; i++)1163				sta_ptr->ampdu_sta[i] =1164					      priv->aggr_prio_tbl[i].ampdu_user;1165		} else {1166			for (i = 0; i < MAX_NUM_TID; i++)1167				sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;1168		}1169		if (sta_ptr->tdls_cap.extcap.ext_capab[3] &1170		    WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) {1171			mwifiex_config_tdls_enable(priv);1172			mwifiex_config_tdls_cs_params(priv);1173		}1174 1175		memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));1176		mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);1177		mwifiex_auto_tdls_update_peer_status(priv, peer,1178						     TDLS_SETUP_COMPLETE);1179	} else {1180		mwifiex_dbg(priv->adapter, ERROR,1181			    "tdls: enable link %pM failed\n", peer);1182		if (sta_ptr) {1183			mwifiex_11n_cleanup_reorder_tbl(priv);1184			spin_lock_bh(&priv->wmm.ra_list_spinlock);1185			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);1186			spin_unlock_bh(&priv->wmm.ra_list_spinlock);1187			mwifiex_del_sta_entry(priv, peer);1188		}1189		mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);1190		mwifiex_auto_tdls_update_peer_status(priv, peer,1191						     TDLS_NOT_SETUP);1192 1193		return -1;1194	}1195 1196	return 0;1197}1198 1199int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action)1200{1201	switch (action) {1202	case MWIFIEX_TDLS_ENABLE_LINK:1203		return mwifiex_tdls_process_enable_link(priv, peer);1204	case MWIFIEX_TDLS_DISABLE_LINK:1205		return mwifiex_tdls_process_disable_link(priv, peer);1206	case MWIFIEX_TDLS_CREATE_LINK:1207		return mwifiex_tdls_process_create_link(priv, peer);1208	case MWIFIEX_TDLS_CONFIG_LINK:1209		return mwifiex_tdls_process_config_link(priv, peer);1210	}1211	return 0;1212}1213 1214int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)1215{1216	struct mwifiex_sta_node *sta_ptr;1217 1218	sta_ptr = mwifiex_get_sta_entry(priv, mac);1219	if (sta_ptr)1220		return sta_ptr->tdls_status;1221 1222	return TDLS_NOT_SETUP;1223}1224 1225int mwifiex_get_tdls_list(struct mwifiex_private *priv,1226			  struct tdls_peer_info *buf)1227{1228	struct mwifiex_sta_node *sta_ptr;1229	struct tdls_peer_info *peer = buf;1230	int count = 0;1231 1232	if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))1233		return 0;1234 1235	/* make sure we are in station mode and connected */1236	if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))1237		return 0;1238 1239	spin_lock_bh(&priv->sta_list_spinlock);1240	list_for_each_entry(sta_ptr, &priv->sta_list, list) {1241		if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) {1242			ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr);1243			peer++;1244			count++;1245			if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED)1246				break;1247		}1248	}1249	spin_unlock_bh(&priv->sta_list_spinlock);1250 1251	return count;1252}1253 1254void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)1255{1256	struct mwifiex_sta_node *sta_ptr;1257	struct mwifiex_ds_tdls_oper tdls_oper;1258 1259	if (list_empty(&priv->sta_list))1260		return;1261 1262	list_for_each_entry(sta_ptr, &priv->sta_list, list) {1263		memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));1264 1265		if (sta_ptr->is_11n_enabled) {1266			mwifiex_11n_cleanup_reorder_tbl(priv);1267			spin_lock_bh(&priv->wmm.ra_list_spinlock);1268			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);1269			spin_unlock_bh(&priv->wmm.ra_list_spinlock);1270		}1271 1272		mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,1273					     TDLS_LINK_TEARDOWN);1274		memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);1275		tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;1276		if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,1277				     HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))1278			mwifiex_dbg(priv->adapter, ERROR,1279				    "Disable link failed for TDLS peer %pM",1280				    sta_ptr->mac_addr);1281	}1282 1283	mwifiex_del_all_sta_list(priv);1284}1285 1286int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)1287{1288	struct mwifiex_auto_tdls_peer *peer;1289	u8 mac[ETH_ALEN];1290 1291	ether_addr_copy(mac, skb->data);1292 1293	spin_lock_bh(&priv->auto_tdls_lock);1294	list_for_each_entry(peer, &priv->auto_tdls_list, list) {1295		if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) {1296			if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&1297			    peer->tdls_status == TDLS_NOT_SETUP &&1298			    (peer->failure_count <1299			     MWIFIEX_TDLS_MAX_FAIL_COUNT)) {1300				peer->tdls_status = TDLS_SETUP_INPROGRESS;1301				mwifiex_dbg(priv->adapter, INFO,1302					    "setup TDLS link, peer=%pM rssi=%d\n",1303					    peer->mac_addr, peer->rssi);1304 1305				cfg80211_tdls_oper_request(priv->netdev,1306							   peer->mac_addr,1307							   NL80211_TDLS_SETUP,1308							   0, GFP_ATOMIC);1309				peer->do_setup = false;1310				priv->check_tdls_tx = false;1311			} else if (peer->failure_count <1312				   MWIFIEX_TDLS_MAX_FAIL_COUNT &&1313				   peer->do_discover) {1314				mwifiex_send_tdls_data_frame(priv,1315							     peer->mac_addr,1316						    WLAN_TDLS_DISCOVERY_REQUEST,1317							     1, 0, NULL, 0);1318				peer->do_discover = false;1319			}1320		}1321	}1322	spin_unlock_bh(&priv->auto_tdls_lock);1323 1324	return 0;1325}1326 1327void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv)1328{1329	struct mwifiex_auto_tdls_peer *peer, *tmp_node;1330 1331	spin_lock_bh(&priv->auto_tdls_lock);1332	list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) {1333		list_del(&peer->list);1334		kfree(peer);1335	}1336 1337	INIT_LIST_HEAD(&priv->auto_tdls_list);1338	spin_unlock_bh(&priv->auto_tdls_lock);1339	priv->check_tdls_tx = false;1340}1341 1342void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)1343{1344	struct mwifiex_auto_tdls_peer *tdls_peer;1345 1346	if (!priv->adapter->auto_tdls)1347		return;1348 1349	spin_lock_bh(&priv->auto_tdls_lock);1350	list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {1351		if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) {1352			tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;1353			tdls_peer->rssi_jiffies = jiffies;1354			spin_unlock_bh(&priv->auto_tdls_lock);1355			return;1356		}1357	}1358 1359	/* create new TDLS peer */1360	tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC);1361	if (tdls_peer) {1362		ether_addr_copy(tdls_peer->mac_addr, mac);1363		tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;1364		tdls_peer->rssi_jiffies = jiffies;1365		INIT_LIST_HEAD(&tdls_peer->list);1366		list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);1367		mwifiex_dbg(priv->adapter, INFO,1368			    "Add auto TDLS peer= %pM to list\n", mac);1369	}1370 1371	spin_unlock_bh(&priv->auto_tdls_lock);1372}1373 1374void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,1375					  const u8 *mac, u8 link_status)1376{1377	struct mwifiex_auto_tdls_peer *peer;1378 1379	if (!priv->adapter->auto_tdls)1380		return;1381 1382	spin_lock_bh(&priv->auto_tdls_lock);1383	list_for_each_entry(peer, &priv->auto_tdls_list, list) {1384		if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {1385			if ((link_status == TDLS_NOT_SETUP) &&1386			    (peer->tdls_status == TDLS_SETUP_INPROGRESS))1387				peer->failure_count++;1388			else if (mwifiex_is_tdls_link_setup(link_status))1389				peer->failure_count = 0;1390 1391			peer->tdls_status = link_status;1392			break;1393		}1394	}1395	spin_unlock_bh(&priv->auto_tdls_lock);1396}1397 1398void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,1399					  u8 *mac, s8 snr, s8 nflr)1400{1401	struct mwifiex_auto_tdls_peer *peer;1402 1403	if (!priv->adapter->auto_tdls)1404		return;1405 1406	spin_lock_bh(&priv->auto_tdls_lock);1407	list_for_each_entry(peer, &priv->auto_tdls_list, list) {1408		if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {1409			peer->rssi = nflr - snr;1410			peer->rssi_jiffies = jiffies;1411			break;1412		}1413	}1414	spin_unlock_bh(&priv->auto_tdls_lock);1415}1416 1417void mwifiex_check_auto_tdls(struct timer_list *t)1418{1419	struct mwifiex_private *priv = from_timer(priv, t, auto_tdls_timer);1420	struct mwifiex_auto_tdls_peer *tdls_peer;1421	u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;1422 1423	if (WARN_ON_ONCE(!priv || !priv->adapter)) {1424		pr_err("mwifiex: %s: adapter or private structure is NULL\n",1425		       __func__);1426		return;1427	}1428 1429	if (unlikely(!priv->adapter->auto_tdls))1430		return;1431 1432	if (!priv->auto_tdls_timer_active) {1433		mwifiex_dbg(priv->adapter, INFO,1434			    "auto TDLS timer inactive; return");1435		return;1436	}1437 1438	priv->check_tdls_tx = false;1439 1440	spin_lock_bh(&priv->auto_tdls_lock);1441	list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {1442		if (time_after(jiffies, tdls_peer->rssi_jiffies +1443					 MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) {1444			tdls_peer->rssi = 0;1445			tdls_peer->do_discover = true;1446			priv->check_tdls_tx = true;1447		}1448 1449		if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) ||1450		     !tdls_peer->rssi) &&1451		    mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) {1452			tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;1453			mwifiex_dbg(priv->adapter, MSG,1454				    "teardown TDLS link,peer=%pM rssi=%d\n",1455				    tdls_peer->mac_addr, -tdls_peer->rssi);1456			tdls_peer->do_discover = true;1457			priv->check_tdls_tx = true;1458			cfg80211_tdls_oper_request(priv->netdev,1459						   tdls_peer->mac_addr,1460						   NL80211_TDLS_TEARDOWN,1461						   reason, GFP_ATOMIC);1462		} else if (tdls_peer->rssi &&1463			   tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&1464			   tdls_peer->tdls_status == TDLS_NOT_SETUP &&1465			   tdls_peer->failure_count <1466			   MWIFIEX_TDLS_MAX_FAIL_COUNT) {1467				priv->check_tdls_tx = true;1468				tdls_peer->do_setup = true;1469				mwifiex_dbg(priv->adapter, INFO,1470					    "check TDLS with peer=%pM\t"1471					    "rssi=%d\n", tdls_peer->mac_addr,1472					    tdls_peer->rssi);1473		}1474	}1475	spin_unlock_bh(&priv->auto_tdls_lock);1476 1477	mod_timer(&priv->auto_tdls_timer,1478		  jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));1479}1480 1481void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv)1482{1483	timer_setup(&priv->auto_tdls_timer, mwifiex_check_auto_tdls, 0);1484	priv->auto_tdls_timer_active = true;1485	mod_timer(&priv->auto_tdls_timer,1486		  jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));1487}1488 1489void mwifiex_clean_auto_tdls(struct mwifiex_private *priv)1490{1491	if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&1492	    priv->adapter->auto_tdls &&1493	    priv->bss_type == MWIFIEX_BSS_TYPE_STA) {1494		priv->auto_tdls_timer_active = false;1495		del_timer(&priv->auto_tdls_timer);1496		mwifiex_flush_auto_tdls_list(priv);1497	}1498}1499 1500static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable)1501{1502	struct mwifiex_tdls_config config;1503 1504	config.enable = cpu_to_le16(enable);1505	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,1506				ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true);1507}1508 1509int mwifiex_config_tdls_enable(struct mwifiex_private *priv)1510{1511	return mwifiex_config_tdls(priv, true);1512}1513 1514int mwifiex_config_tdls_disable(struct mwifiex_private *priv)1515{1516	return mwifiex_config_tdls(priv, false);1517}1518 1519int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv)1520{1521	struct mwifiex_tdls_config_cs_params config_tdls_cs_params;1522 1523	config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME;1524	config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK;1525	config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK;1526 1527	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,1528				ACT_TDLS_CS_PARAMS, 0,1529				&config_tdls_cs_params, true);1530}1531 1532int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac)1533{1534	struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params;1535 1536	ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac);1537 1538	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,1539				ACT_TDLS_CS_STOP, 0,1540				&stop_tdls_cs_params, true);1541}1542 1543int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac,1544			  u8 primary_chan, u8 second_chan_offset, u8 band)1545{1546	struct mwifiex_tdls_init_cs_params start_tdls_cs_params;1547 1548	ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac);1549	start_tdls_cs_params.primary_chan = primary_chan;1550	start_tdls_cs_params.second_chan_offset = second_chan_offset;1551	start_tdls_cs_params.band = band;1552 1553	start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME);1554	start_tdls_cs_params.switch_timeout =1555					cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT);1556	start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS;1557	start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY;1558 1559	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,1560				ACT_TDLS_CS_INIT, 0,1561				&start_tdls_cs_params, true);1562}1563