#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
* 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 {
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;
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 */
}
}
}
+#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,
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;
}
}
+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)
{
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);