]>
Commit | Line | Data |
---|---|---|
8a906d12 JM |
1 | /* |
2 | * Driver interaction with Linux nl80211/cfg80211 - Event processing | |
3 | * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> | |
4 | * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> | |
5 | * Copyright (c) 2009-2010, Atheros Communications | |
6 | * | |
7 | * This software may be distributed under the terms of the BSD license. | |
8 | * See README for more details. | |
9 | */ | |
10 | ||
11 | #include "includes.h" | |
12 | #include <netlink/genl/genl.h> | |
13 | ||
14 | #include "utils/common.h" | |
159a1791 JM |
15 | #include "utils/eloop.h" |
16 | #include "common/qca-vendor.h" | |
17 | #include "common/qca-vendor-attr.h" | |
8a906d12 JM |
18 | #include "common/ieee802_11_defs.h" |
19 | #include "common/ieee802_11_common.h" | |
20 | #include "driver_nl80211.h" | |
21 | ||
22 | ||
159a1791 JM |
23 | static const char * nl80211_command_to_string(enum nl80211_commands cmd) |
24 | { | |
25 | #define C2S(x) case x: return #x; | |
26 | switch (cmd) { | |
27 | C2S(NL80211_CMD_UNSPEC) | |
28 | C2S(NL80211_CMD_GET_WIPHY) | |
29 | C2S(NL80211_CMD_SET_WIPHY) | |
30 | C2S(NL80211_CMD_NEW_WIPHY) | |
31 | C2S(NL80211_CMD_DEL_WIPHY) | |
32 | C2S(NL80211_CMD_GET_INTERFACE) | |
33 | C2S(NL80211_CMD_SET_INTERFACE) | |
34 | C2S(NL80211_CMD_NEW_INTERFACE) | |
35 | C2S(NL80211_CMD_DEL_INTERFACE) | |
36 | C2S(NL80211_CMD_GET_KEY) | |
37 | C2S(NL80211_CMD_SET_KEY) | |
38 | C2S(NL80211_CMD_NEW_KEY) | |
39 | C2S(NL80211_CMD_DEL_KEY) | |
40 | C2S(NL80211_CMD_GET_BEACON) | |
41 | C2S(NL80211_CMD_SET_BEACON) | |
42 | C2S(NL80211_CMD_START_AP) | |
43 | C2S(NL80211_CMD_STOP_AP) | |
44 | C2S(NL80211_CMD_GET_STATION) | |
45 | C2S(NL80211_CMD_SET_STATION) | |
46 | C2S(NL80211_CMD_NEW_STATION) | |
47 | C2S(NL80211_CMD_DEL_STATION) | |
48 | C2S(NL80211_CMD_GET_MPATH) | |
49 | C2S(NL80211_CMD_SET_MPATH) | |
50 | C2S(NL80211_CMD_NEW_MPATH) | |
51 | C2S(NL80211_CMD_DEL_MPATH) | |
52 | C2S(NL80211_CMD_SET_BSS) | |
53 | C2S(NL80211_CMD_SET_REG) | |
54 | C2S(NL80211_CMD_REQ_SET_REG) | |
55 | C2S(NL80211_CMD_GET_MESH_CONFIG) | |
56 | C2S(NL80211_CMD_SET_MESH_CONFIG) | |
57 | C2S(NL80211_CMD_SET_MGMT_EXTRA_IE) | |
58 | C2S(NL80211_CMD_GET_REG) | |
59 | C2S(NL80211_CMD_GET_SCAN) | |
60 | C2S(NL80211_CMD_TRIGGER_SCAN) | |
61 | C2S(NL80211_CMD_NEW_SCAN_RESULTS) | |
62 | C2S(NL80211_CMD_SCAN_ABORTED) | |
63 | C2S(NL80211_CMD_REG_CHANGE) | |
64 | C2S(NL80211_CMD_AUTHENTICATE) | |
65 | C2S(NL80211_CMD_ASSOCIATE) | |
66 | C2S(NL80211_CMD_DEAUTHENTICATE) | |
67 | C2S(NL80211_CMD_DISASSOCIATE) | |
68 | C2S(NL80211_CMD_MICHAEL_MIC_FAILURE) | |
69 | C2S(NL80211_CMD_REG_BEACON_HINT) | |
70 | C2S(NL80211_CMD_JOIN_IBSS) | |
71 | C2S(NL80211_CMD_LEAVE_IBSS) | |
72 | C2S(NL80211_CMD_TESTMODE) | |
73 | C2S(NL80211_CMD_CONNECT) | |
74 | C2S(NL80211_CMD_ROAM) | |
75 | C2S(NL80211_CMD_DISCONNECT) | |
76 | C2S(NL80211_CMD_SET_WIPHY_NETNS) | |
77 | C2S(NL80211_CMD_GET_SURVEY) | |
78 | C2S(NL80211_CMD_NEW_SURVEY_RESULTS) | |
79 | C2S(NL80211_CMD_SET_PMKSA) | |
80 | C2S(NL80211_CMD_DEL_PMKSA) | |
81 | C2S(NL80211_CMD_FLUSH_PMKSA) | |
82 | C2S(NL80211_CMD_REMAIN_ON_CHANNEL) | |
83 | C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL) | |
84 | C2S(NL80211_CMD_SET_TX_BITRATE_MASK) | |
85 | C2S(NL80211_CMD_REGISTER_FRAME) | |
86 | C2S(NL80211_CMD_FRAME) | |
87 | C2S(NL80211_CMD_FRAME_TX_STATUS) | |
88 | C2S(NL80211_CMD_SET_POWER_SAVE) | |
89 | C2S(NL80211_CMD_GET_POWER_SAVE) | |
90 | C2S(NL80211_CMD_SET_CQM) | |
91 | C2S(NL80211_CMD_NOTIFY_CQM) | |
92 | C2S(NL80211_CMD_SET_CHANNEL) | |
93 | C2S(NL80211_CMD_SET_WDS_PEER) | |
94 | C2S(NL80211_CMD_FRAME_WAIT_CANCEL) | |
95 | C2S(NL80211_CMD_JOIN_MESH) | |
96 | C2S(NL80211_CMD_LEAVE_MESH) | |
97 | C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE) | |
98 | C2S(NL80211_CMD_UNPROT_DISASSOCIATE) | |
99 | C2S(NL80211_CMD_NEW_PEER_CANDIDATE) | |
100 | C2S(NL80211_CMD_GET_WOWLAN) | |
101 | C2S(NL80211_CMD_SET_WOWLAN) | |
102 | C2S(NL80211_CMD_START_SCHED_SCAN) | |
103 | C2S(NL80211_CMD_STOP_SCHED_SCAN) | |
104 | C2S(NL80211_CMD_SCHED_SCAN_RESULTS) | |
105 | C2S(NL80211_CMD_SCHED_SCAN_STOPPED) | |
106 | C2S(NL80211_CMD_SET_REKEY_OFFLOAD) | |
107 | C2S(NL80211_CMD_PMKSA_CANDIDATE) | |
108 | C2S(NL80211_CMD_TDLS_OPER) | |
109 | C2S(NL80211_CMD_TDLS_MGMT) | |
110 | C2S(NL80211_CMD_UNEXPECTED_FRAME) | |
111 | C2S(NL80211_CMD_PROBE_CLIENT) | |
112 | C2S(NL80211_CMD_REGISTER_BEACONS) | |
113 | C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME) | |
114 | C2S(NL80211_CMD_SET_NOACK_MAP) | |
115 | C2S(NL80211_CMD_CH_SWITCH_NOTIFY) | |
116 | C2S(NL80211_CMD_START_P2P_DEVICE) | |
117 | C2S(NL80211_CMD_STOP_P2P_DEVICE) | |
118 | C2S(NL80211_CMD_CONN_FAILED) | |
119 | C2S(NL80211_CMD_SET_MCAST_RATE) | |
120 | C2S(NL80211_CMD_SET_MAC_ACL) | |
121 | C2S(NL80211_CMD_RADAR_DETECT) | |
122 | C2S(NL80211_CMD_GET_PROTOCOL_FEATURES) | |
123 | C2S(NL80211_CMD_UPDATE_FT_IES) | |
124 | C2S(NL80211_CMD_FT_EVENT) | |
125 | C2S(NL80211_CMD_CRIT_PROTOCOL_START) | |
126 | C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) | |
127 | C2S(NL80211_CMD_GET_COALESCE) | |
128 | C2S(NL80211_CMD_SET_COALESCE) | |
129 | C2S(NL80211_CMD_CHANNEL_SWITCH) | |
130 | C2S(NL80211_CMD_VENDOR) | |
131 | C2S(NL80211_CMD_SET_QOS_MAP) | |
dfa87878 MB |
132 | C2S(NL80211_CMD_ADD_TX_TS) |
133 | C2S(NL80211_CMD_DEL_TX_TS) | |
159a1791 JM |
134 | default: |
135 | return "NL80211_CMD_UNKNOWN"; | |
136 | } | |
137 | #undef C2S | |
138 | } | |
139 | ||
140 | ||
8a906d12 JM |
141 | static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, |
142 | const u8 *frame, size_t len) | |
143 | { | |
144 | const struct ieee80211_mgmt *mgmt; | |
145 | union wpa_event_data event; | |
146 | ||
147 | if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && | |
148 | drv->force_connect_cmd) { | |
149 | /* | |
150 | * Avoid reporting two association events that would confuse | |
151 | * the core code. | |
152 | */ | |
153 | wpa_printf(MSG_DEBUG, | |
154 | "nl80211: Ignore auth event when using driver SME"); | |
155 | return; | |
156 | } | |
157 | ||
158 | wpa_printf(MSG_DEBUG, "nl80211: Authenticate event"); | |
159 | mgmt = (const struct ieee80211_mgmt *) frame; | |
160 | if (len < 24 + sizeof(mgmt->u.auth)) { | |
161 | wpa_printf(MSG_DEBUG, "nl80211: Too short association event " | |
162 | "frame"); | |
163 | return; | |
164 | } | |
165 | ||
166 | os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); | |
167 | os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN); | |
168 | os_memset(&event, 0, sizeof(event)); | |
169 | os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); | |
170 | event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); | |
171 | event.auth.auth_transaction = | |
172 | le_to_host16(mgmt->u.auth.auth_transaction); | |
173 | event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); | |
174 | if (len > 24 + sizeof(mgmt->u.auth)) { | |
175 | event.auth.ies = mgmt->u.auth.variable; | |
176 | event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); | |
177 | } | |
178 | ||
179 | wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); | |
180 | } | |
181 | ||
182 | ||
dcf8fbc0 JM |
183 | static void nl80211_parse_wmm_params(struct nlattr *wmm_attr, |
184 | struct wmm_params *wmm_params) | |
7e0e1069 EP |
185 | { |
186 | struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1]; | |
187 | static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = { | |
188 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | |
189 | }; | |
190 | ||
dcf8fbc0 JM |
191 | if (!wmm_attr || |
192 | nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr, | |
193 | wme_policy) || | |
194 | !wmm_info[NL80211_STA_WME_UAPSD_QUEUES]) | |
195 | return; | |
7e0e1069 EP |
196 | |
197 | wmm_params->uapsd_queues = | |
198 | nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]); | |
199 | wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO; | |
7e0e1069 EP |
200 | } |
201 | ||
202 | ||
8a906d12 | 203 | static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, |
7e0e1069 | 204 | const u8 *frame, size_t len, struct nlattr *wmm) |
8a906d12 JM |
205 | { |
206 | const struct ieee80211_mgmt *mgmt; | |
207 | union wpa_event_data event; | |
208 | u16 status; | |
209 | ||
210 | if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && | |
211 | drv->force_connect_cmd) { | |
212 | /* | |
213 | * Avoid reporting two association events that would confuse | |
214 | * the core code. | |
215 | */ | |
216 | wpa_printf(MSG_DEBUG, | |
217 | "nl80211: Ignore assoc event when using driver SME"); | |
218 | return; | |
219 | } | |
220 | ||
221 | wpa_printf(MSG_DEBUG, "nl80211: Associate event"); | |
222 | mgmt = (const struct ieee80211_mgmt *) frame; | |
223 | if (len < 24 + sizeof(mgmt->u.assoc_resp)) { | |
224 | wpa_printf(MSG_DEBUG, "nl80211: Too short association event " | |
225 | "frame"); | |
226 | return; | |
227 | } | |
228 | ||
229 | status = le_to_host16(mgmt->u.assoc_resp.status_code); | |
230 | if (status != WLAN_STATUS_SUCCESS) { | |
231 | os_memset(&event, 0, sizeof(event)); | |
232 | event.assoc_reject.bssid = mgmt->bssid; | |
233 | if (len > 24 + sizeof(mgmt->u.assoc_resp)) { | |
234 | event.assoc_reject.resp_ies = | |
235 | (u8 *) mgmt->u.assoc_resp.variable; | |
236 | event.assoc_reject.resp_ies_len = | |
237 | len - 24 - sizeof(mgmt->u.assoc_resp); | |
238 | } | |
239 | event.assoc_reject.status_code = status; | |
240 | ||
241 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); | |
242 | return; | |
243 | } | |
244 | ||
245 | drv->associated = 1; | |
246 | os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); | |
247 | os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN); | |
248 | ||
249 | os_memset(&event, 0, sizeof(event)); | |
250 | if (len > 24 + sizeof(mgmt->u.assoc_resp)) { | |
251 | event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; | |
252 | event.assoc_info.resp_ies_len = | |
253 | len - 24 - sizeof(mgmt->u.assoc_resp); | |
254 | } | |
255 | ||
256 | event.assoc_info.freq = drv->assoc_freq; | |
257 | ||
7e0e1069 EP |
258 | nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params); |
259 | ||
8a906d12 JM |
260 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); |
261 | } | |
262 | ||
263 | ||
159a1791 JM |
264 | static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, |
265 | enum nl80211_commands cmd, struct nlattr *status, | |
266 | struct nlattr *addr, struct nlattr *req_ie, | |
267 | struct nlattr *resp_ie, | |
9a5160f5 | 268 | struct nlattr *timed_out, |
159a1791 JM |
269 | struct nlattr *authorized, |
270 | struct nlattr *key_replay_ctr, | |
271 | struct nlattr *ptk_kck, | |
f32227ed RJ |
272 | struct nlattr *ptk_kek, |
273 | struct nlattr *subnet_status) | |
8a906d12 JM |
274 | { |
275 | union wpa_event_data event; | |
c41d0840 | 276 | const u8 *ssid; |
0d4e3d1d | 277 | u16 status_code; |
8a906d12 JM |
278 | |
279 | if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { | |
280 | /* | |
281 | * Avoid reporting two association events that would confuse | |
282 | * the core code. | |
283 | */ | |
284 | wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) " | |
285 | "when using userspace SME", cmd); | |
286 | return; | |
287 | } | |
288 | ||
1126c078 JM |
289 | drv->connect_reassoc = 0; |
290 | ||
0d4e3d1d JJ |
291 | status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS; |
292 | ||
293 | if (cmd == NL80211_CMD_CONNECT) { | |
294 | wpa_printf(MSG_DEBUG, | |
295 | "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)", | |
296 | status_code, drv->ignore_next_local_disconnect); | |
297 | } else if (cmd == NL80211_CMD_ROAM) { | |
8a906d12 | 298 | wpa_printf(MSG_DEBUG, "nl80211: Roam event"); |
0d4e3d1d | 299 | } |
8a906d12 JM |
300 | |
301 | os_memset(&event, 0, sizeof(event)); | |
0d4e3d1d | 302 | if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) { |
8a906d12 JM |
303 | if (addr) |
304 | event.assoc_reject.bssid = nla_data(addr); | |
0d4e3d1d JJ |
305 | if (drv->ignore_next_local_disconnect) { |
306 | drv->ignore_next_local_disconnect = 0; | |
307 | if (!event.assoc_reject.bssid || | |
308 | (os_memcmp(event.assoc_reject.bssid, | |
309 | drv->auth_attempt_bssid, | |
310 | ETH_ALEN) != 0)) { | |
311 | /* | |
312 | * Ignore the event that came without a BSSID or | |
313 | * for the old connection since this is likely | |
314 | * not relevant to the new Connect command. | |
315 | */ | |
316 | wpa_printf(MSG_DEBUG, | |
317 | "nl80211: Ignore connection failure event triggered during reassociation"); | |
318 | return; | |
319 | } | |
320 | } | |
8a906d12 JM |
321 | if (resp_ie) { |
322 | event.assoc_reject.resp_ies = nla_data(resp_ie); | |
323 | event.assoc_reject.resp_ies_len = nla_len(resp_ie); | |
324 | } | |
0d4e3d1d | 325 | event.assoc_reject.status_code = status_code; |
9a5160f5 | 326 | event.assoc_reject.timed_out = timed_out != NULL; |
8a906d12 JM |
327 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); |
328 | return; | |
329 | } | |
330 | ||
331 | drv->associated = 1; | |
332 | if (addr) { | |
333 | os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); | |
334 | os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); | |
335 | } | |
336 | ||
337 | if (req_ie) { | |
338 | event.assoc_info.req_ies = nla_data(req_ie); | |
339 | event.assoc_info.req_ies_len = nla_len(req_ie); | |
c41d0840 KV |
340 | |
341 | if (cmd == NL80211_CMD_ROAM) { | |
231b04b6 AS |
342 | ssid = get_ie(event.assoc_info.req_ies, |
343 | event.assoc_info.req_ies_len, | |
344 | WLAN_EID_SSID); | |
c41d0840 KV |
345 | if (ssid && ssid[1] > 0 && ssid[1] <= 32) { |
346 | drv->ssid_len = ssid[1]; | |
347 | os_memcpy(drv->ssid, ssid + 2, ssid[1]); | |
348 | } | |
349 | } | |
8a906d12 JM |
350 | } |
351 | if (resp_ie) { | |
352 | event.assoc_info.resp_ies = nla_data(resp_ie); | |
353 | event.assoc_info.resp_ies_len = nla_len(resp_ie); | |
354 | } | |
355 | ||
356 | event.assoc_info.freq = nl80211_get_assoc_freq(drv); | |
357 | ||
358 | if (authorized && nla_get_u8(authorized)) { | |
359 | event.assoc_info.authorized = 1; | |
360 | wpa_printf(MSG_DEBUG, "nl80211: connection authorized"); | |
361 | } | |
362 | if (key_replay_ctr) { | |
363 | event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr); | |
364 | event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr); | |
365 | } | |
366 | if (ptk_kck) { | |
367 | event.assoc_info.ptk_kck = nla_data(ptk_kck); | |
10bbe8b8 | 368 | event.assoc_info.ptk_kck_len = nla_len(ptk_kck); |
8a906d12 JM |
369 | } |
370 | if (ptk_kek) { | |
371 | event.assoc_info.ptk_kek = nla_data(ptk_kek); | |
372 | event.assoc_info.ptk_kek_len = nla_len(ptk_kek); | |
373 | } | |
374 | ||
f32227ed RJ |
375 | if (subnet_status) { |
376 | /* | |
377 | * At least for now, this is only available from | |
378 | * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that | |
379 | * attribute has the same values 0, 1, 2 as are used in the | |
380 | * variable here, so no mapping between different values are | |
381 | * needed. | |
382 | */ | |
383 | event.assoc_info.subnet_status = nla_get_u8(subnet_status); | |
384 | } | |
385 | ||
8a906d12 JM |
386 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); |
387 | } | |
388 | ||
389 | ||
159a1791 JM |
390 | static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, |
391 | struct nlattr *reason, struct nlattr *addr, | |
392 | struct nlattr *by_ap) | |
8a906d12 JM |
393 | { |
394 | union wpa_event_data data; | |
395 | unsigned int locally_generated = by_ap == NULL; | |
396 | ||
397 | if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { | |
398 | /* | |
399 | * Avoid reporting two disassociation events that could | |
400 | * confuse the core code. | |
401 | */ | |
402 | wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " | |
403 | "event when using userspace SME"); | |
404 | return; | |
405 | } | |
406 | ||
407 | if (drv->ignore_next_local_disconnect) { | |
408 | drv->ignore_next_local_disconnect = 0; | |
409 | if (locally_generated) { | |
410 | wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " | |
411 | "event triggered during reassociation"); | |
412 | return; | |
413 | } | |
414 | wpa_printf(MSG_WARNING, "nl80211: Was expecting local " | |
415 | "disconnect but got another disconnect " | |
416 | "event first"); | |
417 | } | |
418 | ||
419 | wpa_printf(MSG_DEBUG, "nl80211: Disconnect event"); | |
420 | nl80211_mark_disconnected(drv); | |
421 | os_memset(&data, 0, sizeof(data)); | |
422 | if (reason) | |
423 | data.deauth_info.reason_code = nla_get_u16(reason); | |
424 | data.deauth_info.locally_generated = by_ap == NULL; | |
425 | wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data); | |
426 | } | |
427 | ||
428 | ||
429 | static int calculate_chan_offset(int width, int freq, int cf1, int cf2) | |
430 | { | |
431 | int freq1 = 0; | |
432 | ||
433 | switch (convert2width(width)) { | |
434 | case CHAN_WIDTH_20_NOHT: | |
435 | case CHAN_WIDTH_20: | |
436 | return 0; | |
437 | case CHAN_WIDTH_40: | |
438 | freq1 = cf1 - 10; | |
439 | break; | |
440 | case CHAN_WIDTH_80: | |
441 | freq1 = cf1 - 30; | |
442 | break; | |
443 | case CHAN_WIDTH_160: | |
444 | freq1 = cf1 - 70; | |
445 | break; | |
446 | case CHAN_WIDTH_UNKNOWN: | |
447 | case CHAN_WIDTH_80P80: | |
448 | /* FIXME: implement this */ | |
449 | return 0; | |
450 | } | |
451 | ||
452 | return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1; | |
453 | } | |
454 | ||
455 | ||
159a1791 JM |
456 | static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, |
457 | struct nlattr *ifindex, struct nlattr *freq, | |
458 | struct nlattr *type, struct nlattr *bw, | |
459 | struct nlattr *cf1, struct nlattr *cf2) | |
8a906d12 JM |
460 | { |
461 | struct i802_bss *bss; | |
462 | union wpa_event_data data; | |
463 | int ht_enabled = 1; | |
464 | int chan_offset = 0; | |
465 | int ifidx; | |
466 | ||
467 | wpa_printf(MSG_DEBUG, "nl80211: Channel switch event"); | |
468 | ||
469 | if (!freq) | |
470 | return; | |
471 | ||
472 | ifidx = nla_get_u32(ifindex); | |
473 | bss = get_bss_ifindex(drv, ifidx); | |
474 | if (bss == NULL) { | |
475 | wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring", | |
476 | ifidx); | |
477 | return; | |
478 | } | |
479 | ||
480 | if (type) { | |
481 | enum nl80211_channel_type ch_type = nla_get_u32(type); | |
482 | ||
483 | wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type); | |
484 | switch (ch_type) { | |
485 | case NL80211_CHAN_NO_HT: | |
486 | ht_enabled = 0; | |
487 | break; | |
488 | case NL80211_CHAN_HT20: | |
489 | break; | |
490 | case NL80211_CHAN_HT40PLUS: | |
491 | chan_offset = 1; | |
492 | break; | |
493 | case NL80211_CHAN_HT40MINUS: | |
494 | chan_offset = -1; | |
495 | break; | |
496 | } | |
497 | } else if (bw && cf1) { | |
498 | /* This can happen for example with VHT80 ch switch */ | |
499 | chan_offset = calculate_chan_offset(nla_get_u32(bw), | |
500 | nla_get_u32(freq), | |
501 | nla_get_u32(cf1), | |
502 | cf2 ? nla_get_u32(cf2) : 0); | |
503 | } else { | |
504 | wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail"); | |
505 | } | |
506 | ||
507 | os_memset(&data, 0, sizeof(data)); | |
508 | data.ch_switch.freq = nla_get_u32(freq); | |
509 | data.ch_switch.ht_enabled = ht_enabled; | |
510 | data.ch_switch.ch_offset = chan_offset; | |
511 | if (bw) | |
512 | data.ch_switch.ch_width = convert2width(nla_get_u32(bw)); | |
513 | if (cf1) | |
514 | data.ch_switch.cf1 = nla_get_u32(cf1); | |
515 | if (cf2) | |
516 | data.ch_switch.cf2 = nla_get_u32(cf2); | |
517 | ||
518 | bss->freq = data.ch_switch.freq; | |
519 | ||
520 | wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data); | |
521 | } | |
522 | ||
523 | ||
524 | static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, | |
525 | enum nl80211_commands cmd, struct nlattr *addr) | |
526 | { | |
527 | union wpa_event_data event; | |
528 | enum wpa_event_type ev; | |
529 | ||
530 | if (nla_len(addr) != ETH_ALEN) | |
531 | return; | |
532 | ||
533 | wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR, | |
534 | cmd, MAC2STR((u8 *) nla_data(addr))); | |
535 | ||
536 | if (cmd == NL80211_CMD_AUTHENTICATE) | |
537 | ev = EVENT_AUTH_TIMED_OUT; | |
538 | else if (cmd == NL80211_CMD_ASSOCIATE) | |
539 | ev = EVENT_ASSOC_TIMED_OUT; | |
540 | else | |
541 | return; | |
542 | ||
543 | os_memset(&event, 0, sizeof(event)); | |
544 | os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); | |
545 | wpa_supplicant_event(drv->ctx, ev, &event); | |
546 | } | |
547 | ||
548 | ||
549 | static void mlme_event_mgmt(struct i802_bss *bss, | |
550 | struct nlattr *freq, struct nlattr *sig, | |
551 | const u8 *frame, size_t len) | |
552 | { | |
553 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
554 | const struct ieee80211_mgmt *mgmt; | |
555 | union wpa_event_data event; | |
556 | u16 fc, stype; | |
557 | int ssi_signal = 0; | |
558 | int rx_freq = 0; | |
559 | ||
560 | wpa_printf(MSG_MSGDUMP, "nl80211: Frame event"); | |
561 | mgmt = (const struct ieee80211_mgmt *) frame; | |
562 | if (len < 24) { | |
563 | wpa_printf(MSG_DEBUG, "nl80211: Too short management frame"); | |
564 | return; | |
565 | } | |
566 | ||
567 | fc = le_to_host16(mgmt->frame_control); | |
568 | stype = WLAN_FC_GET_STYPE(fc); | |
569 | ||
570 | if (sig) | |
571 | ssi_signal = (s32) nla_get_u32(sig); | |
572 | ||
573 | os_memset(&event, 0, sizeof(event)); | |
574 | if (freq) { | |
575 | event.rx_mgmt.freq = nla_get_u32(freq); | |
576 | rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq; | |
577 | } | |
578 | wpa_printf(MSG_DEBUG, | |
b9ca12a9 | 579 | "nl80211: RX frame da=" MACSTR " sa=" MACSTR " bssid=" MACSTR |
1f90dfd2 | 580 | " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u", |
b9ca12a9 JM |
581 | MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid), |
582 | rx_freq, ssi_signal, fc, | |
1f90dfd2 | 583 | le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc), |
8a906d12 JM |
584 | (unsigned int) len); |
585 | event.rx_mgmt.frame = frame; | |
586 | event.rx_mgmt.frame_len = len; | |
587 | event.rx_mgmt.ssi_signal = ssi_signal; | |
588 | event.rx_mgmt.drv_priv = bss; | |
589 | wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); | |
590 | } | |
591 | ||
592 | ||
593 | static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, | |
594 | struct nlattr *cookie, const u8 *frame, | |
595 | size_t len, struct nlattr *ack) | |
596 | { | |
597 | union wpa_event_data event; | |
598 | const struct ieee80211_hdr *hdr; | |
599 | u16 fc; | |
600 | ||
601 | wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event"); | |
602 | if (!is_ap_interface(drv->nlmode)) { | |
603 | u64 cookie_val; | |
604 | ||
605 | if (!cookie) | |
606 | return; | |
607 | ||
608 | cookie_val = nla_get_u64(cookie); | |
609 | wpa_printf(MSG_DEBUG, "nl80211: Action TX status:" | |
610 | " cookie=0%llx%s (ack=%d)", | |
611 | (long long unsigned int) cookie_val, | |
612 | cookie_val == drv->send_action_cookie ? | |
613 | " (match)" : " (unknown)", ack != NULL); | |
614 | if (cookie_val != drv->send_action_cookie) | |
615 | return; | |
616 | } | |
617 | ||
618 | hdr = (const struct ieee80211_hdr *) frame; | |
619 | fc = le_to_host16(hdr->frame_control); | |
620 | ||
621 | os_memset(&event, 0, sizeof(event)); | |
622 | event.tx_status.type = WLAN_FC_GET_TYPE(fc); | |
623 | event.tx_status.stype = WLAN_FC_GET_STYPE(fc); | |
624 | event.tx_status.dst = hdr->addr1; | |
625 | event.tx_status.data = frame; | |
626 | event.tx_status.data_len = len; | |
627 | event.tx_status.ack = ack != NULL; | |
628 | wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); | |
629 | } | |
630 | ||
631 | ||
632 | static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, | |
633 | enum wpa_event_type type, | |
634 | const u8 *frame, size_t len) | |
635 | { | |
636 | const struct ieee80211_mgmt *mgmt; | |
637 | union wpa_event_data event; | |
638 | const u8 *bssid = NULL; | |
639 | u16 reason_code = 0; | |
640 | ||
641 | if (type == EVENT_DEAUTH) | |
642 | wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event"); | |
643 | else | |
644 | wpa_printf(MSG_DEBUG, "nl80211: Disassociate event"); | |
645 | ||
646 | mgmt = (const struct ieee80211_mgmt *) frame; | |
647 | if (len >= 24) { | |
648 | bssid = mgmt->bssid; | |
649 | ||
650 | if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) && | |
651 | !drv->associated && | |
652 | os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 && | |
653 | os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 && | |
654 | os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) { | |
655 | /* | |
656 | * Avoid issues with some roaming cases where | |
657 | * disconnection event for the old AP may show up after | |
658 | * we have started connection with the new AP. | |
757785da AB |
659 | * In case of locally generated event clear |
660 | * ignore_next_local_deauth as well, to avoid next local | |
661 | * deauth event be wrongly ignored. | |
8a906d12 | 662 | */ |
757785da AB |
663 | if (!os_memcmp(mgmt->sa, drv->first_bss->addr, |
664 | ETH_ALEN)) { | |
665 | wpa_printf(MSG_DEBUG, | |
666 | "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag"); | |
667 | drv->ignore_next_local_deauth = 0; | |
668 | } else { | |
669 | wpa_printf(MSG_DEBUG, | |
670 | "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR, | |
671 | MAC2STR(bssid), | |
672 | MAC2STR(drv->auth_attempt_bssid)); | |
673 | } | |
8a906d12 JM |
674 | return; |
675 | } | |
676 | ||
1126c078 JM |
677 | if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && |
678 | drv->connect_reassoc && drv->associated && | |
679 | os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 && | |
680 | os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) { | |
681 | /* | |
682 | * Avoid issues with some roaming cases where | |
683 | * disconnection event for the old AP may show up after | |
684 | * we have started connection with the new AP. | |
685 | */ | |
686 | wpa_printf(MSG_DEBUG, | |
687 | "nl80211: Ignore deauth/disassoc event from old AP " | |
688 | MACSTR | |
689 | " when already connecting with " MACSTR, | |
690 | MAC2STR(bssid), | |
691 | MAC2STR(drv->auth_attempt_bssid)); | |
692 | return; | |
693 | } | |
694 | ||
8a906d12 JM |
695 | if (drv->associated != 0 && |
696 | os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && | |
697 | os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { | |
698 | /* | |
699 | * We have presumably received this deauth as a | |
700 | * response to a clear_state_mismatch() outgoing | |
701 | * deauth. Don't let it take us offline! | |
702 | */ | |
703 | wpa_printf(MSG_DEBUG, "nl80211: Deauth received " | |
704 | "from Unknown BSSID " MACSTR " -- ignoring", | |
705 | MAC2STR(bssid)); | |
706 | return; | |
707 | } | |
708 | } | |
709 | ||
710 | nl80211_mark_disconnected(drv); | |
711 | os_memset(&event, 0, sizeof(event)); | |
712 | ||
713 | /* Note: Same offset for Reason Code in both frame subtypes */ | |
714 | if (len >= 24 + sizeof(mgmt->u.deauth)) | |
715 | reason_code = le_to_host16(mgmt->u.deauth.reason_code); | |
716 | ||
717 | if (type == EVENT_DISASSOC) { | |
718 | event.disassoc_info.locally_generated = | |
719 | !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); | |
720 | event.disassoc_info.addr = bssid; | |
721 | event.disassoc_info.reason_code = reason_code; | |
722 | if (frame + len > mgmt->u.disassoc.variable) { | |
723 | event.disassoc_info.ie = mgmt->u.disassoc.variable; | |
724 | event.disassoc_info.ie_len = frame + len - | |
725 | mgmt->u.disassoc.variable; | |
726 | } | |
727 | } else { | |
cb2a926d SS |
728 | event.deauth_info.locally_generated = |
729 | !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); | |
8a906d12 JM |
730 | if (drv->ignore_deauth_event) { |
731 | wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth"); | |
732 | drv->ignore_deauth_event = 0; | |
cb2a926d SS |
733 | if (event.deauth_info.locally_generated) |
734 | drv->ignore_next_local_deauth = 0; | |
8a906d12 JM |
735 | return; |
736 | } | |
8a906d12 JM |
737 | if (drv->ignore_next_local_deauth) { |
738 | drv->ignore_next_local_deauth = 0; | |
739 | if (event.deauth_info.locally_generated) { | |
740 | wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request"); | |
741 | return; | |
742 | } | |
743 | wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first"); | |
744 | } | |
745 | event.deauth_info.addr = bssid; | |
746 | event.deauth_info.reason_code = reason_code; | |
747 | if (frame + len > mgmt->u.deauth.variable) { | |
748 | event.deauth_info.ie = mgmt->u.deauth.variable; | |
749 | event.deauth_info.ie_len = frame + len - | |
750 | mgmt->u.deauth.variable; | |
751 | } | |
752 | } | |
753 | ||
754 | wpa_supplicant_event(drv->ctx, type, &event); | |
755 | } | |
756 | ||
757 | ||
758 | static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv, | |
759 | enum wpa_event_type type, | |
760 | const u8 *frame, size_t len) | |
761 | { | |
762 | const struct ieee80211_mgmt *mgmt; | |
763 | union wpa_event_data event; | |
764 | u16 reason_code = 0; | |
765 | ||
766 | if (type == EVENT_UNPROT_DEAUTH) | |
767 | wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event"); | |
768 | else | |
769 | wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event"); | |
770 | ||
771 | if (len < 24) | |
772 | return; | |
773 | ||
774 | mgmt = (const struct ieee80211_mgmt *) frame; | |
775 | ||
776 | os_memset(&event, 0, sizeof(event)); | |
777 | /* Note: Same offset for Reason Code in both frame subtypes */ | |
778 | if (len >= 24 + sizeof(mgmt->u.deauth)) | |
779 | reason_code = le_to_host16(mgmt->u.deauth.reason_code); | |
780 | ||
781 | if (type == EVENT_UNPROT_DISASSOC) { | |
782 | event.unprot_disassoc.sa = mgmt->sa; | |
783 | event.unprot_disassoc.da = mgmt->da; | |
784 | event.unprot_disassoc.reason_code = reason_code; | |
785 | } else { | |
786 | event.unprot_deauth.sa = mgmt->sa; | |
787 | event.unprot_deauth.da = mgmt->da; | |
788 | event.unprot_deauth.reason_code = reason_code; | |
789 | } | |
790 | ||
791 | wpa_supplicant_event(drv->ctx, type, &event); | |
792 | } | |
793 | ||
794 | ||
159a1791 JM |
795 | static void mlme_event(struct i802_bss *bss, |
796 | enum nl80211_commands cmd, struct nlattr *frame, | |
797 | struct nlattr *addr, struct nlattr *timed_out, | |
798 | struct nlattr *freq, struct nlattr *ack, | |
7e0e1069 EP |
799 | struct nlattr *cookie, struct nlattr *sig, |
800 | struct nlattr *wmm) | |
8a906d12 JM |
801 | { |
802 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
803 | const u8 *data; | |
804 | size_t len; | |
805 | ||
806 | if (timed_out && addr) { | |
807 | mlme_timeout_event(drv, cmd, addr); | |
808 | return; | |
809 | } | |
810 | ||
811 | if (frame == NULL) { | |
812 | wpa_printf(MSG_DEBUG, | |
813 | "nl80211: MLME event %d (%s) without frame data", | |
814 | cmd, nl80211_command_to_string(cmd)); | |
815 | return; | |
816 | } | |
817 | ||
818 | data = nla_data(frame); | |
819 | len = nla_len(frame); | |
820 | if (len < 4 + 2 * ETH_ALEN) { | |
821 | wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" | |
822 | MACSTR ") - too short", | |
823 | cmd, nl80211_command_to_string(cmd), bss->ifname, | |
824 | MAC2STR(bss->addr)); | |
825 | return; | |
826 | } | |
827 | wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR | |
828 | ") A1=" MACSTR " A2=" MACSTR, cmd, | |
829 | nl80211_command_to_string(cmd), bss->ifname, | |
830 | MAC2STR(bss->addr), MAC2STR(data + 4), | |
831 | MAC2STR(data + 4 + ETH_ALEN)); | |
832 | if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) && | |
833 | os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && | |
834 | os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) { | |
835 | wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event " | |
836 | "for foreign address", bss->ifname); | |
837 | return; | |
838 | } | |
839 | wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame", | |
840 | nla_data(frame), nla_len(frame)); | |
841 | ||
842 | switch (cmd) { | |
843 | case NL80211_CMD_AUTHENTICATE: | |
844 | mlme_event_auth(drv, nla_data(frame), nla_len(frame)); | |
845 | break; | |
846 | case NL80211_CMD_ASSOCIATE: | |
7e0e1069 | 847 | mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm); |
8a906d12 JM |
848 | break; |
849 | case NL80211_CMD_DEAUTHENTICATE: | |
850 | mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, | |
851 | nla_data(frame), nla_len(frame)); | |
852 | break; | |
853 | case NL80211_CMD_DISASSOCIATE: | |
854 | mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, | |
855 | nla_data(frame), nla_len(frame)); | |
856 | break; | |
857 | case NL80211_CMD_FRAME: | |
858 | mlme_event_mgmt(bss, freq, sig, nla_data(frame), | |
859 | nla_len(frame)); | |
860 | break; | |
861 | case NL80211_CMD_FRAME_TX_STATUS: | |
862 | mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), | |
863 | nla_len(frame), ack); | |
864 | break; | |
865 | case NL80211_CMD_UNPROT_DEAUTHENTICATE: | |
866 | mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, | |
867 | nla_data(frame), nla_len(frame)); | |
868 | break; | |
869 | case NL80211_CMD_UNPROT_DISASSOCIATE: | |
870 | mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, | |
871 | nla_data(frame), nla_len(frame)); | |
872 | break; | |
873 | default: | |
874 | break; | |
875 | } | |
876 | } | |
159a1791 JM |
877 | |
878 | ||
879 | static void mlme_event_michael_mic_failure(struct i802_bss *bss, | |
880 | struct nlattr *tb[]) | |
881 | { | |
882 | union wpa_event_data data; | |
883 | ||
884 | wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); | |
885 | os_memset(&data, 0, sizeof(data)); | |
886 | if (tb[NL80211_ATTR_MAC]) { | |
887 | wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", | |
888 | nla_data(tb[NL80211_ATTR_MAC]), | |
889 | nla_len(tb[NL80211_ATTR_MAC])); | |
890 | data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); | |
891 | } | |
892 | if (tb[NL80211_ATTR_KEY_SEQ]) { | |
893 | wpa_hexdump(MSG_DEBUG, "nl80211: TSC", | |
894 | nla_data(tb[NL80211_ATTR_KEY_SEQ]), | |
895 | nla_len(tb[NL80211_ATTR_KEY_SEQ])); | |
896 | } | |
897 | if (tb[NL80211_ATTR_KEY_TYPE]) { | |
898 | enum nl80211_key_type key_type = | |
899 | nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); | |
900 | wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); | |
901 | if (key_type == NL80211_KEYTYPE_PAIRWISE) | |
902 | data.michael_mic_failure.unicast = 1; | |
903 | } else | |
904 | data.michael_mic_failure.unicast = 1; | |
905 | ||
906 | if (tb[NL80211_ATTR_KEY_IDX]) { | |
907 | u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); | |
908 | wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); | |
909 | } | |
910 | ||
911 | wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); | |
912 | } | |
913 | ||
914 | ||
915 | static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, | |
916 | struct nlattr *tb[]) | |
917 | { | |
918 | unsigned int freq; | |
f0e84057 | 919 | union wpa_event_data event; |
159a1791 JM |
920 | |
921 | if (tb[NL80211_ATTR_MAC] == NULL) { | |
922 | wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " | |
923 | "event"); | |
924 | return; | |
925 | } | |
926 | os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); | |
927 | ||
928 | drv->associated = 1; | |
929 | wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", | |
930 | MAC2STR(drv->bssid)); | |
931 | ||
932 | freq = nl80211_get_assoc_freq(drv); | |
933 | if (freq) { | |
934 | wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz", | |
935 | freq); | |
936 | drv->first_bss->freq = freq; | |
937 | } | |
938 | ||
f0e84057 SB |
939 | os_memset(&event, 0, sizeof(event)); |
940 | event.assoc_info.freq = freq; | |
941 | ||
942 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); | |
159a1791 JM |
943 | } |
944 | ||
945 | ||
946 | static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, | |
947 | int cancel_event, struct nlattr *tb[]) | |
948 | { | |
949 | unsigned int freq, chan_type, duration; | |
950 | union wpa_event_data data; | |
951 | u64 cookie; | |
952 | ||
953 | if (tb[NL80211_ATTR_WIPHY_FREQ]) | |
954 | freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); | |
955 | else | |
956 | freq = 0; | |
957 | ||
958 | if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) | |
959 | chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | |
960 | else | |
961 | chan_type = 0; | |
962 | ||
963 | if (tb[NL80211_ATTR_DURATION]) | |
964 | duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); | |
965 | else | |
966 | duration = 0; | |
967 | ||
968 | if (tb[NL80211_ATTR_COOKIE]) | |
969 | cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); | |
970 | else | |
971 | cookie = 0; | |
972 | ||
973 | wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " | |
974 | "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", | |
975 | cancel_event, freq, chan_type, duration, | |
976 | (long long unsigned int) cookie, | |
977 | cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); | |
978 | ||
979 | if (cookie != drv->remain_on_chan_cookie) | |
980 | return; /* not for us */ | |
981 | ||
982 | if (cancel_event) | |
983 | drv->pending_remain_on_chan = 0; | |
984 | ||
985 | os_memset(&data, 0, sizeof(data)); | |
986 | data.remain_on_channel.freq = freq; | |
987 | data.remain_on_channel.duration = duration; | |
988 | wpa_supplicant_event(drv->ctx, cancel_event ? | |
989 | EVENT_CANCEL_REMAIN_ON_CHANNEL : | |
990 | EVENT_REMAIN_ON_CHANNEL, &data); | |
991 | } | |
992 | ||
993 | ||
994 | static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, | |
995 | struct nlattr *tb[]) | |
996 | { | |
997 | union wpa_event_data data; | |
998 | ||
999 | os_memset(&data, 0, sizeof(data)); | |
1000 | ||
1001 | if (tb[NL80211_ATTR_IE]) { | |
1002 | data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]); | |
1003 | data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]); | |
1004 | } | |
1005 | ||
1006 | if (tb[NL80211_ATTR_IE_RIC]) { | |
1007 | data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]); | |
1008 | data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]); | |
1009 | } | |
1010 | ||
1011 | if (tb[NL80211_ATTR_MAC]) | |
1012 | os_memcpy(data.ft_ies.target_ap, | |
1013 | nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); | |
1014 | ||
1015 | wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR, | |
1016 | MAC2STR(data.ft_ies.target_ap)); | |
1017 | ||
1018 | wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data); | |
1019 | } | |
1020 | ||
1021 | ||
1022 | static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, | |
adcd7c4b | 1023 | struct nlattr *tb[], int external_scan) |
159a1791 JM |
1024 | { |
1025 | union wpa_event_data event; | |
1026 | struct nlattr *nl; | |
1027 | int rem; | |
1028 | struct scan_info *info; | |
1029 | #define MAX_REPORT_FREQS 50 | |
1030 | int freqs[MAX_REPORT_FREQS]; | |
1031 | int num_freqs = 0; | |
1032 | ||
adcd7c4b | 1033 | if (!external_scan && drv->scan_for_auth) { |
159a1791 JM |
1034 | drv->scan_for_auth = 0; |
1035 | wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " | |
1036 | "cfg80211 BSS entry"); | |
1037 | wpa_driver_nl80211_authenticate_retry(drv); | |
1038 | return; | |
1039 | } | |
1040 | ||
1041 | os_memset(&event, 0, sizeof(event)); | |
1042 | info = &event.scan_info; | |
1043 | info->aborted = aborted; | |
adcd7c4b KV |
1044 | info->external_scan = external_scan; |
1045 | info->nl_scan_event = 1; | |
159a1791 JM |
1046 | |
1047 | if (tb[NL80211_ATTR_SCAN_SSIDS]) { | |
1048 | nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { | |
1049 | struct wpa_driver_scan_ssid *s = | |
1050 | &info->ssids[info->num_ssids]; | |
1051 | s->ssid = nla_data(nl); | |
1052 | s->ssid_len = nla_len(nl); | |
1053 | wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'", | |
1054 | wpa_ssid_txt(s->ssid, s->ssid_len)); | |
1055 | info->num_ssids++; | |
1056 | if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) | |
1057 | break; | |
1058 | } | |
1059 | } | |
1060 | if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { | |
712525b0 | 1061 | char msg[300], *pos, *end; |
159a1791 JM |
1062 | int res; |
1063 | ||
1064 | pos = msg; | |
1065 | end = pos + sizeof(msg); | |
1066 | *pos = '\0'; | |
1067 | ||
1068 | nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) | |
1069 | { | |
1070 | freqs[num_freqs] = nla_get_u32(nl); | |
1071 | res = os_snprintf(pos, end - pos, " %d", | |
1072 | freqs[num_freqs]); | |
a80ba67a | 1073 | if (!os_snprintf_error(end - pos, res)) |
159a1791 JM |
1074 | pos += res; |
1075 | num_freqs++; | |
1076 | if (num_freqs == MAX_REPORT_FREQS - 1) | |
1077 | break; | |
1078 | } | |
1079 | info->freqs = freqs; | |
1080 | info->num_freqs = num_freqs; | |
1081 | wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", | |
1082 | msg); | |
1083 | } | |
1084 | wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); | |
1085 | } | |
1086 | ||
1087 | ||
1088 | static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, | |
1089 | struct nlattr *tb[]) | |
1090 | { | |
1091 | static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { | |
1092 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | |
1093 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, | |
1094 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | |
1095 | [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, | |
1096 | }; | |
1097 | struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; | |
1098 | enum nl80211_cqm_rssi_threshold_event event; | |
1099 | union wpa_event_data ed; | |
1100 | struct wpa_signal_info sig; | |
1101 | int res; | |
1102 | ||
1103 | if (tb[NL80211_ATTR_CQM] == NULL || | |
1104 | nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], | |
1105 | cqm_policy)) { | |
1106 | wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); | |
1107 | return; | |
1108 | } | |
1109 | ||
1110 | os_memset(&ed, 0, sizeof(ed)); | |
1111 | ||
1112 | if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { | |
1113 | if (!tb[NL80211_ATTR_MAC]) | |
1114 | return; | |
1115 | os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), | |
1116 | ETH_ALEN); | |
1117 | wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); | |
1118 | return; | |
1119 | } | |
1120 | ||
1121 | if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) | |
1122 | return; | |
1123 | event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); | |
1124 | ||
1125 | if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { | |
1126 | wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " | |
1127 | "event: RSSI high"); | |
1128 | ed.signal_change.above_threshold = 1; | |
1129 | } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { | |
1130 | wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " | |
1131 | "event: RSSI low"); | |
1132 | ed.signal_change.above_threshold = 0; | |
1133 | } else | |
1134 | return; | |
1135 | ||
1136 | res = nl80211_get_link_signal(drv, &sig); | |
1137 | if (res == 0) { | |
1138 | ed.signal_change.current_signal = sig.current_signal; | |
1139 | ed.signal_change.current_txrate = sig.current_txrate; | |
1140 | wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", | |
1141 | sig.current_signal, sig.current_txrate); | |
1142 | } | |
1143 | ||
1144 | res = nl80211_get_link_noise(drv, &sig); | |
1145 | if (res == 0) { | |
1146 | ed.signal_change.current_noise = sig.current_noise; | |
1147 | wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm", | |
1148 | sig.current_noise); | |
1149 | } | |
1150 | ||
1151 | wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); | |
1152 | } | |
1153 | ||
1154 | ||
1155 | static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv, | |
1156 | struct nlattr **tb) | |
1157 | { | |
1158 | const u8 *addr; | |
1159 | union wpa_event_data data; | |
1160 | ||
dcf8fbc0 JM |
1161 | if (drv->nlmode != NL80211_IFTYPE_MESH_POINT || |
1162 | !tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE]) | |
159a1791 JM |
1163 | return; |
1164 | ||
1165 | addr = nla_data(tb[NL80211_ATTR_MAC]); | |
7d41907b | 1166 | wpa_printf(MSG_DEBUG, "nl80211: New peer candidate " MACSTR, |
159a1791 JM |
1167 | MAC2STR(addr)); |
1168 | ||
1169 | os_memset(&data, 0, sizeof(data)); | |
1170 | data.mesh_peer.peer = addr; | |
1171 | data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]); | |
1172 | data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]); | |
1173 | wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data); | |
1174 | } | |
1175 | ||
1176 | ||
1177 | static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, | |
7c4027f6 | 1178 | struct i802_bss *bss, |
159a1791 JM |
1179 | struct nlattr **tb) |
1180 | { | |
1181 | u8 *addr; | |
1182 | union wpa_event_data data; | |
1183 | ||
1184 | if (tb[NL80211_ATTR_MAC] == NULL) | |
1185 | return; | |
1186 | addr = nla_data(tb[NL80211_ATTR_MAC]); | |
1187 | wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); | |
1188 | ||
1189 | if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { | |
1190 | u8 *ies = NULL; | |
1191 | size_t ies_len = 0; | |
1192 | if (tb[NL80211_ATTR_IE]) { | |
1193 | ies = nla_data(tb[NL80211_ATTR_IE]); | |
1194 | ies_len = nla_len(tb[NL80211_ATTR_IE]); | |
1195 | } | |
1196 | wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len); | |
7c4027f6 | 1197 | drv_event_assoc(bss->ctx, addr, ies, ies_len, 0); |
159a1791 JM |
1198 | return; |
1199 | } | |
1200 | ||
1201 | if (drv->nlmode != NL80211_IFTYPE_ADHOC) | |
1202 | return; | |
1203 | ||
1204 | os_memset(&data, 0, sizeof(data)); | |
1205 | os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); | |
7c4027f6 | 1206 | wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data); |
159a1791 JM |
1207 | } |
1208 | ||
1209 | ||
1210 | static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, | |
4653ceb7 | 1211 | struct i802_bss *bss, |
159a1791 JM |
1212 | struct nlattr **tb) |
1213 | { | |
1214 | u8 *addr; | |
1215 | union wpa_event_data data; | |
1216 | ||
1217 | if (tb[NL80211_ATTR_MAC] == NULL) | |
1218 | return; | |
1219 | addr = nla_data(tb[NL80211_ATTR_MAC]); | |
1220 | wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, | |
1221 | MAC2STR(addr)); | |
1222 | ||
1223 | if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { | |
4653ceb7 | 1224 | drv_event_disassoc(bss->ctx, addr); |
159a1791 JM |
1225 | return; |
1226 | } | |
1227 | ||
1228 | if (drv->nlmode != NL80211_IFTYPE_ADHOC) | |
1229 | return; | |
1230 | ||
1231 | os_memset(&data, 0, sizeof(data)); | |
1232 | os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); | |
4653ceb7 | 1233 | wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data); |
159a1791 JM |
1234 | } |
1235 | ||
1236 | ||
1237 | static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, | |
1238 | struct nlattr **tb) | |
1239 | { | |
1240 | struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; | |
1241 | static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { | |
1242 | [NL80211_REKEY_DATA_KEK] = { | |
1243 | .minlen = NL80211_KEK_LEN, | |
1244 | .maxlen = NL80211_KEK_LEN, | |
1245 | }, | |
1246 | [NL80211_REKEY_DATA_KCK] = { | |
1247 | .minlen = NL80211_KCK_LEN, | |
1248 | .maxlen = NL80211_KCK_LEN, | |
1249 | }, | |
1250 | [NL80211_REKEY_DATA_REPLAY_CTR] = { | |
1251 | .minlen = NL80211_REPLAY_CTR_LEN, | |
1252 | .maxlen = NL80211_REPLAY_CTR_LEN, | |
1253 | }, | |
1254 | }; | |
1255 | union wpa_event_data data; | |
1256 | ||
dcf8fbc0 JM |
1257 | if (!tb[NL80211_ATTR_MAC] || |
1258 | !tb[NL80211_ATTR_REKEY_DATA] || | |
1259 | nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, | |
1260 | tb[NL80211_ATTR_REKEY_DATA], rekey_policy) || | |
1261 | !rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) | |
159a1791 JM |
1262 | return; |
1263 | ||
1264 | os_memset(&data, 0, sizeof(data)); | |
1265 | data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); | |
1266 | wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR, | |
1267 | MAC2STR(data.driver_gtk_rekey.bssid)); | |
1268 | data.driver_gtk_rekey.replay_ctr = | |
1269 | nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); | |
1270 | wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter", | |
1271 | data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); | |
1272 | wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); | |
1273 | } | |
1274 | ||
1275 | ||
1276 | static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv, | |
1277 | struct nlattr **tb) | |
1278 | { | |
1279 | struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; | |
1280 | static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { | |
1281 | [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, | |
1282 | [NL80211_PMKSA_CANDIDATE_BSSID] = { | |
1283 | .minlen = ETH_ALEN, | |
1284 | .maxlen = ETH_ALEN, | |
1285 | }, | |
1286 | [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, | |
1287 | }; | |
1288 | union wpa_event_data data; | |
1289 | ||
1290 | wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event"); | |
1291 | ||
dcf8fbc0 JM |
1292 | if (!tb[NL80211_ATTR_PMKSA_CANDIDATE] || |
1293 | nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, | |
1294 | tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy) || | |
1295 | !cand[NL80211_PMKSA_CANDIDATE_INDEX] || | |
159a1791 JM |
1296 | !cand[NL80211_PMKSA_CANDIDATE_BSSID]) |
1297 | return; | |
1298 | ||
1299 | os_memset(&data, 0, sizeof(data)); | |
1300 | os_memcpy(data.pmkid_candidate.bssid, | |
1301 | nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); | |
1302 | data.pmkid_candidate.index = | |
1303 | nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); | |
1304 | data.pmkid_candidate.preauth = | |
1305 | cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; | |
1306 | wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); | |
1307 | } | |
1308 | ||
1309 | ||
1310 | static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, | |
1311 | struct nlattr **tb) | |
1312 | { | |
1313 | union wpa_event_data data; | |
1314 | ||
1315 | wpa_printf(MSG_DEBUG, "nl80211: Probe client event"); | |
1316 | ||
1317 | if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) | |
1318 | return; | |
1319 | ||
1320 | os_memset(&data, 0, sizeof(data)); | |
1321 | os_memcpy(data.client_poll.addr, | |
1322 | nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); | |
1323 | ||
1324 | wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); | |
1325 | } | |
1326 | ||
1327 | ||
1328 | static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv, | |
1329 | struct nlattr **tb) | |
1330 | { | |
1331 | union wpa_event_data data; | |
1332 | ||
1333 | wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event"); | |
1334 | ||
1335 | if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION]) | |
1336 | return; | |
1337 | ||
1338 | os_memset(&data, 0, sizeof(data)); | |
1339 | os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); | |
1340 | switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) { | |
1341 | case NL80211_TDLS_SETUP: | |
1342 | wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer " | |
1343 | MACSTR, MAC2STR(data.tdls.peer)); | |
1344 | data.tdls.oper = TDLS_REQUEST_SETUP; | |
1345 | break; | |
1346 | case NL80211_TDLS_TEARDOWN: | |
1347 | wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer " | |
1348 | MACSTR, MAC2STR(data.tdls.peer)); | |
1349 | data.tdls.oper = TDLS_REQUEST_TEARDOWN; | |
1350 | break; | |
3f0e6ec4 SD |
1351 | case NL80211_TDLS_DISCOVERY_REQ: |
1352 | wpa_printf(MSG_DEBUG, | |
1353 | "nl80211: TDLS discovery request for peer " MACSTR, | |
1354 | MAC2STR(data.tdls.peer)); | |
1355 | data.tdls.oper = TDLS_REQUEST_DISCOVER; | |
1356 | break; | |
159a1791 JM |
1357 | default: |
1358 | wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione " | |
1359 | "event"); | |
1360 | return; | |
1361 | } | |
1362 | if (tb[NL80211_ATTR_REASON_CODE]) { | |
1363 | data.tdls.reason_code = | |
1364 | nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); | |
1365 | } | |
1366 | ||
1367 | wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data); | |
1368 | } | |
1369 | ||
1370 | ||
1371 | static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv, | |
1372 | struct nlattr **tb) | |
1373 | { | |
1374 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL); | |
1375 | } | |
1376 | ||
1377 | ||
1378 | static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv, | |
1379 | struct nlattr **tb) | |
1380 | { | |
1381 | union wpa_event_data data; | |
1382 | u32 reason; | |
1383 | ||
1384 | wpa_printf(MSG_DEBUG, "nl80211: Connect failed event"); | |
1385 | ||
1386 | if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON]) | |
1387 | return; | |
1388 | ||
1389 | os_memset(&data, 0, sizeof(data)); | |
1390 | os_memcpy(data.connect_failed_reason.addr, | |
1391 | nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); | |
1392 | ||
1393 | reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]); | |
1394 | switch (reason) { | |
1395 | case NL80211_CONN_FAIL_MAX_CLIENTS: | |
1396 | wpa_printf(MSG_DEBUG, "nl80211: Max client reached"); | |
1397 | data.connect_failed_reason.code = MAX_CLIENT_REACHED; | |
1398 | break; | |
1399 | case NL80211_CONN_FAIL_BLOCKED_CLIENT: | |
1400 | wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR | |
1401 | " tried to connect", | |
1402 | MAC2STR(data.connect_failed_reason.addr)); | |
1403 | data.connect_failed_reason.code = BLOCKED_CLIENT; | |
1404 | break; | |
1405 | default: | |
1406 | wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason " | |
1407 | "%u", reason); | |
1408 | return; | |
1409 | } | |
1410 | ||
1411 | wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data); | |
1412 | } | |
1413 | ||
1414 | ||
1415 | static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, | |
1416 | struct nlattr **tb) | |
1417 | { | |
1418 | union wpa_event_data data; | |
1419 | enum nl80211_radar_event event_type; | |
1420 | ||
1421 | if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT]) | |
1422 | return; | |
1423 | ||
1424 | os_memset(&data, 0, sizeof(data)); | |
1425 | data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); | |
1426 | event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); | |
1427 | ||
1428 | /* Check HT params */ | |
1429 | if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | |
1430 | data.dfs_event.ht_enabled = 1; | |
1431 | data.dfs_event.chan_offset = 0; | |
1432 | ||
1433 | switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { | |
1434 | case NL80211_CHAN_NO_HT: | |
1435 | data.dfs_event.ht_enabled = 0; | |
1436 | break; | |
1437 | case NL80211_CHAN_HT20: | |
1438 | break; | |
1439 | case NL80211_CHAN_HT40PLUS: | |
1440 | data.dfs_event.chan_offset = 1; | |
1441 | break; | |
1442 | case NL80211_CHAN_HT40MINUS: | |
1443 | data.dfs_event.chan_offset = -1; | |
1444 | break; | |
1445 | } | |
1446 | } | |
1447 | ||
1448 | /* Get VHT params */ | |
1449 | if (tb[NL80211_ATTR_CHANNEL_WIDTH]) | |
1450 | data.dfs_event.chan_width = | |
1451 | convert2width(nla_get_u32( | |
1452 | tb[NL80211_ATTR_CHANNEL_WIDTH])); | |
1453 | if (tb[NL80211_ATTR_CENTER_FREQ1]) | |
1454 | data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); | |
1455 | if (tb[NL80211_ATTR_CENTER_FREQ2]) | |
1456 | data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); | |
1457 | ||
1458 | wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", | |
1459 | data.dfs_event.freq, data.dfs_event.ht_enabled, | |
1460 | data.dfs_event.chan_offset, data.dfs_event.chan_width, | |
1461 | data.dfs_event.cf1, data.dfs_event.cf2); | |
1462 | ||
1463 | switch (event_type) { | |
1464 | case NL80211_RADAR_DETECTED: | |
1465 | wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); | |
1466 | break; | |
1467 | case NL80211_RADAR_CAC_FINISHED: | |
1468 | wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); | |
1469 | break; | |
1470 | case NL80211_RADAR_CAC_ABORTED: | |
1471 | wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); | |
1472 | break; | |
1473 | case NL80211_RADAR_NOP_FINISHED: | |
1474 | wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); | |
1475 | break; | |
1476 | default: | |
1477 | wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d " | |
1478 | "received", event_type); | |
1479 | break; | |
1480 | } | |
1481 | } | |
1482 | ||
1483 | ||
1484 | static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, | |
1485 | int wds) | |
1486 | { | |
1487 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
1488 | union wpa_event_data event; | |
1489 | ||
1490 | if (!tb[NL80211_ATTR_MAC]) | |
1491 | return; | |
1492 | ||
1493 | os_memset(&event, 0, sizeof(event)); | |
1494 | event.rx_from_unknown.bssid = bss->addr; | |
1495 | event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); | |
1496 | event.rx_from_unknown.wds = wds; | |
1497 | ||
1498 | wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); | |
1499 | } | |
1500 | ||
1501 | ||
b658547d JM |
1502 | #ifdef CONFIG_DRIVER_NL80211_QCA |
1503 | ||
159a1791 JM |
1504 | static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, |
1505 | const u8 *data, size_t len) | |
1506 | { | |
1507 | u32 i, count; | |
1508 | union wpa_event_data event; | |
1509 | struct wpa_freq_range *range = NULL; | |
1510 | const struct qca_avoid_freq_list *freq_range; | |
1511 | ||
1512 | freq_range = (const struct qca_avoid_freq_list *) data; | |
1513 | if (len < sizeof(freq_range->count)) | |
1514 | return; | |
1515 | ||
1516 | count = freq_range->count; | |
1517 | if (len < sizeof(freq_range->count) + | |
1518 | count * sizeof(struct qca_avoid_freq_range)) { | |
1519 | wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)", | |
1520 | (unsigned int) len); | |
1521 | return; | |
1522 | } | |
1523 | ||
1524 | if (count > 0) { | |
1525 | range = os_calloc(count, sizeof(struct wpa_freq_range)); | |
1526 | if (range == NULL) | |
1527 | return; | |
1528 | } | |
1529 | ||
1530 | os_memset(&event, 0, sizeof(event)); | |
1531 | for (i = 0; i < count; i++) { | |
1532 | unsigned int idx = event.freq_range.num; | |
1533 | range[idx].min = freq_range->range[i].start_freq; | |
1534 | range[idx].max = freq_range->range[i].end_freq; | |
1535 | wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u", | |
1536 | range[idx].min, range[idx].max); | |
1537 | if (range[idx].min > range[idx].max) { | |
1538 | wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range"); | |
1539 | continue; | |
1540 | } | |
1541 | event.freq_range.num++; | |
1542 | } | |
1543 | event.freq_range.range = range; | |
1544 | ||
1545 | wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event); | |
1546 | ||
1547 | os_free(range); | |
1548 | } | |
1549 | ||
1550 | ||
3784c058 PX |
1551 | static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode) |
1552 | { | |
1553 | switch (hw_mode) { | |
1554 | case QCA_ACS_MODE_IEEE80211B: | |
1555 | return HOSTAPD_MODE_IEEE80211B; | |
1556 | case QCA_ACS_MODE_IEEE80211G: | |
1557 | return HOSTAPD_MODE_IEEE80211G; | |
1558 | case QCA_ACS_MODE_IEEE80211A: | |
1559 | return HOSTAPD_MODE_IEEE80211A; | |
1560 | case QCA_ACS_MODE_IEEE80211AD: | |
1561 | return HOSTAPD_MODE_IEEE80211AD; | |
1562 | case QCA_ACS_MODE_IEEE80211ANY: | |
1563 | return HOSTAPD_MODE_IEEE80211ANY; | |
1564 | default: | |
1565 | return NUM_HOSTAPD_MODES; | |
1566 | } | |
1567 | } | |
1568 | ||
1569 | ||
16689c7c PX |
1570 | static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, |
1571 | const u8 *data, size_t len) | |
1572 | { | |
1573 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; | |
1574 | union wpa_event_data event; | |
1575 | ||
1576 | wpa_printf(MSG_DEBUG, | |
1577 | "nl80211: ACS channel selection vendor event received"); | |
1578 | ||
1579 | if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, | |
dcf8fbc0 JM |
1580 | (struct nlattr *) data, len, NULL) || |
1581 | !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] || | |
16689c7c PX |
1582 | !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]) |
1583 | return; | |
1584 | ||
1585 | os_memset(&event, 0, sizeof(event)); | |
1586 | event.acs_selected_channels.pri_channel = | |
1587 | nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]); | |
1588 | event.acs_selected_channels.sec_channel = | |
1589 | nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]); | |
857d9422 MM |
1590 | if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) |
1591 | event.acs_selected_channels.vht_seg0_center_ch = | |
1592 | nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]); | |
1593 | if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) | |
1594 | event.acs_selected_channels.vht_seg1_center_ch = | |
1595 | nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]); | |
1596 | if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) | |
1597 | event.acs_selected_channels.ch_width = | |
1598 | nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); | |
3784c058 PX |
1599 | if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { |
1600 | u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); | |
1601 | ||
1602 | event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode); | |
1603 | if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES || | |
1604 | event.acs_selected_channels.hw_mode == | |
1605 | HOSTAPD_MODE_IEEE80211ANY) { | |
1606 | wpa_printf(MSG_DEBUG, | |
1607 | "nl80211: Invalid hw_mode %d in ACS selection event", | |
1608 | hw_mode); | |
1609 | return; | |
1610 | } | |
1611 | } | |
857d9422 MM |
1612 | |
1613 | wpa_printf(MSG_INFO, | |
3784c058 | 1614 | "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d", |
857d9422 MM |
1615 | event.acs_selected_channels.pri_channel, |
1616 | event.acs_selected_channels.sec_channel, | |
1617 | event.acs_selected_channels.ch_width, | |
1618 | event.acs_selected_channels.vht_seg0_center_ch, | |
3784c058 PX |
1619 | event.acs_selected_channels.vht_seg1_center_ch, |
1620 | event.acs_selected_channels.hw_mode); | |
857d9422 MM |
1621 | |
1622 | /* Ignore ACS channel list check for backwards compatibility */ | |
16689c7c PX |
1623 | |
1624 | wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event); | |
1625 | } | |
1626 | ||
1627 | ||
159a1791 JM |
1628 | static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, |
1629 | const u8 *data, size_t len) | |
1630 | { | |
1631 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1]; | |
1632 | u8 *bssid; | |
1633 | ||
1634 | wpa_printf(MSG_DEBUG, | |
1635 | "nl80211: Key management roam+auth vendor event received"); | |
1636 | ||
1637 | if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX, | |
dcf8fbc0 JM |
1638 | (struct nlattr *) data, len, NULL) || |
1639 | !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] || | |
159a1791 JM |
1640 | nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN || |
1641 | !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] || | |
1642 | !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] || | |
1643 | !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED]) | |
1644 | return; | |
1645 | ||
1646 | bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); | |
1647 | wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid)); | |
1648 | ||
1649 | mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, | |
1650 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], | |
1651 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], | |
1652 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], | |
9a5160f5 | 1653 | NULL, |
159a1791 JM |
1654 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED], |
1655 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR], | |
1656 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK], | |
f32227ed RJ |
1657 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK], |
1658 | tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS]); | |
159a1791 JM |
1659 | } |
1660 | ||
1661 | ||
02e42ab7 AK |
1662 | static void qca_nl80211_dfs_offload_radar_event( |
1663 | struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length) | |
1664 | { | |
1665 | union wpa_event_data data; | |
1666 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
1667 | ||
1668 | wpa_printf(MSG_DEBUG, | |
1669 | "nl80211: DFS offload radar vendor event received"); | |
1670 | ||
1671 | if (nla_parse(tb, NL80211_ATTR_MAX, | |
1672 | (struct nlattr *) msg, length, NULL)) | |
1673 | return; | |
1674 | ||
1675 | if (!tb[NL80211_ATTR_WIPHY_FREQ]) { | |
1676 | wpa_printf(MSG_INFO, | |
1677 | "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event"); | |
1678 | return; | |
1679 | } | |
1680 | ||
1681 | os_memset(&data, 0, sizeof(data)); | |
1682 | data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); | |
1683 | ||
1684 | wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz", | |
1685 | data.dfs_event.freq); | |
1686 | ||
1687 | /* Check HT params */ | |
1688 | if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | |
1689 | data.dfs_event.ht_enabled = 1; | |
1690 | data.dfs_event.chan_offset = 0; | |
1691 | ||
1692 | switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { | |
1693 | case NL80211_CHAN_NO_HT: | |
1694 | data.dfs_event.ht_enabled = 0; | |
1695 | break; | |
1696 | case NL80211_CHAN_HT20: | |
1697 | break; | |
1698 | case NL80211_CHAN_HT40PLUS: | |
1699 | data.dfs_event.chan_offset = 1; | |
1700 | break; | |
1701 | case NL80211_CHAN_HT40MINUS: | |
1702 | data.dfs_event.chan_offset = -1; | |
1703 | break; | |
1704 | } | |
1705 | } | |
1706 | ||
1707 | /* Get VHT params */ | |
1708 | if (tb[NL80211_ATTR_CHANNEL_WIDTH]) | |
1709 | data.dfs_event.chan_width = | |
1710 | convert2width(nla_get_u32( | |
1711 | tb[NL80211_ATTR_CHANNEL_WIDTH])); | |
1712 | if (tb[NL80211_ATTR_CENTER_FREQ1]) | |
1713 | data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); | |
1714 | if (tb[NL80211_ATTR_CENTER_FREQ2]) | |
1715 | data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); | |
1716 | ||
1717 | wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, " | |
1718 | "offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", | |
1719 | data.dfs_event.freq, data.dfs_event.ht_enabled, | |
1720 | data.dfs_event.chan_offset, data.dfs_event.chan_width, | |
1721 | data.dfs_event.cf1, data.dfs_event.cf2); | |
1722 | ||
1723 | switch (subcmd) { | |
1724 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: | |
1725 | wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); | |
1726 | break; | |
1727 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: | |
1728 | wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data); | |
1729 | break; | |
1730 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: | |
1731 | wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); | |
1732 | break; | |
1733 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: | |
1734 | wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); | |
1735 | break; | |
1736 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: | |
1737 | wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); | |
1738 | break; | |
1739 | default: | |
1740 | wpa_printf(MSG_DEBUG, | |
1741 | "nl80211: Unknown DFS offload radar event %d received", | |
1742 | subcmd); | |
1743 | break; | |
1744 | } | |
1745 | } | |
1746 | ||
1747 | ||
f22a080c KV |
1748 | static void qca_nl80211_scan_trigger_event(struct wpa_driver_nl80211_data *drv, |
1749 | u8 *data, size_t len) | |
1750 | { | |
1751 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; | |
1752 | u64 cookie = 0; | |
adcd7c4b KV |
1753 | union wpa_event_data event; |
1754 | struct scan_info *info; | |
f22a080c KV |
1755 | |
1756 | if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, | |
1757 | (struct nlattr *) data, len, NULL) || | |
1758 | !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) | |
1759 | return; | |
1760 | ||
1761 | cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); | |
1762 | if (cookie != drv->vendor_scan_cookie) { | |
1763 | /* External scan trigger event, ignore */ | |
1764 | return; | |
1765 | } | |
1766 | ||
adcd7c4b KV |
1767 | /* Cookie match, own scan */ |
1768 | os_memset(&event, 0, sizeof(event)); | |
1769 | info = &event.scan_info; | |
1770 | info->external_scan = 0; | |
1771 | info->nl_scan_event = 0; | |
1772 | ||
f22a080c | 1773 | drv->scan_state = SCAN_STARTED; |
adcd7c4b | 1774 | wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, &event); |
f22a080c KV |
1775 | } |
1776 | ||
1777 | ||
1778 | static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv, | |
adcd7c4b KV |
1779 | int aborted, struct nlattr *tb[], |
1780 | int external_scan) | |
f22a080c KV |
1781 | { |
1782 | union wpa_event_data event; | |
1783 | struct nlattr *nl; | |
1784 | int rem; | |
1785 | struct scan_info *info; | |
1786 | int freqs[MAX_REPORT_FREQS]; | |
1787 | int num_freqs = 0; | |
1788 | ||
1789 | os_memset(&event, 0, sizeof(event)); | |
1790 | info = &event.scan_info; | |
1791 | info->aborted = aborted; | |
adcd7c4b | 1792 | info->external_scan = external_scan; |
f22a080c KV |
1793 | |
1794 | if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { | |
1795 | nla_for_each_nested(nl, | |
1796 | tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], rem) { | |
1797 | struct wpa_driver_scan_ssid *s = | |
1798 | &info->ssids[info->num_ssids]; | |
1799 | s->ssid = nla_data(nl); | |
1800 | s->ssid_len = nla_len(nl); | |
1801 | wpa_printf(MSG_DEBUG, | |
1802 | "nl80211: Scan probed for SSID '%s'", | |
1803 | wpa_ssid_txt(s->ssid, s->ssid_len)); | |
1804 | info->num_ssids++; | |
1805 | if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) | |
1806 | break; | |
1807 | } | |
1808 | } | |
1809 | ||
1810 | if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { | |
712525b0 | 1811 | char msg[300], *pos, *end; |
f22a080c KV |
1812 | int res; |
1813 | ||
1814 | pos = msg; | |
1815 | end = pos + sizeof(msg); | |
1816 | *pos = '\0'; | |
1817 | ||
1818 | nla_for_each_nested(nl, | |
1819 | tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], | |
1820 | rem) { | |
1821 | freqs[num_freqs] = nla_get_u32(nl); | |
1822 | res = os_snprintf(pos, end - pos, " %d", | |
1823 | freqs[num_freqs]); | |
1824 | if (!os_snprintf_error(end - pos, res)) | |
1825 | pos += res; | |
1826 | num_freqs++; | |
1827 | if (num_freqs == MAX_REPORT_FREQS - 1) | |
1828 | break; | |
1829 | } | |
1830 | ||
1831 | info->freqs = freqs; | |
1832 | info->num_freqs = num_freqs; | |
1833 | wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", | |
1834 | msg); | |
1835 | } | |
1836 | wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); | |
1837 | } | |
1838 | ||
1839 | ||
1840 | static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv, | |
1841 | u8 *data, size_t len) | |
1842 | { | |
1843 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; | |
1844 | u64 cookie = 0; | |
1845 | enum scan_status status; | |
adcd7c4b | 1846 | int external_scan; |
f22a080c KV |
1847 | |
1848 | if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, | |
1849 | (struct nlattr *) data, len, NULL) || | |
1850 | !tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS] || | |
1851 | !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) | |
1852 | return; | |
1853 | ||
1854 | status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS]); | |
1855 | if (status >= VENDOR_SCAN_STATUS_MAX) | |
1856 | return; /* invalid status */ | |
1857 | ||
1858 | cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); | |
1859 | if (cookie != drv->vendor_scan_cookie) { | |
1860 | /* Event from an external scan, get scan results */ | |
adcd7c4b | 1861 | external_scan = 1; |
f22a080c | 1862 | } else { |
adcd7c4b | 1863 | external_scan = 0; |
f22a080c KV |
1864 | if (status == VENDOR_SCAN_STATUS_NEW_RESULTS) |
1865 | drv->scan_state = SCAN_COMPLETED; | |
1866 | else | |
1867 | drv->scan_state = SCAN_ABORTED; | |
1868 | ||
1869 | eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, | |
1870 | drv->ctx); | |
1871 | drv->vendor_scan_cookie = 0; | |
adcd7c4b | 1872 | drv->last_scan_cmd = 0; |
f22a080c KV |
1873 | } |
1874 | ||
adcd7c4b KV |
1875 | send_vendor_scan_event(drv, (status == VENDOR_SCAN_STATUS_ABORTED), tb, |
1876 | external_scan); | |
f22a080c KV |
1877 | } |
1878 | ||
a6f5b193 PX |
1879 | |
1880 | static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv, | |
1881 | u8 *data, size_t len) | |
1882 | { | |
1883 | struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; | |
1884 | union wpa_event_data event; | |
1885 | ||
1886 | wpa_printf(MSG_DEBUG, | |
1887 | "nl80211: P2P listen offload stop vendor event received"); | |
1888 | ||
1889 | if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, | |
1890 | (struct nlattr *) data, len, NULL) || | |
1891 | !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]) | |
1892 | return; | |
1893 | ||
1894 | os_memset(&event, 0, sizeof(event)); | |
1895 | event.p2p_lo_stop.reason_code = | |
1896 | nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]); | |
1897 | ||
1898 | wpa_printf(MSG_DEBUG, | |
1899 | "nl80211: P2P Listen offload stop reason: %d", | |
1900 | event.p2p_lo_stop.reason_code); | |
1901 | wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event); | |
1902 | } | |
1903 | ||
b658547d JM |
1904 | #endif /* CONFIG_DRIVER_NL80211_QCA */ |
1905 | ||
f22a080c | 1906 | |
159a1791 JM |
1907 | static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, |
1908 | u32 subcmd, u8 *data, size_t len) | |
1909 | { | |
1910 | switch (subcmd) { | |
1db718b3 JM |
1911 | case QCA_NL80211_VENDOR_SUBCMD_TEST: |
1912 | wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len); | |
1913 | break; | |
b658547d | 1914 | #ifdef CONFIG_DRIVER_NL80211_QCA |
159a1791 JM |
1915 | case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: |
1916 | qca_nl80211_avoid_freq(drv, data, len); | |
1917 | break; | |
1918 | case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: | |
1919 | qca_nl80211_key_mgmt_auth(drv, data, len); | |
1920 | break; | |
16689c7c PX |
1921 | case QCA_NL80211_VENDOR_SUBCMD_DO_ACS: |
1922 | qca_nl80211_acs_select_ch(drv, data, len); | |
1923 | break; | |
02e42ab7 AK |
1924 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: |
1925 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: | |
1926 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: | |
1927 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: | |
1928 | case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: | |
1929 | qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len); | |
1930 | break; | |
f22a080c KV |
1931 | case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: |
1932 | qca_nl80211_scan_trigger_event(drv, data, len); | |
1933 | break; | |
1934 | case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: | |
1935 | qca_nl80211_scan_done_event(drv, data, len); | |
1936 | break; | |
a6f5b193 PX |
1937 | case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: |
1938 | qca_nl80211_p2p_lo_stop_event(drv, data, len); | |
1939 | break; | |
b658547d | 1940 | #endif /* CONFIG_DRIVER_NL80211_QCA */ |
159a1791 JM |
1941 | default: |
1942 | wpa_printf(MSG_DEBUG, | |
1943 | "nl80211: Ignore unsupported QCA vendor event %u", | |
1944 | subcmd); | |
1945 | break; | |
1946 | } | |
1947 | } | |
1948 | ||
1949 | ||
1950 | static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, | |
1951 | struct nlattr **tb) | |
1952 | { | |
1953 | u32 vendor_id, subcmd, wiphy = 0; | |
1954 | int wiphy_idx; | |
1955 | u8 *data = NULL; | |
1956 | size_t len = 0; | |
1957 | ||
1958 | if (!tb[NL80211_ATTR_VENDOR_ID] || | |
1959 | !tb[NL80211_ATTR_VENDOR_SUBCMD]) | |
1960 | return; | |
1961 | ||
1962 | vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); | |
1963 | subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); | |
1964 | ||
1965 | if (tb[NL80211_ATTR_WIPHY]) | |
1966 | wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | |
1967 | ||
1968 | wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", | |
1969 | wiphy, vendor_id, subcmd); | |
1970 | ||
1971 | if (tb[NL80211_ATTR_VENDOR_DATA]) { | |
1972 | data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); | |
1973 | len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); | |
1974 | wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); | |
1975 | } | |
1976 | ||
1977 | wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); | |
1978 | if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { | |
1979 | wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", | |
1980 | wiphy, wiphy_idx); | |
1981 | return; | |
1982 | } | |
1983 | ||
1984 | switch (vendor_id) { | |
1985 | case OUI_QCA: | |
1986 | nl80211_vendor_event_qca(drv, subcmd, data, len); | |
1987 | break; | |
1988 | default: | |
1989 | wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); | |
1990 | break; | |
1991 | } | |
1992 | } | |
1993 | ||
1994 | ||
1995 | static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv, | |
1996 | struct nlattr *tb[]) | |
1997 | { | |
1998 | union wpa_event_data data; | |
1999 | enum nl80211_reg_initiator init; | |
2000 | ||
2001 | wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change"); | |
2002 | ||
2003 | if (tb[NL80211_ATTR_REG_INITIATOR] == NULL) | |
2004 | return; | |
2005 | ||
2006 | os_memset(&data, 0, sizeof(data)); | |
2007 | init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]); | |
2008 | wpa_printf(MSG_DEBUG, " * initiator=%d", init); | |
2009 | switch (init) { | |
2010 | case NL80211_REGDOM_SET_BY_CORE: | |
2011 | data.channel_list_changed.initiator = REGDOM_SET_BY_CORE; | |
2012 | break; | |
2013 | case NL80211_REGDOM_SET_BY_USER: | |
2014 | data.channel_list_changed.initiator = REGDOM_SET_BY_USER; | |
2015 | break; | |
2016 | case NL80211_REGDOM_SET_BY_DRIVER: | |
2017 | data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER; | |
2018 | break; | |
2019 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | |
2020 | data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE; | |
2021 | break; | |
2022 | } | |
2023 | ||
2024 | if (tb[NL80211_ATTR_REG_TYPE]) { | |
2025 | enum nl80211_reg_type type; | |
2026 | type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); | |
2027 | wpa_printf(MSG_DEBUG, " * type=%d", type); | |
2028 | switch (type) { | |
2029 | case NL80211_REGDOM_TYPE_COUNTRY: | |
2030 | data.channel_list_changed.type = REGDOM_TYPE_COUNTRY; | |
2031 | break; | |
2032 | case NL80211_REGDOM_TYPE_WORLD: | |
2033 | data.channel_list_changed.type = REGDOM_TYPE_WORLD; | |
2034 | break; | |
2035 | case NL80211_REGDOM_TYPE_CUSTOM_WORLD: | |
2036 | data.channel_list_changed.type = | |
2037 | REGDOM_TYPE_CUSTOM_WORLD; | |
2038 | break; | |
2039 | case NL80211_REGDOM_TYPE_INTERSECTION: | |
2040 | data.channel_list_changed.type = | |
2041 | REGDOM_TYPE_INTERSECTION; | |
2042 | break; | |
2043 | } | |
2044 | } | |
2045 | ||
2046 | if (tb[NL80211_ATTR_REG_ALPHA2]) { | |
2047 | os_strlcpy(data.channel_list_changed.alpha2, | |
2048 | nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), | |
2049 | sizeof(data.channel_list_changed.alpha2)); | |
2050 | wpa_printf(MSG_DEBUG, " * alpha2=%s", | |
2051 | data.channel_list_changed.alpha2); | |
2052 | } | |
2053 | ||
2054 | wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data); | |
2055 | } | |
2056 | ||
2057 | ||
2058 | static void do_process_drv_event(struct i802_bss *bss, int cmd, | |
2059 | struct nlattr **tb) | |
2060 | { | |
2061 | struct wpa_driver_nl80211_data *drv = bss->drv; | |
2062 | union wpa_event_data data; | |
adcd7c4b | 2063 | int external_scan_event = 0; |
159a1791 JM |
2064 | |
2065 | wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", | |
2066 | cmd, nl80211_command_to_string(cmd), bss->ifname); | |
2067 | ||
15badebd CL |
2068 | if (cmd == NL80211_CMD_ROAM && |
2069 | (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) { | |
159a1791 JM |
2070 | /* |
2071 | * Device will use roam+auth vendor event to indicate | |
2072 | * roaming, so ignore the regular roam event. | |
2073 | */ | |
2074 | wpa_printf(MSG_DEBUG, | |
2075 | "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth", | |
2076 | cmd); | |
2077 | return; | |
2078 | } | |
2079 | ||
2080 | if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && | |
2081 | (cmd == NL80211_CMD_NEW_SCAN_RESULTS || | |
2082 | cmd == NL80211_CMD_SCAN_ABORTED)) { | |
2083 | wpa_driver_nl80211_set_mode(drv->first_bss, | |
2084 | drv->ap_scan_as_station); | |
2085 | drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; | |
2086 | } | |
2087 | ||
2088 | switch (cmd) { | |
2089 | case NL80211_CMD_TRIGGER_SCAN: | |
2090 | wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); | |
2091 | drv->scan_state = SCAN_STARTED; | |
2092 | if (drv->scan_for_auth) { | |
2093 | /* | |
2094 | * Cannot indicate EVENT_SCAN_STARTED here since we skip | |
2095 | * EVENT_SCAN_RESULTS in scan_for_auth case and the | |
2096 | * upper layer implementation could get confused about | |
2097 | * scanning state. | |
2098 | */ | |
2099 | wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth"); | |
2100 | break; | |
2101 | } | |
2102 | wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); | |
2103 | break; | |
2104 | case NL80211_CMD_START_SCHED_SCAN: | |
2105 | wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); | |
2106 | drv->scan_state = SCHED_SCAN_STARTED; | |
2107 | break; | |
2108 | case NL80211_CMD_SCHED_SCAN_STOPPED: | |
2109 | wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped"); | |
2110 | drv->scan_state = SCHED_SCAN_STOPPED; | |
2111 | wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); | |
2112 | break; | |
2113 | case NL80211_CMD_NEW_SCAN_RESULTS: | |
2114 | wpa_dbg(drv->ctx, MSG_DEBUG, | |
2115 | "nl80211: New scan results available"); | |
159a1791 | 2116 | drv->scan_complete_events = 1; |
adcd7c4b KV |
2117 | if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) { |
2118 | drv->scan_state = SCAN_COMPLETED; | |
2119 | eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, | |
2120 | drv, drv->ctx); | |
2121 | drv->last_scan_cmd = 0; | |
2122 | } else { | |
2123 | external_scan_event = 1; | |
2124 | } | |
2125 | send_scan_event(drv, 0, tb, external_scan_event); | |
159a1791 JM |
2126 | break; |
2127 | case NL80211_CMD_SCHED_SCAN_RESULTS: | |
2128 | wpa_dbg(drv->ctx, MSG_DEBUG, | |
2129 | "nl80211: New sched scan results available"); | |
2130 | drv->scan_state = SCHED_SCAN_RESULTS; | |
adcd7c4b | 2131 | send_scan_event(drv, 0, tb, 0); |
159a1791 JM |
2132 | break; |
2133 | case NL80211_CMD_SCAN_ABORTED: | |
2134 | wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted"); | |
adcd7c4b KV |
2135 | if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) { |
2136 | drv->scan_state = SCAN_ABORTED; | |
2137 | /* | |
2138 | * Need to indicate that scan results are available in | |
2139 | * order not to make wpa_supplicant stop its scanning. | |
2140 | */ | |
2141 | eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, | |
2142 | drv, drv->ctx); | |
2143 | drv->last_scan_cmd = 0; | |
2144 | } else { | |
2145 | external_scan_event = 1; | |
2146 | } | |
2147 | send_scan_event(drv, 1, tb, external_scan_event); | |
159a1791 JM |
2148 | break; |
2149 | case NL80211_CMD_AUTHENTICATE: | |
2150 | case NL80211_CMD_ASSOCIATE: | |
2151 | case NL80211_CMD_DEAUTHENTICATE: | |
2152 | case NL80211_CMD_DISASSOCIATE: | |
2153 | case NL80211_CMD_FRAME_TX_STATUS: | |
2154 | case NL80211_CMD_UNPROT_DEAUTHENTICATE: | |
2155 | case NL80211_CMD_UNPROT_DISASSOCIATE: | |
2156 | mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME], | |
2157 | tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], | |
2158 | tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], | |
2159 | tb[NL80211_ATTR_COOKIE], | |
7e0e1069 EP |
2160 | tb[NL80211_ATTR_RX_SIGNAL_DBM], |
2161 | tb[NL80211_ATTR_STA_WME]); | |
159a1791 JM |
2162 | break; |
2163 | case NL80211_CMD_CONNECT: | |
2164 | case NL80211_CMD_ROAM: | |
2165 | mlme_event_connect(drv, cmd, | |
2166 | tb[NL80211_ATTR_STATUS_CODE], | |
2167 | tb[NL80211_ATTR_MAC], | |
2168 | tb[NL80211_ATTR_REQ_IE], | |
2169 | tb[NL80211_ATTR_RESP_IE], | |
9a5160f5 | 2170 | tb[NL80211_ATTR_TIMED_OUT], |
f32227ed | 2171 | NULL, NULL, NULL, NULL, NULL); |
159a1791 JM |
2172 | break; |
2173 | case NL80211_CMD_CH_SWITCH_NOTIFY: | |
2174 | mlme_event_ch_switch(drv, | |
2175 | tb[NL80211_ATTR_IFINDEX], | |
2176 | tb[NL80211_ATTR_WIPHY_FREQ], | |
2177 | tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], | |
2178 | tb[NL80211_ATTR_CHANNEL_WIDTH], | |
2179 | tb[NL80211_ATTR_CENTER_FREQ1], | |
2180 | tb[NL80211_ATTR_CENTER_FREQ2]); | |
2181 | break; | |
2182 | case NL80211_CMD_DISCONNECT: | |
2183 | mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], | |
2184 | tb[NL80211_ATTR_MAC], | |
2185 | tb[NL80211_ATTR_DISCONNECTED_BY_AP]); | |
2186 | break; | |
2187 | case NL80211_CMD_MICHAEL_MIC_FAILURE: | |
2188 | mlme_event_michael_mic_failure(bss, tb); | |
2189 | break; | |
2190 | case NL80211_CMD_JOIN_IBSS: | |
2191 | mlme_event_join_ibss(drv, tb); | |
2192 | break; | |
2193 | case NL80211_CMD_REMAIN_ON_CHANNEL: | |
2194 | mlme_event_remain_on_channel(drv, 0, tb); | |
2195 | break; | |
2196 | case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: | |
2197 | mlme_event_remain_on_channel(drv, 1, tb); | |
2198 | break; | |
2199 | case NL80211_CMD_NOTIFY_CQM: | |
2200 | nl80211_cqm_event(drv, tb); | |
2201 | break; | |
2202 | case NL80211_CMD_REG_CHANGE: | |
2203 | nl80211_reg_change_event(drv, tb); | |
2204 | break; | |
2205 | case NL80211_CMD_REG_BEACON_HINT: | |
2206 | wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint"); | |
2207 | os_memset(&data, 0, sizeof(data)); | |
2208 | data.channel_list_changed.initiator = REGDOM_BEACON_HINT; | |
2209 | wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, | |
2210 | &data); | |
2211 | break; | |
2212 | case NL80211_CMD_NEW_STATION: | |
7c4027f6 | 2213 | nl80211_new_station_event(drv, bss, tb); |
159a1791 JM |
2214 | break; |
2215 | case NL80211_CMD_DEL_STATION: | |
4653ceb7 | 2216 | nl80211_del_station_event(drv, bss, tb); |
159a1791 JM |
2217 | break; |
2218 | case NL80211_CMD_SET_REKEY_OFFLOAD: | |
2219 | nl80211_rekey_offload_event(drv, tb); | |
2220 | break; | |
2221 | case NL80211_CMD_PMKSA_CANDIDATE: | |
2222 | nl80211_pmksa_candidate_event(drv, tb); | |
2223 | break; | |
2224 | case NL80211_CMD_PROBE_CLIENT: | |
2225 | nl80211_client_probe_event(drv, tb); | |
2226 | break; | |
2227 | case NL80211_CMD_TDLS_OPER: | |
2228 | nl80211_tdls_oper_event(drv, tb); | |
2229 | break; | |
2230 | case NL80211_CMD_CONN_FAILED: | |
2231 | nl80211_connect_failed_event(drv, tb); | |
2232 | break; | |
2233 | case NL80211_CMD_FT_EVENT: | |
2234 | mlme_event_ft_event(drv, tb); | |
2235 | break; | |
2236 | case NL80211_CMD_RADAR_DETECT: | |
2237 | nl80211_radar_event(drv, tb); | |
2238 | break; | |
2239 | case NL80211_CMD_STOP_AP: | |
2240 | nl80211_stop_ap(drv, tb); | |
2241 | break; | |
2242 | case NL80211_CMD_VENDOR: | |
2243 | nl80211_vendor_event(drv, tb); | |
2244 | break; | |
2245 | case NL80211_CMD_NEW_PEER_CANDIDATE: | |
2246 | nl80211_new_peer_candidate(drv, tb); | |
2247 | break; | |
2248 | default: | |
2249 | wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " | |
2250 | "(cmd=%d)", cmd); | |
2251 | break; | |
2252 | } | |
2253 | } | |
2254 | ||
2255 | ||
159a1791 JM |
2256 | int process_global_event(struct nl_msg *msg, void *arg) |
2257 | { | |
2258 | struct nl80211_global *global = arg; | |
2259 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
2260 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
2261 | struct wpa_driver_nl80211_data *drv, *tmp; | |
2262 | int ifidx = -1; | |
2263 | struct i802_bss *bss; | |
2264 | u64 wdev_id = 0; | |
2265 | int wdev_id_set = 0; | |
2266 | ||
2267 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
2268 | genlmsg_attrlen(gnlh, 0), NULL); | |
2269 | ||
2270 | if (tb[NL80211_ATTR_IFINDEX]) | |
2271 | ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | |
2272 | else if (tb[NL80211_ATTR_WDEV]) { | |
2273 | wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); | |
2274 | wdev_id_set = 1; | |
2275 | } | |
2276 | ||
2277 | dl_list_for_each_safe(drv, tmp, &global->interfaces, | |
2278 | struct wpa_driver_nl80211_data, list) { | |
2279 | for (bss = drv->first_bss; bss; bss = bss->next) { | |
2280 | if ((ifidx == -1 && !wdev_id_set) || | |
2281 | ifidx == bss->ifindex || | |
2282 | (wdev_id_set && bss->wdev_id_set && | |
2283 | wdev_id == bss->wdev_id)) { | |
2284 | do_process_drv_event(bss, gnlh->cmd, tb); | |
2285 | return NL_SKIP; | |
2286 | } | |
2287 | } | |
ce20a370 JM |
2288 | wpa_printf(MSG_DEBUG, |
2289 | "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)", | |
2290 | gnlh->cmd, ifidx, (long long unsigned int) wdev_id); | |
159a1791 JM |
2291 | } |
2292 | ||
2293 | return NL_SKIP; | |
2294 | } | |
2295 | ||
2296 | ||
2297 | int process_bss_event(struct nl_msg *msg, void *arg) | |
2298 | { | |
2299 | struct i802_bss *bss = arg; | |
2300 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
2301 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
2302 | ||
2303 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
2304 | genlmsg_attrlen(gnlh, 0), NULL); | |
2305 | ||
2306 | wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s", | |
2307 | gnlh->cmd, nl80211_command_to_string(gnlh->cmd), | |
2308 | bss->ifname); | |
2309 | ||
2310 | switch (gnlh->cmd) { | |
2311 | case NL80211_CMD_FRAME: | |
2312 | case NL80211_CMD_FRAME_TX_STATUS: | |
2313 | mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME], | |
2314 | tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], | |
2315 | tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], | |
2316 | tb[NL80211_ATTR_COOKIE], | |
7e0e1069 EP |
2317 | tb[NL80211_ATTR_RX_SIGNAL_DBM], |
2318 | tb[NL80211_ATTR_STA_WME]); | |
159a1791 JM |
2319 | break; |
2320 | case NL80211_CMD_UNEXPECTED_FRAME: | |
2321 | nl80211_spurious_frame(bss, tb, 0); | |
2322 | break; | |
2323 | case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: | |
2324 | nl80211_spurious_frame(bss, tb, 1); | |
2325 | break; | |
2326 | default: | |
2327 | wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " | |
2328 | "(cmd=%d)", gnlh->cmd); | |
2329 | break; | |
2330 | } | |
2331 | ||
2332 | return NL_SKIP; | |
2333 | } |