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