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