2 * Driver interaction with Linux nl80211/cfg80211 - Event processing
3 * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (c) 2009-2010, Atheros Communications
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
12 #include <netlink/genl/genl.h>
14 #include "utils/common.h"
15 #include "utils/eloop.h"
16 #include "common/qca-vendor.h"
17 #include "common/qca-vendor-attr.h"
18 #include "common/ieee802_11_defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "driver_nl80211.h"
23 static const char * nl80211_command_to_string(enum nl80211_commands cmd
)
25 #define C2S(x) case x: return #x;
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
)
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 C2S(NL80211_CMD_ADD_TX_TS
)
133 C2S(NL80211_CMD_DEL_TX_TS
)
134 C2S(NL80211_CMD_EXTERNAL_AUTH
)
136 return "NL80211_CMD_UNKNOWN";
142 static void mlme_event_auth(struct wpa_driver_nl80211_data
*drv
,
143 const u8
*frame
, size_t len
)
145 const struct ieee80211_mgmt
*mgmt
;
146 union wpa_event_data event
;
148 if (!(drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
) &&
149 drv
->force_connect_cmd
) {
151 * Avoid reporting two association events that would confuse
154 wpa_printf(MSG_DEBUG
,
155 "nl80211: Ignore auth event when using driver SME");
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 "
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
);
180 wpa_supplicant_event(drv
->ctx
, EVENT_AUTH
, &event
);
184 static void nl80211_parse_wmm_params(struct nlattr
*wmm_attr
,
185 struct wmm_params
*wmm_params
)
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
},
193 nla_parse_nested(wmm_info
, NL80211_STA_WME_MAX
, wmm_attr
,
195 !wmm_info
[NL80211_STA_WME_UAPSD_QUEUES
])
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
;
204 static void mlme_event_assoc(struct wpa_driver_nl80211_data
*drv
,
205 const u8
*frame
, size_t len
, struct nlattr
*wmm
)
207 const struct ieee80211_mgmt
*mgmt
;
208 union wpa_event_data event
;
212 if (!(drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
) &&
213 drv
->force_connect_cmd
) {
215 * Avoid reporting two association events that would confuse
218 wpa_printf(MSG_DEBUG
,
219 "nl80211: Ignore assoc event when using driver SME");
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 "
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
);
241 event
.assoc_reject
.status_code
= status
;
243 wpa_supplicant_event(drv
->ctx
, EVENT_ASSOC_REJECT
, &event
);
248 os_memcpy(drv
->bssid
, mgmt
->sa
, ETH_ALEN
);
249 os_memcpy(drv
->prev_bssid
, mgmt
->sa
, ETH_ALEN
);
251 os_memset(&event
, 0, sizeof(event
));
252 event
.assoc_info
.resp_frame
= frame
;
253 event
.assoc_info
.resp_frame_len
= len
;
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
);
260 event
.assoc_info
.freq
= drv
->assoc_freq
;
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
);
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
));
272 nl80211_parse_wmm_params(wmm
, &event
.assoc_info
.wmm_params
);
274 wpa_supplicant_event(drv
->ctx
, EVENT_ASSOC
, &event
);
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
,
282 struct nlattr
*timed_out
,
283 struct nlattr
*timeout_reason
,
284 struct nlattr
*authorized
,
285 struct nlattr
*key_replay_ctr
,
286 struct nlattr
*ptk_kck
,
287 struct nlattr
*ptk_kek
,
288 struct nlattr
*subnet_status
,
289 struct nlattr
*fils_erp_next_seq_num
,
290 struct nlattr
*fils_pmk
,
291 struct nlattr
*fils_pmkid
)
293 union wpa_event_data event
;
294 const u8
*ssid
= NULL
;
298 if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
) {
300 * Avoid reporting two association events that would confuse
303 wpa_printf(MSG_DEBUG
, "nl80211: Ignore connect event (cmd=%d) "
304 "when using userspace SME", cmd
);
308 drv
->connect_reassoc
= 0;
310 status_code
= status
? nla_get_u16(status
) : WLAN_STATUS_SUCCESS
;
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
) {
317 wpa_printf(MSG_DEBUG
, "nl80211: Roam event");
320 os_memset(&event
, 0, sizeof(event
));
321 if (cmd
== NL80211_CMD_CONNECT
&& status_code
!= WLAN_STATUS_SUCCESS
) {
323 event
.assoc_reject
.bssid
= nla_data(addr
);
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
,
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.
335 wpa_printf(MSG_DEBUG
,
336 "nl80211: Ignore connection failure event triggered during reassociation");
341 event
.assoc_reject
.resp_ies
= nla_data(resp_ie
);
342 event
.assoc_reject
.resp_ies_len
= nla_len(resp_ie
);
344 event
.assoc_reject
.status_code
= status_code
;
345 event
.assoc_reject
.timed_out
= timed_out
!= NULL
;
346 if (timed_out
&& timeout_reason
) {
347 enum nl80211_timeout_reason reason
;
349 reason
= nla_get_u32(timeout_reason
);
351 case NL80211_TIMEOUT_SCAN
:
352 event
.assoc_reject
.timeout_reason
= "scan";
354 case NL80211_TIMEOUT_AUTH
:
355 event
.assoc_reject
.timeout_reason
= "auth";
357 case NL80211_TIMEOUT_ASSOC
:
358 event
.assoc_reject
.timeout_reason
= "assoc";
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
);
367 wpa_supplicant_event(drv
->ctx
, EVENT_ASSOC_REJECT
, &event
);
373 os_memcpy(drv
->bssid
, nla_data(addr
), ETH_ALEN
);
374 os_memcpy(drv
->prev_bssid
, drv
->bssid
, ETH_ALEN
);
378 event
.assoc_info
.req_ies
= nla_data(req_ie
);
379 event
.assoc_info
.req_ies_len
= nla_len(req_ie
);
381 if (cmd
== NL80211_CMD_ROAM
) {
382 ssid
= get_ie(event
.assoc_info
.req_ies
,
383 event
.assoc_info
.req_ies_len
,
385 if (ssid
&& ssid
[1] > 0 && ssid
[1] <= 32) {
386 drv
->ssid_len
= ssid
[1];
387 os_memcpy(drv
->ssid
, ssid
+ 2, ssid
[1]);
388 wpa_printf(MSG_DEBUG
,
389 "nl80211: Set drv->ssid based on req_ie to '%s'",
390 wpa_ssid_txt(drv
->ssid
,
396 event
.assoc_info
.resp_ies
= nla_data(resp_ie
);
397 event
.assoc_info
.resp_ies_len
= nla_len(resp_ie
);
400 event
.assoc_info
.freq
= nl80211_get_assoc_freq(drv
);
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
));
412 if (authorized
&& nla_get_u8(authorized
)) {
413 event
.assoc_info
.authorized
= 1;
414 wpa_printf(MSG_DEBUG
, "nl80211: connection authorized");
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
);
421 event
.assoc_info
.ptk_kck
= nla_data(ptk_kck
);
422 event
.assoc_info
.ptk_kck_len
= nla_len(ptk_kck
);
425 event
.assoc_info
.ptk_kek
= nla_data(ptk_kek
);
426 event
.assoc_info
.ptk_kek_len
= nla_len(ptk_kek
);
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
437 event
.assoc_info
.subnet_status
= nla_get_u8(subnet_status
);
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
);
445 event
.assoc_info
.fils_pmk
= nla_data(fils_pmk
);
446 event
.assoc_info
.fils_pmk_len
= nla_len(fils_pmk
);
450 event
.assoc_info
.fils_pmkid
= nla_data(fils_pmkid
);
452 wpa_supplicant_event(drv
->ctx
, EVENT_ASSOC
, &event
);
456 static void mlme_event_disconnect(struct wpa_driver_nl80211_data
*drv
,
457 struct nlattr
*reason
, struct nlattr
*addr
,
458 struct nlattr
*by_ap
)
460 union wpa_event_data data
;
461 unsigned int locally_generated
= by_ap
== NULL
;
463 if (drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
) {
465 * Avoid reporting two disassociation events that could
466 * confuse the core code.
468 wpa_printf(MSG_DEBUG
, "nl80211: Ignore disconnect "
469 "event when using userspace SME");
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");
480 wpa_printf(MSG_WARNING
, "nl80211: Was expecting local "
481 "disconnect but got another disconnect "
485 wpa_printf(MSG_DEBUG
, "nl80211: Disconnect event");
486 nl80211_mark_disconnected(drv
);
487 os_memset(&data
, 0, sizeof(data
));
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
);
495 static int calculate_chan_offset(int width
, int freq
, int cf1
, int cf2
)
499 switch (convert2width(width
)) {
500 case CHAN_WIDTH_20_NOHT
:
512 case CHAN_WIDTH_UNKNOWN
:
513 case CHAN_WIDTH_80P80
:
514 /* FIXME: implement this */
518 return (abs(freq
- freq1
) / 20) % 2 == 0 ? 1 : -1;
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
)
527 struct i802_bss
*bss
;
528 union wpa_event_data data
;
533 wpa_printf(MSG_DEBUG
, "nl80211: Channel switch event");
538 ifidx
= nla_get_u32(ifindex
);
539 bss
= get_bss_ifindex(drv
, ifidx
);
541 wpa_printf(MSG_WARNING
, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
547 enum nl80211_channel_type ch_type
= nla_get_u32(type
);
549 wpa_printf(MSG_DEBUG
, "nl80211: Channel type: %d", ch_type
);
551 case NL80211_CHAN_NO_HT
:
554 case NL80211_CHAN_HT20
:
556 case NL80211_CHAN_HT40PLUS
:
559 case NL80211_CHAN_HT40MINUS
:
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
),
568 cf2
? nla_get_u32(cf2
) : 0);
570 wpa_printf(MSG_WARNING
, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
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
;
578 data
.ch_switch
.ch_width
= convert2width(nla_get_u32(bw
));
580 data
.ch_switch
.cf1
= nla_get_u32(cf1
);
582 data
.ch_switch
.cf2
= nla_get_u32(cf2
);
584 bss
->freq
= data
.ch_switch
.freq
;
585 drv
->assoc_freq
= data
.ch_switch
.freq
;
587 wpa_supplicant_event(bss
->ctx
, EVENT_CH_SWITCH
, &data
);
591 static void mlme_timeout_event(struct wpa_driver_nl80211_data
*drv
,
592 enum nl80211_commands cmd
, struct nlattr
*addr
)
594 union wpa_event_data event
;
595 enum wpa_event_type ev
;
597 if (nla_len(addr
) != ETH_ALEN
)
600 wpa_printf(MSG_DEBUG
, "nl80211: MLME event %d; timeout with " MACSTR
,
601 cmd
, MAC2STR((u8
*) nla_data(addr
)));
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
;
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
);
616 static void mlme_event_mgmt(struct i802_bss
*bss
,
617 struct nlattr
*freq
, struct nlattr
*sig
,
618 const u8
*frame
, size_t len
)
620 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
621 const struct ieee80211_mgmt
*mgmt
;
622 union wpa_event_data event
;
627 wpa_printf(MSG_MSGDUMP
, "nl80211: Frame event");
628 mgmt
= (const struct ieee80211_mgmt
*) frame
;
630 wpa_printf(MSG_DEBUG
, "nl80211: Too short management frame");
634 fc
= le_to_host16(mgmt
->frame_control
);
635 stype
= WLAN_FC_GET_STYPE(fc
);
638 ssi_signal
= (s32
) nla_get_u32(sig
);
640 os_memset(&event
, 0, sizeof(event
));
642 event
.rx_mgmt
.freq
= nla_get_u32(freq
);
643 rx_freq
= drv
->last_mgmt_freq
= event
.rx_mgmt
.freq
;
645 wpa_printf(MSG_DEBUG
,
646 "nl80211: RX frame da=" MACSTR
" sa=" MACSTR
" bssid=" MACSTR
647 " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
648 MAC2STR(mgmt
->da
), MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->bssid
),
649 rx_freq
, ssi_signal
, fc
,
650 le_to_host16(mgmt
->seq_ctrl
), stype
, fc2str(fc
),
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
);
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
)
664 union wpa_event_data event
;
665 const struct ieee80211_hdr
*hdr
;
668 wpa_printf(MSG_DEBUG
, "nl80211: Frame TX status event");
669 if (!is_ap_interface(drv
->nlmode
)) {
675 cookie_val
= nla_get_u64(cookie
);
676 wpa_printf(MSG_DEBUG
, "nl80211: Action TX status:"
677 " cookie=0x%llx%s (ack=%d)",
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
)
685 hdr
= (const struct ieee80211_hdr
*) frame
;
686 fc
= le_to_host16(hdr
->frame_control
);
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
);
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
)
703 const struct ieee80211_mgmt
*mgmt
;
704 union wpa_event_data event
;
705 const u8
*bssid
= NULL
;
708 if (type
== EVENT_DEAUTH
)
709 wpa_printf(MSG_DEBUG
, "nl80211: Deauthenticate event");
711 wpa_printf(MSG_DEBUG
, "nl80211: Disassociate event");
713 mgmt
= (const struct ieee80211_mgmt
*) frame
;
717 if ((drv
->capa
.flags
& WPA_DRIVER_FLAGS_SME
) &&
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) {
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.
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.
730 if (!os_memcmp(mgmt
->sa
, drv
->first_bss
->addr
,
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;
736 wpa_printf(MSG_DEBUG
,
737 "nl80211: Ignore deauth/disassoc event from old AP " MACSTR
" when already authenticating with " MACSTR
,
739 MAC2STR(drv
->auth_attempt_bssid
));
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) {
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.
753 wpa_printf(MSG_DEBUG
,
754 "nl80211: Ignore deauth/disassoc event from old AP "
756 " when already connecting with " MACSTR
,
758 MAC2STR(drv
->auth_attempt_bssid
));
762 if (drv
->associated
!= 0 &&
763 os_memcmp(bssid
, drv
->bssid
, ETH_ALEN
) != 0 &&
764 os_memcmp(bssid
, drv
->auth_bssid
, ETH_ALEN
) != 0) {
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!
770 wpa_printf(MSG_DEBUG
, "nl80211: Deauth received "
771 "from Unknown BSSID " MACSTR
" -- ignoring",
777 nl80211_mark_disconnected(drv
);
778 os_memset(&event
, 0, sizeof(event
));
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
);
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
;
795 event
.deauth_info
.locally_generated
=
796 !os_memcmp(mgmt
->sa
, drv
->first_bss
->addr
, ETH_ALEN
);
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;
800 if (event
.deauth_info
.locally_generated
)
801 drv
->ignore_next_local_deauth
= 0;
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");
810 wpa_printf(MSG_WARNING
, "nl80211: Was expecting local deauth but got another disconnect event first");
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
;
821 wpa_supplicant_event(drv
->ctx
, type
, &event
);
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
)
829 const struct ieee80211_mgmt
*mgmt
;
830 union wpa_event_data event
;
833 if (type
== EVENT_UNPROT_DEAUTH
)
834 wpa_printf(MSG_DEBUG
, "nl80211: Unprot Deauthenticate event");
836 wpa_printf(MSG_DEBUG
, "nl80211: Unprot Disassociate event");
841 mgmt
= (const struct ieee80211_mgmt
*) frame
;
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
);
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
;
853 event
.unprot_deauth
.sa
= mgmt
->sa
;
854 event
.unprot_deauth
.da
= mgmt
->da
;
855 event
.unprot_deauth
.reason_code
= reason_code
;
858 wpa_supplicant_event(drv
->ctx
, type
, &event
);
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
,
866 struct nlattr
*cookie
, struct nlattr
*sig
,
869 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
873 if (timed_out
&& addr
) {
874 mlme_timeout_event(drv
, cmd
, addr
);
879 wpa_printf(MSG_DEBUG
,
880 "nl80211: MLME event %d (%s) without frame data",
881 cmd
, nl80211_command_to_string(cmd
));
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
,
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 &&
901 (is_zero_ether_addr(bss
->rand_addr
) ||
902 os_memcmp(bss
->rand_addr
, data
+ 4, ETH_ALEN
) != 0) &&
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
);
908 wpa_hexdump(MSG_MSGDUMP
, "nl80211: MLME event frame",
909 nla_data(frame
), nla_len(frame
));
912 case NL80211_CMD_AUTHENTICATE
:
913 mlme_event_auth(drv
, nla_data(frame
), nla_len(frame
));
915 case NL80211_CMD_ASSOCIATE
:
916 mlme_event_assoc(drv
, nla_data(frame
), nla_len(frame
), wmm
);
918 case NL80211_CMD_DEAUTHENTICATE
:
919 mlme_event_deauth_disassoc(drv
, EVENT_DEAUTH
,
920 nla_data(frame
), nla_len(frame
));
922 case NL80211_CMD_DISASSOCIATE
:
923 mlme_event_deauth_disassoc(drv
, EVENT_DISASSOC
,
924 nla_data(frame
), nla_len(frame
));
926 case NL80211_CMD_FRAME
:
927 mlme_event_mgmt(bss
, freq
, sig
, nla_data(frame
),
930 case NL80211_CMD_FRAME_TX_STATUS
:
931 mlme_event_mgmt_tx_status(drv
, cookie
, nla_data(frame
),
932 nla_len(frame
), ack
);
934 case NL80211_CMD_UNPROT_DEAUTHENTICATE
:
935 mlme_event_unprot_disconnect(drv
, EVENT_UNPROT_DEAUTH
,
936 nla_data(frame
), nla_len(frame
));
938 case NL80211_CMD_UNPROT_DISASSOCIATE
:
939 mlme_event_unprot_disconnect(drv
, EVENT_UNPROT_DISASSOC
,
940 nla_data(frame
), nla_len(frame
));
948 static void mlme_event_michael_mic_failure(struct i802_bss
*bss
,
951 union wpa_event_data data
;
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
]);
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
]));
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;
973 data
.michael_mic_failure
.unicast
= 1;
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
);
980 wpa_supplicant_event(bss
->ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
984 static void mlme_event_join_ibss(struct wpa_driver_nl80211_data
*drv
,
988 union wpa_event_data event
;
990 if (tb
[NL80211_ATTR_MAC
] == NULL
) {
991 wpa_printf(MSG_DEBUG
, "nl80211: No address in IBSS joined "
995 os_memcpy(drv
->bssid
, nla_data(tb
[NL80211_ATTR_MAC
]), ETH_ALEN
);
998 wpa_printf(MSG_DEBUG
, "nl80211: IBSS " MACSTR
" joined",
999 MAC2STR(drv
->bssid
));
1001 freq
= nl80211_get_assoc_freq(drv
);
1003 wpa_printf(MSG_DEBUG
, "nl80211: IBSS on frequency %u MHz",
1005 drv
->first_bss
->freq
= freq
;
1008 os_memset(&event
, 0, sizeof(event
));
1009 event
.assoc_info
.freq
= freq
;
1011 wpa_supplicant_event(drv
->ctx
, EVENT_ASSOC
, &event
);
1015 static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data
*drv
,
1016 int cancel_event
, struct nlattr
*tb
[])
1018 unsigned int freq
, chan_type
, duration
;
1019 union wpa_event_data data
;
1022 if (tb
[NL80211_ATTR_WIPHY_FREQ
])
1023 freq
= nla_get_u32(tb
[NL80211_ATTR_WIPHY_FREQ
]);
1027 if (tb
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
])
1028 chan_type
= nla_get_u32(tb
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
]);
1032 if (tb
[NL80211_ATTR_DURATION
])
1033 duration
= nla_get_u32(tb
[NL80211_ATTR_DURATION
]);
1037 if (tb
[NL80211_ATTR_COOKIE
])
1038 cookie
= nla_get_u64(tb
[NL80211_ATTR_COOKIE
]);
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");
1048 if (cookie
!= drv
->remain_on_chan_cookie
)
1049 return; /* not for us */
1052 drv
->pending_remain_on_chan
= 0;
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
);
1063 static void mlme_event_ft_event(struct wpa_driver_nl80211_data
*drv
,
1064 struct nlattr
*tb
[])
1066 union wpa_event_data data
;
1068 os_memset(&data
, 0, sizeof(data
));
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
]);
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
]);
1080 if (tb
[NL80211_ATTR_MAC
])
1081 os_memcpy(data
.ft_ies
.target_ap
,
1082 nla_data(tb
[NL80211_ATTR_MAC
]), ETH_ALEN
);
1084 wpa_printf(MSG_DEBUG
, "nl80211: FT event target_ap " MACSTR
,
1085 MAC2STR(data
.ft_ies
.target_ap
));
1087 wpa_supplicant_event(drv
->ctx
, EVENT_FT_RESPONSE
, &data
);
1091 static void send_scan_event(struct wpa_driver_nl80211_data
*drv
, int aborted
,
1092 struct nlattr
*tb
[], int external_scan
)
1094 union wpa_event_data event
;
1097 struct scan_info
*info
;
1098 #define MAX_REPORT_FREQS 50
1099 int freqs
[MAX_REPORT_FREQS
];
1102 if (!external_scan
&& drv
->scan_for_auth
) {
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
);
1110 os_memset(&event
, 0, sizeof(event
));
1111 info
= &event
.scan_info
;
1112 info
->aborted
= aborted
;
1113 info
->external_scan
= external_scan
;
1114 info
->nl_scan_event
= 1;
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
));
1125 if (info
->num_ssids
== WPAS_MAX_SCAN_SSIDS
)
1129 if (tb
[NL80211_ATTR_SCAN_FREQUENCIES
]) {
1130 char msg
[300], *pos
, *end
;
1134 end
= pos
+ sizeof(msg
);
1137 nla_for_each_nested(nl
, tb
[NL80211_ATTR_SCAN_FREQUENCIES
], rem
)
1139 freqs
[num_freqs
] = nla_get_u32(nl
);
1140 res
= os_snprintf(pos
, end
- pos
, " %d",
1142 if (!os_snprintf_error(end
- pos
, res
))
1145 if (num_freqs
== MAX_REPORT_FREQS
- 1)
1148 info
->freqs
= freqs
;
1149 info
->num_freqs
= num_freqs
;
1150 wpa_printf(MSG_DEBUG
, "nl80211: Scan included frequencies:%s",
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
]),
1163 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_RESULTS
, &event
);
1167 static void nl80211_cqm_event(struct wpa_driver_nl80211_data
*drv
,
1168 struct nlattr
*tb
[])
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
},
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
},
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
;
1186 if (tb
[NL80211_ATTR_CQM
] == NULL
||
1187 nla_parse_nested(cqm
, NL80211_ATTR_CQM_MAX
, tb
[NL80211_ATTR_CQM
],
1189 wpa_printf(MSG_DEBUG
, "nl80211: Ignore invalid CQM event");
1193 os_memset(&ed
, 0, sizeof(ed
));
1195 if (cqm
[NL80211_ATTR_CQM_PKT_LOSS_EVENT
]) {
1196 if (!tb
[NL80211_ATTR_MAC
])
1198 os_memcpy(ed
.low_ack
.addr
, nla_data(tb
[NL80211_ATTR_MAC
]),
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
);
1205 wpa_supplicant_event(drv
->ctx
, EVENT_STATION_LOW_ACK
, &ed
);
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
);
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
]));
1228 if (cqm
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT
] == NULL
) {
1229 wpa_printf(MSG_DEBUG
,
1230 "nl80211: Not a CQM RSSI threshold event");
1233 event
= nla_get_u32(cqm
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT
]);
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 "
1242 ed
.signal_change
.above_threshold
= 0;
1244 wpa_printf(MSG_DEBUG
,
1245 "nl80211: Unknown CQM RSSI threshold event: %d",
1250 res
= nl80211_get_link_signal(drv
, &sig
);
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
);
1258 res
= nl80211_get_link_noise(drv
, &sig
);
1260 ed
.signal_change
.current_noise
= sig
.current_noise
;
1261 wpa_printf(MSG_DEBUG
, "nl80211: Noise: %d dBm",
1265 wpa_supplicant_event(drv
->ctx
, EVENT_SIGNAL_CHANGE
, &ed
);
1269 static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data
*drv
,
1273 union wpa_event_data data
;
1275 if (drv
->nlmode
!= NL80211_IFTYPE_MESH_POINT
||
1276 !tb
[NL80211_ATTR_MAC
] || !tb
[NL80211_ATTR_IE
])
1279 addr
= nla_data(tb
[NL80211_ATTR_MAC
]);
1280 wpa_printf(MSG_DEBUG
, "nl80211: New peer candidate " MACSTR
,
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
);
1291 static void nl80211_new_station_event(struct wpa_driver_nl80211_data
*drv
,
1292 struct i802_bss
*bss
,
1296 union wpa_event_data data
;
1298 if (tb
[NL80211_ATTR_MAC
] == NULL
)
1300 addr
= nla_data(tb
[NL80211_ATTR_MAC
]);
1301 wpa_printf(MSG_DEBUG
, "nl80211: New station " MACSTR
, MAC2STR(addr
));
1303 if (is_ap_interface(drv
->nlmode
) && drv
->device_ap_sme
) {
1306 if (tb
[NL80211_ATTR_IE
]) {
1307 ies
= nla_data(tb
[NL80211_ATTR_IE
]);
1308 ies_len
= nla_len(tb
[NL80211_ATTR_IE
]);
1310 wpa_hexdump(MSG_DEBUG
, "nl80211: Assoc Req IEs", ies
, ies_len
);
1311 drv_event_assoc(bss
->ctx
, addr
, ies
, ies_len
, 0);
1315 if (drv
->nlmode
!= NL80211_IFTYPE_ADHOC
)
1318 os_memset(&data
, 0, sizeof(data
));
1319 os_memcpy(data
.ibss_rsn_start
.peer
, addr
, ETH_ALEN
);
1320 wpa_supplicant_event(bss
->ctx
, EVENT_IBSS_RSN_START
, &data
);
1324 static void nl80211_del_station_event(struct wpa_driver_nl80211_data
*drv
,
1325 struct i802_bss
*bss
,
1329 union wpa_event_data data
;
1331 if (tb
[NL80211_ATTR_MAC
] == NULL
)
1333 addr
= nla_data(tb
[NL80211_ATTR_MAC
]);
1334 wpa_printf(MSG_DEBUG
, "nl80211: Delete station " MACSTR
,
1337 if (is_ap_interface(drv
->nlmode
) && drv
->device_ap_sme
) {
1338 drv_event_disassoc(bss
->ctx
, addr
);
1342 if (drv
->nlmode
!= NL80211_IFTYPE_ADHOC
)
1345 os_memset(&data
, 0, sizeof(data
));
1346 os_memcpy(data
.ibss_peer_lost
.peer
, addr
, ETH_ALEN
);
1347 wpa_supplicant_event(bss
->ctx
, EVENT_IBSS_PEER_LOST
, &data
);
1351 static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data
*drv
,
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
,
1360 [NL80211_REKEY_DATA_KCK
] = {
1361 .minlen
= NL80211_KCK_LEN
,
1362 .maxlen
= NL80211_KCK_LEN
,
1364 [NL80211_REKEY_DATA_REPLAY_CTR
] = {
1365 .minlen
= NL80211_REPLAY_CTR_LEN
,
1366 .maxlen
= NL80211_REPLAY_CTR_LEN
,
1369 union wpa_event_data data
;
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
])
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
);
1390 static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data
*drv
,
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
] = {
1400 [NL80211_PMKSA_CANDIDATE_PREAUTH
] = { .type
= NLA_FLAG
},
1402 union wpa_event_data data
;
1404 wpa_printf(MSG_DEBUG
, "nl80211: PMKSA candidate event");
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
] ||
1410 !cand
[NL80211_PMKSA_CANDIDATE_BSSID
])
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
);
1424 static void nl80211_client_probe_event(struct wpa_driver_nl80211_data
*drv
,
1427 union wpa_event_data data
;
1429 wpa_printf(MSG_DEBUG
, "nl80211: Probe client event");
1431 if (!tb
[NL80211_ATTR_MAC
] || !tb
[NL80211_ATTR_ACK
])
1434 os_memset(&data
, 0, sizeof(data
));
1435 os_memcpy(data
.client_poll
.addr
,
1436 nla_data(tb
[NL80211_ATTR_MAC
]), ETH_ALEN
);
1438 wpa_supplicant_event(drv
->ctx
, EVENT_DRIVER_CLIENT_POLL_OK
, &data
);
1442 static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data
*drv
,
1445 union wpa_event_data data
;
1447 wpa_printf(MSG_DEBUG
, "nl80211: TDLS operation event");
1449 if (!tb
[NL80211_ATTR_MAC
] || !tb
[NL80211_ATTR_TDLS_OPERATION
])
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
;
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
;
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
;
1472 wpa_printf(MSG_DEBUG
, "nl80211: Unsupported TDLS operatione "
1476 if (tb
[NL80211_ATTR_REASON_CODE
]) {
1477 data
.tdls
.reason_code
=
1478 nla_get_u16(tb
[NL80211_ATTR_REASON_CODE
]);
1481 wpa_supplicant_event(drv
->ctx
, EVENT_TDLS
, &data
);
1485 static void nl80211_stop_ap(struct wpa_driver_nl80211_data
*drv
,
1488 wpa_supplicant_event(drv
->ctx
, EVENT_INTERFACE_UNAVAILABLE
, NULL
);
1492 static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data
*drv
,
1495 union wpa_event_data data
;
1498 wpa_printf(MSG_DEBUG
, "nl80211: Connect failed event");
1500 if (!tb
[NL80211_ATTR_MAC
] || !tb
[NL80211_ATTR_CONN_FAILED_REASON
])
1503 os_memset(&data
, 0, sizeof(data
));
1504 os_memcpy(data
.connect_failed_reason
.addr
,
1505 nla_data(tb
[NL80211_ATTR_MAC
]), ETH_ALEN
);
1507 reason
= nla_get_u32(tb
[NL80211_ATTR_CONN_FAILED_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
;
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
;
1520 wpa_printf(MSG_DEBUG
, "nl8021l: Unknown connect failed reason "
1525 wpa_supplicant_event(drv
->ctx
, EVENT_CONNECT_FAILED_REASON
, &data
);
1529 static void nl80211_radar_event(struct wpa_driver_nl80211_data
*drv
,
1532 union wpa_event_data data
;
1533 enum nl80211_radar_event event_type
;
1535 if (!tb
[NL80211_ATTR_WIPHY_FREQ
] || !tb
[NL80211_ATTR_RADAR_EVENT
])
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
]);
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;
1547 switch (nla_get_u32(tb
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
])) {
1548 case NL80211_CHAN_NO_HT
:
1549 data
.dfs_event
.ht_enabled
= 0;
1551 case NL80211_CHAN_HT20
:
1553 case NL80211_CHAN_HT40PLUS
:
1554 data
.dfs_event
.chan_offset
= 1;
1556 case NL80211_CHAN_HT40MINUS
:
1557 data
.dfs_event
.chan_offset
= -1;
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
]);
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
);
1577 switch (event_type
) {
1578 case NL80211_RADAR_DETECTED
:
1579 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_RADAR_DETECTED
, &data
);
1581 case NL80211_RADAR_CAC_FINISHED
:
1582 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_CAC_FINISHED
, &data
);
1584 case NL80211_RADAR_CAC_ABORTED
:
1585 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_CAC_ABORTED
, &data
);
1587 case NL80211_RADAR_NOP_FINISHED
:
1588 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_NOP_FINISHED
, &data
);
1590 case NL80211_RADAR_PRE_CAC_EXPIRED
:
1591 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_PRE_CAC_EXPIRED
,
1595 wpa_printf(MSG_DEBUG
, "nl80211: Unknown radar event %d "
1596 "received", event_type
);
1602 static void nl80211_spurious_frame(struct i802_bss
*bss
, struct nlattr
**tb
,
1605 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
1606 union wpa_event_data event
;
1608 if (!tb
[NL80211_ATTR_MAC
])
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
;
1616 wpa_supplicant_event(drv
->ctx
, EVENT_RX_FROM_UNKNOWN
, &event
);
1620 #ifdef CONFIG_DRIVER_NL80211_QCA
1622 static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data
*drv
,
1623 const u8
*data
, size_t len
)
1626 union wpa_event_data event
;
1627 struct wpa_freq_range
*range
= NULL
;
1628 const struct qca_avoid_freq_list
*freq_range
;
1630 freq_range
= (const struct qca_avoid_freq_list
*) data
;
1631 if (len
< sizeof(freq_range
->count
))
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
);
1643 range
= os_calloc(count
, sizeof(struct wpa_freq_range
));
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");
1659 event
.freq_range
.num
++;
1661 event
.freq_range
.range
= range
;
1663 wpa_supplicant_event(drv
->ctx
, EVENT_AVOID_FREQUENCIES
, &event
);
1669 static enum hostapd_hw_mode
get_qca_hw_mode(u8 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
;
1683 return NUM_HOSTAPD_MODES
;
1688 static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data
*drv
,
1689 const u8
*data
, size_t len
)
1691 struct nlattr
*tb
[QCA_WLAN_VENDOR_ATTR_ACS_MAX
+ 1];
1692 union wpa_event_data event
;
1694 wpa_printf(MSG_DEBUG
,
1695 "nl80211: ACS channel selection vendor event received");
1697 if (nla_parse(tb
, QCA_WLAN_VENDOR_ATTR_ACS_MAX
,
1698 (struct nlattr
*) data
, len
, NULL
) ||
1699 !tb
[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
] ||
1700 !tb
[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL
])
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
]);
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
]);
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
]);
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",
1731 wpa_printf(MSG_INFO
,
1732 "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
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
,
1737 event
.acs_selected_channels
.vht_seg1_center_ch
,
1738 event
.acs_selected_channels
.hw_mode
);
1740 /* Ignore ACS channel list check for backwards compatibility */
1742 wpa_supplicant_event(drv
->ctx
, EVENT_ACS_CHANNEL_SELECTED
, &event
);
1746 static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data
*drv
,
1747 const u8
*data
, size_t len
)
1749 struct nlattr
*tb
[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX
+ 1];
1752 wpa_printf(MSG_DEBUG
,
1753 "nl80211: Key management roam+auth vendor event received");
1755 if (nla_parse(tb
, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX
,
1756 (struct nlattr
*) data
, len
, NULL
) ||
1757 !tb
[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID
] ||
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
])
1764 bssid
= nla_data(tb
[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID
]);
1765 wpa_printf(MSG_DEBUG
, " * roam BSSID " MACSTR
, MAC2STR(bssid
));
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
],
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
],
1775 tb
[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK
],
1776 tb
[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS
],
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
]);
1783 static void qca_nl80211_dfs_offload_radar_event(
1784 struct wpa_driver_nl80211_data
*drv
, u32 subcmd
, u8
*msg
, int length
)
1786 union wpa_event_data data
;
1787 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1789 wpa_printf(MSG_DEBUG
,
1790 "nl80211: DFS offload radar vendor event received");
1792 if (nla_parse(tb
, NL80211_ATTR_MAX
,
1793 (struct nlattr
*) msg
, length
, NULL
))
1796 if (!tb
[NL80211_ATTR_WIPHY_FREQ
]) {
1797 wpa_printf(MSG_INFO
,
1798 "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event");
1802 os_memset(&data
, 0, sizeof(data
));
1803 data
.dfs_event
.freq
= nla_get_u32(tb
[NL80211_ATTR_WIPHY_FREQ
]);
1805 wpa_printf(MSG_DEBUG
, "nl80211: DFS event on freq %d MHz",
1806 data
.dfs_event
.freq
);
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;
1813 switch (nla_get_u32(tb
[NL80211_ATTR_WIPHY_CHANNEL_TYPE
])) {
1814 case NL80211_CHAN_NO_HT
:
1815 data
.dfs_event
.ht_enabled
= 0;
1817 case NL80211_CHAN_HT20
:
1819 case NL80211_CHAN_HT40PLUS
:
1820 data
.dfs_event
.chan_offset
= 1;
1822 case NL80211_CHAN_HT40MINUS
:
1823 data
.dfs_event
.chan_offset
= -1;
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
]);
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
);
1845 case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED
:
1846 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_RADAR_DETECTED
, &data
);
1848 case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED
:
1849 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_CAC_STARTED
, &data
);
1851 case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED
:
1852 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_CAC_FINISHED
, &data
);
1854 case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED
:
1855 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_CAC_ABORTED
, &data
);
1857 case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED
:
1858 wpa_supplicant_event(drv
->ctx
, EVENT_DFS_NOP_FINISHED
, &data
);
1861 wpa_printf(MSG_DEBUG
,
1862 "nl80211: Unknown DFS offload radar event %d received",
1869 static void qca_nl80211_scan_trigger_event(struct wpa_driver_nl80211_data
*drv
,
1870 u8
*data
, size_t len
)
1872 struct nlattr
*tb
[QCA_WLAN_VENDOR_ATTR_SCAN_MAX
+ 1];
1874 union wpa_event_data event
;
1875 struct scan_info
*info
;
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
])
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 */
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;
1894 drv
->scan_state
= SCAN_STARTED
;
1895 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_STARTED
, &event
);
1899 static void send_vendor_scan_event(struct wpa_driver_nl80211_data
*drv
,
1900 int aborted
, struct nlattr
*tb
[],
1903 union wpa_event_data event
;
1906 struct scan_info
*info
;
1907 int freqs
[MAX_REPORT_FREQS
];
1910 os_memset(&event
, 0, sizeof(event
));
1911 info
= &event
.scan_info
;
1912 info
->aborted
= aborted
;
1913 info
->external_scan
= external_scan
;
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
));
1926 if (info
->num_ssids
== WPAS_MAX_SCAN_SSIDS
)
1931 if (tb
[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES
]) {
1932 char msg
[300], *pos
, *end
;
1936 end
= pos
+ sizeof(msg
);
1939 nla_for_each_nested(nl
,
1940 tb
[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES
],
1942 freqs
[num_freqs
] = nla_get_u32(nl
);
1943 res
= os_snprintf(pos
, end
- pos
, " %d",
1945 if (!os_snprintf_error(end
- pos
, res
))
1948 if (num_freqs
== MAX_REPORT_FREQS
- 1)
1952 info
->freqs
= freqs
;
1953 info
->num_freqs
= num_freqs
;
1954 wpa_printf(MSG_DEBUG
, "nl80211: Scan included frequencies:%s",
1957 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_RESULTS
, &event
);
1961 static void qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data
*drv
,
1962 u8
*data
, size_t len
)
1964 struct nlattr
*tb
[QCA_WLAN_VENDOR_ATTR_SCAN_MAX
+ 1];
1966 enum scan_status status
;
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
])
1975 status
= nla_get_u8(tb
[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS
]);
1976 if (status
>= VENDOR_SCAN_STATUS_MAX
)
1977 return; /* invalid status */
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 */
1985 if (status
== VENDOR_SCAN_STATUS_NEW_RESULTS
)
1986 drv
->scan_state
= SCAN_COMPLETED
;
1988 drv
->scan_state
= SCAN_ABORTED
;
1990 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout
, drv
,
1992 drv
->vendor_scan_cookie
= 0;
1993 drv
->last_scan_cmd
= 0;
1996 send_vendor_scan_event(drv
, (status
== VENDOR_SCAN_STATUS_ABORTED
), tb
,
2001 static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data
*drv
,
2002 u8
*data
, size_t len
)
2004 struct nlattr
*tb
[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX
+ 1];
2005 union wpa_event_data event
;
2007 wpa_printf(MSG_DEBUG
,
2008 "nl80211: P2P listen offload stop vendor event received");
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
])
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
]);
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
);
2025 #endif /* CONFIG_DRIVER_NL80211_QCA */
2028 static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data
*drv
,
2029 u32 subcmd
, u8
*data
, size_t len
)
2032 case QCA_NL80211_VENDOR_SUBCMD_TEST
:
2033 wpa_hexdump(MSG_DEBUG
, "nl80211: QCA test event", data
, len
);
2035 #ifdef CONFIG_DRIVER_NL80211_QCA
2036 case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY
:
2037 qca_nl80211_avoid_freq(drv
, data
, len
);
2039 case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH
:
2040 qca_nl80211_key_mgmt_auth(drv
, data
, len
);
2042 case QCA_NL80211_VENDOR_SUBCMD_DO_ACS
:
2043 qca_nl80211_acs_select_ch(drv
, data
, len
);
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
);
2052 case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
:
2053 qca_nl80211_scan_trigger_event(drv
, data
, len
);
2055 case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE
:
2056 qca_nl80211_scan_done_event(drv
, data
, len
);
2058 case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP
:
2059 qca_nl80211_p2p_lo_stop_event(drv
, data
, len
);
2061 #endif /* CONFIG_DRIVER_NL80211_QCA */
2063 wpa_printf(MSG_DEBUG
,
2064 "nl80211: Ignore unsupported QCA vendor event %u",
2071 static void nl80211_vendor_event(struct wpa_driver_nl80211_data
*drv
,
2074 u32 vendor_id
, subcmd
, wiphy
= 0;
2079 if (!tb
[NL80211_ATTR_VENDOR_ID
] ||
2080 !tb
[NL80211_ATTR_VENDOR_SUBCMD
])
2083 vendor_id
= nla_get_u32(tb
[NL80211_ATTR_VENDOR_ID
]);
2084 subcmd
= nla_get_u32(tb
[NL80211_ATTR_VENDOR_SUBCMD
]);
2086 if (tb
[NL80211_ATTR_WIPHY
])
2087 wiphy
= nla_get_u32(tb
[NL80211_ATTR_WIPHY
]);
2089 wpa_printf(MSG_DEBUG
, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
2090 wiphy
, vendor_id
, subcmd
);
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
);
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)",
2105 switch (vendor_id
) {
2107 nl80211_vendor_event_qca(drv
, subcmd
, data
, len
);
2110 wpa_printf(MSG_DEBUG
, "nl80211: Ignore unsupported vendor event");
2116 static void nl80211_reg_change_event(struct wpa_driver_nl80211_data
*drv
,
2117 struct nlattr
*tb
[])
2119 union wpa_event_data data
;
2120 enum nl80211_reg_initiator init
;
2122 wpa_printf(MSG_DEBUG
, "nl80211: Regulatory domain change");
2124 if (tb
[NL80211_ATTR_REG_INITIATOR
] == NULL
)
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
);
2131 case NL80211_REGDOM_SET_BY_CORE
:
2132 data
.channel_list_changed
.initiator
= REGDOM_SET_BY_CORE
;
2134 case NL80211_REGDOM_SET_BY_USER
:
2135 data
.channel_list_changed
.initiator
= REGDOM_SET_BY_USER
;
2137 case NL80211_REGDOM_SET_BY_DRIVER
:
2138 data
.channel_list_changed
.initiator
= REGDOM_SET_BY_DRIVER
;
2140 case NL80211_REGDOM_SET_BY_COUNTRY_IE
:
2141 data
.channel_list_changed
.initiator
= REGDOM_SET_BY_COUNTRY_IE
;
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
);
2150 case NL80211_REGDOM_TYPE_COUNTRY
:
2151 data
.channel_list_changed
.type
= REGDOM_TYPE_COUNTRY
;
2153 case NL80211_REGDOM_TYPE_WORLD
:
2154 data
.channel_list_changed
.type
= REGDOM_TYPE_WORLD
;
2156 case NL80211_REGDOM_TYPE_CUSTOM_WORLD
:
2157 data
.channel_list_changed
.type
=
2158 REGDOM_TYPE_CUSTOM_WORLD
;
2160 case NL80211_REGDOM_TYPE_INTERSECTION
:
2161 data
.channel_list_changed
.type
=
2162 REGDOM_TYPE_INTERSECTION
;
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
);
2175 wpa_supplicant_event(drv
->ctx
, EVENT_CHANNEL_LIST_CHANGED
, &data
);
2179 static void nl80211_external_auth(struct wpa_driver_nl80211_data
*drv
,
2182 union wpa_event_data event
;
2183 enum nl80211_external_auth_action act
;
2185 if (!tb
[NL80211_ATTR_AKM_SUITES
] ||
2186 !tb
[NL80211_ATTR_EXTERNAL_AUTH_ACTION
] ||
2187 !tb
[NL80211_ATTR_BSSID
] ||
2188 !tb
[NL80211_ATTR_SSID
])
2191 os_memset(&event
, 0, sizeof(event
));
2192 act
= nla_get_u32(tb
[NL80211_ATTR_EXTERNAL_AUTH_ACTION
]);
2194 case NL80211_EXTERNAL_AUTH_START
:
2195 event
.external_auth
.action
= EXT_AUTH_START
;
2197 case NL80211_EXTERNAL_AUTH_ABORT
:
2198 event
.external_auth
.action
= EXT_AUTH_ABORT
;
2204 event
.external_auth
.key_mgmt_suite
=
2205 nla_get_u32(tb
[NL80211_ATTR_AKM_SUITES
]);
2207 event
.external_auth
.ssid_len
= nla_len(tb
[NL80211_ATTR_SSID
]);
2208 if (event
.external_auth
.ssid_len
> SSID_MAX_LEN
)
2210 os_memcpy(event
.external_auth
.ssid
, nla_data(tb
[NL80211_ATTR_SSID
]),
2211 event
.external_auth
.ssid_len
);
2213 os_memcpy(event
.external_auth
.bssid
, nla_data(tb
[NL80211_ATTR_BSSID
]),
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
);
2223 static void do_process_drv_event(struct i802_bss
*bss
, int cmd
,
2226 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
2227 union wpa_event_data data
;
2228 int external_scan_event
= 0;
2230 wpa_printf(MSG_DEBUG
, "nl80211: Drv Event %d (%s) received for %s",
2231 cmd
, nl80211_command_to_string(cmd
), bss
->ifname
);
2233 if (cmd
== NL80211_CMD_ROAM
&&
2234 (drv
->capa
.flags
& WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD
)) {
2236 * Device will use roam+auth vendor event to indicate
2237 * roaming, so ignore the regular roam event.
2239 wpa_printf(MSG_DEBUG
,
2240 "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
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
;
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
) {
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
2264 wpa_printf(MSG_DEBUG
, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
2267 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_STARTED
, NULL
);
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
;
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
);
2278 case NL80211_CMD_NEW_SCAN_RESULTS
:
2279 wpa_dbg(drv
->ctx
, MSG_DEBUG
,
2280 "nl80211: New scan results available");
2281 if (drv
->last_scan_cmd
!= NL80211_CMD_VENDOR
)
2282 drv
->scan_state
= SCAN_COMPLETED
;
2283 drv
->scan_complete_events
= 1;
2284 if (drv
->last_scan_cmd
== NL80211_CMD_TRIGGER_SCAN
) {
2285 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout
,
2287 drv
->last_scan_cmd
= 0;
2289 external_scan_event
= 1;
2291 send_scan_event(drv
, 0, tb
, external_scan_event
);
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
;
2297 send_scan_event(drv
, 0, tb
, 0);
2299 case NL80211_CMD_SCAN_ABORTED
:
2300 wpa_dbg(drv
->ctx
, MSG_DEBUG
, "nl80211: Scan aborted");
2301 if (drv
->last_scan_cmd
!= NL80211_CMD_VENDOR
)
2302 drv
->scan_state
= SCAN_ABORTED
;
2303 if (drv
->last_scan_cmd
== NL80211_CMD_TRIGGER_SCAN
) {
2305 * Need to indicate that scan results are available in
2306 * order not to make wpa_supplicant stop its scanning.
2308 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout
,
2310 drv
->last_scan_cmd
= 0;
2312 external_scan_event
= 1;
2314 send_scan_event(drv
, 1, tb
, external_scan_event
);
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
],
2327 tb
[NL80211_ATTR_RX_SIGNAL_DBM
],
2328 tb
[NL80211_ATTR_STA_WME
]);
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
],
2337 tb
[NL80211_ATTR_TIMED_OUT
],
2338 tb
[NL80211_ATTR_TIMEOUT_REASON
],
2340 tb
[NL80211_ATTR_FILS_KEK
],
2342 tb
[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM
],
2343 tb
[NL80211_ATTR_PMK
],
2344 tb
[NL80211_ATTR_PMKID
]);
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
]);
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
]);
2360 case NL80211_CMD_MICHAEL_MIC_FAILURE
:
2361 mlme_event_michael_mic_failure(bss
, tb
);
2363 case NL80211_CMD_JOIN_IBSS
:
2364 mlme_event_join_ibss(drv
, tb
);
2366 case NL80211_CMD_REMAIN_ON_CHANNEL
:
2367 mlme_event_remain_on_channel(drv
, 0, tb
);
2369 case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL
:
2370 mlme_event_remain_on_channel(drv
, 1, tb
);
2372 case NL80211_CMD_NOTIFY_CQM
:
2373 nl80211_cqm_event(drv
, tb
);
2375 case NL80211_CMD_REG_CHANGE
:
2376 nl80211_reg_change_event(drv
, tb
);
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
,
2385 case NL80211_CMD_NEW_STATION
:
2386 nl80211_new_station_event(drv
, bss
, tb
);
2388 case NL80211_CMD_DEL_STATION
:
2389 nl80211_del_station_event(drv
, bss
, tb
);
2391 case NL80211_CMD_SET_REKEY_OFFLOAD
:
2392 nl80211_rekey_offload_event(drv
, tb
);
2394 case NL80211_CMD_PMKSA_CANDIDATE
:
2395 nl80211_pmksa_candidate_event(drv
, tb
);
2397 case NL80211_CMD_PROBE_CLIENT
:
2398 nl80211_client_probe_event(drv
, tb
);
2400 case NL80211_CMD_TDLS_OPER
:
2401 nl80211_tdls_oper_event(drv
, tb
);
2403 case NL80211_CMD_CONN_FAILED
:
2404 nl80211_connect_failed_event(drv
, tb
);
2406 case NL80211_CMD_FT_EVENT
:
2407 mlme_event_ft_event(drv
, tb
);
2409 case NL80211_CMD_RADAR_DETECT
:
2410 nl80211_radar_event(drv
, tb
);
2412 case NL80211_CMD_STOP_AP
:
2413 nl80211_stop_ap(drv
, tb
);
2415 case NL80211_CMD_VENDOR
:
2416 nl80211_vendor_event(drv
, tb
);
2418 case NL80211_CMD_NEW_PEER_CANDIDATE
:
2419 nl80211_new_peer_candidate(drv
, tb
);
2422 wpa_dbg(drv
->ctx
, MSG_DEBUG
, "nl80211: Ignored unknown event "
2429 int process_global_event(struct nl_msg
*msg
, void *arg
)
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
;
2435 int ifidx
= -1, wiphy_idx
= -1, wiphy_idx_rx
= -1;
2436 struct i802_bss
*bss
;
2438 int wdev_id_set
= 0;
2439 int wiphy_idx_set
= 0;
2441 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2442 genlmsg_attrlen(gnlh
, 0), NULL
);
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
]);
2449 } else if (tb
[NL80211_ATTR_WIPHY
]) {
2450 wiphy_idx_rx
= nla_get_u32(tb
[NL80211_ATTR_WIPHY
]);
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
) {
2458 wiphy_idx
= nl80211_get_wiphy_index(bss
);
2459 if ((ifidx
== -1 && !wiphy_idx_set
&& !wdev_id_set
) ||
2460 ifidx
== bss
->ifindex
||
2461 (wiphy_idx_set
&& wiphy_idx
== wiphy_idx_rx
) ||
2462 (wdev_id_set
&& bss
->wdev_id_set
&&
2463 wdev_id
== bss
->wdev_id
)) {
2464 do_process_drv_event(bss
, gnlh
->cmd
, tb
);
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
);
2477 int process_bss_event(struct nl_msg
*msg
, void *arg
)
2479 struct i802_bss
*bss
= arg
;
2480 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2481 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2483 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2484 genlmsg_attrlen(gnlh
, 0), NULL
);
2486 wpa_printf(MSG_DEBUG
, "nl80211: BSS Event %d (%s) received for %s",
2487 gnlh
->cmd
, nl80211_command_to_string(gnlh
->cmd
),
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
],
2497 tb
[NL80211_ATTR_RX_SIGNAL_DBM
],
2498 tb
[NL80211_ATTR_STA_WME
]);
2500 case NL80211_CMD_UNEXPECTED_FRAME
:
2501 nl80211_spurious_frame(bss
, tb
, 0);
2503 case NL80211_CMD_UNEXPECTED_4ADDR_FRAME
:
2504 nl80211_spurious_frame(bss
, tb
, 1);
2506 case NL80211_CMD_EXTERNAL_AUTH
:
2507 nl80211_external_auth(bss
->drv
, tb
);
2510 wpa_printf(MSG_DEBUG
, "nl80211: Ignored unknown event "
2511 "(cmd=%d)", gnlh
->cmd
);