blob: df9704de07150d82887de1db36c99fd15d3933f7 [file] [log] [blame]
Avinash Patilb23bce22014-02-07 16:27:32 -08001/* 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"
Avinash Patil5f2caaf2014-02-07 16:27:33 -080019#include "wmm.h"
Avinash Patil429d90d2014-02-07 16:27:34 -080020#include "11n.h"
21#include "11n_rxreorder.h"
Avinash Patil5f6d5982014-02-07 16:30:39 -080022#include "11ac.h"
Avinash Patil5f2caaf2014-02-07 16:27:33 -080023
24#define TDLS_REQ_FIX_LEN 6
25#define TDLS_RESP_FIX_LEN 8
26#define TDLS_CONFIRM_FIX_LEN 6
Avinash Patil16fa5e62014-11-13 21:54:15 +053027#define MWIFIEX_TDLS_WMM_INFO_SIZE 7
Avinash Patilb23bce22014-02-07 16:27:32 -080028
Johannes Berg3b3a0162014-05-19 17:19:31 +020029static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
30 const u8 *mac, u8 status)
Avinash Patil56bd24a2014-02-07 16:30:35 -080031{
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 unsigned long flags;
37 u32 tid;
38 u8 tid_down;
39
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +053040 mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
Avinash Patil56bd24a2014-02-07 16:30:35 -080041 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
42
43 skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
44 if (!ether_addr_equal(mac, skb->data))
45 continue;
46
47 __skb_unlink(skb, &priv->tdls_txq);
48 tx_info = MWIFIEX_SKB_TXCB(skb);
49 tid = skb->priority;
50 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
51
Xinming Hu55a2c072015-06-22 19:06:14 +053052 if (mwifiex_is_tdls_link_setup(status)) {
Avinash Patil56bd24a2014-02-07 16:30:35 -080053 ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);
Avinash Patildaeb5bb2014-02-07 16:30:37 -080054 ra_list->tdls_link = true;
Avinash Patil56bd24a2014-02-07 16:30:35 -080055 tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
56 } else {
57 tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;
58 if (!list_empty(tid_list))
59 ra_list = list_first_entry(tid_list,
60 struct mwifiex_ra_list_tbl, list);
61 else
62 ra_list = NULL;
63 tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
64 }
65
66 if (!ra_list) {
67 mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
68 continue;
69 }
70
71 skb_queue_tail(&ra_list->skb_head, skb);
72
73 ra_list->ba_pkt_count++;
74 ra_list->total_pkt_count++;
75
76 if (atomic_read(&priv->wmm.highest_queued_prio) <
77 tos_to_tid_inv[tid_down])
78 atomic_set(&priv->wmm.highest_queued_prio,
79 tos_to_tid_inv[tid_down]);
80
81 atomic_inc(&priv->wmm.tx_pkts_queued);
82 }
83
84 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
85 return;
86}
87
Johannes Berg3b3a0162014-05-19 17:19:31 +020088static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
89 const u8 *mac)
Avinash Patil56bd24a2014-02-07 16:30:35 -080090{
91 struct mwifiex_ra_list_tbl *ra_list;
92 struct list_head *ra_list_head;
93 struct sk_buff *skb, *tmp;
94 unsigned long flags;
95 int i;
96
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +053097 mwifiex_dbg(priv->adapter, DATA, "%s: %pM\n", __func__, mac);
Avinash Patil56bd24a2014-02-07 16:30:35 -080098 spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
99
100 for (i = 0; i < MAX_NUM_TID; i++) {
101 if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
102 ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
103 list_for_each_entry(ra_list, ra_list_head, list) {
104 skb_queue_walk_safe(&ra_list->skb_head, skb,
105 tmp) {
106 if (!ether_addr_equal(mac, skb->data))
107 continue;
108 __skb_unlink(skb, &ra_list->skb_head);
109 atomic_dec(&priv->wmm.tx_pkts_queued);
110 ra_list->total_pkt_count--;
111 skb_queue_tail(&priv->tdls_txq, skb);
112 }
113 }
114 }
115 }
116
117 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
118 return;
119}
120
Avinash Patilb23bce22014-02-07 16:27:32 -0800121/* This function appends rate TLV to scan config command. */
122static int
123mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
124 struct sk_buff *skb)
125{
126 u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;
127 u16 rates_size, supp_rates_size, ext_rates_size;
128
129 memset(rates, 0, sizeof(rates));
130 rates_size = mwifiex_get_supported_rates(priv, rates);
131
132 supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
133
134 if (skb_tailroom(skb) < rates_size + 4) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530135 mwifiex_dbg(priv->adapter, ERROR,
136 "Insuffient space while adding rates\n");
Avinash Patilb23bce22014-02-07 16:27:32 -0800137 return -ENOMEM;
138 }
139
140 pos = skb_put(skb, supp_rates_size + 2);
141 *pos++ = WLAN_EID_SUPP_RATES;
142 *pos++ = supp_rates_size;
143 memcpy(pos, rates, supp_rates_size);
144
145 if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {
146 ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;
147 pos = skb_put(skb, ext_rates_size + 2);
148 *pos++ = WLAN_EID_EXT_SUPP_RATES;
149 *pos++ = ext_rates_size;
150 memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,
151 ext_rates_size);
152 }
153
154 return 0;
155}
156
Avinash Patil5f6d5982014-02-07 16:30:39 -0800157static void mwifiex_tdls_add_aid(struct mwifiex_private *priv,
158 struct sk_buff *skb)
159{
160 struct ieee_types_assoc_rsp *assoc_rsp;
161 u8 *pos;
162
163 assoc_rsp = (struct ieee_types_assoc_rsp *)&priv->assoc_rsp_buf;
164 pos = (void *)skb_put(skb, 4);
165 *pos++ = WLAN_EID_AID;
166 *pos++ = 2;
Xinming Hu3afafd62015-07-22 04:53:42 -0700167 memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id));
Avinash Patil5f6d5982014-02-07 16:30:39 -0800168
169 return;
170}
171
172static int mwifiex_tdls_add_vht_capab(struct mwifiex_private *priv,
173 struct sk_buff *skb)
174{
175 struct ieee80211_vht_cap vht_cap;
176 u8 *pos;
177
178 pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
179 *pos++ = WLAN_EID_VHT_CAPABILITY;
180 *pos++ = sizeof(struct ieee80211_vht_cap);
181
182 memset(&vht_cap, 0, sizeof(struct ieee80211_vht_cap));
183
184 mwifiex_fill_vht_cap_tlv(priv, &vht_cap, priv->curr_bss_params.band);
Dan Carpenterc42c65c2014-02-14 12:03:13 +0300185 memcpy(pos, &vht_cap, sizeof(vht_cap));
Avinash Patil5f6d5982014-02-07 16:30:39 -0800186
187 return 0;
188}
189
Avinash Patil396939f2014-05-06 22:02:45 -0700190static int
John W. Linvilleef1b0752014-05-22 14:21:12 -0400191mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
Avinash Patil396939f2014-05-06 22:02:45 -0700192 u8 vht_enabled, struct sk_buff *skb)
193{
194 struct ieee80211_ht_operation *ht_oper;
195 struct mwifiex_sta_node *sta_ptr;
196 struct mwifiex_bssdescriptor *bss_desc =
197 &priv->curr_bss_params.bss_descriptor;
198 u8 *pos;
199
200 sta_ptr = mwifiex_get_sta_entry(priv, mac);
201 if (unlikely(!sta_ptr)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530202 mwifiex_dbg(priv->adapter, ERROR,
203 "TDLS peer station not found in list\n");
Avinash Patil396939f2014-05-06 22:02:45 -0700204 return -1;
205 }
206
Aniket Nagarnaik2c3da962015-09-18 06:32:08 -0700207 if (!(le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info))) {
208 mwifiex_dbg(priv->adapter, WARN,
209 "TDLS peer doesn't support ht capabilities\n");
210 return 0;
211 }
212
Avinash Patil396939f2014-05-06 22:02:45 -0700213 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_operation) + 2);
214 *pos++ = WLAN_EID_HT_OPERATION;
215 *pos++ = sizeof(struct ieee80211_ht_operation);
216 ht_oper = (void *)pos;
217
218 ht_oper->primary_chan = bss_desc->channel;
219
220 /* follow AP's channel bandwidth */
221 if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
222 bss_desc->bcn_ht_cap &&
223 ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
224 ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
225
226 if (vht_enabled) {
227 ht_oper->ht_param =
228 mwifiex_get_sec_chan_offset(bss_desc->channel);
229 ht_oper->ht_param |= BIT(2);
230 }
231
232 memcpy(&sta_ptr->tdls_cap.ht_oper, ht_oper,
233 sizeof(struct ieee80211_ht_operation));
234
235 return 0;
236}
237
Avinash Patil5f6d5982014-02-07 16:30:39 -0800238static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
Johannes Berg3b3a0162014-05-19 17:19:31 +0200239 const u8 *mac, struct sk_buff *skb)
Avinash Patil5f6d5982014-02-07 16:30:39 -0800240{
241 struct mwifiex_bssdescriptor *bss_desc;
242 struct ieee80211_vht_operation *vht_oper;
243 struct ieee80211_vht_cap *vht_cap, *ap_vht_cap = NULL;
244 struct mwifiex_sta_node *sta_ptr;
245 struct mwifiex_adapter *adapter = priv->adapter;
246 u8 supp_chwd_set, peer_supp_chwd_set;
247 u8 *pos, ap_supp_chwd_set, chan_bw;
248 u16 mcs_map_user, mcs_map_resp, mcs_map_result;
249 u16 mcs_user, mcs_resp, nss;
250 u32 usr_vht_cap_info;
251
252 bss_desc = &priv->curr_bss_params.bss_descriptor;
253
254 sta_ptr = mwifiex_get_sta_entry(priv, mac);
255 if (unlikely(!sta_ptr)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530256 mwifiex_dbg(adapter, ERROR,
257 "TDLS peer station not found in list\n");
Avinash Patil5f6d5982014-02-07 16:30:39 -0800258 return -1;
259 }
260
Aniket Nagarnaik2c3da962015-09-18 06:32:08 -0700261 if (!(le32_to_cpu(sta_ptr->tdls_cap.vhtcap.vht_cap_info))) {
262 mwifiex_dbg(adapter, WARN,
263 "TDLS peer doesn't support vht capabilities\n");
264 return 0;
265 }
266
Avinash Patil5f6d5982014-02-07 16:30:39 -0800267 if (!mwifiex_is_bss_in_11ac_mode(priv)) {
268 if (sta_ptr->tdls_cap.extcap.ext_capab[7] &
269 WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530270 mwifiex_dbg(adapter, WARN,
271 "TDLS peer doesn't support wider bandwidth\n");
Avinash Patil5f6d5982014-02-07 16:30:39 -0800272 return 0;
273 }
274 } else {
275 ap_vht_cap = bss_desc->bcn_vht_cap;
276 }
277
278 pos = (void *)skb_put(skb, sizeof(struct ieee80211_vht_operation) + 2);
279 *pos++ = WLAN_EID_VHT_OPERATION;
280 *pos++ = sizeof(struct ieee80211_vht_operation);
281 vht_oper = (struct ieee80211_vht_operation *)pos;
282
283 if (bss_desc->bss_band & BAND_A)
284 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
285 else
286 usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
287
Geert Uytterhoevenf8df33d2016-03-14 16:31:10 +0100288 /* find the minimum bandwidth between AP/TDLS peers */
Avinash Patil5f6d5982014-02-07 16:30:39 -0800289 vht_cap = &sta_ptr->tdls_cap.vhtcap;
290 supp_chwd_set = GET_VHTCAP_CHWDSET(usr_vht_cap_info);
291 peer_supp_chwd_set =
292 GET_VHTCAP_CHWDSET(le32_to_cpu(vht_cap->vht_cap_info));
293 supp_chwd_set = min_t(u8, supp_chwd_set, peer_supp_chwd_set);
294
295 /* We need check AP's bandwidth when TDLS_WIDER_BANDWIDTH is off */
296
297 if (ap_vht_cap && sta_ptr->tdls_cap.extcap.ext_capab[7] &
298 WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) {
299 ap_supp_chwd_set =
300 GET_VHTCAP_CHWDSET(le32_to_cpu(ap_vht_cap->vht_cap_info));
301 supp_chwd_set = min_t(u8, supp_chwd_set, ap_supp_chwd_set);
302 }
303
304 switch (supp_chwd_set) {
305 case IEEE80211_VHT_CHANWIDTH_80MHZ:
306 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
307 break;
308 case IEEE80211_VHT_CHANWIDTH_160MHZ:
309 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
310 break;
311 case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
312 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
313 break;
314 default:
315 vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
316 break;
317 }
318
319 mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
320 mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
321 mcs_map_result = 0;
322
323 for (nss = 1; nss <= 8; nss++) {
324 mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
325 mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
326
327 if ((mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED) ||
328 (mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED))
329 SET_VHTNSSMCS(mcs_map_result, nss,
330 IEEE80211_VHT_MCS_NOT_SUPPORTED);
331 else
332 SET_VHTNSSMCS(mcs_map_result, nss,
333 min_t(u16, mcs_user, mcs_resp));
334 }
335
336 vht_oper->basic_mcs_set = cpu_to_le16(mcs_map_result);
337
338 switch (vht_oper->chan_width) {
339 case IEEE80211_VHT_CHANWIDTH_80MHZ:
340 chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
341 break;
342 case IEEE80211_VHT_CHANWIDTH_160MHZ:
343 chan_bw = IEEE80211_VHT_CHANWIDTH_160MHZ;
344 break;
345 case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
346 chan_bw = IEEE80211_VHT_CHANWIDTH_80MHZ;
347 break;
348 default:
349 chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
350 break;
351 }
352 vht_oper->center_freq_seg1_idx =
353 mwifiex_get_center_freq_index(priv, BAND_AAC,
354 bss_desc->channel,
355 chan_bw);
356
357 return 0;
358}
359
360static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv,
361 struct sk_buff *skb)
Avinash Patilb23bce22014-02-07 16:27:32 -0800362{
363 struct ieee_types_extcap *extcap;
364
365 extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap));
366 extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;
367 extcap->ieee_hdr.len = 8;
368 memset(extcap->ext_capab, 0, 8);
369 extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;
Xinming Hu20834342015-06-22 19:06:13 +0530370 extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH;
Avinash Patil5f6d5982014-02-07 16:30:39 -0800371
372 if (priv->adapter->is_hw_11ac_capable)
373 extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED;
Avinash Patilb23bce22014-02-07 16:27:32 -0800374}
375
376static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)
377{
378 u8 *pos = (void *)skb_put(skb, 3);
379
380 *pos++ = WLAN_EID_QOS_CAPA;
381 *pos++ = 1;
382 *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;
383}
384
Avinash Patil16fa5e62014-11-13 21:54:15 +0530385static void
386mwifiex_tdls_add_wmm_param_ie(struct mwifiex_private *priv, struct sk_buff *skb)
387{
388 struct ieee80211_wmm_param_ie *wmm;
389 u8 ac_vi[] = {0x42, 0x43, 0x5e, 0x00};
390 u8 ac_vo[] = {0x62, 0x32, 0x2f, 0x00};
391 u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00};
392 u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00};
393
394 wmm = (void *)skb_put(skb, sizeof(*wmm));
395 memset(wmm, 0, sizeof(*wmm));
396
397 wmm->element_id = WLAN_EID_VENDOR_SPECIFIC;
398 wmm->len = sizeof(*wmm) - 2;
399 wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */
400 wmm->oui[1] = 0x50;
401 wmm->oui[2] = 0xf2;
402 wmm->oui_type = 2; /* WME */
403 wmm->oui_subtype = 1; /* WME param */
404 wmm->version = 1; /* WME ver */
405 wmm->qos_info = 0; /* U-APSD not in use */
406
407 /* use default WMM AC parameters for TDLS link*/
408 memcpy(&wmm->ac[0], ac_be, sizeof(ac_be));
409 memcpy(&wmm->ac[1], ac_bk, sizeof(ac_bk));
410 memcpy(&wmm->ac[2], ac_vi, sizeof(ac_vi));
411 memcpy(&wmm->ac[3], ac_vo, sizeof(ac_vo));
412}
413
414static void
415mwifiex_add_wmm_info_ie(struct mwifiex_private *priv, struct sk_buff *skb,
416 u8 qosinfo)
417{
418 u8 *buf;
419
420 buf = (void *)skb_put(skb, MWIFIEX_TDLS_WMM_INFO_SIZE +
421 sizeof(struct ieee_types_header));
422
423 *buf++ = WLAN_EID_VENDOR_SPECIFIC;
424 *buf++ = 7; /* len */
425 *buf++ = 0x00; /* Microsoft OUI 00:50:F2 */
426 *buf++ = 0x50;
427 *buf++ = 0xf2;
428 *buf++ = 2; /* WME */
429 *buf++ = 0; /* WME info */
430 *buf++ = 1; /* WME ver */
431 *buf++ = qosinfo; /* U-APSD no in use */
432}
433
Avinash Patilb23bce22014-02-07 16:27:32 -0800434static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
Johannes Berg3b3a0162014-05-19 17:19:31 +0200435 const u8 *peer, u8 action_code,
436 u8 dialog_token,
437 u16 status_code, struct sk_buff *skb)
Avinash Patilb23bce22014-02-07 16:27:32 -0800438{
439 struct ieee80211_tdls_data *tf;
440 int ret;
441 u16 capab;
442 struct ieee80211_ht_cap *ht_cap;
443 u8 radio, *pos;
444
445 capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
446
447 tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
448 memcpy(tf->da, peer, ETH_ALEN);
449 memcpy(tf->sa, priv->curr_addr, ETH_ALEN);
450 tf->ether_type = cpu_to_be16(ETH_P_TDLS);
451 tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
452
453 switch (action_code) {
454 case WLAN_TDLS_SETUP_REQUEST:
455 tf->category = WLAN_CATEGORY_TDLS;
456 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
457 skb_put(skb, sizeof(tf->u.setup_req));
458 tf->u.setup_req.dialog_token = dialog_token;
459 tf->u.setup_req.capability = cpu_to_le16(capab);
460 ret = mwifiex_tdls_append_rates_ie(priv, skb);
461 if (ret) {
462 dev_kfree_skb_any(skb);
463 return ret;
464 }
465
466 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
467 *pos++ = WLAN_EID_HT_CAPABILITY;
468 *pos++ = sizeof(struct ieee80211_ht_cap);
469 ht_cap = (void *)pos;
470 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
471 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
472 if (ret) {
473 dev_kfree_skb_any(skb);
474 return ret;
475 }
476
Avinash Patil5f6d5982014-02-07 16:30:39 -0800477 if (priv->adapter->is_hw_11ac_capable) {
478 ret = mwifiex_tdls_add_vht_capab(priv, skb);
479 if (ret) {
480 dev_kfree_skb_any(skb);
481 return ret;
482 }
483 mwifiex_tdls_add_aid(priv, skb);
484 }
485
486 mwifiex_tdls_add_ext_capab(priv, skb);
Avinash Patilb23bce22014-02-07 16:27:32 -0800487 mwifiex_tdls_add_qos_capab(skb);
Avinash Patil16fa5e62014-11-13 21:54:15 +0530488 mwifiex_add_wmm_info_ie(priv, skb, 0);
Avinash Patilb23bce22014-02-07 16:27:32 -0800489 break;
490
491 case WLAN_TDLS_SETUP_RESPONSE:
492 tf->category = WLAN_CATEGORY_TDLS;
493 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
494 skb_put(skb, sizeof(tf->u.setup_resp));
495 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
496 tf->u.setup_resp.dialog_token = dialog_token;
497 tf->u.setup_resp.capability = cpu_to_le16(capab);
498 ret = mwifiex_tdls_append_rates_ie(priv, skb);
499 if (ret) {
500 dev_kfree_skb_any(skb);
501 return ret;
502 }
503
504 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
505 *pos++ = WLAN_EID_HT_CAPABILITY;
506 *pos++ = sizeof(struct ieee80211_ht_cap);
507 ht_cap = (void *)pos;
508 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
509 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
510 if (ret) {
511 dev_kfree_skb_any(skb);
512 return ret;
513 }
514
Avinash Patil5f6d5982014-02-07 16:30:39 -0800515 if (priv->adapter->is_hw_11ac_capable) {
516 ret = mwifiex_tdls_add_vht_capab(priv, skb);
517 if (ret) {
518 dev_kfree_skb_any(skb);
519 return ret;
520 }
521 mwifiex_tdls_add_aid(priv, skb);
522 }
523
524 mwifiex_tdls_add_ext_capab(priv, skb);
Avinash Patilb23bce22014-02-07 16:27:32 -0800525 mwifiex_tdls_add_qos_capab(skb);
Avinash Patil16fa5e62014-11-13 21:54:15 +0530526 mwifiex_add_wmm_info_ie(priv, skb, 0);
Avinash Patilb23bce22014-02-07 16:27:32 -0800527 break;
528
529 case WLAN_TDLS_SETUP_CONFIRM:
530 tf->category = WLAN_CATEGORY_TDLS;
531 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
532 skb_put(skb, sizeof(tf->u.setup_cfm));
533 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
534 tf->u.setup_cfm.dialog_token = dialog_token;
Avinash Patil16fa5e62014-11-13 21:54:15 +0530535
536 mwifiex_tdls_add_wmm_param_ie(priv, skb);
Avinash Patil5f6d5982014-02-07 16:30:39 -0800537 if (priv->adapter->is_hw_11ac_capable) {
538 ret = mwifiex_tdls_add_vht_oper(priv, peer, skb);
539 if (ret) {
540 dev_kfree_skb_any(skb);
541 return ret;
542 }
Avinash Patil396939f2014-05-06 22:02:45 -0700543 ret = mwifiex_tdls_add_ht_oper(priv, peer, 1, skb);
544 if (ret) {
545 dev_kfree_skb_any(skb);
546 return ret;
547 }
548 } else {
549 ret = mwifiex_tdls_add_ht_oper(priv, peer, 0, skb);
550 if (ret) {
551 dev_kfree_skb_any(skb);
552 return ret;
553 }
Avinash Patil5f6d5982014-02-07 16:30:39 -0800554 }
Avinash Patilb23bce22014-02-07 16:27:32 -0800555 break;
556
557 case WLAN_TDLS_TEARDOWN:
558 tf->category = WLAN_CATEGORY_TDLS;
559 tf->action_code = WLAN_TDLS_TEARDOWN;
560 skb_put(skb, sizeof(tf->u.teardown));
561 tf->u.teardown.reason_code = cpu_to_le16(status_code);
562 break;
563
564 case WLAN_TDLS_DISCOVERY_REQUEST:
565 tf->category = WLAN_CATEGORY_TDLS;
566 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
567 skb_put(skb, sizeof(tf->u.discover_req));
568 tf->u.discover_req.dialog_token = dialog_token;
569 break;
570 default:
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530571 mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
Avinash Patilb23bce22014-02-07 16:27:32 -0800572 return -EINVAL;
573 }
574
575 return 0;
576}
577
578static void
Johannes Berg3b3a0162014-05-19 17:19:31 +0200579mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
580 const u8 *peer, const u8 *bssid)
Avinash Patilb23bce22014-02-07 16:27:32 -0800581{
582 struct ieee80211_tdls_lnkie *lnkid;
583
584 lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
585 lnkid->ie_type = WLAN_EID_LINK_ID;
586 lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -
587 sizeof(struct ieee_types_header);
588
589 memcpy(lnkid->bssid, bssid, ETH_ALEN);
590 memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
591 memcpy(lnkid->resp_sta, peer, ETH_ALEN);
592}
593
Johannes Berg3b3a0162014-05-19 17:19:31 +0200594int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
595 u8 action_code, u8 dialog_token,
Avinash Patilb23bce22014-02-07 16:27:32 -0800596 u16 status_code, const u8 *extra_ies,
597 size_t extra_ies_len)
598{
599 struct sk_buff *skb;
600 struct mwifiex_txinfo *tx_info;
Avinash Patilb23bce22014-02-07 16:27:32 -0800601 int ret;
602 u16 skb_len;
603
604 skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
605 max(sizeof(struct ieee80211_mgmt),
606 sizeof(struct ieee80211_tdls_data)) +
607 MWIFIEX_MGMT_FRAME_HEADER_SIZE +
608 MWIFIEX_SUPPORTED_RATES +
609 3 + /* Qos Info */
610 sizeof(struct ieee_types_extcap) +
611 sizeof(struct ieee80211_ht_cap) +
612 sizeof(struct ieee_types_bss_co_2040) +
613 sizeof(struct ieee80211_ht_operation) +
614 sizeof(struct ieee80211_tdls_lnkie) +
Avinash Patil16fa5e62014-11-13 21:54:15 +0530615 sizeof(struct ieee80211_wmm_param_ie) +
Avinash Patilb23bce22014-02-07 16:27:32 -0800616 extra_ies_len;
617
Avinash Patil5f6d5982014-02-07 16:30:39 -0800618 if (priv->adapter->is_hw_11ac_capable)
619 skb_len += sizeof(struct ieee_types_vht_cap) +
620 sizeof(struct ieee_types_vht_oper) +
621 sizeof(struct ieee_types_aid);
622
Avinash Patilb23bce22014-02-07 16:27:32 -0800623 skb = dev_alloc_skb(skb_len);
624 if (!skb) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530625 mwifiex_dbg(priv->adapter, ERROR,
626 "allocate skb failed for management frame\n");
Avinash Patilb23bce22014-02-07 16:27:32 -0800627 return -ENOMEM;
628 }
629 skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
630
631 switch (action_code) {
632 case WLAN_TDLS_SETUP_REQUEST:
633 case WLAN_TDLS_SETUP_CONFIRM:
634 case WLAN_TDLS_TEARDOWN:
635 case WLAN_TDLS_DISCOVERY_REQUEST:
636 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
637 dialog_token, status_code,
638 skb);
639 if (ret) {
640 dev_kfree_skb_any(skb);
641 return ret;
642 }
643 if (extra_ies_len)
644 memcpy(skb_put(skb, extra_ies_len), extra_ies,
645 extra_ies_len);
646 mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,
647 priv->cfg_bssid);
648 break;
649 case WLAN_TDLS_SETUP_RESPONSE:
650 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
651 dialog_token, status_code,
652 skb);
653 if (ret) {
654 dev_kfree_skb_any(skb);
655 return ret;
656 }
657 if (extra_ies_len)
658 memcpy(skb_put(skb, extra_ies_len), extra_ies,
659 extra_ies_len);
660 mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
661 priv->cfg_bssid);
662 break;
663 }
664
665 switch (action_code) {
666 case WLAN_TDLS_SETUP_REQUEST:
667 case WLAN_TDLS_SETUP_RESPONSE:
668 skb->priority = MWIFIEX_PRIO_BK;
669 break;
670 default:
671 skb->priority = MWIFIEX_PRIO_VI;
672 break;
673 }
674
675 tx_info = MWIFIEX_SKB_TXCB(skb);
Amitkumar Karwar701a9e62014-07-01 14:39:04 -0700676 memset(tx_info, 0, sizeof(*tx_info));
Avinash Patilb23bce22014-02-07 16:27:32 -0800677 tx_info->bss_num = priv->bss_num;
678 tx_info->bss_type = priv->bss_type;
679
Thomas Gleixnerc64800e2014-06-12 08:31:34 +0100680 __net_timestamp(skb);
Avinash Patilb23bce22014-02-07 16:27:32 -0800681 mwifiex_queue_tx_pkt(priv, skb);
682
Xinming Hude651ce2016-02-23 05:16:16 -0800683 /* Delay 10ms to make sure tdls setup confirm/teardown frame
684 * is received by peer
685 */
686 if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
687 action_code == WLAN_TDLS_TEARDOWN)
688 msleep_interruptible(10);
689
Avinash Patilb23bce22014-02-07 16:27:32 -0800690 return 0;
691}
692
693static int
Johannes Berg3b3a0162014-05-19 17:19:31 +0200694mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
695 const u8 *peer,
Avinash Patilb23bce22014-02-07 16:27:32 -0800696 u8 action_code, u8 dialog_token,
697 u16 status_code, struct sk_buff *skb)
698{
699 struct ieee80211_mgmt *mgmt;
700 u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
701 int ret;
702 u16 capab;
703 struct ieee80211_ht_cap *ht_cap;
704 u8 radio, *pos;
705
706 capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
707
708 mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u));
709
710 memset(mgmt, 0, 24);
711 memcpy(mgmt->da, peer, ETH_ALEN);
712 memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);
713 memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
714 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
715 IEEE80211_STYPE_ACTION);
716
717 /* add address 4 */
718 pos = skb_put(skb, ETH_ALEN);
719
720 switch (action_code) {
721 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
722 skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
723 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
724 mgmt->u.action.u.tdls_discover_resp.action_code =
725 WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
726 mgmt->u.action.u.tdls_discover_resp.dialog_token =
727 dialog_token;
728 mgmt->u.action.u.tdls_discover_resp.capability =
729 cpu_to_le16(capab);
730 /* move back for addr4 */
731 memmove(pos + ETH_ALEN, &mgmt->u.action.category,
732 sizeof(mgmt->u.action.u.tdls_discover_resp));
733 /* init address 4 */
734 memcpy(pos, bc_addr, ETH_ALEN);
735
736 ret = mwifiex_tdls_append_rates_ie(priv, skb);
737 if (ret) {
738 dev_kfree_skb_any(skb);
739 return ret;
740 }
741
742 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
743 *pos++ = WLAN_EID_HT_CAPABILITY;
744 *pos++ = sizeof(struct ieee80211_ht_cap);
745 ht_cap = (void *)pos;
746 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
747 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
748 if (ret) {
749 dev_kfree_skb_any(skb);
750 return ret;
751 }
752
Avinash Patil5f6d5982014-02-07 16:30:39 -0800753 if (priv->adapter->is_hw_11ac_capable) {
754 ret = mwifiex_tdls_add_vht_capab(priv, skb);
755 if (ret) {
756 dev_kfree_skb_any(skb);
757 return ret;
758 }
759 mwifiex_tdls_add_aid(priv, skb);
760 }
761
762 mwifiex_tdls_add_ext_capab(priv, skb);
Avinash Patilb23bce22014-02-07 16:27:32 -0800763 mwifiex_tdls_add_qos_capab(skb);
764 break;
765 default:
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530766 mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS action frame type\n");
Avinash Patilb23bce22014-02-07 16:27:32 -0800767 return -EINVAL;
768 }
769
770 return 0;
771}
772
Johannes Berg3b3a0162014-05-19 17:19:31 +0200773int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
774 u8 action_code, u8 dialog_token,
775 u16 status_code, const u8 *extra_ies,
776 size_t extra_ies_len)
Avinash Patilb23bce22014-02-07 16:27:32 -0800777{
778 struct sk_buff *skb;
779 struct mwifiex_txinfo *tx_info;
Avinash Patilb23bce22014-02-07 16:27:32 -0800780 u8 *pos;
781 u32 pkt_type, tx_control;
782 u16 pkt_len, skb_len;
783
784 skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
785 max(sizeof(struct ieee80211_mgmt),
786 sizeof(struct ieee80211_tdls_data)) +
787 MWIFIEX_MGMT_FRAME_HEADER_SIZE +
788 MWIFIEX_SUPPORTED_RATES +
789 sizeof(struct ieee_types_extcap) +
790 sizeof(struct ieee80211_ht_cap) +
791 sizeof(struct ieee_types_bss_co_2040) +
792 sizeof(struct ieee80211_ht_operation) +
793 sizeof(struct ieee80211_tdls_lnkie) +
794 extra_ies_len +
795 3 + /* Qos Info */
796 ETH_ALEN; /* Address4 */
797
Avinash Patil5f6d5982014-02-07 16:30:39 -0800798 if (priv->adapter->is_hw_11ac_capable)
799 skb_len += sizeof(struct ieee_types_vht_cap) +
800 sizeof(struct ieee_types_vht_oper) +
801 sizeof(struct ieee_types_aid);
802
Avinash Patilb23bce22014-02-07 16:27:32 -0800803 skb = dev_alloc_skb(skb_len);
804 if (!skb) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530805 mwifiex_dbg(priv->adapter, ERROR,
806 "allocate skb failed for management frame\n");
Avinash Patilb23bce22014-02-07 16:27:32 -0800807 return -ENOMEM;
808 }
809
810 skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
811
812 pkt_type = PKT_TYPE_MGMT;
813 tx_control = 0;
814 pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
815 memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
816 memcpy(pos, &pkt_type, sizeof(pkt_type));
817 memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
818
819 if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,
820 dialog_token, status_code,
821 skb)) {
822 dev_kfree_skb_any(skb);
823 return -EINVAL;
824 }
825
826 if (extra_ies_len)
827 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
828
829 /* the TDLS link IE is always added last we are the responder */
830
831 mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
832 priv->cfg_bssid);
833
834 skb->priority = MWIFIEX_PRIO_VI;
835
836 tx_info = MWIFIEX_SKB_TXCB(skb);
Amitkumar Karwar701a9e62014-07-01 14:39:04 -0700837 memset(tx_info, 0, sizeof(*tx_info));
Avinash Patilb23bce22014-02-07 16:27:32 -0800838 tx_info->bss_num = priv->bss_num;
839 tx_info->bss_type = priv->bss_type;
840 tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
841
842 pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);
843 memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,
844 sizeof(pkt_len));
Thomas Gleixnerc64800e2014-06-12 08:31:34 +0100845 __net_timestamp(skb);
Avinash Patilb23bce22014-02-07 16:27:32 -0800846 mwifiex_queue_tx_pkt(priv, skb);
847
848 return 0;
849}
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800850
851/* This function process tdls action frame from peer.
852 * Peer capabilities are stored into station node structure.
853 */
854void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
855 u8 *buf, int len)
856{
857 struct mwifiex_sta_node *sta_ptr;
858 u8 *peer, *pos, *end;
859 u8 i, action, basic;
Bing Zhaof95f59f2014-07-14 20:53:34 -0700860 __le16 cap = 0;
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800861 int ie_len = 0;
862
863 if (len < (sizeof(struct ethhdr) + 3))
864 return;
Joe Perches45d18c52014-03-24 13:15:39 -0700865 if (*(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800866 return;
Joe Perches45d18c52014-03-24 13:15:39 -0700867 if (*(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800868 return;
869
870 peer = buf + ETH_ALEN;
Joe Perches45d18c52014-03-24 13:15:39 -0700871 action = *(buf + sizeof(struct ethhdr) + 2);
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530872 mwifiex_dbg(priv->adapter, DATA,
873 "rx:tdls action: peer=%pM, action=%d\n", peer, action);
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800874
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800875 switch (action) {
876 case WLAN_TDLS_SETUP_REQUEST:
877 if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
878 return;
879
880 pos = buf + sizeof(struct ethhdr) + 4;
881 /* payload 1+ category 1 + action 1 + dialog 1 */
Bing Zhaof95f59f2014-07-14 20:53:34 -0700882 cap = cpu_to_le16(*(u16 *)pos);
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800883 ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
884 pos += 2;
885 break;
886
887 case WLAN_TDLS_SETUP_RESPONSE:
888 if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
889 return;
890 /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
891 pos = buf + sizeof(struct ethhdr) + 6;
Bing Zhaof95f59f2014-07-14 20:53:34 -0700892 cap = cpu_to_le16(*(u16 *)pos);
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800893 ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
894 pos += 2;
895 break;
896
897 case WLAN_TDLS_SETUP_CONFIRM:
898 if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
899 return;
900 pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
901 ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
902 break;
903 default:
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530904 mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS frame type.\n");
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800905 return;
906 }
907
Bing Zhaof95f59f2014-07-14 20:53:34 -0700908 sta_ptr = mwifiex_add_sta_entry(priv, peer);
909 if (!sta_ptr)
910 return;
911
912 sta_ptr->tdls_cap.capab = cap;
913
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800914 for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
915 if (pos + 2 + pos[1] > end)
916 break;
917
918 switch (*pos) {
919 case WLAN_EID_SUPP_RATES:
920 sta_ptr->tdls_cap.rates_len = pos[1];
921 for (i = 0; i < pos[1]; i++)
922 sta_ptr->tdls_cap.rates[i] = pos[i + 2];
923 break;
924
925 case WLAN_EID_EXT_SUPP_RATES:
926 basic = sta_ptr->tdls_cap.rates_len;
927 for (i = 0; i < pos[1]; i++)
928 sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
929 sta_ptr->tdls_cap.rates_len += pos[1];
930 break;
931 case WLAN_EID_HT_CAPABILITY:
932 memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
933 sizeof(struct ieee80211_ht_cap));
934 sta_ptr->is_11n_enabled = 1;
935 break;
936 case WLAN_EID_HT_OPERATION:
937 memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
938 sizeof(struct ieee80211_ht_operation));
939 break;
940 case WLAN_EID_BSS_COEX_2040:
941 sta_ptr->tdls_cap.coex_2040 = pos[2];
942 break;
943 case WLAN_EID_EXT_CAPABILITY:
944 memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
945 sizeof(struct ieee_types_header) +
946 min_t(u8, pos[1], 8));
947 break;
948 case WLAN_EID_RSN:
949 memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
Avinash Patil3c998322014-09-12 20:08:46 +0530950 sizeof(struct ieee_types_header) +
951 min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
952 sizeof(struct ieee_types_header)));
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800953 break;
954 case WLAN_EID_QOS_CAPA:
955 sta_ptr->tdls_cap.qos_info = pos[2];
956 break;
Avinash Patil5f6d5982014-02-07 16:30:39 -0800957 case WLAN_EID_VHT_OPERATION:
958 if (priv->adapter->is_hw_11ac_capable)
959 memcpy(&sta_ptr->tdls_cap.vhtoper, pos,
960 sizeof(struct ieee80211_vht_operation));
961 break;
962 case WLAN_EID_VHT_CAPABILITY:
963 if (priv->adapter->is_hw_11ac_capable) {
964 memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos,
965 sizeof(struct ieee80211_vht_cap));
966 sta_ptr->is_11ac_enabled = 1;
967 }
968 break;
969 case WLAN_EID_AID:
970 if (priv->adapter->is_hw_11ac_capable)
971 sta_ptr->tdls_cap.aid =
972 le16_to_cpu(*(__le16 *)(pos + 2));
Avinash Patil5f2caaf2014-02-07 16:27:33 -0800973 default:
974 break;
975 }
976 }
977
978 return;
979}
Avinash Patil429d90d2014-02-07 16:27:34 -0800980
981static int
Johannes Berg3b3a0162014-05-19 17:19:31 +0200982mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
Avinash Patil1f4dfd82014-02-07 16:30:34 -0800983{
984 struct mwifiex_sta_node *sta_ptr;
985 struct mwifiex_ds_tdls_oper tdls_oper;
986
987 memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
988 sta_ptr = mwifiex_get_sta_entry(priv, peer);
989
990 if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +0530991 mwifiex_dbg(priv->adapter, ERROR,
992 "link absent for peer %pM; cannot config\n", peer);
Avinash Patil1f4dfd82014-02-07 16:30:34 -0800993 return -EINVAL;
994 }
995
996 memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
997 tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -0800998 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
999 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
Avinash Patil1f4dfd82014-02-07 16:30:34 -08001000}
1001
1002static int
Johannes Berg3b3a0162014-05-19 17:19:31 +02001003mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
Avinash Patile48e0de2014-02-07 16:30:33 -08001004{
1005 struct mwifiex_sta_node *sta_ptr;
1006 struct mwifiex_ds_tdls_oper tdls_oper;
1007
1008 memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1009 sta_ptr = mwifiex_get_sta_entry(priv, peer);
1010
1011 if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301012 mwifiex_dbg(priv->adapter, WARN,
1013 "Setup already in progress for peer %pM\n", peer);
Avinash Patile48e0de2014-02-07 16:30:33 -08001014 return 0;
1015 }
1016
1017 sta_ptr = mwifiex_add_sta_entry(priv, peer);
1018 if (!sta_ptr)
1019 return -ENOMEM;
1020
1021 sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;
Avinash Patil56bd24a2014-02-07 16:30:35 -08001022 mwifiex_hold_tdls_packets(priv, peer);
Avinash Patile48e0de2014-02-07 16:30:33 -08001023 memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
1024 tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001025 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1026 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
Avinash Patile48e0de2014-02-07 16:30:33 -08001027}
1028
1029static int
Johannes Berg3b3a0162014-05-19 17:19:31 +02001030mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
Avinash Patil429d90d2014-02-07 16:27:34 -08001031{
1032 struct mwifiex_sta_node *sta_ptr;
1033 struct mwifiex_ds_tdls_oper tdls_oper;
1034 unsigned long flags;
1035
1036 memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1037 sta_ptr = mwifiex_get_sta_entry(priv, peer);
1038
1039 if (sta_ptr) {
1040 if (sta_ptr->is_11n_enabled) {
1041 mwifiex_11n_cleanup_reorder_tbl(priv);
1042 spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1043 flags);
1044 mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1045 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1046 flags);
1047 }
1048 mwifiex_del_sta_entry(priv, peer);
1049 }
1050
Avinash Patil56bd24a2014-02-07 16:30:35 -08001051 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
Avinash Patil9927baa2014-11-13 21:54:16 +05301052 mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP);
Avinash Patil429d90d2014-02-07 16:27:34 -08001053 memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
1054 tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001055 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1056 HostCmd_ACT_GEN_SET, 0, &tdls_oper, true);
Avinash Patil429d90d2014-02-07 16:27:34 -08001057}
1058
1059static int
Johannes Berg3b3a0162014-05-19 17:19:31 +02001060mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
Avinash Patil429d90d2014-02-07 16:27:34 -08001061{
1062 struct mwifiex_sta_node *sta_ptr;
1063 struct ieee80211_mcs_info mcs;
1064 unsigned long flags;
1065 int i;
1066
1067 sta_ptr = mwifiex_get_sta_entry(priv, peer);
1068
1069 if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301070 mwifiex_dbg(priv->adapter, MSG,
1071 "tdls: enable link %pM success\n", peer);
Avinash Patil429d90d2014-02-07 16:27:34 -08001072
1073 sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
1074
1075 mcs = sta_ptr->tdls_cap.ht_capb.mcs;
1076 if (mcs.rx_mask[0] != 0xff)
1077 sta_ptr->is_11n_enabled = true;
1078 if (sta_ptr->is_11n_enabled) {
1079 if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &
1080 IEEE80211_HT_CAP_MAX_AMSDU)
1081 sta_ptr->max_amsdu =
1082 MWIFIEX_TX_DATA_BUF_SIZE_8K;
1083 else
1084 sta_ptr->max_amsdu =
1085 MWIFIEX_TX_DATA_BUF_SIZE_4K;
1086
1087 for (i = 0; i < MAX_NUM_TID; i++)
1088 sta_ptr->ampdu_sta[i] =
1089 priv->aggr_prio_tbl[i].ampdu_user;
1090 } else {
1091 for (i = 0; i < MAX_NUM_TID; i++)
1092 sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
1093 }
Xinming Hu20834342015-06-22 19:06:13 +05301094 if (sta_ptr->tdls_cap.extcap.ext_capab[3] &
1095 WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) {
1096 mwifiex_config_tdls_enable(priv);
1097 mwifiex_config_tdls_cs_params(priv);
1098 }
Avinash Patil429d90d2014-02-07 16:27:34 -08001099
1100 memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
Avinash Patil56bd24a2014-02-07 16:30:35 -08001101 mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
Avinash Patil9927baa2014-11-13 21:54:16 +05301102 mwifiex_auto_tdls_update_peer_status(priv, peer,
1103 TDLS_SETUP_COMPLETE);
Avinash Patil429d90d2014-02-07 16:27:34 -08001104 } else {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301105 mwifiex_dbg(priv->adapter, ERROR,
1106 "tdls: enable link %pM failed\n", peer);
Avinash Patil429d90d2014-02-07 16:27:34 -08001107 if (sta_ptr) {
1108 mwifiex_11n_cleanup_reorder_tbl(priv);
1109 spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1110 flags);
1111 mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1112 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1113 flags);
1114 mwifiex_del_sta_entry(priv, peer);
1115 }
Avinash Patil56bd24a2014-02-07 16:30:35 -08001116 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
Avinash Patil9927baa2014-11-13 21:54:16 +05301117 mwifiex_auto_tdls_update_peer_status(priv, peer,
1118 TDLS_NOT_SETUP);
Avinash Patil429d90d2014-02-07 16:27:34 -08001119
1120 return -1;
1121 }
1122
1123 return 0;
1124}
1125
Johannes Berg3b3a0162014-05-19 17:19:31 +02001126int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action)
Avinash Patil429d90d2014-02-07 16:27:34 -08001127{
1128 switch (action) {
1129 case MWIFIEX_TDLS_ENABLE_LINK:
1130 return mwifiex_tdls_process_enable_link(priv, peer);
1131 case MWIFIEX_TDLS_DISABLE_LINK:
1132 return mwifiex_tdls_process_disable_link(priv, peer);
Avinash Patile48e0de2014-02-07 16:30:33 -08001133 case MWIFIEX_TDLS_CREATE_LINK:
1134 return mwifiex_tdls_process_create_link(priv, peer);
Avinash Patil1f4dfd82014-02-07 16:30:34 -08001135 case MWIFIEX_TDLS_CONFIG_LINK:
1136 return mwifiex_tdls_process_config_link(priv, peer);
Avinash Patil429d90d2014-02-07 16:27:34 -08001137 }
1138 return 0;
1139}
Avinash Patild63bf5e2014-02-07 16:30:36 -08001140
Johannes Berg3b3a0162014-05-19 17:19:31 +02001141int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)
Avinash Patild63bf5e2014-02-07 16:30:36 -08001142{
1143 struct mwifiex_sta_node *sta_ptr;
1144
1145 sta_ptr = mwifiex_get_sta_entry(priv, mac);
1146 if (sta_ptr)
1147 return sta_ptr->tdls_status;
1148
1149 return TDLS_NOT_SETUP;
1150}
Avinash Patilbe104b92014-02-07 16:30:41 -08001151
Xinming Hu72df6312014-12-23 19:14:05 +05301152int mwifiex_get_tdls_list(struct mwifiex_private *priv,
1153 struct tdls_peer_info *buf)
1154{
1155 struct mwifiex_sta_node *sta_ptr;
1156 struct tdls_peer_info *peer = buf;
1157 int count = 0;
1158 unsigned long flags;
1159
1160 if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
1161 return 0;
1162
1163 /* make sure we are in station mode and connected */
1164 if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
1165 return 0;
1166
1167 spin_lock_irqsave(&priv->sta_list_spinlock, flags);
1168 list_for_each_entry(sta_ptr, &priv->sta_list, list) {
Xinming Hu55a2c072015-06-22 19:06:14 +05301169 if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) {
Xinming Hu72df6312014-12-23 19:14:05 +05301170 ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr);
1171 peer++;
1172 count++;
1173 if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED)
1174 break;
1175 }
1176 }
1177 spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
1178
1179 return count;
1180}
1181
Avinash Patilbe104b92014-02-07 16:30:41 -08001182void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
1183{
1184 struct mwifiex_sta_node *sta_ptr;
1185 struct mwifiex_ds_tdls_oper tdls_oper;
1186 unsigned long flags;
1187
1188 if (list_empty(&priv->sta_list))
1189 return;
1190
1191 list_for_each_entry(sta_ptr, &priv->sta_list, list) {
1192 memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
1193
1194 if (sta_ptr->is_11n_enabled) {
1195 mwifiex_11n_cleanup_reorder_tbl(priv);
1196 spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
1197 flags);
1198 mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
1199 spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
1200 flags);
1201 }
1202
1203 mwifiex_restore_tdls_packets(priv, sta_ptr->mac_addr,
1204 TDLS_LINK_TEARDOWN);
1205 memcpy(&tdls_oper.peer_mac, sta_ptr->mac_addr, ETH_ALEN);
1206 tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
Bing Zhaofa0ecbb2014-02-27 19:35:12 -08001207 if (mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
1208 HostCmd_ACT_GEN_SET, 0, &tdls_oper, false))
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301209 mwifiex_dbg(priv->adapter, ERROR,
1210 "Disable link failed for TDLS peer %pM",
1211 sta_ptr->mac_addr);
Avinash Patilbe104b92014-02-07 16:30:41 -08001212 }
1213
1214 mwifiex_del_all_sta_list(priv);
1215}
Avinash Patil9927baa2014-11-13 21:54:16 +05301216
1217int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
1218{
1219 struct mwifiex_auto_tdls_peer *peer;
1220 unsigned long flags;
1221 u8 mac[ETH_ALEN];
1222
1223 ether_addr_copy(mac, skb->data);
1224
1225 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1226 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1227 if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) {
1228 if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
1229 peer->tdls_status == TDLS_NOT_SETUP &&
1230 (peer->failure_count <
1231 MWIFIEX_TDLS_MAX_FAIL_COUNT)) {
1232 peer->tdls_status = TDLS_SETUP_INPROGRESS;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301233 mwifiex_dbg(priv->adapter, INFO,
1234 "setup TDLS link, peer=%pM rssi=%d\n",
1235 peer->mac_addr, peer->rssi);
Avinash Patil9927baa2014-11-13 21:54:16 +05301236
1237 cfg80211_tdls_oper_request(priv->netdev,
1238 peer->mac_addr,
1239 NL80211_TDLS_SETUP,
1240 0, GFP_ATOMIC);
1241 peer->do_setup = false;
1242 priv->check_tdls_tx = false;
1243 } else if (peer->failure_count <
1244 MWIFIEX_TDLS_MAX_FAIL_COUNT &&
1245 peer->do_discover) {
1246 mwifiex_send_tdls_data_frame(priv,
1247 peer->mac_addr,
1248 WLAN_TDLS_DISCOVERY_REQUEST,
1249 1, 0, NULL, 0);
1250 peer->do_discover = false;
1251 }
1252 }
1253 }
1254 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1255
1256 return 0;
1257}
1258
1259void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv)
1260{
1261 struct mwifiex_auto_tdls_peer *peer, *tmp_node;
1262 unsigned long flags;
1263
1264 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1265 list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) {
1266 list_del(&peer->list);
1267 kfree(peer);
1268 }
1269
1270 INIT_LIST_HEAD(&priv->auto_tdls_list);
1271 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1272 priv->check_tdls_tx = false;
1273}
1274
1275void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
1276{
1277 struct mwifiex_auto_tdls_peer *tdls_peer;
1278 unsigned long flags;
1279
1280 if (!priv->adapter->auto_tdls)
1281 return;
1282
1283 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1284 list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
1285 if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) {
1286 tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
1287 tdls_peer->rssi_jiffies = jiffies;
1288 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1289 return;
1290 }
1291 }
1292
1293 /* create new TDLS peer */
1294 tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC);
1295 if (tdls_peer) {
1296 ether_addr_copy(tdls_peer->mac_addr, mac);
1297 tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
1298 tdls_peer->rssi_jiffies = jiffies;
1299 INIT_LIST_HEAD(&tdls_peer->list);
1300 list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301301 mwifiex_dbg(priv->adapter, INFO,
1302 "Add auto TDLS peer= %pM to list\n", mac);
Avinash Patil9927baa2014-11-13 21:54:16 +05301303 }
1304
1305 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1306}
1307
1308void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
1309 const u8 *mac, u8 link_status)
1310{
1311 struct mwifiex_auto_tdls_peer *peer;
1312 unsigned long flags;
1313
1314 if (!priv->adapter->auto_tdls)
1315 return;
1316
1317 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1318 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1319 if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
1320 if ((link_status == TDLS_NOT_SETUP) &&
1321 (peer->tdls_status == TDLS_SETUP_INPROGRESS))
1322 peer->failure_count++;
Xinming Hu55a2c072015-06-22 19:06:14 +05301323 else if (mwifiex_is_tdls_link_setup(link_status))
Avinash Patil9927baa2014-11-13 21:54:16 +05301324 peer->failure_count = 0;
1325
1326 peer->tdls_status = link_status;
1327 break;
1328 }
1329 }
1330 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1331}
1332
1333void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
1334 u8 *mac, s8 snr, s8 nflr)
1335{
1336 struct mwifiex_auto_tdls_peer *peer;
1337 unsigned long flags;
1338
1339 if (!priv->adapter->auto_tdls)
1340 return;
1341
1342 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1343 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1344 if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
1345 peer->rssi = nflr - snr;
1346 peer->rssi_jiffies = jiffies;
1347 break;
1348 }
1349 }
1350 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1351}
1352
1353void mwifiex_check_auto_tdls(unsigned long context)
1354{
1355 struct mwifiex_private *priv = (struct mwifiex_private *)context;
1356 struct mwifiex_auto_tdls_peer *tdls_peer;
1357 unsigned long flags;
1358 u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
1359
1360 if (WARN_ON_ONCE(!priv || !priv->adapter)) {
1361 pr_err("mwifiex: %s: adapter or private structure is NULL\n",
1362 __func__);
1363 return;
1364 }
1365
1366 if (unlikely(!priv->adapter->auto_tdls))
1367 return;
1368
1369 if (!priv->auto_tdls_timer_active) {
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301370 mwifiex_dbg(priv->adapter, INFO,
1371 "auto TDLS timer inactive; return");
Avinash Patil9927baa2014-11-13 21:54:16 +05301372 return;
1373 }
1374
1375 priv->check_tdls_tx = false;
1376
1377 if (list_empty(&priv->auto_tdls_list)) {
1378 mod_timer(&priv->auto_tdls_timer,
1379 jiffies +
1380 msecs_to_jiffies(MWIFIEX_TIMER_10S));
1381 return;
1382 }
1383
1384 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1385 list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
1386 if ((jiffies - tdls_peer->rssi_jiffies) >
1387 (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) {
1388 tdls_peer->rssi = 0;
1389 tdls_peer->do_discover = true;
1390 priv->check_tdls_tx = true;
1391 }
1392
1393 if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) ||
1394 !tdls_peer->rssi) &&
Xinming Hu55a2c072015-06-22 19:06:14 +05301395 mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) {
Avinash Patil9927baa2014-11-13 21:54:16 +05301396 tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301397 mwifiex_dbg(priv->adapter, MSG,
1398 "teardown TDLS link,peer=%pM rssi=%d\n",
1399 tdls_peer->mac_addr, -tdls_peer->rssi);
Avinash Patil9927baa2014-11-13 21:54:16 +05301400 tdls_peer->do_discover = true;
1401 priv->check_tdls_tx = true;
1402 cfg80211_tdls_oper_request(priv->netdev,
1403 tdls_peer->mac_addr,
1404 NL80211_TDLS_TEARDOWN,
1405 reason, GFP_ATOMIC);
1406 } else if (tdls_peer->rssi &&
1407 tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
1408 tdls_peer->tdls_status == TDLS_NOT_SETUP &&
1409 tdls_peer->failure_count <
1410 MWIFIEX_TDLS_MAX_FAIL_COUNT) {
1411 priv->check_tdls_tx = true;
1412 tdls_peer->do_setup = true;
Zhaoyang Liuacebe8c2015-05-12 00:48:20 +05301413 mwifiex_dbg(priv->adapter, INFO,
1414 "check TDLS with peer=%pM\t"
1415 "rssi=%d\n", tdls_peer->mac_addr,
1416 tdls_peer->rssi);
Avinash Patil9927baa2014-11-13 21:54:16 +05301417 }
1418 }
1419 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1420
1421 mod_timer(&priv->auto_tdls_timer,
1422 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
1423}
1424
1425void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv)
1426{
Julia Lawall63835392014-12-26 15:35:58 +01001427 setup_timer(&priv->auto_tdls_timer, mwifiex_check_auto_tdls,
1428 (unsigned long)priv);
Avinash Patil9927baa2014-11-13 21:54:16 +05301429 priv->auto_tdls_timer_active = true;
1430 mod_timer(&priv->auto_tdls_timer,
1431 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
1432}
1433
1434void mwifiex_clean_auto_tdls(struct mwifiex_private *priv)
1435{
1436 if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
1437 priv->adapter->auto_tdls &&
1438 priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
1439 priv->auto_tdls_timer_active = false;
1440 del_timer(&priv->auto_tdls_timer);
1441 mwifiex_flush_auto_tdls_list(priv);
1442 }
1443}
Xinming Hu449b8bb2015-06-22 19:06:12 +05301444
1445static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable)
1446{
1447 struct mwifiex_tdls_config config;
1448
1449 config.enable = cpu_to_le16(enable);
1450 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,
1451 ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true);
1452}
1453
1454int mwifiex_config_tdls_enable(struct mwifiex_private *priv)
1455{
1456 return mwifiex_config_tdls(priv, true);
1457}
1458
1459int mwifiex_config_tdls_disable(struct mwifiex_private *priv)
1460{
1461 return mwifiex_config_tdls(priv, false);
1462}
1463
1464int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv)
1465{
1466 struct mwifiex_tdls_config_cs_params config_tdls_cs_params;
1467
1468 config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME;
1469 config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK;
1470 config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK;
1471
1472 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,
1473 ACT_TDLS_CS_PARAMS, 0,
1474 &config_tdls_cs_params, true);
1475}
1476
1477int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac)
1478{
1479 struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params;
1480
1481 ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac);
1482
1483 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,
1484 ACT_TDLS_CS_STOP, 0,
1485 &stop_tdls_cs_params, true);
1486}
1487
1488int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac,
1489 u8 primary_chan, u8 second_chan_offset, u8 band)
1490{
1491 struct mwifiex_tdls_init_cs_params start_tdls_cs_params;
1492
1493 ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac);
1494 start_tdls_cs_params.primary_chan = primary_chan;
1495 start_tdls_cs_params.second_chan_offset = second_chan_offset;
1496 start_tdls_cs_params.band = band;
1497
1498 start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME);
1499 start_tdls_cs_params.switch_timeout =
1500 cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT);
1501 start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS;
1502 start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY;
1503
1504 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG,
1505 ACT_TDLS_CS_INIT, 0,
1506 &start_tdls_cs_params, true);
1507}