X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=blobdiff_plain;f=libeap%2Fsrc%2Fdrivers%2Fdriver_nl80211_event.c;fp=libeap%2Fsrc%2Fdrivers%2Fdriver_nl80211_event.c;h=762e3acc2807904af8ce9d2d3335ea0ed3c1d089;hp=7b0f721e65842aac3bcfb5de58aab670a7153989;hb=d1dd9aae6741e74f20bfc35e1db598652680279d;hpb=bd3bd69af16ab99706ba70ed11a3e291e968e5c6 diff --git a/libeap/src/drivers/driver_nl80211_event.c b/libeap/src/drivers/driver_nl80211_event.c index 7b0f721..762e3ac 100644 --- a/libeap/src/drivers/driver_nl80211_event.c +++ b/libeap/src/drivers/driver_nl80211_event.c @@ -265,10 +265,12 @@ 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 *timed_out, struct nlattr *authorized, struct nlattr *key_replay_ctr, struct nlattr *ptk_kck, - struct nlattr *ptk_kek) + struct nlattr *ptk_kek, + struct nlattr *subnet_status) { union wpa_event_data event; const u8 *ssid; @@ -284,6 +286,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, return; } + drv->connect_reassoc = 0; + status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS; if (cmd == NL80211_CMD_CONNECT) { @@ -319,6 +323,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_reject.resp_ies_len = nla_len(resp_ie); } event.assoc_reject.status_code = status_code; + event.assoc_reject.timed_out = timed_out != NULL; wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } @@ -334,9 +339,9 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_info.req_ies_len = nla_len(req_ie); if (cmd == NL80211_CMD_ROAM) { - ssid = nl80211_get_ie(event.assoc_info.req_ies, - event.assoc_info.req_ies_len, - WLAN_EID_SSID); + ssid = get_ie(event.assoc_info.req_ies, + event.assoc_info.req_ies_len, + WLAN_EID_SSID); if (ssid && ssid[1] > 0 && ssid[1] <= 32) { drv->ssid_len = ssid[1]; os_memcpy(drv->ssid, ssid + 2, ssid[1]); @@ -367,6 +372,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_info.ptk_kek_len = nla_len(ptk_kek); } + if (subnet_status) { + /* + * At least for now, this is only available from + * QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS and that + * attribute has the same values 0, 1, 2 as are used in the + * variable here, so no mapping between different values are + * needed. + */ + event.assoc_info.subnet_status = nla_get_u8(subnet_status); + } + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } @@ -560,9 +576,10 @@ static void mlme_event_mgmt(struct i802_bss *bss, rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq; } wpa_printf(MSG_DEBUG, - "nl80211: RX frame sa=" MACSTR + "nl80211: RX frame da=" MACSTR " sa=" MACSTR " bssid=" MACSTR " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u", - MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc, + MAC2STR(mgmt->da), MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid), + rx_freq, ssi_signal, fc, le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc), (unsigned int) len); event.rx_mgmt.frame = frame; @@ -639,10 +656,39 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, * Avoid issues with some roaming cases where * disconnection event for the old AP may show up after * we have started connection with the new AP. + * In case of locally generated event clear + * ignore_next_local_deauth as well, to avoid next local + * deauth event be wrongly ignored. */ - wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR, - MAC2STR(bssid), - MAC2STR(drv->auth_attempt_bssid)); + if (!os_memcmp(mgmt->sa, drv->first_bss->addr, + ETH_ALEN)) { + wpa_printf(MSG_DEBUG, + "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag"); + drv->ignore_next_local_deauth = 0; + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR, + MAC2STR(bssid), + MAC2STR(drv->auth_attempt_bssid)); + } + return; + } + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && + drv->connect_reassoc && drv->associated && + os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 && + os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) { + /* + * Avoid issues with some roaming cases where + * disconnection event for the old AP may show up after + * we have started connection with the new AP. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore deauth/disassoc event from old AP " + MACSTR + " when already connecting with " MACSTR, + MAC2STR(bssid), + MAC2STR(drv->auth_attempt_bssid)); return; } @@ -679,13 +725,15 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, mgmt->u.disassoc.variable; } } else { + event.deauth_info.locally_generated = + !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); if (drv->ignore_deauth_event) { wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth"); drv->ignore_deauth_event = 0; + if (event.deauth_info.locally_generated) + drv->ignore_next_local_deauth = 0; return; } - event.deauth_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); if (drv->ignore_next_local_deauth) { drv->ignore_next_local_deauth = 0; if (event.deauth_info.locally_generated) { @@ -868,6 +916,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, struct nlattr *tb[]) { unsigned int freq; + union wpa_event_data event; if (tb[NL80211_ATTR_MAC] == NULL) { wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " @@ -887,7 +936,10 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, drv->first_bss->freq = freq; } - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); + os_memset(&event, 0, sizeof(event)); + event.assoc_info.freq = freq; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } @@ -968,7 +1020,7 @@ static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, - struct nlattr *tb[]) + struct nlattr *tb[], int external_scan) { union wpa_event_data event; struct nlattr *nl; @@ -978,7 +1030,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; - if (drv->scan_for_auth) { + if (!external_scan && drv->scan_for_auth) { drv->scan_for_auth = 0; wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing " "cfg80211 BSS entry"); @@ -989,6 +1041,8 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, os_memset(&event, 0, sizeof(event)); info = &event.scan_info; info->aborted = aborted; + info->external_scan = external_scan; + info->nl_scan_event = 1; if (tb[NL80211_ATTR_SCAN_SSIDS]) { nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { @@ -1004,7 +1058,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[200], *pos, *end; + char msg[300], *pos, *end; int res; pos = msg; @@ -1109,7 +1163,7 @@ static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv, return; addr = nla_data(tb[NL80211_ATTR_MAC]); - wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR, + wpa_printf(MSG_DEBUG, "nl80211: New peer candidate " MACSTR, MAC2STR(addr)); os_memset(&data, 0, sizeof(data)); @@ -1154,6 +1208,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, + struct i802_bss *bss, struct nlattr **tb) { u8 *addr; @@ -1166,7 +1221,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, MAC2STR(addr)); if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - drv_event_disassoc(drv->ctx, addr); + drv_event_disassoc(bss->ctx, addr); return; } @@ -1175,7 +1230,7 @@ static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, 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); + wpa_supplicant_event(bss->ctx, EVENT_IBSS_PEER_LOST, &data); } @@ -1444,6 +1499,8 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, } +#ifdef CONFIG_DRIVER_NL80211_QCA + static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, const u8 *data, size_t len) { @@ -1593,10 +1650,12 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, 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], + NULL, 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]); + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS]); } @@ -1686,6 +1745,165 @@ static void qca_nl80211_dfs_offload_radar_event( } +static void qca_nl80211_scan_trigger_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + u64 cookie = 0; + union wpa_event_data event; + struct scan_info *info; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) + return; + + cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); + if (cookie != drv->vendor_scan_cookie) { + /* External scan trigger event, ignore */ + return; + } + + /* Cookie match, own scan */ + os_memset(&event, 0, sizeof(event)); + info = &event.scan_info; + info->external_scan = 0; + info->nl_scan_event = 0; + + drv->scan_state = SCAN_STARTED; + wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, &event); +} + + +static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv, + int aborted, struct nlattr *tb[], + int external_scan) +{ + union wpa_event_data event; + struct nlattr *nl; + int rem; + struct scan_info *info; + int freqs[MAX_REPORT_FREQS]; + int num_freqs = 0; + + os_memset(&event, 0, sizeof(event)); + info = &event.scan_info; + info->aborted = aborted; + info->external_scan = external_scan; + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(nl, + tb[QCA_WLAN_VENDOR_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[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + char msg[300], *pos, *end; + int res; + + pos = msg; + end = pos + sizeof(msg); + *pos = '\0'; + + nla_for_each_nested(nl, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], + rem) { + freqs[num_freqs] = nla_get_u32(nl); + res = os_snprintf(pos, end - pos, " %d", + freqs[num_freqs]); + if (!os_snprintf_error(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 qca_nl80211_scan_done_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + u64 cookie = 0; + enum scan_status status; + int external_scan; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS] || + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) + return; + + status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SCAN_STATUS]); + if (status >= VENDOR_SCAN_STATUS_MAX) + return; /* invalid status */ + + cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); + if (cookie != drv->vendor_scan_cookie) { + /* Event from an external scan, get scan results */ + external_scan = 1; + } else { + external_scan = 0; + if (status == VENDOR_SCAN_STATUS_NEW_RESULTS) + drv->scan_state = SCAN_COMPLETED; + else + drv->scan_state = SCAN_ABORTED; + + eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, + drv->ctx); + drv->vendor_scan_cookie = 0; + drv->last_scan_cmd = 0; + } + + send_vendor_scan_event(drv, (status == VENDOR_SCAN_STATUS_ABORTED), tb, + external_scan); +} + + +static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; + union wpa_event_data event; + + wpa_printf(MSG_DEBUG, + "nl80211: P2P listen offload stop vendor event received"); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]) + return; + + os_memset(&event, 0, sizeof(event)); + event.p2p_lo_stop.reason_code = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]); + + wpa_printf(MSG_DEBUG, + "nl80211: P2P Listen offload stop reason: %d", + event.p2p_lo_stop.reason_code); + wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event); +} + +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *data, size_t len) { @@ -1693,6 +1911,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_TEST: wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len); break; +#ifdef CONFIG_DRIVER_NL80211_QCA case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: qca_nl80211_avoid_freq(drv, data, len); break; @@ -1709,6 +1928,16 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len); break; + case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: + qca_nl80211_scan_trigger_event(drv, data, len); + break; + case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: + qca_nl80211_scan_done_event(drv, data, len); + break; + case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: + qca_nl80211_p2p_lo_stop_event(drv, data, len); + break; +#endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported QCA vendor event %u", @@ -1831,6 +2060,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, { struct wpa_driver_nl80211_data *drv = bss->drv; union wpa_event_data data; + int external_scan_event = 0; wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", cmd, nl80211_command_to_string(cmd), bss->ifname); @@ -1883,28 +2113,38 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, 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); + if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) { + drv->scan_state = SCAN_COMPLETED; + eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, + drv, drv->ctx); + drv->last_scan_cmd = 0; + } else { + external_scan_event = 1; + } + send_scan_event(drv, 0, tb, external_scan_event); 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); + send_scan_event(drv, 0, tb, 0); 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); + if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) { + 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); + drv->last_scan_cmd = 0; + } else { + external_scan_event = 1; + } + send_scan_event(drv, 1, tb, external_scan_event); break; case NL80211_CMD_AUTHENTICATE: case NL80211_CMD_ASSOCIATE: @@ -1927,7 +2167,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_RESP_IE], - NULL, NULL, NULL, NULL); + tb[NL80211_ATTR_TIMED_OUT], + NULL, NULL, NULL, NULL, NULL); break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, @@ -1972,7 +2213,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, nl80211_new_station_event(drv, bss, tb); break; case NL80211_CMD_DEL_STATION: - nl80211_del_station_event(drv, tb); + nl80211_del_station_event(drv, bss, tb); break; case NL80211_CMD_SET_REKEY_OFFLOAD: nl80211_rekey_offload_event(drv, tb);