}
-int wpa_sm_has_ptk(struct wpa_sm *sm)
+#ifdef CONFIG_IEEE80211R
+bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md)
{
- if (sm == NULL)
- return 0;
+ if (!sm)
+ return false;
+ if (!wpa_key_mgmt_ft(sm->key_mgmt) ||
+ os_memcmp(md, sm->key_mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0) {
+ /* Do not allow FT protocol to be used even if we were to have
+ * an PTK since the mobility domain has changed. */
+ return false;
+ }
return sm->ptk_set;
}
+#endif /* CONFIG_IEEE80211R */
int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
}
os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+ os_memcpy(sm->key_mobility_domain, sm->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
/* Management Group Cipher Suite */
pos = wpabuf_put(buf, RSN_SELECTOR_LEN);
const u8 *pmkid,
const void *network_ctx,
int akmp);
-int wpa_sm_has_ptk(struct wpa_sm *sm);
+bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md);
int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
- const u8 *mdie);
+ const u8 *mdie, bool force);
#ifdef CONFIG_PASN
return ret;
}
+ os_memcpy(sm->key_mobility_domain, sm->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+
#ifdef CONFIG_PASN
if (sm->secure_ltf &&
ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
kdk_len) < 0)
return -1;
+ os_memcpy(sm->key_mobility_domain, sm->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN);
+
#ifdef CONFIG_PASN
if (sm->secure_ltf &&
ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @target_ap: Target AP Address
* @mdie: Mobility Domain IE from the target AP
+ * @force: Whether to force the request and ignore mobility domain differences
+ * (only for testing purposes)
* Returns: 0 on success, -1 on failure
*/
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
- const u8 *mdie)
+ const u8 *mdie, bool force)
{
u8 *ft_ies;
size_t ft_ies_len;
+ if (!force &&
+ (!mdie || mdie[1] < 3 || !wpa_sm_has_ft_keys(sm, mdie + 2))) {
+ wpa_printf(MSG_DEBUG, "FT: Cannot use over-the DS with " MACSTR
+ " - no keys matching the mobility domain",
+ MAC2STR(target_ap));
+ return -1;
+ }
+
wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
MAC2STR(target_ap));
size_t pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+ u8 key_mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
size_t r0kh_id_len;
u8 r1kh_id[FT_R1KH_ID_LEN];
dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
scan_freq="2412")
- dev[0].roam_over_ds("02:11:22:33:44:55", fail_test=True)
+ dev[0].roam_over_ds("02:11:22:33:44:55", fail_test=True, force=True)
@remote_compatible
def test_ap_ft_over_ds_unexpected(dev, apdev):
# Try over_ds roaming to non-WPA-enabled AP.
# If hostapd does not check hapd->wpa_auth internally, it will crash now.
- dev[0].roam_over_ds(apdev[1]['bssid'], fail_test=True)
+ dev[0].roam_over_ds(apdev[1]['bssid'], fail_test=True, force=True)
def test_ap_ft_extra_ie(dev, apdev):
"""WPA2-PSK-FT AP with WPA2-PSK enabled and unexpected MDE"""
if check_bssid and self.get_status_field('bssid') != bssid:
raise Exception("Did not roam to correct BSSID")
- def roam_over_ds(self, bssid, fail_test=False):
+ def roam_over_ds(self, bssid, fail_test=False, force=False):
self.dump_monitor()
- if "OK" not in self.request("FT_DS " + bssid):
+ cmd = "FT_DS " + bssid
+ if force:
+ cmd += " force"
+ if "OK" not in self.request(cmd):
raise Exception("FT_DS failed")
if fail_test:
ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
u8 target_ap[ETH_ALEN];
struct wpa_bss *bss;
const u8 *mdie;
+ bool force = os_strstr(addr, " force") != NULL;
if (hwaddr_aton(addr, target_ap)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
else
mdie = NULL;
- return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
+ return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie, force);
}
#endif /* CONFIG_IEEE80211R */
if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
- wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
"over-the-air");
params.auth_alg = WPA_AUTH_ALG_FT;
}
#ifdef CONFIG_SME
if (len > 0 && wpa_s->sme.ft_used &&
- wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Trying to use FT over-the-air");
algs |= WPA_AUTH_ALG_FT;