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