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