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 <jouni@codeaurora.org>
This commit is contained in:
Vinita S. Maloo 2020-10-15 20:28:17 +05:30 committed by Jouni Malinen
parent 7423fa6e8f
commit 60c902f408
5 changed files with 173 additions and 4 deletions

View File

@ -5062,6 +5062,34 @@ struct freq_survey {
#define SURVEY_HAS_CHAN_TIME_RX BIT(3) #define SURVEY_HAS_CHAN_TIME_RX BIT(3)
#define SURVEY_HAS_CHAN_TIME_TX BIT(4) #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 * union wpa_event_data - Additional data for wpa_supplicant_event() calls
@ -5463,6 +5491,11 @@ union wpa_event_data {
* FILS ERP messages * FILS ERP messages
*/ */
u16 fils_erp_next_seq_num; 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; } assoc_reject;
struct timeout_event { struct timeout_event {

View File

@ -174,6 +174,7 @@ struct wpa_driver_nl80211_data {
unsigned int control_port_ap:1; unsigned int control_port_ap:1;
unsigned int multicast_registrations:1; unsigned int multicast_registrations:1;
unsigned int no_rrm:1; unsigned int no_rrm:1;
unsigned int get_sta_info_vendor_cmd_avail:1;
u64 vendor_scan_cookie; u64 vendor_scan_cookie;
u64 remain_on_chan_cookie; u64 remain_on_chan_cookie;

View File

@ -994,6 +994,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
drv->add_sta_node_vendor_cmd_avail = 1; drv->add_sta_node_vendor_cmd_avail = 1;
break; break;
case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO:
drv->get_sta_info_vendor_cmd_avail = 1;
break;
#endif /* CONFIG_DRIVER_NL80211_QCA */ #endif /* CONFIG_DRIVER_NL80211_QCA */
} }
} }

View File

@ -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, static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, struct nlattr *status, enum nl80211_commands cmd, struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie, 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) if (fils_erp_next_seq_num)
event.assoc_reject.fils_erp_next_seq_num = event.assoc_reject.fils_erp_next_seq_num =
nla_get_u16(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); wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return; return;
} }

View File

@ -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, static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
union wpa_event_data *data) 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) if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT 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), MAC2STR(data->assoc_reject.bssid),
data->assoc_reject.status_code, data->assoc_reject.status_code,
data->assoc_reject.timed_out ? " timeout" : "", 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.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 else
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT 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.status_code,
data->assoc_reject.timed_out ? " timeout" : "", 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.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; wpa_s->assoc_status_code = data->assoc_reject.status_code;
wpas_notify_assoc_status_code(wpa_s); wpas_notify_assoc_status_code(wpa_s);