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