@ -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 ,
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 ;
os_free ( params - > proberesp ) ;
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 ;
# endif /* CONFIG_SAE */
# ifdef CONFIG_FILS
params . fd_frame_tmpl = hostapd_fils_discovery ( hapd , & params ) ;
# endif /* CONFIG_FILS */
if ( cmode & &
hostapd_set_freq_params ( & freq , iconf - > hw_mode , iface - > freq ,
iconf - > channel , iconf - > enable_edmg ,