From 159a17916f68f62f4ff4570b7eee8eeeb109f05a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 26 Oct 2014 16:23:46 +0200 Subject: [PATCH] nl80211: Move more event processing into driver_nl80211_event.c Signed-off-by: Jouni Malinen --- src/drivers/driver_nl80211.c | 1239 --------------------------- src/drivers/driver_nl80211.h | 25 +- src/drivers/driver_nl80211_event.c | 1282 +++++++++++++++++++++++++++- 3 files changed, 1265 insertions(+), 1281 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 9e0b71410..6dea23efb 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -186,122 +186,6 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); static int i802_set_iface_flags(struct i802_bss *bss, int up); -const char * nl80211_command_to_string(enum nl80211_commands cmd) -{ -#define C2S(x) case x: return #x; - switch (cmd) { - C2S(NL80211_CMD_UNSPEC) - C2S(NL80211_CMD_GET_WIPHY) - C2S(NL80211_CMD_SET_WIPHY) - C2S(NL80211_CMD_NEW_WIPHY) - C2S(NL80211_CMD_DEL_WIPHY) - C2S(NL80211_CMD_GET_INTERFACE) - C2S(NL80211_CMD_SET_INTERFACE) - C2S(NL80211_CMD_NEW_INTERFACE) - C2S(NL80211_CMD_DEL_INTERFACE) - C2S(NL80211_CMD_GET_KEY) - C2S(NL80211_CMD_SET_KEY) - C2S(NL80211_CMD_NEW_KEY) - C2S(NL80211_CMD_DEL_KEY) - C2S(NL80211_CMD_GET_BEACON) - C2S(NL80211_CMD_SET_BEACON) - C2S(NL80211_CMD_START_AP) - C2S(NL80211_CMD_STOP_AP) - C2S(NL80211_CMD_GET_STATION) - C2S(NL80211_CMD_SET_STATION) - C2S(NL80211_CMD_NEW_STATION) - C2S(NL80211_CMD_DEL_STATION) - C2S(NL80211_CMD_GET_MPATH) - C2S(NL80211_CMD_SET_MPATH) - C2S(NL80211_CMD_NEW_MPATH) - C2S(NL80211_CMD_DEL_MPATH) - C2S(NL80211_CMD_SET_BSS) - C2S(NL80211_CMD_SET_REG) - C2S(NL80211_CMD_REQ_SET_REG) - C2S(NL80211_CMD_GET_MESH_CONFIG) - C2S(NL80211_CMD_SET_MESH_CONFIG) - C2S(NL80211_CMD_SET_MGMT_EXTRA_IE) - C2S(NL80211_CMD_GET_REG) - C2S(NL80211_CMD_GET_SCAN) - C2S(NL80211_CMD_TRIGGER_SCAN) - C2S(NL80211_CMD_NEW_SCAN_RESULTS) - C2S(NL80211_CMD_SCAN_ABORTED) - C2S(NL80211_CMD_REG_CHANGE) - C2S(NL80211_CMD_AUTHENTICATE) - C2S(NL80211_CMD_ASSOCIATE) - C2S(NL80211_CMD_DEAUTHENTICATE) - C2S(NL80211_CMD_DISASSOCIATE) - C2S(NL80211_CMD_MICHAEL_MIC_FAILURE) - C2S(NL80211_CMD_REG_BEACON_HINT) - C2S(NL80211_CMD_JOIN_IBSS) - C2S(NL80211_CMD_LEAVE_IBSS) - C2S(NL80211_CMD_TESTMODE) - C2S(NL80211_CMD_CONNECT) - C2S(NL80211_CMD_ROAM) - C2S(NL80211_CMD_DISCONNECT) - C2S(NL80211_CMD_SET_WIPHY_NETNS) - C2S(NL80211_CMD_GET_SURVEY) - C2S(NL80211_CMD_NEW_SURVEY_RESULTS) - C2S(NL80211_CMD_SET_PMKSA) - C2S(NL80211_CMD_DEL_PMKSA) - C2S(NL80211_CMD_FLUSH_PMKSA) - C2S(NL80211_CMD_REMAIN_ON_CHANNEL) - C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL) - C2S(NL80211_CMD_SET_TX_BITRATE_MASK) - C2S(NL80211_CMD_REGISTER_FRAME) - C2S(NL80211_CMD_FRAME) - C2S(NL80211_CMD_FRAME_TX_STATUS) - C2S(NL80211_CMD_SET_POWER_SAVE) - C2S(NL80211_CMD_GET_POWER_SAVE) - C2S(NL80211_CMD_SET_CQM) - C2S(NL80211_CMD_NOTIFY_CQM) - C2S(NL80211_CMD_SET_CHANNEL) - C2S(NL80211_CMD_SET_WDS_PEER) - C2S(NL80211_CMD_FRAME_WAIT_CANCEL) - C2S(NL80211_CMD_JOIN_MESH) - C2S(NL80211_CMD_LEAVE_MESH) - C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE) - C2S(NL80211_CMD_UNPROT_DISASSOCIATE) - C2S(NL80211_CMD_NEW_PEER_CANDIDATE) - C2S(NL80211_CMD_GET_WOWLAN) - C2S(NL80211_CMD_SET_WOWLAN) - C2S(NL80211_CMD_START_SCHED_SCAN) - C2S(NL80211_CMD_STOP_SCHED_SCAN) - C2S(NL80211_CMD_SCHED_SCAN_RESULTS) - C2S(NL80211_CMD_SCHED_SCAN_STOPPED) - C2S(NL80211_CMD_SET_REKEY_OFFLOAD) - C2S(NL80211_CMD_PMKSA_CANDIDATE) - C2S(NL80211_CMD_TDLS_OPER) - C2S(NL80211_CMD_TDLS_MGMT) - C2S(NL80211_CMD_UNEXPECTED_FRAME) - C2S(NL80211_CMD_PROBE_CLIENT) - C2S(NL80211_CMD_REGISTER_BEACONS) - C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME) - C2S(NL80211_CMD_SET_NOACK_MAP) - C2S(NL80211_CMD_CH_SWITCH_NOTIFY) - C2S(NL80211_CMD_START_P2P_DEVICE) - C2S(NL80211_CMD_STOP_P2P_DEVICE) - C2S(NL80211_CMD_CONN_FAILED) - C2S(NL80211_CMD_SET_MCAST_RATE) - C2S(NL80211_CMD_SET_MAC_ACL) - C2S(NL80211_CMD_RADAR_DETECT) - C2S(NL80211_CMD_GET_PROTOCOL_FEATURES) - C2S(NL80211_CMD_UPDATE_FT_IES) - C2S(NL80211_CMD_FT_EVENT) - C2S(NL80211_CMD_CRIT_PROTOCOL_START) - C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) - C2S(NL80211_CMD_GET_COALESCE) - C2S(NL80211_CMD_SET_COALESCE) - C2S(NL80211_CMD_CHANNEL_SWITCH) - C2S(NL80211_CMD_VENDOR) - C2S(NL80211_CMD_SET_QOS_MAP) - default: - return "NL80211_CMD_UNKNOWN"; - } -#undef C2S -} - - /* Converts nl80211_chan_width to a common format */ enum chan_width convert2width(int width) { @@ -1254,209 +1138,6 @@ nla_put_failure: } -static void mlme_event_michael_mic_failure(struct i802_bss *bss, - struct nlattr *tb[]) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); - os_memset(&data, 0, sizeof(data)); - if (tb[NL80211_ATTR_MAC]) { - wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", - nla_data(tb[NL80211_ATTR_MAC]), - nla_len(tb[NL80211_ATTR_MAC])); - data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); - } - if (tb[NL80211_ATTR_KEY_SEQ]) { - wpa_hexdump(MSG_DEBUG, "nl80211: TSC", - nla_data(tb[NL80211_ATTR_KEY_SEQ]), - nla_len(tb[NL80211_ATTR_KEY_SEQ])); - } - if (tb[NL80211_ATTR_KEY_TYPE]) { - enum nl80211_key_type key_type = - nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); - wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); - if (key_type == NL80211_KEYTYPE_PAIRWISE) - data.michael_mic_failure.unicast = 1; - } else - data.michael_mic_failure.unicast = 1; - - if (tb[NL80211_ATTR_KEY_IDX]) { - u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); - wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); - } - - wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -} - - -static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - unsigned int freq; - - if (tb[NL80211_ATTR_MAC] == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " - "event"); - return; - } - os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - drv->associated = 1; - wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", - MAC2STR(drv->bssid)); - - freq = nl80211_get_assoc_freq(drv); - if (freq) { - wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz", - freq); - drv->first_bss->freq = freq; - } - - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -} - - -static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, - int cancel_event, struct nlattr *tb[]) -{ - unsigned int freq, chan_type, duration; - union wpa_event_data data; - u64 cookie; - - if (tb[NL80211_ATTR_WIPHY_FREQ]) - freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - else - freq = 0; - - if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) - chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - else - chan_type = 0; - - if (tb[NL80211_ATTR_DURATION]) - duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); - else - duration = 0; - - if (tb[NL80211_ATTR_COOKIE]) - cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); - else - cookie = 0; - - wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " - "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", - cancel_event, freq, chan_type, duration, - (long long unsigned int) cookie, - cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); - - if (cookie != drv->remain_on_chan_cookie) - return; /* not for us */ - - if (cancel_event) - drv->pending_remain_on_chan = 0; - - os_memset(&data, 0, sizeof(data)); - data.remain_on_channel.freq = freq; - data.remain_on_channel.duration = duration; - wpa_supplicant_event(drv->ctx, cancel_event ? - EVENT_CANCEL_REMAIN_ON_CHANNEL : - EVENT_REMAIN_ON_CHANNEL, &data); -} - - -static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - union wpa_event_data data; - - os_memset(&data, 0, sizeof(data)); - - if (tb[NL80211_ATTR_IE]) { - data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]); - data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]); - } - - if (tb[NL80211_ATTR_IE_RIC]) { - data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]); - data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]); - } - - if (tb[NL80211_ATTR_MAC]) - os_memcpy(data.ft_ies.target_ap, - nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR, - MAC2STR(data.ft_ies.target_ap)); - - wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data); -} - - -static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, - struct nlattr *tb[]) -{ - union wpa_event_data event; - struct nlattr *nl; - int rem; - struct scan_info *info; -#define MAX_REPORT_FREQS 50 - int freqs[MAX_REPORT_FREQS]; - int num_freqs = 0; - - if (drv->scan_for_auth) { - drv->scan_for_auth = 0; - wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " - "cfg80211 BSS entry"); - wpa_driver_nl80211_authenticate_retry(drv); - return; - } - - os_memset(&event, 0, sizeof(event)); - info = &event.scan_info; - info->aborted = aborted; - - if (tb[NL80211_ATTR_SCAN_SSIDS]) { - nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { - struct wpa_driver_scan_ssid *s = - &info->ssids[info->num_ssids]; - s->ssid = nla_data(nl); - s->ssid_len = nla_len(nl); - wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'", - wpa_ssid_txt(s->ssid, s->ssid_len)); - info->num_ssids++; - if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) - break; - } - } - if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[200], *pos, *end; - int res; - - pos = msg; - end = pos + sizeof(msg); - *pos = '\0'; - - nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) - { - freqs[num_freqs] = nla_get_u32(nl); - res = os_snprintf(pos, end - pos, " %d", - freqs[num_freqs]); - if (res > 0 && end - pos > res) - pos += res; - num_freqs++; - if (num_freqs == MAX_REPORT_FREQS - 1) - break; - } - info->freqs = freqs; - info->num_freqs = num_freqs; - wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", - msg); - } - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); -} - - static int get_link_signal(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -1677,926 +1358,6 @@ static int nl80211_get_noise_for_scan_results( } -static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { - [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, - [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, - [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, - [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, - }; - struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; - enum nl80211_cqm_rssi_threshold_event event; - union wpa_event_data ed; - struct wpa_signal_info sig; - int res; - - if (tb[NL80211_ATTR_CQM] == NULL || - nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], - cqm_policy)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); - return; - } - - os_memset(&ed, 0, sizeof(ed)); - - if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { - if (!tb[NL80211_ATTR_MAC]) - return; - os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), - ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); - return; - } - - if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) - return; - event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); - - if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { - wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " - "event: RSSI high"); - ed.signal_change.above_threshold = 1; - } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { - wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " - "event: RSSI low"); - ed.signal_change.above_threshold = 0; - } else - return; - - res = nl80211_get_link_signal(drv, &sig); - if (res == 0) { - ed.signal_change.current_signal = sig.current_signal; - ed.signal_change.current_txrate = sig.current_txrate; - wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", - sig.current_signal, sig.current_txrate); - } - - res = nl80211_get_link_noise(drv, &sig); - if (res == 0) { - ed.signal_change.current_noise = sig.current_noise; - wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm", - sig.current_noise); - } - - wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); -} - - -static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - const u8 *addr; - union wpa_event_data data; - - if (drv->nlmode != NL80211_IFTYPE_MESH_POINT) - return; - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE]) - return; - - addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR, - MAC2STR(addr)); - - os_memset(&data, 0, sizeof(data)); - data.mesh_peer.peer = addr; - data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]); - data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]); - wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data); -} - - -static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u8 *addr; - union wpa_event_data data; - - if (tb[NL80211_ATTR_MAC] == NULL) - return; - addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); - - if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - u8 *ies = NULL; - size_t ies_len = 0; - if (tb[NL80211_ATTR_IE]) { - ies = nla_data(tb[NL80211_ATTR_IE]); - ies_len = nla_len(tb[NL80211_ATTR_IE]); - } - wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len); - drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); - return; - } - - if (drv->nlmode != NL80211_IFTYPE_ADHOC) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); -} - - -static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u8 *addr; - union wpa_event_data data; - - if (tb[NL80211_ATTR_MAC] == NULL) - return; - addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, - MAC2STR(addr)); - - if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - drv_event_disassoc(drv->ctx, addr); - return; - } - - if (drv->nlmode != NL80211_IFTYPE_ADHOC) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); - wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); -} - - -static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; - static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { - [NL80211_REKEY_DATA_KEK] = { - .minlen = NL80211_KEK_LEN, - .maxlen = NL80211_KEK_LEN, - }, - [NL80211_REKEY_DATA_KCK] = { - .minlen = NL80211_KCK_LEN, - .maxlen = NL80211_KCK_LEN, - }, - [NL80211_REKEY_DATA_REPLAY_CTR] = { - .minlen = NL80211_REPLAY_CTR_LEN, - .maxlen = NL80211_REPLAY_CTR_LEN, - }, - }; - union wpa_event_data data; - - if (!tb[NL80211_ATTR_MAC]) - return; - if (!tb[NL80211_ATTR_REKEY_DATA]) - return; - if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, - tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) - return; - if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) - return; - - os_memset(&data, 0, sizeof(data)); - data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR, - MAC2STR(data.driver_gtk_rekey.bssid)); - data.driver_gtk_rekey.replay_ctr = - nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); - wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter", - data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); - wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); -} - - -static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; - static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { - [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, - [NL80211_PMKSA_CANDIDATE_BSSID] = { - .minlen = ETH_ALEN, - .maxlen = ETH_ALEN, - }, - [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, - }; - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event"); - - if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) - return; - if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, - tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) - return; - if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || - !cand[NL80211_PMKSA_CANDIDATE_BSSID]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.pmkid_candidate.bssid, - nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); - data.pmkid_candidate.index = - nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); - data.pmkid_candidate.preauth = - cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; - wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); -} - - -static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: Probe client event"); - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.client_poll.addr, - nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); -} - - -static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event"); - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) { - case NL80211_TDLS_SETUP: - wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer " - MACSTR, MAC2STR(data.tdls.peer)); - data.tdls.oper = TDLS_REQUEST_SETUP; - break; - case NL80211_TDLS_TEARDOWN: - wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer " - MACSTR, MAC2STR(data.tdls.peer)); - data.tdls.oper = TDLS_REQUEST_TEARDOWN; - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione " - "event"); - return; - } - if (tb[NL80211_ATTR_REASON_CODE]) { - data.tdls.reason_code = - nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); - } - - wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data); -} - - -static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL); -} - - -static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - u32 reason; - - wpa_printf(MSG_DEBUG, "nl80211: Connect failed event"); - - if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON]) - return; - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.connect_failed_reason.addr, - nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - - reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]); - switch (reason) { - case NL80211_CONN_FAIL_MAX_CLIENTS: - wpa_printf(MSG_DEBUG, "nl80211: Max client reached"); - data.connect_failed_reason.code = MAX_CLIENT_REACHED; - break; - case NL80211_CONN_FAIL_BLOCKED_CLIENT: - wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR - " tried to connect", - MAC2STR(data.connect_failed_reason.addr)); - data.connect_failed_reason.code = BLOCKED_CLIENT; - break; - default: - wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason " - "%u", reason); - return; - } - - wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data); -} - - -static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - union wpa_event_data data; - enum nl80211_radar_event event_type; - - if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT]) - return; - - os_memset(&data, 0, sizeof(data)); - data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); - - /* Check HT params */ - if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - data.dfs_event.ht_enabled = 1; - data.dfs_event.chan_offset = 0; - - switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { - case NL80211_CHAN_NO_HT: - data.dfs_event.ht_enabled = 0; - break; - case NL80211_CHAN_HT20: - break; - case NL80211_CHAN_HT40PLUS: - data.dfs_event.chan_offset = 1; - break; - case NL80211_CHAN_HT40MINUS: - data.dfs_event.chan_offset = -1; - break; - } - } - - /* Get VHT params */ - if (tb[NL80211_ATTR_CHANNEL_WIDTH]) - data.dfs_event.chan_width = - convert2width(nla_get_u32( - tb[NL80211_ATTR_CHANNEL_WIDTH])); - if (tb[NL80211_ATTR_CENTER_FREQ1]) - data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); - if (tb[NL80211_ATTR_CENTER_FREQ2]) - data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); - - wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", - data.dfs_event.freq, data.dfs_event.ht_enabled, - data.dfs_event.chan_offset, data.dfs_event.chan_width, - data.dfs_event.cf1, data.dfs_event.cf2); - - switch (event_type) { - case NL80211_RADAR_DETECTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); - break; - case NL80211_RADAR_CAC_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); - break; - case NL80211_RADAR_CAC_ABORTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); - break; - case NL80211_RADAR_NOP_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d " - "received", event_type); - break; - } -} - - -static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, - int wds) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - union wpa_event_data event; - - if (!tb[NL80211_ATTR_MAC]) - return; - - os_memset(&event, 0, sizeof(event)); - event.rx_from_unknown.bssid = bss->addr; - event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); - event.rx_from_unknown.wds = wds; - - wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); -} - - -static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, - const u8 *data, size_t len) -{ - u32 i, count; - union wpa_event_data event; - struct wpa_freq_range *range = NULL; - const struct qca_avoid_freq_list *freq_range; - - freq_range = (const struct qca_avoid_freq_list *) data; - if (len < sizeof(freq_range->count)) - return; - - count = freq_range->count; - if (len < sizeof(freq_range->count) + - count * sizeof(struct qca_avoid_freq_range)) { - wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)", - (unsigned int) len); - return; - } - - if (count > 0) { - range = os_calloc(count, sizeof(struct wpa_freq_range)); - if (range == NULL) - return; - } - - os_memset(&event, 0, sizeof(event)); - for (i = 0; i < count; i++) { - unsigned int idx = event.freq_range.num; - range[idx].min = freq_range->range[i].start_freq; - range[idx].max = freq_range->range[i].end_freq; - wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u", - range[idx].min, range[idx].max); - if (range[idx].min > range[idx].max) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range"); - continue; - } - event.freq_range.num++; - } - event.freq_range.range = range; - - wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event); - - os_free(range); -} - - -static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, - const u8 *data, size_t len) -{ - struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1]; - u8 *bssid; - - wpa_printf(MSG_DEBUG, - "nl80211: Key management roam+auth vendor event received"); - - if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX, - (struct nlattr *) data, len, NULL)) - return; - if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] || - nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN || - !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] || - !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] || - !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED]) - return; - - bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); - wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid)); - - mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]); -} - - -static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, - u32 subcmd, u8 *data, size_t len) -{ - switch (subcmd) { - case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: - qca_nl80211_avoid_freq(drv, data, len); - break; - case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: - qca_nl80211_key_mgmt_auth(drv, data, len); - break; - default: - wpa_printf(MSG_DEBUG, - "nl80211: Ignore unsupported QCA vendor event %u", - subcmd); - break; - } -} - - -static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) -{ - u32 vendor_id, subcmd, wiphy = 0; - int wiphy_idx; - u8 *data = NULL; - size_t len = 0; - - if (!tb[NL80211_ATTR_VENDOR_ID] || - !tb[NL80211_ATTR_VENDOR_SUBCMD]) - return; - - vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); - subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); - - if (tb[NL80211_ATTR_WIPHY]) - wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); - - wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", - wiphy, vendor_id, subcmd); - - if (tb[NL80211_ATTR_VENDOR_DATA]) { - data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); - len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); - wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); - } - - wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); - if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { - wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", - wiphy, wiphy_idx); - return; - } - - switch (vendor_id) { - case OUI_QCA: - nl80211_vendor_event_qca(drv, subcmd, data, len); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); - break; - } -} - - -static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv, - struct nlattr *tb[]) -{ - union wpa_event_data data; - enum nl80211_reg_initiator init; - - wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change"); - - if (tb[NL80211_ATTR_REG_INITIATOR] == NULL) - return; - - os_memset(&data, 0, sizeof(data)); - init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]); - wpa_printf(MSG_DEBUG, " * initiator=%d", init); - switch (init) { - case NL80211_REGDOM_SET_BY_CORE: - data.channel_list_changed.initiator = REGDOM_SET_BY_CORE; - break; - case NL80211_REGDOM_SET_BY_USER: - data.channel_list_changed.initiator = REGDOM_SET_BY_USER; - break; - case NL80211_REGDOM_SET_BY_DRIVER: - data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER; - break; - case NL80211_REGDOM_SET_BY_COUNTRY_IE: - data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE; - break; - } - - if (tb[NL80211_ATTR_REG_TYPE]) { - enum nl80211_reg_type type; - type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); - wpa_printf(MSG_DEBUG, " * type=%d", type); - switch (type) { - case NL80211_REGDOM_TYPE_COUNTRY: - data.channel_list_changed.type = REGDOM_TYPE_COUNTRY; - break; - case NL80211_REGDOM_TYPE_WORLD: - data.channel_list_changed.type = REGDOM_TYPE_WORLD; - break; - case NL80211_REGDOM_TYPE_CUSTOM_WORLD: - data.channel_list_changed.type = - REGDOM_TYPE_CUSTOM_WORLD; - break; - case NL80211_REGDOM_TYPE_INTERSECTION: - data.channel_list_changed.type = - REGDOM_TYPE_INTERSECTION; - break; - } - } - - if (tb[NL80211_ATTR_REG_ALPHA2]) { - os_strlcpy(data.channel_list_changed.alpha2, - nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), - sizeof(data.channel_list_changed.alpha2)); - wpa_printf(MSG_DEBUG, " * alpha2=%s", - data.channel_list_changed.alpha2); - } - - wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data); -} - - -static void do_process_drv_event(struct i802_bss *bss, int cmd, - struct nlattr **tb) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - union wpa_event_data data; - - wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", - cmd, nl80211_command_to_string(cmd), bss->ifname); - - if (cmd == NL80211_CMD_ROAM && drv->roam_auth_vendor_event_avail) { - /* - * Device will use roam+auth vendor event to indicate - * roaming, so ignore the regular roam event. - */ - wpa_printf(MSG_DEBUG, - "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth", - cmd); - return; - } - - if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && - (cmd == NL80211_CMD_NEW_SCAN_RESULTS || - cmd == NL80211_CMD_SCAN_ABORTED)) { - wpa_driver_nl80211_set_mode(drv->first_bss, - drv->ap_scan_as_station); - drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; - } - - switch (cmd) { - case NL80211_CMD_TRIGGER_SCAN: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); - drv->scan_state = SCAN_STARTED; - if (drv->scan_for_auth) { - /* - * Cannot indicate EVENT_SCAN_STARTED here since we skip - * EVENT_SCAN_RESULTS in scan_for_auth case and the - * upper layer implementation could get confused about - * scanning state. - */ - wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth"); - break; - } - wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); - break; - case NL80211_CMD_START_SCHED_SCAN: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); - drv->scan_state = SCHED_SCAN_STARTED; - break; - case NL80211_CMD_SCHED_SCAN_STOPPED: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped"); - drv->scan_state = SCHED_SCAN_STOPPED; - wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); - break; - case NL80211_CMD_NEW_SCAN_RESULTS: - wpa_dbg(drv->ctx, MSG_DEBUG, - "nl80211: New scan results available"); - drv->scan_state = SCAN_COMPLETED; - drv->scan_complete_events = 1; - eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, - drv->ctx); - send_scan_event(drv, 0, tb); - break; - case NL80211_CMD_SCHED_SCAN_RESULTS: - wpa_dbg(drv->ctx, MSG_DEBUG, - "nl80211: New sched scan results available"); - drv->scan_state = SCHED_SCAN_RESULTS; - send_scan_event(drv, 0, tb); - break; - case NL80211_CMD_SCAN_ABORTED: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted"); - drv->scan_state = SCAN_ABORTED; - /* - * Need to indicate that scan results are available in order - * not to make wpa_supplicant stop its scanning. - */ - eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, - drv->ctx); - send_scan_event(drv, 1, tb); - break; - case NL80211_CMD_AUTHENTICATE: - case NL80211_CMD_ASSOCIATE: - case NL80211_CMD_DEAUTHENTICATE: - case NL80211_CMD_DISASSOCIATE: - case NL80211_CMD_FRAME_TX_STATUS: - case NL80211_CMD_UNPROT_DEAUTHENTICATE: - case NL80211_CMD_UNPROT_DISASSOCIATE: - mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME], - tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], - tb[NL80211_ATTR_COOKIE], - tb[NL80211_ATTR_RX_SIGNAL_DBM]); - break; - case NL80211_CMD_CONNECT: - case NL80211_CMD_ROAM: - mlme_event_connect(drv, cmd, - tb[NL80211_ATTR_STATUS_CODE], - tb[NL80211_ATTR_MAC], - tb[NL80211_ATTR_REQ_IE], - tb[NL80211_ATTR_RESP_IE], - NULL, NULL, NULL, NULL); - break; - case NL80211_CMD_CH_SWITCH_NOTIFY: - mlme_event_ch_switch(drv, - tb[NL80211_ATTR_IFINDEX], - tb[NL80211_ATTR_WIPHY_FREQ], - tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], - tb[NL80211_ATTR_CHANNEL_WIDTH], - tb[NL80211_ATTR_CENTER_FREQ1], - tb[NL80211_ATTR_CENTER_FREQ2]); - break; - case NL80211_CMD_DISCONNECT: - mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], - tb[NL80211_ATTR_MAC], - tb[NL80211_ATTR_DISCONNECTED_BY_AP]); - break; - case NL80211_CMD_MICHAEL_MIC_FAILURE: - mlme_event_michael_mic_failure(bss, tb); - break; - case NL80211_CMD_JOIN_IBSS: - mlme_event_join_ibss(drv, tb); - break; - case NL80211_CMD_REMAIN_ON_CHANNEL: - mlme_event_remain_on_channel(drv, 0, tb); - break; - case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: - mlme_event_remain_on_channel(drv, 1, tb); - break; - case NL80211_CMD_NOTIFY_CQM: - nl80211_cqm_event(drv, tb); - break; - case NL80211_CMD_REG_CHANGE: - nl80211_reg_change_event(drv, tb); - break; - case NL80211_CMD_REG_BEACON_HINT: - wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint"); - os_memset(&data, 0, sizeof(data)); - data.channel_list_changed.initiator = REGDOM_BEACON_HINT; - wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, - &data); - break; - case NL80211_CMD_NEW_STATION: - nl80211_new_station_event(drv, tb); - break; - case NL80211_CMD_DEL_STATION: - nl80211_del_station_event(drv, tb); - break; - case NL80211_CMD_SET_REKEY_OFFLOAD: - nl80211_rekey_offload_event(drv, tb); - break; - case NL80211_CMD_PMKSA_CANDIDATE: - nl80211_pmksa_candidate_event(drv, tb); - break; - case NL80211_CMD_PROBE_CLIENT: - nl80211_client_probe_event(drv, tb); - break; - case NL80211_CMD_TDLS_OPER: - nl80211_tdls_oper_event(drv, tb); - break; - case NL80211_CMD_CONN_FAILED: - nl80211_connect_failed_event(drv, tb); - break; - case NL80211_CMD_FT_EVENT: - mlme_event_ft_event(drv, tb); - break; - case NL80211_CMD_RADAR_DETECT: - nl80211_radar_event(drv, tb); - break; - case NL80211_CMD_STOP_AP: - nl80211_stop_ap(drv, tb); - break; - case NL80211_CMD_VENDOR: - nl80211_vendor_event(drv, tb); - break; - case NL80211_CMD_NEW_PEER_CANDIDATE: - nl80211_new_peer_candidate(drv, tb); - break; - default: - wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " - "(cmd=%d)", cmd); - break; - } -} - - -static int process_drv_event(struct nl_msg *msg, void *arg) -{ - struct wpa_driver_nl80211_data *drv = arg; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct i802_bss *bss; - int ifidx = -1; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb[NL80211_ATTR_IFINDEX]) { - ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - - for (bss = drv->first_bss; bss; bss = bss->next) - if (ifidx == -1 || ifidx == bss->ifindex) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - wpa_printf(MSG_DEBUG, - "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)", - gnlh->cmd, ifidx); - } else if (tb[NL80211_ATTR_WDEV]) { - u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); - wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device"); - for (bss = drv->first_bss; bss; bss = bss->next) { - if (bss->wdev_id_set && wdev_id == bss->wdev_id) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - } - wpa_printf(MSG_DEBUG, - "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)", - gnlh->cmd, (long long unsigned int) wdev_id); - } - - return NL_SKIP; -} - - -static int process_global_event(struct nl_msg *msg, void *arg) -{ - struct nl80211_global *global = arg; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct wpa_driver_nl80211_data *drv, *tmp; - int ifidx = -1; - struct i802_bss *bss; - u64 wdev_id = 0; - int wdev_id_set = 0; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (tb[NL80211_ATTR_IFINDEX]) - ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - else if (tb[NL80211_ATTR_WDEV]) { - wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); - wdev_id_set = 1; - } - - dl_list_for_each_safe(drv, tmp, &global->interfaces, - struct wpa_driver_nl80211_data, list) { - for (bss = drv->first_bss; bss; bss = bss->next) { - if ((ifidx == -1 && !wdev_id_set) || - ifidx == bss->ifindex || - (wdev_id_set && bss->wdev_id_set && - wdev_id == bss->wdev_id)) { - do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; - } - } - } - - return NL_SKIP; -} - - -static int process_bss_event(struct nl_msg *msg, void *arg) -{ - struct i802_bss *bss = arg; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s", - gnlh->cmd, nl80211_command_to_string(gnlh->cmd), - bss->ifname); - - switch (gnlh->cmd) { - case NL80211_CMD_FRAME: - case NL80211_CMD_FRAME_TX_STATUS: - mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME], - tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], - tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], - tb[NL80211_ATTR_COOKIE], - tb[NL80211_ATTR_RX_SIGNAL_DBM]); - break; - case NL80211_CMD_UNEXPECTED_FRAME: - nl80211_spurious_frame(bss, tb, 0); - break; - case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: - nl80211_spurious_frame(bss, tb, 1); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " - "(cmd=%d)", gnlh->cmd); - break; - } - - return NL_SKIP; -} - - static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, void *handle) { diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 750a83be2..a7caf5bae 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -181,7 +181,6 @@ struct wpa_driver_nl80211_data { }; struct nl_msg; -struct nlattr; int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss); void * nl80211_cmd(struct wpa_driver_nl80211_data *drv, @@ -210,7 +209,6 @@ int nl80211_get_wiphy_index(struct i802_bss *bss); int wpa_driver_nl80211_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode); void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); -const char * nl80211_command_to_string(enum nl80211_commands cmd); int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv); void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv); @@ -222,26 +220,9 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv); struct hostapd_hw_modes * nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags); -void mlme_event_connect(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *status, - struct nlattr *addr, struct nlattr *req_ie, - struct nlattr *resp_ie, - struct nlattr *authorized, - struct nlattr *key_replay_ctr, - struct nlattr *ptk_kck, - struct nlattr *ptk_kek); -void mlme_event(struct i802_bss *bss, - enum nl80211_commands cmd, struct nlattr *frame, - struct nlattr *addr, struct nlattr *timed_out, - struct nlattr *freq, struct nlattr *ack, - struct nlattr *cookie, struct nlattr *sig); -void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2); -void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, - struct nlattr *reason, struct nlattr *addr, - struct nlattr *by_ap); +int process_global_event(struct nl_msg *msg, void *arg); +int process_drv_event(struct nl_msg *msg, void *arg); +int process_bss_event(struct nl_msg *msg, void *arg); #ifdef ANDROID int android_nl_socket_set_nonblocking(struct nl_handle *handle); diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 12594418f..7ba81688d 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -12,11 +12,130 @@ #include #include "utils/common.h" +#include "utils/eloop.h" +#include "common/qca-vendor.h" +#include "common/qca-vendor-attr.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "driver_nl80211.h" +static const char * nl80211_command_to_string(enum nl80211_commands cmd) +{ +#define C2S(x) case x: return #x; + switch (cmd) { + C2S(NL80211_CMD_UNSPEC) + C2S(NL80211_CMD_GET_WIPHY) + C2S(NL80211_CMD_SET_WIPHY) + C2S(NL80211_CMD_NEW_WIPHY) + C2S(NL80211_CMD_DEL_WIPHY) + C2S(NL80211_CMD_GET_INTERFACE) + C2S(NL80211_CMD_SET_INTERFACE) + C2S(NL80211_CMD_NEW_INTERFACE) + C2S(NL80211_CMD_DEL_INTERFACE) + C2S(NL80211_CMD_GET_KEY) + C2S(NL80211_CMD_SET_KEY) + C2S(NL80211_CMD_NEW_KEY) + C2S(NL80211_CMD_DEL_KEY) + C2S(NL80211_CMD_GET_BEACON) + C2S(NL80211_CMD_SET_BEACON) + C2S(NL80211_CMD_START_AP) + C2S(NL80211_CMD_STOP_AP) + C2S(NL80211_CMD_GET_STATION) + C2S(NL80211_CMD_SET_STATION) + C2S(NL80211_CMD_NEW_STATION) + C2S(NL80211_CMD_DEL_STATION) + C2S(NL80211_CMD_GET_MPATH) + C2S(NL80211_CMD_SET_MPATH) + C2S(NL80211_CMD_NEW_MPATH) + C2S(NL80211_CMD_DEL_MPATH) + C2S(NL80211_CMD_SET_BSS) + C2S(NL80211_CMD_SET_REG) + C2S(NL80211_CMD_REQ_SET_REG) + C2S(NL80211_CMD_GET_MESH_CONFIG) + C2S(NL80211_CMD_SET_MESH_CONFIG) + C2S(NL80211_CMD_SET_MGMT_EXTRA_IE) + C2S(NL80211_CMD_GET_REG) + C2S(NL80211_CMD_GET_SCAN) + C2S(NL80211_CMD_TRIGGER_SCAN) + C2S(NL80211_CMD_NEW_SCAN_RESULTS) + C2S(NL80211_CMD_SCAN_ABORTED) + C2S(NL80211_CMD_REG_CHANGE) + C2S(NL80211_CMD_AUTHENTICATE) + C2S(NL80211_CMD_ASSOCIATE) + C2S(NL80211_CMD_DEAUTHENTICATE) + C2S(NL80211_CMD_DISASSOCIATE) + C2S(NL80211_CMD_MICHAEL_MIC_FAILURE) + C2S(NL80211_CMD_REG_BEACON_HINT) + C2S(NL80211_CMD_JOIN_IBSS) + C2S(NL80211_CMD_LEAVE_IBSS) + C2S(NL80211_CMD_TESTMODE) + C2S(NL80211_CMD_CONNECT) + C2S(NL80211_CMD_ROAM) + C2S(NL80211_CMD_DISCONNECT) + C2S(NL80211_CMD_SET_WIPHY_NETNS) + C2S(NL80211_CMD_GET_SURVEY) + C2S(NL80211_CMD_NEW_SURVEY_RESULTS) + C2S(NL80211_CMD_SET_PMKSA) + C2S(NL80211_CMD_DEL_PMKSA) + C2S(NL80211_CMD_FLUSH_PMKSA) + C2S(NL80211_CMD_REMAIN_ON_CHANNEL) + C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL) + C2S(NL80211_CMD_SET_TX_BITRATE_MASK) + C2S(NL80211_CMD_REGISTER_FRAME) + C2S(NL80211_CMD_FRAME) + C2S(NL80211_CMD_FRAME_TX_STATUS) + C2S(NL80211_CMD_SET_POWER_SAVE) + C2S(NL80211_CMD_GET_POWER_SAVE) + C2S(NL80211_CMD_SET_CQM) + C2S(NL80211_CMD_NOTIFY_CQM) + C2S(NL80211_CMD_SET_CHANNEL) + C2S(NL80211_CMD_SET_WDS_PEER) + C2S(NL80211_CMD_FRAME_WAIT_CANCEL) + C2S(NL80211_CMD_JOIN_MESH) + C2S(NL80211_CMD_LEAVE_MESH) + C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE) + C2S(NL80211_CMD_UNPROT_DISASSOCIATE) + C2S(NL80211_CMD_NEW_PEER_CANDIDATE) + C2S(NL80211_CMD_GET_WOWLAN) + C2S(NL80211_CMD_SET_WOWLAN) + C2S(NL80211_CMD_START_SCHED_SCAN) + C2S(NL80211_CMD_STOP_SCHED_SCAN) + C2S(NL80211_CMD_SCHED_SCAN_RESULTS) + C2S(NL80211_CMD_SCHED_SCAN_STOPPED) + C2S(NL80211_CMD_SET_REKEY_OFFLOAD) + C2S(NL80211_CMD_PMKSA_CANDIDATE) + C2S(NL80211_CMD_TDLS_OPER) + C2S(NL80211_CMD_TDLS_MGMT) + C2S(NL80211_CMD_UNEXPECTED_FRAME) + C2S(NL80211_CMD_PROBE_CLIENT) + C2S(NL80211_CMD_REGISTER_BEACONS) + C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME) + C2S(NL80211_CMD_SET_NOACK_MAP) + C2S(NL80211_CMD_CH_SWITCH_NOTIFY) + C2S(NL80211_CMD_START_P2P_DEVICE) + C2S(NL80211_CMD_STOP_P2P_DEVICE) + C2S(NL80211_CMD_CONN_FAILED) + C2S(NL80211_CMD_SET_MCAST_RATE) + C2S(NL80211_CMD_SET_MAC_ACL) + C2S(NL80211_CMD_RADAR_DETECT) + C2S(NL80211_CMD_GET_PROTOCOL_FEATURES) + C2S(NL80211_CMD_UPDATE_FT_IES) + C2S(NL80211_CMD_FT_EVENT) + C2S(NL80211_CMD_CRIT_PROTOCOL_START) + C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) + C2S(NL80211_CMD_GET_COALESCE) + C2S(NL80211_CMD_SET_COALESCE) + C2S(NL80211_CMD_CHANNEL_SWITCH) + C2S(NL80211_CMD_VENDOR) + C2S(NL80211_CMD_SET_QOS_MAP) + default: + return "NL80211_CMD_UNKNOWN"; + } +#undef C2S +} + + static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, const u8 *frame, size_t len) { @@ -118,14 +237,14 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } -void mlme_event_connect(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *status, - struct nlattr *addr, struct nlattr *req_ie, - struct nlattr *resp_ie, - struct nlattr *authorized, - struct nlattr *key_replay_ctr, - struct nlattr *ptk_kck, - struct nlattr *ptk_kek) +static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, + enum nl80211_commands cmd, struct nlattr *status, + struct nlattr *addr, struct nlattr *req_ie, + struct nlattr *resp_ie, + struct nlattr *authorized, + struct nlattr *key_replay_ctr, + struct nlattr *ptk_kck, + struct nlattr *ptk_kek) { union wpa_event_data event; @@ -196,9 +315,9 @@ void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } -void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, - struct nlattr *reason, struct nlattr *addr, - struct nlattr *by_ap) +static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv, + struct nlattr *reason, struct nlattr *addr, + struct nlattr *by_ap) { union wpa_event_data data; unsigned int locally_generated = by_ap == NULL; @@ -262,10 +381,10 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) } -void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2) +static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, + struct nlattr *ifindex, struct nlattr *freq, + struct nlattr *type, struct nlattr *bw, + struct nlattr *cf1, struct nlattr *cf2) { struct i802_bss *bss; union wpa_event_data data; @@ -568,11 +687,11 @@ static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv, } -void mlme_event(struct i802_bss *bss, - enum nl80211_commands cmd, struct nlattr *frame, - struct nlattr *addr, struct nlattr *timed_out, - struct nlattr *freq, struct nlattr *ack, - struct nlattr *cookie, struct nlattr *sig) +static void mlme_event(struct i802_bss *bss, + enum nl80211_commands cmd, struct nlattr *frame, + struct nlattr *addr, struct nlattr *timed_out, + struct nlattr *freq, struct nlattr *ack, + struct nlattr *cookie, struct nlattr *sig) { struct wpa_driver_nl80211_data *drv = bss->drv; const u8 *data; @@ -649,3 +768,1126 @@ void mlme_event(struct i802_bss *bss, break; } } + + +static void mlme_event_michael_mic_failure(struct i802_bss *bss, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); + os_memset(&data, 0, sizeof(data)); + if (tb[NL80211_ATTR_MAC]) { + wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", + nla_data(tb[NL80211_ATTR_MAC]), + nla_len(tb[NL80211_ATTR_MAC])); + data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); + } + if (tb[NL80211_ATTR_KEY_SEQ]) { + wpa_hexdump(MSG_DEBUG, "nl80211: TSC", + nla_data(tb[NL80211_ATTR_KEY_SEQ]), + nla_len(tb[NL80211_ATTR_KEY_SEQ])); + } + if (tb[NL80211_ATTR_KEY_TYPE]) { + enum nl80211_key_type key_type = + nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); + wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); + if (key_type == NL80211_KEYTYPE_PAIRWISE) + data.michael_mic_failure.unicast = 1; + } else + data.michael_mic_failure.unicast = 1; + + if (tb[NL80211_ATTR_KEY_IDX]) { + u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); + wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); + } + + wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); +} + + +static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + unsigned int freq; + + if (tb[NL80211_ATTR_MAC] == NULL) { + wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " + "event"); + return; + } + os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + drv->associated = 1; + wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", + MAC2STR(drv->bssid)); + + freq = nl80211_get_assoc_freq(drv); + if (freq) { + wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz", + freq); + drv->first_bss->freq = freq; + } + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); +} + + +static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, + int cancel_event, struct nlattr *tb[]) +{ + unsigned int freq, chan_type, duration; + union wpa_event_data data; + u64 cookie; + + if (tb[NL80211_ATTR_WIPHY_FREQ]) + freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + else + freq = 0; + + if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) + chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + else + chan_type = 0; + + if (tb[NL80211_ATTR_DURATION]) + duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); + else + duration = 0; + + if (tb[NL80211_ATTR_COOKIE]) + cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + else + cookie = 0; + + wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " + "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", + cancel_event, freq, chan_type, duration, + (long long unsigned int) cookie, + cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); + + if (cookie != drv->remain_on_chan_cookie) + return; /* not for us */ + + if (cancel_event) + drv->pending_remain_on_chan = 0; + + os_memset(&data, 0, sizeof(data)); + data.remain_on_channel.freq = freq; + data.remain_on_channel.duration = duration; + wpa_supplicant_event(drv->ctx, cancel_event ? + EVENT_CANCEL_REMAIN_ON_CHANNEL : + EVENT_REMAIN_ON_CHANNEL, &data); +} + + +static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + os_memset(&data, 0, sizeof(data)); + + if (tb[NL80211_ATTR_IE]) { + data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]); + data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]); + } + + if (tb[NL80211_ATTR_IE_RIC]) { + data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]); + data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]); + } + + if (tb[NL80211_ATTR_MAC]) + os_memcpy(data.ft_ies.target_ap, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR, + MAC2STR(data.ft_ies.target_ap)); + + wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data); +} + + +static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, + struct nlattr *tb[]) +{ + union wpa_event_data event; + struct nlattr *nl; + int rem; + struct scan_info *info; +#define MAX_REPORT_FREQS 50 + int freqs[MAX_REPORT_FREQS]; + int num_freqs = 0; + + if (drv->scan_for_auth) { + drv->scan_for_auth = 0; + wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " + "cfg80211 BSS entry"); + wpa_driver_nl80211_authenticate_retry(drv); + return; + } + + os_memset(&event, 0, sizeof(event)); + info = &event.scan_info; + info->aborted = aborted; + + if (tb[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { + struct wpa_driver_scan_ssid *s = + &info->ssids[info->num_ssids]; + s->ssid = nla_data(nl); + s->ssid_len = nla_len(nl); + wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'", + wpa_ssid_txt(s->ssid, s->ssid_len)); + info->num_ssids++; + if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) + break; + } + } + if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { + char msg[200], *pos, *end; + int res; + + pos = msg; + end = pos + sizeof(msg); + *pos = '\0'; + + nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) + { + freqs[num_freqs] = nla_get_u32(nl); + res = os_snprintf(pos, end - pos, " %d", + freqs[num_freqs]); + if (res > 0 && end - pos > res) + pos += res; + num_freqs++; + if (num_freqs == MAX_REPORT_FREQS - 1) + break; + } + info->freqs = freqs; + info->num_freqs = num_freqs; + wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", + msg); + } + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); +} + + +static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, + [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, + }; + struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; + enum nl80211_cqm_rssi_threshold_event event; + union wpa_event_data ed; + struct wpa_signal_info sig; + int res; + + if (tb[NL80211_ATTR_CQM] == NULL || + nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], + cqm_policy)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); + return; + } + + os_memset(&ed, 0, sizeof(ed)); + + if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { + if (!tb[NL80211_ATTR_MAC]) + return; + os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), + ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); + return; + } + + if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) + return; + event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); + + if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { + wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " + "event: RSSI high"); + ed.signal_change.above_threshold = 1; + } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { + wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " + "event: RSSI low"); + ed.signal_change.above_threshold = 0; + } else + return; + + res = nl80211_get_link_signal(drv, &sig); + if (res == 0) { + ed.signal_change.current_signal = sig.current_signal; + ed.signal_change.current_txrate = sig.current_txrate; + wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", + sig.current_signal, sig.current_txrate); + } + + res = nl80211_get_link_noise(drv, &sig); + if (res == 0) { + ed.signal_change.current_noise = sig.current_noise; + wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm", + sig.current_noise); + } + + wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); +} + + +static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + const u8 *addr; + union wpa_event_data data; + + if (drv->nlmode != NL80211_IFTYPE_MESH_POINT) + return; + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE]) + return; + + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR, + MAC2STR(addr)); + + os_memset(&data, 0, sizeof(data)); + data.mesh_peer.peer = addr; + data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]); + data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]); + wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data); +} + + +static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u8 *addr; + union wpa_event_data data; + + if (tb[NL80211_ATTR_MAC] == NULL) + return; + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); + + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + u8 *ies = NULL; + size_t ies_len = 0; + if (tb[NL80211_ATTR_IE]) { + ies = nla_data(tb[NL80211_ATTR_IE]); + ies_len = nla_len(tb[NL80211_ATTR_IE]); + } + wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len); + drv_event_assoc(drv->ctx, addr, ies, ies_len, 0); + return; + } + + if (drv->nlmode != NL80211_IFTYPE_ADHOC) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); +} + + +static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u8 *addr; + union wpa_event_data data; + + if (tb[NL80211_ATTR_MAC] == NULL) + return; + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, + MAC2STR(addr)); + + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + drv_event_disassoc(drv->ctx, addr); + return; + } + + if (drv->nlmode != NL80211_IFTYPE_ADHOC) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); + wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); +} + + +static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA]; + static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = { + [NL80211_REKEY_DATA_KEK] = { + .minlen = NL80211_KEK_LEN, + .maxlen = NL80211_KEK_LEN, + }, + [NL80211_REKEY_DATA_KCK] = { + .minlen = NL80211_KCK_LEN, + .maxlen = NL80211_KCK_LEN, + }, + [NL80211_REKEY_DATA_REPLAY_CTR] = { + .minlen = NL80211_REPLAY_CTR_LEN, + .maxlen = NL80211_REPLAY_CTR_LEN, + }, + }; + union wpa_event_data data; + + if (!tb[NL80211_ATTR_MAC]) + return; + if (!tb[NL80211_ATTR_REKEY_DATA]) + return; + if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA, + tb[NL80211_ATTR_REKEY_DATA], rekey_policy)) + return; + if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]) + return; + + os_memset(&data, 0, sizeof(data)); + data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR, + MAC2STR(data.driver_gtk_rekey.bssid)); + data.driver_gtk_rekey.replay_ctr = + nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]); + wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter", + data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN); + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data); +} + + +static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE]; + static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = { + [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 }, + [NL80211_PMKSA_CANDIDATE_BSSID] = { + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN, + }, + [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG }, + }; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event"); + + if (!tb[NL80211_ATTR_PMKSA_CANDIDATE]) + return; + if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE, + tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy)) + return; + if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] || + !cand[NL80211_PMKSA_CANDIDATE_BSSID]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.pmkid_candidate.bssid, + nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN); + data.pmkid_candidate.index = + nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]); + data.pmkid_candidate.preauth = + cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL; + wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); +} + + +static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: Probe client event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.client_poll.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data); +} + + +static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) { + case NL80211_TDLS_SETUP: + wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer " + MACSTR, MAC2STR(data.tdls.peer)); + data.tdls.oper = TDLS_REQUEST_SETUP; + break; + case NL80211_TDLS_TEARDOWN: + wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer " + MACSTR, MAC2STR(data.tdls.peer)); + data.tdls.oper = TDLS_REQUEST_TEARDOWN; + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione " + "event"); + return; + } + if (tb[NL80211_ATTR_REASON_CODE]) { + data.tdls.reason_code = + nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); + } + + wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data); +} + + +static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL); +} + + +static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + u32 reason; + + wpa_printf(MSG_DEBUG, "nl80211: Connect failed event"); + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON]) + return; + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.connect_failed_reason.addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]); + switch (reason) { + case NL80211_CONN_FAIL_MAX_CLIENTS: + wpa_printf(MSG_DEBUG, "nl80211: Max client reached"); + data.connect_failed_reason.code = MAX_CLIENT_REACHED; + break; + case NL80211_CONN_FAIL_BLOCKED_CLIENT: + wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR + " tried to connect", + MAC2STR(data.connect_failed_reason.addr)); + data.connect_failed_reason.code = BLOCKED_CLIENT; + break; + default: + wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason " + "%u", reason); + return; + } + + wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data); +} + + +static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data data; + enum nl80211_radar_event event_type; + + if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT]) + return; + + os_memset(&data, 0, sizeof(data)); + data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); + + /* Check HT params */ + if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + data.dfs_event.ht_enabled = 1; + data.dfs_event.chan_offset = 0; + + switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { + case NL80211_CHAN_NO_HT: + data.dfs_event.ht_enabled = 0; + break; + case NL80211_CHAN_HT20: + break; + case NL80211_CHAN_HT40PLUS: + data.dfs_event.chan_offset = 1; + break; + case NL80211_CHAN_HT40MINUS: + data.dfs_event.chan_offset = -1; + break; + } + } + + /* Get VHT params */ + if (tb[NL80211_ATTR_CHANNEL_WIDTH]) + data.dfs_event.chan_width = + convert2width(nla_get_u32( + tb[NL80211_ATTR_CHANNEL_WIDTH])); + if (tb[NL80211_ATTR_CENTER_FREQ1]) + data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); + if (tb[NL80211_ATTR_CENTER_FREQ2]) + data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); + + wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", + data.dfs_event.freq, data.dfs_event.ht_enabled, + data.dfs_event.chan_offset, data.dfs_event.chan_width, + data.dfs_event.cf1, data.dfs_event.cf2); + + switch (event_type) { + case NL80211_RADAR_DETECTED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); + break; + case NL80211_RADAR_CAC_FINISHED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); + break; + case NL80211_RADAR_CAC_ABORTED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); + break; + case NL80211_RADAR_NOP_FINISHED: + wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d " + "received", event_type); + break; + } +} + + +static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, + int wds) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + union wpa_event_data event; + + if (!tb[NL80211_ATTR_MAC]) + return; + + os_memset(&event, 0, sizeof(event)); + event.rx_from_unknown.bssid = bss->addr; + event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]); + event.rx_from_unknown.wds = wds; + + wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); +} + + +static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, + const u8 *data, size_t len) +{ + u32 i, count; + union wpa_event_data event; + struct wpa_freq_range *range = NULL; + const struct qca_avoid_freq_list *freq_range; + + freq_range = (const struct qca_avoid_freq_list *) data; + if (len < sizeof(freq_range->count)) + return; + + count = freq_range->count; + if (len < sizeof(freq_range->count) + + count * sizeof(struct qca_avoid_freq_range)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)", + (unsigned int) len); + return; + } + + if (count > 0) { + range = os_calloc(count, sizeof(struct wpa_freq_range)); + if (range == NULL) + return; + } + + os_memset(&event, 0, sizeof(event)); + for (i = 0; i < count; i++) { + unsigned int idx = event.freq_range.num; + range[idx].min = freq_range->range[i].start_freq; + range[idx].max = freq_range->range[i].end_freq; + wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u", + range[idx].min, range[idx].max); + if (range[idx].min > range[idx].max) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range"); + continue; + } + event.freq_range.num++; + } + event.freq_range.range = range; + + wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event); + + os_free(range); +} + + +static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, + const u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1]; + u8 *bssid; + + wpa_printf(MSG_DEBUG, + "nl80211: Key management roam+auth vendor event received"); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX, + (struct nlattr *) data, len, NULL)) + return; + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] || + nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED]) + return; + + bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); + wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid)); + + mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]); +} + + +static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, + u32 subcmd, u8 *data, size_t len) +{ + switch (subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: + qca_nl80211_avoid_freq(drv, data, len); + break; + case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: + qca_nl80211_key_mgmt_auth(drv, data, len); + break; + default: + wpa_printf(MSG_DEBUG, + "nl80211: Ignore unsupported QCA vendor event %u", + subcmd); + break; + } +} + + +static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u32 vendor_id, subcmd, wiphy = 0; + int wiphy_idx; + u8 *data = NULL; + size_t len = 0; + + if (!tb[NL80211_ATTR_VENDOR_ID] || + !tb[NL80211_ATTR_VENDOR_SUBCMD]) + return; + + vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); + + if (tb[NL80211_ATTR_WIPHY]) + wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", + wiphy, vendor_id, subcmd); + + if (tb[NL80211_ATTR_VENDOR_DATA]) { + data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); + len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); + wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); + } + + wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); + if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", + wiphy, wiphy_idx); + return; + } + + switch (vendor_id) { + case OUI_QCA: + nl80211_vendor_event_qca(drv, subcmd, data, len); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); + break; + } +} + + +static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + union wpa_event_data data; + enum nl80211_reg_initiator init; + + wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change"); + + if (tb[NL80211_ATTR_REG_INITIATOR] == NULL) + return; + + os_memset(&data, 0, sizeof(data)); + init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]); + wpa_printf(MSG_DEBUG, " * initiator=%d", init); + switch (init) { + case NL80211_REGDOM_SET_BY_CORE: + data.channel_list_changed.initiator = REGDOM_SET_BY_CORE; + break; + case NL80211_REGDOM_SET_BY_USER: + data.channel_list_changed.initiator = REGDOM_SET_BY_USER; + break; + case NL80211_REGDOM_SET_BY_DRIVER: + data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER; + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE; + break; + } + + if (tb[NL80211_ATTR_REG_TYPE]) { + enum nl80211_reg_type type; + type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); + wpa_printf(MSG_DEBUG, " * type=%d", type); + switch (type) { + case NL80211_REGDOM_TYPE_COUNTRY: + data.channel_list_changed.type = REGDOM_TYPE_COUNTRY; + break; + case NL80211_REGDOM_TYPE_WORLD: + data.channel_list_changed.type = REGDOM_TYPE_WORLD; + break; + case NL80211_REGDOM_TYPE_CUSTOM_WORLD: + data.channel_list_changed.type = + REGDOM_TYPE_CUSTOM_WORLD; + break; + case NL80211_REGDOM_TYPE_INTERSECTION: + data.channel_list_changed.type = + REGDOM_TYPE_INTERSECTION; + break; + } + } + + if (tb[NL80211_ATTR_REG_ALPHA2]) { + os_strlcpy(data.channel_list_changed.alpha2, + nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), + sizeof(data.channel_list_changed.alpha2)); + wpa_printf(MSG_DEBUG, " * alpha2=%s", + data.channel_list_changed.alpha2); + } + + wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data); +} + + +static void do_process_drv_event(struct i802_bss *bss, int cmd, + struct nlattr **tb) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + union wpa_event_data data; + + wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", + cmd, nl80211_command_to_string(cmd), bss->ifname); + + if (cmd == NL80211_CMD_ROAM && drv->roam_auth_vendor_event_avail) { + /* + * Device will use roam+auth vendor event to indicate + * roaming, so ignore the regular roam event. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth", + cmd); + return; + } + + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && + (cmd == NL80211_CMD_NEW_SCAN_RESULTS || + cmd == NL80211_CMD_SCAN_ABORTED)) { + wpa_driver_nl80211_set_mode(drv->first_bss, + drv->ap_scan_as_station); + drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; + } + + switch (cmd) { + case NL80211_CMD_TRIGGER_SCAN: + wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); + drv->scan_state = SCAN_STARTED; + if (drv->scan_for_auth) { + /* + * Cannot indicate EVENT_SCAN_STARTED here since we skip + * EVENT_SCAN_RESULTS in scan_for_auth case and the + * upper layer implementation could get confused about + * scanning state. + */ + wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth"); + break; + } + wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); + break; + case NL80211_CMD_START_SCHED_SCAN: + wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); + drv->scan_state = SCHED_SCAN_STARTED; + break; + case NL80211_CMD_SCHED_SCAN_STOPPED: + wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped"); + drv->scan_state = SCHED_SCAN_STOPPED; + wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL); + break; + case NL80211_CMD_NEW_SCAN_RESULTS: + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: New scan results available"); + drv->scan_state = SCAN_COMPLETED; + drv->scan_complete_events = 1; + eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, + drv->ctx); + send_scan_event(drv, 0, tb); + break; + case NL80211_CMD_SCHED_SCAN_RESULTS: + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: New sched scan results available"); + drv->scan_state = SCHED_SCAN_RESULTS; + send_scan_event(drv, 0, tb); + break; + case NL80211_CMD_SCAN_ABORTED: + wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted"); + drv->scan_state = SCAN_ABORTED; + /* + * Need to indicate that scan results are available in order + * not to make wpa_supplicant stop its scanning. + */ + eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, + drv->ctx); + send_scan_event(drv, 1, tb); + break; + case NL80211_CMD_AUTHENTICATE: + case NL80211_CMD_ASSOCIATE: + case NL80211_CMD_DEAUTHENTICATE: + case NL80211_CMD_DISASSOCIATE: + case NL80211_CMD_FRAME_TX_STATUS: + case NL80211_CMD_UNPROT_DEAUTHENTICATE: + case NL80211_CMD_UNPROT_DISASSOCIATE: + mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE], + tb[NL80211_ATTR_RX_SIGNAL_DBM]); + break; + case NL80211_CMD_CONNECT: + case NL80211_CMD_ROAM: + mlme_event_connect(drv, cmd, + tb[NL80211_ATTR_STATUS_CODE], + tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_REQ_IE], + tb[NL80211_ATTR_RESP_IE], + NULL, NULL, NULL, NULL); + break; + case NL80211_CMD_CH_SWITCH_NOTIFY: + mlme_event_ch_switch(drv, + tb[NL80211_ATTR_IFINDEX], + tb[NL80211_ATTR_WIPHY_FREQ], + tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], + tb[NL80211_ATTR_CHANNEL_WIDTH], + tb[NL80211_ATTR_CENTER_FREQ1], + tb[NL80211_ATTR_CENTER_FREQ2]); + break; + case NL80211_CMD_DISCONNECT: + mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE], + tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_DISCONNECTED_BY_AP]); + break; + case NL80211_CMD_MICHAEL_MIC_FAILURE: + mlme_event_michael_mic_failure(bss, tb); + break; + case NL80211_CMD_JOIN_IBSS: + mlme_event_join_ibss(drv, tb); + break; + case NL80211_CMD_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 0, tb); + break; + case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: + mlme_event_remain_on_channel(drv, 1, tb); + break; + case NL80211_CMD_NOTIFY_CQM: + nl80211_cqm_event(drv, tb); + break; + case NL80211_CMD_REG_CHANGE: + nl80211_reg_change_event(drv, tb); + break; + case NL80211_CMD_REG_BEACON_HINT: + wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint"); + os_memset(&data, 0, sizeof(data)); + data.channel_list_changed.initiator = REGDOM_BEACON_HINT; + wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, + &data); + break; + case NL80211_CMD_NEW_STATION: + nl80211_new_station_event(drv, tb); + break; + case NL80211_CMD_DEL_STATION: + nl80211_del_station_event(drv, tb); + break; + case NL80211_CMD_SET_REKEY_OFFLOAD: + nl80211_rekey_offload_event(drv, tb); + break; + case NL80211_CMD_PMKSA_CANDIDATE: + nl80211_pmksa_candidate_event(drv, tb); + break; + case NL80211_CMD_PROBE_CLIENT: + nl80211_client_probe_event(drv, tb); + break; + case NL80211_CMD_TDLS_OPER: + nl80211_tdls_oper_event(drv, tb); + break; + case NL80211_CMD_CONN_FAILED: + nl80211_connect_failed_event(drv, tb); + break; + case NL80211_CMD_FT_EVENT: + mlme_event_ft_event(drv, tb); + break; + case NL80211_CMD_RADAR_DETECT: + nl80211_radar_event(drv, tb); + break; + case NL80211_CMD_STOP_AP: + nl80211_stop_ap(drv, tb); + break; + case NL80211_CMD_VENDOR: + nl80211_vendor_event(drv, tb); + break; + case NL80211_CMD_NEW_PEER_CANDIDATE: + nl80211_new_peer_candidate(drv, tb); + break; + default: + wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " + "(cmd=%d)", cmd); + break; + } +} + + +int process_drv_event(struct nl_msg *msg, void *arg) +{ + struct wpa_driver_nl80211_data *drv = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct i802_bss *bss; + int ifidx = -1; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) { + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + + for (bss = drv->first_bss; bss; bss = bss->next) + if (ifidx == -1 || ifidx == bss->ifindex) { + do_process_drv_event(bss, gnlh->cmd, tb); + return NL_SKIP; + } + wpa_printf(MSG_DEBUG, + "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)", + gnlh->cmd, ifidx); + } else if (tb[NL80211_ATTR_WDEV]) { + u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); + wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device"); + for (bss = drv->first_bss; bss; bss = bss->next) { + if (bss->wdev_id_set && wdev_id == bss->wdev_id) { + do_process_drv_event(bss, gnlh->cmd, tb); + return NL_SKIP; + } + } + wpa_printf(MSG_DEBUG, + "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)", + gnlh->cmd, (long long unsigned int) wdev_id); + } + + return NL_SKIP; +} + + +int process_global_event(struct nl_msg *msg, void *arg) +{ + struct nl80211_global *global = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct wpa_driver_nl80211_data *drv, *tmp; + int ifidx = -1; + struct i802_bss *bss; + u64 wdev_id = 0; + int wdev_id_set = 0; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (tb[NL80211_ATTR_IFINDEX]) + ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + else if (tb[NL80211_ATTR_WDEV]) { + wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); + wdev_id_set = 1; + } + + dl_list_for_each_safe(drv, tmp, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + for (bss = drv->first_bss; bss; bss = bss->next) { + if ((ifidx == -1 && !wdev_id_set) || + ifidx == bss->ifindex || + (wdev_id_set && bss->wdev_id_set && + wdev_id == bss->wdev_id)) { + do_process_drv_event(bss, gnlh->cmd, tb); + return NL_SKIP; + } + } + } + + return NL_SKIP; +} + + +int process_bss_event(struct nl_msg *msg, void *arg) +{ + struct i802_bss *bss = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s", + gnlh->cmd, nl80211_command_to_string(gnlh->cmd), + bss->ifname); + + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: + case NL80211_CMD_FRAME_TX_STATUS: + mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME], + tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], + tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], + tb[NL80211_ATTR_COOKIE], + tb[NL80211_ATTR_RX_SIGNAL_DBM]); + break; + case NL80211_CMD_UNEXPECTED_FRAME: + nl80211_spurious_frame(bss, tb, 0); + break; + case NL80211_CMD_UNEXPECTED_4ADDR_FRAME: + nl80211_spurious_frame(bss, tb, 1); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " + "(cmd=%d)", gnlh->cmd); + break; + } + + return NL_SKIP; +}