From 60c902f408ae4fdbf982e137f97162f5d540be69 Mon Sep 17 00:00:00 2001 From: "Vinita S. Maloo" Date: Thu, 15 Oct 2020 20:28:17 +0530 Subject: [PATCH] Add connect fail reason code from the driver to assoc reject event Add support to report a vendor specific connect fail reason code fetched from the driver to users by adding the reason code to the event CTRL-EVENT-ASSOC-REJECT. Fetch the connect fail reason code when the driver sends a failure connection result and append the reason code, if available, to assoc reject event. Signed-off-by: Jouni Malinen --- src/drivers/driver.h | 33 ++++++++++ src/drivers/driver_nl80211.h | 1 + src/drivers/driver_nl80211_capa.c | 3 + src/drivers/driver_nl80211_event.c | 99 ++++++++++++++++++++++++++++++ wpa_supplicant/events.c | 41 +++++++++++-- 5 files changed, 173 insertions(+), 4 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 0019f54f9..2f7f09a8a 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -5062,6 +5062,34 @@ struct freq_survey { #define SURVEY_HAS_CHAN_TIME_RX BIT(3) #define SURVEY_HAS_CHAN_TIME_TX BIT(4) +/** + * enum sta_connect_fail_reason_codes - STA connect failure reason code values + * @STA_CONNECT_FAIL_REASON_UNSPECIFIED: No reason code specified for + * connection failure. + * @STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: No Probe Response frame received + * for unicast Probe Request frame. + * @STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: STA failed to send auth request. + * @STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: AP didn't send ACK for + * auth request. + * @STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: Auth response is not + * received from AP. + * @STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: STA failed to send + * Association Request frame. + * @STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: AP didn't send ACK for + * Association Request frame. + * @STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: Association Response + * frame is not received from AP. + */ +enum sta_connect_fail_reason_codes { + STA_CONNECT_FAIL_REASON_UNSPECIFIED = 0, + STA_CONNECT_FAIL_REASON_NO_BSS_FOUND = 1, + STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL = 2, + STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED = 3, + STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED = 4, + STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL = 5, + STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED = 6, + STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED = 7, +}; /** * union wpa_event_data - Additional data for wpa_supplicant_event() calls @@ -5463,6 +5491,11 @@ union wpa_event_data { * FILS ERP messages */ u16 fils_erp_next_seq_num; + + /** + * reason_code - Connection failure reason code from the driver + */ + enum sta_connect_fail_reason_codes reason_code; } assoc_reject; struct timeout_event { diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 017c025a0..4009545fa 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -174,6 +174,7 @@ struct wpa_driver_nl80211_data { unsigned int control_port_ap:1; unsigned int multicast_registrations:1; unsigned int no_rrm:1; + unsigned int get_sta_info_vendor_cmd_avail:1; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 287b8aa30..6c2ab515e 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -994,6 +994,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: drv->add_sta_node_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO: + drv->get_sta_info_vendor_cmd_avail = 1; + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index ce95e9cd3..f75f7b3ae 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -296,6 +296,94 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } +#ifdef CONFIG_DRIVER_NL80211_QCA + +static int qca_drv_connect_fail_reason_code_handler(struct nl_msg *msg, + void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + u32 *reason_code = arg; + + *reason_code = 0; + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_VENDOR_DATA]) { + wpa_printf(MSG_ERROR, "%s: Vendor data not found", __func__); + return NL_SKIP; + } + + nla_parse(tb_sta_info, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX, + nla_data(tb[NL80211_ATTR_VENDOR_DATA]), + nla_len(tb[NL80211_ATTR_VENDOR_DATA]), NULL); + + if (!tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]) { + wpa_printf(MSG_INFO, "%s: Vendor attr not found", __func__); + return NL_SKIP; + } + + *reason_code = nla_get_u32(tb_sta_info[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE]); + + return NL_SKIP; +} + + +static enum qca_sta_connect_fail_reason_codes +drv_get_connect_fail_reason_code(struct wpa_driver_nl80211_data *drv) +{ + enum qca_sta_connect_fail_reason_codes reason_code; + struct nl_msg *msg; + int ret; + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR); + if (!msg || nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO)) { + nlmsg_free(msg); + return 0; + } + + ret = send_and_recv_msgs(drv, msg, + qca_drv_connect_fail_reason_code_handler, + &reason_code, NULL, NULL); + if (ret) + wpa_printf(MSG_DEBUG, + "nl80211: Get connect fail reason_code failed: ret=%d (%s)", + ret, strerror(-ret)); + + return reason_code; +} + + +static enum sta_connect_fail_reason_codes +convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes + reason_code) +{ + switch (reason_code) { + case QCA_STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: + return STA_CONNECT_FAIL_REASON_NO_BSS_FOUND; + case QCA_STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: + return STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL; + case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: + return STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED; + case QCA_STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: + return STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED; + case QCA_STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: + return STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL; + case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: + return STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED; + case QCA_STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: + return STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED; + default: + return STA_CONNECT_FAIL_REASON_UNSPECIFIED; + } +} + +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + 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, @@ -385,6 +473,17 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, if (fils_erp_next_seq_num) event.assoc_reject.fils_erp_next_seq_num = nla_get_u16(fils_erp_next_seq_num); + +#ifdef CONFIG_DRIVER_NL80211_QCA + if (drv->get_sta_info_vendor_cmd_avail) { + enum qca_sta_connect_fail_reason_codes reason_code; + + reason_code = drv_get_connect_fail_reason_code(drv); + event.assoc_reject.reason_code = + convert_connect_fail_reason_codes(reason_code); + } +#endif /* CONFIG_DRIVER_NL80211_QCA */ + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 1b46a9715..b53746b70 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -4425,6 +4425,31 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, } +static const char * connect_fail_reason(enum sta_connect_fail_reason_codes code) +{ + switch (code) { + case STA_CONNECT_FAIL_REASON_UNSPECIFIED: + return ""; + case STA_CONNECT_FAIL_REASON_NO_BSS_FOUND: + return "no_bss_found"; + case STA_CONNECT_FAIL_REASON_AUTH_TX_FAIL: + return "auth_tx_fail"; + case STA_CONNECT_FAIL_REASON_AUTH_NO_ACK_RECEIVED: + return "auth_no_ack_received"; + case STA_CONNECT_FAIL_REASON_AUTH_NO_RESP_RECEIVED: + return "auth_no_resp_received"; + case STA_CONNECT_FAIL_REASON_ASSOC_REQ_TX_FAIL: + return "assoc_req_tx_fail"; + case STA_CONNECT_FAIL_REASON_ASSOC_NO_ACK_RECEIVED: + return "assoc_no_ack_received"; + case STA_CONNECT_FAIL_REASON_ASSOC_NO_RESP_RECEIVED: + return "assoc_no_resp_received"; + default: + return "unknown_reason"; + } +} + + static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -4444,21 +4469,29 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, if (data->assoc_reject.bssid) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "bssid=" MACSTR " status_code=%u%s%s%s", + "bssid=" MACSTR " status_code=%u%s%s%s%s%s", MAC2STR(data->assoc_reject.bssid), data->assoc_reject.status_code, data->assoc_reject.timed_out ? " timeout" : "", data->assoc_reject.timeout_reason ? "=" : "", data->assoc_reject.timeout_reason ? - data->assoc_reject.timeout_reason : ""); + data->assoc_reject.timeout_reason : "", + data->assoc_reject.reason_code != + STA_CONNECT_FAIL_REASON_UNSPECIFIED ? + " qca_driver_reason=" : "", + connect_fail_reason(data->assoc_reject.reason_code)); else wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "status_code=%u%s%s%s", + "status_code=%u%s%s%s%s%s", data->assoc_reject.status_code, data->assoc_reject.timed_out ? " timeout" : "", data->assoc_reject.timeout_reason ? "=" : "", data->assoc_reject.timeout_reason ? - data->assoc_reject.timeout_reason : ""); + data->assoc_reject.timeout_reason : "", + data->assoc_reject.reason_code != + STA_CONNECT_FAIL_REASON_UNSPECIFIED ? + " qca_driver_reason=" : "", + connect_fail_reason(data->assoc_reject.reason_code)); wpa_s->assoc_status_code = data->assoc_reject.status_code; wpas_notify_assoc_status_code(wpa_s);