mwifiex: tdls related handling for data packets addressed to TDLS peer
[firefly-linux-kernel-4.4.55.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
23 #define TDLS_REQ_FIX_LEN      6
24 #define TDLS_RESP_FIX_LEN     8
25 #define TDLS_CONFIRM_FIX_LEN  6
26
27 static void
28 mwifiex_restore_tdls_packets(struct mwifiex_private *priv, u8 *mac, u8 status)
29 {
30         struct mwifiex_ra_list_tbl *ra_list;
31         struct list_head *tid_list;
32         struct sk_buff *skb, *tmp;
33         struct mwifiex_txinfo *tx_info;
34         unsigned long flags;
35         u32 tid;
36         u8 tid_down;
37
38         dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
39         spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
40
41         skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) {
42                 if (!ether_addr_equal(mac, skb->data))
43                         continue;
44
45                 __skb_unlink(skb, &priv->tdls_txq);
46                 tx_info = MWIFIEX_SKB_TXCB(skb);
47                 tid = skb->priority;
48                 tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
49
50                 if (status == TDLS_SETUP_COMPLETE) {
51                         ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac);
52                         tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
53                 } else {
54                         tid_list = &priv->wmm.tid_tbl_ptr[tid_down].ra_list;
55                         if (!list_empty(tid_list))
56                                 ra_list = list_first_entry(tid_list,
57                                               struct mwifiex_ra_list_tbl, list);
58                         else
59                                 ra_list = NULL;
60                         tx_info->flags &= ~MWIFIEX_BUF_FLAG_TDLS_PKT;
61                 }
62
63                 if (!ra_list) {
64                         mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
65                         continue;
66                 }
67
68                 skb_queue_tail(&ra_list->skb_head, skb);
69
70                 ra_list->ba_pkt_count++;
71                 ra_list->total_pkt_count++;
72
73                 if (atomic_read(&priv->wmm.highest_queued_prio) <
74                                                        tos_to_tid_inv[tid_down])
75                         atomic_set(&priv->wmm.highest_queued_prio,
76                                    tos_to_tid_inv[tid_down]);
77
78                 atomic_inc(&priv->wmm.tx_pkts_queued);
79         }
80
81         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
82         return;
83 }
84
85 static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv, u8 *mac)
86 {
87         struct mwifiex_ra_list_tbl *ra_list;
88         struct list_head *ra_list_head;
89         struct sk_buff *skb, *tmp;
90         unsigned long flags;
91         int i;
92
93         dev_dbg(priv->adapter->dev, "%s: %pM\n", __func__, mac);
94         spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
95
96         for (i = 0; i < MAX_NUM_TID; i++) {
97                 if (!list_empty(&priv->wmm.tid_tbl_ptr[i].ra_list)) {
98                         ra_list_head = &priv->wmm.tid_tbl_ptr[i].ra_list;
99                         list_for_each_entry(ra_list, ra_list_head, list) {
100                                 skb_queue_walk_safe(&ra_list->skb_head, skb,
101                                                     tmp) {
102                                         if (!ether_addr_equal(mac, skb->data))
103                                                 continue;
104                                         __skb_unlink(skb, &ra_list->skb_head);
105                                         atomic_dec(&priv->wmm.tx_pkts_queued);
106                                         ra_list->total_pkt_count--;
107                                         skb_queue_tail(&priv->tdls_txq, skb);
108                                 }
109                         }
110                 }
111         }
112
113         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
114         return;
115 }
116
117 /* This function appends rate TLV to scan config command. */
118 static int
119 mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv,
120                              struct sk_buff *skb)
121 {
122         u8 rates[MWIFIEX_SUPPORTED_RATES], *pos;
123         u16 rates_size, supp_rates_size, ext_rates_size;
124
125         memset(rates, 0, sizeof(rates));
126         rates_size = mwifiex_get_supported_rates(priv, rates);
127
128         supp_rates_size = min_t(u16, rates_size, MWIFIEX_TDLS_SUPPORTED_RATES);
129
130         if (skb_tailroom(skb) < rates_size + 4) {
131                 dev_err(priv->adapter->dev,
132                         "Insuffient space while adding rates\n");
133                 return -ENOMEM;
134         }
135
136         pos = skb_put(skb, supp_rates_size + 2);
137         *pos++ = WLAN_EID_SUPP_RATES;
138         *pos++ = supp_rates_size;
139         memcpy(pos, rates, supp_rates_size);
140
141         if (rates_size > MWIFIEX_TDLS_SUPPORTED_RATES) {
142                 ext_rates_size = rates_size - MWIFIEX_TDLS_SUPPORTED_RATES;
143                 pos = skb_put(skb, ext_rates_size + 2);
144                 *pos++ = WLAN_EID_EXT_SUPP_RATES;
145                 *pos++ = ext_rates_size;
146                 memcpy(pos, rates + MWIFIEX_TDLS_SUPPORTED_RATES,
147                        ext_rates_size);
148         }
149
150         return 0;
151 }
152
153 static void mwifiex_tdls_add_ext_capab(struct sk_buff *skb)
154 {
155         struct ieee_types_extcap *extcap;
156
157         extcap = (void *)skb_put(skb, sizeof(struct ieee_types_extcap));
158         extcap->ieee_hdr.element_id = WLAN_EID_EXT_CAPABILITY;
159         extcap->ieee_hdr.len = 8;
160         memset(extcap->ext_capab, 0, 8);
161         extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED;
162 }
163
164 static void mwifiex_tdls_add_qos_capab(struct sk_buff *skb)
165 {
166         u8 *pos = (void *)skb_put(skb, 3);
167
168         *pos++ = WLAN_EID_QOS_CAPA;
169         *pos++ = 1;
170         *pos++ = MWIFIEX_TDLS_DEF_QOS_CAPAB;
171 }
172
173 static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
174                              u8 *peer, u8 action_code, u8 dialog_token,
175                              u16 status_code, struct sk_buff *skb)
176 {
177         struct ieee80211_tdls_data *tf;
178         int ret;
179         u16 capab;
180         struct ieee80211_ht_cap *ht_cap;
181         u8 radio, *pos;
182
183         capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
184
185         tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
186         memcpy(tf->da, peer, ETH_ALEN);
187         memcpy(tf->sa, priv->curr_addr, ETH_ALEN);
188         tf->ether_type = cpu_to_be16(ETH_P_TDLS);
189         tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
190
191         switch (action_code) {
192         case WLAN_TDLS_SETUP_REQUEST:
193                 tf->category = WLAN_CATEGORY_TDLS;
194                 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
195                 skb_put(skb, sizeof(tf->u.setup_req));
196                 tf->u.setup_req.dialog_token = dialog_token;
197                 tf->u.setup_req.capability = cpu_to_le16(capab);
198                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
199                 if (ret) {
200                         dev_kfree_skb_any(skb);
201                         return ret;
202                 }
203
204                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
205                 *pos++ = WLAN_EID_HT_CAPABILITY;
206                 *pos++ = sizeof(struct ieee80211_ht_cap);
207                 ht_cap = (void *)pos;
208                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
209                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
210                 if (ret) {
211                         dev_kfree_skb_any(skb);
212                         return ret;
213                 }
214
215                 mwifiex_tdls_add_ext_capab(skb);
216                 mwifiex_tdls_add_qos_capab(skb);
217                 break;
218
219         case WLAN_TDLS_SETUP_RESPONSE:
220                 tf->category = WLAN_CATEGORY_TDLS;
221                 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
222                 skb_put(skb, sizeof(tf->u.setup_resp));
223                 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
224                 tf->u.setup_resp.dialog_token = dialog_token;
225                 tf->u.setup_resp.capability = cpu_to_le16(capab);
226                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
227                 if (ret) {
228                         dev_kfree_skb_any(skb);
229                         return ret;
230                 }
231
232                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
233                 *pos++ = WLAN_EID_HT_CAPABILITY;
234                 *pos++ = sizeof(struct ieee80211_ht_cap);
235                 ht_cap = (void *)pos;
236                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
237                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
238                 if (ret) {
239                         dev_kfree_skb_any(skb);
240                         return ret;
241                 }
242
243                 mwifiex_tdls_add_ext_capab(skb);
244                 mwifiex_tdls_add_qos_capab(skb);
245                 break;
246
247         case WLAN_TDLS_SETUP_CONFIRM:
248                 tf->category = WLAN_CATEGORY_TDLS;
249                 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
250                 skb_put(skb, sizeof(tf->u.setup_cfm));
251                 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
252                 tf->u.setup_cfm.dialog_token = dialog_token;
253                 break;
254
255         case WLAN_TDLS_TEARDOWN:
256                 tf->category = WLAN_CATEGORY_TDLS;
257                 tf->action_code = WLAN_TDLS_TEARDOWN;
258                 skb_put(skb, sizeof(tf->u.teardown));
259                 tf->u.teardown.reason_code = cpu_to_le16(status_code);
260                 break;
261
262         case WLAN_TDLS_DISCOVERY_REQUEST:
263                 tf->category = WLAN_CATEGORY_TDLS;
264                 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
265                 skb_put(skb, sizeof(tf->u.discover_req));
266                 tf->u.discover_req.dialog_token = dialog_token;
267                 break;
268         default:
269                 dev_err(priv->adapter->dev, "Unknown TDLS frame type.\n");
270                 return -EINVAL;
271         }
272
273         return 0;
274 }
275
276 static void
277 mwifiex_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, u8 *peer, u8 *bssid)
278 {
279         struct ieee80211_tdls_lnkie *lnkid;
280
281         lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
282         lnkid->ie_type = WLAN_EID_LINK_ID;
283         lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) -
284                         sizeof(struct ieee_types_header);
285
286         memcpy(lnkid->bssid, bssid, ETH_ALEN);
287         memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
288         memcpy(lnkid->resp_sta, peer, ETH_ALEN);
289 }
290
291 int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv,
292                                  u8 *peer, u8 action_code, u8 dialog_token,
293                                  u16 status_code, const u8 *extra_ies,
294                                  size_t extra_ies_len)
295 {
296         struct sk_buff *skb;
297         struct mwifiex_txinfo *tx_info;
298         struct timeval tv;
299         int ret;
300         u16 skb_len;
301
302         skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
303                   max(sizeof(struct ieee80211_mgmt),
304                       sizeof(struct ieee80211_tdls_data)) +
305                   MWIFIEX_MGMT_FRAME_HEADER_SIZE +
306                   MWIFIEX_SUPPORTED_RATES +
307                   3 + /* Qos Info */
308                   sizeof(struct ieee_types_extcap) +
309                   sizeof(struct ieee80211_ht_cap) +
310                   sizeof(struct ieee_types_bss_co_2040) +
311                   sizeof(struct ieee80211_ht_operation) +
312                   sizeof(struct ieee80211_tdls_lnkie) +
313                   extra_ies_len;
314
315         skb = dev_alloc_skb(skb_len);
316         if (!skb) {
317                 dev_err(priv->adapter->dev,
318                         "allocate skb failed for management frame\n");
319                 return -ENOMEM;
320         }
321         skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
322
323         switch (action_code) {
324         case WLAN_TDLS_SETUP_REQUEST:
325         case WLAN_TDLS_SETUP_CONFIRM:
326         case WLAN_TDLS_TEARDOWN:
327         case WLAN_TDLS_DISCOVERY_REQUEST:
328                 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
329                                                    dialog_token, status_code,
330                                                    skb);
331                 if (ret) {
332                         dev_kfree_skb_any(skb);
333                         return ret;
334                 }
335                 if (extra_ies_len)
336                         memcpy(skb_put(skb, extra_ies_len), extra_ies,
337                                extra_ies_len);
338                 mwifiex_tdls_add_link_ie(skb, priv->curr_addr, peer,
339                                          priv->cfg_bssid);
340                 break;
341         case WLAN_TDLS_SETUP_RESPONSE:
342                 ret = mwifiex_prep_tdls_encap_data(priv, peer, action_code,
343                                                    dialog_token, status_code,
344                                                    skb);
345                 if (ret) {
346                         dev_kfree_skb_any(skb);
347                         return ret;
348                 }
349                 if (extra_ies_len)
350                         memcpy(skb_put(skb, extra_ies_len), extra_ies,
351                                extra_ies_len);
352                 mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
353                                          priv->cfg_bssid);
354                 break;
355         }
356
357         switch (action_code) {
358         case WLAN_TDLS_SETUP_REQUEST:
359         case WLAN_TDLS_SETUP_RESPONSE:
360                 skb->priority = MWIFIEX_PRIO_BK;
361                 break;
362         default:
363                 skb->priority = MWIFIEX_PRIO_VI;
364                 break;
365         }
366
367         tx_info = MWIFIEX_SKB_TXCB(skb);
368         tx_info->bss_num = priv->bss_num;
369         tx_info->bss_type = priv->bss_type;
370
371         do_gettimeofday(&tv);
372         skb->tstamp = timeval_to_ktime(tv);
373         mwifiex_queue_tx_pkt(priv, skb);
374
375         return 0;
376 }
377
378 static int
379 mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, u8 *peer,
380                                     u8 action_code, u8 dialog_token,
381                                     u16 status_code, struct sk_buff *skb)
382 {
383         struct ieee80211_mgmt *mgmt;
384         u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
385         int ret;
386         u16 capab;
387         struct ieee80211_ht_cap *ht_cap;
388         u8 radio, *pos;
389
390         capab = priv->curr_bss_params.bss_descriptor.cap_info_bitmap;
391
392         mgmt = (void *)skb_put(skb, offsetof(struct ieee80211_mgmt, u));
393
394         memset(mgmt, 0, 24);
395         memcpy(mgmt->da, peer, ETH_ALEN);
396         memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN);
397         memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
398         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
399                                           IEEE80211_STYPE_ACTION);
400
401         /* add address 4 */
402         pos = skb_put(skb, ETH_ALEN);
403
404         switch (action_code) {
405         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
406                 skb_put(skb, sizeof(mgmt->u.action.u.tdls_discover_resp) + 1);
407                 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
408                 mgmt->u.action.u.tdls_discover_resp.action_code =
409                                               WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
410                 mgmt->u.action.u.tdls_discover_resp.dialog_token =
411                                                                    dialog_token;
412                 mgmt->u.action.u.tdls_discover_resp.capability =
413                                                              cpu_to_le16(capab);
414                 /* move back for addr4 */
415                 memmove(pos + ETH_ALEN, &mgmt->u.action.category,
416                         sizeof(mgmt->u.action.u.tdls_discover_resp));
417                 /* init address 4 */
418                 memcpy(pos, bc_addr, ETH_ALEN);
419
420                 ret = mwifiex_tdls_append_rates_ie(priv, skb);
421                 if (ret) {
422                         dev_kfree_skb_any(skb);
423                         return ret;
424                 }
425
426                 pos = (void *)skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
427                 *pos++ = WLAN_EID_HT_CAPABILITY;
428                 *pos++ = sizeof(struct ieee80211_ht_cap);
429                 ht_cap = (void *)pos;
430                 radio = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
431                 ret = mwifiex_fill_cap_info(priv, radio, ht_cap);
432                 if (ret) {
433                         dev_kfree_skb_any(skb);
434                         return ret;
435                 }
436
437                 mwifiex_tdls_add_ext_capab(skb);
438                 mwifiex_tdls_add_qos_capab(skb);
439                 break;
440         default:
441                 dev_err(priv->adapter->dev, "Unknown TDLS action frame type\n");
442                 return -EINVAL;
443         }
444
445         return 0;
446 }
447
448 int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
449                                  u8 *peer, u8 action_code, u8 dialog_token,
450                                  u16 status_code, const u8 *extra_ies,
451                                  size_t extra_ies_len)
452 {
453         struct sk_buff *skb;
454         struct mwifiex_txinfo *tx_info;
455         struct timeval tv;
456         u8 *pos;
457         u32 pkt_type, tx_control;
458         u16 pkt_len, skb_len;
459
460         skb_len = MWIFIEX_MIN_DATA_HEADER_LEN +
461                   max(sizeof(struct ieee80211_mgmt),
462                       sizeof(struct ieee80211_tdls_data)) +
463                   MWIFIEX_MGMT_FRAME_HEADER_SIZE +
464                   MWIFIEX_SUPPORTED_RATES +
465                   sizeof(struct ieee_types_extcap) +
466                   sizeof(struct ieee80211_ht_cap) +
467                   sizeof(struct ieee_types_bss_co_2040) +
468                   sizeof(struct ieee80211_ht_operation) +
469                   sizeof(struct ieee80211_tdls_lnkie) +
470                   extra_ies_len +
471                   3 + /* Qos Info */
472                   ETH_ALEN; /* Address4 */
473
474         skb = dev_alloc_skb(skb_len);
475         if (!skb) {
476                 dev_err(priv->adapter->dev,
477                         "allocate skb failed for management frame\n");
478                 return -ENOMEM;
479         }
480
481         skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
482
483         pkt_type = PKT_TYPE_MGMT;
484         tx_control = 0;
485         pos = skb_put(skb, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
486         memset(pos, 0, MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len));
487         memcpy(pos, &pkt_type, sizeof(pkt_type));
488         memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
489
490         if (mwifiex_construct_tdls_action_frame(priv, peer, action_code,
491                                                 dialog_token, status_code,
492                                                 skb)) {
493                 dev_kfree_skb_any(skb);
494                 return -EINVAL;
495         }
496
497         if (extra_ies_len)
498                 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
499
500         /* the TDLS link IE is always added last we are the responder */
501
502         mwifiex_tdls_add_link_ie(skb, peer, priv->curr_addr,
503                                  priv->cfg_bssid);
504
505         skb->priority = MWIFIEX_PRIO_VI;
506
507         tx_info = MWIFIEX_SKB_TXCB(skb);
508         tx_info->bss_num = priv->bss_num;
509         tx_info->bss_type = priv->bss_type;
510         tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
511
512         pkt_len = skb->len - MWIFIEX_MGMT_FRAME_HEADER_SIZE - sizeof(pkt_len);
513         memcpy(skb->data + MWIFIEX_MGMT_FRAME_HEADER_SIZE, &pkt_len,
514                sizeof(pkt_len));
515         do_gettimeofday(&tv);
516         skb->tstamp = timeval_to_ktime(tv);
517         mwifiex_queue_tx_pkt(priv, skb);
518
519         return 0;
520 }
521
522 /* This function process tdls action frame from peer.
523  * Peer capabilities are stored into station node structure.
524  */
525 void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
526                                        u8 *buf, int len)
527 {
528         struct mwifiex_sta_node *sta_ptr;
529         u8 *peer, *pos, *end;
530         u8 i, action, basic;
531         int ie_len = 0;
532
533         if (len < (sizeof(struct ethhdr) + 3))
534                 return;
535         if (*(u8 *)(buf + sizeof(struct ethhdr)) != WLAN_TDLS_SNAP_RFTYPE)
536                 return;
537         if (*(u8 *)(buf + sizeof(struct ethhdr) + 1) != WLAN_CATEGORY_TDLS)
538                 return;
539
540         peer = buf + ETH_ALEN;
541         action = *(u8 *)(buf + sizeof(struct ethhdr) + 2);
542
543         /* just handle TDLS setup request/response/confirm */
544         if (action > WLAN_TDLS_SETUP_CONFIRM)
545                 return;
546
547         dev_dbg(priv->adapter->dev,
548                 "rx:tdls action: peer=%pM, action=%d\n", peer, action);
549
550         sta_ptr = mwifiex_add_sta_entry(priv, peer);
551         if (!sta_ptr)
552                 return;
553
554         switch (action) {
555         case WLAN_TDLS_SETUP_REQUEST:
556                 if (len < (sizeof(struct ethhdr) + TDLS_REQ_FIX_LEN))
557                         return;
558
559                 pos = buf + sizeof(struct ethhdr) + 4;
560                 /* payload 1+ category 1 + action 1 + dialog 1 */
561                 sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
562                 ie_len = len - sizeof(struct ethhdr) - TDLS_REQ_FIX_LEN;
563                 pos += 2;
564                 break;
565
566         case WLAN_TDLS_SETUP_RESPONSE:
567                 if (len < (sizeof(struct ethhdr) + TDLS_RESP_FIX_LEN))
568                         return;
569                 /* payload 1+ category 1 + action 1 + dialog 1 + status code 2*/
570                 pos = buf + sizeof(struct ethhdr) + 6;
571                 sta_ptr->tdls_cap.capab = cpu_to_le16(*(u16 *)pos);
572                 ie_len = len - sizeof(struct ethhdr) - TDLS_RESP_FIX_LEN;
573                 pos += 2;
574                 break;
575
576         case WLAN_TDLS_SETUP_CONFIRM:
577                 if (len < (sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN))
578                         return;
579                 pos = buf + sizeof(struct ethhdr) + TDLS_CONFIRM_FIX_LEN;
580                 ie_len = len - sizeof(struct ethhdr) - TDLS_CONFIRM_FIX_LEN;
581                 break;
582         default:
583                 dev_warn(priv->adapter->dev, "Unknown TDLS frame type.\n");
584                 return;
585         }
586
587         for (end = pos + ie_len; pos + 1 < end; pos += 2 + pos[1]) {
588                 if (pos + 2 + pos[1] > end)
589                         break;
590
591                 switch (*pos) {
592                 case WLAN_EID_SUPP_RATES:
593                         sta_ptr->tdls_cap.rates_len = pos[1];
594                         for (i = 0; i < pos[1]; i++)
595                                 sta_ptr->tdls_cap.rates[i] = pos[i + 2];
596                         break;
597
598                 case WLAN_EID_EXT_SUPP_RATES:
599                         basic = sta_ptr->tdls_cap.rates_len;
600                         for (i = 0; i < pos[1]; i++)
601                                 sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2];
602                         sta_ptr->tdls_cap.rates_len += pos[1];
603                         break;
604                 case WLAN_EID_HT_CAPABILITY:
605                         memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,
606                                sizeof(struct ieee80211_ht_cap));
607                         sta_ptr->is_11n_enabled = 1;
608                         break;
609                 case WLAN_EID_HT_OPERATION:
610                         memcpy(&sta_ptr->tdls_cap.ht_oper, pos,
611                                sizeof(struct ieee80211_ht_operation));
612                         break;
613                 case WLAN_EID_BSS_COEX_2040:
614                         sta_ptr->tdls_cap.coex_2040 = pos[2];
615                         break;
616                 case WLAN_EID_EXT_CAPABILITY:
617                         memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos,
618                                sizeof(struct ieee_types_header) +
619                                min_t(u8, pos[1], 8));
620                         break;
621                 case WLAN_EID_RSN:
622                         memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
623                                sizeof(struct ieee_types_header) + pos[1]);
624                         break;
625                 case WLAN_EID_QOS_CAPA:
626                         sta_ptr->tdls_cap.qos_info = pos[2];
627                         break;
628                 default:
629                         break;
630                 }
631         }
632
633         return;
634 }
635
636 static int
637 mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer)
638 {
639         struct mwifiex_sta_node *sta_ptr;
640         struct mwifiex_ds_tdls_oper tdls_oper;
641
642         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
643         sta_ptr = mwifiex_get_sta_entry(priv, peer);
644
645         if (!sta_ptr || sta_ptr->tdls_status == TDLS_SETUP_FAILURE) {
646                 dev_err(priv->adapter->dev,
647                         "link absent for peer %pM; cannot config\n", peer);
648                 return -EINVAL;
649         }
650
651         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
652         tdls_oper.tdls_action = MWIFIEX_TDLS_CONFIG_LINK;
653         return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
654                                      HostCmd_ACT_GEN_SET, 0, &tdls_oper);
655 }
656
657 static int
658 mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
659 {
660         struct mwifiex_sta_node *sta_ptr;
661         struct mwifiex_ds_tdls_oper tdls_oper;
662
663         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
664         sta_ptr = mwifiex_get_sta_entry(priv, peer);
665
666         if (sta_ptr && sta_ptr->tdls_status == TDLS_SETUP_INPROGRESS) {
667                 dev_dbg(priv->adapter->dev,
668                         "Setup already in progress for peer %pM\n", peer);
669                 return 0;
670         }
671
672         sta_ptr = mwifiex_add_sta_entry(priv, peer);
673         if (!sta_ptr)
674                 return -ENOMEM;
675
676         sta_ptr->tdls_status = TDLS_SETUP_INPROGRESS;
677         mwifiex_hold_tdls_packets(priv, peer);
678         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
679         tdls_oper.tdls_action = MWIFIEX_TDLS_CREATE_LINK;
680         return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
681                                      HostCmd_ACT_GEN_SET, 0, &tdls_oper);
682 }
683
684 static int
685 mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, u8 *peer)
686 {
687         struct mwifiex_sta_node *sta_ptr;
688         struct mwifiex_ds_tdls_oper tdls_oper;
689         unsigned long flags;
690
691         memset(&tdls_oper, 0, sizeof(struct mwifiex_ds_tdls_oper));
692         sta_ptr = mwifiex_get_sta_entry(priv, peer);
693
694         if (sta_ptr) {
695                 if (sta_ptr->is_11n_enabled) {
696                         mwifiex_11n_cleanup_reorder_tbl(priv);
697                         spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
698                                           flags);
699                         mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
700                         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
701                                                flags);
702                 }
703                 mwifiex_del_sta_entry(priv, peer);
704         }
705
706         mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
707         memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
708         tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
709         return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TDLS_OPER,
710                                      HostCmd_ACT_GEN_SET, 0, &tdls_oper);
711 }
712
713 static int
714 mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, u8 *peer)
715 {
716         struct mwifiex_sta_node *sta_ptr;
717         struct ieee80211_mcs_info mcs;
718         unsigned long flags;
719         int i;
720
721         sta_ptr = mwifiex_get_sta_entry(priv, peer);
722
723         if (sta_ptr && (sta_ptr->tdls_status != TDLS_SETUP_FAILURE)) {
724                 dev_dbg(priv->adapter->dev,
725                         "tdls: enable link %pM success\n", peer);
726
727                 sta_ptr->tdls_status = TDLS_SETUP_COMPLETE;
728
729                 mcs = sta_ptr->tdls_cap.ht_capb.mcs;
730                 if (mcs.rx_mask[0] != 0xff)
731                         sta_ptr->is_11n_enabled = true;
732                 if (sta_ptr->is_11n_enabled) {
733                         if (le16_to_cpu(sta_ptr->tdls_cap.ht_capb.cap_info) &
734                             IEEE80211_HT_CAP_MAX_AMSDU)
735                                 sta_ptr->max_amsdu =
736                                         MWIFIEX_TX_DATA_BUF_SIZE_8K;
737                         else
738                                 sta_ptr->max_amsdu =
739                                         MWIFIEX_TX_DATA_BUF_SIZE_4K;
740
741                         for (i = 0; i < MAX_NUM_TID; i++)
742                                 sta_ptr->ampdu_sta[i] =
743                                               priv->aggr_prio_tbl[i].ampdu_user;
744                 } else {
745                         for (i = 0; i < MAX_NUM_TID; i++)
746                                 sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
747                 }
748
749                 memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
750                 mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
751         } else {
752                 dev_dbg(priv->adapter->dev,
753                         "tdls: enable link %pM failed\n", peer);
754                 if (sta_ptr) {
755                         mwifiex_11n_cleanup_reorder_tbl(priv);
756                         spin_lock_irqsave(&priv->wmm.ra_list_spinlock,
757                                           flags);
758                         mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
759                         spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
760                                                flags);
761                         mwifiex_del_sta_entry(priv, peer);
762                 }
763                 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
764
765                 return -1;
766         }
767
768         return 0;
769 }
770
771 int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action)
772 {
773         switch (action) {
774         case MWIFIEX_TDLS_ENABLE_LINK:
775                 return mwifiex_tdls_process_enable_link(priv, peer);
776         case MWIFIEX_TDLS_DISABLE_LINK:
777                 return mwifiex_tdls_process_disable_link(priv, peer);
778         case MWIFIEX_TDLS_CREATE_LINK:
779                 return mwifiex_tdls_process_create_link(priv, peer);
780         case MWIFIEX_TDLS_CONFIG_LINK:
781                 return mwifiex_tdls_process_config_link(priv, peer);
782         }
783         return 0;
784 }
785
786 int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, u8 *mac)
787 {
788         struct mwifiex_sta_node *sta_ptr;
789
790         sta_ptr = mwifiex_get_sta_entry(priv, mac);
791         if (sta_ptr)
792                 return sta_ptr->tdls_status;
793
794         return TDLS_NOT_SETUP;
795 }