root/drivers/net/wireless/marvell/mwifiex/tdls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mwifiex_restore_tdls_packets
  2. mwifiex_hold_tdls_packets
  3. mwifiex_tdls_append_rates_ie
  4. mwifiex_tdls_add_aid
  5. mwifiex_tdls_add_vht_capab
  6. mwifiex_tdls_add_ht_oper
  7. mwifiex_tdls_add_vht_oper
  8. mwifiex_tdls_add_ext_capab
  9. mwifiex_tdls_add_qos_capab
  10. mwifiex_tdls_add_wmm_param_ie
  11. mwifiex_add_wmm_info_ie
  12. mwifiex_tdls_add_bss_co_2040
  13. mwifiex_tdls_add_supported_chan
  14. mwifiex_tdls_add_oper_class
  15. mwifiex_prep_tdls_encap_data
  16. mwifiex_tdls_add_link_ie
  17. mwifiex_send_tdls_data_frame
  18. mwifiex_construct_tdls_action_frame
  19. mwifiex_send_tdls_action_frame
  20. mwifiex_process_tdls_action_frame
  21. mwifiex_tdls_process_config_link
  22. mwifiex_tdls_process_create_link
  23. mwifiex_tdls_process_disable_link
  24. mwifiex_tdls_process_enable_link
  25. mwifiex_tdls_oper
  26. mwifiex_get_tdls_link_status
  27. mwifiex_get_tdls_list
  28. mwifiex_disable_all_tdls_links
  29. mwifiex_tdls_check_tx
  30. mwifiex_flush_auto_tdls_list
  31. mwifiex_add_auto_tdls_peer
  32. mwifiex_auto_tdls_update_peer_status
  33. mwifiex_auto_tdls_update_peer_signal
  34. mwifiex_check_auto_tdls
  35. mwifiex_setup_auto_tdls_timer
  36. mwifiex_clean_auto_tdls
  37. mwifiex_config_tdls
  38. mwifiex_config_tdls_enable
  39. mwifiex_config_tdls_disable
  40. mwifiex_config_tdls_cs_params
  41. mwifiex_stop_tdls_cs
  42. mwifiex_start_tdls_cs

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

/* [<][>][^][v][top][bottom][index][help] */