FILS: Add generation of FILS Discovery frame template

Add hostapd configuration parameters for FILS Discovery frame
transmission interval and prepare a template for FILS Discovery frame
for the driver interface. The actual driver interface changes are not
included in this commit.

Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
This commit is contained in:
Aloka Dixit 2020-12-14 18:04:27 -08:00 committed by Jouni Malinen
parent c4c529e9cb
commit 9c02a0f5a6
8 changed files with 369 additions and 0 deletions

View file

@ -4423,6 +4423,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->dhcp_server_port = atoi(pos); bss->dhcp_server_port = atoi(pos);
} else if (os_strcmp(buf, "dhcp_relay_port") == 0) { } else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
bss->dhcp_relay_port = atoi(pos); bss->dhcp_relay_port = atoi(pos);
} else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) {
bss->fils_discovery_min_int = atoi(pos);
} else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) {
bss->fils_discovery_max_int = atoi(pos);
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) { } else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
bss->multicast_to_unicast = atoi(pos); bss->multicast_to_unicast = atoi(pos);

View file

@ -1987,6 +1987,13 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds) # default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30 #fils_hlp_wait_time=30
# FILS Discovery frame transmission minimum and maximum interval settings.
# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
# frame transmission. These values use TUs as the unit and have allowed range
# of 0-10000. fils_discovery_min_interval defaults to 20.
#fils_discovery_min_interval=20
#fils_discovery_max_interval=0
# Transition Disable indication # Transition Disable indication
# The AP can notify authenticated stations to disable transition mode in their # The AP can notify authenticated stations to disable transition mode in their
# network profiles when the network has completed transition steps, i.e., once # network profiles when the network has completed transition steps, i.e., once

View file

@ -131,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->fils_hlp_wait_time = 30; bss->fils_hlp_wait_time = 30;
bss->dhcp_server_port = DHCP_SERVER_PORT; bss->dhcp_server_port = DHCP_SERVER_PORT;
bss->dhcp_relay_port = DHCP_SERVER_PORT; bss->dhcp_relay_port = DHCP_SERVER_PORT;
bss->fils_discovery_min_int = 20;
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
bss->broadcast_deauth = 1; bss->broadcast_deauth = 1;

View file

@ -730,6 +730,8 @@ struct hostapd_bss_config {
unsigned int fils_hlp_wait_time; unsigned int fils_hlp_wait_time;
u16 dhcp_server_port; u16 dhcp_server_port;
u16 dhcp_relay_port; u16 dhcp_relay_port;
u32 fils_discovery_min_int;
u32 fils_discovery_max_int;
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
int multicast_to_unicast; int multicast_to_unicast;

View file

@ -1134,6 +1134,243 @@ void sta_track_del(struct hostapd_sta_info *info)
} }
#ifdef CONFIG_FILS
static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
{
u16 cap_info, phy_index = 0;
u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
cap_info = FD_CAP_ESS;
if (hapd->conf->wpa)
cap_info |= FD_CAP_PRIVACY;
if (is_6ghz_op_class(hapd->iconf->op_class)) {
phy_index = FD_CAP_PHY_INDEX_HE;
switch (hapd->iconf->op_class) {
case 135:
mcs_nss_size += 4;
/* fallthrough */
case 134:
mcs_nss_size += 4;
chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
break;
case 133:
chwidth = FD_CAP_BSS_CHWIDTH_80;
break;
case 132:
chwidth = FD_CAP_BSS_CHWIDTH_40;
break;
}
} else {
switch (hostapd_get_oper_chwidth(hapd->iconf)) {
case CHANWIDTH_80P80MHZ:
mcs_nss_size += 4;
/* fallthrough */
case CHANWIDTH_160MHZ:
mcs_nss_size += 4;
chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
break;
case CHANWIDTH_80MHZ:
chwidth = FD_CAP_BSS_CHWIDTH_80;
break;
case CHANWIDTH_USE_HT:
if (hapd->iconf->secondary_channel)
chwidth = FD_CAP_BSS_CHWIDTH_40;
else
chwidth = FD_CAP_BSS_CHWIDTH_20;
break;
}
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
phy_index = FD_CAP_PHY_INDEX_HE;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211AC
if (!phy_index &&
hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
phy_index = FD_CAP_PHY_INDEX_VHT;
#endif /* CONFIG_IEEE80211AC */
if (!phy_index &&
hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
phy_index = FD_CAP_PHY_INDEX_HT;
}
cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
if (mode) {
u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
int i;
u16 nss = 0;
for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
u16 nss_mask = 0x3 << (i * 2);
if (mcs_nss_size == 4 &&
(((mcs[0] & nss_mask) == nss_mask) ||
((mcs[1] & nss_mask) == nss_mask)))
continue;
if (mcs_nss_size == 8 &&
(((mcs[2] & nss_mask) == nss_mask) ||
((mcs[3] & nss_mask) == nss_mask)))
continue;
if (mcs_nss_size == 12 &&
(((mcs[4] & nss_mask) == nss_mask) ||
((mcs[5] & nss_mask) == nss_mask)))
continue;
nss++;
}
if (nss > 4)
cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
else if (nss)
cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
}
return cap_info;
}
static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
{
struct ieee80211_mgmt *head;
const u8 *mobility_domain;
u8 *pos, *length_pos, buf[200];
u16 ctl = 0;
u8 fd_rsn_info[5];
size_t total_len, buf_len;
total_len = 24 + 2 + 12;
/* FILS Discovery Frame Control */
ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
FD_FRAME_CTL_SHORT_SSID_PRESENT |
FD_FRAME_CTL_LENGTH_PRESENT |
FD_FRAME_CTL_CAP_PRESENT;
total_len += 4 + 1 + 2;
/* Check for optional subfields and calculate length */
if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
total_len += sizeof(fd_rsn_info);
}
mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
if (mobility_domain) {
ctl |= FD_FRAME_CTL_MD_PRESENT;
total_len += 3;
}
pos = hostapd_eid_fils_indic(hapd, buf, 0);
buf_len = pos - buf;
total_len += buf_len;
head = os_zalloc(total_len);
if (!head)
return NULL;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memset(head->da, 0xff, ETH_ALEN);
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
head->u.action.category = WLAN_ACTION_PUBLIC;
head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
pos = &head->u.action.u.public_action.variable[0];
/* FILS Discovery Information field */
/* FILS Discovery Frame Control */
WPA_PUT_LE16(pos, ctl);
pos += 2;
/* Hardware or low-level driver will fill in the Timestamp value */
pos += 8;
/* Beacon Interval */
WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
pos += 2;
/* Short SSID */
WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
pos += sizeof(hapd->conf->ssid.short_ssid);
/* Store position of FILS discovery information element Length field */
length_pos = pos++;
/* FD Capability */
WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
pos += 2;
/* Operating Class - not present */
/* Primary Channel - not present */
/* AP Configuration Sequence Number - not present */
/* Access Network Options - not present */
/* FD RSN Information */
if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
pos += sizeof(fd_rsn_info);
}
/* Channel Center Frequency Segment 1 - not present */
/* Mobility Domain */
if (ctl & FD_FRAME_CTL_MD_PRESENT) {
os_memcpy(pos, &mobility_domain[2], 3);
pos += 3;
}
/* Fill in the Length field value */
*length_pos = pos - (length_pos + 1);
/* FILS Indication element */
if (buf_len) {
os_memcpy(pos, buf, buf_len);
pos += buf_len;
}
*len = pos - (u8 *) head;
wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
head, pos - (u8 *) head);
return (u8 *) head;
}
/* Configure FILS Discovery frame transmission parameters */
static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
params->fd_max_int = hapd->conf->fils_discovery_max_int;
if (is_6ghz_op_class(hapd->iconf->op_class) &&
params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
params->fd_min_int = hapd->conf->fils_discovery_min_int;
if (params->fd_min_int > params->fd_max_int)
params->fd_min_int = params->fd_max_int;
if (params->fd_max_int)
return hostapd_gen_fils_discovery(hapd,
&params->fd_frame_tmpl_len);
return NULL;
}
#endif /* CONFIG_FILS */
int ieee802_11_build_ap_params(struct hostapd_data *hapd, int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params) struct wpa_driver_ap_params *params)
{ {
@ -1478,6 +1715,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL; params->head = NULL;
os_free(params->proberesp); os_free(params->proberesp);
params->proberesp = NULL; params->proberesp = NULL;
#ifdef CONFIG_FILS
os_free(params->fd_frame_tmpl);
params->fd_frame_tmpl = NULL;
#endif /* CONFIG_FILS */
} }
@ -1534,6 +1775,10 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.sae_pwe = hapd->conf->sae_pwe; params.sae_pwe = hapd->conf->sae_pwe;
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
#endif /* CONFIG_FILS */
if (cmode && if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->enable_edmg, iconf->channel, iconf->enable_edmg,

View file

@ -537,6 +537,8 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm, u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len, u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len); const u8 *req_ies, size_t req_ies_len);
bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg); void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z); void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth, void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,

View file

@ -1125,6 +1125,7 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
#ifdef CONFIG_FILS #ifdef CONFIG_FILS
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm, u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len, u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len) const u8 *req_ies, size_t req_ies_len)
@ -1141,4 +1142,91 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
return pos; return pos;
return pos + res; return pos + res;
} }
bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
u8 *fd_rsn_info)
{
struct wpa_auth_config *conf;
u32 selectors = 0;
u8 *pos = fd_rsn_info;
int i, res;
u32 cipher, suite, selector, mask;
u8 tmp[10 * RSN_SELECTOR_LEN];
if (!wpa_auth)
return false;
conf = &wpa_auth->conf;
if (!(conf->wpa & WPA_PROTO_RSN))
return false;
/* RSN Capability (B0..B15) */
WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
pos += 2;
/* Group Data Cipher Suite Selector (B16..B21) */
suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
cipher = 63; /* No cipher suite selected */
if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
cipher = suite & 0xff;
else
cipher = 62; /* vendor specific */
selectors |= cipher;
/* Group Management Cipher Suite Selector (B22..B27) */
cipher = 63; /* Default to no cipher suite selected */
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
switch (conf->group_mgmt_cipher) {
case WPA_CIPHER_AES_128_CMAC:
cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
break;
case WPA_CIPHER_BIP_GMAC_128:
cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
break;
case WPA_CIPHER_BIP_GMAC_256:
cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
break;
case WPA_CIPHER_BIP_CMAC_256:
cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
break;
}
}
selectors |= cipher << 6;
/* Pairwise Cipher Suite Selector (B28..B33) */
cipher = 63; /* Default to no cipher suite selected */
res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
tmp[3] <= 13)
cipher = tmp[3];
selectors |= cipher << 12;
/* AKM Suite Selector (B34..B39) */
selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
WPA_KEY_MGMT_FT_FILS_SHA384;
if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
suite = conf->wpa_key_mgmt & mask;
if (suite == WPA_KEY_MGMT_FILS_SHA256)
selector = 1; /* 00-0f-ac:14 */
else if (suite == WPA_KEY_MGMT_FILS_SHA384)
selector = 2; /* 00-0f-ac:15 */
else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
WPA_KEY_MGMT_FILS_SHA384))
selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
selector = 4; /* 00-0f-ac:17 */
}
selectors |= selector << 18;
for (i = 0; i < 3; i++) {
*pos++ = selectors & 0xff;
selectors >>= 8;
}
return true;
}
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */

View file

@ -1541,6 +1541,26 @@ struct wpa_driver_ap_params {
* 2 = both hunting-and-pecking loop and hash-to-element enabled * 2 = both hunting-and-pecking loop and hash-to-element enabled
*/ */
int sae_pwe; int sae_pwe;
/**
* FILS Discovery frame minimum interval in TUs
*/
u32 fd_min_int;
/**
* FILS Discovery frame maximum interval in TUs (0 = FD frame disabled)
*/
u32 fd_max_int;
/**
* FILS Discovery frame template data
*/
u8 *fd_frame_tmpl;
/**
* FILS Discovery frame template length
*/
size_t fd_frame_tmpl_len;
}; };
struct wpa_driver_mesh_bss_params { struct wpa_driver_mesh_bss_params {