blob: f7185338a0fad33508f17837041cbdb2c2d90d68 [file] [log] [blame]
Arik Nemtsov95224fe2014-05-01 10:17:28 +03001/*
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>
Arik Nemtsovc887f0d32014-06-11 17:18:25 +030011#include <net/cfg80211.h>
Arik Nemtsov95224fe2014-05-01 10:17:28 +030012#include "ieee80211_i.h"
Arik Nemtsovee10f2c2014-06-11 17:18:27 +030013#include "driver-ops.h"
Arik Nemtsov95224fe2014-05-01 10:17:28 +030014
Arik Nemtsov17e6a592014-06-11 17:18:20 +030015/* 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
Arik Nemtsov95224fe2014-05-01 10:17:28 +030036static 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
Johannes Berg3b3a0162014-05-19 17:19:31 +020066static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
67 const u8 *peer, const u8 *bssid)
Arik Nemtsov95224fe2014-05-01 10:17:28 +030068{
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
81static int
82ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +020083 const u8 *peer, u8 action_code, u8 dialog_token,
Arik Nemtsov95224fe2014-05-01 10:17:28 +030084 u16 status_code, struct sk_buff *skb)
85{
86 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
87 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
88 struct ieee80211_tdls_data *tf;
89
90 tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
91
92 memcpy(tf->da, peer, ETH_ALEN);
93 memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
94 tf->ether_type = cpu_to_be16(ETH_P_TDLS);
95 tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
96
97 switch (action_code) {
98 case WLAN_TDLS_SETUP_REQUEST:
99 tf->category = WLAN_CATEGORY_TDLS;
100 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
101
102 skb_put(skb, sizeof(tf->u.setup_req));
103 tf->u.setup_req.dialog_token = dialog_token;
104 tf->u.setup_req.capability =
105 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
106
107 ieee80211_add_srates_ie(sdata, skb, false, band);
108 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
109 ieee80211_tdls_add_ext_capab(skb);
110 break;
111 case WLAN_TDLS_SETUP_RESPONSE:
112 tf->category = WLAN_CATEGORY_TDLS;
113 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
114
115 skb_put(skb, sizeof(tf->u.setup_resp));
116 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
117 tf->u.setup_resp.dialog_token = dialog_token;
118 tf->u.setup_resp.capability =
119 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
120
121 ieee80211_add_srates_ie(sdata, skb, false, band);
122 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
123 ieee80211_tdls_add_ext_capab(skb);
124 break;
125 case WLAN_TDLS_SETUP_CONFIRM:
126 tf->category = WLAN_CATEGORY_TDLS;
127 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
128
129 skb_put(skb, sizeof(tf->u.setup_cfm));
130 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
131 tf->u.setup_cfm.dialog_token = dialog_token;
132 break;
133 case WLAN_TDLS_TEARDOWN:
134 tf->category = WLAN_CATEGORY_TDLS;
135 tf->action_code = WLAN_TDLS_TEARDOWN;
136
137 skb_put(skb, sizeof(tf->u.teardown));
138 tf->u.teardown.reason_code = cpu_to_le16(status_code);
139 break;
140 case WLAN_TDLS_DISCOVERY_REQUEST:
141 tf->category = WLAN_CATEGORY_TDLS;
142 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
143
144 skb_put(skb, sizeof(tf->u.discover_req));
145 tf->u.discover_req.dialog_token = dialog_token;
146 break;
147 default:
148 return -EINVAL;
149 }
150
151 return 0;
152}
153
154static int
155ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +0200156 const u8 *peer, u8 action_code, u8 dialog_token,
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300157 u16 status_code, struct sk_buff *skb)
158{
159 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
160 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
161 struct ieee80211_mgmt *mgmt;
162
163 mgmt = (void *)skb_put(skb, 24);
164 memset(mgmt, 0, 24);
165 memcpy(mgmt->da, peer, ETH_ALEN);
166 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
167 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
168
169 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
170 IEEE80211_STYPE_ACTION);
171
172 switch (action_code) {
173 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
174 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
175 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
176 mgmt->u.action.u.tdls_discover_resp.action_code =
177 WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
178 mgmt->u.action.u.tdls_discover_resp.dialog_token =
179 dialog_token;
180 mgmt->u.action.u.tdls_discover_resp.capability =
181 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
182
183 ieee80211_add_srates_ie(sdata, skb, false, band);
184 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
185 ieee80211_tdls_add_ext_capab(skb);
186 break;
187 default:
188 return -EINVAL;
189 }
190
191 return 0;
192}
193
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300194static int
195ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
196 const u8 *peer, u8 action_code,
197 u8 dialog_token, u16 status_code,
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300198 u32 peer_capability, bool initiator,
199 const u8 *extra_ies, size_t extra_ies_len)
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300200{
201 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
202 struct ieee80211_local *local = sdata->local;
203 struct sk_buff *skb = NULL;
204 bool send_direct;
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300205 const u8 *init_addr, *rsp_addr;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300206 int ret;
207
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300208 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
209 max(sizeof(struct ieee80211_mgmt),
210 sizeof(struct ieee80211_tdls_data)) +
211 50 + /* supported rates */
212 7 + /* ext capab */
213 extra_ies_len +
214 sizeof(struct ieee80211_tdls_lnkie));
215 if (!skb)
216 return -ENOMEM;
217
218 skb_reserve(skb, local->hw.extra_tx_headroom);
219
220 switch (action_code) {
221 case WLAN_TDLS_SETUP_REQUEST:
222 case WLAN_TDLS_SETUP_RESPONSE:
223 case WLAN_TDLS_SETUP_CONFIRM:
224 case WLAN_TDLS_TEARDOWN:
225 case WLAN_TDLS_DISCOVERY_REQUEST:
226 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
227 action_code, dialog_token,
228 status_code, skb);
229 send_direct = false;
230 break;
231 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
232 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
233 dialog_token, status_code,
234 skb);
235 send_direct = true;
236 break;
237 default:
238 ret = -ENOTSUPP;
239 break;
240 }
241
242 if (ret < 0)
243 goto fail;
244
245 if (extra_ies_len)
246 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
247
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300248 /* sanity check for initiator */
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300249 switch (action_code) {
250 case WLAN_TDLS_SETUP_REQUEST:
251 case WLAN_TDLS_SETUP_CONFIRM:
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300252 case WLAN_TDLS_DISCOVERY_REQUEST:
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300253 if (!initiator) {
254 ret = -EINVAL;
255 goto fail;
256 }
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300257 break;
258 case WLAN_TDLS_SETUP_RESPONSE:
259 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300260 if (initiator) {
261 ret = -EINVAL;
262 goto fail;
263 }
264 break;
265 case WLAN_TDLS_TEARDOWN:
266 /* any value is ok */
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300267 break;
268 default:
269 ret = -ENOTSUPP;
270 goto fail;
271 }
272
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300273 if (initiator) {
274 init_addr = sdata->vif.addr;
275 rsp_addr = peer;
276 } else {
277 init_addr = peer;
278 rsp_addr = sdata->vif.addr;
279 }
280
281 ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr,
282 sdata->u.mgd.bssid);
283
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300284 if (send_direct) {
285 ieee80211_tx_skb(sdata, skb);
286 return 0;
287 }
288
289 /*
290 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
291 * we should default to AC_VI.
292 */
293 switch (action_code) {
294 case WLAN_TDLS_SETUP_REQUEST:
295 case WLAN_TDLS_SETUP_RESPONSE:
296 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
297 skb->priority = 2;
298 break;
299 default:
300 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
301 skb->priority = 5;
302 break;
303 }
304
305 /* disable bottom halves when entering the Tx path */
306 local_bh_disable();
307 ret = ieee80211_subif_start_xmit(skb, dev);
308 local_bh_enable();
309
310 return ret;
311
312fail:
313 dev_kfree_skb(skb);
314 return ret;
315}
316
Arik Nemtsov191dd462014-06-11 17:18:23 +0300317static int
318ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
319 const u8 *peer, u8 action_code, u8 dialog_token,
320 u16 status_code, u32 peer_capability, bool initiator,
321 const u8 *extra_ies, size_t extra_ies_len)
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300322{
323 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
324 struct ieee80211_local *local = sdata->local;
325 int ret;
326
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300327 mutex_lock(&local->mtx);
328
329 /* we don't support concurrent TDLS peer setups */
330 if (!is_zero_ether_addr(sdata->tdls_peer) &&
Arik Nemtsov191dd462014-06-11 17:18:23 +0300331 !ether_addr_equal(sdata->tdls_peer, peer)) {
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300332 ret = -EBUSY;
333 goto exit;
334 }
335
Arik Nemtsov7adc3e42014-06-11 17:18:26 +0300336 /*
337 * make sure we have a STA representing the peer so we drop or buffer
338 * non-TDLS-setup frames to the peer. We can't send other packets
339 * during setup through the AP path
340 */
341 rcu_read_lock();
342 if (!sta_info_get(sdata, peer)) {
343 rcu_read_unlock();
344 ret = -ENOLINK;
345 goto exit;
346 }
347 rcu_read_unlock();
348
Arik Nemtsovdb67d662014-06-11 17:18:24 +0300349 ieee80211_flush_queues(local, sdata);
350
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300351 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
352 dialog_token, status_code,
Arik Nemtsov2fb6b9b2014-06-11 17:18:22 +0300353 peer_capability, initiator,
354 extra_ies, extra_ies_len);
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300355 if (ret < 0)
356 goto exit;
357
Arik Nemtsov191dd462014-06-11 17:18:23 +0300358 memcpy(sdata->tdls_peer, peer, ETH_ALEN);
359 ieee80211_queue_delayed_work(&sdata->local->hw,
360 &sdata->tdls_peer_del_work,
361 TDLS_PEER_SETUP_TIMEOUT);
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300362
363exit:
364 mutex_unlock(&local->mtx);
Arik Nemtsov191dd462014-06-11 17:18:23 +0300365 return ret;
366}
367
Arik Nemtsovdb67d662014-06-11 17:18:24 +0300368static int
369ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
370 const u8 *peer, u8 action_code, u8 dialog_token,
371 u16 status_code, u32 peer_capability,
372 bool initiator, const u8 *extra_ies,
373 size_t extra_ies_len)
374{
375 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
376 struct ieee80211_local *local = sdata->local;
377 struct sta_info *sta;
378 int ret;
379
380 /*
381 * No packets can be transmitted to the peer via the AP during setup -
382 * the STA is set as a TDLS peer, but is not authorized.
383 * During teardown, we prevent direct transmissions by stopping the
384 * queues and flushing all direct packets.
385 */
386 ieee80211_stop_vif_queues(local, sdata,
387 IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
388 ieee80211_flush_queues(local, sdata);
389
390 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
391 dialog_token, status_code,
392 peer_capability, initiator,
393 extra_ies, extra_ies_len);
394 if (ret < 0)
395 sdata_err(sdata, "Failed sending TDLS teardown packet %d\n",
396 ret);
397
398 /*
399 * Remove the STA AUTH flag to force further traffic through the AP. If
400 * the STA was unreachable, it was already removed.
401 */
402 rcu_read_lock();
403 sta = sta_info_get(sdata, peer);
404 if (sta)
405 clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
406 rcu_read_unlock();
407
408 ieee80211_wake_vif_queues(local, sdata,
409 IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
410
411 return 0;
412}
413
Arik Nemtsov191dd462014-06-11 17:18:23 +0300414int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
415 const u8 *peer, u8 action_code, u8 dialog_token,
416 u16 status_code, u32 peer_capability,
417 bool initiator, const u8 *extra_ies,
418 size_t extra_ies_len)
419{
420 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
421 int ret;
422
423 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
424 return -ENOTSUPP;
425
426 /* make sure we are in managed mode, and associated */
427 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
428 !sdata->u.mgd.associated)
429 return -EINVAL;
430
431 switch (action_code) {
432 case WLAN_TDLS_SETUP_REQUEST:
433 case WLAN_TDLS_SETUP_RESPONSE:
434 ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code,
435 dialog_token, status_code,
436 peer_capability, initiator,
437 extra_ies, extra_ies_len);
438 break;
439 case WLAN_TDLS_TEARDOWN:
Arik Nemtsovdb67d662014-06-11 17:18:24 +0300440 ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer,
441 action_code, dialog_token,
442 status_code,
443 peer_capability, initiator,
444 extra_ies, extra_ies_len);
445 break;
Arik Nemtsov191dd462014-06-11 17:18:23 +0300446 case WLAN_TDLS_DISCOVERY_REQUEST:
Arik Nemtsovee10f2c2014-06-11 17:18:27 +0300447 /*
448 * Protect the discovery so we can hear the TDLS discovery
449 * response frame. It is transmitted directly and not buffered
450 * by the AP.
451 */
452 drv_mgd_protect_tdls_discover(sdata->local, sdata);
453 /* fall-through */
454 case WLAN_TDLS_SETUP_CONFIRM:
Arik Nemtsov191dd462014-06-11 17:18:23 +0300455 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
456 /* no special handling */
457 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
458 action_code,
459 dialog_token,
460 status_code,
461 peer_capability,
462 initiator, extra_ies,
463 extra_ies_len);
464 break;
465 default:
466 ret = -EOPNOTSUPP;
467 break;
468 }
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300469
470 tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n",
471 action_code, peer, ret);
472 return ret;
473}
474
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300475int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
Johannes Berg3b3a0162014-05-19 17:19:31 +0200476 const u8 *peer, enum nl80211_tdls_operation oper)
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300477{
478 struct sta_info *sta;
479 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300480 struct ieee80211_local *local = sdata->local;
481 int ret;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300482
483 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
484 return -ENOTSUPP;
485
486 if (sdata->vif.type != NL80211_IFTYPE_STATION)
487 return -EINVAL;
488
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300489 switch (oper) {
490 case NL80211_TDLS_ENABLE_LINK:
491 case NL80211_TDLS_DISABLE_LINK:
492 break;
493 case NL80211_TDLS_TEARDOWN:
494 case NL80211_TDLS_SETUP:
495 case NL80211_TDLS_DISCOVERY_REQ:
496 /* We don't support in-driver setup/teardown/discovery */
497 return -ENOTSUPP;
498 }
499
500 mutex_lock(&local->mtx);
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300501 tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
502
503 switch (oper) {
504 case NL80211_TDLS_ENABLE_LINK:
505 rcu_read_lock();
506 sta = sta_info_get(sdata, peer);
507 if (!sta) {
508 rcu_read_unlock();
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300509 ret = -ENOLINK;
510 break;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300511 }
512
513 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
514 rcu_read_unlock();
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300515
516 WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) ||
517 !ether_addr_equal(sdata->tdls_peer, peer));
518 ret = 0;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300519 break;
520 case NL80211_TDLS_DISABLE_LINK:
Arik Nemtsovdb67d662014-06-11 17:18:24 +0300521 /* flush a potentially queued teardown packet */
522 ieee80211_flush_queues(local, sdata);
523
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300524 ret = sta_info_destroy_addr(sdata, peer);
525 break;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300526 default:
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300527 ret = -ENOTSUPP;
528 break;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300529 }
530
Arik Nemtsov17e6a592014-06-11 17:18:20 +0300531 if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) {
532 cancel_delayed_work(&sdata->tdls_peer_del_work);
533 eth_zero_addr(sdata->tdls_peer);
534 }
535
536 mutex_unlock(&local->mtx);
537 return ret;
Arik Nemtsov95224fe2014-05-01 10:17:28 +0300538}
Arik Nemtsovc887f0d32014-06-11 17:18:25 +0300539
540void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer,
541 enum nl80211_tdls_operation oper,
542 u16 reason_code, gfp_t gfp)
543{
544 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
545
546 if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) {
547 sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n",
548 oper);
549 return;
550 }
551
552 cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp);
553}
554EXPORT_SYMBOL(ieee80211_tdls_oper_request);