nl80211: Introduce the interface for external authentication

This command/event interface can be used by host drivers that do not
define separate commands for authentication and association but rely on
wpa_supplicant for the authentication (SAE) processing.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Sunil Dutt 2018-02-01 12:45:41 +05:30 committed by Jouni Malinen
parent 8678b14faa
commit ba71cb821a
4 changed files with 143 additions and 1 deletions

View file

@ -2051,6 +2051,36 @@ enum wpa_drv_update_connect_params_mask {
WPA_DRV_UPDATE_AUTH_TYPE = BIT(2), 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 * struct wpa_driver_ops - Driver interface API definition
* *
@ -4012,6 +4042,16 @@ struct wpa_driver_ops {
int (*update_connect_params)( int (*update_connect_params)(
void *priv, struct wpa_driver_associate_params *params, void *priv, struct wpa_driver_associate_params *params,
enum wpa_drv_update_connect_params_mask mask); 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. * performed before start operating on this channel.
*/ */
EVENT_DFS_PRE_CAC_EXPIRED, 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, P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
} reason_code; } reason_code;
} p2p_lo_stop; } p2p_lo_stop;
/* For EVENT_EXTERNAL_AUTH */
struct external_auth external_auth;
}; };
/** /**

View file

@ -82,6 +82,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(P2P_LO_STOP); E2S(P2P_LO_STOP);
E2S(BEACON_LOSS); E2S(BEACON_LOSS);
E2S(DFS_PRE_CAC_EXPIRED); E2S(DFS_PRE_CAC_EXPIRED);
E2S(EXTERNAL_AUTH);
} }
return "UNKNOWN"; return "UNKNOWN";

View file

@ -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 " wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt); "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); u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
/* register for any AUTH message */ /* 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) nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1; 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; 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 = { const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211", .name = "nl80211",
.desc = "Linux nl80211/cfg80211", .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, .configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab, .get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params, .update_connect_params = nl80211_update_connection_params,
.send_external_auth_status = nl80211_send_external_auth_status,
}; };

View file

@ -131,6 +131,7 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
C2S(NL80211_CMD_SET_QOS_MAP) C2S(NL80211_CMD_SET_QOS_MAP)
C2S(NL80211_CMD_ADD_TX_TS) C2S(NL80211_CMD_ADD_TX_TS)
C2S(NL80211_CMD_DEL_TX_TS) C2S(NL80211_CMD_DEL_TX_TS)
C2S(NL80211_CMD_EXTERNAL_AUTH)
default: default:
return "NL80211_CMD_UNKNOWN"; 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, static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb) 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: case NL80211_CMD_NEW_PEER_CANDIDATE:
nl80211_new_peer_candidate(drv, tb); nl80211_new_peer_candidate(drv, tb);
break; break;
case NL80211_CMD_EXTERNAL_AUTH:
nl80211_external_auth(drv, tb);
break;
default: default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd); "(cmd=%d)", cmd);