xref: /openbmc/linux/net/mac80211/tdls.c (revision d2168146)
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 }
326