Blame view
net/wireless/mlme.c
24.3 KB
6039f6d23 nl80211: Event no... |
1 2 3 4 5 6 7 8 |
/* * cfg80211 MLME SAP interface * * Copyright (c) 2009, Jouni Malinen <j@w1.fi> */ #include <linux/kernel.h> #include <linux/module.h> |
c6fb08aaa cfg80211: use com... |
9 |
#include <linux/etherdevice.h> |
6039f6d23 nl80211: Event no... |
10 11 |
#include <linux/netdevice.h> #include <linux/nl80211.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
a9a11622c cfg80211: self-co... |
13 |
#include <linux/wireless.h> |
6039f6d23 nl80211: Event no... |
14 |
#include <net/cfg80211.h> |
a9a11622c cfg80211: self-co... |
15 |
#include <net/iw_handler.h> |
6039f6d23 nl80211: Event no... |
16 17 |
#include "core.h" #include "nl80211.h" |
e35e4d28b cfg80211: add wra... |
18 |
#include "rdev-ops.h" |
6039f6d23 nl80211: Event no... |
19 |
|
cb0b4beb9 cfg80211: mlme AP... |
20 |
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) |
6039f6d23 nl80211: Event no... |
21 |
{ |
19957bb39 cfg80211: keep tr... |
22 23 |
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; |
6039f6d23 nl80211: Event no... |
24 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
19957bb39 cfg80211: keep tr... |
25 |
|
4ee3e063f cfg80211: add cfg... |
26 |
trace_cfg80211_send_rx_auth(dev); |
667503ddc cfg80211: fix loc... |
27 |
wdev_lock(wdev); |
cb0b4beb9 cfg80211: mlme AP... |
28 |
|
95de817b9 cfg80211: stop tr... |
29 30 |
nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); cfg80211_sme_rx_auth(dev, buf, len); |
667503ddc cfg80211: fix loc... |
31 32 |
wdev_unlock(wdev); |
6039f6d23 nl80211: Event no... |
33 34 |
} EXPORT_SYMBOL(cfg80211_send_rx_auth); |
95de817b9 cfg80211: stop tr... |
35 36 |
void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, const u8 *buf, size_t len) |
6039f6d23 nl80211: Event no... |
37 |
{ |
6829c878e cfg80211: emulate... |
38 39 40 |
u16 status_code; struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; |
6039f6d23 nl80211: Event no... |
41 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878e cfg80211: emulate... |
42 43 |
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; u8 *ie = mgmt->u.assoc_resp.variable; |
95de817b9 cfg80211: stop tr... |
44 |
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
6829c878e cfg80211: emulate... |
45 |
|
4ee3e063f cfg80211: add cfg... |
46 |
trace_cfg80211_send_rx_assoc(dev, bss); |
667503ddc cfg80211: fix loc... |
47 |
wdev_lock(wdev); |
cb0b4beb9 cfg80211: mlme AP... |
48 |
|
6829c878e cfg80211: emulate... |
49 |
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
f401a6f7e cfg80211: use rea... |
50 51 52 53 54 55 56 |
/* * This is a bit of a hack, we don't notify userspace of * a (re-)association reply if we tried to send a reassoc * and got a reject -- we only try again with an assoc * frame instead of reassoc. */ if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && |
95de817b9 cfg80211: stop tr... |
57 |
cfg80211_sme_failed_reassoc(wdev)) { |
5b112d3d0 cfg80211: pass wi... |
58 |
cfg80211_put_bss(wiphy, bss); |
f401a6f7e cfg80211: use rea... |
59 |
goto out; |
95de817b9 cfg80211: stop tr... |
60 |
} |
f401a6f7e cfg80211: use rea... |
61 |
|
cb0b4beb9 cfg80211: mlme AP... |
62 |
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
6829c878e cfg80211: emulate... |
63 |
|
95de817b9 cfg80211: stop tr... |
64 |
if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) { |
7d930bc33 cfg80211: sme: de... |
65 |
cfg80211_sme_failed_assoc(wdev); |
7d930bc33 cfg80211: sme: de... |
66 67 68 69 |
/* * do not call connect_result() now because the * sme will schedule work that does it later. */ |
5b112d3d0 cfg80211: pass wi... |
70 |
cfg80211_put_bss(wiphy, bss); |
7d930bc33 cfg80211: sme: de... |
71 |
goto out; |
df7fc0f97 cfg80211: keep tr... |
72 |
} |
ea416a793 cfg80211: report ... |
73 74 75 76 77 78 79 80 |
if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { /* * This is for the userspace SME, the CONNECTING * state will be changed to CONNECTED by * __cfg80211_connect_result() below. */ wdev->sme_state = CFG80211_SME_CONNECTING; } |
95de817b9 cfg80211: stop tr... |
81 |
/* this consumes the bss reference */ |
df7fc0f97 cfg80211: keep tr... |
82 83 |
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, status_code, |
95de817b9 cfg80211: stop tr... |
84 |
status_code == WLAN_STATUS_SUCCESS, bss); |
f401a6f7e cfg80211: use rea... |
85 |
out: |
667503ddc cfg80211: fix loc... |
86 |
wdev_unlock(wdev); |
6039f6d23 nl80211: Event no... |
87 88 |
} EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
ce470613c cfg80211: no cook... |
89 |
void __cfg80211_send_deauth(struct net_device *dev, |
667503ddc cfg80211: fix loc... |
90 |
const u8 *buf, size_t len) |
6039f6d23 nl80211: Event no... |
91 |
{ |
6829c878e cfg80211: emulate... |
92 93 |
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; |
6039f6d23 nl80211: Event no... |
94 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878e cfg80211: emulate... |
95 |
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
19957bb39 cfg80211: keep tr... |
96 |
const u8 *bssid = mgmt->bssid; |
95de817b9 cfg80211: stop tr... |
97 |
bool was_current = false; |
6829c878e cfg80211: emulate... |
98 |
|
4ee3e063f cfg80211: add cfg... |
99 |
trace___cfg80211_send_deauth(dev); |
667503ddc cfg80211: fix loc... |
100 |
ASSERT_WDEV_LOCK(wdev); |
cb0b4beb9 cfg80211: mlme AP... |
101 |
|
19957bb39 cfg80211: keep tr... |
102 |
if (wdev->current_bss && |
ac422d3cc wireless: Convert... |
103 |
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { |
19957bb39 cfg80211: keep tr... |
104 |
cfg80211_unhold_bss(wdev->current_bss); |
5b112d3d0 cfg80211: pass wi... |
105 |
cfg80211_put_bss(wiphy, &wdev->current_bss->pub); |
19957bb39 cfg80211: keep tr... |
106 |
wdev->current_bss = NULL; |
3f3b6a8d9 cfg80211: deauth ... |
107 |
was_current = true; |
19957bb39 cfg80211: keep tr... |
108 |
} |
19957bb39 cfg80211: keep tr... |
109 |
|
5fba4af32 cfg80211: avoid s... |
110 |
nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); |
3f3b6a8d9 cfg80211: deauth ... |
111 |
if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) { |
6829c878e cfg80211: emulate... |
112 113 114 115 |
u16 reason_code; bool from_ap; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
ac422d3cc wireless: Convert... |
116 |
from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); |
667503ddc cfg80211: fix loc... |
117 |
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
6829c878e cfg80211: emulate... |
118 |
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
667503ddc cfg80211: fix loc... |
119 120 |
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, |
df7fc0f97 cfg80211: keep tr... |
121 |
false, NULL); |
667503ddc cfg80211: fix loc... |
122 123 |
} } |
ce470613c cfg80211: no cook... |
124 |
EXPORT_SYMBOL(__cfg80211_send_deauth); |
667503ddc cfg80211: fix loc... |
125 |
|
ce470613c cfg80211: no cook... |
126 |
void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) |
667503ddc cfg80211: fix loc... |
127 128 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; |
ce470613c cfg80211: no cook... |
129 130 131 |
wdev_lock(wdev); __cfg80211_send_deauth(dev, buf, len); wdev_unlock(wdev); |
6039f6d23 nl80211: Event no... |
132 |
} |
53b46b844 nl80211: Generate... |
133 |
EXPORT_SYMBOL(cfg80211_send_deauth); |
6039f6d23 nl80211: Event no... |
134 |
|
ce470613c cfg80211: no cook... |
135 |
void __cfg80211_send_disassoc(struct net_device *dev, |
667503ddc cfg80211: fix loc... |
136 |
const u8 *buf, size_t len) |
6039f6d23 nl80211: Event no... |
137 |
{ |
6829c878e cfg80211: emulate... |
138 139 |
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; |
6039f6d23 nl80211: Event no... |
140 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878e cfg80211: emulate... |
141 |
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
19957bb39 cfg80211: keep tr... |
142 |
const u8 *bssid = mgmt->bssid; |
19957bb39 cfg80211: keep tr... |
143 144 |
u16 reason_code; bool from_ap; |
6829c878e cfg80211: emulate... |
145 |
|
4ee3e063f cfg80211: add cfg... |
146 |
trace___cfg80211_send_disassoc(dev); |
596a07c18 cfg80211: fix mor... |
147 |
ASSERT_WDEV_LOCK(wdev); |
cb0b4beb9 cfg80211: mlme AP... |
148 149 |
nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); |
a3b8b0569 nl80211: Add Mich... |
150 |
|
596a07c18 cfg80211: fix mor... |
151 152 |
if (wdev->sme_state != CFG80211_SME_CONNECTED) return; |
6829c878e cfg80211: emulate... |
153 |
|
19957bb39 cfg80211: keep tr... |
154 |
if (wdev->current_bss && |
ac422d3cc wireless: Convert... |
155 |
ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) { |
95de817b9 cfg80211: stop tr... |
156 157 |
cfg80211_sme_disassoc(dev, wdev->current_bss); cfg80211_unhold_bss(wdev->current_bss); |
5b112d3d0 cfg80211: pass wi... |
158 |
cfg80211_put_bss(wiphy, &wdev->current_bss->pub); |
95de817b9 cfg80211: stop tr... |
159 |
wdev->current_bss = NULL; |
19957bb39 cfg80211: keep tr... |
160 161 |
} else WARN_ON(1); |
6829c878e cfg80211: emulate... |
162 |
|
6829c878e cfg80211: emulate... |
163 |
|
19957bb39 cfg80211: keep tr... |
164 |
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
ac422d3cc wireless: Convert... |
165 |
from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); |
667503ddc cfg80211: fix loc... |
166 |
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
667503ddc cfg80211: fix loc... |
167 |
} |
ce470613c cfg80211: no cook... |
168 |
EXPORT_SYMBOL(__cfg80211_send_disassoc); |
667503ddc cfg80211: fix loc... |
169 |
|
ce470613c cfg80211: no cook... |
170 |
void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) |
667503ddc cfg80211: fix loc... |
171 172 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; |
ce470613c cfg80211: no cook... |
173 174 175 |
wdev_lock(wdev); __cfg80211_send_disassoc(dev, buf, len); wdev_unlock(wdev); |
1965c8533 nl80211: Add even... |
176 |
} |
6829c878e cfg80211: emulate... |
177 |
EXPORT_SYMBOL(cfg80211_send_disassoc); |
1965c8533 nl80211: Add even... |
178 |
|
a58ce43f2 mac80211: avoid s... |
179 180 181 182 183 |
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
4ee3e063f cfg80211: add cfg... |
184 |
trace_cfg80211_send_auth_timeout(dev, addr); |
a58ce43f2 mac80211: avoid s... |
185 186 187 188 189 190 191 |
wdev_lock(wdev); nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); if (wdev->sme_state == CFG80211_SME_CONNECTING) __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, false, NULL); |
667503ddc cfg80211: fix loc... |
192 |
wdev_unlock(wdev); |
1965c8533 nl80211: Add even... |
193 194 |
} EXPORT_SYMBOL(cfg80211_send_auth_timeout); |
cb0b4beb9 cfg80211: mlme AP... |
195 |
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) |
1965c8533 nl80211: Add even... |
196 |
{ |
6829c878e cfg80211: emulate... |
197 198 |
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; |
1965c8533 nl80211: Add even... |
199 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
19957bb39 cfg80211: keep tr... |
200 |
|
4ee3e063f cfg80211: add cfg... |
201 |
trace_cfg80211_send_assoc_timeout(dev, addr); |
667503ddc cfg80211: fix loc... |
202 |
wdev_lock(wdev); |
cb0b4beb9 cfg80211: mlme AP... |
203 204 |
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); |
6829c878e cfg80211: emulate... |
205 |
if (wdev->sme_state == CFG80211_SME_CONNECTING) |
667503ddc cfg80211: fix loc... |
206 207 |
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, |
df7fc0f97 cfg80211: keep tr... |
208 |
false, NULL); |
19957bb39 cfg80211: keep tr... |
209 |
|
667503ddc cfg80211: fix loc... |
210 |
wdev_unlock(wdev); |
1965c8533 nl80211: Add even... |
211 212 |
} EXPORT_SYMBOL(cfg80211_send_assoc_timeout); |
a3b8b0569 nl80211: Add Mich... |
213 214 |
void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, enum nl80211_key_type key_type, int key_id, |
e6d6e3420 cfg80211: use pro... |
215 |
const u8 *tsc, gfp_t gfp) |
a3b8b0569 nl80211: Add Mich... |
216 217 218 |
{ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
3d23e349d wext: refactor |
219 |
#ifdef CONFIG_CFG80211_WEXT |
f58d4ed98 cfg80211: send we... |
220 |
union iwreq_data wrqu; |
e6d6e3420 cfg80211: use pro... |
221 |
char *buf = kmalloc(128, gfp); |
f58d4ed98 cfg80211: send we... |
222 223 224 225 226 227 228 229 230 231 232 233 |
if (buf) { sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" "keyid=%d %scast addr=%pM)", key_id, key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", addr); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); kfree(buf); } #endif |
4ee3e063f cfg80211: add cfg... |
234 |
trace_cfg80211_michael_mic_failure(dev, addr, key_type, key_id, tsc); |
e6d6e3420 cfg80211: use pro... |
235 |
nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); |
a3b8b0569 nl80211: Add Mich... |
236 237 |
} EXPORT_SYMBOL(cfg80211_michael_mic_failure); |
19957bb39 cfg80211: keep tr... |
238 239 |
/* some MLME handling for userspace SME */ |
667503ddc cfg80211: fix loc... |
240 241 242 243 244 245 |
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, |
fffd0934b cfg80211: rework ... |
246 |
const u8 *ie, int ie_len, |
e39e5b5e7 cfg80211: Allow u... |
247 248 |
const u8 *key, int key_len, int key_idx, const u8 *sae_data, int sae_data_len) |
19957bb39 cfg80211: keep tr... |
249 250 251 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_auth_request req; |
95de817b9 cfg80211: stop tr... |
252 |
int err; |
19957bb39 cfg80211: keep tr... |
253 |
|
667503ddc cfg80211: fix loc... |
254 |
ASSERT_WDEV_LOCK(wdev); |
fffd0934b cfg80211: rework ... |
255 256 257 |
if (auth_type == NL80211_AUTHTYPE_SHARED_KEY) if (!key || !key_len || key_idx < 0 || key_idx > 4) return -EINVAL; |
0a9b5e179 cfg80211: refuse ... |
258 |
if (wdev->current_bss && |
ac422d3cc wireless: Convert... |
259 |
ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) |
0a9b5e179 cfg80211: refuse ... |
260 |
return -EALREADY; |
19957bb39 cfg80211: keep tr... |
261 262 263 264 |
memset(&req, 0, sizeof(req)); req.ie = ie; req.ie_len = ie_len; |
e39e5b5e7 cfg80211: Allow u... |
265 266 |
req.sae_data = sae_data; req.sae_data_len = sae_data_len; |
19957bb39 cfg80211: keep tr... |
267 268 269 |
req.auth_type = auth_type; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
fffd0934b cfg80211: rework ... |
270 271 272 |
req.key = key; req.key_len = key_len; req.key_idx = key_idx; |
19957bb39 cfg80211: keep tr... |
273 274 |
if (!req.bss) return -ENOENT; |
e4e32459c cfg80211: respect... |
275 276 277 278 |
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, CHAN_MODE_SHARED); if (err) goto out; |
e35e4d28b cfg80211: add wra... |
279 |
err = rdev_auth(rdev, dev, &req); |
19957bb39 cfg80211: keep tr... |
280 |
|
e4e32459c cfg80211: respect... |
281 |
out: |
5b112d3d0 cfg80211: pass wi... |
282 |
cfg80211_put_bss(&rdev->wiphy, req.bss); |
19957bb39 cfg80211: keep tr... |
283 284 |
return err; } |
667503ddc cfg80211: fix loc... |
285 286 287 288 |
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_auth_type auth_type, const u8 *bssid, const u8 *ssid, int ssid_len, |
fffd0934b cfg80211: rework ... |
289 |
const u8 *ie, int ie_len, |
e39e5b5e7 cfg80211: Allow u... |
290 291 |
const u8 *key, int key_len, int key_idx, const u8 *sae_data, int sae_data_len) |
667503ddc cfg80211: fix loc... |
292 293 |
{ int err; |
e4e32459c cfg80211: respect... |
294 |
mutex_lock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
295 296 |
wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
fffd0934b cfg80211: rework ... |
297 |
ssid, ssid_len, ie, ie_len, |
e39e5b5e7 cfg80211: Allow u... |
298 299 |
key, key_len, key_idx, sae_data, sae_data_len); |
667503ddc cfg80211: fix loc... |
300 |
wdev_unlock(dev->ieee80211_ptr); |
e4e32459c cfg80211: respect... |
301 |
mutex_unlock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
302 303 304 |
return err; } |
7e7c8926b wireless: Support... |
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
/* Do a logical ht_capa &= ht_capa_mask. */ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, const struct ieee80211_ht_cap *ht_capa_mask) { int i; u8 *p1, *p2; if (!ht_capa_mask) { memset(ht_capa, 0, sizeof(*ht_capa)); return; } p1 = (u8*)(ht_capa); p2 = (u8*)(ht_capa_mask); for (i = 0; i<sizeof(*ht_capa); i++) p1[i] &= p2[i]; } |
ee2aca343 cfg80211: add abi... |
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
/* Do a logical ht_capa &= ht_capa_mask. */ void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, const struct ieee80211_vht_cap *vht_capa_mask) { int i; u8 *p1, *p2; if (!vht_capa_mask) { memset(vht_capa, 0, sizeof(*vht_capa)); return; } p1 = (u8*)(vht_capa); p2 = (u8*)(vht_capa_mask); for (i = 0; i < sizeof(*vht_capa); i++) p1[i] &= p2[i]; } |
667503ddc cfg80211: fix loc... |
337 338 339 |
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, |
f62fab735 cfg80211: refacto... |
340 |
const u8 *bssid, |
667503ddc cfg80211: fix loc... |
341 |
const u8 *ssid, int ssid_len, |
f62fab735 cfg80211: refacto... |
342 |
struct cfg80211_assoc_request *req) |
19957bb39 cfg80211: keep tr... |
343 344 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; |
95de817b9 cfg80211: stop tr... |
345 |
int err; |
24b6b15f7 cfg80211: Allow r... |
346 |
bool was_connected = false; |
19957bb39 cfg80211: keep tr... |
347 |
|
667503ddc cfg80211: fix loc... |
348 |
ASSERT_WDEV_LOCK(wdev); |
f62fab735 cfg80211: refacto... |
349 350 |
if (wdev->current_bss && req->prev_bssid && ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { |
24b6b15f7 cfg80211: Allow r... |
351 352 353 354 355 356 357 358 359 |
/* * Trying to reassociate: Allow this to proceed and let the old * association to be dropped when the new one is completed. */ if (wdev->sme_state == CFG80211_SME_CONNECTED) { was_connected = true; wdev->sme_state = CFG80211_SME_CONNECTING; } } else if (wdev->current_bss) |
19957bb39 cfg80211: keep tr... |
360 |
return -EALREADY; |
f62fab735 cfg80211: refacto... |
361 |
cfg80211_oper_and_ht_capa(&req->ht_capa_mask, |
7e7c8926b wireless: Support... |
362 |
rdev->wiphy.ht_capa_mod_mask); |
f62fab735 cfg80211: refacto... |
363 |
cfg80211_oper_and_vht_capa(&req->vht_capa_mask, |
ee2aca343 cfg80211: add abi... |
364 |
rdev->wiphy.vht_capa_mod_mask); |
7e7c8926b wireless: Support... |
365 |
|
f62fab735 cfg80211: refacto... |
366 367 368 |
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!req->bss) { |
24b6b15f7 cfg80211: Allow r... |
369 370 |
if (was_connected) wdev->sme_state = CFG80211_SME_CONNECTED; |
19957bb39 cfg80211: keep tr... |
371 |
return -ENOENT; |
24b6b15f7 cfg80211: Allow r... |
372 |
} |
19957bb39 cfg80211: keep tr... |
373 |
|
f62fab735 cfg80211: refacto... |
374 |
err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); |
e4e32459c cfg80211: respect... |
375 376 |
if (err) goto out; |
f62fab735 cfg80211: refacto... |
377 |
err = rdev_assoc(rdev, dev, req); |
19957bb39 cfg80211: keep tr... |
378 |
|
e4e32459c cfg80211: respect... |
379 |
out: |
95de817b9 cfg80211: stop tr... |
380 381 382 |
if (err) { if (was_connected) wdev->sme_state = CFG80211_SME_CONNECTED; |
f62fab735 cfg80211: refacto... |
383 |
cfg80211_put_bss(&rdev->wiphy, req->bss); |
19957bb39 cfg80211: keep tr... |
384 |
} |
19957bb39 cfg80211: keep tr... |
385 386 |
return err; } |
667503ddc cfg80211: fix loc... |
387 388 389 |
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_channel *chan, |
f62fab735 cfg80211: refacto... |
390 |
const u8 *bssid, |
667503ddc cfg80211: fix loc... |
391 |
const u8 *ssid, int ssid_len, |
f62fab735 cfg80211: refacto... |
392 |
struct cfg80211_assoc_request *req) |
667503ddc cfg80211: fix loc... |
393 394 395 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; int err; |
e4e32459c cfg80211: respect... |
396 |
mutex_lock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
397 |
wdev_lock(wdev); |
f62fab735 cfg80211: refacto... |
398 399 |
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, ssid_len, req); |
667503ddc cfg80211: fix loc... |
400 |
wdev_unlock(wdev); |
e4e32459c cfg80211: respect... |
401 |
mutex_unlock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
402 403 404 405 406 407 |
return err; } int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, |
d5cdfacb3 cfg80211: Add loc... |
408 409 |
const u8 *ie, int ie_len, u16 reason, bool local_state_change) |
19957bb39 cfg80211: keep tr... |
410 411 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; |
95de817b9 cfg80211: stop tr... |
412 413 414 415 416 |
struct cfg80211_deauth_request req = { .bssid = bssid, .reason_code = reason, .ie = ie, .ie_len = ie_len, |
6863255bd cfg80211/mac80211... |
417 |
.local_state_change = local_state_change, |
95de817b9 cfg80211: stop tr... |
418 |
}; |
19957bb39 cfg80211: keep tr... |
419 |
|
667503ddc cfg80211: fix loc... |
420 |
ASSERT_WDEV_LOCK(wdev); |
6863255bd cfg80211/mac80211... |
421 422 |
if (local_state_change && (!wdev->current_bss || !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) |
95de817b9 cfg80211: stop tr... |
423 |
return 0; |
19957bb39 cfg80211: keep tr... |
424 |
|
e35e4d28b cfg80211: add wra... |
425 |
return rdev_deauth(rdev, dev, &req); |
19957bb39 cfg80211: keep tr... |
426 |
} |
667503ddc cfg80211: fix loc... |
427 428 |
int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, |
d5cdfacb3 cfg80211: Add loc... |
429 430 |
const u8 *ie, int ie_len, u16 reason, bool local_state_change) |
667503ddc cfg80211: fix loc... |
431 432 433 434 435 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); |
d5cdfacb3 cfg80211: Add loc... |
436 437 |
err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason, local_state_change); |
667503ddc cfg80211: fix loc... |
438 439 440 441 442 443 444 |
wdev_unlock(wdev); return err; } static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, |
d5cdfacb3 cfg80211: Add loc... |
445 446 |
const u8 *ie, int ie_len, u16 reason, bool local_state_change) |
19957bb39 cfg80211: keep tr... |
447 448 449 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_disassoc_request req; |
667503ddc cfg80211: fix loc... |
450 |
ASSERT_WDEV_LOCK(wdev); |
f9d6b4026 cfg80211: fix dis... |
451 452 |
if (wdev->sme_state != CFG80211_SME_CONNECTED) return -ENOTCONN; |
8dcf011ab cfg80211: add SME... |
453 454 |
if (WARN(!wdev->current_bss, "sme_state=%d ", wdev->sme_state)) |
f9d6b4026 cfg80211: fix dis... |
455 |
return -ENOTCONN; |
19957bb39 cfg80211: keep tr... |
456 457 |
memset(&req, 0, sizeof(req)); req.reason_code = reason; |
d5cdfacb3 cfg80211: Add loc... |
458 |
req.local_state_change = local_state_change; |
19957bb39 cfg80211: keep tr... |
459 460 |
req.ie = ie; req.ie_len = ie_len; |
ac422d3cc wireless: Convert... |
461 |
if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
19957bb39 cfg80211: keep tr... |
462 463 464 |
req.bss = &wdev->current_bss->pub; else return -ENOTCONN; |
e35e4d28b cfg80211: add wra... |
465 |
return rdev_disassoc(rdev, dev, &req); |
667503ddc cfg80211: fix loc... |
466 467 468 469 |
} int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *bssid, |
d5cdfacb3 cfg80211: Add loc... |
470 471 |
const u8 *ie, int ie_len, u16 reason, bool local_state_change) |
667503ddc cfg80211: fix loc... |
472 473 474 475 476 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); |
d5cdfacb3 cfg80211: Add loc... |
477 478 |
err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason, local_state_change); |
667503ddc cfg80211: fix loc... |
479 480 481 |
wdev_unlock(wdev); return err; |
19957bb39 cfg80211: keep tr... |
482 483 484 485 486 487 488 |
} void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, struct net_device *dev) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_deauth_request req; |
95de817b9 cfg80211: stop tr... |
489 |
u8 bssid[ETH_ALEN]; |
19957bb39 cfg80211: keep tr... |
490 |
|
667503ddc cfg80211: fix loc... |
491 |
ASSERT_WDEV_LOCK(wdev); |
19957bb39 cfg80211: keep tr... |
492 493 494 495 496 497 498 |
if (!rdev->ops->deauth) return; memset(&req, 0, sizeof(req)); req.reason_code = WLAN_REASON_DEAUTH_LEAVING; req.ie = NULL; req.ie_len = 0; |
95de817b9 cfg80211: stop tr... |
499 500 |
if (!wdev->current_bss) return; |
19957bb39 cfg80211: keep tr... |
501 |
|
95de817b9 cfg80211: stop tr... |
502 503 |
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); req.bssid = bssid; |
e35e4d28b cfg80211: add wra... |
504 |
rdev_deauth(rdev, dev, &req); |
95de817b9 cfg80211: stop tr... |
505 506 507 |
if (wdev->current_bss) { cfg80211_unhold_bss(wdev->current_bss); |
5b112d3d0 cfg80211: pass wi... |
508 |
cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub); |
95de817b9 cfg80211: stop tr... |
509 |
wdev->current_bss = NULL; |
19957bb39 cfg80211: keep tr... |
510 511 |
} } |
9588bbd55 cfg80211: add rem... |
512 |
|
2e161f78e cfg80211/mac80211... |
513 |
struct cfg80211_mgmt_registration { |
026331c4d cfg80211/mac80211... |
514 |
struct list_head list; |
15e473046 netlink: Rename p... |
515 |
u32 nlportid; |
026331c4d cfg80211/mac80211... |
516 517 |
int match_len; |
2e161f78e cfg80211/mac80211... |
518 |
__le16 frame_type; |
026331c4d cfg80211/mac80211... |
519 520 |
u8 match[]; }; |
15e473046 netlink: Rename p... |
521 |
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, |
2e161f78e cfg80211/mac80211... |
522 523 |
u16 frame_type, const u8 *match_data, int match_len) |
026331c4d cfg80211/mac80211... |
524 |
{ |
271733cf8 cfg80211: notify ... |
525 526 |
struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
2e161f78e cfg80211/mac80211... |
527 |
struct cfg80211_mgmt_registration *reg, *nreg; |
026331c4d cfg80211/mac80211... |
528 |
int err = 0; |
2e161f78e cfg80211/mac80211... |
529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
u16 mgmt_type; if (!wdev->wiphy->mgmt_stypes) return -EOPNOTSUPP; if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) return -EINVAL; if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) return -EINVAL; mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) return -EINVAL; |
026331c4d cfg80211/mac80211... |
543 544 545 546 |
nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); if (!nreg) return -ENOMEM; |
2e161f78e cfg80211/mac80211... |
547 |
spin_lock_bh(&wdev->mgmt_registrations_lock); |
026331c4d cfg80211/mac80211... |
548 |
|
2e161f78e cfg80211/mac80211... |
549 |
list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
026331c4d cfg80211/mac80211... |
550 |
int mlen = min(match_len, reg->match_len); |
2e161f78e cfg80211/mac80211... |
551 552 |
if (frame_type != le16_to_cpu(reg->frame_type)) continue; |
026331c4d cfg80211/mac80211... |
553 554 555 556 557 558 559 560 561 562 563 564 565 |
if (memcmp(reg->match, match_data, mlen) == 0) { err = -EALREADY; break; } } if (err) { kfree(nreg); goto out; } memcpy(nreg->match, match_data, match_len); nreg->match_len = match_len; |
15e473046 netlink: Rename p... |
566 |
nreg->nlportid = snd_portid; |
2e161f78e cfg80211/mac80211... |
567 568 |
nreg->frame_type = cpu_to_le16(frame_type); list_add(&nreg->list, &wdev->mgmt_registrations); |
026331c4d cfg80211/mac80211... |
569 |
|
271733cf8 cfg80211: notify ... |
570 |
if (rdev->ops->mgmt_frame_register) |
e35e4d28b cfg80211: add wra... |
571 |
rdev_mgmt_frame_register(rdev, wdev, frame_type, true); |
271733cf8 cfg80211: notify ... |
572 |
|
026331c4d cfg80211/mac80211... |
573 |
out: |
2e161f78e cfg80211/mac80211... |
574 |
spin_unlock_bh(&wdev->mgmt_registrations_lock); |
271733cf8 cfg80211: notify ... |
575 |
|
026331c4d cfg80211/mac80211... |
576 577 |
return err; } |
15e473046 netlink: Rename p... |
578 |
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) |
026331c4d cfg80211/mac80211... |
579 |
{ |
271733cf8 cfg80211: notify ... |
580 581 |
struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
2e161f78e cfg80211/mac80211... |
582 |
struct cfg80211_mgmt_registration *reg, *tmp; |
026331c4d cfg80211/mac80211... |
583 |
|
2e161f78e cfg80211/mac80211... |
584 |
spin_lock_bh(&wdev->mgmt_registrations_lock); |
026331c4d cfg80211/mac80211... |
585 |
|
2e161f78e cfg80211/mac80211... |
586 |
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
15e473046 netlink: Rename p... |
587 |
if (reg->nlportid != nlportid) |
271733cf8 cfg80211: notify ... |
588 589 590 591 |
continue; if (rdev->ops->mgmt_frame_register) { u16 frame_type = le16_to_cpu(reg->frame_type); |
e35e4d28b cfg80211: add wra... |
592 593 |
rdev_mgmt_frame_register(rdev, wdev, frame_type, false); |
026331c4d cfg80211/mac80211... |
594 |
} |
271733cf8 cfg80211: notify ... |
595 596 597 |
list_del(®->list); kfree(reg); |
026331c4d cfg80211/mac80211... |
598 |
} |
2e161f78e cfg80211/mac80211... |
599 |
spin_unlock_bh(&wdev->mgmt_registrations_lock); |
28946da76 nl80211: allow su... |
600 |
|
5de179848 cfg80211: introdu... |
601 602 603 604 |
if (nlportid && rdev->crit_proto_nlportid == nlportid) { rdev->crit_proto_nlportid = 0; rdev_crit_proto_stop(rdev, wdev); } |
15e473046 netlink: Rename p... |
605 606 |
if (nlportid == wdev->ap_unexpected_nlportid) wdev->ap_unexpected_nlportid = 0; |
026331c4d cfg80211/mac80211... |
607 |
} |
2e161f78e cfg80211/mac80211... |
608 |
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
026331c4d cfg80211/mac80211... |
609 |
{ |
2e161f78e cfg80211/mac80211... |
610 |
struct cfg80211_mgmt_registration *reg, *tmp; |
026331c4d cfg80211/mac80211... |
611 |
|
2e161f78e cfg80211/mac80211... |
612 |
spin_lock_bh(&wdev->mgmt_registrations_lock); |
026331c4d cfg80211/mac80211... |
613 |
|
2e161f78e cfg80211/mac80211... |
614 |
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
026331c4d cfg80211/mac80211... |
615 616 617 |
list_del(®->list); kfree(reg); } |
2e161f78e cfg80211/mac80211... |
618 |
spin_unlock_bh(&wdev->mgmt_registrations_lock); |
026331c4d cfg80211/mac80211... |
619 |
} |
2e161f78e cfg80211/mac80211... |
620 |
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
71bbc9943 cfg80211: use wde... |
621 |
struct wireless_dev *wdev, |
f7ca38dfe nl80211/cfg80211:... |
622 |
struct ieee80211_channel *chan, bool offchan, |
42d97a599 cfg80211: remove ... |
623 624 |
unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) |
026331c4d cfg80211/mac80211... |
625 |
{ |
026331c4d cfg80211/mac80211... |
626 |
const struct ieee80211_mgmt *mgmt; |
2e161f78e cfg80211/mac80211... |
627 628 629 630 |
u16 stype; if (!wdev->wiphy->mgmt_stypes) return -EOPNOTSUPP; |
026331c4d cfg80211/mac80211... |
631 |
|
2e161f78e cfg80211/mac80211... |
632 |
if (!rdev->ops->mgmt_tx) |
026331c4d cfg80211/mac80211... |
633 |
return -EOPNOTSUPP; |
2e161f78e cfg80211/mac80211... |
634 |
|
026331c4d cfg80211/mac80211... |
635 636 637 638 |
if (len < 24 + 1) return -EINVAL; mgmt = (const struct ieee80211_mgmt *) buf; |
2e161f78e cfg80211/mac80211... |
639 640 |
if (!ieee80211_is_mgmt(mgmt->frame_control)) |
026331c4d cfg80211/mac80211... |
641 |
return -EINVAL; |
2e161f78e cfg80211/mac80211... |
642 643 644 645 646 647 648 |
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) return -EINVAL; if (ieee80211_is_action(mgmt->frame_control) && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { |
663fcafd9 cfg80211/mac80211... |
649 |
int err = 0; |
fe100acdd cfg80211: fix loc... |
650 |
wdev_lock(wdev); |
663fcafd9 cfg80211/mac80211... |
651 652 653 654 655 656 657 658 |
switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: if (!wdev->current_bss) { err = -ENOTCONN; break; } |
ac422d3cc wireless: Convert... |
659 660 |
if (!ether_addr_equal(wdev->current_bss->pub.bssid, mgmt->bssid)) { |
663fcafd9 cfg80211/mac80211... |
661 662 663 664 665 666 667 668 669 670 |
err = -ENOTCONN; break; } /* * check for IBSS DA must be done by driver as * cfg80211 doesn't track the stations */ if (wdev->iftype == NL80211_IFTYPE_ADHOC) break; |
fe100acdd cfg80211: fix loc... |
671 |
|
663fcafd9 cfg80211/mac80211... |
672 |
/* for station, check that DA is the AP */ |
ac422d3cc wireless: Convert... |
673 674 |
if (!ether_addr_equal(wdev->current_bss->pub.bssid, mgmt->da)) { |
663fcafd9 cfg80211/mac80211... |
675 676 677 678 679 680 681 |
err = -ENOTCONN; break; } break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_AP_VLAN: |
98104fded cfg80211: add P2P... |
682 |
if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev))) |
663fcafd9 cfg80211/mac80211... |
683 684 |
err = -EINVAL; break; |
0778a6a3e mac80211: Let use... |
685 |
case NL80211_IFTYPE_MESH_POINT: |
ac422d3cc wireless: Convert... |
686 |
if (!ether_addr_equal(mgmt->sa, mgmt->bssid)) { |
0778a6a3e mac80211: Let use... |
687 688 689 690 691 692 693 694 |
err = -EINVAL; break; } /* * check for mesh DA must be done by driver as * cfg80211 doesn't track the stations */ break; |
98104fded cfg80211: add P2P... |
695 696 697 698 699 |
case NL80211_IFTYPE_P2P_DEVICE: /* * fall through, P2P device only supports * public action frames */ |
663fcafd9 cfg80211/mac80211... |
700 701 702 703 |
default: err = -EOPNOTSUPP; break; } |
fe100acdd cfg80211: fix loc... |
704 |
wdev_unlock(wdev); |
663fcafd9 cfg80211/mac80211... |
705 706 707 |
if (err) return err; |
026331c4d cfg80211/mac80211... |
708 |
} |
98104fded cfg80211: add P2P... |
709 |
if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) |
026331c4d cfg80211/mac80211... |
710 711 712 |
return -EINVAL; /* Transmit the Action frame as requested by user space */ |
e35e4d28b cfg80211: add wra... |
713 |
return rdev_mgmt_tx(rdev, wdev, chan, offchan, |
e35e4d28b cfg80211: add wra... |
714 715 |
wait, buf, len, no_cck, dont_wait_for_ack, cookie); |
026331c4d cfg80211/mac80211... |
716 |
} |
71bbc9943 cfg80211: use wde... |
717 |
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, |
804483e90 cfg80211/mac80211... |
718 |
const u8 *buf, size_t len, gfp_t gfp) |
026331c4d cfg80211/mac80211... |
719 |
{ |
026331c4d cfg80211/mac80211... |
720 721 |
struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
2e161f78e cfg80211/mac80211... |
722 723 724 725 726 727 |
struct cfg80211_mgmt_registration *reg; const struct ieee80211_txrx_stypes *stypes = &wiphy->mgmt_stypes[wdev->iftype]; struct ieee80211_mgmt *mgmt = (void *)buf; const u8 *data; int data_len; |
026331c4d cfg80211/mac80211... |
728 |
bool result = false; |
2e161f78e cfg80211/mac80211... |
729 730 731 |
__le16 ftype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); u16 stype; |
026331c4d cfg80211/mac80211... |
732 |
|
4ee3e063f cfg80211: add cfg... |
733 |
trace_cfg80211_rx_mgmt(wdev, freq, sig_mbm); |
2e161f78e cfg80211/mac80211... |
734 |
stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; |
026331c4d cfg80211/mac80211... |
735 |
|
4ee3e063f cfg80211: add cfg... |
736 737 |
if (!(stypes->rx & BIT(stype))) { trace_cfg80211_return_bool(false); |
2e161f78e cfg80211/mac80211... |
738 |
return false; |
4ee3e063f cfg80211: add cfg... |
739 |
} |
026331c4d cfg80211/mac80211... |
740 |
|
2e161f78e cfg80211/mac80211... |
741 742 743 744 745 746 747 748 |
data = buf + ieee80211_hdrlen(mgmt->frame_control); data_len = len - ieee80211_hdrlen(mgmt->frame_control); spin_lock_bh(&wdev->mgmt_registrations_lock); list_for_each_entry(reg, &wdev->mgmt_registrations, list) { if (reg->frame_type != ftype) continue; |
026331c4d cfg80211/mac80211... |
749 |
|
2e161f78e cfg80211/mac80211... |
750 |
if (reg->match_len > data_len) |
026331c4d cfg80211/mac80211... |
751 |
continue; |
2e161f78e cfg80211/mac80211... |
752 |
if (memcmp(reg->match, data, reg->match_len)) |
026331c4d cfg80211/mac80211... |
753 754 755 756 757 |
continue; /* found match! */ /* Indicate the received Action frame to user space */ |
15e473046 netlink: Rename p... |
758 |
if (nl80211_send_mgmt(rdev, wdev, reg->nlportid, |
804483e90 cfg80211/mac80211... |
759 |
freq, sig_mbm, |
2e161f78e cfg80211/mac80211... |
760 |
buf, len, gfp)) |
026331c4d cfg80211/mac80211... |
761 762 763 764 765 |
continue; result = true; break; } |
2e161f78e cfg80211/mac80211... |
766 |
spin_unlock_bh(&wdev->mgmt_registrations_lock); |
026331c4d cfg80211/mac80211... |
767 |
|
4ee3e063f cfg80211: add cfg... |
768 |
trace_cfg80211_return_bool(result); |
026331c4d cfg80211/mac80211... |
769 770 |
return result; } |
2e161f78e cfg80211/mac80211... |
771 |
EXPORT_SYMBOL(cfg80211_rx_mgmt); |
026331c4d cfg80211/mac80211... |
772 |
|
04f39047a nl80211/cfg80211:... |
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
void cfg80211_dfs_channels_update_work(struct work_struct *work) { struct delayed_work *delayed_work; struct cfg80211_registered_device *rdev; struct cfg80211_chan_def chandef; struct ieee80211_supported_band *sband; struct ieee80211_channel *c; struct wiphy *wiphy; bool check_again = false; unsigned long timeout, next_time = 0; int bandid, i; delayed_work = container_of(work, struct delayed_work, work); rdev = container_of(delayed_work, struct cfg80211_registered_device, dfs_update_channels_wk); wiphy = &rdev->wiphy; mutex_lock(&cfg80211_mutex); for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) { sband = wiphy->bands[bandid]; if (!sband) continue; for (i = 0; i < sband->n_channels; i++) { c = &sband->channels[i]; if (c->dfs_state != NL80211_DFS_UNAVAILABLE) continue; timeout = c->dfs_state_entered + IEEE80211_DFS_MIN_NOP_TIME_MS; if (time_after_eq(jiffies, timeout)) { c->dfs_state = NL80211_DFS_USABLE; cfg80211_chandef_create(&chandef, c, NL80211_CHAN_NO_HT); nl80211_radar_notify(rdev, &chandef, NL80211_RADAR_NOP_FINISHED, NULL, GFP_ATOMIC); continue; } if (!check_again) next_time = timeout - jiffies; else next_time = min(next_time, timeout - jiffies); check_again = true; } } mutex_unlock(&cfg80211_mutex); /* reschedule if there are other channels waiting to be cleared again */ if (check_again) queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, next_time); } void cfg80211_radar_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); unsigned long timeout; trace_cfg80211_radar_event(wiphy, chandef); /* only set the chandef supplied channel to unavailable, in * case the radar is detected on only one of multiple channels * spanned by the chandef. */ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, timeout); nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); } EXPORT_SYMBOL(cfg80211_radar_event); void cfg80211_cac_event(struct net_device *netdev, enum nl80211_radar_event event, gfp_t gfp) { struct wireless_dev *wdev = netdev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_chan_def chandef; unsigned long timeout; trace_cfg80211_cac_event(netdev, event); if (WARN_ON(!wdev->cac_started)) return; if (WARN_ON(!wdev->channel)) return; cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); switch (event) { case NL80211_RADAR_CAC_FINISHED: timeout = wdev->cac_start_time + msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); WARN_ON(!time_after_eq(jiffies, timeout)); cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); break; case NL80211_RADAR_CAC_ABORTED: break; default: WARN_ON(1); return; } wdev->cac_started = false; nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); } EXPORT_SYMBOL(cfg80211_cac_event); |