diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f28bd2b2c..d9c6fd9f5 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2051,6 +2051,36 @@ enum wpa_drv_update_connect_params_mask { WPA_DRV_UPDATE_AUTH_TYPE = BIT(2), }; +/** + * struct external_auth - External authentication trigger parameters + * + * These are used across the external authentication request and event + * interfaces. + * @action: Action type / trigger for external authentication. Only significant + * for the event interface. + * @bssid: BSSID of the peer with which the authentication has to happen. Used + * by both the request and event interface. + * @ssid: SSID of the AP. Used by both the request and event interface. + * @ssid_len: SSID length in octets. + * @key_mgmt_suite: AKM suite of the respective authentication. Optional for + * the request interface. + * @status: Status code, %WLAN_STATUS_SUCCESS for successful authentication, + * use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give + * the real status code for failures. Used only for the request interface + * from user space to the driver. + */ +struct external_auth { + enum { + EXT_AUTH_START, + EXT_AUTH_ABORT, + } action; + u8 bssid[ETH_ALEN]; + u8 ssid[SSID_MAX_LEN]; + size_t ssid_len; + unsigned int key_mgmt_suite; + u16 status; +}; + /** * struct wpa_driver_ops - Driver interface API definition * @@ -4012,6 +4042,16 @@ struct wpa_driver_ops { int (*update_connect_params)( void *priv, struct wpa_driver_associate_params *params, enum wpa_drv_update_connect_params_mask mask); + + /** + * send_external_auth_status - Indicate the status of external + * authentication processing to the host driver. + * @priv: Private driver interface data + * @params: Status of authentication processing. + * Returns: 0 on success, -1 on failure + */ + int (*send_external_auth_status)(void *priv, + struct external_auth *params); }; /** @@ -4507,6 +4547,16 @@ enum wpa_event_type { * performed before start operating on this channel. */ EVENT_DFS_PRE_CAC_EXPIRED, + + /** + * EVENT_EXTERNAL_AUTH - This event interface is used by host drivers + * that do not define separate commands for authentication and + * association (~WPA_DRIVER_FLAGS_SME) but offload the 802.11 + * authentication to wpa_supplicant. This event carries all the + * necessary information from the host driver for the authentication to + * happen. + */ + EVENT_EXTERNAL_AUTH, }; @@ -5309,6 +5359,9 @@ union wpa_event_data { P2P_LO_STOPPED_REASON_NOT_SUPPORTED, } reason_code; } p2p_lo_stop; + + /* For EVENT_EXTERNAL_AUTH */ + struct external_auth external_auth; }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 04643043e..33a6db346 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -82,6 +82,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(P2P_LO_STOP); E2S(BEACON_LOSS); E2S(DFS_PRE_CAC_EXPIRED); + E2S(EXTERNAL_AUTH); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 9b3bde278..d6bf12160 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2020,7 +2020,9 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " "handle %p", bss->nl_mgmt); - if (drv->nlmode == NL80211_IFTYPE_ADHOC) { + if (drv->nlmode == NL80211_IFTYPE_ADHOC || + ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4); /* register for any AUTH message */ @@ -5368,6 +5370,11 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, nl80211_put_fils_connect_params(drv, params, msg) != 0) return -1; + if ((params->auth_alg & WPA_AUTH_ALG_SAE) && + (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) && + nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) + return -1; + return 0; } @@ -10377,6 +10384,38 @@ fail: } +static int nl80211_send_external_auth_status(void *priv, + struct external_auth *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg = NULL; + int ret = -1; + + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: External auth status: %u", params->status); + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH); + if (!msg || + nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) || + nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, + params->ssid) || + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)) + goto fail; + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: External Auth status update failed: ret=%d (%s)", + ret, strerror(-ret)); + goto fail; + } +fail: + nlmsg_free(msg); + return ret; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -10504,4 +10543,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .configure_data_frame_filters = nl80211_configure_data_frame_filters, .get_ext_capab = nl80211_get_ext_capab, .update_connect_params = nl80211_update_connection_params, + .send_external_auth_status = nl80211_send_external_auth_status, }; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 1b5be97c4..5591cebe8 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -131,6 +131,7 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_SET_QOS_MAP) C2S(NL80211_CMD_ADD_TX_TS) C2S(NL80211_CMD_DEL_TX_TS) + C2S(NL80211_CMD_EXTERNAL_AUTH) default: return "NL80211_CMD_UNKNOWN"; } @@ -2175,6 +2176,50 @@ static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv, } +static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + union wpa_event_data event; + enum nl80211_external_auth_action act; + + if (!tb[NL80211_ATTR_AKM_SUITES] || + !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] || + !tb[NL80211_ATTR_BSSID] || + !tb[NL80211_ATTR_SSID]) + return; + + os_memset(&event, 0, sizeof(event)); + act = nla_get_u32(tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION]); + switch (act) { + case NL80211_EXTERNAL_AUTH_START: + event.external_auth.action = EXT_AUTH_START; + break; + case NL80211_EXTERNAL_AUTH_ABORT: + event.external_auth.action = EXT_AUTH_ABORT; + break; + default: + return; + } + + event.external_auth.key_mgmt_suite = + nla_get_u32(tb[NL80211_ATTR_AKM_SUITES]); + + event.external_auth.ssid_len = nla_len(tb[NL80211_ATTR_SSID]); + if (event.external_auth.ssid_len > SSID_MAX_LEN) + return; + os_memcpy(event.external_auth.ssid, nla_data(tb[NL80211_ATTR_SSID]), + event.external_auth.ssid_len); + + os_memcpy(event.external_auth.bssid, nla_data(tb[NL80211_ATTR_BSSID]), + ETH_ALEN); + + wpa_printf(MSG_DEBUG, + "nl80211: External auth action: %u, AKM: 0x%x", + event.external_auth.action, + event.external_auth.key_mgmt_suite); + wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event); +} + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2373,6 +2418,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_NEW_PEER_CANDIDATE: nl80211_new_peer_candidate(drv, tb); break; + case NL80211_CMD_EXTERNAL_AUTH: + nl80211_external_auth(drv, tb); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd);