ARM: nomadik: fix up double inversion in DT
[cascardo/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 "ieee80211_i.h"
12
13 static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
14 {
15         u8 *pos = (void *)skb_put(skb, 7);
16
17         *pos++ = WLAN_EID_EXT_CAPABILITY;
18         *pos++ = 5; /* len */
19         *pos++ = 0x0;
20         *pos++ = 0x0;
21         *pos++ = 0x0;
22         *pos++ = 0x0;
23         *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
24 }
25
26 static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
27 {
28         struct ieee80211_local *local = sdata->local;
29         u16 capab;
30
31         capab = 0;
32         if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
33                 return capab;
34
35         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
36                 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
37         if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
38                 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
39
40         return capab;
41 }
42
43 static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
44                                        const u8 *peer, const u8 *bssid)
45 {
46         struct ieee80211_tdls_lnkie *lnkid;
47
48         lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
49
50         lnkid->ie_type = WLAN_EID_LINK_ID;
51         lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
52
53         memcpy(lnkid->bssid, bssid, ETH_ALEN);
54         memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
55         memcpy(lnkid->resp_sta, peer, ETH_ALEN);
56 }
57
58 static int
59 ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
60                                const u8 *peer, u8 action_code, u8 dialog_token,
61                                u16 status_code, struct sk_buff *skb)
62 {
63         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
64         enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
65         struct ieee80211_tdls_data *tf;
66
67         tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
68
69         memcpy(tf->da, peer, ETH_ALEN);
70         memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
71         tf->ether_type = cpu_to_be16(ETH_P_TDLS);
72         tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
73
74         switch (action_code) {
75         case WLAN_TDLS_SETUP_REQUEST:
76                 tf->category = WLAN_CATEGORY_TDLS;
77                 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
78
79                 skb_put(skb, sizeof(tf->u.setup_req));
80                 tf->u.setup_req.dialog_token = dialog_token;
81                 tf->u.setup_req.capability =
82                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
83
84                 ieee80211_add_srates_ie(sdata, skb, false, band);
85                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
86                 ieee80211_tdls_add_ext_capab(skb);
87                 break;
88         case WLAN_TDLS_SETUP_RESPONSE:
89                 tf->category = WLAN_CATEGORY_TDLS;
90                 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
91
92                 skb_put(skb, sizeof(tf->u.setup_resp));
93                 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
94                 tf->u.setup_resp.dialog_token = dialog_token;
95                 tf->u.setup_resp.capability =
96                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
97
98                 ieee80211_add_srates_ie(sdata, skb, false, band);
99                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
100                 ieee80211_tdls_add_ext_capab(skb);
101                 break;
102         case WLAN_TDLS_SETUP_CONFIRM:
103                 tf->category = WLAN_CATEGORY_TDLS;
104                 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
105
106                 skb_put(skb, sizeof(tf->u.setup_cfm));
107                 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
108                 tf->u.setup_cfm.dialog_token = dialog_token;
109                 break;
110         case WLAN_TDLS_TEARDOWN:
111                 tf->category = WLAN_CATEGORY_TDLS;
112                 tf->action_code = WLAN_TDLS_TEARDOWN;
113
114                 skb_put(skb, sizeof(tf->u.teardown));
115                 tf->u.teardown.reason_code = cpu_to_le16(status_code);
116                 break;
117         case WLAN_TDLS_DISCOVERY_REQUEST:
118                 tf->category = WLAN_CATEGORY_TDLS;
119                 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
120
121                 skb_put(skb, sizeof(tf->u.discover_req));
122                 tf->u.discover_req.dialog_token = dialog_token;
123                 break;
124         default:
125                 return -EINVAL;
126         }
127
128         return 0;
129 }
130
131 static int
132 ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
133                            const u8 *peer, u8 action_code, u8 dialog_token,
134                            u16 status_code, struct sk_buff *skb)
135 {
136         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
137         enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
138         struct ieee80211_mgmt *mgmt;
139
140         mgmt = (void *)skb_put(skb, 24);
141         memset(mgmt, 0, 24);
142         memcpy(mgmt->da, peer, ETH_ALEN);
143         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
144         memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
145
146         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
147                                           IEEE80211_STYPE_ACTION);
148
149         switch (action_code) {
150         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
151                 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
152                 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
153                 mgmt->u.action.u.tdls_discover_resp.action_code =
154                         WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
155                 mgmt->u.action.u.tdls_discover_resp.dialog_token =
156                         dialog_token;
157                 mgmt->u.action.u.tdls_discover_resp.capability =
158                         cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
159
160                 ieee80211_add_srates_ie(sdata, skb, false, band);
161                 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
162                 ieee80211_tdls_add_ext_capab(skb);
163                 break;
164         default:
165                 return -EINVAL;
166         }
167
168         return 0;
169 }
170
171 int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
172                         const u8 *peer, u8 action_code, u8 dialog_token,
173                         u16 status_code, u32 peer_capability,
174                         const u8 *extra_ies, size_t extra_ies_len)
175 {
176         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
177         struct ieee80211_local *local = sdata->local;
178         struct sk_buff *skb = NULL;
179         bool send_direct;
180         int ret;
181
182         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
183                 return -ENOTSUPP;
184
185         /* make sure we are in managed mode, and associated */
186         if (sdata->vif.type != NL80211_IFTYPE_STATION ||
187             !sdata->u.mgd.associated)
188                 return -EINVAL;
189
190         tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
191                  action_code, peer);
192
193         skb = dev_alloc_skb(local->hw.extra_tx_headroom +
194                             max(sizeof(struct ieee80211_mgmt),
195                                 sizeof(struct ieee80211_tdls_data)) +
196                             50 + /* supported rates */
197                             7 + /* ext capab */
198                             extra_ies_len +
199                             sizeof(struct ieee80211_tdls_lnkie));
200         if (!skb)
201                 return -ENOMEM;
202
203         skb_reserve(skb, local->hw.extra_tx_headroom);
204
205         switch (action_code) {
206         case WLAN_TDLS_SETUP_REQUEST:
207         case WLAN_TDLS_SETUP_RESPONSE:
208         case WLAN_TDLS_SETUP_CONFIRM:
209         case WLAN_TDLS_TEARDOWN:
210         case WLAN_TDLS_DISCOVERY_REQUEST:
211                 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
212                                                      action_code, dialog_token,
213                                                      status_code, skb);
214                 send_direct = false;
215                 break;
216         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
217                 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
218                                                  dialog_token, status_code,
219                                                  skb);
220                 send_direct = true;
221                 break;
222         default:
223                 ret = -ENOTSUPP;
224                 break;
225         }
226
227         if (ret < 0)
228                 goto fail;
229
230         if (extra_ies_len)
231                 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
232
233         /* the TDLS link IE is always added last */
234         switch (action_code) {
235         case WLAN_TDLS_SETUP_REQUEST:
236         case WLAN_TDLS_SETUP_CONFIRM:
237         case WLAN_TDLS_TEARDOWN:
238         case WLAN_TDLS_DISCOVERY_REQUEST:
239                 /* we are the initiator */
240                 ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
241                                            sdata->u.mgd.bssid);
242                 break;
243         case WLAN_TDLS_SETUP_RESPONSE:
244         case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
245                 /* we are the responder */
246                 ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
247                                            sdata->u.mgd.bssid);
248                 break;
249         default:
250                 ret = -ENOTSUPP;
251                 goto fail;
252         }
253
254         if (send_direct) {
255                 ieee80211_tx_skb(sdata, skb);
256                 return 0;
257         }
258
259         /*
260          * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
261          * we should default to AC_VI.
262          */
263         switch (action_code) {
264         case WLAN_TDLS_SETUP_REQUEST:
265         case WLAN_TDLS_SETUP_RESPONSE:
266                 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
267                 skb->priority = 2;
268                 break;
269         default:
270                 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
271                 skb->priority = 5;
272                 break;
273         }
274
275         /* disable bottom halves when entering the Tx path */
276         local_bh_disable();
277         ret = ieee80211_subif_start_xmit(skb, dev);
278         local_bh_enable();
279
280         return ret;
281
282 fail:
283         dev_kfree_skb(skb);
284         return ret;
285 }
286
287 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
288                         const u8 *peer, enum nl80211_tdls_operation oper)
289 {
290         struct sta_info *sta;
291         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
292
293         if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
294                 return -ENOTSUPP;
295
296         if (sdata->vif.type != NL80211_IFTYPE_STATION)
297                 return -EINVAL;
298
299         tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
300
301         switch (oper) {
302         case NL80211_TDLS_ENABLE_LINK:
303                 rcu_read_lock();
304                 sta = sta_info_get(sdata, peer);
305                 if (!sta) {
306                         rcu_read_unlock();
307                         return -ENOLINK;
308                 }
309
310                 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
311                 rcu_read_unlock();
312                 break;
313         case NL80211_TDLS_DISABLE_LINK:
314                 return sta_info_destroy_addr(sdata, peer);
315         case NL80211_TDLS_TEARDOWN:
316         case NL80211_TDLS_SETUP:
317         case NL80211_TDLS_DISCOVERY_REQ:
318                 /* We don't support in-driver setup/teardown/discovery */
319                 return -ENOTSUPP;
320         default:
321                 return -ENOTSUPP;
322         }
323
324         return 0;
325 }