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