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