]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/mac80211/tdls.c
mac80211: add API to request TDLS operation from userspace
[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
14 /* give usermode some time for retries in setting up the TDLS session */
15 #define TDLS_PEER_SETUP_TIMEOUT (15 * HZ)
16
17 void ieee80211_tdls_peer_del_work(struct work_struct *wk)
18 {
19         struct ieee80211_sub_if_data *sdata;
20         struct ieee80211_local *local;
21
22         sdata = container_of(wk, struct ieee80211_sub_if_data,
23                              tdls_peer_del_work.work);
24         local = sdata->local;
25
26         mutex_lock(&local->mtx);
27         if (!is_zero_ether_addr(sdata->tdls_peer)) {
28                 tdls_dbg(sdata, "TDLS del peer %pM\n", sdata->tdls_peer);
29                 sta_info_destroy_addr(sdata, sdata->tdls_peer);
30                 eth_zero_addr(sdata->tdls_peer);
31         }
32         mutex_unlock(&local->mtx);
33 }
34
35 static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
36 {
37         u8 *pos = (void *)skb_put(skb, 7);
38
39         *pos++ = WLAN_EID_EXT_CAPABILITY;
40         *pos++ = 5; /* len */
41         *pos++ = 0x0;
42         *pos++ = 0x0;
43         *pos++ = 0x0;
44         *pos++ = 0x0;
45         *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
46 }
47
48 static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
49 {
50         struct ieee80211_local *local = sdata->local;
51         u16 capab;
52
53         capab = 0;
54         if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
55                 return capab;
56
57         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
58                 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
59         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
60                 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
61
62         return capab;
63 }
64
65 static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
66                                        const u8 *peer, const u8 *bssid)
67 {
68         struct ieee80211_tdls_lnkie *lnkid;
69
70         lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
71
72         lnkid->ie_type = WLAN_EID_LINK_ID;
73         lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
74
75         memcpy(lnkid->bssid, bssid, ETH_ALEN);
76         memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
77         memcpy(lnkid->resp_sta, peer, ETH_ALEN);
78 }
79
80 static int
81 ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
82                                const u8 *peer, u8 action_code, u8 dialog_token,
83                                u16 status_code, struct sk_buff *skb)
84 {
85         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
86         enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
87         struct ieee80211_tdls_data *tf;
88
89         tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
90
91         memcpy(tf->da, peer, ETH_ALEN);
92         memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
93         tf->ether_type = cpu_to_be16(ETH_P_TDLS);
94         tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
95
96         switch (action_code) {
97         case WLAN_TDLS_SETUP_REQUEST:
98                 tf->category = WLAN_CATEGORY_TDLS;
99                 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
100
101                 skb_put(skb, sizeof(tf->u.setup_req));
102                 tf->u.setup_req.dialog_token = dialog_token;
103                 tf->u.setup_req.capability =
104                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
105
106                 ieee80211_add_srates_ie(sdata, skb, false, band);
107                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
108                 ieee80211_tdls_add_ext_capab(skb);
109                 break;
110         case WLAN_TDLS_SETUP_RESPONSE:
111                 tf->category = WLAN_CATEGORY_TDLS;
112                 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
113
114                 skb_put(skb, sizeof(tf->u.setup_resp));
115                 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
116                 tf->u.setup_resp.dialog_token = dialog_token;
117                 tf->u.setup_resp.capability =
118                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
119
120                 ieee80211_add_srates_ie(sdata, skb, false, band);
121                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
122                 ieee80211_tdls_add_ext_capab(skb);
123                 break;
124         case WLAN_TDLS_SETUP_CONFIRM:
125                 tf->category = WLAN_CATEGORY_TDLS;
126                 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
127
128                 skb_put(skb, sizeof(tf->u.setup_cfm));
129                 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
130                 tf->u.setup_cfm.dialog_token = dialog_token;
131                 break;
132         case WLAN_TDLS_TEARDOWN:
133                 tf->category = WLAN_CATEGORY_TDLS;
134                 tf->action_code = WLAN_TDLS_TEARDOWN;
135
136                 skb_put(skb, sizeof(tf->u.teardown));
137                 tf->u.teardown.reason_code = cpu_to_le16(status_code);
138                 break;
139         case WLAN_TDLS_DISCOVERY_REQUEST:
140                 tf->category = WLAN_CATEGORY_TDLS;
141                 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
142
143                 skb_put(skb, sizeof(tf->u.discover_req));
144                 tf->u.discover_req.dialog_token = dialog_token;
145                 break;
146         default:
147                 return -EINVAL;
148         }
149
150         return 0;
151 }
152
153 static int
154 ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
155                            const u8 *peer, u8 action_code, u8 dialog_token,
156                            u16 status_code, struct sk_buff *skb)
157 {
158         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
159         enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
160         struct ieee80211_mgmt *mgmt;
161
162         mgmt = (void *)skb_put(skb, 24);
163         memset(mgmt, 0, 24);
164         memcpy(mgmt->da, peer, ETH_ALEN);
165         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
166         memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
167
168         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
169                                           IEEE80211_STYPE_ACTION);
170
171         switch (action_code) {
172         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
173                 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
174                 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
175                 mgmt->u.action.u.tdls_discover_resp.action_code =
176                         WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
177                 mgmt->u.action.u.tdls_discover_resp.dialog_token =
178                         dialog_token;
179                 mgmt->u.action.u.tdls_discover_resp.capability =
180                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
181
182                 ieee80211_add_srates_ie(sdata, skb, false, band);
183                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
184                 ieee80211_tdls_add_ext_capab(skb);
185                 break;
186         default:
187                 return -EINVAL;
188         }
189
190         return 0;
191 }
192
193 static int
194 ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
195                                 const u8 *peer, u8 action_code,
196                                 u8 dialog_token, u16 status_code,
197                                 u32 peer_capability, bool initiator,
198                                 const u8 *extra_ies, size_t extra_ies_len)
199 {
200         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
201         struct ieee80211_local *local = sdata->local;
202         struct sk_buff *skb = NULL;
203         bool send_direct;
204         const u8 *init_addr, *rsp_addr;
205         int ret;
206
207         skb = dev_alloc_skb(local->hw.extra_tx_headroom +
208                             max(sizeof(struct ieee80211_mgmt),
209                                 sizeof(struct ieee80211_tdls_data)) +
210                             50 + /* supported rates */
211                             7 + /* ext capab */
212                             extra_ies_len +
213                             sizeof(struct ieee80211_tdls_lnkie));
214         if (!skb)
215                 return -ENOMEM;
216
217         skb_reserve(skb, local->hw.extra_tx_headroom);
218
219         switch (action_code) {
220         case WLAN_TDLS_SETUP_REQUEST:
221         case WLAN_TDLS_SETUP_RESPONSE:
222         case WLAN_TDLS_SETUP_CONFIRM:
223         case WLAN_TDLS_TEARDOWN:
224         case WLAN_TDLS_DISCOVERY_REQUEST:
225                 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
226                                                      action_code, dialog_token,
227                                                      status_code, skb);
228                 send_direct = false;
229                 break;
230         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
231                 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
232                                                  dialog_token, status_code,
233                                                  skb);
234                 send_direct = true;
235                 break;
236         default:
237                 ret = -ENOTSUPP;
238                 break;
239         }
240
241         if (ret < 0)
242                 goto fail;
243
244         if (extra_ies_len)
245                 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
246
247         /* sanity check for initiator */
248         switch (action_code) {
249         case WLAN_TDLS_SETUP_REQUEST:
250         case WLAN_TDLS_SETUP_CONFIRM:
251         case WLAN_TDLS_DISCOVERY_REQUEST:
252                 if (!initiator) {
253                         ret = -EINVAL;
254                         goto fail;
255                 }
256                 break;
257         case WLAN_TDLS_SETUP_RESPONSE:
258         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
259                 if (initiator) {
260                         ret = -EINVAL;
261                         goto fail;
262                 }
263                 break;
264         case WLAN_TDLS_TEARDOWN:
265                 /* any value is ok */
266                 break;
267         default:
268                 ret = -ENOTSUPP;
269                 goto fail;
270         }
271
272         if (initiator) {
273                 init_addr = sdata->vif.addr;
274                 rsp_addr = peer;
275         } else {
276                 init_addr = peer;
277                 rsp_addr = sdata->vif.addr;
278         }
279
280         ieee80211_tdls_add_link_ie(skb, init_addr, rsp_addr,
281                                    sdata->u.mgd.bssid);
282
283         if (send_direct) {
284                 ieee80211_tx_skb(sdata, skb);
285                 return 0;
286         }
287
288         /*
289          * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
290          * we should default to AC_VI.
291          */
292         switch (action_code) {
293         case WLAN_TDLS_SETUP_REQUEST:
294         case WLAN_TDLS_SETUP_RESPONSE:
295                 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
296                 skb->priority = 2;
297                 break;
298         default:
299                 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
300                 skb->priority = 5;
301                 break;
302         }
303
304         /* disable bottom halves when entering the Tx path */
305         local_bh_disable();
306         ret = ieee80211_subif_start_xmit(skb, dev);
307         local_bh_enable();
308
309         return ret;
310
311 fail:
312         dev_kfree_skb(skb);
313         return ret;
314 }
315
316 static int
317 ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
318                           const u8 *peer, u8 action_code, u8 dialog_token,
319                           u16 status_code, u32 peer_capability, bool initiator,
320                           const u8 *extra_ies, size_t extra_ies_len)
321 {
322         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
323         struct ieee80211_local *local = sdata->local;
324         int ret;
325
326         mutex_lock(&local->mtx);
327
328         /* we don't support concurrent TDLS peer setups */
329         if (!is_zero_ether_addr(sdata->tdls_peer) &&
330             !ether_addr_equal(sdata->tdls_peer, peer)) {
331                 ret = -EBUSY;
332                 goto exit;
333         }
334
335         ieee80211_flush_queues(local, sdata);
336
337         ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
338                                               dialog_token, status_code,
339                                               peer_capability, initiator,
340                                               extra_ies, extra_ies_len);
341         if (ret < 0)
342                 goto exit;
343
344         memcpy(sdata->tdls_peer, peer, ETH_ALEN);
345         ieee80211_queue_delayed_work(&sdata->local->hw,
346                                      &sdata->tdls_peer_del_work,
347                                      TDLS_PEER_SETUP_TIMEOUT);
348
349 exit:
350         mutex_unlock(&local->mtx);
351         return ret;
352 }
353
354 static int
355 ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
356                              const u8 *peer, u8 action_code, u8 dialog_token,
357                              u16 status_code, u32 peer_capability,
358                              bool initiator, const u8 *extra_ies,
359                              size_t extra_ies_len)
360 {
361         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
362         struct ieee80211_local *local = sdata->local;
363         struct sta_info *sta;
364         int ret;
365
366         /*
367          * No packets can be transmitted to the peer via the AP during setup -
368          * the STA is set as a TDLS peer, but is not authorized.
369          * During teardown, we prevent direct transmissions by stopping the
370          * queues and flushing all direct packets.
371          */
372         ieee80211_stop_vif_queues(local, sdata,
373                                   IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
374         ieee80211_flush_queues(local, sdata);
375
376         ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
377                                               dialog_token, status_code,
378                                               peer_capability, initiator,
379                                               extra_ies, extra_ies_len);
380         if (ret < 0)
381                 sdata_err(sdata, "Failed sending TDLS teardown packet %d\n",
382                           ret);
383
384         /*
385          * Remove the STA AUTH flag to force further traffic through the AP. If
386          * the STA was unreachable, it was already removed.
387          */
388         rcu_read_lock();
389         sta = sta_info_get(sdata, peer);
390         if (sta)
391                 clear_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
392         rcu_read_unlock();
393
394         ieee80211_wake_vif_queues(local, sdata,
395                                   IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
396
397         return 0;
398 }
399
400 int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
401                         const u8 *peer, u8 action_code, u8 dialog_token,
402                         u16 status_code, u32 peer_capability,
403                         bool initiator, const u8 *extra_ies,
404                         size_t extra_ies_len)
405 {
406         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
407         int ret;
408
409         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
410                 return -ENOTSUPP;
411
412         /* make sure we are in managed mode, and associated */
413         if (sdata->vif.type != NL80211_IFTYPE_STATION ||
414             !sdata->u.mgd.associated)
415                 return -EINVAL;
416
417         switch (action_code) {
418         case WLAN_TDLS_SETUP_REQUEST:
419         case WLAN_TDLS_SETUP_RESPONSE:
420                 ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code,
421                                                 dialog_token, status_code,
422                                                 peer_capability, initiator,
423                                                 extra_ies, extra_ies_len);
424                 break;
425         case WLAN_TDLS_TEARDOWN:
426                 ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer,
427                                                    action_code, dialog_token,
428                                                    status_code,
429                                                    peer_capability, initiator,
430                                                    extra_ies, extra_ies_len);
431                 break;
432         case WLAN_TDLS_SETUP_CONFIRM:
433         case WLAN_TDLS_DISCOVERY_REQUEST:
434         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
435                 /* no special handling */
436                 ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
437                                                       action_code,
438                                                       dialog_token,
439                                                       status_code,
440                                                       peer_capability,
441                                                       initiator, extra_ies,
442                                                       extra_ies_len);
443                 break;
444         default:
445                 ret = -EOPNOTSUPP;
446                 break;
447         }
448
449         tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n",
450                  action_code, peer, ret);
451         return ret;
452 }
453
454 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
455                         const u8 *peer, enum nl80211_tdls_operation oper)
456 {
457         struct sta_info *sta;
458         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
459         struct ieee80211_local *local = sdata->local;
460         int ret;
461
462         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
463                 return -ENOTSUPP;
464
465         if (sdata->vif.type != NL80211_IFTYPE_STATION)
466                 return -EINVAL;
467
468         switch (oper) {
469         case NL80211_TDLS_ENABLE_LINK:
470         case NL80211_TDLS_DISABLE_LINK:
471                 break;
472         case NL80211_TDLS_TEARDOWN:
473         case NL80211_TDLS_SETUP:
474         case NL80211_TDLS_DISCOVERY_REQ:
475                 /* We don't support in-driver setup/teardown/discovery */
476                 return -ENOTSUPP;
477         }
478
479         mutex_lock(&local->mtx);
480         tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
481
482         switch (oper) {
483         case NL80211_TDLS_ENABLE_LINK:
484                 rcu_read_lock();
485                 sta = sta_info_get(sdata, peer);
486                 if (!sta) {
487                         rcu_read_unlock();
488                         ret = -ENOLINK;
489                         break;
490                 }
491
492                 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
493                 rcu_read_unlock();
494
495                 WARN_ON_ONCE(is_zero_ether_addr(sdata->tdls_peer) ||
496                              !ether_addr_equal(sdata->tdls_peer, peer));
497                 ret = 0;
498                 break;
499         case NL80211_TDLS_DISABLE_LINK:
500                 /* flush a potentially queued teardown packet */
501                 ieee80211_flush_queues(local, sdata);
502
503                 ret = sta_info_destroy_addr(sdata, peer);
504                 break;
505         default:
506                 ret = -ENOTSUPP;
507                 break;
508         }
509
510         if (ret == 0 && ether_addr_equal(sdata->tdls_peer, peer)) {
511                 cancel_delayed_work(&sdata->tdls_peer_del_work);
512                 eth_zero_addr(sdata->tdls_peer);
513         }
514
515         mutex_unlock(&local->mtx);
516         return ret;
517 }
518
519 void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer,
520                                  enum nl80211_tdls_operation oper,
521                                  u16 reason_code, gfp_t gfp)
522 {
523         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
524
525         if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) {
526                 sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n",
527                           oper);
528                 return;
529         }
530
531         cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp);
532 }
533 EXPORT_SYMBOL(ieee80211_tdls_oper_request);