Linux-libre 3.16.85-gnu
[librecmc/linux-libre.git] / drivers / net / wireless / mwifiex / tdls.c
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
28 static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
29                                          const u8 *mac, u8 status)
30 {
31         struct mwifiex_ra_list_tbl *ra_list;
32         struct list_head *tid_list;
33         struct sk_buff *skb, *tmp;
34         struct mwifiex_txinfo *tx_info;
35         unsigned long flags;
36         u32 tid;
37         u8 tid_down;
38
39         dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
40         spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
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 (status == TDLS_SETUP_COMPLETE) {
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                         if (!list_empty(tid_list))
58                                 ra_list = list_first_entry(tid_list,
59                                               struct mwifiex_ra_list_tbl, list);
60                         else
61                                 ra_list = NULL;
62                         tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
63                 }
64
65                 if (!ra_list) {
66                         mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
67                         continue;
68                 }
69
70                 skb_queue_tail(&ra_list->skb_head, skb);
71
72                 ra_list->ba_pkt_count++;
73                 ra_list->total_pkt_count++;
74
75                 if (atomic_read(&priv->wmm.highest_queued_prio) <
76                                                        tos_to_tid_inv[tid_down])
77                         atomic_set(&priv->wmm.highest_queued_prio,
78                                    tos_to_tid_inv[tid_down]);
79
80                 atomic_inc(&priv->wmm.tx_pkts_queued);
81         }
82
83         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
84         return;
85 }
86
87 static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
88                                       const u8 *mac)
89 {
90         struct mwifiex_ra_list_tbl *ra_list;
91         struct list_head *ra_list_head;
92         struct sk_buff *skb, *tmp;
93         unsigned long flags;
94         int i;
95
96         dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
97         spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
98
99         for (i = 0; i < MAX_NUM_TID; i++) {
100                 if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
101                         ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
102                         list_for_each_entry(ra_list, ra_list_head, list) {
103                                 skb_queue_walk_safe(&ra_list->skb_head, skb,
104                                                     tmp) {
105                                         if (!ether_addr_equal(mac, skb->data))
106                                                 continue;
107                                         __skb_unlink(skb, &ra_list->skb_head);
108                                         atomic_dec(&priv->wmm.tx_pkts_queued);
109                                         ra_list->total_pkt_count--;
110                                         skb_queue_tail(&priv->tdls_txq, skb);
111                                 }
112                         }
113                 }
114         }
115
116         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
117         return;
118 }
119
120 /* This function appends rate TLV to scan config command. */
121 static int
122 mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
123                              struct sk_buff *skb)
124 {
125         u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;
126         u16 rates_size, supp_rates_size, ext_rates_size;
127
128         memset(rates, 0, sizeof(rates));
129         rates_size = mwifiex_get_supported_rates(priv, rates);
130
131         supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
132
133         if (skb_tailroom(skb) < rates_size + 4) {
134                 dev_err(priv->adapter->dev,
135                         "Insuffient space while adding rates\n");
136                 return -ENOMEM;
137         }
138
139         pos = skb_put(skb, supp_rates_size + 2);
140         *pos++ = WLAN_EID_SUPP_RATES;
141         *pos++ = supp_rates_size;
142         memcpy(pos, rates, supp_rates_size);
143
144         if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {
145                 ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;
146                 pos = skb_put(skb, ext_rates_size + 2);
147                 *pos++ = WLAN_EID_EXT_SUPP_RATES;
148                 *pos++ = ext_rates_size;
149                 memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,
150                        ext_rates_size);
151         }
152
153         return 0;
154 }
155
156 static void mwifiex_tdls_add_aid(struct mwifiex_private *priv,
157                                 struct sk_buff *skb)
158 {
159         struct ieee_types_assoc_rsp *assoc_rsp;
160         u8 *pos;
161
162         assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf;
163         pos = (void *)skb_put(skb, 4);
164         *pos++ = WLAN_EID_AID;
165         *pos++ = 2;
166         *pos++ = le16_to_cpu(assoc_rsp->a_id);
167
168         return;
169 }
170
171 static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,
172                                       struct sk_buff *skb)
173 {
174         struct ieee80211_vht_cap vht_cap;
175         u8 *pos;
176
177         pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
178         *pos++ = WLAN_EID_VHT_CAPABILITY;
179         *pos++ = sizeof(struct ieee80211_vht_cap);
180
181         memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));
182
183         mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);
184         memcpy(pos, &vht_cap, sizeof(vht_cap));
185
186         return 0;
187 }
188
189 static int
190 mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
191                          u8 vht_enabled, struct sk_buff *skb)
192 {
193         struct ieee80211_ht_operation *ht_oper;
194         struct mwifiex_sta_node *sta_ptr;
195         struct mwifiex_bssdescriptor *bss_desc =
196                                         &priv->curr_bss_params.bss_descriptor;
197         u8 *pos;
198
199         sta_ptr = mwifiex_get_sta_entry(priv, mac);
200         if (unlikely(!sta_ptr)) {
201                 dev_warn(priv->adapter->dev,
202                          "TDLS peer station not found in list\n");
203                 return -1;
204         }
205
206         pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2);
207         *pos++ = WLAN_EID_HT_OPERATION;
208         *pos++ = sizeof(struct ieee80211_ht_operation);
209         ht_oper = (void *)pos;
210
211         ht_oper->primary_chan = bss_desc->channel;
212
213         /* follow AP's channel bandwidth */
214         if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
215             bss_desc->bcn_ht_cap &&
216             ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
217                 ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
218
219         if (vht_enabled) {
220                 ht_oper->ht_param =
221                           mwifiex_get_sec_chan_offset(bss_desc->channel);
222                 ht_oper->ht_param |= BIT(2);
223         }
224
225         memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper,
226                sizeof(struct ieee80211_ht_operation));
227
228         return 0;
229 }
230
231 static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
232                                      const u8 *mac, struct sk_buff *skb)
233 {
234         struct mwifiex_bssdescriptor *bss_desc;
235         struct ieee80211_vht_operation *vht_oper;
236         struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL;
237         struct mwifiex_sta_node *sta_ptr;
238         struct mwifiex_adapter *adapter = priv->adapter;
239         u8 supp_chwd_set, peer_supp_chwd_set;
240         u8 *pos, ap_supp_chwd_set, chan_bw;
241         u16 mcs_map_user, mcs_map_resp, mcs_map_result;
242         u16 mcs_user, mcs_resp, nss;
243         u32 usr_vht_cap_info;
244
245         bss_desc = &priv->curr_bss_params.bss_descriptor;
246
247         sta_ptr = mwifiex_get_sta_entry(priv, mac);
248         if (unlikely(!sta_ptr)) {
249                 dev_warn(adapter->dev, "TDLS peer station not found in list\n");
250                 return -1;
251         }
252
253         if (!mwifiex_is_bss_in_11ac_mode(priv)) {
254                 if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
255                    WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
256                         dev_dbg(adapter->dev,
257                                 "TDLS peer doesn't support wider bandwitdh\n");
258                         return 0;
259                 }
260         } else {
261                 ap_vht_cap = bss_desc->bcn_vht_cap;
262         }
263
264         pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2);
265         *pos++ = WLAN_EID_VHT_OPERATION;
266         *pos++ = sizeof(struct ieee80211_vht_operation);
267         vht_oper = (struct ieee80211_vht_operation *)pos;
268
269         if (bss_desc->bss_band & BAND_A)
270                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
271         else
272                 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
273
274         /* find the minmum bandwith between AP/TDLS peers */
275         vht_cap = &sta_ptr->tdls_cap.vhtcap;
276         supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
277         peer_supp_chwd_set =
278                          GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info));
279         supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set);
280
281         /* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */
282
283         if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] &
284             WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
285                 ap_supp_chwd_set =
286                       GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info));
287                 supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set);
288         }
289
290         switch (supp_chwd_set) {
291         case IEEE80211_VHT_CHANWIDTH_80MHZ:
292                 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
293                 break;
294         case IEEE80211_VHT_CHANWIDTH_160MHZ:
295                 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
296                 break;
297         case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
298                 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
299                 break;
300         default:
301                 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
302                 break;
303         }
304
305         mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
306         mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
307         mcs_map_result = 0;
308
309         for (nss = 1; nss <= 8; nss++) {
310                 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
311                 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
312
313                 if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
314                     (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
315                         SET_VHTNSSMCS(mcs_map_result, nss,
316                                       IEEE80211_VHT_MCS_NOT_SUPPORTED);
317                 else
318                         SET_VHTNSSMCS(mcs_map_result, nss,
319                                       min_t(u16, mcs_user, mcs_resp));
320         }
321
322         vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result);
323
324         switch (vht_oper->chan_width) {
325         case IEEE80211_VHT_CHANWIDTH_80MHZ:
326                 chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
327                 break;
328         case IEEE80211_VHT_CHANWIDTH_160MHZ:
329                 chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ;
330                 break;
331         case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
332                 chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
333                 break;
334         default:
335                 chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
336                 break;
337         }
338         vht_oper->center_freq_seg1_idx =
339                         mwifiex_get_center_freq_index(priv, BAND_AAC,
340                                                       bss_desc->channel,
341                                                       chan_bw);
342
343         return 0;
344 }
345
346 static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,
347                                        struct sk_buff *skb)
348 {
349         struct ieee_types_extcap *extcap;
350
351         extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap));
352         extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;
353         extcap->ieee_hdr.len = 8;
354         memset(extcap->ext_capab, 0, 8);
355         extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;
356
357         if (priv->adapter->is_hw_11ac_capable)
358                 extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED;
359 }
360
361 static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)
362 {
363         u8 *pos = (void *)skb_put(skb, 3);
364
365         *pos++ = WLAN_EID_QOS_CAPA;
366         *pos++ = 1;
367         *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;
368 }
369
370 static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
371                                         const u8 *peer, u8 action_code,
372                                         u8 dialog_token,
373                                         u16 status_code, struct sk_buff *skb)
374 {
375         struct ieee80211_tdls_data *tf;
376         int ret;
377         u16 capab;
378         struct ieee80211_ht_cap *ht_cap;
379         u8 radio, *pos;
380
381         capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
382
383         tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
384         memcpy(tf->da, peer, ETH_ALEN);
385         memcpy(tf->sa, priv->curr_addr, ETH_ALEN);
386         tf->ether_type = cpu_to_be16(ETH_P_TDLS);
387         tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
388
389         switch (action_code) {
390         case WLAN_TDLS_SETUP_REQUEST:
391                 tf->category = WLAN_CATEGORY_TDLS;
392                 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
393                 skb_put(skb, sizeof(tf->u.setup_req));
394                 tf->u.setup_req.dialog_token = dialog_token;
395                 tf->u.setup_req.capability = cpu_to_le16(capab);
396                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
397                 if (ret) {
398                         dev_kfree_skb_any(skb);
399                         return ret;
400                 }
401
402                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
403                 *pos++ = WLAN_EID_HT_CAPABILITY;
404                 *pos++ = sizeof(struct ieee80211_ht_cap);
405                 ht_cap = (void *)pos;
406                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
407                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
408                 if (ret) {
409                         dev_kfree_skb_any(skb);
410                         return ret;
411                 }
412
413                 if (priv->adapter->is_hw_11ac_capable) {
414                         ret = mwifiex_tdls_add_vht_capab(priv, skb);
415                         if (ret) {
416                                 dev_kfree_skb_any(skb);
417                                 return ret;
418                         }
419                         mwifiex_tdls_add_aid(priv, skb);
420                 }
421
422                 mwifiex_tdls_add_ext_capab(priv, skb);
423                 mwifiex_tdls_add_qos_capab(skb);
424                 break;
425
426         case WLAN_TDLS_SETUP_RESPONSE:
427                 tf->category = WLAN_CATEGORY_TDLS;
428                 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
429                 skb_put(skb, sizeof(tf->u.setup_resp));
430                 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
431                 tf->u.setup_resp.dialog_token = dialog_token;
432                 tf->u.setup_resp.capability = cpu_to_le16(capab);
433                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
434                 if (ret) {
435                         dev_kfree_skb_any(skb);
436                         return ret;
437                 }
438
439                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
440                 *pos++ = WLAN_EID_HT_CAPABILITY;
441                 *pos++ = sizeof(struct ieee80211_ht_cap);
442                 ht_cap = (void *)pos;
443                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
444                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
445                 if (ret) {
446                         dev_kfree_skb_any(skb);
447                         return ret;
448                 }
449
450                 if (priv->adapter->is_hw_11ac_capable) {
451                         ret = mwifiex_tdls_add_vht_capab(priv, skb);
452                         if (ret) {
453                                 dev_kfree_skb_any(skb);
454                                 return ret;
455                         }
456                         mwifiex_tdls_add_aid(priv, skb);
457                 }
458
459                 mwifiex_tdls_add_ext_capab(priv, skb);
460                 mwifiex_tdls_add_qos_capab(skb);
461                 break;
462
463         case WLAN_TDLS_SETUP_CONFIRM:
464                 tf->category = WLAN_CATEGORY_TDLS;
465                 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
466                 skb_put(skb, sizeof(tf->u.setup_cfm));
467                 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
468                 tf->u.setup_cfm.dialog_token = dialog_token;
469                 if (priv->adapter->is_hw_11ac_capable) {
470                         ret = mwifiex_tdls_add_vht_oper(priv, peer, skb);
471                         if (ret) {
472                                 dev_kfree_skb_any(skb);
473                                 return ret;
474                         }
475                         ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb);
476                         if (ret) {
477                                 dev_kfree_skb_any(skb);
478                                 return ret;
479                         }
480                 } else {
481                         ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb);
482                         if (ret) {
483                                 dev_kfree_skb_any(skb);
484                                 return ret;
485                         }
486                 }
487                 break;
488
489         case WLAN_TDLS_TEARDOWN:
490                 tf->category = WLAN_CATEGORY_TDLS;
491                 tf->action_code = WLAN_TDLS_TEARDOWN;
492                 skb_put(skb, sizeof(tf->u.teardown));
493                 tf->u.teardown.reason_code = cpu_to_le16(status_code);
494                 break;
495
496         case WLAN_TDLS_DISCOVERY_REQUEST:
497                 tf->category = WLAN_CATEGORY_TDLS;
498                 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
499                 skb_put(skb, sizeof(tf->u.discover_req));
500                 tf->u.discover_req.dialog_token = dialog_token;
501                 break;
502         default:
503                 dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
504                 return -EINVAL;
505         }
506
507         return 0;
508 }
509
510 static void
511 mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
512                          const u8 *peer, const u8 *bssid)
513 {
514         struct ieee80211_tdls_lnkie *lnkid;
515
516         lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
517         lnkid->ie_type = WLAN_EID_LINK_ID;
518         lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -
519                         sizeof(struct ieee_types_header);
520
521         memcpy(lnkid->bssid, bssid, ETH_ALEN);
522         memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
523         memcpy(lnkid->resp_sta, peer, ETH_ALEN);
524 }
525
526 int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
527                                  u8 action_code, u8 dialog_token,
528                                  u16 status_code, const u8 *extra_ies,
529                                  size_t extra_ies_len)
530 {
531         struct sk_buff *skb;
532         struct mwifiex_txinfo *tx_info;
533         struct timeval tv;
534         int ret;
535         u16 skb_len;
536
537         skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
538                   max(sizeof(struct ieee80211_mgmt),
539                       sizeof(struct ieee80211_tdls_data)) +
540                   MWIFIEX_MGMT_FRAME_HEADER_SIZE +
541                   MWIFIEX_SUPPORTED_RATES +
542                   3 + /* Qos Info */
543                   sizeof(struct ieee_types_extcap) +
544                   sizeof(struct ieee80211_ht_cap) +
545                   sizeof(struct ieee_types_bss_co_2040) +
546                   sizeof(struct ieee80211_ht_operation) +
547                   sizeof(struct ieee80211_tdls_lnkie) +
548                   extra_ies_len;
549
550         if (priv->adapter->is_hw_11ac_capable)
551                 skb_len += sizeof(struct ieee_types_vht_cap) +
552                            sizeof(struct ieee_types_vht_oper) +
553                            sizeof(struct ieee_types_aid);
554
555         skb = dev_alloc_skb(skb_len);
556         if (!skb) {
557                 dev_err(priv->adapter->dev,
558                         "allocate skb failed for management frame\n");
559                 return -ENOMEM;
560         }
561         skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
562
563         switch (action_code) {
564         case WLAN_TDLS_SETUP_REQUEST:
565         case WLAN_TDLS_SETUP_CONFIRM:
566         case WLAN_TDLS_TEARDOWN:
567         case WLAN_TDLS_DISCOVERY_REQUEST:
568                 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
569                                                    dialog_token, status_code,
570                                                    skb);
571                 if (ret) {
572                         dev_kfree_skb_any(skb);
573                         return ret;
574                 }
575                 if (extra_ies_len)
576                         memcpy(skb_put(skb, extra_ies_len), extra_ies,
577                                extra_ies_len);
578                 mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,
579                                          priv->cfg_bssid);
580                 break;
581         case WLAN_TDLS_SETUP_RESPONSE:
582                 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
583                                                    dialog_token, status_code,
584                                                    skb);
585                 if (ret) {
586                         dev_kfree_skb_any(skb);
587                         return ret;
588                 }
589                 if (extra_ies_len)
590                         memcpy(skb_put(skb, extra_ies_len), extra_ies,
591                                extra_ies_len);
592                 mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
593                                          priv->cfg_bssid);
594                 break;
595         }
596
597         switch (action_code) {
598         case WLAN_TDLS_SETUP_REQUEST:
599         case WLAN_TDLS_SETUP_RESPONSE:
600                 skb->priority = MWIFIEX_PRIO_BK;
601                 break;
602         default:
603                 skb->priority = MWIFIEX_PRIO_VI;
604                 break;
605         }
606
607         tx_info = MWIFIEX_SKB_TXCB(skb);
608         memset(tx_info, 0, sizeof(*tx_info));
609         tx_info->bss_num = priv->bss_num;
610         tx_info->bss_type = priv->bss_type;
611
612         do_gettimeofday(&tv);
613         skb->tstamp = timeval_to_ktime(tv);
614         mwifiex_queue_tx_pkt(priv, skb);
615
616         return 0;
617 }
618
619 static int
620 mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
621                                     const u8 *peer,
622                                     u8 action_code, u8 dialog_token,
623                                     u16 status_code, struct sk_buff *skb)
624 {
625         struct ieee80211_mgmt *mgmt;
626         u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
627         int ret;
628         u16 capab;
629         struct ieee80211_ht_cap *ht_cap;
630         u8 radio, *pos;
631
632         capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
633
634         mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u));
635
636         memset(mgmt, 0, 24);
637         memcpy(mgmt->da, peer, ETH_ALEN);
638         memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);
639         memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
640         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
641                                           IEEE80211_STYPE_ACTION);
642
643         /* add address 4 */
644         pos = skb_put(skb, ETH_ALEN);
645
646         switch (action_code) {
647         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
648                 skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
649                 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
650                 mgmt->u.action.u.tdls_discover_resp.action_code =
651                                               WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
652                 mgmt->u.action.u.tdls_discover_resp.dialog_token =
653                                                                    dialog_token;
654                 mgmt->u.action.u.tdls_discover_resp.capability =
655                                                              cpu_to_le16(capab);
656                 /* move back for addr4 */
657                 memmove(pos + ETH_ALEN, &mgmt->u.action.category,
658                         sizeof(mgmt->u.action.u.tdls_discover_resp));
659                 /* init address 4 */
660                 memcpy(pos, bc_addr, ETH_ALEN);
661
662                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
663                 if (ret) {
664                         dev_kfree_skb_any(skb);
665                         return ret;
666                 }
667
668                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
669                 *pos++ = WLAN_EID_HT_CAPABILITY;
670                 *pos++ = sizeof(struct ieee80211_ht_cap);
671                 ht_cap = (void *)pos;
672                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
673                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
674                 if (ret) {
675                         dev_kfree_skb_any(skb);
676                         return ret;
677                 }
678
679                 if (priv->adapter->is_hw_11ac_capable) {
680                         ret = mwifiex_tdls_add_vht_capab(priv, skb);
681                         if (ret) {
682                                 dev_kfree_skb_any(skb);
683                                 return ret;
684                         }
685                         mwifiex_tdls_add_aid(priv, skb);
686                 }
687
688                 mwifiex_tdls_add_ext_capab(priv, skb);
689                 mwifiex_tdls_add_qos_capab(skb);
690                 break;
691         default:
692                 dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
693                 return -EINVAL;
694         }
695
696         return 0;
697 }
698
699 int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
700                                    u8 action_code, u8 dialog_token,
701                                    u16 status_code, const u8 *extra_ies,
702                                    size_t extra_ies_len)
703 {
704         struct sk_buff *skb;
705         struct mwifiex_txinfo *tx_info;
706         struct timeval tv;
707         u8 *pos;
708         u32 pkt_type, tx_control;
709         u16 pkt_len, skb_len;
710
711         skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
712                   max(sizeof(struct ieee80211_mgmt),
713                       sizeof(struct ieee80211_tdls_data)) +
714                   MWIFIEX_MGMT_FRAME_HEADER_SIZE +
715                   MWIFIEX_SUPPORTED_RATES +
716                   sizeof(struct ieee_types_extcap) +
717                   sizeof(struct ieee80211_ht_cap) +
718                   sizeof(struct ieee_types_bss_co_2040) +
719                   sizeof(struct ieee80211_ht_operation) +
720                   sizeof(struct ieee80211_tdls_lnkie) +
721                   extra_ies_len +
722                   3 + /* Qos Info */
723                   ETH_ALEN; /* Address4 */
724
725         if (priv->adapter->is_hw_11ac_capable)
726                 skb_len += sizeof(struct ieee_types_vht_cap) +
727                            sizeof(struct ieee_types_vht_oper) +
728                            sizeof(struct ieee_types_aid);
729
730         skb = dev_alloc_skb(skb_len);
731         if (!skb) {
732                 dev_err(priv->adapter->dev,
733                         "allocate skb failed for management frame\n");
734                 return -ENOMEM;
735         }
736
737         skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
738
739         pkt_type = PKT_TYPE_MGMT;
740         tx_control = 0;
741         pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
742         memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
743         memcpy(pos, &pkt_type, sizeof(pkt_type));
744         memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
745
746         if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,
747                                                 dialog_token, status_code,
748                                                 skb)) {
749                 dev_kfree_skb_any(skb);
750                 return -EINVAL;
751         }
752
753         if (extra_ies_len)
754                 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
755
756         /* the TDLS link IE is always added last we are the responder */
757
758         mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
759                                  priv->cfg_bssid);
760
761         skb->priority = MWIFIEX_PRIO_VI;
762
763         tx_info = MWIFIEX_SKB_TXCB(skb);
764         memset(tx_info, 0, sizeof(*tx_info));
765         tx_info->bss_num = priv->bss_num;
766         tx_info->bss_type = priv->bss_type;
767         tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
768
769         pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);
770         memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,
771                sizeof(pkt_len));
772         do_gettimeofday(&tv);
773         skb->tstamp = timeval_to_ktime(tv);
774         mwifiex_queue_tx_pkt(priv, skb);
775
776         return 0;
777 }
778
779 /* This function process tdls action frame from peer.
780  * Peer capabilities are stored into station node structure.
781  */
782 void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
783                                        u8 *buf, int len)
784 {
785         struct mwifiex_sta_node *sta_ptr;
786         u8 *peer, *pos, *end;
787         u8 i, action, basic;
788         int ie_len = 0;
789
790         if (len < (sizeof(struct ethhdr) + 3))
791                 return;
792         if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
793                 return;
794         if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
795                 return;
796
797         peer = buf + ETH_ALEN;
798         action = *(buf + sizeof(struct ethhdr) + 2);
799
800         /* just handle TDLS setup request/response/confirm */
801         if (action > WLAN_TDLS_SETUP_CONFIRM)
802                 return;
803
804         dev_dbg(priv->adapter->dev,
805                 "rx:tdls action: peer=%pM, action=%d\n", peer, action);
806
807         sta_ptr = mwifiex_add_sta_entry(priv, peer);
808         if (!sta_ptr)
809                 return;
810
811         switch (action) {
812         case WLAN_TDLS_SETUP_REQUEST:
813                 if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
814                         return;
815
816                 pos = buf + sizeof(struct ethhdr) + 4;
817                 /* payload 1+ category 1 + action 1 + dialog 1 */
818                 sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
819                 ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
820                 pos += 2;
821                 break;
822
823         case WLAN_TDLS_SETUP_RESPONSE:
824                 if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
825                         return;
826                 /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
827                 pos = buf + sizeof(struct ethhdr) + 6;
828                 sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
829                 ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
830                 pos += 2;
831                 break;
832
833         case WLAN_TDLS_SETUP_CONFIRM:
834                 if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
835                         return;
836                 pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
837                 ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
838                 break;
839         default:
840                 dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n");
841                 return;
842         }
843
844         for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
845                 if (pos + 2 + pos[1] > end)
846                         break;
847
848                 switch (*pos) {
849                 case WLAN_EID_SUPP_RATES:
850                         if (pos[1] > 32)
851                                 return;
852                         sta_ptr->tdls_cap.rates_len = pos[1];
853                         for (i = 0; i < pos[1]; i++)
854                                 sta_ptr->tdls_cap.rates[i] = pos[i + 2];
855                         break;
856
857                 case WLAN_EID_EXT_SUPP_RATES:
858                         if (pos[1] > 32)
859                                 return;
860                         basic = sta_ptr->tdls_cap.rates_len;
861                         if (pos[1] > 32 - basic)
862                                 return;
863                         for (i = 0; i < pos[1]; i++)
864                                 sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
865                         sta_ptr->tdls_cap.rates_len += pos[1];
866                         break;
867                 case WLAN_EID_HT_CAPABILITY:
868                         if (pos > end - sizeof(struct ieee80211_ht_cap) - 2)
869                                 return;
870                         if (pos[1] != sizeof(struct ieee80211_ht_cap))
871                                 return;
872                         /* copy the ie's value into ht_capb*/
873                         memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2,
874                                sizeof(struct ieee80211_ht_cap));
875                         sta_ptr->is_11n_enabled = 1;
876                         break;
877                 case WLAN_EID_HT_OPERATION:
878                         if (pos > end -
879                             sizeof(struct ieee80211_ht_operation) - 2)
880                                 return;
881                         if (pos[1] != sizeof(struct ieee80211_ht_operation))
882                                 return;
883                         /* copy the ie's value into ht_oper*/
884                         memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2,
885                                sizeof(struct ieee80211_ht_operation));
886                         break;
887                 case WLAN_EID_BSS_COEX_2040:
888                         if (pos > end - 3)
889                                 return;
890                         if (pos[1] != 1)
891                                 return;
892                         sta_ptr->tdls_cap.coex_2040 = pos[2];
893                         break;
894                 case WLAN_EID_EXT_CAPABILITY:
895                         if (pos > end - sizeof(struct ieee_types_header))
896                                 return;
897                         if (pos[1] < sizeof(struct ieee_types_header))
898                                 return;
899                         if (pos[1] > 8)
900                                 return;
901                         memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
902                                sizeof(struct ieee_types_header) +
903                                min_t(u8, pos[1], 8));
904                         break;
905                 case WLAN_EID_RSN:
906                         if (pos > end - sizeof(struct ieee_types_header))
907                                 return;
908                         if (pos[1] < sizeof(struct ieee_types_header))
909                                 return;
910                         if (pos[1] > IEEE_MAX_IE_SIZE -
911                             sizeof(struct ieee_types_header))
912                                 return;
913                         memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
914                                sizeof(struct ieee_types_header) +
915                                min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
916                                      sizeof(struct ieee_types_header)));
917                         break;
918                 case WLAN_EID_QOS_CAPA:
919                         if (pos > end - 3)
920                                 return;
921                         if (pos[1] != 1)
922                                 return;
923                         sta_ptr->tdls_cap.qos_info = pos[2];
924                         break;
925                 case WLAN_EID_VHT_OPERATION:
926                         if (priv->adapter->is_hw_11ac_capable) {
927                                 if (pos > end -
928                                     sizeof(struct ieee80211_vht_operation) - 2)
929                                         return;
930                                 if (pos[1] !=
931                                     sizeof(struct ieee80211_vht_operation))
932                                         return;
933                                 /* copy the ie's value into vhtoper*/
934                                 memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2,
935                                        sizeof(struct ieee80211_vht_operation));
936                         }
937                         break;
938                 case WLAN_EID_VHT_CAPABILITY:
939                         if (priv->adapter->is_hw_11ac_capable) {
940                                 if (pos > end -
941                                     sizeof(struct ieee80211_vht_cap) - 2)
942                                         return;
943                                 if (pos[1] != sizeof(struct ieee80211_vht_cap))
944                                         return;
945                                 /* copy the ie's value into vhtcap*/
946                                 memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2,
947                                        sizeof(struct ieee80211_vht_cap));
948                                 sta_ptr->is_11ac_enabled = 1;
949                         }
950                         break;
951                 case WLAN_EID_AID:
952                         if (priv->adapter->is_hw_11ac_capable) {
953                                 if (pos > end - 4)
954                                         return;
955                                 if (pos[1] != 2)
956                                         return;
957                                 sta_ptr->tdls_cap.aid =
958                                               le16_to_cpu(*(__le16 *)(pos + 2));
959                         }
960                         break;
961                 default:
962                         break;
963                 }
964         }
965
966         return;
967 }
968
969 static int
970 mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
971 {
972         struct mwifiex_sta_node *sta_ptr;
973         struct mwifiex_ds_tdls_oper tdls_oper;
974
975         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
976         sta_ptr = mwifiex_get_sta_entry(priv, peer);
977
978         if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
979                 dev_err(priv->adapter->dev,
980                         "link absent for peer %pM; cannot config\n", peer);
981                 return -EINVAL;
982         }
983
984         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
985         tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
986         return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
987                                 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
988 }
989
990 static int
991 mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
992 {
993         struct mwifiex_sta_node *sta_ptr;
994         struct mwifiex_ds_tdls_oper tdls_oper;
995
996         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
997         sta_ptr = mwifiex_get_sta_entry(priv, peer);
998
999         if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
1000                 dev_dbg(priv->adapter->dev,
1001                         "Setup already in progress for peer %pM\n", peer);
1002                 return 0;
1003         }
1004
1005         sta_ptr = mwifiex_add_sta_entry(priv, peer);
1006         if (!sta_ptr)
1007                 return -ENOMEM;
1008
1009         sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;
1010         mwifiex_hold_tdls_packets(priv, peer);
1011         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
1012         tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
1013         return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1014                                 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
1015 }
1016
1017 static int
1018 mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
1019 {
1020         struct mwifiex_sta_node *sta_ptr;
1021         struct mwifiex_ds_tdls_oper tdls_oper;
1022         unsigned long flags;
1023
1024         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1025         sta_ptr = mwifiex_get_sta_entry(priv, peer);
1026
1027         if (sta_ptr) {
1028                 if (sta_ptr->is_11n_enabled) {
1029                         mwifiex_11n_cleanup_reorder_tbl(priv);
1030                         spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1031                                           flags);
1032                         mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1033                         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1034                                                flags);
1035                 }
1036                 mwifiex_del_sta_entry(priv, peer);
1037         }
1038
1039         mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
1040         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
1041         tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
1042         return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1043                                 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
1044 }
1045
1046 static int
1047 mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
1048 {
1049         struct mwifiex_sta_node *sta_ptr;
1050         struct ieee80211_mcs_info mcs;
1051         unsigned long flags;
1052         int i;
1053
1054         sta_ptr = mwifiex_get_sta_entry(priv, peer);
1055
1056         if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
1057                 dev_dbg(priv->adapter->dev,
1058                         "tdls: enable link %pM success\n", peer);
1059
1060                 sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
1061
1062                 mcs = sta_ptr->tdls_cap.ht_capb.mcs;
1063                 if (mcs.rx_mask[0] != 0xff)
1064                         sta_ptr->is_11n_enabled = true;
1065                 if (sta_ptr->is_11n_enabled) {
1066                         if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &
1067                             IEEE80211_HT_CAP_MAX_AMSDU)
1068                                 sta_ptr->max_amsdu =
1069                                         MWIFIEX_TX_DATA_BUF_SIZE_8K;
1070                         else
1071                                 sta_ptr->max_amsdu =
1072                                         MWIFIEX_TX_DATA_BUF_SIZE_4K;
1073
1074                         for (i = 0; i < MAX_NUM_TID; i++)
1075                                 sta_ptr->ampdu_sta[i] =
1076                                               priv->aggr_prio_tbl[i].ampdu_user;
1077                 } else {
1078                         for (i = 0; i < MAX_NUM_TID; i++)
1079                                 sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
1080                 }
1081
1082                 memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
1083                 mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
1084         } else {
1085                 dev_dbg(priv->adapter->dev,
1086                         "tdls: enable link %pM failed\n", peer);
1087                 if (sta_ptr) {
1088                         mwifiex_11n_cleanup_reorder_tbl(priv);
1089                         spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1090                                           flags);
1091                         mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1092                         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1093                                                flags);
1094                         mwifiex_del_sta_entry(priv, peer);
1095                 }
1096                 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
1097
1098                 return -1;
1099         }
1100
1101         return 0;
1102 }
1103
1104 int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action)
1105 {
1106         switch (action) {
1107         case MWIFIEX_TDLS_ENABLE_LINK:
1108                 return mwifiex_tdls_process_enable_link(priv, peer);
1109         case MWIFIEX_TDLS_DISABLE_LINK:
1110                 return mwifiex_tdls_process_disable_link(priv, peer);
1111         case MWIFIEX_TDLS_CREATE_LINK:
1112                 return mwifiex_tdls_process_create_link(priv, peer);
1113         case MWIFIEX_TDLS_CONFIG_LINK:
1114                 return mwifiex_tdls_process_config_link(priv, peer);
1115         }
1116         return 0;
1117 }
1118
1119 int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)
1120 {
1121         struct mwifiex_sta_node *sta_ptr;
1122
1123         sta_ptr = mwifiex_get_sta_entry(priv, mac);
1124         if (sta_ptr)
1125                 return sta_ptr->tdls_status;
1126
1127         return TDLS_NOT_SETUP;
1128 }
1129
1130 void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
1131 {
1132         struct mwifiex_sta_node *sta_ptr;
1133         struct mwifiex_ds_tdls_oper tdls_oper;
1134         unsigned long flags;
1135
1136         if (list_empty(&priv->sta_list))
1137                 return;
1138
1139         list_for_each_entry(sta_ptr, &priv->sta_list, list) {
1140                 memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1141
1142                 if (sta_ptr->is_11n_enabled) {
1143                         mwifiex_11n_cleanup_reorder_tbl(priv);
1144                         spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1145                                           flags);
1146                         mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1147                         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1148                                                flags);
1149                 }
1150
1151                 mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,
1152                                              TDLS_LINK_TEARDOWN);
1153                 memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);
1154                 tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
1155                 if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1156                                      HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
1157                         dev_warn(priv->adapter->dev,
1158                                  "Disable link failed for TDLS peer %pM",
1159                                  sta_ptr->mac_addr);
1160         }
1161
1162         mwifiex_del_all_sta_list(priv);
1163 }