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