diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/tdls.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/tdls.c | 1500 |
1 files changed, 0 insertions, 1500 deletions
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c deleted file mode 100644 index 9275f9c..0000000 --- a/drivers/net/wireless/mwifiex/tdls.c +++ /dev/null @@ -1,1500 +0,0 @@ -/* Marvell Wireless LAN device driver: TDLS handling - * - * Copyright (C) 2014, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available on the worldwide web at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. - */ - -#include "main.h" -#include "wmm.h" -#include "11n.h" -#include "11n_rxreorder.h" -#include "11ac.h" - -#define TDLS_REQ_FIX_LEN 6 -#define TDLS_RESP_FIX_LEN 8 -#define TDLS_CONFIRM_FIX_LEN 6 -#define MWIFIEX_TDLS_WMM_INFO_SIZE 7 - -static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, - const u8 *mac, u8 status) -{ - struct mwifiex_ra_list_tbl *ra_list; - struct list_head *tid_list; - struct sk_buff *skb, *tmp; - struct mwifiex_txinfo *tx_info; - unsigned long flags; - u32 tid; - u8 tid_down; - - mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac); - spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); - - skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) { - if (!ether_addr_equal(mac, skb->data)) - continue; - - __skb_unlink(skb, &priv->tdls_txq); - tx_info = MWIFIEX_SKB_TXCB(skb); - tid = skb->priority; - tid_down = mwifiex_wmm_downgrade_tid(priv, tid); - - if (mwifiex_is_tdls_link_setup(status)) { - ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac); - ra_list->tdls_link = true; - tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; - } else { - tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list; - if (!list_empty(tid_list)) - ra_list = list_first_entry(tid_list, - struct mwifiex_ra_list_tbl, list); - else - ra_list = NULL; - tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT; - } - - if (!ra_list) { - mwifiex_write_data_complete(priv->adapter, skb, 0, -1); - continue; - } - - skb_queue_tail(&ra_list->skb_head, skb); - - ra_list->ba_pkt_count++; - ra_list->total_pkt_count++; - - if (atomic_read(&priv->wmm.highest_queued_prio) < - tos_to_tid_inv[tid_down]) - atomic_set(&priv->wmm.highest_queued_prio, - tos_to_tid_inv[tid_down]); - - atomic_inc(&priv->wmm.tx_pkts_queued); - } - - spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); - return; -} - -static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv, - const u8 *mac) -{ - struct mwifiex_ra_list_tbl *ra_list; - struct list_head *ra_list_head; - struct sk_buff *skb, *tmp; - unsigned long flags; - int i; - - mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac); - spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); - - for (i = 0; i < MAX_NUM_TID; i++) { - if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) { - ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list; - list_for_each_entry(ra_list, ra_list_head, list) { - skb_queue_walk_safe(&ra_list->skb_head, skb, - tmp) { - if (!ether_addr_equal(mac, skb->data)) - continue; - __skb_unlink(skb, &ra_list->skb_head); - atomic_dec(&priv->wmm.tx_pkts_queued); - ra_list->total_pkt_count--; - skb_queue_tail(&priv->tdls_txq, skb); - } - } - } - } - - spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); - return; -} - -/* This function appends rate TLV to scan config command. */ -static int -mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv, - struct sk_buff *skb) -{ - u8 rates[MWIFIEX_SUPPORTED_RATES], *pos; - u16 rates_size, supp_rates_size, ext_rates_size; - - memset(rates, 0, sizeof(rates)); - rates_size = mwifiex_get_supported_rates(priv, rates); - - supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES); - - if (skb_tailroom(skb) < rates_size + 4) { - mwifiex_dbg(priv->adapter, ERROR, - "Insuffient space while adding rates\n"); - return -ENOMEM; - } - - pos = skb_put(skb, supp_rates_size + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = supp_rates_size; - memcpy(pos, rates, supp_rates_size); - - if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) { - ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES; - pos = skb_put(skb, ext_rates_size + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = ext_rates_size; - memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES, - ext_rates_size); - } - - return 0; -} - -static void mwifiex_tdls_add_aid(struct mwifiex_private *priv, - struct sk_buff *skb) -{ - struct ieee_types_assoc_rsp *assoc_rsp; - u8 *pos; - - assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf; - pos = (void *)skb_put(skb, 4); - *pos++ = WLAN_EID_AID; - *pos++ = 2; - memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id)); - - return; -} - -static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv, - struct sk_buff *skb) -{ - struct ieee80211_vht_cap vht_cap; - u8 *pos; - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); - *pos++ = WLAN_EID_VHT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_vht_cap); - - memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap)); - - mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band); - memcpy(pos, &vht_cap, sizeof(vht_cap)); - - return 0; -} - -static int -mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac, - u8 vht_enabled, struct sk_buff *skb) -{ - struct ieee80211_ht_operation *ht_oper; - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_bssdescriptor *bss_desc = - &priv->curr_bss_params.bss_descriptor; - u8 *pos; - - sta_ptr = mwifiex_get_sta_entry(priv, mac); - if (unlikely(!sta_ptr)) { - mwifiex_dbg(priv->adapter, ERROR, - "TDLS peer station not found in list\n"); - return -1; - } - - if (!(le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info))) { - mwifiex_dbg(priv->adapter, WARN, - "TDLS peer doesn't support ht capabilities\n"); - return 0; - } - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2); - *pos++ = WLAN_EID_HT_OPERATION; - *pos++ = sizeof(struct ieee80211_ht_operation); - ht_oper = (void *)pos; - - ht_oper->primary_chan = bss_desc->channel; - - /* follow AP's channel bandwidth */ - if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && - bss_desc->bcn_ht_cap && - ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param)) - ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param; - - if (vht_enabled) { - ht_oper->ht_param = - mwifiex_get_sec_chan_offset(bss_desc->channel); - ht_oper->ht_param |= BIT(2); - } - - memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper, - sizeof(struct ieee80211_ht_operation)); - - return 0; -} - -static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, - const u8 *mac, struct sk_buff *skb) -{ - struct mwifiex_bssdescriptor *bss_desc; - struct ieee80211_vht_operation *vht_oper; - struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL; - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_adapter *adapter = priv->adapter; - u8 supp_chwd_set, peer_supp_chwd_set; - u8 *pos, ap_supp_chwd_set, chan_bw; - u16 mcs_map_user, mcs_map_resp, mcs_map_result; - u16 mcs_user, mcs_resp, nss; - u32 usr_vht_cap_info; - - bss_desc = &priv->curr_bss_params.bss_descriptor; - - sta_ptr = mwifiex_get_sta_entry(priv, mac); - if (unlikely(!sta_ptr)) { - mwifiex_dbg(adapter, ERROR, - "TDLS peer station not found in list\n"); - return -1; - } - - if (!(le32_to_cpu(sta_ptr->tdls_cap.vhtcap.vht_cap_info))) { - mwifiex_dbg(adapter, WARN, - "TDLS peer doesn't support vht capabilities\n"); - return 0; - } - - if (!mwifiex_is_bss_in_11ac_mode(priv)) { - if (sta_ptr->tdls_cap.extcap.ext_capab[7] & - WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) { - mwifiex_dbg(adapter, WARN, - "TDLS peer doesn't support wider bandwidth\n"); - return 0; - } - } else { - ap_vht_cap = bss_desc->bcn_vht_cap; - } - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2); - *pos++ = WLAN_EID_VHT_OPERATION; - *pos++ = sizeof(struct ieee80211_vht_operation); - vht_oper = (struct ieee80211_vht_operation *)pos; - - if (bss_desc->bss_band & BAND_A) - usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a; - else - usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg; - - /* find the minmum bandwith between AP/TDLS peers */ - vht_cap = &sta_ptr->tdls_cap.vhtcap; - supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info); - peer_supp_chwd_set = - GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info)); - supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set); - - /* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */ - - if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] & - WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) { - ap_supp_chwd_set = - GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info)); - supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set); - } - - switch (supp_chwd_set) { - case IEEE80211_VHT_CHANWIDTH_80MHZ: - vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; - break; - case IEEE80211_VHT_CHANWIDTH_160MHZ: - vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ; - break; - case IEEE80211_VHT_CHANWIDTH_80P80MHZ: - vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ; - break; - default: - vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT; - break; - } - - mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support); - mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map); - mcs_map_result = 0; - - for (nss = 1; nss <= 8; nss++) { - mcs_user = GET_VHTNSSMCS(mcs_map_user, nss); - mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss); - - if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) || - (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED)) - SET_VHTNSSMCS(mcs_map_result, nss, - IEEE80211_VHT_MCS_NOT_SUPPORTED); - else - SET_VHTNSSMCS(mcs_map_result, nss, - min_t(u16, mcs_user, mcs_resp)); - } - - vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result); - - switch (vht_oper->chan_width) { - case IEEE80211_VHT_CHANWIDTH_80MHZ: - chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ; - break; - case IEEE80211_VHT_CHANWIDTH_160MHZ: - chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ; - break; - case IEEE80211_VHT_CHANWIDTH_80P80MHZ: - chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ; - break; - default: - chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT; - break; - } - vht_oper->center_freq_seg1_idx = - mwifiex_get_center_freq_index(priv, BAND_AAC, - bss_desc->channel, - chan_bw); - - return 0; -} - -static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, - struct sk_buff *skb) -{ - struct ieee_types_extcap *extcap; - - extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap)); - extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY; - extcap->ieee_hdr.len = 8; - memset(extcap->ext_capab, 0, 8); - extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED; - extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH; - - if (priv->adapter->is_hw_11ac_capable) - extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED; -} - -static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb) -{ - u8 *pos = (void *)skb_put(skb, 3); - - *pos++ = WLAN_EID_QOS_CAPA; - *pos++ = 1; - *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB; -} - -static void -mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb) -{ - struct ieee80211_wmm_param_ie *wmm; - u8 ac_vi[] = {0x42, 0x43, 0x5e, 0x00}; - u8 ac_vo[] = {0x62, 0x32, 0x2f, 0x00}; - u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00}; - u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00}; - - wmm = (void *)skb_put(skb, sizeof(*wmm)); - memset(wmm, 0, sizeof(*wmm)); - - wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; - wmm->len = sizeof(*wmm) - 2; - wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ - wmm->oui[1] = 0x50; - wmm->oui[2] = 0xf2; - wmm->oui_type = 2; /* WME */ - wmm->oui_subtype = 1; /* WME param */ - wmm->version = 1; /* WME ver */ - wmm->qos_info = 0; /* U-APSD not in use */ - - /* use default WMM AC parameters for TDLS link*/ - memcpy(&wmm->ac[0], ac_be, sizeof(ac_be)); - memcpy(&wmm->ac[1], ac_bk, sizeof(ac_bk)); - memcpy(&wmm->ac[2], ac_vi, sizeof(ac_vi)); - memcpy(&wmm->ac[3], ac_vo, sizeof(ac_vo)); -} - -static void -mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb, - u8 qosinfo) -{ - u8 *buf; - - buf = (void *)skb_put(skb, MWIFIEX_TDLS_WMM_INFO_SIZE + - sizeof(struct ieee_types_header)); - - *buf++ = WLAN_EID_VENDOR_SPECIFIC; - *buf++ = 7; /* len */ - *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *buf++ = 0x50; - *buf++ = 0xf2; - *buf++ = 2; /* WME */ - *buf++ = 0; /* WME info */ - *buf++ = 1; /* WME ver */ - *buf++ = qosinfo; /* U-APSD no in use */ -} - -static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv, - const u8 *peer, u8 action_code, - u8 dialog_token, - u16 status_code, struct sk_buff *skb) -{ - struct ieee80211_tdls_data *tf; - int ret; - u16 capab; - struct ieee80211_ht_cap *ht_cap; - u8 radio, *pos; - - capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - - tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); - memcpy(tf->da, peer, ETH_ALEN); - memcpy(tf->sa, priv->curr_addr, ETH_ALEN); - tf->ether_type = cpu_to_be16(ETH_P_TDLS); - tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; - - switch (action_code) { - case WLAN_TDLS_SETUP_REQUEST: - tf->category = WLAN_CATEGORY_TDLS; - tf->action_code = WLAN_TDLS_SETUP_REQUEST; - skb_put(skb, sizeof(tf->u.setup_req)); - tf->u.setup_req.dialog_token = dialog_token; - tf->u.setup_req.capability = cpu_to_le16(capab); - ret = mwifiex_tdls_append_rates_ie(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (void *)pos; - radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - ret = mwifiex_fill_cap_info(priv, radio, ht_cap); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - if (priv->adapter->is_hw_11ac_capable) { - ret = mwifiex_tdls_add_vht_capab(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - mwifiex_tdls_add_aid(priv, skb); - } - - mwifiex_tdls_add_ext_capab(priv, skb); - mwifiex_tdls_add_qos_capab(skb); - mwifiex_add_wmm_info_ie(priv, skb, 0); - break; - - case WLAN_TDLS_SETUP_RESPONSE: - tf->category = WLAN_CATEGORY_TDLS; - tf->action_code = WLAN_TDLS_SETUP_RESPONSE; - skb_put(skb, sizeof(tf->u.setup_resp)); - tf->u.setup_resp.status_code = cpu_to_le16(status_code); - tf->u.setup_resp.dialog_token = dialog_token; - tf->u.setup_resp.capability = cpu_to_le16(capab); - ret = mwifiex_tdls_append_rates_ie(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (void *)pos; - radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - ret = mwifiex_fill_cap_info(priv, radio, ht_cap); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - if (priv->adapter->is_hw_11ac_capable) { - ret = mwifiex_tdls_add_vht_capab(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - mwifiex_tdls_add_aid(priv, skb); - } - - mwifiex_tdls_add_ext_capab(priv, skb); - mwifiex_tdls_add_qos_capab(skb); - mwifiex_add_wmm_info_ie(priv, skb, 0); - break; - - case WLAN_TDLS_SETUP_CONFIRM: - tf->category = WLAN_CATEGORY_TDLS; - tf->action_code = WLAN_TDLS_SETUP_CONFIRM; - skb_put(skb, sizeof(tf->u.setup_cfm)); - tf->u.setup_cfm.status_code = cpu_to_le16(status_code); - tf->u.setup_cfm.dialog_token = dialog_token; - - mwifiex_tdls_add_wmm_param_ie(priv, skb); - if (priv->adapter->is_hw_11ac_capable) { - ret = mwifiex_tdls_add_vht_oper(priv, peer, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - } else { - ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - } - break; - - case WLAN_TDLS_TEARDOWN: - tf->category = WLAN_CATEGORY_TDLS; - tf->action_code = WLAN_TDLS_TEARDOWN; - skb_put(skb, sizeof(tf->u.teardown)); - tf->u.teardown.reason_code = cpu_to_le16(status_code); - break; - - case WLAN_TDLS_DISCOVERY_REQUEST: - tf->category = WLAN_CATEGORY_TDLS; - tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST; - skb_put(skb, sizeof(tf->u.discover_req)); - tf->u.discover_req.dialog_token = dialog_token; - break; - default: - mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n"); - return -EINVAL; - } - - return 0; -} - -static void -mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr, - const u8 *peer, const u8 *bssid) -{ - struct ieee80211_tdls_lnkie *lnkid; - - lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); - lnkid->ie_type = WLAN_EID_LINK_ID; - lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - - sizeof(struct ieee_types_header); - - memcpy(lnkid->bssid, bssid, ETH_ALEN); - memcpy(lnkid->init_sta, src_addr, ETH_ALEN); - memcpy(lnkid->resp_sta, peer, ETH_ALEN); -} - -int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, - u8 action_code, u8 dialog_token, - u16 status_code, const u8 *extra_ies, - size_t extra_ies_len) -{ - struct sk_buff *skb; - struct mwifiex_txinfo *tx_info; - int ret; - u16 skb_len; - - skb_len = MWIFIEX_MIN_DATA_HEADER_LEN + - max(sizeof(struct ieee80211_mgmt), - sizeof(struct ieee80211_tdls_data)) + - MWIFIEX_MGMT_FRAME_HEADER_SIZE + - MWIFIEX_SUPPORTED_RATES + - 3 + /* Qos Info */ - sizeof(struct ieee_types_extcap) + - sizeof(struct ieee80211_ht_cap) + - sizeof(struct ieee_types_bss_co_2040) + - sizeof(struct ieee80211_ht_operation) + - sizeof(struct ieee80211_tdls_lnkie) + - sizeof(struct ieee80211_wmm_param_ie) + - extra_ies_len; - - if (priv->adapter->is_hw_11ac_capable) - skb_len += sizeof(struct ieee_types_vht_cap) + - sizeof(struct ieee_types_vht_oper) + - sizeof(struct ieee_types_aid); - - skb = dev_alloc_skb(skb_len); - if (!skb) { - mwifiex_dbg(priv->adapter, ERROR, - "allocate skb failed for management frame\n"); - return -ENOMEM; - } - skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN); - - switch (action_code) { - case WLAN_TDLS_SETUP_REQUEST: - case WLAN_TDLS_SETUP_CONFIRM: - case WLAN_TDLS_TEARDOWN: - case WLAN_TDLS_DISCOVERY_REQUEST: - ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code, - dialog_token, status_code, - skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); - mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer, - priv->cfg_bssid); - break; - case WLAN_TDLS_SETUP_RESPONSE: - ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code, - dialog_token, status_code, - skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, - extra_ies_len); - mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr, - priv->cfg_bssid); - break; - } - - switch (action_code) { - case WLAN_TDLS_SETUP_REQUEST: - case WLAN_TDLS_SETUP_RESPONSE: - skb->priority = MWIFIEX_PRIO_BK; - break; - default: - skb->priority = MWIFIEX_PRIO_VI; - break; - } - - tx_info = MWIFIEX_SKB_TXCB(skb); - memset(tx_info, 0, sizeof(*tx_info)); - tx_info->bss_num = priv->bss_num; - tx_info->bss_type = priv->bss_type; - - __net_timestamp(skb); - mwifiex_queue_tx_pkt(priv, skb); - - return 0; -} - -static int -mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, - const u8 *peer, - u8 action_code, u8 dialog_token, - u16 status_code, struct sk_buff *skb) -{ - struct ieee80211_mgmt *mgmt; - u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - int ret; - u16 capab; - struct ieee80211_ht_cap *ht_cap; - u8 radio, *pos; - - capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap; - - mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u)); - - memset(mgmt, 0, 24); - memcpy(mgmt->da, peer, ETH_ALEN); - memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN); - memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN); - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION); - - /* add address 4 */ - pos = skb_put(skb, ETH_ALEN); - - switch (action_code) { - case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: - skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1); - mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; - mgmt->u.action.u.tdls_discover_resp.action_code = - WLAN_PUB_ACTION_TDLS_DISCOVER_RES; - mgmt->u.action.u.tdls_discover_resp.dialog_token = - dialog_token; - mgmt->u.action.u.tdls_discover_resp.capability = - cpu_to_le16(capab); - /* move back for addr4 */ - memmove(pos + ETH_ALEN, &mgmt->u.action.category, - sizeof(mgmt->u.action.u.tdls_discover_resp)); - /* init address 4 */ - memcpy(pos, bc_addr, ETH_ALEN); - - ret = mwifiex_tdls_append_rates_ie(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - ht_cap = (void *)pos; - radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - ret = mwifiex_fill_cap_info(priv, radio, ht_cap); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - - if (priv->adapter->is_hw_11ac_capable) { - ret = mwifiex_tdls_add_vht_capab(priv, skb); - if (ret) { - dev_kfree_skb_any(skb); - return ret; - } - mwifiex_tdls_add_aid(priv, skb); - } - - mwifiex_tdls_add_ext_capab(priv, skb); - mwifiex_tdls_add_qos_capab(skb); - break; - default: - mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n"); - return -EINVAL; - } - - return 0; -} - -int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer, - u8 action_code, u8 dialog_token, - u16 status_code, const u8 *extra_ies, - size_t extra_ies_len) -{ - struct sk_buff *skb; - struct mwifiex_txinfo *tx_info; - u8 *pos; - u32 pkt_type, tx_control; - u16 pkt_len, skb_len; - - skb_len = MWIFIEX_MIN_DATA_HEADER_LEN + - max(sizeof(struct ieee80211_mgmt), - sizeof(struct ieee80211_tdls_data)) + - MWIFIEX_MGMT_FRAME_HEADER_SIZE + - MWIFIEX_SUPPORTED_RATES + - sizeof(struct ieee_types_extcap) + - sizeof(struct ieee80211_ht_cap) + - sizeof(struct ieee_types_bss_co_2040) + - sizeof(struct ieee80211_ht_operation) + - sizeof(struct ieee80211_tdls_lnkie) + - extra_ies_len + - 3 + /* Qos Info */ - ETH_ALEN; /* Address4 */ - - if (priv->adapter->is_hw_11ac_capable) - skb_len += sizeof(struct ieee_types_vht_cap) + - sizeof(struct ieee_types_vht_oper) + - sizeof(struct ieee_types_aid); - - skb = dev_alloc_skb(skb_len); - if (!skb) { - mwifiex_dbg(priv->adapter, ERROR, - "allocate skb failed for management frame\n"); - return -ENOMEM; - } - - skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN); - - pkt_type = PKT_TYPE_MGMT; - tx_control = 0; - pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); - memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); - memcpy(pos, &pkt_type, sizeof(pkt_type)); - memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control)); - - if (mwifiex_construct_tdls_action_frame(priv, peer, action_code, - dialog_token, status_code, - skb)) { - dev_kfree_skb_any(skb); - return -EINVAL; - } - - if (extra_ies_len) - memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); - - /* the TDLS link IE is always added last we are the responder */ - - mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr, - priv->cfg_bssid); - - skb->priority = MWIFIEX_PRIO_VI; - - tx_info = MWIFIEX_SKB_TXCB(skb); - memset(tx_info, 0, sizeof(*tx_info)); - tx_info->bss_num = priv->bss_num; - tx_info->bss_type = priv->bss_type; - tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; - - pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len); - memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len, - sizeof(pkt_len)); - __net_timestamp(skb); - mwifiex_queue_tx_pkt(priv, skb); - - return 0; -} - -/* This function process tdls action frame from peer. - * Peer capabilities are stored into station node structure. - */ -void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, - u8 *buf, int len) -{ - struct mwifiex_sta_node *sta_ptr; - u8 *peer, *pos, *end; - u8 i, action, basic; - __le16 cap = 0; - int ie_len = 0; - - if (len < (sizeof(struct ethhdr) + 3)) - return; - if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE) - return; - if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS) - return; - - peer = buf + ETH_ALEN; - action = *(buf + sizeof(struct ethhdr) + 2); - mwifiex_dbg(priv->adapter, DATA, - "rx:tdls action: peer=%pM, action=%d\n", peer, action); - - switch (action) { - case WLAN_TDLS_SETUP_REQUEST: - if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN)) - return; - - pos = buf + sizeof(struct ethhdr) + 4; - /* payload 1+ category 1 + action 1 + dialog 1 */ - cap = cpu_to_le16(*(u16 *)pos); - ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN; - pos += 2; - break; - - case WLAN_TDLS_SETUP_RESPONSE: - if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN)) - return; - /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/ - pos = buf + sizeof(struct ethhdr) + 6; - cap = cpu_to_le16(*(u16 *)pos); - ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN; - pos += 2; - break; - - case WLAN_TDLS_SETUP_CONFIRM: - if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN)) - return; - pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN; - ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN; - break; - default: - mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n"); - return; - } - - sta_ptr = mwifiex_add_sta_entry(priv, peer); - if (!sta_ptr) - return; - - sta_ptr->tdls_cap.capab = cap; - - for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) { - if (pos + 2 + pos[1] > end) - break; - - switch (*pos) { - case WLAN_EID_SUPP_RATES: - sta_ptr->tdls_cap.rates_len = pos[1]; - for (i = 0; i < pos[1]; i++) - sta_ptr->tdls_cap.rates[i] = pos[i + 2]; - break; - - case WLAN_EID_EXT_SUPP_RATES: - basic = sta_ptr->tdls_cap.rates_len; - for (i = 0; i < pos[1]; i++) - sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; - sta_ptr->tdls_cap.rates_len += pos[1]; - break; - case WLAN_EID_HT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, - sizeof(struct ieee80211_ht_cap)); - sta_ptr->is_11n_enabled = 1; - break; - case WLAN_EID_HT_OPERATION: - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, - sizeof(struct ieee80211_ht_operation)); - break; - case WLAN_EID_BSS_COEX_2040: - sta_ptr->tdls_cap.coex_2040 = pos[2]; - break; - case WLAN_EID_EXT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, - sizeof(struct ieee_types_header) + - min_t(u8, pos[1], 8)); - break; - case WLAN_EID_RSN: - memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, - sizeof(struct ieee_types_header) + - min_t(u8, pos[1], IEEE_MAX_IE_SIZE - - sizeof(struct ieee_types_header))); - break; - case WLAN_EID_QOS_CAPA: - sta_ptr->tdls_cap.qos_info = pos[2]; - break; - case WLAN_EID_VHT_OPERATION: - if (priv->adapter->is_hw_11ac_capable) - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, - sizeof(struct ieee80211_vht_operation)); - break; - case WLAN_EID_VHT_CAPABILITY: - if (priv->adapter->is_hw_11ac_capable) { - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, - sizeof(struct ieee80211_vht_cap)); - sta_ptr->is_11ac_enabled = 1; - } - break; - case WLAN_EID_AID: - if (priv->adapter->is_hw_11ac_capable) - sta_ptr->tdls_cap.aid = - le16_to_cpu(*(__le16 *)(pos + 2)); - default: - break; - } - } - - return; -} - -static int -mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer) -{ - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_ds_tdls_oper tdls_oper; - - memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper)); - sta_ptr = mwifiex_get_sta_entry(priv, peer); - - if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) { - mwifiex_dbg(priv->adapter, ERROR, - "link absent for peer %pM; cannot config\n", peer); - return -EINVAL; - } - - memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); - tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK; - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); -} - -static int -mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer) -{ - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_ds_tdls_oper tdls_oper; - - memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper)); - sta_ptr = mwifiex_get_sta_entry(priv, peer); - - if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) { - mwifiex_dbg(priv->adapter, WARN, - "Setup already in progress for peer %pM\n", peer); - return 0; - } - - sta_ptr = mwifiex_add_sta_entry(priv, peer); - if (!sta_ptr) - return -ENOMEM; - - sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS; - mwifiex_hold_tdls_packets(priv, peer); - memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); - tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK; - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); -} - -static int -mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer) -{ - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_ds_tdls_oper tdls_oper; - unsigned long flags; - - memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper)); - sta_ptr = mwifiex_get_sta_entry(priv, peer); - - if (sta_ptr) { - if (sta_ptr->is_11n_enabled) { - mwifiex_11n_cleanup_reorder_tbl(priv); - spin_lock_irqsave(&priv->wmm.ra_list_spinlock, - flags); - mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); - spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, - flags); - } - mwifiex_del_sta_entry(priv, peer); - } - - mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); - mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP); - memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); - tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper, true); -} - -static int -mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) -{ - struct mwifiex_sta_node *sta_ptr; - struct ieee80211_mcs_info mcs; - unsigned long flags; - int i; - - sta_ptr = mwifiex_get_sta_entry(priv, peer); - - if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) { - mwifiex_dbg(priv->adapter, MSG, - "tdls: enable link %pM success\n", peer); - - sta_ptr->tdls_status = TDLS_SETUP_COMPLETE; - - mcs = sta_ptr->tdls_cap.ht_capb.mcs; - if (mcs.rx_mask[0] != 0xff) - sta_ptr->is_11n_enabled = true; - if (sta_ptr->is_11n_enabled) { - if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) & - IEEE80211_HT_CAP_MAX_AMSDU) - sta_ptr->max_amsdu = - MWIFIEX_TX_DATA_BUF_SIZE_8K; - else - sta_ptr->max_amsdu = - MWIFIEX_TX_DATA_BUF_SIZE_4K; - - for (i = 0; i < MAX_NUM_TID; i++) - sta_ptr->ampdu_sta[i] = - priv->aggr_prio_tbl[i].ampdu_user; - } else { - for (i = 0; i < MAX_NUM_TID; i++) - sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; - } - if (sta_ptr->tdls_cap.extcap.ext_capab[3] & - WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) { - mwifiex_config_tdls_enable(priv); - mwifiex_config_tdls_cs_params(priv); - } - - memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); - mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); - mwifiex_auto_tdls_update_peer_status(priv, peer, - TDLS_SETUP_COMPLETE); - } else { - mwifiex_dbg(priv->adapter, ERROR, - "tdls: enable link %pM failed\n", peer); - if (sta_ptr) { - mwifiex_11n_cleanup_reorder_tbl(priv); - spin_lock_irqsave(&priv->wmm.ra_list_spinlock, - flags); - mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); - spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, - flags); - mwifiex_del_sta_entry(priv, peer); - } - mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); - mwifiex_auto_tdls_update_peer_status(priv, peer, - TDLS_NOT_SETUP); - - return -1; - } - - return 0; -} - -int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action) -{ - switch (action) { - case MWIFIEX_TDLS_ENABLE_LINK: - return mwifiex_tdls_process_enable_link(priv, peer); - case MWIFIEX_TDLS_DISABLE_LINK: - return mwifiex_tdls_process_disable_link(priv, peer); - case MWIFIEX_TDLS_CREATE_LINK: - return mwifiex_tdls_process_create_link(priv, peer); - case MWIFIEX_TDLS_CONFIG_LINK: - return mwifiex_tdls_process_config_link(priv, peer); - } - return 0; -} - -int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac) -{ - struct mwifiex_sta_node *sta_ptr; - - sta_ptr = mwifiex_get_sta_entry(priv, mac); - if (sta_ptr) - return sta_ptr->tdls_status; - - return TDLS_NOT_SETUP; -} - -int mwifiex_get_tdls_list(struct mwifiex_private *priv, - struct tdls_peer_info *buf) -{ - struct mwifiex_sta_node *sta_ptr; - struct tdls_peer_info *peer = buf; - int count = 0; - unsigned long flags; - - if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) - return 0; - - /* make sure we are in station mode and connected */ - if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) - return 0; - - spin_lock_irqsave(&priv->sta_list_spinlock, flags); - list_for_each_entry(sta_ptr, &priv->sta_list, list) { - if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) { - ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); - peer++; - count++; - if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED) - break; - } - } - spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); - - return count; -} - -void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv) -{ - struct mwifiex_sta_node *sta_ptr; - struct mwifiex_ds_tdls_oper tdls_oper; - unsigned long flags; - - if (list_empty(&priv->sta_list)) - return; - - list_for_each_entry(sta_ptr, &priv->sta_list, list) { - memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper)); - - if (sta_ptr->is_11n_enabled) { - mwifiex_11n_cleanup_reorder_tbl(priv); - spin_lock_irqsave(&priv->wmm.ra_list_spinlock, - flags); - mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); - spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, - flags); - } - - mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr, - TDLS_LINK_TEARDOWN); - memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN); - tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; - if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, - HostCmd_ACT_GEN_SET, 0, &tdls_oper, false)) - mwifiex_dbg(priv->adapter, ERROR, - "Disable link failed for TDLS peer %pM", - sta_ptr->mac_addr); - } - - mwifiex_del_all_sta_list(priv); -} - -int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb) -{ - struct mwifiex_auto_tdls_peer *peer; - unsigned long flags; - u8 mac[ETH_ALEN]; - - ether_addr_copy(mac, skb->data); - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry(peer, &priv->auto_tdls_list, list) { - if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) { - if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH && - peer->tdls_status == TDLS_NOT_SETUP && - (peer->failure_count < - MWIFIEX_TDLS_MAX_FAIL_COUNT)) { - peer->tdls_status = TDLS_SETUP_INPROGRESS; - mwifiex_dbg(priv->adapter, INFO, - "setup TDLS link, peer=%pM rssi=%d\n", - peer->mac_addr, peer->rssi); - - cfg80211_tdls_oper_request(priv->netdev, - peer->mac_addr, - NL80211_TDLS_SETUP, - 0, GFP_ATOMIC); - peer->do_setup = false; - priv->check_tdls_tx = false; - } else if (peer->failure_count < - MWIFIEX_TDLS_MAX_FAIL_COUNT && - peer->do_discover) { - mwifiex_send_tdls_data_frame(priv, - peer->mac_addr, - WLAN_TDLS_DISCOVERY_REQUEST, - 1, 0, NULL, 0); - peer->do_discover = false; - } - } - } - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); - - return 0; -} - -void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv) -{ - struct mwifiex_auto_tdls_peer *peer, *tmp_node; - unsigned long flags; - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) { - list_del(&peer->list); - kfree(peer); - } - - INIT_LIST_HEAD(&priv->auto_tdls_list); - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); - priv->check_tdls_tx = false; -} - -void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac) -{ - struct mwifiex_auto_tdls_peer *tdls_peer; - unsigned long flags; - - if (!priv->adapter->auto_tdls) - return; - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) { - if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) { - tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS; - tdls_peer->rssi_jiffies = jiffies; - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); - return; - } - } - - /* create new TDLS peer */ - tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC); - if (tdls_peer) { - ether_addr_copy(tdls_peer->mac_addr, mac); - tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS; - tdls_peer->rssi_jiffies = jiffies; - INIT_LIST_HEAD(&tdls_peer->list); - list_add_tail(&tdls_peer->list, &priv->auto_tdls_list); - mwifiex_dbg(priv->adapter, INFO, - "Add auto TDLS peer= %pM to list\n", mac); - } - - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); -} - -void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, - const u8 *mac, u8 link_status) -{ - struct mwifiex_auto_tdls_peer *peer; - unsigned long flags; - - if (!priv->adapter->auto_tdls) - return; - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry(peer, &priv->auto_tdls_list, list) { - if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) { - if ((link_status == TDLS_NOT_SETUP) && - (peer->tdls_status == TDLS_SETUP_INPROGRESS)) - peer->failure_count++; - else if (mwifiex_is_tdls_link_setup(link_status)) - peer->failure_count = 0; - - peer->tdls_status = link_status; - break; - } - } - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); -} - -void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv, - u8 *mac, s8 snr, s8 nflr) -{ - struct mwifiex_auto_tdls_peer *peer; - unsigned long flags; - - if (!priv->adapter->auto_tdls) - return; - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry(peer, &priv->auto_tdls_list, list) { - if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) { - peer->rssi = nflr - snr; - peer->rssi_jiffies = jiffies; - break; - } - } - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); -} - -void mwifiex_check_auto_tdls(unsigned long context) -{ - struct mwifiex_private *priv = (struct mwifiex_private *)context; - struct mwifiex_auto_tdls_peer *tdls_peer; - unsigned long flags; - u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; - - if (WARN_ON_ONCE(!priv || !priv->adapter)) { - pr_err("mwifiex: %s: adapter or private structure is NULL\n", - __func__); - return; - } - - if (unlikely(!priv->adapter->auto_tdls)) - return; - - if (!priv->auto_tdls_timer_active) { - mwifiex_dbg(priv->adapter, INFO, - "auto TDLS timer inactive; return"); - return; - } - - priv->check_tdls_tx = false; - - if (list_empty(&priv->auto_tdls_list)) { - mod_timer(&priv->auto_tdls_timer, - jiffies + - msecs_to_jiffies(MWIFIEX_TIMER_10S)); - return; - } - - spin_lock_irqsave(&priv->auto_tdls_lock, flags); - list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) { - if ((jiffies - tdls_peer->rssi_jiffies) > - (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) { - tdls_peer->rssi = 0; - tdls_peer->do_discover = true; - priv->check_tdls_tx = true; - } - - if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) || - !tdls_peer->rssi) && - mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) { - tdls_peer->tdls_status = TDLS_LINK_TEARDOWN; - mwifiex_dbg(priv->adapter, MSG, - "teardown TDLS link,peer=%pM rssi=%d\n", - tdls_peer->mac_addr, -tdls_peer->rssi); - tdls_peer->do_discover = true; - priv->check_tdls_tx = true; - cfg80211_tdls_oper_request(priv->netdev, - tdls_peer->mac_addr, - NL80211_TDLS_TEARDOWN, - reason, GFP_ATOMIC); - } else if (tdls_peer->rssi && - tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH && - tdls_peer->tdls_status == TDLS_NOT_SETUP && - tdls_peer->failure_count < - MWIFIEX_TDLS_MAX_FAIL_COUNT) { - priv->check_tdls_tx = true; - tdls_peer->do_setup = true; - mwifiex_dbg(priv->adapter, INFO, - "check TDLS with peer=%pM\t" - "rssi=%d\n", tdls_peer->mac_addr, - tdls_peer->rssi); - } - } - spin_unlock_irqrestore(&priv->auto_tdls_lock, flags); - - mod_timer(&priv->auto_tdls_timer, - jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); -} - -void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv) -{ - setup_timer(&priv->auto_tdls_timer, mwifiex_check_auto_tdls, - (unsigned long)priv); - priv->auto_tdls_timer_active = true; - mod_timer(&priv->auto_tdls_timer, - jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); -} - -void mwifiex_clean_auto_tdls(struct mwifiex_private *priv) -{ - if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && - priv->adapter->auto_tdls && - priv->bss_type == MWIFIEX_BSS_TYPE_STA) { - priv->auto_tdls_timer_active = false; - del_timer(&priv->auto_tdls_timer); - mwifiex_flush_auto_tdls_list(priv); - } -} - -static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable) -{ - struct mwifiex_tdls_config config; - - config.enable = cpu_to_le16(enable); - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, - ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true); -} - -int mwifiex_config_tdls_enable(struct mwifiex_private *priv) -{ - return mwifiex_config_tdls(priv, true); -} - -int mwifiex_config_tdls_disable(struct mwifiex_private *priv) -{ - return mwifiex_config_tdls(priv, false); -} - -int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv) -{ - struct mwifiex_tdls_config_cs_params config_tdls_cs_params; - - config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME; - config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK; - config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK; - - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, - ACT_TDLS_CS_PARAMS, 0, - &config_tdls_cs_params, true); -} - -int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac) -{ - struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params; - - ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac); - - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, - ACT_TDLS_CS_STOP, 0, - &stop_tdls_cs_params, true); -} - -int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, - u8 primary_chan, u8 second_chan_offset, u8 band) -{ - struct mwifiex_tdls_init_cs_params start_tdls_cs_params; - - ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac); - start_tdls_cs_params.primary_chan = primary_chan; - start_tdls_cs_params.second_chan_offset = second_chan_offset; - start_tdls_cs_params.band = band; - - start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME); - start_tdls_cs_params.switch_timeout = - cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT); - start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS; - start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY; - - return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, - ACT_TDLS_CS_INIT, 0, - &start_tdls_cs_params, true); -} |