]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/mac80211/tdls.c
mac80211: set TDLS capab to zero on failure frames
[karo-tx-linux.git] / net / mac80211 / tdls.c
1 /*
2  * mac80211 TDLS handling code
3  *
4  * Copyright 2006-2010  Johannes Berg <johannes@sipsolutions.net>
5  * Copyright 2014, Intel Corporation
6  *
7  * This file is GPLv2 as found in COPYING.
8  */
9
10 #include <linux/ieee80211.h>
11 #include <net/cfg80211.h>
12 #include "ieee80211_i.h"
13 #include "driver-ops.h"
14
15 /* give usermode some time for retries in setting up the TDLS session */
16 #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ)
17
18 void ieee80211_tdls_peer_del_work(struct work_struct *wk)
19 {
20         struct ieee80211_sub_if_data *sdata;
21         struct ieee80211_local *local;
22
23         sdata = container_of(wk, struct ieee80211_sub_if_data,
24                              tdls_peer_del_work.work);
25         local = sdata->local;
26
27         mutex_lock(&local->mtx);
28         if (!is_zero_ether_addr(sdata->tdls_peer)) {
29                 tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer);
30                 sta_info_destroy_addr(sdata, sdata->tdls_peer);
31                 eth_zero_addr(sdata->tdls_peer);
32         }
33         mutex_unlock(&local->mtx);
34 }
35
36 static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
37 {
38         u8 *pos = (void *)skb_put(skb, 7);
39
40         *pos++ = WLAN_EID_EXT_CAPABILITY;
41         *pos++ = 5; /* len */
42         *pos++ = 0x0;
43         *pos++ = 0x0;
44         *pos++ = 0x0;
45         *pos++ = 0x0;
46         *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
47 }
48
49 static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata,
50                                         u16 status_code)
51 {
52         struct ieee80211_local *local = sdata->local;
53         u16 capab;
54
55         /* The capability will be 0 when sending a failure code */
56         if (status_code != 0)
57                 return 0;
58
59         capab = 0;
60         if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
61                 return capab;
62
63         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
64                 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
65         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
66                 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
67
68         return capab;
69 }
70
71 static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
72                                        struct sk_buff *skb, const u8 *peer,
73                                        bool initiator)
74 {
75         struct ieee80211_tdls_lnkie *lnkid;
76         const u8 *init_addr, *rsp_addr;
77
78         if (initiator) {
79                 init_addr = sdata->vif.addr;
80                 rsp_addr = peer;
81         } else {
82                 init_addr = peer;
83                 rsp_addr = sdata->vif.addr;
84         }
85
86         lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
87
88         lnkid->ie_type = WLAN_EID_LINK_ID;
89         lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
90
91         memcpy(lnkid->bssid, sdata->u.mgd.bssid, ETH_ALEN);
92         memcpy(lnkid->init_sta, init_addr, ETH_ALEN);
93         memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
94 }
95
96 static void
97 ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
98                                    struct sk_buff *skb, const u8 *peer,
99                                    u8 action_code, bool initiator,
100                                    const u8 *extra_ies, size_t extra_ies_len)
101 {
102         enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
103         size_t offset = 0, noffset;
104         u8 *pos;
105
106         ieee80211_add_srates_ie(sdata, skb, false, band);
107         ieee80211_add_ext_srates_ie(sdata, skb, false, band);
108
109         /* add any custom IEs that go before Extended Capabilities */
110         if (extra_ies_len) {
111                 static const u8 before_ext_cap[] = {
112                         WLAN_EID_SUPP_RATES,
113                         WLAN_EID_COUNTRY,
114                         WLAN_EID_EXT_SUPP_RATES,
115                         WLAN_EID_SUPPORTED_CHANNELS,
116                         WLAN_EID_RSN,
117                 };
118                 noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
119                                              before_ext_cap,
120                                              ARRAY_SIZE(before_ext_cap),
121                                              offset);
122                 pos = skb_put(skb, noffset - offset);
123                 memcpy(pos, extra_ies + offset, noffset - offset);
124                 offset = noffset;
125         }
126
127         ieee80211_tdls_add_ext_capab(skb);
128
129         /* add any custom IEs that go before HT capabilities */
130         if (extra_ies_len) {
131                 static const u8 before_ht_cap[] = {
132                         WLAN_EID_SUPP_RATES,
133                         WLAN_EID_COUNTRY,
134                         WLAN_EID_EXT_SUPP_RATES,
135                         WLAN_EID_SUPPORTED_CHANNELS,
136                         WLAN_EID_RSN,
137                         WLAN_EID_EXT_CAPABILITY,
138                         WLAN_EID_QOS_CAPA,
139                         WLAN_EID_FAST_BSS_TRANSITION,
140                         WLAN_EID_TIMEOUT_INTERVAL,
141                         WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
142                 };
143                 noffset = ieee80211_ie_split(extra_ies, extra_ies_len,
144                                              before_ht_cap,
145                                              ARRAY_SIZE(before_ht_cap),
146                                              offset);
147                 pos = skb_put(skb, noffset - offset);
148                 memcpy(pos, extra_ies + offset, noffset - offset);
149                 offset = noffset;
150         }
151
152         /* add any remaining IEs */
153         if (extra_ies_len) {
154                 noffset = extra_ies_len;
155                 pos = skb_put(skb, noffset - offset);
156                 memcpy(pos, extra_ies + offset, noffset - offset);
157         }
158
159         ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
160 }
161
162 static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata,
163                                    struct sk_buff *skb, const u8 *peer,
164                                    u8 action_code, u16 status_code,
165                                    bool initiator, const u8 *extra_ies,
166                                    size_t extra_ies_len)
167 {
168         switch (action_code) {
169         case WLAN_TDLS_SETUP_REQUEST:
170         case WLAN_TDLS_SETUP_RESPONSE:
171         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
172                 if (status_code == 0)
173                         ieee80211_tdls_add_setup_start_ies(sdata, skb, peer,
174                                                            action_code,
175                                                            initiator,
176                                                            extra_ies,
177                                                            extra_ies_len);
178                 break;
179         case WLAN_TDLS_SETUP_CONFIRM:
180         case WLAN_TDLS_TEARDOWN:
181         case WLAN_TDLS_DISCOVERY_REQUEST:
182                 if (extra_ies_len)
183                         memcpy(skb_put(skb, extra_ies_len), extra_ies,
184                                extra_ies_len);
185                 if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN)
186                         ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator);
187                 break;
188         }
189
190 }
191
192 static int
193 ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
194                                const u8 *peer, u8 action_code, u8 dialog_token,
195                                u16 status_code, struct sk_buff *skb)
196 {
197         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
198         struct ieee80211_tdls_data *tf;
199
200         tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
201
202         memcpy(tf->da, peer, ETH_ALEN);
203         memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
204         tf->ether_type = cpu_to_be16(ETH_P_TDLS);
205         tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
206
207         switch (action_code) {
208         case WLAN_TDLS_SETUP_REQUEST:
209                 tf->category = WLAN_CATEGORY_TDLS;
210                 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
211
212                 skb_put(skb, sizeof(tf->u.setup_req));
213                 tf->u.setup_req.dialog_token = dialog_token;
214                 tf->u.setup_req.capability =
215                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata,
216                                                                  status_code));
217                 break;
218         case WLAN_TDLS_SETUP_RESPONSE:
219                 tf->category = WLAN_CATEGORY_TDLS;
220                 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
221
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 =
226                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata,
227                                                                  status_code));
228                 break;
229         case WLAN_TDLS_SETUP_CONFIRM:
230                 tf->category = WLAN_CATEGORY_TDLS;
231                 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
232
233                 skb_put(skb, sizeof(tf->u.setup_cfm));
234                 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
235                 tf->u.setup_cfm.dialog_token = dialog_token;
236                 break;
237         case WLAN_TDLS_TEARDOWN:
238                 tf->category = WLAN_CATEGORY_TDLS;
239                 tf->action_code = WLAN_TDLS_TEARDOWN;
240
241                 skb_put(skb, sizeof(tf->u.teardown));
242                 tf->u.teardown.reason_code = cpu_to_le16(status_code);
243                 break;
244         case WLAN_TDLS_DISCOVERY_REQUEST:
245                 tf->category = WLAN_CATEGORY_TDLS;
246                 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
247
248                 skb_put(skb, sizeof(tf->u.discover_req));
249                 tf->u.discover_req.dialog_token = dialog_token;
250                 break;
251         default:
252                 return -EINVAL;
253         }
254
255         return 0;
256 }
257
258 static int
259 ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
260                            const u8 *peer, u8 action_code, u8 dialog_token,
261                            u16 status_code, struct sk_buff *skb)
262 {
263         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
264         struct ieee80211_mgmt *mgmt;
265
266         mgmt = (void *)skb_put(skb, 24);
267         memset(mgmt, 0, 24);
268         memcpy(mgmt->da, peer, ETH_ALEN);
269         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
270         memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
271
272         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
273                                           IEEE80211_STYPE_ACTION);
274
275         switch (action_code) {
276         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
277                 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
278                 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
279                 mgmt->u.action.u.tdls_discover_resp.action_code =
280                         WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
281                 mgmt->u.action.u.tdls_discover_resp.dialog_token =
282                         dialog_token;
283                 mgmt->u.action.u.tdls_discover_resp.capability =
284                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata,
285                                                                  status_code));
286                 break;
287         default:
288                 return -EINVAL;
289         }
290
291         return 0;
292 }
293
294 static int
295 ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
296                                 const u8 *peer, u8 action_code,
297                                 u8 dialog_token, u16 status_code,
298                                 u32 peer_capability, bool initiator,
299                                 const u8 *extra_ies, size_t extra_ies_len)
300 {
301         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
302         struct ieee80211_local *local = sdata->local;
303         struct sk_buff *skb = NULL;
304         bool send_direct;
305         struct sta_info *sta;
306         int ret;
307
308         skb = dev_alloc_skb(local->hw.extra_tx_headroom +
309                             max(sizeof(struct ieee80211_mgmt),
310                                 sizeof(struct ieee80211_tdls_data)) +
311                             50 + /* supported rates */
312                             7 + /* ext capab */
313                             extra_ies_len +
314                             sizeof(struct ieee80211_tdls_lnkie));
315         if (!skb)
316                 return -ENOMEM;
317
318         skb_reserve(skb, local->hw.extra_tx_headroom);
319
320         switch (action_code) {
321         case WLAN_TDLS_SETUP_REQUEST:
322         case WLAN_TDLS_SETUP_RESPONSE:
323         case WLAN_TDLS_SETUP_CONFIRM:
324         case WLAN_TDLS_TEARDOWN:
325         case WLAN_TDLS_DISCOVERY_REQUEST:
326                 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
327                                                      action_code, dialog_token,
328                                                      status_code, skb);
329                 send_direct = false;
330                 break;
331         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
332                 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
333                                                  dialog_token, status_code,
334                                                  skb);
335                 send_direct = true;
336                 break;
337         default:
338                 ret = -ENOTSUPP;
339                 break;
340         }
341
342         if (ret < 0)
343                 goto fail;
344
345         rcu_read_lock();
346         sta = sta_info_get(sdata, peer);
347
348         /* infer the initiator if we can, to support old userspace */
349         switch (action_code) {
350         case WLAN_TDLS_SETUP_REQUEST:
351                 if (sta)
352                         set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
353                 /* fall-through */
354         case WLAN_TDLS_SETUP_CONFIRM:
355         case WLAN_TDLS_DISCOVERY_REQUEST:
356                 initiator = true;
357                 break;
358         case WLAN_TDLS_SETUP_RESPONSE:
359                 /*
360                  * In some testing scenarios, we send a request and response.
361                  * Make the last packet sent take effect for the initiator
362                  * value.
363                  */
364                 if (sta)
365                         clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
366                 /* fall-through */
367         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
368                 initiator = false;
369                 break;
370         case WLAN_TDLS_TEARDOWN:
371                 /* any value is ok */
372                 break;
373         default:
374                 ret = -ENOTSUPP;
375                 break;
376         }
377
378         if (sta && test_sta_flag(sta, WLAN_STA_TDLS_INITIATOR))
379                 initiator = true;
380
381         rcu_read_unlock();
382         if (ret < 0)
383                 goto fail;
384
385         ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code,
386                                initiator, extra_ies, extra_ies_len);
387         if (send_direct) {
388                 ieee80211_tx_skb(sdata, skb);
389                 return 0;
390         }
391
392         /*
393          * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
394          * we should default to AC_VI.
395          */
396         switch (action_code) {
397         case WLAN_TDLS_SETUP_REQUEST:
398         case WLAN_TDLS_SETUP_RESPONSE:
399                 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
400                 skb->priority = 2;
401                 break;
402         default:
403                 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
404                 skb->priority = 5;
405                 break;
406         }
407
408         /* disable bottom halves when entering the Tx path */
409         local_bh_disable();
410         ret = ieee80211_subif_start_xmit(skb, dev);
411         local_bh_enable();
412
413         return ret;
414
415 fail:
416         dev_kfree_skb(skb);
417         return ret;
418 }
419
420 static int
421 ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
422                           const u8 *peer, u8 action_code, u8 dialog_token,
423                           u16 status_code, u32 peer_capability, bool initiator,
424                           const u8 *extra_ies, size_t extra_ies_len)
425 {
426         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
427         struct ieee80211_local *local = sdata->local;
428         int ret;
429
430         mutex_lock(&local->mtx);
431
432         /* we don't support concurrent TDLS peer setups */
433         if (!is_zero_ether_addr(sdata->tdls_peer) &&
434             !ether_addr_equal(sdata->tdls_peer, peer)) {
435                 ret = -EBUSY;
436                 goto exit;
437         }
438
439         /*
440          * make sure we have a STA representing the peer so we drop or buffer
441          * non-TDLS-setup frames to the peer. We can't send other packets
442          * during setup through the AP path.
443          * Allow error packets to be sent - sometimes we don't even add a STA
444          * before failing the setup.
445          */
446         if (status_code == 0) {
447                 rcu_read_lock();
448                 if (!sta_info_get(sdata, peer)) {
449                         rcu_read_unlock();
450                         ret = -ENOLINK;
451                         goto exit;
452                 }
453                 rcu_read_unlock();
454         }
455
456         ieee80211_flush_queues(local, sdata);
457
458         ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
459                                               dialog_token, status_code,
460                                               peer_capability, initiator,
461                                               extra_ies, extra_ies_len);
462         if (ret < 0)
463                 goto exit;
464
465         memcpy(sdata->tdls_peer, peer, ETH_ALEN);
466         ieee80211_queue_delayed_work(&sdata->local->hw,
467                                      &sdata->tdls_peer_del_work,
468                                      TDLS_PEER_SETUP_TIMEOUT);
469
470 exit:
471         mutex_unlock(&local->mtx);
472         return ret;
473 }
474
475 static int
476 ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
477                              const u8 *peer, u8 action_code, u8 dialog_token,
478                              u16 status_code, u32 peer_capability,
479                              bool initiator, const u8 *extra_ies,
480                              size_t extra_ies_len)
481 {
482         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
483         struct ieee80211_local *local = sdata->local;
484         struct sta_info *sta;
485         int ret;
486
487         /*
488          * No packets can be transmitted to the peer via the AP during setup -
489          * the STA is set as a TDLS peer, but is not authorized.
490          * During teardown, we prevent direct transmissions by stopping the
491          * queues and flushing all direct packets.
492          */
493         ieee80211_stop_vif_queues(local, sdata,
494                                   IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
495         ieee80211_flush_queues(local, sdata);
496
497         ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
498                                               dialog_token, status_code,
499                                               peer_capability, initiator,
500                                               extra_ies, extra_ies_len);
501         if (ret < 0)
502                 sdata_err(sdata, "Failed sending TDLS teardown packet %d\n",
503                           ret);
504
505         /*
506          * Remove the STA AUTH flag to force further traffic through the AP. If
507          * the STA was unreachable, it was already removed.
508          */
509         rcu_read_lock();
510         sta = sta_info_get(sdata, peer);
511         if (sta)
512                 clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
513         rcu_read_unlock();
514
515         ieee80211_wake_vif_queues(local, sdata,
516                                   IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
517
518         return 0;
519 }
520
521 int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
522                         const u8 *peer, u8 action_code, u8 dialog_token,
523                         u16 status_code, u32 peer_capability,
524                         bool initiator, const u8 *extra_ies,
525                         size_t extra_ies_len)
526 {
527         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
528         int ret;
529
530         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
531                 return -ENOTSUPP;
532
533         /* make sure we are in managed mode, and associated */
534         if (sdata->vif.type != NL80211_IFTYPE_STATION ||
535             !sdata->u.mgd.associated)
536                 return -EINVAL;
537
538         switch (action_code) {
539         case WLAN_TDLS_SETUP_REQUEST:
540         case WLAN_TDLS_SETUP_RESPONSE:
541                 ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code,
542                                                 dialog_token, status_code,
543                                                 peer_capability, initiator,
544                                                 extra_ies, extra_ies_len);
545                 break;
546         case WLAN_TDLS_TEARDOWN:
547                 ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer,
548                                                    action_code, dialog_token,
549                                                    status_code,
550                                                    peer_capability, initiator,
551                                                    extra_ies, extra_ies_len);
552                 break;
553         case WLAN_TDLS_DISCOVERY_REQUEST:
554                 /*
555                  * Protect the discovery so we can hear the TDLS discovery
556                  * response frame. It is transmitted directly and not buffered
557                  * by the AP.
558                  */
559                 drv_mgd_protect_tdls_discover(sdata->local, sdata);
560                 /* fall-through */
561         case WLAN_TDLS_SETUP_CONFIRM:
562         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
563                 /* no special handling */
564                 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
565                                                       action_code,
566                                                       dialog_token,
567                                                       status_code,
568                                                       peer_capability,
569                                                       initiator, extra_ies,
570                                                       extra_ies_len);
571                 break;
572         default:
573                 ret = -EOPNOTSUPP;
574                 break;
575         }
576
577         tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n",
578                  action_code, peer, ret);
579         return ret;
580 }
581
582 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
583                         const u8 *peer, enum nl80211_tdls_operation oper)
584 {
585         struct sta_info *sta;
586         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
587         struct ieee80211_local *local = sdata->local;
588         int ret;
589
590         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
591                 return -ENOTSUPP;
592
593         if (sdata->vif.type != NL80211_IFTYPE_STATION)
594                 return -EINVAL;
595
596         switch (oper) {
597         case NL80211_TDLS_ENABLE_LINK:
598         case NL80211_TDLS_DISABLE_LINK:
599                 break;
600         case NL80211_TDLS_TEARDOWN:
601         case NL80211_TDLS_SETUP:
602         case NL80211_TDLS_DISCOVERY_REQ:
603                 /* We don't support in-driver setup/teardown/discovery */
604                 return -ENOTSUPP;
605         }
606
607         mutex_lock(&local->mtx);
608         tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
609
610         switch (oper) {
611         case NL80211_TDLS_ENABLE_LINK:
612                 rcu_read_lock();
613                 sta = sta_info_get(sdata, peer);
614                 if (!sta) {
615                         rcu_read_unlock();
616                         ret = -ENOLINK;
617                         break;
618                 }
619
620                 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
621                 rcu_read_unlock();
622
623                 WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) ||
624                              !ether_addr_equal(sdata->tdls_peer, peer));
625                 ret = 0;
626                 break;
627         case NL80211_TDLS_DISABLE_LINK:
628                 /* flush a potentially queued teardown packet */
629                 ieee80211_flush_queues(local, sdata);
630
631                 ret = sta_info_destroy_addr(sdata, peer);
632                 break;
633         default:
634                 ret = -ENOTSUPP;
635                 break;
636         }
637
638         if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) {
639                 cancel_delayed_work(&sdata->tdls_peer_del_work);
640                 eth_zero_addr(sdata->tdls_peer);
641         }
642
643         mutex_unlock(&local->mtx);
644         return ret;
645 }
646
647 void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer,
648                                  enum nl80211_tdls_operation oper,
649                                  u16 reason_code, gfp_t gfp)
650 {
651         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
652
653         if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) {
654                 sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n",
655                           oper);
656                 return;
657         }
658
659         cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp);
660 }
661 EXPORT_SYMBOL(ieee80211_tdls_oper_request);