From 6ebe816be00702904332744547180bdb27b126f3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 5 Sep 2015 13:21:17 +0300 Subject: [PATCH] wpa_priv: Add authentication command and event These are needed to work with nl80211 driver interface. Signed-off-by: Jouni Malinen --- src/common/privsep_commands.h | 30 ++++++++++++ src/drivers/driver_privsep.c | 80 +++++++++++++++++++++++++++++++ wpa_supplicant/wpa_priv.c | 88 +++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h index 65621405d..8dff30382 100644 --- a/src/common/privsep_commands.h +++ b/src/common/privsep_commands.h @@ -26,6 +26,25 @@ enum privsep_cmd { PRIVSEP_CMD_L2_NOTIFY_AUTH_START, PRIVSEP_CMD_L2_SEND, PRIVSEP_CMD_SET_COUNTRY, + PRIVSEP_CMD_AUTHENTICATE, +}; + +struct privsep_cmd_authenticate +{ + int freq; + u8 bssid[ETH_ALEN]; + u8 ssid[SSID_MAX_LEN]; + size_t ssid_len; + int auth_alg; + size_t ie_len; + u8 wep_key[4][16]; + size_t wep_key_len[4]; + int wep_tx_keyidx; + int local_state_change; + int p2p; + size_t sae_data_len; + /* followed by ie_len bytes of ie */ + /* followed by sae_data_len bytes of sae_data */ }; struct privsep_cmd_associate @@ -69,6 +88,17 @@ enum privsep_event { PRIVSEP_EVENT_FT_RESPONSE, PRIVSEP_EVENT_RX_EAPOL, PRIVSEP_EVENT_SCAN_STARTED, + PRIVSEP_EVENT_AUTH, +}; + +struct privsep_event_auth { + u8 peer[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 auth_type; + u16 auth_transaction; + u16 status_code; + size_t ies_len; + /* followed by ies_len bytes of ies */ }; #endif /* PRIVSEP_COMMANDS_H */ diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index c2d70fcc6..1f1676a20 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -220,6 +220,56 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv, } +static int wpa_driver_privsep_authenticate( + void *priv, struct wpa_driver_auth_params *params) +{ + struct wpa_driver_privsep_data *drv = priv; + struct privsep_cmd_authenticate *data; + int i, res; + size_t buflen; + u8 *pos; + + wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d bssid=" MACSTR + " auth_alg=%d local_state_change=%d p2p=%d", + __func__, priv, params->freq, MAC2STR(params->bssid), + params->auth_alg, params->local_state_change, params->p2p); + + buflen = sizeof(*data) + params->ie_len + params->sae_data_len; + data = os_zalloc(buflen); + if (data == NULL) + return -1; + + data->freq = params->freq; + os_memcpy(data->bssid, params->bssid, ETH_ALEN); + os_memcpy(data->ssid, params->ssid, params->ssid_len); + data->ssid_len = params->ssid_len; + data->auth_alg = params->auth_alg; + data->ie_len = params->ie_len; + for (i = 0; i < 4; i++) { + if (params->wep_key[i]) + os_memcpy(data->wep_key[i], params->wep_key[i], + params->wep_key_len[i]); + data->wep_key_len[i] = params->wep_key_len[i]; + } + data->wep_tx_keyidx = params->wep_tx_keyidx; + data->local_state_change = params->local_state_change; + data->p2p = params->p2p; + pos = (u8 *) (data + 1); + if (params->ie_len) { + os_memcpy(pos, params->ie, params->ie_len); + pos += params->ie_len; + } + if (params->sae_data_len) + os_memcpy(pos, params->sae_data, params->sae_data_len); + + res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen, + NULL, NULL); + os_free(data); + + return res; +} + + static int wpa_driver_privsep_associate( void *priv, struct wpa_driver_associate_params *params) { @@ -309,6 +359,32 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr, } +static void wpa_driver_privsep_event_auth(void *ctx, u8 *buf, size_t len) +{ + union wpa_event_data data; + struct privsep_event_auth *auth; + + os_memset(&data, 0, sizeof(data)); + if (len < sizeof(*auth)) + return; + auth = (struct privsep_event_auth *) buf; + if (len < sizeof(*auth) + auth->ies_len) + return; + + os_memcpy(data.auth.peer, auth->peer, ETH_ALEN); + os_memcpy(data.auth.bssid, auth->bssid, ETH_ALEN); + data.auth.auth_type = auth->auth_type; + data.auth.auth_transaction = auth->auth_transaction; + data.auth.status_code = auth->status_code; + if (auth->ies_len) { + data.auth.ies = (u8 *) (auth + 1); + data.auth.ies_len = auth->ies_len; + } + + wpa_supplicant_event(ctx, EVENT_AUTH, &data); +} + + static void wpa_driver_privsep_event_assoc(void *ctx, enum wpa_event_type event, u8 *buf, size_t len) @@ -506,6 +582,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, event_len); break; + case PRIVSEP_EVENT_AUTH: + wpa_driver_privsep_event_auth(drv->ctx, event_buf, event_len); + break; } os_free(buf); @@ -742,6 +821,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = { .set_param = wpa_driver_privsep_set_param, .scan2 = wpa_driver_privsep_scan, .deauthenticate = wpa_driver_privsep_deauthenticate, + .authenticate = wpa_driver_privsep_authenticate, .associate = wpa_driver_privsep_associate, .get_capa = wpa_driver_privsep_get_capa, .get_mac_addr = wpa_driver_privsep_get_mac_addr, diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c index cfd9d5259..850ec405b 100644 --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c @@ -195,6 +195,58 @@ static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, } +static void wpa_priv_cmd_authenticate(struct wpa_priv_interface *iface, + void *buf, size_t len) +{ + struct wpa_driver_auth_params params; + struct privsep_cmd_authenticate *auth; + int res, i; + + if (iface->drv_priv == NULL || iface->driver->authenticate == NULL) + return; + + if (len < sizeof(*auth)) { + wpa_printf(MSG_DEBUG, "Invalid authentication request"); + return; + } + + auth = buf; + if (sizeof(*auth) + auth->ie_len + auth->sae_data_len > len) { + wpa_printf(MSG_DEBUG, "Authentication request overflow"); + return; + } + + os_memset(¶ms, 0, sizeof(params)); + params.freq = auth->freq; + params.bssid = auth->bssid; + params.ssid = auth->ssid; + if (auth->ssid_len > SSID_MAX_LEN) + return; + params.ssid_len = auth->ssid_len; + params.auth_alg = auth->auth_alg; + for (i = 0; i < 4; i++) { + if (auth->wep_key_len[i]) { + params.wep_key[i] = auth->wep_key[i]; + params.wep_key_len[i] = auth->wep_key_len[i]; + } + } + params.wep_tx_keyidx = auth->wep_tx_keyidx; + params.local_state_change = auth->local_state_change; + params.p2p = auth->p2p; + if (auth->ie_len) { + params.ie = (u8 *) (auth + 1); + params.ie_len = auth->ie_len; + } + if (auth->sae_data_len) { + params.sae_data = ((u8 *) (auth + 1)) + auth->ie_len; + params.sae_data_len = auth->sae_data_len; + } + + res = iface->driver->authenticate(iface->drv_priv, ¶ms); + wpa_printf(MSG_DEBUG, "drv->authenticate: res=%d", res); +} + + static void wpa_priv_cmd_associate(struct wpa_priv_interface *iface, void *buf, size_t len) { @@ -557,6 +609,9 @@ static void wpa_priv_receive(int sock, void *eloop_ctx, void *sock_ctx) pos[cmd_len] = '\0'; wpa_priv_cmd_set_country(iface, pos); break; + case PRIVSEP_CMD_AUTHENTICATE: + wpa_priv_cmd_authenticate(iface, cmd_buf, cmd_len); + break; } } @@ -726,6 +781,36 @@ static int wpa_priv_send_event(struct wpa_priv_interface *iface, int event, } +static void wpa_priv_send_auth(struct wpa_priv_interface *iface, + union wpa_event_data *data) +{ + size_t buflen = sizeof(struct privsep_event_auth) + data->auth.ies_len; + struct privsep_event_auth *auth; + u8 *buf, *pos; + + buf = os_malloc(buflen); + if (buf == NULL) + return; + + auth = (struct privsep_event_auth *) buf; + pos = (u8 *) (auth + 1); + + os_memcpy(auth->peer, data->auth.peer, ETH_ALEN); + os_memcpy(auth->bssid, data->auth.bssid, ETH_ALEN); + auth->auth_type = data->auth.auth_type; + auth->auth_transaction = data->auth.auth_transaction; + auth->status_code = data->auth.status_code; + if (data->auth.ies) { + os_memcpy(pos, data->auth.ies, data->auth.ies_len); + auth->ies_len = data->auth.ies_len; + } + + wpa_priv_send_event(iface, PRIVSEP_EVENT_AUTH, buf, buflen); + + os_free(buf); +} + + static void wpa_priv_send_assoc(struct wpa_priv_interface *iface, int event, union wpa_event_data *data) { @@ -906,6 +991,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_FT_RESPONSE: wpa_priv_send_ft_response(iface, data); break; + case EVENT_AUTH: + wpa_priv_send_auth(iface, data); + break; default: wpa_printf(MSG_DEBUG, "Unsupported driver event %d (%s) - TODO", event, event_to_string(event));