[go: nahoru, domu]

1b23bce296568011b76c27103032dea5a90291d8aAvinash Patil/* Marvell Wireless LAN device driver: TDLS handling
2b23bce296568011b76c27103032dea5a90291d8aAvinash Patil *
3b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * Copyright (C) 2014, Marvell International Ltd.
4b23bce296568011b76c27103032dea5a90291d8aAvinash Patil *
5b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * This software file (the "File") is distributed by Marvell International
6b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * Ltd. under the terms of the GNU General Public License Version 2, June 1991
7b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * (the "License").  You may use, redistribute and/or modify this File in
8b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * accordance with the terms and conditions of the License, a copy of which
9b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * is available on the worldwide web at
10b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
11b23bce296568011b76c27103032dea5a90291d8aAvinash Patil *
12b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
13b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
14b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
15b23bce296568011b76c27103032dea5a90291d8aAvinash Patil * this warranty disclaimer.
16b23bce296568011b76c27103032dea5a90291d8aAvinash Patil */
17b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
18b23bce296568011b76c27103032dea5a90291d8aAvinash Patil#include "main.h"
195f2caaf32bc64c200007611505ce2453f4862276Avinash Patil#include "wmm.h"
20429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil#include "11n.h"
21429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil#include "11n_rxreorder.h"
225f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil#include "11ac.h"
235f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
245f2caaf32bc64c200007611505ce2453f4862276Avinash Patil#define TDLS_REQ_FIX_LEN      6
255f2caaf32bc64c200007611505ce2453f4862276Avinash Patil#define TDLS_RESP_FIX_LEN     8
265f2caaf32bc64c200007611505ce2453f4862276Avinash Patil#define TDLS_CONFIRM_FIX_LEN  6
27b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
283b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergstatic void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
293b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg					 const u8 *mac, u8 status)
3056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil{
3156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct mwifiex_ra_list_tbl *ra_list;
3256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct list_head *tid_list;
3356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct sk_buff *skb, *tmp;
3456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct mwifiex_txinfo *tx_info;
3556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	unsigned long flags;
3656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	u32 tid;
3756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	u8 tid_down;
3856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
3956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
4056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
4156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
4256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
4356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		if (!ether_addr_equal(mac, skb->data))
4456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			continue;
4556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
4656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		__skb_unlink(skb, &priv->tdls_txq);
4756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		tx_info = MWIFIEX_SKB_TXCB(skb);
4856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		tid = skb->priority;
4956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
5056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
5156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		if (status == TDLS_SETUP_COMPLETE) {
5256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);
53daeb5bb48256d7488246d48453b2315281ce9c75Avinash Patil			ra_list->tdls_link = true;
5456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
5556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		} else {
5656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;
5756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			if (!list_empty(tid_list))
5856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil				ra_list = list_first_entry(tid_list,
5956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					      struct mwifiex_ra_list_tbl, list);
6056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			else
6156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil				ra_list = NULL;
6256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
6356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		}
6456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
6556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		if (!ra_list) {
6656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
6756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			continue;
6856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		}
6956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
7056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		skb_queue_tail(&ra_list->skb_head, skb);
7156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
7256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		ra_list->ba_pkt_count++;
7356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		ra_list->total_pkt_count++;
7456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
7556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		if (atomic_read(&priv->wmm.highest_queued_prio) <
7656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil						       tos_to_tid_inv[tid_down])
7756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			atomic_set(&priv->wmm.highest_queued_prio,
7856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil				   tos_to_tid_inv[tid_down]);
7956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
8056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		atomic_inc(&priv->wmm.tx_pkts_queued);
8156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	}
8256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
8356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
8456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	return;
8556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil}
8656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
873b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergstatic void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
883b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				      const u8 *mac)
8956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil{
9056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct mwifiex_ra_list_tbl *ra_list;
9156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct list_head *ra_list_head;
9256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	struct sk_buff *skb, *tmp;
9356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	unsigned long flags;
9456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	int i;
9556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
9656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
9756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
9856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
9956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	for (i = 0; i < MAX_NUM_TID; i++) {
10056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
10156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
10256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			list_for_each_entry(ra_list, ra_list_head, list) {
10356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil				skb_queue_walk_safe(&ra_list->skb_head, skb,
10456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil						    tmp) {
10556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					if (!ether_addr_equal(mac, skb->data))
10656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil						continue;
10756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					__skb_unlink(skb, &ra_list->skb_head);
10856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					atomic_dec(&priv->wmm.tx_pkts_queued);
10956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					ra_list->total_pkt_count--;
11056bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil					skb_queue_tail(&priv->tdls_txq, skb);
11156bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil				}
11256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil			}
11356bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		}
11456bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	}
11556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
11656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
11756bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	return;
11856bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil}
11956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil
120b23bce296568011b76c27103032dea5a90291d8aAvinash Patil/* This function appends rate TLV to scan config command. */
121b23bce296568011b76c27103032dea5a90291d8aAvinash Patilstatic int
122b23bce296568011b76c27103032dea5a90291d8aAvinash Patilmwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
123b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			     struct sk_buff *skb)
124b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
125b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;
126b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u16 rates_size, supp_rates_size, ext_rates_size;
127b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
128b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memset(rates, 0, sizeof(rates));
129b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	rates_size = mwifiex_get_supported_rates(priv, rates);
130b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
131b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
132b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
133b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (skb_tailroom(skb) < rates_size + 4) {
134b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_err(priv->adapter->dev,
135b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			"Insuffient space while adding rates\n");
136b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -ENOMEM;
137b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
138b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
139b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	pos = skb_put(skb, supp_rates_size + 2);
140b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	*pos++ = WLAN_EID_SUPP_RATES;
141b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	*pos++ = supp_rates_size;
142b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(pos, rates, supp_rates_size);
143b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
144b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {
145b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;
146b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		pos = skb_put(skb, ext_rates_size + 2);
147b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = WLAN_EID_EXT_SUPP_RATES;
148b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = ext_rates_size;
149b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,
150b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		       ext_rates_size);
151b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
152b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
153b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	return 0;
154b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
155b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
1565f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patilstatic void mwifiex_tdls_add_aid(struct mwifiex_private *priv,
1575f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				struct sk_buff *skb)
1585f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil{
1595f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct ieee_types_assoc_rsp *assoc_rsp;
1605f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u8 *pos;
1615f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1625f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf;
1635f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	pos = (void *)skb_put(skb, 4);
1645f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = WLAN_EID_AID;
1655f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = 2;
1665f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = le16_to_cpu(assoc_rsp->a_id);
1675f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1685f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	return;
1695f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil}
1705f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1715f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patilstatic int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,
1725f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				      struct sk_buff *skb)
1735f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil{
1745f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct ieee80211_vht_cap vht_cap;
1755f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u8 *pos;
1765f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1775f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
1785f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = WLAN_EID_VHT_CAPABILITY;
1795f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = sizeof(struct ieee80211_vht_cap);
1805f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1815f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));
1825f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1835f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);
184c42c65c1d5863bca54e45ea25ecb24a3def29f59Dan Carpenter	memcpy(pos, &vht_cap, sizeof(vht_cap));
1855f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
1865f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	return 0;
1875f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil}
1885f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
189396939f94084d5923d558e9f22db48bc51156e47Avinash Patilstatic int
190ef1b075c15d55c71200c63450756a9bb51ce2a60John W. Linvillemwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
191396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			 u8 vht_enabled, struct sk_buff *skb)
192396939f94084d5923d558e9f22db48bc51156e47Avinash Patil{
193396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	struct ieee80211_ht_operation *ht_oper;
194396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	struct mwifiex_sta_node *sta_ptr;
195396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	struct mwifiex_bssdescriptor *bss_desc =
196396939f94084d5923d558e9f22db48bc51156e47Avinash Patil					&priv->curr_bss_params.bss_descriptor;
197396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	u8 *pos;
198396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
199396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, mac);
200396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	if (unlikely(!sta_ptr)) {
201396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		dev_warn(priv->adapter->dev,
202396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			 "TDLS peer station not found in list\n");
203396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		return -1;
204396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	}
205396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
206396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2);
207396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	*pos++ = WLAN_EID_HT_OPERATION;
208396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	*pos++ = sizeof(struct ieee80211_ht_operation);
209396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	ht_oper = (void *)pos;
210396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
211396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	ht_oper->primary_chan = bss_desc->channel;
212396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
213396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	/* follow AP's channel bandwidth */
214396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
215396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	    bss_desc->bcn_ht_cap &&
216396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	    ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
217396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
218396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
219396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	if (vht_enabled) {
220396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		ht_oper->ht_param =
221396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			  mwifiex_get_sec_chan_offset(bss_desc->channel);
222396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		ht_oper->ht_param |= BIT(2);
223396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	}
224396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
225396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper,
226396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	       sizeof(struct ieee80211_ht_operation));
227396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
228396939f94084d5923d558e9f22db48bc51156e47Avinash Patil	return 0;
229396939f94084d5923d558e9f22db48bc51156e47Avinash Patil}
230396939f94084d5923d558e9f22db48bc51156e47Avinash Patil
2315f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patilstatic int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
2323b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				     const u8 *mac, struct sk_buff *skb)
2335f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil{
2345f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct mwifiex_bssdescriptor *bss_desc;
2355f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct ieee80211_vht_operation *vht_oper;
2365f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL;
2375f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct mwifiex_sta_node *sta_ptr;
2385f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	struct mwifiex_adapter *adapter = priv->adapter;
2395f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u8 supp_chwd_set, peer_supp_chwd_set;
2405f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u8 *pos, ap_supp_chwd_set, chan_bw;
2415f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u16 mcs_map_user, mcs_map_resp, mcs_map_result;
2425f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u16 mcs_user, mcs_resp, nss;
2435f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	u32 usr_vht_cap_info;
2445f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2455f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	bss_desc = &priv->curr_bss_params.bss_descriptor;
2465f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2475f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, mac);
2485f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (unlikely(!sta_ptr)) {
2495f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		dev_warn(adapter->dev, "TDLS peer station not found in list\n");
2505f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		return -1;
2515f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
2525f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2535f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (!mwifiex_is_bss_in_11ac_mode(priv)) {
2545f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
2555f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		   WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
2565f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			dev_dbg(adapter->dev,
2575f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				"TDLS peer doesn't support wider bandwitdh\n");
2585f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			return 0;
2595f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		}
2605f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	} else {
2615f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		ap_vht_cap = bss_desc->bcn_vht_cap;
2625f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
2635f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2645f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2);
2655f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = WLAN_EID_VHT_OPERATION;
2665f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	*pos++ = sizeof(struct ieee80211_vht_operation);
2675f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	vht_oper = (struct ieee80211_vht_operation *)pos;
2685f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2695f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (bss_desc->bss_band & BAND_A)
2705f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
2715f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	else
2725f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
2735f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2745f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	/* find the minmum bandwith between AP/TDLS peers */
2755f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	vht_cap = &sta_ptr->tdls_cap.vhtcap;
2765f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
2775f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	peer_supp_chwd_set =
2785f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			 GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info));
2795f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set);
2805f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2815f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	/* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */
2825f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2835f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] &
2845f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	    WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
2855f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		ap_supp_chwd_set =
2865f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		      GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info));
2875f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set);
2885f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
2895f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
2905f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	switch (supp_chwd_set) {
2915f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_80MHZ:
2925f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
2935f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
2945f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_160MHZ:
2955f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
2965f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
2975f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
2985f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
2995f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3005f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	default:
3015f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
3025f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3035f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
3045f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3055f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
3065f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
3075f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	mcs_map_result = 0;
3085f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3095f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	for (nss = 1; nss <= 8; nss++) {
3105f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
3115f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
3125f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3135f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
3145f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		    (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
3155f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			SET_VHTNSSMCS(mcs_map_result, nss,
3165f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				      IEEE80211_VHT_MCS_NOT_SUPPORTED);
3175f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		else
3185f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			SET_VHTNSSMCS(mcs_map_result, nss,
3195f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				      min_t(u16, mcs_user, mcs_resp));
3205f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
3215f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3225f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result);
3235f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3245f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	switch (vht_oper->chan_width) {
3255f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_80MHZ:
3265f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
3275f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3285f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_160MHZ:
3295f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ;
3305f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3315f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
3325f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
3335f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3345f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	default:
3355f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
3365f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		break;
3375f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	}
3385f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	vht_oper->center_freq_seg1_idx =
3395f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			mwifiex_get_center_freq_index(priv, BAND_AAC,
3405f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil						      bss_desc->channel,
3415f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil						      chan_bw);
3425f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3435f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	return 0;
3445f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil}
3455f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3465f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patilstatic void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,
3475f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				       struct sk_buff *skb)
348b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
349b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee_types_extcap *extcap;
350b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
351b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap));
352b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;
353b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	extcap->ieee_hdr.len = 8;
354b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memset(extcap->ext_capab, 0, 8);
355b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;
3565f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
3575f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (priv->adapter->is_hw_11ac_capable)
3585f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED;
359b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
360b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
361b23bce296568011b76c27103032dea5a90291d8aAvinash Patilstatic void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)
362b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
363b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 *pos = (void *)skb_put(skb, 3);
364b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
365b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	*pos++ = WLAN_EID_QOS_CAPA;
366b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	*pos++ = 1;
367b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	*pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;
368b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
369b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
370b23bce296568011b76c27103032dea5a90291d8aAvinash Patilstatic int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
3713b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg					const u8 *peer, u8 action_code,
3723b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg					u8 dialog_token,
3733b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg					u16 status_code, struct sk_buff *skb)
374b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
375b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee80211_tdls_data *tf;
376b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	int ret;
377b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u16 capab;
378b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee80211_ht_cap *ht_cap;
379b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 radio, *pos;
380b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
381b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
382b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
383b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
384b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(tf->da, peer, ETH_ALEN);
385b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(tf->sa, priv->curr_addr, ETH_ALEN);
386b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tf->ether_type = cpu_to_be16(ETH_P_TDLS);
387b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
388b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
389b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	switch (action_code) {
390b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_REQUEST:
391b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->category = WLAN_CATEGORY_TDLS;
392b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->action_code = WLAN_TDLS_SETUP_REQUEST;
393b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(tf->u.setup_req));
394b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_req.dialog_token = dialog_token;
395b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_req.capability = cpu_to_le16(capab);
396b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_tdls_append_rates_ie(priv, skb);
397b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
398b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
399b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
400b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
401b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
402b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
403b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = WLAN_EID_HT_CAPABILITY;
404b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = sizeof(struct ieee80211_ht_cap);
405b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ht_cap = (void *)pos;
406b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
407b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
408b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
409b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
410b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
411b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
412b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
4135f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if (priv->adapter->is_hw_11ac_capable) {
4145f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			ret = mwifiex_tdls_add_vht_capab(priv, skb);
4155f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (ret) {
4165f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				dev_kfree_skb_any(skb);
4175f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				return ret;
4185f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			}
4195f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			mwifiex_tdls_add_aid(priv, skb);
4205f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		}
4215f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
4225f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		mwifiex_tdls_add_ext_capab(priv, skb);
423b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mwifiex_tdls_add_qos_capab(skb);
424b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
425b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
426b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_RESPONSE:
427b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->category = WLAN_CATEGORY_TDLS;
428b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
429b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(tf->u.setup_resp));
430b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_resp.status_code = cpu_to_le16(status_code);
431b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_resp.dialog_token = dialog_token;
432b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_resp.capability = cpu_to_le16(capab);
433b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_tdls_append_rates_ie(priv, skb);
434b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
435b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
436b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
437b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
438b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
439b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
440b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = WLAN_EID_HT_CAPABILITY;
441b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = sizeof(struct ieee80211_ht_cap);
442b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ht_cap = (void *)pos;
443b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
444b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
445b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
446b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
447b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
448b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
449b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
4505f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if (priv->adapter->is_hw_11ac_capable) {
4515f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			ret = mwifiex_tdls_add_vht_capab(priv, skb);
4525f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (ret) {
4535f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				dev_kfree_skb_any(skb);
4545f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				return ret;
4555f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			}
4565f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			mwifiex_tdls_add_aid(priv, skb);
4575f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		}
4585f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
4595f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		mwifiex_tdls_add_ext_capab(priv, skb);
460b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mwifiex_tdls_add_qos_capab(skb);
461b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
462b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
463b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_CONFIRM:
464b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->category = WLAN_CATEGORY_TDLS;
465b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
466b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(tf->u.setup_cfm));
467b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
468b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.setup_cfm.dialog_token = dialog_token;
4695f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if (priv->adapter->is_hw_11ac_capable) {
4705f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			ret = mwifiex_tdls_add_vht_oper(priv, peer, skb);
4715f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (ret) {
4725f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				dev_kfree_skb_any(skb);
4735f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				return ret;
4745f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			}
475396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb);
476396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			if (ret) {
477396939f94084d5923d558e9f22db48bc51156e47Avinash Patil				dev_kfree_skb_any(skb);
478396939f94084d5923d558e9f22db48bc51156e47Avinash Patil				return ret;
479396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			}
480396939f94084d5923d558e9f22db48bc51156e47Avinash Patil		} else {
481396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb);
482396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			if (ret) {
483396939f94084d5923d558e9f22db48bc51156e47Avinash Patil				dev_kfree_skb_any(skb);
484396939f94084d5923d558e9f22db48bc51156e47Avinash Patil				return ret;
485396939f94084d5923d558e9f22db48bc51156e47Avinash Patil			}
4865f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		}
487b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
488b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
489b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_TEARDOWN:
490b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->category = WLAN_CATEGORY_TDLS;
491b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->action_code = WLAN_TDLS_TEARDOWN;
492b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(tf->u.teardown));
493b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.teardown.reason_code = cpu_to_le16(status_code);
494b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
495b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
496b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_DISCOVERY_REQUEST:
497b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->category = WLAN_CATEGORY_TDLS;
498b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
499b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(tf->u.discover_req));
500b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		tf->u.discover_req.dialog_token = dialog_token;
501b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
502b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	default:
503b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
504b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -EINVAL;
505b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
506b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
507b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	return 0;
508b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
509b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
510b23bce296568011b76c27103032dea5a90291d8aAvinash Patilstatic void
5113b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
5123b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg			 const u8 *peer, const u8 *bssid)
513b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
514b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee80211_tdls_lnkie *lnkid;
515b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
516b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
517b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	lnkid->ie_type = WLAN_EID_LINK_ID;
518b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -
519b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			sizeof(struct ieee_types_header);
520b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
521b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(lnkid->bssid, bssid, ETH_ALEN);
522b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
523b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(lnkid->resp_sta, peer, ETH_ALEN);
524b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
525b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
5263b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergint mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
5273b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				 u8 action_code, u8 dialog_token,
528b23bce296568011b76c27103032dea5a90291d8aAvinash Patil				 u16 status_code, const u8 *extra_ies,
529b23bce296568011b76c27103032dea5a90291d8aAvinash Patil				 size_t extra_ies_len)
530b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
531b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct sk_buff *skb;
532b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct mwifiex_txinfo *tx_info;
533b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	int ret;
534b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u16 skb_len;
535b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
536b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
537b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  max(sizeof(struct ieee80211_mgmt),
538b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		      sizeof(struct ieee80211_tdls_data)) +
539b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  MWIFIEX_MGMT_FRAME_HEADER_SIZE +
540b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  MWIFIEX_SUPPORTED_RATES +
541b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  3 + /* Qos Info */
542b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee_types_extcap) +
543b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_ht_cap) +
544b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee_types_bss_co_2040) +
545b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_ht_operation) +
546b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_tdls_lnkie) +
547b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  extra_ies_len;
548b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
5495f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (priv->adapter->is_hw_11ac_capable)
5505f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		skb_len += sizeof(struct ieee_types_vht_cap) +
5515f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			   sizeof(struct ieee_types_vht_oper) +
5525f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			   sizeof(struct ieee_types_aid);
5535f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
554b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb = dev_alloc_skb(skb_len);
555b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (!skb) {
556b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_err(priv->adapter->dev,
557b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			"allocate skb failed for management frame\n");
558b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -ENOMEM;
559b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
560b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
561b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
562b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	switch (action_code) {
563b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_REQUEST:
564b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_CONFIRM:
565b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_TEARDOWN:
566b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_DISCOVERY_REQUEST:
567b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
568b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						   dialog_token, status_code,
569b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						   skb);
570b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
571b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
572b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
573b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
574b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (extra_ies_len)
575b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			memcpy(skb_put(skb, extra_ies_len), extra_ies,
576b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			       extra_ies_len);
577b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,
578b23bce296568011b76c27103032dea5a90291d8aAvinash Patil					 priv->cfg_bssid);
579b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
580b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_RESPONSE:
581b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
582b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						   dialog_token, status_code,
583b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						   skb);
584b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
585b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
586b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
587b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
588b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (extra_ies_len)
589b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			memcpy(skb_put(skb, extra_ies_len), extra_ies,
590b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			       extra_ies_len);
591b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
592b23bce296568011b76c27103032dea5a90291d8aAvinash Patil					 priv->cfg_bssid);
593b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
594b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
595b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
596b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	switch (action_code) {
597b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_REQUEST:
598b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_TDLS_SETUP_RESPONSE:
599b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb->priority = MWIFIEX_PRIO_BK;
600b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
601b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	default:
602b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb->priority = MWIFIEX_PRIO_VI;
603b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
604b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
605b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
606b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info = MWIFIEX_SKB_TXCB(skb);
607701a9e619347ac06d59481db14bbc4df99763270Amitkumar Karwar	memset(tx_info, 0, sizeof(*tx_info));
608b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info->bss_num = priv->bss_num;
609b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info->bss_type = priv->bss_type;
610b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
611c64800e772a03a8162e107c2d03d06175fff443dThomas Gleixner	__net_timestamp(skb);
612b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	mwifiex_queue_tx_pkt(priv, skb);
613b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
614b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	return 0;
615b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
616b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
617b23bce296568011b76c27103032dea5a90291d8aAvinash Patilstatic int
6183b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
6193b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				    const u8 *peer,
620b23bce296568011b76c27103032dea5a90291d8aAvinash Patil				    u8 action_code, u8 dialog_token,
621b23bce296568011b76c27103032dea5a90291d8aAvinash Patil				    u16 status_code, struct sk_buff *skb)
622b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
623b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee80211_mgmt *mgmt;
624b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
625b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	int ret;
626b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u16 capab;
627b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct ieee80211_ht_cap *ht_cap;
628b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 radio, *pos;
629b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
630b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
631b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
632b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u));
633b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
634b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memset(mgmt, 0, 24);
635b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(mgmt->da, peer, ETH_ALEN);
636b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);
637b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
638b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
639b23bce296568011b76c27103032dea5a90291d8aAvinash Patil					  IEEE80211_STYPE_ACTION);
640b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
641b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	/* add address 4 */
642b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	pos = skb_put(skb, ETH_ALEN);
643b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
644b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	switch (action_code) {
645b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
646b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
647b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
648b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mgmt->u.action.u.tdls_discover_resp.action_code =
649b23bce296568011b76c27103032dea5a90291d8aAvinash Patil					      WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
650b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mgmt->u.action.u.tdls_discover_resp.dialog_token =
651b23bce296568011b76c27103032dea5a90291d8aAvinash Patil								   dialog_token;
652b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mgmt->u.action.u.tdls_discover_resp.capability =
653b23bce296568011b76c27103032dea5a90291d8aAvinash Patil							     cpu_to_le16(capab);
654b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		/* move back for addr4 */
655b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		memmove(pos + ETH_ALEN, &mgmt->u.action.category,
656b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			sizeof(mgmt->u.action.u.tdls_discover_resp));
657b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		/* init address 4 */
658b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		memcpy(pos, bc_addr, ETH_ALEN);
659b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
660b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_tdls_append_rates_ie(priv, skb);
661b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
662b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
663b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
664b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
665b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
666b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
667b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = WLAN_EID_HT_CAPABILITY;
668b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		*pos++ = sizeof(struct ieee80211_ht_cap);
669b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ht_cap = (void *)pos;
670b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
671b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
672b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		if (ret) {
673b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			dev_kfree_skb_any(skb);
674b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			return ret;
675b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		}
676b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
6775f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		if (priv->adapter->is_hw_11ac_capable) {
6785f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			ret = mwifiex_tdls_add_vht_capab(priv, skb);
6795f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (ret) {
6805f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				dev_kfree_skb_any(skb);
6815f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				return ret;
6825f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			}
6835f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			mwifiex_tdls_add_aid(priv, skb);
6845f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		}
6855f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
6865f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		mwifiex_tdls_add_ext_capab(priv, skb);
687b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		mwifiex_tdls_add_qos_capab(skb);
688b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		break;
689b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	default:
690b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
691b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -EINVAL;
692b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
693b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
694b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	return 0;
695b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
696b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
6973b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergint mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
6983b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				   u8 action_code, u8 dialog_token,
6993b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				   u16 status_code, const u8 *extra_ies,
7003b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Berg				   size_t extra_ies_len)
701b23bce296568011b76c27103032dea5a90291d8aAvinash Patil{
702b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct sk_buff *skb;
703b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	struct mwifiex_txinfo *tx_info;
704b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u8 *pos;
705b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u32 pkt_type, tx_control;
706b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	u16 pkt_len, skb_len;
707b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
708b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
709b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  max(sizeof(struct ieee80211_mgmt),
710b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		      sizeof(struct ieee80211_tdls_data)) +
711b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  MWIFIEX_MGMT_FRAME_HEADER_SIZE +
712b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  MWIFIEX_SUPPORTED_RATES +
713b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee_types_extcap) +
714b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_ht_cap) +
715b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee_types_bss_co_2040) +
716b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_ht_operation) +
717b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  sizeof(struct ieee80211_tdls_lnkie) +
718b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  extra_ies_len +
719b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  3 + /* Qos Info */
720b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		  ETH_ALEN; /* Address4 */
721b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
7225f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil	if (priv->adapter->is_hw_11ac_capable)
7235f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		skb_len += sizeof(struct ieee_types_vht_cap) +
7245f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			   sizeof(struct ieee_types_vht_oper) +
7255f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			   sizeof(struct ieee_types_aid);
7265f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil
727b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb = dev_alloc_skb(skb_len);
728b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (!skb) {
729b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_err(priv->adapter->dev,
730b23bce296568011b76c27103032dea5a90291d8aAvinash Patil			"allocate skb failed for management frame\n");
731b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -ENOMEM;
732b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
733b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
734b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
735b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
736b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	pkt_type = PKT_TYPE_MGMT;
737b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_control = 0;
738b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
739b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
740b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(pos, &pkt_type, sizeof(pkt_type));
741b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
742b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
743b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,
744b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						dialog_token, status_code,
745b23bce296568011b76c27103032dea5a90291d8aAvinash Patil						skb)) {
746b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		dev_kfree_skb_any(skb);
747b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		return -EINVAL;
748b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	}
749b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
750b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	if (extra_ies_len)
751b23bce296568011b76c27103032dea5a90291d8aAvinash Patil		memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
752b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
753b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	/* the TDLS link IE is always added last we are the responder */
754b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
755b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
756b23bce296568011b76c27103032dea5a90291d8aAvinash Patil				 priv->cfg_bssid);
757b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
758b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	skb->priority = MWIFIEX_PRIO_VI;
759b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
760b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info = MWIFIEX_SKB_TXCB(skb);
761701a9e619347ac06d59481db14bbc4df99763270Amitkumar Karwar	memset(tx_info, 0, sizeof(*tx_info));
762b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info->bss_num = priv->bss_num;
763b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info->bss_type = priv->bss_type;
764b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
765b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
766b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);
767b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,
768b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	       sizeof(pkt_len));
769c64800e772a03a8162e107c2d03d06175fff443dThomas Gleixner	__net_timestamp(skb);
770b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	mwifiex_queue_tx_pkt(priv, skb);
771b23bce296568011b76c27103032dea5a90291d8aAvinash Patil
772b23bce296568011b76c27103032dea5a90291d8aAvinash Patil	return 0;
773b23bce296568011b76c27103032dea5a90291d8aAvinash Patil}
7745f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
7755f2caaf32bc64c200007611505ce2453f4862276Avinash Patil/* This function process tdls action frame from peer.
7765f2caaf32bc64c200007611505ce2453f4862276Avinash Patil * Peer capabilities are stored into station node structure.
7775f2caaf32bc64c200007611505ce2453f4862276Avinash Patil */
7785f2caaf32bc64c200007611505ce2453f4862276Avinash Patilvoid mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
7795f2caaf32bc64c200007611505ce2453f4862276Avinash Patil				       u8 *buf, int len)
7805f2caaf32bc64c200007611505ce2453f4862276Avinash Patil{
7815f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	struct mwifiex_sta_node *sta_ptr;
7825f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	u8 *peer, *pos, *end;
7835f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	u8 i, action, basic;
784f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao	__le16 cap = 0;
7855f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	int ie_len = 0;
7865f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
7875f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	if (len < (sizeof(struct ethhdr) + 3))
7885f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		return;
78945d18c562adefe9d807c0ba833affdeff68bad98Joe Perches	if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
7905f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		return;
79145d18c562adefe9d807c0ba833affdeff68bad98Joe Perches	if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
7925f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		return;
7935f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
7945f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	peer = buf + ETH_ALEN;
79545d18c562adefe9d807c0ba833affdeff68bad98Joe Perches	action = *(buf + sizeof(struct ethhdr) + 2);
7965f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	dev_dbg(priv->adapter->dev,
7975f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		"rx:tdls action: peer=%pM, action=%d\n", peer, action);
7985f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
7995f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	switch (action) {
8005f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	case WLAN_TDLS_SETUP_REQUEST:
8015f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
8025f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			return;
8035f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
8045f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		pos = buf + sizeof(struct ethhdr) + 4;
8055f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		/* payload 1+ category 1 + action 1 + dialog 1 */
806f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao		cap = cpu_to_le16(*(u16 *)pos);
8075f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
8085f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		pos += 2;
8095f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		break;
8105f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
8115f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	case WLAN_TDLS_SETUP_RESPONSE:
8125f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
8135f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			return;
8145f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		/* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
8155f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		pos = buf + sizeof(struct ethhdr) + 6;
816f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao		cap = cpu_to_le16(*(u16 *)pos);
8175f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
8185f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		pos += 2;
8195f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		break;
8205f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
8215f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	case WLAN_TDLS_SETUP_CONFIRM:
8225f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
8235f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			return;
8245f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
8255f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
8265f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		break;
8275f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	default:
828f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao		dev_dbg(priv->adapter->dev, "Unknown TDLS frame type.\n");
8295f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		return;
8305f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	}
8315f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
832f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao	sta_ptr = mwifiex_add_sta_entry(priv, peer);
833f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao	if (!sta_ptr)
834f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao		return;
835f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao
836f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao	sta_ptr->tdls_cap.capab = cap;
837f95f59fe5d2b05a0333214eeba78690081ee5f70Bing Zhao
8385f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
8395f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		if (pos + 2 + pos[1] > end)
8405f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8415f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
8425f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		switch (*pos) {
8435f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_SUPP_RATES:
8445f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			sta_ptr->tdls_cap.rates_len = pos[1];
8455f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			for (i = 0; i < pos[1]; i++)
8465f2caaf32bc64c200007611505ce2453f4862276Avinash Patil				sta_ptr->tdls_cap.rates[i] = pos[i + 2];
8475f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8485f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
8495f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_EXT_SUPP_RATES:
8505f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			basic = sta_ptr->tdls_cap.rates_len;
8515f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			for (i = 0; i < pos[1]; i++)
8525f2caaf32bc64c200007611505ce2453f4862276Avinash Patil				sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
8535f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			sta_ptr->tdls_cap.rates_len += pos[1];
8545f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8555f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_HT_CAPABILITY:
8565f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
8575f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			       sizeof(struct ieee80211_ht_cap));
8585f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			sta_ptr->is_11n_enabled = 1;
8595f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8605f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_HT_OPERATION:
8615f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
8625f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			       sizeof(struct ieee80211_ht_operation));
8635f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8645f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_BSS_COEX_2040:
8655f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			sta_ptr->tdls_cap.coex_2040 = pos[2];
8665f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8675f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_EXT_CAPABILITY:
8685f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
8695f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			       sizeof(struct ieee_types_header) +
8705f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			       min_t(u8, pos[1], 8));
8715f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8725f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_RSN:
8735f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
8743c99832d74777c9ec5545a92450fac5d37b0d0e1Avinash Patil			       sizeof(struct ieee_types_header) +
8753c99832d74777c9ec5545a92450fac5d37b0d0e1Avinash Patil			       min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
8763c99832d74777c9ec5545a92450fac5d37b0d0e1Avinash Patil				     sizeof(struct ieee_types_header)));
8775f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8785f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		case WLAN_EID_QOS_CAPA:
8795f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			sta_ptr->tdls_cap.qos_info = pos[2];
8805f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8815f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		case WLAN_EID_VHT_OPERATION:
8825f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (priv->adapter->is_hw_11ac_capable)
8835f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				memcpy(&sta_ptr->tdls_cap.vhtoper, pos,
8845f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				       sizeof(struct ieee80211_vht_operation));
8855f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			break;
8865f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		case WLAN_EID_VHT_CAPABILITY:
8875f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (priv->adapter->is_hw_11ac_capable) {
8885f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos,
8895f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				       sizeof(struct ieee80211_vht_cap));
8905f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				sta_ptr->is_11ac_enabled = 1;
8915f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			}
8925f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			break;
8935f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil		case WLAN_EID_AID:
8945f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil			if (priv->adapter->is_hw_11ac_capable)
8955f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil				sta_ptr->tdls_cap.aid =
8965f6d5983394fd7b918385dbee7e4d983a7b990d9Avinash Patil					      le16_to_cpu(*(__le16 *)(pos + 2));
8975f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		default:
8985f2caaf32bc64c200007611505ce2453f4862276Avinash Patil			break;
8995f2caaf32bc64c200007611505ce2453f4862276Avinash Patil		}
9005f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	}
9015f2caaf32bc64c200007611505ce2453f4862276Avinash Patil
9025f2caaf32bc64c200007611505ce2453f4862276Avinash Patil	return;
9035f2caaf32bc64c200007611505ce2453f4862276Avinash Patil}
904429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
905429d90d2212b561859767a74e3bb855f32b4600dAvinash Patilstatic int
9063b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
9071f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil{
9081f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	struct mwifiex_sta_node *sta_ptr;
9091f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	struct mwifiex_ds_tdls_oper tdls_oper;
9101f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil
9111f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
9121f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, peer);
9131f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil
9141f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
9151f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil		dev_err(priv->adapter->dev,
9161f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil			"link absent for peer %pM; cannot config\n", peer);
9171f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil		return -EINVAL;
9181f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	}
9191f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil
9201f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
9211f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
922fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
923fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
9241f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil}
9251f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil
9261f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patilstatic int
9273b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
928e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil{
929e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	struct mwifiex_sta_node *sta_ptr;
930e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	struct mwifiex_ds_tdls_oper tdls_oper;
931e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil
932e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
933e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, peer);
934e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil
935e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
936e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil		dev_dbg(priv->adapter->dev,
937e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil			"Setup already in progress for peer %pM\n", peer);
938e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil		return 0;
939e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	}
940e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil
941e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	sta_ptr = mwifiex_add_sta_entry(priv, peer);
942e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	if (!sta_ptr)
943e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil		return -ENOMEM;
944e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil
945e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;
94656bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	mwifiex_hold_tdls_packets(priv, peer);
947e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
948e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
949fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
950fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
951e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil}
952e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil
953e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patilstatic int
9543b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
955429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil{
956429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	struct mwifiex_sta_node *sta_ptr;
957429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	struct mwifiex_ds_tdls_oper tdls_oper;
958429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	unsigned long flags;
959429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
960429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
961429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, peer);
962429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
963429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	if (sta_ptr) {
964429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		if (sta_ptr->is_11n_enabled) {
965429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			mwifiex_11n_cleanup_reorder_tbl(priv);
966429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
967429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					  flags);
968429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
969429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
970429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					       flags);
971429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		}
972429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		mwifiex_del_sta_entry(priv, peer);
973429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	}
974429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
97556bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil	mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
976429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
977429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
978fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao	return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
979fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao				HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
980429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil}
981429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
982429d90d2212b561859767a74e3bb855f32b4600dAvinash Patilstatic int
9833b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergmwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
984429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil{
985429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	struct mwifiex_sta_node *sta_ptr;
986429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	struct ieee80211_mcs_info mcs;
987429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	unsigned long flags;
988429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	int i;
989429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
990429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, peer);
991429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
992429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
993429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		dev_dbg(priv->adapter->dev,
994429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			"tdls: enable link %pM success\n", peer);
995429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
996429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
997429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
998429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		mcs = sta_ptr->tdls_cap.ht_capb.mcs;
999429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		if (mcs.rx_mask[0] != 0xff)
1000429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			sta_ptr->is_11n_enabled = true;
1001429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		if (sta_ptr->is_11n_enabled) {
1002429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &
1003429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			    IEEE80211_HT_CAP_MAX_AMSDU)
1004429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil				sta_ptr->max_amsdu =
1005429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					MWIFIEX_TX_DATA_BUF_SIZE_8K;
1006429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			else
1007429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil				sta_ptr->max_amsdu =
1008429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					MWIFIEX_TX_DATA_BUF_SIZE_4K;
1009429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
1010429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			for (i = 0; i < MAX_NUM_TID; i++)
1011429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil				sta_ptr->ampdu_sta[i] =
1012429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					      priv->aggr_prio_tbl[i].ampdu_user;
1013429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		} else {
1014429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			for (i = 0; i < MAX_NUM_TID; i++)
1015429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil				sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
1016429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		}
1017429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
1018429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
101956bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
1020429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	} else {
1021429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		dev_dbg(priv->adapter->dev,
1022429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			"tdls: enable link %pM failed\n", peer);
1023429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		if (sta_ptr) {
1024429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			mwifiex_11n_cleanup_reorder_tbl(priv);
1025429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1026429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					  flags);
1027429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1028429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1029429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil					       flags);
1030429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil			mwifiex_del_sta_entry(priv, peer);
1031429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		}
103256bd24a18e1a7306a21f6b7d7716cced7e593057Avinash Patil		mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
1033429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
1034429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		return -1;
1035429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	}
1036429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
1037429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	return 0;
1038429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil}
1039429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil
10403b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergint mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action)
1041429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil{
1042429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	switch (action) {
1043429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	case MWIFIEX_TDLS_ENABLE_LINK:
1044429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		return mwifiex_tdls_process_enable_link(priv, peer);
1045429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	case MWIFIEX_TDLS_DISABLE_LINK:
1046429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil		return mwifiex_tdls_process_disable_link(priv, peer);
1047e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil	case MWIFIEX_TDLS_CREATE_LINK:
1048e48e0de0053f077dc8a98e1e06019024e93bb866Avinash Patil		return mwifiex_tdls_process_create_link(priv, peer);
10491f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil	case MWIFIEX_TDLS_CONFIG_LINK:
10501f4dfd8a1e911cd9e12994cd7cc1180e94ee1bc5Avinash Patil		return mwifiex_tdls_process_config_link(priv, peer);
1051429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	}
1052429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil	return 0;
1053429d90d2212b561859767a74e3bb855f32b4600dAvinash Patil}
1054d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil
10553b3a0162fade6b83d5c83efafcd5adb9e4537047Johannes Bergint mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)
1056d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil{
1057d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil	struct mwifiex_sta_node *sta_ptr;
1058d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil
1059d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil	sta_ptr = mwifiex_get_sta_entry(priv, mac);
1060d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil	if (sta_ptr)
1061d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil		return sta_ptr->tdls_status;
1062d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil
1063d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil	return TDLS_NOT_SETUP;
1064d63bf5e5e00dc025c71532e9244a96966ac8e252Avinash Patil}
1065be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1066be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patilvoid mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
1067be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil{
1068be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	struct mwifiex_sta_node *sta_ptr;
1069be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	struct mwifiex_ds_tdls_oper tdls_oper;
1070be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	unsigned long flags;
1071be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1072be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	if (list_empty(&priv->sta_list))
1073be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		return;
1074be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1075be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	list_for_each_entry(sta_ptr, &priv->sta_list, list) {
1076be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1077be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1078be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		if (sta_ptr->is_11n_enabled) {
1079be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil			mwifiex_11n_cleanup_reorder_tbl(priv);
1080be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil			spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1081be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil					  flags);
1082be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil			mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1083be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil			spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1084be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil					       flags);
1085be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		}
1086be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1087be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,
1088be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil					     TDLS_LINK_TEARDOWN);
1089be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);
1090be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil		tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
1091fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao		if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1092fa0ecbb9905d985a77e76801ba1153394ba593e8Bing Zhao				     HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
1093be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil			dev_warn(priv->adapter->dev,
1094be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil				 "Disable link failed for TDLS peer %pM",
1095be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil				 sta_ptr->mac_addr);
1096be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	}
1097be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil
1098be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil	mwifiex_del_all_sta_list(priv);
1099be104b916caf36af7e664b61149389b96c1c0ff6Avinash Patil}
1100