diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 652476ff9..f782c8658 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1005,6 +1005,8 @@ enum wifi_display_subelem { /* AKM suite selectors */ #define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_PSK 0x000FAC02 +#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03 +#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04 #define WLAN_AKM_SUITE_CCKM 0x00409600 diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4635d05e9..100434db6 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1633,6 +1633,34 @@ static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, } +static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + os_memset(&data, 0, sizeof(data)); + + if (tb[NL80211_ATTR_IE]) { + data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]); + data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]); + } + + if (tb[NL80211_ATTR_IE_RIC]) { + data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]); + data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]); + } + + if (tb[NL80211_ATTR_MAC]) + os_memcpy(data.ft_ies.target_ap, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + + wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR, + MAC2STR(data.ft_ies.target_ap)); + + wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data); +} + + static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, struct nlattr *tb[]) { @@ -2330,6 +2358,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_CONN_FAILED: nl80211_connect_failed_event(drv, tb); break; + case NL80211_CMD_FT_EVENT: + mlme_event_ft_event(drv, tb); + break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); @@ -7142,6 +7173,8 @@ skip_auth_type: if (params->key_mgmt_suite == KEY_MGMT_802_1X || params->key_mgmt_suite == KEY_MGMT_PSK || + params->key_mgmt_suite == KEY_MGMT_FT_802_1X || + params->key_mgmt_suite == KEY_MGMT_FT_PSK || params->key_mgmt_suite == KEY_MGMT_CCKM) { int mgmt = WLAN_AKM_SUITE_PSK; @@ -7152,6 +7185,12 @@ skip_auth_type: case KEY_MGMT_802_1X: mgmt = WLAN_AKM_SUITE_8021X; break; + case KEY_MGMT_FT_802_1X: + mgmt = WLAN_AKM_SUITE_FT_8021X; + break; + case KEY_MGMT_FT_PSK: + mgmt = WLAN_AKM_SUITE_FT_PSK; + break; case KEY_MGMT_PSK: default: mgmt = WLAN_AKM_SUITE_PSK; @@ -9628,6 +9667,39 @@ static int driver_nl80211_probe_req_report(void *priv, int report) } +static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md, + const u8 *ies, size_t ies_len) +{ + int ret; + struct nl_msg *msg; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + u16 mdid = WPA_GET_LE16(md); + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs"); + nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies); + NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed " + "err=%d (%s)", ret, strerror(-ret)); + } + + return ret; + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -9703,4 +9775,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .send_tdls_mgmt = nl80211_send_tdls_mgmt, .tdls_oper = nl80211_tdls_oper, #endif /* CONFIG_TDLS */ + .update_ft_ies = wpa_driver_nl80211_update_ft_ies, }; diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 2df060ca8..4b08a624d 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -788,9 +788,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, if (parse.ric) { wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", parse.ric, parse.ric_len); - /* TODO: parse response and inform driver about results */ + /* TODO: parse response and inform driver about results when + * using wpa_supplicant SME */ } + wpa_printf(MSG_DEBUG, "FT: Completed successfully"); + return 0; } diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 6c8ab6ca2..186db8aa2 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1438,6 +1438,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, { int l, len, found = 0, wpa_found, rsn_found; const u8 *p; + u8 bssid[ETH_ALEN]; wpa_dbg(wpa_s, MSG_DEBUG, "Association info event"); if (data->assoc_info.req_ies) @@ -1492,7 +1493,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SME if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) { - u8 bssid[ETH_ALEN]; if (wpa_drv_get_bssid(wpa_s, bssid) < 0 || wpa_ft_validate_reassoc_resp(wpa_s->wpa, data->assoc_info.resp_ies, @@ -1550,6 +1550,23 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SME */ + /* Process FT when SME is in the driver */ + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + wpa_ft_is_completed(wpa_s->wpa)) { + if (wpa_drv_get_bssid(wpa_s, bssid) < 0 || + wpa_ft_validate_reassoc_resp(wpa_s->wpa, + data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, + bssid) < 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of " + "Reassociation Response failed"); + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_INVALID_IE); + return -1; + } + wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done"); + } + wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_IEEE80211R */