MFV r346563:
Update wpa 2.8 --> 2.9 hostapd: * SAE changes - disable use of groups using Brainpool curves - improved protection against side channel attacks [https://w1.fi/security/2019-6/] * EAP-pwd changes - disable use of groups using Brainpool curves - improved protection against side channel attacks [https://w1.fi/security/2019-6/] * fixed FT-EAP initial mobility domain association using PMKSA caching * added configuration of airtime policy * fixed FILS to and RSNE into (Re)Association Response frames * fixed DPP bootstrapping URI parser of channel list * added support for regulatory WMM limitation (for ETSI) * added support for MACsec Key Agreement using IEEE 802.1X/PSK * added experimental support for EAP-TEAP server (RFC 7170) * added experimental support for EAP-TLS server with TLS v1.3 * added support for two server certificates/keys (RSA/ECC) * added AKMSuiteSelector into "STA <addr>" control interface data to determine with AKM was used for an association * added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and fast reauthentication use to be disabled * fixed an ECDH operation corner case with OpenSSL wpa_supplicant: * SAE changes - disable use of groups using Brainpool curves - improved protection against side channel attacks [https://w1.fi/security/2019-6/] * EAP-pwd changes - disable use of groups using Brainpool curves - allow the set of groups to be configured (eap_pwd_groups) - improved protection against side channel attacks [https://w1.fi/security/2019-6/] * fixed FT-EAP initial mobility domain association using PMKSA caching (disabled by default for backwards compatibility; can be enabled with ft_eap_pmksa_caching=1) * fixed a regression in OpenSSL 1.1+ engine loading * added validation of RSNE in (Re)Association Response frames * fixed DPP bootstrapping URI parser of channel list * extended EAP-SIM/AKA fast re-authentication to allow use with FILS * extended ca_cert_blob to support PEM format * improved robustness of P2P Action frame scheduling * added support for EAP-SIM/AKA using anonymous@realm identity * fixed Hotspot 2.0 credential selection based on roaming consortium to ignore credentials without a specific EAP method * added experimental support for EAP-TEAP peer (RFC 7170) * added experimental support for EAP-TLS peer with TLS v1.3 * fixed a regression in WMM parameter configuration for a TDLS peer * fixed a regression in operation with drivers that offload 802.1X 4-way handshake * fixed an ECDH operation corner case with OpenSSL MFC after: 1 week Security: https://w1.fi/security/2019-6/\ sae-eap-pwd-side-channel-attack-update.txt
This commit is contained in:
commit
53d87406a6
@ -1,5 +1,29 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2019-08-07 - v2.9
|
||||
* SAE changes
|
||||
- disable use of groups using Brainpool curves
|
||||
- improved protection against side channel attacks
|
||||
[https://w1.fi/security/2019-6/]
|
||||
* EAP-pwd changes
|
||||
- disable use of groups using Brainpool curves
|
||||
- improved protection against side channel attacks
|
||||
[https://w1.fi/security/2019-6/]
|
||||
* fixed FT-EAP initial mobility domain association using PMKSA caching
|
||||
* added configuration of airtime policy
|
||||
* fixed FILS to and RSNE into (Re)Association Response frames
|
||||
* fixed DPP bootstrapping URI parser of channel list
|
||||
* added support for regulatory WMM limitation (for ETSI)
|
||||
* added support for MACsec Key Agreement using IEEE 802.1X/PSK
|
||||
* added experimental support for EAP-TEAP server (RFC 7170)
|
||||
* added experimental support for EAP-TLS server with TLS v1.3
|
||||
* added support for two server certificates/keys (RSA/ECC)
|
||||
* added AKMSuiteSelector into "STA <addr>" control interface data to
|
||||
determine with AKM was used for an association
|
||||
* added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and
|
||||
fast reauthentication use to be disabled
|
||||
* fixed an ECDH operation corner case with OpenSSL
|
||||
|
||||
2019-04-21 - v2.8
|
||||
* SAE changes
|
||||
- added support for SAE Password Identifier
|
||||
|
@ -24,14 +24,6 @@
|
||||
#include "config_file.h"
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
#ifdef EAP_SERVER
|
||||
static struct hostapd_radius_attr *
|
||||
hostapd_parse_radius_attr(const char *value);
|
||||
#endif /* EAP_SERVER */
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
const char *fname)
|
||||
@ -660,75 +652,6 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_radius_attr *
|
||||
hostapd_parse_radius_attr(const char *value)
|
||||
{
|
||||
const char *pos;
|
||||
char syntax;
|
||||
struct hostapd_radius_attr *attr;
|
||||
size_t len;
|
||||
|
||||
attr = os_zalloc(sizeof(*attr));
|
||||
if (attr == NULL)
|
||||
return NULL;
|
||||
|
||||
attr->type = atoi(value);
|
||||
|
||||
pos = os_strchr(value, ':');
|
||||
if (pos == NULL) {
|
||||
attr->val = wpabuf_alloc(1);
|
||||
if (attr->val == NULL) {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put_u8(attr->val, 0);
|
||||
return attr;
|
||||
}
|
||||
|
||||
pos++;
|
||||
if (pos[0] == '\0' || pos[1] != ':') {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
syntax = *pos++;
|
||||
pos++;
|
||||
|
||||
switch (syntax) {
|
||||
case 's':
|
||||
attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
|
||||
break;
|
||||
case 'x':
|
||||
len = os_strlen(pos);
|
||||
if (len & 1)
|
||||
break;
|
||||
len /= 2;
|
||||
attr->val = wpabuf_alloc(len);
|
||||
if (attr->val == NULL)
|
||||
break;
|
||||
if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
|
||||
wpabuf_free(attr->val);
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
attr->val = wpabuf_alloc(4);
|
||||
if (attr->val)
|
||||
wpabuf_put_be32(attr->val, atoi(pos));
|
||||
break;
|
||||
default:
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (attr->val == NULL) {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
|
||||
{
|
||||
@ -2313,6 +2236,42 @@ static unsigned int parse_tls_flags(const char *val)
|
||||
#endif /* EAP_SERVER */
|
||||
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
static int add_airtime_weight(struct hostapd_bss_config *bss, char *value)
|
||||
{
|
||||
struct airtime_sta_weight *wt;
|
||||
char *pos, *next;
|
||||
|
||||
wt = os_zalloc(sizeof(*wt));
|
||||
if (!wt)
|
||||
return -1;
|
||||
|
||||
/* 02:01:02:03:04:05 10 */
|
||||
pos = value;
|
||||
next = os_strchr(pos, ' ');
|
||||
if (next)
|
||||
*next++ = '\0';
|
||||
if (!next || hwaddr_aton(pos, wt->addr)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid station address: '%s'", pos);
|
||||
os_free(wt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = next;
|
||||
wt->weight = atoi(pos);
|
||||
if (!wt->weight) {
|
||||
wpa_printf(MSG_ERROR, "Invalid weight: '%s'", pos);
|
||||
os_free(wt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wt->next = bss->airtime_weight_list;
|
||||
bss->airtime_weight_list = wt;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
{
|
||||
@ -2376,6 +2335,36 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss,
|
||||
const char *pos)
|
||||
{
|
||||
struct dpp_controller_conf *conf;
|
||||
char *val;
|
||||
|
||||
conf = os_zalloc(sizeof(*conf));
|
||||
if (!conf)
|
||||
return -1;
|
||||
val = get_param(pos, "ipaddr=");
|
||||
if (!val || hostapd_parse_ip_addr(val, &conf->ipaddr))
|
||||
goto fail;
|
||||
os_free(val);
|
||||
val = get_param(pos, "pkhash=");
|
||||
if (!val || os_strlen(val) != 2 * SHA256_MAC_LEN ||
|
||||
hexstr2bin(val, conf->pkhash, SHA256_MAC_LEN) < 0)
|
||||
goto fail;
|
||||
os_free(val);
|
||||
conf->next = bss->dpp_controller;
|
||||
bss->dpp_controller = conf;
|
||||
return 0;
|
||||
fail:
|
||||
os_free(val);
|
||||
os_free(conf);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss,
|
||||
const char *buf, char *pos, int line)
|
||||
@ -2496,7 +2485,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "eapol_version") == 0) {
|
||||
int eapol_version = atoi(pos);
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
if (eapol_version < 1 || eapol_version > 3) {
|
||||
#else /* CONFIG_MACSEC */
|
||||
if (eapol_version < 1 || eapol_version > 2) {
|
||||
#endif /* CONFIG_MACSEC */
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid EAPOL version (%d): '%s'.",
|
||||
line, eapol_version, pos);
|
||||
@ -2519,12 +2512,21 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "server_cert") == 0) {
|
||||
os_free(bss->server_cert);
|
||||
bss->server_cert = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "server_cert2") == 0) {
|
||||
os_free(bss->server_cert2);
|
||||
bss->server_cert2 = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "private_key") == 0) {
|
||||
os_free(bss->private_key);
|
||||
bss->private_key = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "private_key2") == 0) {
|
||||
os_free(bss->private_key2);
|
||||
bss->private_key2 = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "private_key_passwd") == 0) {
|
||||
os_free(bss->private_key_passwd);
|
||||
bss->private_key_passwd = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "private_key_passwd2") == 0) {
|
||||
os_free(bss->private_key_passwd2);
|
||||
bss->private_key_passwd2 = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "check_cert_subject") == 0) {
|
||||
if (!pos[0]) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
|
||||
@ -2605,6 +2607,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
|
||||
bss->pac_key_refresh_time = atoi(pos);
|
||||
#endif /* EAP_SERVER_FAST */
|
||||
#ifdef EAP_SERVER_TEAP
|
||||
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid eap_teap_auth value",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
bss->eap_teap_auth = val;
|
||||
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
|
||||
bss->eap_teap_pac_no_inner = atoi(pos);
|
||||
#endif /* EAP_SERVER_TEAP */
|
||||
#ifdef EAP_SERVER_SIM
|
||||
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
|
||||
os_free(bss->eap_sim_db);
|
||||
@ -2613,6 +2629,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->eap_sim_db_timeout = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
|
||||
bss->eap_sim_aka_result_ind = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
|
||||
bss->eap_sim_id = atoi(pos);
|
||||
#endif /* EAP_SERVER_SIM */
|
||||
#ifdef EAP_SERVER_TNC
|
||||
} else if (os_strcmp(buf, "tnc") == 0) {
|
||||
@ -2816,6 +2834,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
a = a->next;
|
||||
a->next = attr;
|
||||
}
|
||||
} else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
|
||||
os_free(bss->radius_req_attr_sqlite);
|
||||
bss->radius_req_attr_sqlite = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "radius_das_port") == 0) {
|
||||
bss->radius_das_port = atoi(pos);
|
||||
} else if (os_strcmp(buf, "radius_das_client") == 0) {
|
||||
@ -3442,6 +3463,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->he_op.he_twt_required = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
|
||||
conf->he_op.he_rts_threshold = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_basic_mcs_nss_set") == 0) {
|
||||
conf->he_op.he_basic_mcs_nss_set = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
|
||||
conf->he_mu_edca.he_qos_info |=
|
||||
set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
|
||||
@ -3526,6 +3549,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
|
||||
atoi(pos) & 0xff;
|
||||
} else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
|
||||
conf->spr.sr_control = atoi(pos) & 0xff;
|
||||
} else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
|
||||
conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
|
||||
conf->spr.srg_obss_pd_min_offset = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
|
||||
conf->spr.srg_obss_pd_max_offset = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
|
||||
conf->he_oper_chwidth = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
|
||||
conf->he_oper_centr_freq_seg0_idx = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
|
||||
conf->he_oper_centr_freq_seg1_idx = atoi(pos);
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
|
||||
bss->max_listen_interval = atoi(pos);
|
||||
@ -4298,6 +4335,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "dpp_csign") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
|
||||
return 1;
|
||||
#ifdef CONFIG_DPP2
|
||||
} else if (os_strcmp(buf, "dpp_controller") == 0) {
|
||||
if (hostapd_dpp_controller_parse(bss, pos))
|
||||
return 1;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef CONFIG_OWE
|
||||
} else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
|
||||
@ -4349,6 +4391,121 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->rssi_reject_assoc_timeout = atoi(pos);
|
||||
} else if (os_strcmp(buf, "pbss") == 0) {
|
||||
bss->pbss = atoi(pos);
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
} else if (os_strcmp(buf, "airtime_mode") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > AIRTIME_MODE_MAX) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Unknown airtime_mode",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
conf->airtime_mode = val;
|
||||
} else if (os_strcmp(buf, "airtime_update_interval") == 0) {
|
||||
conf->airtime_update_interval = atoi(pos);
|
||||
} else if (os_strcmp(buf, "airtime_bss_weight") == 0) {
|
||||
bss->airtime_weight = atoi(pos);
|
||||
} else if (os_strcmp(buf, "airtime_bss_limit") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid airtime_bss_limit (must be 0 or 1)",
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
bss->airtime_limit = val;
|
||||
} else if (os_strcmp(buf, "airtime_sta_weight") == 0) {
|
||||
if (add_airtime_weight(bss, pos) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid airtime weight '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
#ifdef CONFIG_MACSEC
|
||||
} else if (os_strcmp(buf, "macsec_policy") == 0) {
|
||||
int macsec_policy = atoi(pos);
|
||||
|
||||
if (macsec_policy < 0 || macsec_policy > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_policy (%d): '%s'.",
|
||||
line, macsec_policy, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_policy = macsec_policy;
|
||||
} else if (os_strcmp(buf, "macsec_integ_only") == 0) {
|
||||
int macsec_integ_only = atoi(pos);
|
||||
|
||||
if (macsec_integ_only < 0 || macsec_integ_only > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_integ_only (%d): '%s'.",
|
||||
line, macsec_integ_only, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_integ_only = macsec_integ_only;
|
||||
} else if (os_strcmp(buf, "macsec_replay_protect") == 0) {
|
||||
int macsec_replay_protect = atoi(pos);
|
||||
|
||||
if (macsec_replay_protect < 0 || macsec_replay_protect > 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_replay_protect (%d): '%s'.",
|
||||
line, macsec_replay_protect, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_replay_protect = macsec_replay_protect;
|
||||
} else if (os_strcmp(buf, "macsec_replay_window") == 0) {
|
||||
bss->macsec_replay_window = atoi(pos);
|
||||
} else if (os_strcmp(buf, "macsec_port") == 0) {
|
||||
int macsec_port = atoi(pos);
|
||||
|
||||
if (macsec_port < 1 || macsec_port > 65534) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid macsec_port (%d): '%s'.",
|
||||
line, macsec_port, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->macsec_port = macsec_port;
|
||||
} else if (os_strcmp(buf, "mka_priority") == 0) {
|
||||
int mka_priority = atoi(pos);
|
||||
|
||||
if (mka_priority < 0 || mka_priority > 255) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid mka_priority (%d): '%s'.",
|
||||
line, mka_priority, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->mka_priority = mka_priority;
|
||||
} else if (os_strcmp(buf, "mka_cak") == 0) {
|
||||
size_t len = os_strlen(pos);
|
||||
|
||||
if (len > 2 * MACSEC_CAK_MAX_LEN ||
|
||||
(len != 2 * 16 && len != 2 * 32) ||
|
||||
hexstr2bin(pos, bss->mka_cak, len / 2)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->mka_cak_len = len / 2;
|
||||
bss->mka_psk_set |= MKA_PSK_SET_CAK;
|
||||
} else if (os_strcmp(buf, "mka_ckn") == 0) {
|
||||
size_t len = os_strlen(pos);
|
||||
|
||||
if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
|
||||
len < 2 || /* too short */
|
||||
len % 2 != 0 /* not an integral number of bytes */) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->mka_ckn_len = len / 2;
|
||||
if (hexstr2bin(pos, bss->mka_ckn, bss->mka_ckn_len)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
|
||||
line, pos);
|
||||
return -1;
|
||||
}
|
||||
bss->mka_psk_set |= MKA_PSK_SET_CKN;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
|
@ -1830,26 +1830,40 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
struct iphdr ip;
|
||||
const u8 *pos;
|
||||
unsigned int i;
|
||||
char extra[30];
|
||||
|
||||
if (len != HWSIM_PACKETLEN)
|
||||
if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"test data: RX - ignore unexpected length %d",
|
||||
(int) len);
|
||||
return;
|
||||
}
|
||||
|
||||
eth = (const struct ether_header *) buf;
|
||||
os_memcpy(&ip, eth + 1, sizeof(ip));
|
||||
pos = &buf[sizeof(*eth) + sizeof(ip)];
|
||||
|
||||
if (ip.ihl != 5 || ip.version != 4 ||
|
||||
ntohs(ip.tot_len) != HWSIM_IP_LEN)
|
||||
ntohs(ip.tot_len) > HWSIM_IP_LEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"test data: RX - ignore unexpect IP header");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
|
||||
if (*pos != (u8) i)
|
||||
for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
|
||||
if (*pos != (u8) i) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"test data: RX - ignore mismatching payload");
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
|
||||
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
|
||||
extra[0] = '\0';
|
||||
if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
|
||||
os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
|
||||
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
|
||||
}
|
||||
|
||||
|
||||
@ -1894,7 +1908,7 @@ static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
|
||||
static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
|
||||
{
|
||||
u8 dst[ETH_ALEN], src[ETH_ALEN];
|
||||
char *pos;
|
||||
char *pos, *pos2;
|
||||
int used;
|
||||
long int val;
|
||||
u8 tos;
|
||||
@ -1903,11 +1917,12 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
|
||||
struct iphdr *ip;
|
||||
u8 *dpos;
|
||||
unsigned int i;
|
||||
size_t send_len = HWSIM_IP_LEN;
|
||||
|
||||
if (hapd->l2_test == NULL)
|
||||
return -1;
|
||||
|
||||
/* format: <dst> <src> <tos> */
|
||||
/* format: <dst> <src> <tos> [len=<length>] */
|
||||
|
||||
pos = cmd;
|
||||
used = hwaddr_aton2(pos, dst);
|
||||
@ -1921,11 +1936,19 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
|
||||
return -1;
|
||||
pos += used;
|
||||
|
||||
val = strtol(pos, NULL, 0);
|
||||
val = strtol(pos, &pos2, 0);
|
||||
if (val < 0 || val > 0xff)
|
||||
return -1;
|
||||
tos = val;
|
||||
|
||||
pos = os_strstr(pos2, " len=");
|
||||
if (pos) {
|
||||
i = atoi(pos + 5);
|
||||
if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
|
||||
return -1;
|
||||
send_len = i;
|
||||
}
|
||||
|
||||
eth = (struct ether_header *) &buf[2];
|
||||
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
|
||||
os_memcpy(eth->ether_shost, src, ETH_ALEN);
|
||||
@ -1936,17 +1959,17 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
|
||||
ip->version = 4;
|
||||
ip->ttl = 64;
|
||||
ip->tos = tos;
|
||||
ip->tot_len = htons(HWSIM_IP_LEN);
|
||||
ip->tot_len = htons(send_len);
|
||||
ip->protocol = 1;
|
||||
ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
|
||||
ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
|
||||
ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
|
||||
dpos = (u8 *) (ip + 1);
|
||||
for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
|
||||
for (i = 0; i < send_len - sizeof(*ip); i++)
|
||||
*dpos++ = i;
|
||||
|
||||
if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
|
||||
HWSIM_PACKETLEN) < 0)
|
||||
sizeof(struct ether_header) + send_len) < 0)
|
||||
return -1;
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
|
||||
|
@ -108,11 +108,18 @@ CONFIG_EAP_TTLS=y
|
||||
#CONFIG_EAP_GPSK_SHA256=y
|
||||
|
||||
# EAP-FAST for the integrated EAP server
|
||||
# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
|
||||
# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
|
||||
# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
|
||||
#CONFIG_EAP_FAST=y
|
||||
|
||||
# EAP-TEAP for the integrated EAP server
|
||||
# Note: The current EAP-TEAP implementation is experimental and should not be
|
||||
# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number
|
||||
# of conflicting statements and missing details and the implementation has
|
||||
# vendor specific workarounds for those and as such, may not interoperate with
|
||||
# any other implementation. This should not be used for anything else than
|
||||
# experimentation and interoperability testing until those issues has been
|
||||
# resolved.
|
||||
#CONFIG_EAP_TEAP=y
|
||||
|
||||
# Wi-Fi Protected Setup (WPS)
|
||||
#CONFIG_WPS=y
|
||||
# Enable UPnP support for external WPS Registrars
|
||||
@ -376,6 +383,9 @@ CONFIG_IPV6=y
|
||||
# Experimental implementation of draft-harkins-owe-07.txt
|
||||
#CONFIG_OWE=y
|
||||
|
||||
# Airtime policy support
|
||||
#CONFIG_AIRTIME_POLICY=y
|
||||
|
||||
# Override default value for the wpa_disable_eapol_key_retries configuration
|
||||
# parameter. See that parameter in hostapd.conf for more details.
|
||||
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
|
||||
|
@ -121,6 +121,11 @@ int eap_server_register_methods(void)
|
||||
ret = eap_server_fast_register();
|
||||
#endif /* EAP_SERVER_FAST */
|
||||
|
||||
#ifdef EAP_SERVER_TEAP
|
||||
if (ret == 0)
|
||||
ret = eap_server_teap_register();
|
||||
#endif /* EAP_SERVER_TEAP */
|
||||
|
||||
#ifdef EAP_SERVER_WSC
|
||||
if (ret == 0)
|
||||
ret = eap_server_wsc_register();
|
||||
|
@ -782,10 +782,8 @@ wmm_ac_vo_acm=0
|
||||
# 1 = supported
|
||||
#he_mu_beamformer=1
|
||||
|
||||
# he_bss_color: BSS color
|
||||
# 0 = no BSS color (default)
|
||||
# unsigned integer = BSS color
|
||||
#he_bss_color=0
|
||||
# he_bss_color: BSS color (1-63)
|
||||
#he_bss_color=1
|
||||
|
||||
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
|
||||
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
|
||||
@ -801,6 +799,17 @@ wmm_ac_vo_acm=0
|
||||
# unsigned integer = duration in units of 16 us
|
||||
#he_rts_threshold=0
|
||||
|
||||
# HE operating channel information; see matching vht_* parameters for details.
|
||||
#he_oper_chwidth
|
||||
#he_oper_centr_freq_seg0_idx
|
||||
#he_oper_centr_freq_seg1_idx
|
||||
|
||||
#he_basic_mcs_nss_set: Basic NSS/MCS set
|
||||
# 16-bit combination of 2-bit values of Max HE-MCS For 1..8 SS; each 2-bit
|
||||
# value having following meaning:
|
||||
# 0 = HE-MCS 0-7, 1 = HE-MCS 0-9, 2 = HE-MCS 0-11, 3 = not supported
|
||||
#he_basic_mcs_nss_set
|
||||
|
||||
#he_mu_edca_qos_info_param_count
|
||||
#he_mu_edca_qos_info_q_ack
|
||||
#he_mu_edca_qos_info_queue_request=1
|
||||
@ -825,6 +834,12 @@ wmm_ac_vo_acm=0
|
||||
#he_mu_edca_ac_vo_ecwmax=15
|
||||
#he_mu_edca_ac_vo_timer=255
|
||||
|
||||
# Spatial Reuse Parameter Set
|
||||
#he_spr_sr_control
|
||||
#he_spr_non_srg_obss_pd_max_offset
|
||||
#he_spr_srg_obss_pd_min_offset
|
||||
#he_spr_srg_obss_pd_max_offset
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -836,6 +851,8 @@ wmm_ac_vo_acm=0
|
||||
# the new version number correctly (they seem to drop the frames completely).
|
||||
# In order to make hostapd interoperate with these clients, the version number
|
||||
# can be set to the older version (1) with this configuration value.
|
||||
# Note: When using MACsec, eapol_version shall be set to 3, which is
|
||||
# defined in IEEE Std 802.1X-2010.
|
||||
#eapol_version=2
|
||||
|
||||
# Optional displayable message sent with EAP Request-Identity. The first \0
|
||||
@ -879,6 +896,54 @@ eapol_key_index_workaround=0
|
||||
# ERP is enabled (eap_server_erp=1).
|
||||
#erp_domain=example.com
|
||||
|
||||
##### MACsec ##################################################################
|
||||
|
||||
# macsec_policy: IEEE 802.1X/MACsec options
|
||||
# This determines how sessions are secured with MACsec (only for MACsec
|
||||
# drivers).
|
||||
# 0: MACsec not in use (default)
|
||||
# 1: MACsec enabled - Should secure, accept key server's advice to
|
||||
# determine whether to use a secure session or not.
|
||||
#
|
||||
# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
|
||||
# This setting applies only when MACsec is in use, i.e.,
|
||||
# - macsec_policy is enabled
|
||||
# - the key server has decided to enable MACsec
|
||||
# 0: Encrypt traffic (default)
|
||||
# 1: Integrity only
|
||||
#
|
||||
# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
|
||||
# This setting applies only when MACsec is in use, i.e.,
|
||||
# - macsec_policy is enabled
|
||||
# - the key server has decided to enable MACsec
|
||||
# 0: Replay protection disabled (default)
|
||||
# 1: Replay protection enabled
|
||||
#
|
||||
# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
|
||||
# This determines a window in which replay is tolerated, to allow receipt
|
||||
# of frames that have been misordered by the network.
|
||||
# This setting applies only when MACsec replay protection active, i.e.,
|
||||
# - macsec_replay_protect is enabled
|
||||
# - the key server has decided to enable MACsec
|
||||
# 0: No replay window, strict check (default)
|
||||
# 1..2^32-1: number of packets that could be misordered
|
||||
#
|
||||
# macsec_port: IEEE 802.1X/MACsec port
|
||||
# Port component of the SCI
|
||||
# Range: 1-65534 (default: 1)
|
||||
#
|
||||
# mka_priority (Priority of MKA Actor)
|
||||
# Range: 0..255 (default: 255)
|
||||
#
|
||||
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
|
||||
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
|
||||
# In this mode, instances of hostapd can act as MACsec peers. The peer
|
||||
# with lower priority will become the key server and start distributing SAKs.
|
||||
# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
|
||||
# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
|
||||
# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
|
||||
# (2..64 hex-digits)
|
||||
|
||||
##### Integrated EAP server ###################################################
|
||||
|
||||
# Optionally, hostapd can be configured to use an integrated EAP server
|
||||
@ -912,6 +977,23 @@ eap_server=0
|
||||
# Passphrase for private key
|
||||
#private_key_passwd=secret passphrase
|
||||
|
||||
# An alternative server certificate and private key can be configured with the
|
||||
# following parameters (with values just like the parameters above without the
|
||||
# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots
|
||||
# for both server certificates and/or client certificates).
|
||||
#
|
||||
# The main use case for this alternative server certificate configuration is to
|
||||
# enable both RSA and ECC public keys. The server will pick which one to use
|
||||
# based on the client preferences for the cipher suite (in the TLS ClientHello
|
||||
# message). It should be noted that number of deployed EAP peer implementations
|
||||
# do not filter out the cipher suite list based on their local configuration and
|
||||
# as such, configuration of alternative types of certificates on the server may
|
||||
# result in interoperability issues.
|
||||
#server_cert2=/etc/hostapd.server-ecc.pem
|
||||
#private_key2=/etc/hostapd.server-ecc.prv
|
||||
#private_key_passwd2=secret passphrase
|
||||
|
||||
|
||||
# Server identity
|
||||
# EAP methods that provide mechanism for authenticated server identity delivery
|
||||
# use this value. If not set, "hostapd" is used as a default.
|
||||
@ -1109,10 +1191,27 @@ eap_server=0
|
||||
# (or fewer) of the lifetime remains.
|
||||
#pac_key_refresh_time=86400
|
||||
|
||||
# EAP-TEAP authentication type
|
||||
# 0 = inner EAP (default)
|
||||
# 1 = Basic-Password-Auth
|
||||
#eap_teap_auth=0
|
||||
|
||||
# EAP-TEAP authentication behavior when using PAC
|
||||
# 0 = perform inner authentication (default)
|
||||
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
|
||||
#eap_teap_pac_no_inner=0
|
||||
|
||||
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
|
||||
# (default: 0 = disabled).
|
||||
#eap_sim_aka_result_ind=1
|
||||
|
||||
# EAP-SIM and EAP-AKA identity options
|
||||
# 0 = do not use pseudonyms or fast reauthentication
|
||||
# 1 = use pseudonyms, but not fast reauthentication
|
||||
# 2 = do not use pseudonyms, but use fast reauthentication
|
||||
# 3 = use pseudonyms and use fast reauthentication (default)
|
||||
#eap_sim_id=3
|
||||
|
||||
# Trusted Network Connect (TNC)
|
||||
# If enabled, TNC validation will be required before the peer is allowed to
|
||||
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
|
||||
@ -1292,6 +1391,17 @@ own_ip_addr=127.0.0.1
|
||||
# Operator-Name = "Operator"
|
||||
#radius_acct_req_attr=126:s:Operator
|
||||
|
||||
# If SQLite support is included, path to a database from which additional
|
||||
# RADIUS request attributes are extracted based on the station MAC address.
|
||||
#
|
||||
# The schema for the radius_attributes table is:
|
||||
# id | sta | reqtype | attr : multi-key (sta, reqtype)
|
||||
# id = autonumber
|
||||
# sta = station MAC address in `11:22:33:44:55:66` format.
|
||||
# type = `auth` | `acct` | NULL (match any)
|
||||
# attr = existing config file format, e.g. `126:s:Test Operator`
|
||||
#radius_req_attr_sqlite=radius_attr.sqlite
|
||||
|
||||
# Dynamic Authorization Extensions (RFC 5176)
|
||||
# This mechanism can be used to allow dynamic changes to user session based on
|
||||
# commands from a RADIUS server (or some other disconnect client that has the
|
||||
@ -2492,6 +2602,42 @@ own_ip_addr=127.0.0.1
|
||||
# that allows sending of such data. Default: 0.
|
||||
#stationary_ap=0
|
||||
|
||||
##### Airtime policy configuration ###########################################
|
||||
|
||||
# Set the airtime policy operating mode:
|
||||
# 0 = disabled (default)
|
||||
# 1 = static config
|
||||
# 2 = per-BSS dynamic config
|
||||
# 3 = per-BSS limit mode
|
||||
#airtime_mode=0
|
||||
|
||||
# Interval (in milliseconds) to poll the kernel for updated station activity in
|
||||
# dynamic and limit modes
|
||||
#airtime_update_interval=200
|
||||
|
||||
# Static configuration of station weights (when airtime_mode=1). Kernel default
|
||||
# weight is 256; set higher for larger airtime share, lower for smaller share.
|
||||
# Each entry is a MAC address followed by a weight.
|
||||
#airtime_sta_weight=02:01:02:03:04:05 256
|
||||
#airtime_sta_weight=02:01:02:03:04:06 512
|
||||
|
||||
# Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will
|
||||
# configure station weights to enforce the correct ratio between BSS weights
|
||||
# depending on the number of active stations. The *ratios* between different
|
||||
# BSSes is what's important, not the absolute numbers.
|
||||
# Must be set for all BSSes if airtime_mode=2 or 3, has no effect otherwise.
|
||||
#airtime_bss_weight=1
|
||||
|
||||
# Whether the current BSS should be limited (when airtime_mode=3).
|
||||
#
|
||||
# If set, the BSS weight ratio will be applied in the case where the current BSS
|
||||
# would exceed the share defined by the BSS weight ratio. E.g., if two BSSes are
|
||||
# set to the same weights, and one is set to limited, the limited BSS will get
|
||||
# no more than half the available airtime, but if the non-limited BSS has more
|
||||
# stations active, that *will* be allowed to exceed its half of the available
|
||||
# airtime.
|
||||
#airtime_bss_limit=1
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
|
@ -1214,6 +1214,13 @@ static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
@ -1617,6 +1624,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"= reload configuration for current interface" },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL,
|
||||
"= disable hostapd on current interface" },
|
||||
{ "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
|
||||
"= update Beacon frame contents\n"},
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
|
||||
"= drop all ERP keys"},
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL,
|
||||
|
@ -653,6 +653,9 @@ int main(int argc, char *argv[])
|
||||
int start_ifaces_in_sync = 0;
|
||||
char **if_names = NULL;
|
||||
size_t if_names_size = 0;
|
||||
#ifdef CONFIG_DPP
|
||||
struct dpp_global_config dpp_conf;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (os_program_init())
|
||||
return -1;
|
||||
@ -672,7 +675,9 @@ int main(int argc, char *argv[])
|
||||
dl_list_init(&interfaces.eth_p_oui);
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
#ifdef CONFIG_DPP
|
||||
interfaces.dpp = dpp_global_init();
|
||||
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
|
||||
/* TODO: dpp_conf.msg_ctx? */
|
||||
interfaces.dpp = dpp_global_init(&dpp_conf);
|
||||
if (!interfaces.dpp)
|
||||
return -1;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
@ -1588,6 +1588,7 @@ static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id,
|
||||
xml_node_t *node, const char *fqdn)
|
||||
{
|
||||
char buf[200], dir[200];
|
||||
int res;
|
||||
|
||||
wpa_printf(MSG_INFO, "- Credential/DigitalCertificate");
|
||||
|
||||
@ -1599,14 +1600,20 @@ static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id,
|
||||
wpa_printf(MSG_INFO, "Failed to set username");
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, fqdn);
|
||||
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir,
|
||||
fqdn);
|
||||
if (os_snprintf_error(sizeof(buf), res))
|
||||
return;
|
||||
if (os_file_exists(buf)) {
|
||||
if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) {
|
||||
wpa_printf(MSG_INFO, "Failed to set client_cert");
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, fqdn);
|
||||
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir,
|
||||
fqdn);
|
||||
if (os_snprintf_error(sizeof(buf), res))
|
||||
return;
|
||||
if (os_file_exists(buf)) {
|
||||
if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) {
|
||||
wpa_printf(MSG_INFO, "Failed to set private_key");
|
||||
@ -1620,6 +1627,7 @@ static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id,
|
||||
{
|
||||
char *str = xml_node_get_text(ctx->xml, node);
|
||||
char buf[200], dir[200];
|
||||
int res;
|
||||
|
||||
if (str == NULL)
|
||||
return;
|
||||
@ -1634,7 +1642,9 @@ static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id,
|
||||
|
||||
if (getcwd(dir, sizeof(dir)) == NULL)
|
||||
return;
|
||||
snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
|
||||
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
|
||||
if (os_snprintf_error(sizeof(buf), res))
|
||||
return;
|
||||
if (os_file_exists(buf)) {
|
||||
if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) {
|
||||
wpa_printf(MSG_INFO, "Failed to set CA cert");
|
||||
@ -2717,6 +2727,8 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
|
||||
|
||||
if (!pps_fname) {
|
||||
char buf[256];
|
||||
int res;
|
||||
|
||||
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
|
||||
if (address && os_strncmp(address, "fqdn=", 5) == 0) {
|
||||
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
|
||||
@ -2737,8 +2749,13 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
|
||||
"SP/%s/pps.xml", ctx->fqdn);
|
||||
pps_fname = pps_fname_buf;
|
||||
|
||||
os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
|
||||
buf);
|
||||
res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf),
|
||||
"SP/%s/ca.pem", buf);
|
||||
if (os_snprintf_error(sizeof(ca_fname_buf), res)) {
|
||||
os_free(ctx->fqdn);
|
||||
ctx->fqdn = NULL;
|
||||
return -1;
|
||||
}
|
||||
ca_fname = ca_fname_buf;
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||
msg) < 0)
|
||||
goto fail;
|
||||
|
||||
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
|
||||
goto fail;
|
||||
|
||||
if (sta) {
|
||||
for (i = 0; ; i++) {
|
||||
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
||||
|
@ -594,12 +594,12 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac) {
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
}
|
||||
@ -607,7 +607,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
|
||||
bw = num_chan_to_bw(n_chans);
|
||||
|
||||
/* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
|
||||
/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
|
||||
@ -647,9 +647,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
iface->conf->ieee80211ac) {
|
||||
if (iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_80MHZ &&
|
||||
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CHANWIDTH_80MHZ &&
|
||||
!acs_usable_vht80_chan(chan)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for VHT80",
|
||||
@ -657,8 +657,8 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_160MHZ &&
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CHANWIDTH_160MHZ &&
|
||||
!acs_usable_vht160_chan(chan)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for VHT160",
|
||||
@ -783,20 +783,20 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
|
||||
static void acs_adjust_center_freq(struct hostapd_iface *iface)
|
||||
{
|
||||
int offset;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
|
||||
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
offset = 2 * iface->conf->secondary_channel;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_80MHZ:
|
||||
offset = 6;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
offset = 14;
|
||||
break;
|
||||
default:
|
||||
@ -807,8 +807,8 @@ static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
|
||||
return;
|
||||
}
|
||||
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx =
|
||||
iface->conf->channel + offset;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
iface->conf->channel + offset);
|
||||
}
|
||||
|
||||
|
||||
@ -863,8 +863,8 @@ static void acs_study(struct hostapd_iface *iface)
|
||||
|
||||
iface->conf->channel = ideal_chan->chan;
|
||||
|
||||
if (iface->conf->ieee80211ac)
|
||||
acs_adjust_vht_center_freq(iface);
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
|
||||
acs_adjust_center_freq(iface);
|
||||
|
||||
err = 0;
|
||||
fail:
|
||||
|
269
contrib/wpa/src/ap/airtime_policy.c
Normal file
269
contrib/wpa/src/ap/airtime_policy.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Airtime policy configuration
|
||||
* Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
#include "airtime_policy.h"
|
||||
|
||||
/* Idea:
|
||||
* Two modes of airtime enforcement:
|
||||
* 1. Static weights: specify weights per MAC address with a per-BSS default
|
||||
* 2. Per-BSS limits: Dynamically calculate weights of backlogged stations to
|
||||
* enforce relative total shares between BSSes.
|
||||
*
|
||||
* - Periodic per-station callback to update queue status.
|
||||
*
|
||||
* Copy accounting_sta_update_stats() to get TXQ info and airtime weights and
|
||||
* keep them updated in sta_info.
|
||||
*
|
||||
* - Separate periodic per-bss (or per-iface?) callback to update weights.
|
||||
*
|
||||
* Just need to loop through all interfaces, count sum the active stations (or
|
||||
* should the per-STA callback just adjust that for the BSS?) and calculate new
|
||||
* weights.
|
||||
*/
|
||||
|
||||
static int get_airtime_policy_update_timeout(struct hostapd_iface *iface,
|
||||
unsigned int *sec,
|
||||
unsigned int *usec)
|
||||
{
|
||||
unsigned int update_int = iface->conf->airtime_update_interval;
|
||||
|
||||
if (!update_int) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Airtime policy: Invalid airtime policy update interval %u",
|
||||
update_int);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sec = update_int / 1000;
|
||||
*usec = (update_int % 1000) * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void set_new_backlog_time(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct os_reltime *now)
|
||||
{
|
||||
sta->backlogged_until = *now;
|
||||
sta->backlogged_until.usec += hapd->iconf->airtime_update_interval *
|
||||
AIRTIME_BACKLOG_EXPIRY_FACTOR;
|
||||
while (sta->backlogged_until.usec >= 1000000) {
|
||||
sta->backlogged_until.sec++;
|
||||
sta->backlogged_until.usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void count_backlogged_sta(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct hostap_sta_driver_data data = {};
|
||||
unsigned int num_backlogged = 0;
|
||||
struct os_reltime now;
|
||||
|
||||
os_get_reltime(&now);
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
|
||||
continue;
|
||||
|
||||
if (data.backlog_bytes > 0)
|
||||
set_new_backlog_time(hapd, sta, &now);
|
||||
if (os_reltime_before(&now, &sta->backlogged_until))
|
||||
num_backlogged++;
|
||||
}
|
||||
hapd->num_backlogged_sta = num_backlogged;
|
||||
}
|
||||
|
||||
|
||||
static int sta_set_airtime_weight(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
unsigned int weight)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (weight != sta->airtime_weight &&
|
||||
(ret = hostapd_sta_set_airtime_weight(hapd, sta->addr, weight)))
|
||||
return ret;
|
||||
|
||||
sta->airtime_weight = weight;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void set_sta_weights(struct hostapd_data *hapd, unsigned int weight)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next)
|
||||
sta_set_airtime_weight(hapd, sta, weight);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int get_airtime_quantum(unsigned int max_wt)
|
||||
{
|
||||
unsigned int quantum = AIRTIME_QUANTUM_TARGET / max_wt;
|
||||
|
||||
if (quantum < AIRTIME_QUANTUM_MIN)
|
||||
quantum = AIRTIME_QUANTUM_MIN;
|
||||
else if (quantum > AIRTIME_QUANTUM_MAX)
|
||||
quantum = AIRTIME_QUANTUM_MAX;
|
||||
|
||||
return quantum;
|
||||
}
|
||||
|
||||
|
||||
static void update_airtime_weights(void *eloop_data, void *user_data)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_data;
|
||||
struct hostapd_data *bss;
|
||||
unsigned int sec, usec;
|
||||
unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
|
||||
wt_sum = 0;
|
||||
unsigned int quantum;
|
||||
Boolean all_div_min = TRUE;
|
||||
Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
|
||||
int wt, num_bss = 0, max_wt = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
bss = iface->bss[i];
|
||||
if (!bss->started || !bss->conf->airtime_weight)
|
||||
continue;
|
||||
|
||||
count_backlogged_sta(bss);
|
||||
if (!bss->num_backlogged_sta)
|
||||
continue;
|
||||
|
||||
if (!num_sta_min || bss->num_backlogged_sta < num_sta_min)
|
||||
num_sta_min = bss->num_backlogged_sta;
|
||||
|
||||
num_sta_prod *= bss->num_backlogged_sta;
|
||||
num_sta_sum += bss->num_backlogged_sta;
|
||||
wt_sum += bss->conf->airtime_weight;
|
||||
num_bss++;
|
||||
}
|
||||
|
||||
if (num_sta_min) {
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
bss = iface->bss[i];
|
||||
if (!bss->started || !bss->conf->airtime_weight)
|
||||
continue;
|
||||
|
||||
/* Check if we can divide all sta numbers by the
|
||||
* smallest number to keep weights as small as possible.
|
||||
* This is a lazy way to avoid having to factor
|
||||
* integers. */
|
||||
if (bss->num_backlogged_sta &&
|
||||
bss->num_backlogged_sta % num_sta_min > 0)
|
||||
all_div_min = FALSE;
|
||||
|
||||
/* If we're in LIMIT mode, we only apply the weight
|
||||
* scaling when the BSS(es) marked as limited would a
|
||||
* larger share than the relative BSS weights indicates
|
||||
* it should. */
|
||||
if (!apply_limit && bss->conf->airtime_limit) {
|
||||
if (bss->num_backlogged_sta * wt_sum >
|
||||
bss->conf->airtime_weight * num_sta_sum)
|
||||
apply_limit = TRUE;
|
||||
}
|
||||
}
|
||||
if (all_div_min)
|
||||
num_sta_prod /= num_sta_min;
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
bss = iface->bss[i];
|
||||
if (!bss->started || !bss->conf->airtime_weight)
|
||||
continue;
|
||||
|
||||
/* We only set the calculated weight if the BSS has active
|
||||
* stations and there are other active interfaces as well -
|
||||
* otherwise we just set a unit weight. This ensures that
|
||||
* the weights are set reasonably when stations transition from
|
||||
* inactive to active. */
|
||||
if (apply_limit && bss->num_backlogged_sta && num_bss > 1)
|
||||
wt = bss->conf->airtime_weight * num_sta_prod /
|
||||
bss->num_backlogged_sta;
|
||||
else
|
||||
wt = 1;
|
||||
|
||||
bss->airtime_weight = wt;
|
||||
if (wt > max_wt)
|
||||
max_wt = wt;
|
||||
}
|
||||
|
||||
quantum = get_airtime_quantum(max_wt);
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
bss = iface->bss[i];
|
||||
if (!bss->started || !bss->conf->airtime_weight)
|
||||
continue;
|
||||
set_sta_weights(bss, bss->airtime_weight * quantum);
|
||||
}
|
||||
|
||||
if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
|
||||
return;
|
||||
|
||||
eloop_register_timeout(sec, usec, update_airtime_weights, iface,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||
{
|
||||
struct airtime_sta_weight *wt;
|
||||
|
||||
wt = hapd->conf->airtime_weight_list;
|
||||
while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
|
||||
wt = wt->next;
|
||||
|
||||
return wt ? wt->weight : hapd->conf->airtime_weight;
|
||||
}
|
||||
|
||||
|
||||
int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
unsigned int weight;
|
||||
|
||||
if (hapd->iconf->airtime_mode == AIRTIME_MODE_STATIC) {
|
||||
weight = get_weight_for_sta(hapd, sta->addr);
|
||||
if (weight)
|
||||
return sta_set_airtime_weight(hapd, sta, weight);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int airtime_policy_update_init(struct hostapd_iface *iface)
|
||||
{
|
||||
unsigned int sec, usec;
|
||||
|
||||
if (iface->conf->airtime_mode < AIRTIME_MODE_DYNAMIC)
|
||||
return 0;
|
||||
|
||||
if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
|
||||
return -1;
|
||||
|
||||
eloop_register_timeout(sec, usec, update_airtime_weights, iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void airtime_policy_update_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
eloop_cancel_timeout(update_airtime_weights, iface, NULL);
|
||||
}
|
48
contrib/wpa/src/ap/airtime_policy.h
Normal file
48
contrib/wpa/src/ap/airtime_policy.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Airtime policy configuration
|
||||
* Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef AIRTIME_POLICY_H
|
||||
#define AIRTIME_POLICY_H
|
||||
|
||||
struct hostapd_iface;
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
|
||||
#define AIRTIME_DEFAULT_UPDATE_INTERVAL 200 /* ms */
|
||||
#define AIRTIME_BACKLOG_EXPIRY_FACTOR 2500 /* 2.5 intervals + convert to usec */
|
||||
|
||||
/* scale quantum so this becomes the effective quantum after applying the max
|
||||
* weight, but never go below min or above max */
|
||||
#define AIRTIME_QUANTUM_MIN 8 /* usec */
|
||||
#define AIRTIME_QUANTUM_MAX 256 /* usec */
|
||||
#define AIRTIME_QUANTUM_TARGET 1024 /* usec */
|
||||
|
||||
int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int airtime_policy_update_init(struct hostapd_iface *iface);
|
||||
void airtime_policy_update_deinit(struct hostapd_iface *iface);
|
||||
|
||||
#else /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
static inline int airtime_policy_new_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int airtime_policy_update_init(struct hostapd_iface *iface)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void airtime_policy_update_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
#endif /* AIRTIME_POLICY_H */
|
@ -13,12 +13,14 @@
|
||||
#include "crypto/tls.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_1x_defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "common/dhcp.h"
|
||||
#include "eap_common/eap_wsc_common.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "sta_info.h"
|
||||
#include "airtime_policy.h"
|
||||
#include "ap_config.h"
|
||||
|
||||
|
||||
@ -76,6 +78,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
|
||||
bss->radius_server_auth_port = 1812;
|
||||
bss->eap_sim_db_timeout = 1;
|
||||
bss->eap_sim_id = 3;
|
||||
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
|
||||
bss->eapol_version = EAPOL_VERSION;
|
||||
|
||||
@ -138,6 +141,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
bss->hs20_release = (HS20_VERSION >> 4) + 1;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
bss->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
|
||||
bss->macsec_port = 1;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
/* Default to strict CRL checking. */
|
||||
bss->check_crl_strict = 1;
|
||||
}
|
||||
@ -236,6 +244,13 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->acs_num_scans = 5;
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
conf->he_op.he_rts_threshold = HE_OPERATION_RTS_THRESHOLD_MASK >>
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET;
|
||||
/* Set default basic MCS/NSS set to single stream MCS 0-7 */
|
||||
conf->he_op.he_basic_mcs_nss_set = 0xfffc;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* The third octet of the country string uses an ASCII space character
|
||||
* by default to indicate that the regulations encompass all
|
||||
* environments for the current frequency band in the country. */
|
||||
@ -244,6 +259,10 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->rssi_reject_assoc_rssi = 0;
|
||||
conf->rssi_reject_assoc_timeout = 30;
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -458,7 +477,76 @@ hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
|
||||
struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
|
||||
{
|
||||
const char *pos;
|
||||
char syntax;
|
||||
struct hostapd_radius_attr *attr;
|
||||
size_t len;
|
||||
|
||||
attr = os_zalloc(sizeof(*attr));
|
||||
if (!attr)
|
||||
return NULL;
|
||||
|
||||
attr->type = atoi(value);
|
||||
|
||||
pos = os_strchr(value, ':');
|
||||
if (!pos) {
|
||||
attr->val = wpabuf_alloc(1);
|
||||
if (!attr->val) {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put_u8(attr->val, 0);
|
||||
return attr;
|
||||
}
|
||||
|
||||
pos++;
|
||||
if (pos[0] == '\0' || pos[1] != ':') {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
syntax = *pos++;
|
||||
pos++;
|
||||
|
||||
switch (syntax) {
|
||||
case 's':
|
||||
attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
|
||||
break;
|
||||
case 'x':
|
||||
len = os_strlen(pos);
|
||||
if (len & 1)
|
||||
break;
|
||||
len /= 2;
|
||||
attr->val = wpabuf_alloc(len);
|
||||
if (!attr->val)
|
||||
break;
|
||||
if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
|
||||
wpabuf_free(attr->val);
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
attr->val = wpabuf_alloc(4);
|
||||
if (attr->val)
|
||||
wpabuf_put_be32(attr->val, atoi(pos));
|
||||
break;
|
||||
default:
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!attr->val) {
|
||||
os_free(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
|
||||
{
|
||||
struct hostapd_radius_attr *prev;
|
||||
|
||||
@ -559,8 +647,26 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
static void hostapd_dpp_controller_conf_free(struct dpp_controller_conf *conf)
|
||||
{
|
||||
struct dpp_controller_conf *prev;
|
||||
|
||||
while (conf) {
|
||||
prev = conf;
|
||||
conf = conf->next;
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
{
|
||||
#if defined(CONFIG_WPS) || defined(CONFIG_HS20)
|
||||
size_t i;
|
||||
#endif
|
||||
|
||||
if (conf == NULL)
|
||||
return;
|
||||
|
||||
@ -589,12 +695,16 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
}
|
||||
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
|
||||
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
|
||||
os_free(conf->radius_req_attr_sqlite);
|
||||
os_free(conf->rsn_preauth_interfaces);
|
||||
os_free(conf->ctrl_interface);
|
||||
os_free(conf->ca_cert);
|
||||
os_free(conf->server_cert);
|
||||
os_free(conf->server_cert2);
|
||||
os_free(conf->private_key);
|
||||
os_free(conf->private_key2);
|
||||
os_free(conf->private_key_passwd);
|
||||
os_free(conf->private_key_passwd2);
|
||||
os_free(conf->check_cert_subject);
|
||||
os_free(conf->ocsp_stapling_response);
|
||||
os_free(conf->ocsp_stapling_response_multi);
|
||||
@ -653,12 +763,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->model_description);
|
||||
os_free(conf->model_url);
|
||||
os_free(conf->upc);
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
|
||||
wpabuf_free(conf->wps_vendor_ext[i]);
|
||||
}
|
||||
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
|
||||
wpabuf_free(conf->wps_vendor_ext[i]);
|
||||
wpabuf_free(conf->wps_nfc_dh_pubkey);
|
||||
wpabuf_free(conf->wps_nfc_dh_privkey);
|
||||
wpabuf_free(conf->wps_nfc_dev_pw);
|
||||
@ -684,7 +790,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->hs20_operating_class);
|
||||
os_free(conf->hs20_icons);
|
||||
if (conf->hs20_osu_providers) {
|
||||
size_t i;
|
||||
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
|
||||
struct hs20_osu_provider *p;
|
||||
size_t j;
|
||||
@ -702,8 +807,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->hs20_osu_providers);
|
||||
}
|
||||
if (conf->hs20_operator_icon) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < conf->hs20_operator_icon_count; i++)
|
||||
os_free(conf->hs20_operator_icon[i]);
|
||||
os_free(conf->hs20_operator_icon);
|
||||
@ -740,10 +843,27 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->dpp_connector);
|
||||
wpabuf_free(conf->dpp_netaccesskey);
|
||||
wpabuf_free(conf->dpp_csign);
|
||||
#ifdef CONFIG_DPP2
|
||||
hostapd_dpp_controller_conf_free(conf->dpp_controller);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
hostapd_config_free_sae_passwords(conf);
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
{
|
||||
struct airtime_sta_weight *wt, *wt_prev;
|
||||
|
||||
wt = conf->airtime_weight_list;
|
||||
conf->airtime_weight_list = NULL;
|
||||
while (wt) {
|
||||
wt_prev = wt;
|
||||
wt = wt->next;
|
||||
os_free(wt_prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
|
||||
@ -1140,6 +1260,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
if (full_config && conf->airtime_mode > AIRTIME_MODE_STATIC &&
|
||||
!conf->airtime_update_interval) {
|
||||
wpa_printf(MSG_ERROR, "Airtime update interval cannot be zero");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
if (hostapd_config_check_cw(conf, i))
|
||||
return -1;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst.h"
|
||||
#include "vlan.h"
|
||||
@ -252,6 +253,18 @@ struct sae_password_entry {
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
struct dpp_controller_conf {
|
||||
struct dpp_controller_conf *next;
|
||||
u8 pkhash[SHA256_MAC_LEN];
|
||||
struct hostapd_ip_addr ipaddr;
|
||||
};
|
||||
|
||||
struct airtime_sta_weight {
|
||||
struct airtime_sta_weight *next;
|
||||
unsigned int weight;
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_bss_config - Per-BSS configuration
|
||||
*/
|
||||
@ -288,6 +301,7 @@ struct hostapd_bss_config {
|
||||
int radius_request_cui;
|
||||
struct hostapd_radius_attr *radius_auth_req_attr;
|
||||
struct hostapd_radius_attr *radius_acct_req_attr;
|
||||
char *radius_req_attr_sqlite;
|
||||
int radius_das_port;
|
||||
unsigned int radius_das_time_window;
|
||||
int radius_das_require_event_timestamp;
|
||||
@ -390,8 +404,11 @@ struct hostapd_bss_config {
|
||||
|
||||
char *ca_cert;
|
||||
char *server_cert;
|
||||
char *server_cert2;
|
||||
char *private_key;
|
||||
char *private_key2;
|
||||
char *private_key_passwd;
|
||||
char *private_key_passwd2;
|
||||
char *check_cert_subject;
|
||||
int check_crl;
|
||||
int check_crl_strict;
|
||||
@ -410,7 +427,10 @@ struct hostapd_bss_config {
|
||||
int eap_fast_prov;
|
||||
int pac_key_lifetime;
|
||||
int pac_key_refresh_time;
|
||||
int eap_teap_auth;
|
||||
int eap_teap_pac_no_inner;
|
||||
int eap_sim_aka_result_ind;
|
||||
int eap_sim_id;
|
||||
int tnc;
|
||||
int fragment_size;
|
||||
u16 pwd_group;
|
||||
@ -570,6 +590,7 @@ struct hostapd_bss_config {
|
||||
int osen;
|
||||
int proxy_arp;
|
||||
int na_mcast_to_ucast;
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
int hs20;
|
||||
int hs20_release;
|
||||
@ -692,6 +713,9 @@ struct hostapd_bss_config {
|
||||
struct wpabuf *dpp_netaccesskey;
|
||||
unsigned int dpp_netaccesskey_expiry;
|
||||
struct wpabuf *dpp_csign;
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dpp_controller_conf *dpp_controller;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
@ -709,6 +733,100 @@ struct hostapd_bss_config {
|
||||
#define BACKHAUL_BSS 1
|
||||
#define FRONTHAUL_BSS 2
|
||||
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
unsigned int airtime_weight;
|
||||
int airtime_limit;
|
||||
struct airtime_sta_weight *airtime_weight_list;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
/**
|
||||
* macsec_policy - Determines the policy for MACsec secure session
|
||||
*
|
||||
* 0: MACsec not in use (default)
|
||||
* 1: MACsec enabled - Should secure, accept key server's advice to
|
||||
* determine whether to use a secure session or not.
|
||||
*/
|
||||
int macsec_policy;
|
||||
|
||||
/**
|
||||
* macsec_integ_only - Determines how MACsec are transmitted
|
||||
*
|
||||
* This setting applies only when MACsec is in use, i.e.,
|
||||
* - macsec_policy is enabled
|
||||
* - the key server has decided to enable MACsec
|
||||
*
|
||||
* 0: Encrypt traffic (default)
|
||||
* 1: Integrity only
|
||||
*/
|
||||
int macsec_integ_only;
|
||||
|
||||
/**
|
||||
* macsec_replay_protect - Enable MACsec replay protection
|
||||
*
|
||||
* This setting applies only when MACsec is in use, i.e.,
|
||||
* - macsec_policy is enabled
|
||||
* - the key server has decided to enable MACsec
|
||||
*
|
||||
* 0: Replay protection disabled (default)
|
||||
* 1: Replay protection enabled
|
||||
*/
|
||||
int macsec_replay_protect;
|
||||
|
||||
/**
|
||||
* macsec_replay_window - MACsec replay protection window
|
||||
*
|
||||
* A window in which replay is tolerated, to allow receipt of frames
|
||||
* that have been misordered by the network.
|
||||
*
|
||||
* This setting applies only when MACsec replay protection active, i.e.,
|
||||
* - macsec_replay_protect is enabled
|
||||
* - the key server has decided to enable MACsec
|
||||
*
|
||||
* 0: No replay window, strict check (default)
|
||||
* 1..2^32-1: number of packets that could be misordered
|
||||
*/
|
||||
u32 macsec_replay_window;
|
||||
|
||||
/**
|
||||
* macsec_port - MACsec port (in SCI)
|
||||
*
|
||||
* Port component of the SCI.
|
||||
*
|
||||
* Range: 1-65534 (default: 1)
|
||||
*/
|
||||
int macsec_port;
|
||||
|
||||
/**
|
||||
* mka_priority - Priority of MKA Actor
|
||||
*
|
||||
* Range: 0-255 (default: 255)
|
||||
*/
|
||||
int mka_priority;
|
||||
|
||||
/**
|
||||
* mka_ckn - MKA pre-shared CKN
|
||||
*/
|
||||
#define MACSEC_CKN_MAX_LEN 32
|
||||
size_t mka_ckn_len;
|
||||
u8 mka_ckn[MACSEC_CKN_MAX_LEN];
|
||||
|
||||
/**
|
||||
* mka_cak - MKA pre-shared CAK
|
||||
*/
|
||||
#define MACSEC_CAK_MAX_LEN 32
|
||||
size_t mka_cak_len;
|
||||
u8 mka_cak[MACSEC_CAK_MAX_LEN];
|
||||
|
||||
#define MKA_PSK_SET_CKN BIT(0)
|
||||
#define MKA_PSK_SET_CAK BIT(1)
|
||||
#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
|
||||
/**
|
||||
* mka_psk_set - Whether mka_ckn and mka_cak are set
|
||||
*/
|
||||
u8 mka_psk_set;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -727,7 +845,20 @@ struct he_operation {
|
||||
u8 he_bss_color;
|
||||
u8 he_default_pe_duration;
|
||||
u8 he_twt_required;
|
||||
u8 he_rts_threshold;
|
||||
u16 he_rts_threshold;
|
||||
u16 he_basic_mcs_nss_set;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct spatial_reuse - Spatial reuse
|
||||
*/
|
||||
struct spatial_reuse {
|
||||
u8 sr_control;
|
||||
u8 non_srg_obss_pd_max_offset;
|
||||
u8 srg_obss_pd_min_offset;
|
||||
u8 srg_obss_pd_max_offset;
|
||||
u8 srg_obss_color_bitmap;
|
||||
u8 srg_obss_color_partial_bitmap;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -852,6 +983,10 @@ struct hostapd_config {
|
||||
struct he_phy_capabilities_info he_phy_capab;
|
||||
struct he_operation he_op;
|
||||
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
|
||||
struct spatial_reuse spr;
|
||||
u8 he_oper_chwidth;
|
||||
u8 he_oper_centr_freq_seg0_idx;
|
||||
u8 he_oper_centr_freq_seg1_idx;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* VHT enable/disable config from CHAN_SWITCH */
|
||||
@ -861,12 +996,87 @@ struct hostapd_config {
|
||||
|
||||
int rssi_reject_assoc_rssi;
|
||||
int rssi_reject_assoc_timeout;
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
enum {
|
||||
AIRTIME_MODE_OFF = 0,
|
||||
AIRTIME_MODE_STATIC = 1,
|
||||
AIRTIME_MODE_DYNAMIC = 2,
|
||||
AIRTIME_MODE_LIMIT = 3,
|
||||
__AIRTIME_MODE_MAX,
|
||||
} airtime_mode;
|
||||
unsigned int airtime_update_interval;
|
||||
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
};
|
||||
|
||||
|
||||
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
return conf->he_oper_chwidth;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
return conf->vht_oper_chwidth;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
conf->he_oper_chwidth = oper_chwidth;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
conf->vht_oper_chwidth = oper_chwidth;
|
||||
}
|
||||
|
||||
static inline u8
|
||||
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
return conf->he_oper_centr_freq_seg0_idx;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
return conf->vht_oper_centr_freq_seg0_idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
|
||||
u8 oper_centr_freq_seg0_idx)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
conf->vht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
|
||||
}
|
||||
|
||||
static inline u8
|
||||
hostapd_get_oper_centr_freq_seg1_idx(struct hostapd_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
return conf->he_oper_centr_freq_seg1_idx;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
return conf->vht_oper_centr_freq_seg1_idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
|
||||
u8 oper_centr_freq_seg1_idx)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (conf->ieee80211ax)
|
||||
conf->he_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b);
|
||||
struct hostapd_config * hostapd_config_defaults(void);
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
|
||||
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
|
||||
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
|
||||
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
|
||||
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
|
||||
@ -885,6 +1095,7 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
|
||||
int vlan_id);
|
||||
struct hostapd_radius_attr *
|
||||
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
|
||||
struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value);
|
||||
int hostapd_config_check(struct hostapd_config *conf, int full_config);
|
||||
void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
int full_config);
|
||||
|
@ -413,6 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set)
|
||||
{
|
||||
@ -432,6 +434,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
params.listen_interval = listen_interval;
|
||||
params.ht_capabilities = ht_capab;
|
||||
params.vht_capabilities = vht_capab;
|
||||
params.he_capab = he_capab;
|
||||
params.he_capab_len = he_capab_len;
|
||||
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
|
||||
params.vht_opmode = vht_opmode;
|
||||
params.flags = hostapd_sta_flags_to_drv(flags);
|
||||
@ -537,17 +541,20 @@ int hostapd_flush(struct hostapd_data *hapd)
|
||||
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int ht_enabled, int vht_enabled,
|
||||
int sec_channel_offset, int vht_oper_chwidth,
|
||||
int he_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1)
|
||||
{
|
||||
struct hostapd_freq_params data;
|
||||
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
|
||||
|
||||
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
|
||||
vht_enabled, sec_channel_offset,
|
||||
vht_oper_chwidth,
|
||||
vht_enabled, he_enabled, sec_channel_offset,
|
||||
oper_chwidth,
|
||||
center_segment0, center_segment1,
|
||||
hapd->iface->current_mode ?
|
||||
hapd->iface->current_mode->vht_capab : 0))
|
||||
cmode ? cmode->vht_capab : 0,
|
||||
cmode ?
|
||||
&cmode->he_capab[IEEE80211_MODE_AP] : NULL))
|
||||
return -1;
|
||||
|
||||
if (hapd->driver == NULL)
|
||||
@ -583,6 +590,16 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||
}
|
||||
|
||||
|
||||
int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
|
||||
unsigned int weight)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->sta_set_airtime_weight)
|
||||
return 0;
|
||||
return hapd->driver->sta_set_airtime_weight(hapd->drv_priv, addr,
|
||||
weight);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
@ -775,14 +792,16 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
|
||||
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
enum hostapd_hw_mode mode, int freq,
|
||||
int channel, int ht_enabled, int vht_enabled,
|
||||
int sec_channel_offset, int vht_oper_chwidth,
|
||||
int he_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_freq_params data;
|
||||
int res;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
|
||||
if (!hapd->driver || !hapd->driver->start_dfs_cac)
|
||||
if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
|
||||
return 0;
|
||||
|
||||
if (!iface->conf->ieee80211h) {
|
||||
@ -792,10 +811,11 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
|
||||
vht_enabled, sec_channel_offset,
|
||||
vht_oper_chwidth, center_segment0,
|
||||
vht_enabled, he_enabled, sec_channel_offset,
|
||||
oper_chwidth, center_segment0,
|
||||
center_segment1,
|
||||
iface->current_mode->vht_capab)) {
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[IEEE80211_MODE_AP])) {
|
||||
wpa_printf(MSG_ERROR, "Can't set freq params");
|
||||
return -1;
|
||||
}
|
||||
@ -919,15 +939,17 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
|
||||
params.ch_width = 40;
|
||||
|
||||
/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
|
||||
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
|
||||
*/
|
||||
if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
|
||||
if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
if ((hapd->iface->conf->ieee80211ax ||
|
||||
hapd->iface->conf->ieee80211ac) &&
|
||||
params.ht40_enabled) {
|
||||
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
|
||||
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ)
|
||||
params.ch_width = 80;
|
||||
else if (hapd->iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_160MHZ ||
|
||||
hapd->iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_80P80MHZ)
|
||||
else if (oper_chwidth == CHANWIDTH_160MHZ ||
|
||||
oper_chwidth == CHANWIDTH_80P80MHZ)
|
||||
params.ch_width = 160;
|
||||
}
|
||||
|
||||
@ -936,3 +958,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
|
||||
u16 reason_code, const u8 *ie, size_t ielen)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
|
||||
ie, ielen);
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
@ -61,12 +63,14 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||
int hostapd_flush(struct hostapd_data *hapd);
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int ht_enabled, int vht_enabled,
|
||||
int sec_channel_offset, int vht_oper_chwidth,
|
||||
int he_enabled, int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1);
|
||||
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
|
||||
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
|
||||
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||
int total_flags, int flags_or, int flags_and);
|
||||
int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
|
||||
unsigned int weight);
|
||||
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
|
||||
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time);
|
||||
@ -122,9 +126,12 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
enum hostapd_hw_mode mode, int freq,
|
||||
int channel, int ht_enabled, int vht_enabled,
|
||||
int sec_channel_offset, int vht_oper_chwidth,
|
||||
int he_enabled,
|
||||
int sec_channel_offset, int oper_chwidth,
|
||||
int center_segment0, int center_segment1);
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd);
|
||||
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
|
||||
u16 reason_code, const u8 *ie, size_t ielen);
|
||||
|
||||
|
||||
#include "drivers/driver.h"
|
||||
|
@ -120,7 +120,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
srv.eap_fast_prov = conf->eap_fast_prov;
|
||||
srv.pac_key_lifetime = conf->pac_key_lifetime;
|
||||
srv.pac_key_refresh_time = conf->pac_key_refresh_time;
|
||||
srv.eap_teap_auth = conf->eap_teap_auth;
|
||||
srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
|
||||
srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
|
||||
srv.eap_sim_id = conf->eap_sim_id;
|
||||
srv.tnc = conf->tnc;
|
||||
srv.wps = hapd->wps;
|
||||
srv.ipv6 = conf->radius_server_ipv6;
|
||||
@ -195,7 +198,8 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
if (hapd->conf->eap_server &&
|
||||
(hapd->conf->ca_cert || hapd->conf->server_cert ||
|
||||
hapd->conf->private_key || hapd->conf->dh_file)) {
|
||||
hapd->conf->private_key || hapd->conf->dh_file ||
|
||||
hapd->conf->server_cert2 || hapd->conf->private_key2)) {
|
||||
struct tls_config conf;
|
||||
struct tls_connection_params params;
|
||||
|
||||
@ -224,8 +228,11 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.ca_cert = hapd->conf->ca_cert;
|
||||
params.client_cert = hapd->conf->server_cert;
|
||||
params.client_cert2 = hapd->conf->server_cert2;
|
||||
params.private_key = hapd->conf->private_key;
|
||||
params.private_key2 = hapd->conf->private_key2;
|
||||
params.private_key_passwd = hapd->conf->private_key_passwd;
|
||||
params.private_key_passwd2 = hapd->conf->private_key_passwd2;
|
||||
params.dh_file = hapd->conf->dh_file;
|
||||
params.openssl_ciphers = hapd->conf->openssl_ciphers;
|
||||
params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
|
||||
|
@ -347,7 +347,7 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
hostapd_get_oper_chwidth(hapd->iconf),
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return eid;
|
||||
@ -398,7 +398,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
|
||||
3 + sizeof(struct ieee80211_spatial_reuse);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -509,9 +510,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
pos = hostapd_eid_he_capab(hapd, pos);
|
||||
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
|
||||
pos = hostapd_eid_he_operation(hapd, pos);
|
||||
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
|
||||
pos = hostapd_eid_spatial_reuse(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -593,7 +595,7 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
|
||||
|
||||
pos = ssid_list;
|
||||
end = ssid_list + ssid_list_len;
|
||||
while (end - pos >= 1) {
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
if (pos[1] == 0)
|
||||
@ -1088,7 +1090,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
|
||||
3 + sizeof(struct ieee80211_spatial_reuse);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -1223,9 +1226,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos,
|
||||
IEEE80211_MODE_AP);
|
||||
tailpos = hostapd_eid_he_operation(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
|
||||
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -1394,6 +1399,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||
struct hostapd_freq_params freq;
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct hostapd_config *iconf = iface->conf;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
struct wpabuf *beacon, *proberesp, *assocresp;
|
||||
int res, ret = -1;
|
||||
|
||||
@ -1417,15 +1423,16 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||
params.reenable = hapd->reenable_beacon;
|
||||
hapd->reenable_beacon = 0;
|
||||
|
||||
if (iface->current_mode &&
|
||||
if (cmode &&
|
||||
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
|
||||
iconf->channel, iconf->ieee80211n,
|
||||
iconf->ieee80211ac,
|
||||
iconf->ieee80211ac, iconf->ieee80211ax,
|
||||
iconf->secondary_channel,
|
||||
iconf->vht_oper_chwidth,
|
||||
iconf->vht_oper_centr_freq_seg0_idx,
|
||||
iconf->vht_oper_centr_freq_seg1_idx,
|
||||
iface->current_mode->vht_capab) == 0)
|
||||
hostapd_get_oper_chwidth(iconf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iconf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iconf),
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[IEEE80211_MODE_AP]) == 0)
|
||||
params.freq = &freq;
|
||||
|
||||
res = hostapd_drv_set_ap(hapd, ¶ms);
|
||||
|
@ -712,6 +712,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
"secondary_channel=%d\n"
|
||||
"ieee80211n=%d\n"
|
||||
"ieee80211ac=%d\n"
|
||||
"ieee80211ax=%d\n"
|
||||
"beacon_int=%u\n"
|
||||
"dtim_period=%d\n",
|
||||
iface->conf->channel,
|
||||
@ -720,6 +721,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n,
|
||||
iface->conf->ieee80211ac &&
|
||||
!hapd->conf->disable_11ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->beacon_int,
|
||||
hapd->conf->dtim_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
|
@ -28,17 +28,17 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
|
||||
if (iface->conf->ieee80211n && iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac) {
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
n_chans = 4;
|
||||
*seg1 = 4;
|
||||
break;
|
||||
@ -188,8 +188,8 @@ static int is_in_chanlist(struct hostapd_iface *iface,
|
||||
* The function assumes HT40+ operation.
|
||||
* Make sure to adjust the following variables after calling this:
|
||||
* - hapd->secondary_channel
|
||||
* - hapd->vht_oper_centr_freq_seg0_idx
|
||||
* - hapd->vht_oper_centr_freq_seg1_idx
|
||||
* - hapd->vht/he_oper_centr_freq_seg0_idx
|
||||
* - hapd->vht/he_oper_centr_freq_seg1_idx
|
||||
*/
|
||||
static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data **ret_chan,
|
||||
@ -232,44 +232,44 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan,
|
||||
int secondary_channel,
|
||||
u8 *vht_oper_centr_freq_seg0_idx,
|
||||
u8 *vht_oper_centr_freq_seg1_idx)
|
||||
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan,
|
||||
int secondary_channel,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx)
|
||||
{
|
||||
if (!iface->conf->ieee80211ac)
|
||||
if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
|
||||
return;
|
||||
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
*vht_oper_centr_freq_seg1_idx = 0;
|
||||
*oper_centr_freq_seg1_idx = 0;
|
||||
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (secondary_channel == 1)
|
||||
*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 2;
|
||||
else if (secondary_channel == -1)
|
||||
*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
|
||||
*oper_centr_freq_seg0_idx = chan->chan - 2;
|
||||
else
|
||||
*vht_oper_centr_freq_seg0_idx = chan->chan;
|
||||
*oper_centr_freq_seg0_idx = chan->chan;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
|
||||
case CHANWIDTH_80MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 6;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
|
||||
case CHANWIDTH_160MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 14;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
|
||||
*vht_oper_centr_freq_seg0_idx = 0;
|
||||
*oper_centr_freq_seg0_idx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
|
||||
*vht_oper_centr_freq_seg0_idx,
|
||||
*vht_oper_centr_freq_seg1_idx);
|
||||
*oper_centr_freq_seg0_idx,
|
||||
*oper_centr_freq_seg1_idx);
|
||||
}
|
||||
|
||||
|
||||
@ -288,24 +288,24 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
|
||||
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
|
||||
channel_no -= 4;
|
||||
|
||||
/* VHT */
|
||||
if (iface->conf->ieee80211ac) {
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
/* VHT/HE */
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
channel_no =
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx - 6;
|
||||
case CHANWIDTH_80MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 6;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
channel_no =
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx - 14;
|
||||
case CHANWIDTH_160MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 14;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
channel_no =
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx - 6;
|
||||
chan_seg1 =
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx - 6;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
iface->conf) - 6;
|
||||
chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
|
||||
iface->conf) - 6;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO,
|
||||
@ -348,7 +348,7 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
|
||||
mode->num_channels, channel_no, iface->conf->channel,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->secondary_channel,
|
||||
iface->conf->vht_oper_chwidth);
|
||||
hostapd_get_oper_chwidth(iface->conf));
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
wpa_printf(MSG_DEBUG, "Available channel: %d",
|
||||
@ -435,8 +435,8 @@ static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
|
||||
static struct hostapd_channel_data *
|
||||
dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
int *secondary_channel,
|
||||
u8 *vht_oper_centr_freq_seg0_idx,
|
||||
u8 *vht_oper_centr_freq_seg1_idx,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx,
|
||||
int skip_radar)
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
@ -447,8 +447,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
|
||||
*secondary_channel = 0;
|
||||
*vht_oper_centr_freq_seg0_idx = 0;
|
||||
*vht_oper_centr_freq_seg1_idx = 0;
|
||||
*oper_centr_freq_seg0_idx = 0;
|
||||
*oper_centr_freq_seg1_idx = 0;
|
||||
|
||||
if (iface->current_mode == NULL)
|
||||
return NULL;
|
||||
@ -473,10 +473,10 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
else
|
||||
*secondary_channel = 0;
|
||||
|
||||
dfs_adjust_vht_center_freq(iface, chan,
|
||||
*secondary_channel,
|
||||
vht_oper_centr_freq_seg0_idx,
|
||||
vht_oper_centr_freq_seg1_idx);
|
||||
dfs_adjust_center_freq(iface, chan,
|
||||
*secondary_channel,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
return chan;
|
||||
}
|
||||
@ -724,8 +724,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = sec;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
|
||||
}
|
||||
} while (res);
|
||||
|
||||
@ -736,20 +736,19 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
|
||||
iface->freq,
|
||||
iface->conf->channel, iface->conf->secondary_channel,
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx,
|
||||
hostapd_get_oper_chwidth(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
|
||||
iface->dfs_cac_ms / 1000);
|
||||
|
||||
res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
|
||||
iface->freq,
|
||||
iface->conf->channel,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->secondary_channel,
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx);
|
||||
res = hostapd_start_dfs_cac(
|
||||
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
|
||||
iface->conf->ieee80211n, iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->secondary_channel,
|
||||
hostapd_get_oper_chwidth(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
|
||||
|
||||
if (res) {
|
||||
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
|
||||
@ -842,16 +841,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
int secondary_channel;
|
||||
u8 vht_oper_centr_freq_seg0_idx = 0;
|
||||
u8 vht_oper_centr_freq_seg1_idx = 0;
|
||||
u8 oper_centr_freq_seg0_idx = 0;
|
||||
u8 oper_centr_freq_seg1_idx = 0;
|
||||
int skip_radar = 0;
|
||||
int err = 1;
|
||||
|
||||
/* Radar detected during active CAC */
|
||||
iface->cac_started = 0;
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&vht_oper_centr_freq_seg0_idx,
|
||||
&vht_oper_centr_freq_seg1_idx,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
|
||||
if (!channel) {
|
||||
@ -868,10 +867,10 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx =
|
||||
vht_oper_centr_freq_seg0_idx;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx =
|
||||
vht_oper_centr_freq_seg1_idx;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
err = 0;
|
||||
|
||||
hostapd_setup_interface_complete(iface, err);
|
||||
@ -883,12 +882,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
int secondary_channel;
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
u8 oper_centr_freq_seg0_idx;
|
||||
u8 oper_centr_freq_seg1_idx;
|
||||
int skip_radar = 1;
|
||||
struct csa_settings csa_settings;
|
||||
unsigned int i;
|
||||
int err = 1;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
|
||||
__func__, iface->cac_started ? "yes" : "no",
|
||||
@ -911,8 +911,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
|
||||
/* Perform channel switch/CSA */
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&vht_oper_centr_freq_seg0_idx,
|
||||
&vht_oper_centr_freq_seg1_idx,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
|
||||
if (!channel) {
|
||||
@ -923,8 +923,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
*/
|
||||
skip_radar = 0;
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&vht_oper_centr_freq_seg0_idx,
|
||||
&vht_oper_centr_freq_seg1_idx,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_INFO,
|
||||
@ -936,10 +936,10 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx =
|
||||
vht_oper_centr_freq_seg0_idx;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx =
|
||||
vht_oper_centr_freq_seg1_idx;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
@ -962,11 +962,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
channel->chan,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
secondary_channel,
|
||||
iface->conf->vht_oper_chwidth,
|
||||
vht_oper_centr_freq_seg0_idx,
|
||||
vht_oper_centr_freq_seg1_idx,
|
||||
iface->current_mode->vht_capab);
|
||||
hostapd_get_oper_chwidth(iface->conf),
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[IEEE80211_MODE_AP]);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
||||
@ -986,10 +988,10 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx =
|
||||
vht_oper_centr_freq_seg0_idx;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx =
|
||||
vht_oper_centr_freq_seg1_idx;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "gas_query_ap.h"
|
||||
#include "gas_serv.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "dpp_hostapd.h"
|
||||
|
||||
@ -557,6 +558,14 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
* received hash values */
|
||||
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
|
||||
r_bootstrap, &own_bi, &peer_bi);
|
||||
#ifdef CONFIG_DPP2
|
||||
if (!own_bi) {
|
||||
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
|
||||
src, hdr, buf, len, freq, i_bootstrap,
|
||||
r_bootstrap) == 0)
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
if (!own_bi) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||
"No matching own bootstrapping key found - ignore message");
|
||||
@ -1357,6 +1366,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
|
||||
" freq=%u type=%d", MAC2STR(src), freq, type);
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
|
||||
src, hdr, buf, len, freq, NULL, NULL) == 0)
|
||||
return;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
switch (type) {
|
||||
case DPP_PA_AUTHENTICATION_REQ:
|
||||
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
|
||||
@ -1410,7 +1425,8 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
|
||||
struct wpabuf *
|
||||
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 *query, size_t query_len)
|
||||
const u8 *query, size_t query_len,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
struct wpabuf *resp;
|
||||
@ -1418,6 +1434,13 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
|
||||
if (!auth || !auth->auth_success ||
|
||||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
||||
#ifdef CONFIG_DPP2
|
||||
if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
|
||||
data_len) == 0) {
|
||||
/* Response will be forwarded once received over TCP */
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
|
||||
return NULL;
|
||||
}
|
||||
@ -1609,11 +1632,67 @@ void hostapd_dpp_stop(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
|
||||
static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
|
||||
const u8 *msg, size_t len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
u8 *buf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
|
||||
MAC2STR(addr), freq);
|
||||
buf = os_malloc(2 + len);
|
||||
if (!buf)
|
||||
return;
|
||||
buf[0] = WLAN_ACTION_PUBLIC;
|
||||
buf[1] = WLAN_PA_VENDOR_SPECIFIC;
|
||||
os_memcpy(buf + 2, msg, len);
|
||||
hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
|
||||
u8 dialog_token, int prot,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
static int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dpp_controller_conf *ctrl;
|
||||
struct dpp_relay_config config;
|
||||
|
||||
os_memset(&config, 0, sizeof(config));
|
||||
config.cb_ctx = hapd;
|
||||
config.tx = hostapd_dpp_relay_tx;
|
||||
config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
|
||||
for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
|
||||
config.ipaddr = &ctrl->ipaddr;
|
||||
config.pkhash = ctrl->pkhash;
|
||||
if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
|
||||
&config) < 0)
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_init(struct hostapd_data *hapd)
|
||||
{
|
||||
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
|
||||
hapd->dpp_init_done = 1;
|
||||
return 0;
|
||||
return hostapd_dpp_add_controllers(hapd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,7 +19,8 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok);
|
||||
struct wpabuf *
|
||||
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 *query, size_t query_len);
|
||||
const u8 *query, size_t query_len,
|
||||
const u8 *data, size_t data_len);
|
||||
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
|
||||
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
|
||||
|
@ -772,7 +772,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
|
||||
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2)
|
||||
int offset, int width, int cf1, int cf2,
|
||||
int finished)
|
||||
{
|
||||
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
|
||||
|
||||
@ -783,10 +784,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
|
||||
"driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
|
||||
finished ? "had" : "starting",
|
||||
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
|
||||
width, channel_width_to_string(width), cf1, cf2);
|
||||
|
||||
if (!hapd->iface->current_mode) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"ignore channel switch since the interface is not yet ready");
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->iface->freq = freq;
|
||||
|
||||
channel = hostapd_hw_get_channel(hapd, freq);
|
||||
@ -799,19 +808,19 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
switch (width) {
|
||||
case CHAN_WIDTH_80:
|
||||
chwidth = VHT_CHANWIDTH_80MHZ;
|
||||
chwidth = CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_80P80:
|
||||
chwidth = VHT_CHANWIDTH_80P80MHZ;
|
||||
chwidth = CHANWIDTH_80P80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
chwidth = VHT_CHANWIDTH_160MHZ;
|
||||
chwidth = CHANWIDTH_160MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
case CHAN_WIDTH_20:
|
||||
case CHAN_WIDTH_40:
|
||||
default:
|
||||
chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
chwidth = CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -844,13 +853,22 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
hapd->iconf->ch_switch_vht_config = 0;
|
||||
|
||||
hapd->iconf->secondary_channel = offset;
|
||||
hapd->iconf->vht_oper_chwidth = chwidth;
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
|
||||
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
|
||||
|
||||
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
|
||||
hapd->iface->num_hw_features);
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
"%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
|
||||
finished ? WPA_EVENT_CHANNEL_SWITCH :
|
||||
WPA_EVENT_CHANNEL_SWITCH_STARTED,
|
||||
freq, ht, offset, channel_width_to_string(width),
|
||||
cf1, cf2, is_dfs);
|
||||
if (!finished)
|
||||
return;
|
||||
|
||||
if (hapd->csa_in_progress &&
|
||||
freq == hapd->cs_freq_params.freq) {
|
||||
hostapd_cleanup_cs_params(hapd);
|
||||
@ -942,28 +960,31 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hapd->iface->conf->ieee80211ac) {
|
||||
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
|
||||
/* set defaults for backwards compatibility */
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
|
||||
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
|
||||
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
|
||||
if (acs_res->ch_width == 80) {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf, acs_res->vht_seg0_center_ch);
|
||||
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
|
||||
} else if (acs_res->ch_width == 160) {
|
||||
if (acs_res->vht_seg1_center_ch == 0) {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth =
|
||||
VHT_CHANWIDTH_160MHZ;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf,
|
||||
acs_res->vht_seg0_center_ch);
|
||||
hostapd_set_oper_chwidth(hapd->iconf,
|
||||
CHANWIDTH_160MHZ);
|
||||
} else {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx =
|
||||
acs_res->vht_seg1_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth =
|
||||
VHT_CHANWIDTH_80P80MHZ;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf,
|
||||
acs_res->vht_seg0_center_ch);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(
|
||||
hapd->iconf,
|
||||
acs_res->vht_seg1_center_ch);
|
||||
hostapd_set_oper_chwidth(hapd->iconf,
|
||||
CHANWIDTH_80P80MHZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1568,6 +1589,73 @@ static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
|
||||
const u8 *peer, const u8 *ie,
|
||||
size_t ie_len)
|
||||
{
|
||||
u16 status;
|
||||
struct sta_info *sta;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (!hapd || !hapd->wpa_auth) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
|
||||
return -1;
|
||||
}
|
||||
if (!peer) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
|
||||
return -1;
|
||||
}
|
||||
if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
|
||||
status = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
goto err;
|
||||
}
|
||||
if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
|
||||
MACSTR, MAC2STR(peer));
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
status = owe_validate_request(hapd, peer, elems.rsn_ie,
|
||||
elems.rsn_ie_len,
|
||||
elems.owe_dh, elems.owe_dh_len);
|
||||
if (status != WLAN_STATUS_SUCCESS)
|
||||
goto err;
|
||||
|
||||
sta = ap_get_sta(hapd, peer);
|
||||
if (sta) {
|
||||
ap_sta_no_session_timeout(hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
|
||||
/*
|
||||
* Make sure that the previously registered inactivity timer
|
||||
* will not remove the STA immediately.
|
||||
*/
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
} else {
|
||||
sta = ap_sta_add(hapd, peer);
|
||||
if (!sta) {
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
|
||||
|
||||
status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
|
||||
elems.rsn_ie_len, elems.owe_dh,
|
||||
elems.owe_dh_len);
|
||||
if (status != WLAN_STATUS_SUCCESS)
|
||||
ap_free_sta(hapd, sta);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
@ -1673,6 +1761,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
data->assoc_info.req_ies_len,
|
||||
data->assoc_info.reassoc);
|
||||
break;
|
||||
#ifdef CONFIG_OWE
|
||||
case EVENT_UPDATE_DH:
|
||||
if (!data)
|
||||
return;
|
||||
hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
|
||||
data->update_dh.ie,
|
||||
data->update_dh.ie_len);
|
||||
break;
|
||||
#endif /* CONFIG_OWE */
|
||||
case EVENT_DISASSOC:
|
||||
if (data)
|
||||
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
|
||||
@ -1689,6 +1786,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
case EVENT_AUTH:
|
||||
hostapd_notif_auth(hapd, &data->auth);
|
||||
break;
|
||||
case EVENT_CH_SWITCH_STARTED:
|
||||
case EVENT_CH_SWITCH:
|
||||
if (!data)
|
||||
break;
|
||||
@ -1697,7 +1795,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
data->ch_switch.ch_offset,
|
||||
data->ch_switch.ch_width,
|
||||
data->ch_switch.cf1,
|
||||
data->ch_switch.cf2);
|
||||
data->ch_switch.cf2,
|
||||
event == EVENT_CH_SWITCH);
|
||||
break;
|
||||
case EVENT_CONNECT_FAILED_REASON:
|
||||
if (!data)
|
||||
|
@ -1522,9 +1522,9 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf)
|
||||
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf)
|
||||
{
|
||||
struct wpabuf *tx_buf;
|
||||
|
||||
@ -1681,7 +1681,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
if (dpp) {
|
||||
struct wpabuf *msg;
|
||||
|
||||
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
|
||||
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen,
|
||||
data, len);
|
||||
if (!msg)
|
||||
return;
|
||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
||||
|
@ -88,4 +88,8 @@ void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
|
||||
int gas_serv_init(struct hostapd_data *hapd);
|
||||
void gas_serv_deinit(struct hostapd_data *hapd);
|
||||
|
||||
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
int prot, struct wpabuf *buf);
|
||||
|
||||
#endif /* GAS_SERV_H */
|
||||
|
@ -7,6 +7,9 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#ifdef CONFIG_SQLITE
|
||||
#include <sqlite3.h>
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
@ -50,6 +53,8 @@
|
||||
#include "fils_hlp.h"
|
||||
#include "acs.h"
|
||||
#include "hs20.h"
|
||||
#include "airtime_policy.h"
|
||||
#include "wpa_auth_kay.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
@ -260,11 +265,14 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
|
||||
hapd->iconf->ht_capab = oldconf->ht_capab;
|
||||
hapd->iconf->vht_capab = oldconf->vht_capab;
|
||||
hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
oldconf->vht_oper_centr_freq_seg0_idx;
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx =
|
||||
oldconf->vht_oper_centr_freq_seg1_idx;
|
||||
hostapd_set_oper_chwidth(hapd->iconf,
|
||||
hostapd_get_oper_chwidth(oldconf));
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf,
|
||||
hostapd_get_oper_centr_freq_seg0_idx(oldconf));
|
||||
hostapd_set_oper_centr_freq_seg1_idx(
|
||||
hapd->iconf,
|
||||
hostapd_get_oper_centr_freq_seg1_idx(oldconf));
|
||||
hapd->conf = newconf->bss[j];
|
||||
hostapd_reload_bss(hapd);
|
||||
}
|
||||
@ -369,6 +377,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
hostapd_deinit_wps(hapd);
|
||||
ieee802_1x_dealloc_kay_sm_hapd(hapd);
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit(hapd);
|
||||
gas_query_ap_deinit(hapd->gas);
|
||||
@ -491,6 +500,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
iface->basic_rates = NULL;
|
||||
ap_list_deinit(iface);
|
||||
sta_track_deinit(iface);
|
||||
airtime_policy_update_deinit(iface);
|
||||
}
|
||||
|
||||
|
||||
@ -1018,6 +1028,43 @@ hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
|
||||
#define hostapd_das_coa NULL
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
|
||||
static int db_table_exists(sqlite3 *db, const char *name)
|
||||
{
|
||||
char cmd[128];
|
||||
|
||||
os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
|
||||
return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
static int db_table_create_radius_attributes(sqlite3 *db)
|
||||
{
|
||||
char *err = NULL;
|
||||
const char *sql =
|
||||
"CREATE TABLE radius_attributes("
|
||||
" id INTEGER PRIMARY KEY,"
|
||||
" sta TEXT,"
|
||||
" reqtype TEXT,"
|
||||
" attr TEXT"
|
||||
");"
|
||||
"CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Adding database table for RADIUS attribute information");
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
wpa_printf(MSG_ERROR, "SQLite error: %s", err);
|
||||
sqlite3_free(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
@ -1171,6 +1218,24 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (wpa_debug_level <= MSG_MSGDUMP)
|
||||
conf->radius->msg_dumps = 1;
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (conf->radius_req_attr_sqlite) {
|
||||
if (sqlite3_open(conf->radius_req_attr_sqlite,
|
||||
&hapd->rad_attr_db)) {
|
||||
wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
|
||||
conf->radius_req_attr_sqlite);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
|
||||
conf->radius_req_attr_sqlite);
|
||||
if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
|
||||
db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
hapd->radius = radius_client_init(hapd, conf->radius);
|
||||
if (hapd->radius == NULL) {
|
||||
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
|
||||
@ -1863,10 +1928,13 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
hapd->iconf->channel,
|
||||
hapd->iconf->ieee80211n,
|
||||
hapd->iconf->ieee80211ac,
|
||||
hapd->iconf->ieee80211ax,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx,
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
|
||||
hostapd_get_oper_chwidth(hapd->iconf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(
|
||||
hapd->iconf))) {
|
||||
wpa_printf(MSG_ERROR, "Could not set channel for "
|
||||
"kernel driver");
|
||||
goto fail;
|
||||
@ -1976,6 +2044,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
|
||||
hostapd_owe_update_trans(iface);
|
||||
airtime_policy_update_init(iface);
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
@ -2183,6 +2252,12 @@ static void hostapd_bss_deinit(struct hostapd_data *hapd)
|
||||
hapd->conf ? hapd->conf->iface : "N/A");
|
||||
hostapd_bss_deinit_no_free(hapd);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (hapd->rad_attr_db) {
|
||||
sqlite3_close(hapd->rad_attr_db);
|
||||
hapd->rad_attr_db = NULL;
|
||||
}
|
||||
#endif /* CONFIG_SQLITE */
|
||||
hostapd_cleanup(hapd);
|
||||
}
|
||||
|
||||
@ -2486,8 +2561,12 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
|
||||
wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
|
||||
__func__, (int) j,
|
||||
hapd_iface->bss[j]->drv_priv);
|
||||
if (hapd_iface->bss[j]->drv_priv == drv_priv)
|
||||
if (hapd_iface->bss[j]->drv_priv == drv_priv) {
|
||||
hapd_iface->bss[j]->drv_priv = NULL;
|
||||
hapd_iface->extended_capa = NULL;
|
||||
hapd_iface->extended_capa_mask = NULL;
|
||||
hapd_iface->extended_capa_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2992,6 +3071,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
airtime_policy_new_sta(hapd, sta);
|
||||
|
||||
/* Start accounting here, if IEEE 802.1X and WPA are not used.
|
||||
* IEEE 802.1X/WPA code will start accounting after the station has
|
||||
* been authorized. */
|
||||
@ -3032,6 +3113,14 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
|
||||
hapd->conf->mka_psk_set)
|
||||
ieee802_1x_create_preshared_mka_hapd(hapd, sta);
|
||||
else
|
||||
ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
|
||||
#endif /* CONFIG_MACSEC */
|
||||
}
|
||||
|
||||
|
||||
@ -3191,6 +3280,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
|
||||
struct hostapd_freq_params *old_params)
|
||||
{
|
||||
int channel;
|
||||
u8 seg0, seg1;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
if (!params->channel) {
|
||||
/* check if the new channel is supported by hw */
|
||||
@ -3201,33 +3292,37 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
|
||||
if (!channel)
|
||||
return -1;
|
||||
|
||||
mode = hapd->iface->current_mode;
|
||||
|
||||
/* if a pointer to old_params is provided we save previous state */
|
||||
if (old_params &&
|
||||
hostapd_set_freq_params(old_params, conf->hw_mode,
|
||||
hostapd_hw_get_freq(hapd, conf->channel),
|
||||
conf->channel, conf->ieee80211n,
|
||||
conf->ieee80211ac,
|
||||
conf->ieee80211ac, conf->ieee80211ax,
|
||||
conf->secondary_channel,
|
||||
conf->vht_oper_chwidth,
|
||||
conf->vht_oper_centr_freq_seg0_idx,
|
||||
conf->vht_oper_centr_freq_seg1_idx,
|
||||
conf->vht_capab))
|
||||
hostapd_get_oper_chwidth(conf),
|
||||
hostapd_get_oper_centr_freq_seg0_idx(conf),
|
||||
hostapd_get_oper_centr_freq_seg1_idx(conf),
|
||||
conf->vht_capab,
|
||||
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
|
||||
NULL))
|
||||
return -1;
|
||||
|
||||
switch (params->bandwidth) {
|
||||
case 0:
|
||||
case 20:
|
||||
case 40:
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
|
||||
break;
|
||||
case 80:
|
||||
if (params->center_freq2)
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
|
||||
hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
|
||||
else
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
|
||||
hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
|
||||
break;
|
||||
case 160:
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
|
||||
hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -3237,9 +3332,11 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
|
||||
conf->ieee80211n = params->ht_enabled;
|
||||
conf->secondary_channel = params->sec_channel_offset;
|
||||
ieee80211_freq_to_chan(params->center_freq1,
|
||||
&conf->vht_oper_centr_freq_seg0_idx);
|
||||
&seg0);
|
||||
ieee80211_freq_to_chan(params->center_freq2,
|
||||
&conf->vht_oper_centr_freq_seg1_idx);
|
||||
&seg1);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
|
||||
|
||||
/* TODO: maybe call here hostapd_config_check here? */
|
||||
|
||||
@ -3253,7 +3350,7 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct hostapd_freq_params old_freq;
|
||||
int ret;
|
||||
u8 chan, vht_bandwidth;
|
||||
u8 chan, bandwidth;
|
||||
|
||||
os_memset(&old_freq, 0, sizeof(old_freq));
|
||||
if (!iface || !iface->freq || hapd->csa_in_progress)
|
||||
@ -3262,29 +3359,30 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
|
||||
switch (settings->freq_params.bandwidth) {
|
||||
case 80:
|
||||
if (settings->freq_params.center_freq2)
|
||||
vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
|
||||
bandwidth = CHANWIDTH_80P80MHZ;
|
||||
else
|
||||
vht_bandwidth = VHT_CHANWIDTH_80MHZ;
|
||||
bandwidth = CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case 160:
|
||||
vht_bandwidth = VHT_CHANWIDTH_160MHZ;
|
||||
bandwidth = CHANWIDTH_160MHZ;
|
||||
break;
|
||||
default:
|
||||
vht_bandwidth = VHT_CHANWIDTH_USE_HT;
|
||||
bandwidth = CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(
|
||||
settings->freq_params.freq,
|
||||
settings->freq_params.sec_channel_offset,
|
||||
vht_bandwidth,
|
||||
bandwidth,
|
||||
&hapd->iface->cs_oper_class,
|
||||
&chan) == NUM_HOSTAPD_MODES) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
|
||||
"invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
|
||||
settings->freq_params.freq,
|
||||
settings->freq_params.sec_channel_offset,
|
||||
settings->freq_params.vht_enabled);
|
||||
settings->freq_params.vht_enabled,
|
||||
settings->freq_params.he_enabled);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -3384,29 +3482,29 @@ void
|
||||
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
const struct hostapd_freq_params *freq_params)
|
||||
{
|
||||
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
|
||||
int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
|
||||
|
||||
if (freq_params->center_freq1)
|
||||
vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
|
||||
seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
|
||||
if (freq_params->center_freq2)
|
||||
vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
|
||||
seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
|
||||
|
||||
switch (freq_params->bandwidth) {
|
||||
case 0:
|
||||
case 20:
|
||||
case 40:
|
||||
vht_bw = VHT_CHANWIDTH_USE_HT;
|
||||
bw = CHANWIDTH_USE_HT;
|
||||
break;
|
||||
case 80:
|
||||
if (freq_params->center_freq2)
|
||||
vht_bw = VHT_CHANWIDTH_80P80MHZ;
|
||||
bw = CHANWIDTH_80P80MHZ;
|
||||
else
|
||||
vht_bw = VHT_CHANWIDTH_80MHZ;
|
||||
bw = CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case 160:
|
||||
vht_bw = VHT_CHANWIDTH_160MHZ;
|
||||
bw = CHANWIDTH_160MHZ;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
|
||||
@ -3417,11 +3515,12 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
iface->freq = freq_params->freq;
|
||||
iface->conf->channel = freq_params->channel;
|
||||
iface->conf->secondary_channel = freq_params->sec_channel_offset;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
|
||||
iface->conf->vht_oper_chwidth = vht_bw;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
|
||||
hostapd_set_oper_chwidth(iface->conf, bw);
|
||||
iface->conf->ieee80211n = freq_params->ht_enabled;
|
||||
iface->conf->ieee80211ac = freq_params->vht_enabled;
|
||||
iface->conf->ieee80211ax = freq_params->he_enabled;
|
||||
|
||||
/*
|
||||
* cs_params must not be cleared earlier because the freq_params
|
||||
|
@ -9,6 +9,10 @@
|
||||
#ifndef HOSTAPD_H
|
||||
#define HOSTAPD_H
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
#include <sqlite3.h>
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "utils/list.h"
|
||||
#include "ap_config.h"
|
||||
@ -232,6 +236,10 @@ struct hostapd_data {
|
||||
struct wps_stat wps_stats;
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
struct ieee802_1x_kay *kay;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
struct hostapd_probereq_cb *probereq_cb;
|
||||
size_t num_probereq_cb;
|
||||
|
||||
@ -379,6 +387,17 @@ struct hostapd_data {
|
||||
unsigned int dpp_ignore_netaccesskey_mismatch:1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
unsigned int num_backlogged_sta;
|
||||
unsigned int airtime_weight;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
u8 last_1x_eapol_key_replay_counter[8];
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
sqlite3 *rad_attr_db;
|
||||
#endif /* CONFIG_SQLITE */
|
||||
};
|
||||
|
||||
|
||||
@ -541,6 +560,12 @@ struct hostapd_iface {
|
||||
unsigned int num_sta_seen;
|
||||
|
||||
u8 dfs_domain;
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
unsigned int airtime_quantum;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
|
||||
/* Previous WMM element information */
|
||||
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -607,7 +632,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||
const u8 *bssid, const u8 *ie, size_t ie_len,
|
||||
int ssi_signal);
|
||||
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2);
|
||||
int offset, int width, int cf1, int cf2,
|
||||
int finished);
|
||||
struct survey_results;
|
||||
void hostapd_event_get_survey(struct hostapd_iface *iface,
|
||||
struct survey_results *survey_results);
|
||||
|
@ -329,9 +329,9 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
|
||||
res = ieee80211n_allowed_ht40_channel_pair(iface);
|
||||
if (!res) {
|
||||
iface->conf->secondary_channel = 0;
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx = 0;
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx = 0;
|
||||
iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
|
||||
hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
|
||||
res = 1;
|
||||
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
|
||||
}
|
||||
@ -655,6 +655,14 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
|
||||
@ -675,6 +683,11 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
|
||||
if (!ieee80211n_supported_ht_capab(iface))
|
||||
return -1;
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (iface->conf->ieee80211ax &&
|
||||
!ieee80211ax_supported_he_capab(iface))
|
||||
return -1;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (iface->conf->ieee80211ac &&
|
||||
!ieee80211ac_supported_vht_capab(iface))
|
||||
@ -863,12 +876,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
|
||||
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
|
||||
iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
|
||||
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
|
||||
iface->conf->ieee80211ax) &&
|
||||
iface->conf->channel == 14) {
|
||||
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
|
||||
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
|
||||
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
|
||||
iface->conf->ieee80211n = 0;
|
||||
iface->conf->ieee80211ac = 0;
|
||||
iface->conf->ieee80211ax = 0;
|
||||
}
|
||||
|
||||
iface->current_mode = NULL;
|
||||
@ -936,11 +951,16 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||
int i, channel;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
channel = hw_get_chan(hapd->iface->current_mode, freq);
|
||||
if (channel)
|
||||
return channel;
|
||||
if (hapd->iface->current_mode) {
|
||||
channel = hw_get_chan(hapd->iface->current_mode, freq);
|
||||
if (channel)
|
||||
return channel;
|
||||
}
|
||||
|
||||
/* Check other available modes since the channel list for the current
|
||||
* mode did not include the specified frequency. */
|
||||
if (!hapd->iface->hw_features)
|
||||
return 0;
|
||||
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||
mode = &hapd->iface->hw_features[i];
|
||||
channel = hw_get_chan(mode, freq);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "common/sae.h"
|
||||
#include "common/dpp.h"
|
||||
#include "common/ocv.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
@ -709,7 +710,8 @@ static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.status = status;
|
||||
params.bssid = sta->addr;
|
||||
if (status == WLAN_STATUS_SUCCESS && sta->sae)
|
||||
if (status == WLAN_STATUS_SUCCESS && sta->sae &&
|
||||
!hapd->conf->disable_pmksa_caching)
|
||||
params.pmkid = sta->sae->pmkid;
|
||||
|
||||
hostapd_drv_send_external_auth_status(hapd, ¶ms);
|
||||
@ -1038,8 +1040,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"start SAE authentication (RX commit, status=%u)",
|
||||
status_code);
|
||||
"start SAE authentication (RX commit, status=%u (%s))",
|
||||
status_code, status2str(status_code));
|
||||
|
||||
if ((hapd->conf->mesh & MESH_ENABLED) &&
|
||||
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
|
||||
@ -1182,8 +1184,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
} else if (auth_transaction == 2) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"SAE authentication (RX confirm, status=%u)",
|
||||
status_code);
|
||||
"SAE authentication (RX confirm, status=%u (%s))",
|
||||
status_code, status2str(status_code));
|
||||
if (status_code != WLAN_STATUS_SUCCESS)
|
||||
goto remove_sta;
|
||||
if (sta->sae->state >= SAE_CONFIRMED ||
|
||||
@ -1224,8 +1226,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
} else {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"unexpected SAE authentication transaction %u (status=%u)",
|
||||
auth_transaction, status_code);
|
||||
"unexpected SAE authentication transaction %u (status=%u (%s))",
|
||||
auth_transaction, status_code,
|
||||
status2str(status_code));
|
||||
if (status_code != WLAN_STATUS_SUCCESS)
|
||||
goto remove_sta;
|
||||
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
|
||||
@ -2323,8 +2326,11 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
|
||||
WLAN_STA_AUTHORIZED);
|
||||
|
||||
if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
|
||||
NULL, NULL, sta->flags, 0, 0, 0, 0)) {
|
||||
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
|
||||
sta->supported_rates,
|
||||
sta->supported_rates_len,
|
||||
0, NULL, NULL, NULL, 0,
|
||||
sta->flags, 0, 0, 0, 0)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
@ -2790,6 +2796,123 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd,
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
{
|
||||
struct wpa_ie_data data;
|
||||
int res;
|
||||
|
||||
if (!rsn_ie || rsn_ie_len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
|
||||
MAC2STR(peer));
|
||||
return WLAN_STATUS_INVALID_IE;
|
||||
}
|
||||
rsn_ie -= 2;
|
||||
rsn_ie_len += 2;
|
||||
|
||||
res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
|
||||
if (res) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
|
||||
" (res=%d)", MAC2STR(peer), res);
|
||||
wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
|
||||
return wpa_res_to_status_code(res);
|
||||
}
|
||||
if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Unexpected key mgmt 0x%x from " MACSTR,
|
||||
(unsigned int) data.key_mgmt, MAC2STR(peer));
|
||||
return WLAN_STATUS_AKMP_NOT_VALID;
|
||||
}
|
||||
if (!owe_dh) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: No Diffie-Hellman Parameter element from "
|
||||
MACSTR, MAC2STR(peer));
|
||||
return WLAN_STATUS_AKMP_NOT_VALID;
|
||||
}
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
u16 owe_process_rsn_ie(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
{
|
||||
u16 status;
|
||||
u8 *owe_buf, ie[256 * 2];
|
||||
size_t ie_len = 0;
|
||||
int res;
|
||||
|
||||
if (!rsn_ie || rsn_ie_len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!sta->wpa_sm)
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
|
||||
NULL);
|
||||
if (!sta->wpa_sm) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"OWE: Failed to initialize WPA state machine");
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
rsn_ie -= 2;
|
||||
rsn_ie_len += 2;
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
hapd->iface->freq, rsn_ie, rsn_ie_len,
|
||||
NULL, 0, owe_dh, owe_dh_len);
|
||||
status = wpa_res_to_status_code(res);
|
||||
if (status != WLAN_STATUS_SUCCESS)
|
||||
goto end;
|
||||
status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
|
||||
if (status != WLAN_STATUS_SUCCESS)
|
||||
goto end;
|
||||
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
|
||||
NULL, 0);
|
||||
if (!owe_buf) {
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sta->owe_ecdh) {
|
||||
struct wpabuf *pub;
|
||||
|
||||
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
|
||||
if (!pub) {
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* OWE Diffie-Hellman Parameter element */
|
||||
*owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
|
||||
*owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
|
||||
*owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
|
||||
*/
|
||||
WPA_PUT_LE16(owe_buf, sta->owe_group);
|
||||
owe_buf += 2;
|
||||
os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
|
||||
owe_buf += wpabuf_len(pub);
|
||||
wpabuf_free(pub);
|
||||
sta->external_dh_updated = 1;
|
||||
}
|
||||
ie_len = owe_buf - ie;
|
||||
|
||||
end:
|
||||
wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
|
||||
MACSTR, status, (unsigned int) ie_len,
|
||||
MAC2STR(sta->addr));
|
||||
hostapd_drv_update_dh_ie(hapd, sta->addr, status,
|
||||
status == WLAN_STATUS_SUCCESS ? ie : NULL,
|
||||
ie_len);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
@ -2845,10 +2968,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
|
||||
resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
|
||||
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
@ -2869,6 +2988,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
return resp;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
|
||||
elems.he_capabilities,
|
||||
elems.he_capabilities_len);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (elems.p2p) {
|
||||
@ -3231,6 +3359,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
{
|
||||
struct ieee80211_ht_capabilities ht_cap;
|
||||
struct ieee80211_vht_capabilities vht_cap;
|
||||
struct ieee80211_he_capabilities he_cap;
|
||||
int set = 1;
|
||||
|
||||
/*
|
||||
@ -3283,6 +3412,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
if (sta->flags & WLAN_STA_VHT)
|
||||
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (sta->flags & WLAN_STA_HE) {
|
||||
hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
|
||||
sta->he_capab_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/*
|
||||
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
|
||||
@ -3294,6 +3429,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
sta->listen_interval,
|
||||
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
|
||||
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
|
||||
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
|
||||
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
|
||||
set)) {
|
||||
@ -3331,6 +3468,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#ifdef CONFIG_FILS
|
||||
if (sta && sta->fils_hlp_resp)
|
||||
buflen += wpabuf_len(sta->fils_hlp_resp);
|
||||
if (sta)
|
||||
buflen += 150;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_OWE
|
||||
if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
|
||||
@ -3392,6 +3531,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_FILS
|
||||
if (sta && status_code == WLAN_STATUS_SUCCESS &&
|
||||
(sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK))
|
||||
p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
|
||||
buf + buflen - p,
|
||||
ies, ies_len);
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if (sta && status_code == WLAN_STATUS_SUCCESS &&
|
||||
@ -3434,6 +3582,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
|
||||
p = hostapd_eid_he_operation(hapd, p);
|
||||
p = hostapd_eid_spatial_reuse(hapd, p);
|
||||
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
p = hostapd_eid_ext_capab(hapd, p);
|
||||
p = hostapd_eid_bss_max_idle_period(hapd, p);
|
||||
if (sta && sta->qos_map_enabled)
|
||||
@ -3610,6 +3767,12 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
return owe_buf;
|
||||
}
|
||||
|
||||
if (sta->owe_pmk && sta->external_dh_updated) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
|
||||
*reason = WLAN_STATUS_SUCCESS;
|
||||
return owe_buf;
|
||||
}
|
||||
|
||||
*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
|
||||
if (*reason != WLAN_STATUS_SUCCESS)
|
||||
return NULL;
|
||||
|
@ -18,6 +18,7 @@ struct ieee80211_vht_capabilities;
|
||||
struct ieee80211_mgmt;
|
||||
struct vlan_description;
|
||||
struct hostapd_sta_wpa_psk_short;
|
||||
enum ieee80211_op_mode;
|
||||
|
||||
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
struct hostapd_frame_info *fi);
|
||||
@ -57,9 +58,11 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
enum ieee80211_op_mode opmode);
|
||||
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
|
||||
|
||||
int hostapd_ht_operation_update(struct hostapd_iface *iface);
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
@ -70,6 +73,10 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
|
||||
void hostapd_get_vht_capab(struct hostapd_data *hapd,
|
||||
struct ieee80211_vht_capabilities *vht_cap,
|
||||
struct ieee80211_vht_capabilities *neg_vht_cap);
|
||||
void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
size_t he_capab_len);
|
||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab);
|
||||
@ -85,6 +92,9 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_oper);
|
||||
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_opmode);
|
||||
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
enum ieee80211_op_mode opmode, const u8 *he_capab,
|
||||
size_t he_capab_len);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len, int ack);
|
||||
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
@ -153,6 +163,12 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
|
||||
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *owe_dh, u8 owe_dh_len,
|
||||
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
|
||||
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
|
||||
const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
|
||||
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11ax HE
|
||||
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2019 John Crispin <john@phrozen.org>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -13,37 +14,113 @@
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
#include "sta_info.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
||||
{
|
||||
u8 sz = 0, ru;
|
||||
|
||||
if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
|
||||
HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
|
||||
return 0;
|
||||
|
||||
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
|
||||
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
|
||||
while (ru) {
|
||||
if (ru & 0x1)
|
||||
sz++;
|
||||
ru >>= 1;
|
||||
}
|
||||
|
||||
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
|
||||
sz = (sz * 6) + 7;
|
||||
if (sz % 8)
|
||||
sz += 8;
|
||||
sz /= 8;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
enum ieee80211_op_mode opmode)
|
||||
{
|
||||
struct ieee80211_he_capabilities *cap;
|
||||
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
|
||||
u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
|
||||
u8 *pos = eid;
|
||||
u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
if (!mode)
|
||||
return eid;
|
||||
|
||||
ie_size = sizeof(struct ieee80211_he_capabilities);
|
||||
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
|
||||
mode->he_capab[opmode].phy_cap);
|
||||
|
||||
switch (hapd->iface->conf->he_oper_chwidth) {
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
he_oper_chwidth |=
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
|
||||
mcs_nss_size += 4;
|
||||
/* fall through */
|
||||
case CHANWIDTH_160MHZ:
|
||||
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
|
||||
mcs_nss_size += 4;
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_USE_HT:
|
||||
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
|
||||
mcs_nss_size += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
ie_size += mcs_nss_size + ppet_size;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
|
||||
*pos++ = 1 + ie_size;
|
||||
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
|
||||
|
||||
cap = (struct ieee80211_he_capabilities *) pos;
|
||||
os_memset(cap, 0, sizeof(*cap));
|
||||
|
||||
os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
|
||||
HE_MAX_MAC_CAPAB_SIZE);
|
||||
os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
|
||||
HE_MAX_PHY_CAPAB_SIZE);
|
||||
os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
|
||||
if (ppet_size)
|
||||
os_memcpy(&cap->optional[mcs_nss_size],
|
||||
mode->he_capab[opmode].ppet, ppet_size);
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
|
||||
HE_PHYCAP_SU_BEAMFORMER_CAPAB;
|
||||
else
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &=
|
||||
~HE_PHYCAP_SU_BEAMFORMER_CAPAB;
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
|
||||
HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
|
||||
else
|
||||
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &=
|
||||
~HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
|
||||
|
||||
if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
|
||||
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
|
||||
HE_PHYCAP_MU_BEAMFORMER_CAPAB;
|
||||
else
|
||||
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &=
|
||||
~HE_PHYCAP_MU_BEAMFORMER_CAPAB;
|
||||
|
||||
pos += sizeof(*cap);
|
||||
cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &=
|
||||
he_oper_chwidth;
|
||||
|
||||
pos += ie_size;
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -53,36 +130,43 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_operation *oper;
|
||||
u8 *pos = eid;
|
||||
int oper_size = 6;
|
||||
u32 params = 0;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_operation);
|
||||
*pos++ = 1 + oper_size;
|
||||
*pos++ = WLAN_EID_EXT_HE_OPERATION;
|
||||
|
||||
oper = (struct ieee80211_he_operation *) pos;
|
||||
os_memset(oper, 0, sizeof(*oper));
|
||||
|
||||
if (hapd->iface->conf->he_op.he_bss_color)
|
||||
oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
|
||||
|
||||
if (hapd->iface->conf->he_op.he_default_pe_duration)
|
||||
oper->he_oper_params |=
|
||||
(hapd->iface->conf->he_op.he_default_pe_duration <<
|
||||
HE_OPERATION_DFLT_PE_DURATION_OFFSET);
|
||||
params |= (hapd->iface->conf->he_op.he_default_pe_duration <<
|
||||
HE_OPERATION_DFLT_PE_DURATION_OFFSET);
|
||||
|
||||
if (hapd->iface->conf->he_op.he_twt_required)
|
||||
oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
|
||||
params |= HE_OPERATION_TWT_REQUIRED;
|
||||
|
||||
if (hapd->iface->conf->he_op.he_rts_threshold)
|
||||
oper->he_oper_params |=
|
||||
(hapd->iface->conf->he_op.he_rts_threshold <<
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET);
|
||||
params |= (hapd->iface->conf->he_op.he_rts_threshold <<
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET);
|
||||
|
||||
if (hapd->iface->conf->he_op.he_bss_color)
|
||||
params |= (hapd->iface->conf->he_op.he_bss_color <<
|
||||
HE_OPERATION_BSS_COLOR_OFFSET);
|
||||
|
||||
/* HE minimum required basic MCS and NSS for STAs */
|
||||
oper->he_mcs_nss_set =
|
||||
host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set);
|
||||
|
||||
/* TODO: conditional MaxBSSID Indicator subfield */
|
||||
|
||||
pos += sizeof(*oper);
|
||||
oper->he_oper_params = host_to_le32(params);
|
||||
|
||||
pos += oper_size;
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -117,3 +201,148 @@ u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_spatial_reuse *spr;
|
||||
u8 *pos = eid, *spr_param;
|
||||
u8 sz = 1;
|
||||
|
||||
if (!hapd->iface->conf->spr.sr_control)
|
||||
return eid;
|
||||
|
||||
if (hapd->iface->conf->spr.sr_control &
|
||||
SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
|
||||
sz++;
|
||||
|
||||
if (hapd->iface->conf->spr.sr_control &
|
||||
SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
|
||||
sz += 18;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sz;
|
||||
*pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
|
||||
|
||||
spr = (struct ieee80211_spatial_reuse *) pos;
|
||||
os_memset(spr, 0, sizeof(*spr));
|
||||
|
||||
spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
|
||||
pos++;
|
||||
spr_param = spr->params;
|
||||
if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
|
||||
*spr_param++ =
|
||||
hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
|
||||
pos++;
|
||||
}
|
||||
if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
|
||||
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
|
||||
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
|
||||
pos += 18;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
size_t he_capab_len)
|
||||
{
|
||||
if (!he_cap)
|
||||
return;
|
||||
|
||||
if (he_capab_len > sizeof(*neg_he_cap))
|
||||
he_capab_len = sizeof(*neg_he_cap);
|
||||
/* TODO: mask out unsupported features */
|
||||
|
||||
os_memcpy(neg_he_cap, he_cap, he_capab_len);
|
||||
}
|
||||
|
||||
|
||||
static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
|
||||
enum ieee80211_op_mode opmode)
|
||||
{
|
||||
u16 sta_rx_mcs_set, ap_tx_mcs_set;
|
||||
u8 mcs_count = 0;
|
||||
const u16 *ap_mcs_set, *sta_mcs_set;
|
||||
int i;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return 1;
|
||||
ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
|
||||
sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
|
||||
sta_he_capab)->optional;
|
||||
|
||||
/*
|
||||
* Disable HE capabilities for STAs for which there is not even a single
|
||||
* allowed MCS in any supported number of streams, i.e., STA is
|
||||
* advertising 3 (not supported) as HE MCS rates for all supported
|
||||
* band/stream cases.
|
||||
*/
|
||||
switch (hapd->iface->conf->he_oper_chwidth) {
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
mcs_count = 3;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
mcs_count = 2;
|
||||
break;
|
||||
default:
|
||||
mcs_count = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < mcs_count; i++) {
|
||||
int j;
|
||||
|
||||
/* AP Tx MCS map vs. STA Rx MCS map */
|
||||
sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
|
||||
ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
|
||||
&ap_mcs_set[(i * 2) + 1]);
|
||||
|
||||
for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
|
||||
if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
|
||||
continue;
|
||||
|
||||
if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
|
||||
continue;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No matching HE MCS found between AP TX and STA RX");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
enum ieee80211_op_mode opmode, const u8 *he_capab,
|
||||
size_t he_capab_len)
|
||||
{
|
||||
if (!he_capab || !hapd->iconf->ieee80211ax ||
|
||||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
|
||||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
|
||||
sta->flags &= ~WLAN_STA_HE;
|
||||
os_free(sta->he_capab);
|
||||
sta->he_capab = NULL;
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!sta->he_capab) {
|
||||
sta->he_capab =
|
||||
os_zalloc(sizeof(struct ieee80211_he_capabilities));
|
||||
if (!sta->he_capab)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
sta->flags |= WLAN_STA_HE;
|
||||
os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
|
||||
os_memcpy(sta->he_capab, he_capab, he_capab_len);
|
||||
sta->he_capab_len = he_capab_len;
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
|
||||
return eid;
|
||||
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (iconf->secondary_channel == 0) {
|
||||
/* Max Transmit Power count = 0 (20 MHz) */
|
||||
tx_pwr_count = 0;
|
||||
@ -251,12 +251,12 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
|
||||
tx_pwr_count = 1;
|
||||
}
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_80MHZ:
|
||||
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
|
||||
tx_pwr_count = 2;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
|
||||
tx_pwr_count = 3;
|
||||
break;
|
||||
|
@ -7,6 +7,9 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#ifdef CONFIG_SQLITE
|
||||
#include <sqlite3.h>
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
@ -34,6 +37,7 @@
|
||||
/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "wpa_auth_kay.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
@ -63,6 +67,10 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
xhdr = (struct ieee802_1x_hdr *) buf;
|
||||
xhdr->version = hapd->conf->eapol_version;
|
||||
#ifdef CONFIG_MACSEC
|
||||
if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
|
||||
xhdr->version = 2;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
xhdr->type = type;
|
||||
xhdr->length = host_to_be16(datalen);
|
||||
|
||||
@ -157,6 +165,21 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
|
||||
key->type = EAPOL_KEY_TYPE_RC4;
|
||||
WPA_PUT_BE16(key->key_length, key_len);
|
||||
wpa_get_ntp_timestamp(key->replay_counter);
|
||||
if (os_memcmp(key->replay_counter,
|
||||
hapd->last_1x_eapol_key_replay_counter,
|
||||
IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
|
||||
/* NTP timestamp did not increment from last EAPOL-Key frame;
|
||||
* use previously used value + 1 instead. */
|
||||
inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
|
||||
IEEE8021X_REPLAY_COUNTER_LEN);
|
||||
os_memcpy(key->replay_counter,
|
||||
hapd->last_1x_eapol_key_replay_counter,
|
||||
IEEE8021X_REPLAY_COUNTER_LEN);
|
||||
} else {
|
||||
os_memcpy(hapd->last_1x_eapol_key_replay_counter,
|
||||
key->replay_counter,
|
||||
IEEE8021X_REPLAY_COUNTER_LEN);
|
||||
}
|
||||
|
||||
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
|
||||
wpa_printf(MSG_ERROR, "Could not get random numbers");
|
||||
@ -197,6 +220,10 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
|
||||
/* This header is needed here for HMAC-MD5, but it will be regenerated
|
||||
* in ieee802_1x_send() */
|
||||
hdr->version = hapd->conf->eapol_version;
|
||||
#ifdef CONFIG_MACSEC
|
||||
if (hdr->version > 2)
|
||||
hdr->version = 2;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
|
||||
hdr->length = host_to_be16(len);
|
||||
hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
|
||||
@ -591,6 +618,63 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct radius_msg *msg, int acct)
|
||||
{
|
||||
#ifdef CONFIG_SQLITE
|
||||
const char *attrtxt;
|
||||
char addrtxt[3 * ETH_ALEN];
|
||||
char *sql;
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
|
||||
if (!hapd->rad_attr_db)
|
||||
return 0;
|
||||
|
||||
os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
|
||||
|
||||
sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
|
||||
if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
|
||||
NULL) != SQLITE_OK) {
|
||||
wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
|
||||
sqlite3_errmsg(hapd->rad_attr_db));
|
||||
return -1;
|
||||
}
|
||||
sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
struct hostapd_radius_attr *attr;
|
||||
struct radius_attr_hdr *hdr;
|
||||
|
||||
attrtxt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
attr = hostapd_parse_radius_attr(attrtxt);
|
||||
if (!attr) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Skipping invalid attribute from SQL: %s",
|
||||
attrtxt);
|
||||
continue;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
|
||||
attrtxt);
|
||||
hdr = radius_msg_add_attr(msg, attr->type,
|
||||
wpabuf_head(attr->val),
|
||||
wpabuf_len(attr->val));
|
||||
hostapd_config_free_radius_attr(attr);
|
||||
if (!hdr) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Could not add RADIUS attribute from SQL");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_reset(stmt);
|
||||
sqlite3_clear_bindings(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *eap, size_t len)
|
||||
@ -630,6 +714,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
msg) < 0)
|
||||
goto fail;
|
||||
|
||||
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
/* TODO: should probably check MTU from driver config; 2304 is max for
|
||||
* IEEE 802.11, but use 1400 to avoid problems with too large packets
|
||||
*/
|
||||
@ -1104,6 +1191,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
/* TODO: implement support for this; show data */
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
case IEEE802_1X_TYPE_EAPOL_MKA:
|
||||
wpa_printf(MSG_EXCESSIVE,
|
||||
"EAPOL type %d will be handled by MKA", hdr->type);
|
||||
break;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
|
||||
sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
|
||||
@ -1385,6 +1479,8 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
|
||||
size_t shared_secret_len)
|
||||
{
|
||||
struct radius_ms_mppe_keys *keys;
|
||||
u8 *buf;
|
||||
size_t len;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
if (sm == NULL)
|
||||
return;
|
||||
@ -1393,7 +1489,7 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
|
||||
shared_secret_len);
|
||||
|
||||
if (keys && keys->send && keys->recv) {
|
||||
size_t len = keys->send_len + keys->recv_len;
|
||||
len = keys->send_len + keys->recv_len;
|
||||
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
|
||||
keys->send, keys->send_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
|
||||
@ -1421,6 +1517,20 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
|
||||
os_free(keys->recv);
|
||||
os_free(keys);
|
||||
}
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
|
||||
NULL) == 0) {
|
||||
os_free(sm->eap_if->eapSessionId);
|
||||
sm->eap_if->eapSessionId = os_memdup(buf, len);
|
||||
if (sm->eap_if->eapSessionId) {
|
||||
sm->eap_if->eapSessionIdLen = len;
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
|
||||
sm->eap_if->eapSessionId,
|
||||
sm->eap_if->eapSessionIdLen);
|
||||
}
|
||||
} else {
|
||||
sm->eap_if->eapSessionIdLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2324,7 +2434,10 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
conf.eap_fast_prov = hapd->conf->eap_fast_prov;
|
||||
conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
|
||||
conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
|
||||
conf.eap_teap_auth = hapd->conf->eap_teap_auth;
|
||||
conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
|
||||
conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
|
||||
conf.eap_sim_id = hapd->conf->eap_sim_id;
|
||||
conf.tnc = hapd->conf->tnc;
|
||||
conf.wps = hapd->wps;
|
||||
conf.fragment_size = hapd->conf->fragment_size;
|
||||
@ -2543,6 +2656,20 @@ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
|
||||
size_t *len)
|
||||
{
|
||||
*len = 0;
|
||||
if (!sm || !sm->eap_if)
|
||||
return NULL;
|
||||
|
||||
*len = sm->eap_if->eapSessionIdLen;
|
||||
return sm->eap_if->eapSessionId;
|
||||
}
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled)
|
||||
{
|
||||
@ -2833,6 +2960,10 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
ieee802_1x_notify_create_actor_hapd(hapd, sta);
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
key = ieee802_1x_get_key(sta->eapol_sm, &len);
|
||||
if (sta->session_timeout_set) {
|
||||
os_get_reltime(&now);
|
||||
|
@ -39,6 +39,8 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
|
||||
int idx);
|
||||
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
|
||||
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
|
||||
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
|
||||
size_t *len);
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled);
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||
@ -57,6 +59,8 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
struct hostapd_radius_attr *req_attr,
|
||||
struct sta_info *sta,
|
||||
struct radius_msg *msg);
|
||||
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct radius_msg *msg, int acct);
|
||||
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *eap, size_t len);
|
||||
|
@ -139,19 +139,21 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
||||
int ht, int vht)
|
||||
int ht, int vht, int he)
|
||||
{
|
||||
if (!ht && !vht)
|
||||
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
|
||||
|
||||
if (!ht && !vht && !he)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if (!hapd->iconf->secondary_channel)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
|
||||
if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
|
||||
return NR_CHAN_WIDTH_40;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
if (oper_chwidth == CHANWIDTH_80MHZ)
|
||||
return NR_CHAN_WIDTH_80;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
|
||||
if (oper_chwidth == CHANWIDTH_160MHZ)
|
||||
return NR_CHAN_WIDTH_160;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
|
||||
if (oper_chwidth == CHANWIDTH_80P80MHZ)
|
||||
return NR_CHAN_WIDTH_80P80;
|
||||
return NR_CHAN_WIDTH_20;
|
||||
}
|
||||
@ -164,6 +166,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
u16 capab = hostapd_own_capab_info(hapd);
|
||||
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
int he = hapd->iconf->ieee80211ax;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
@ -205,16 +208,18 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
hostapd_get_oper_chwidth(hapd->iconf),
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return;
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht);
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht, he);
|
||||
if (vht) {
|
||||
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx(
|
||||
hapd->iconf);
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
hostapd_get_oper_centr_freq_seg1_idx(
|
||||
hapd->iconf);
|
||||
} else if (ht) {
|
||||
ieee80211_freq_to_chan(hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel,
|
||||
|
@ -330,6 +330,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_free(sta->ht_capabilities);
|
||||
os_free(sta->vht_capabilities);
|
||||
os_free(sta->vht_operation);
|
||||
os_free(sta->he_capab);
|
||||
hostapd_free_psk_list(sta->psk);
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
@ -670,6 +671,7 @@ void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
|
||||
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
@ -694,6 +696,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
|
||||
if (!hapd->iface->basic_rates)
|
||||
break;
|
||||
if (hapd->iface->basic_rates[i] < 0)
|
||||
break;
|
||||
sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
|
||||
}
|
||||
sta->supported_rates_len = i;
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define WLAN_STA_VENDOR_VHT BIT(21)
|
||||
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
|
||||
#define WLAN_STA_MULTI_AP BIT(23)
|
||||
#define WLAN_STA_HE BIT(24)
|
||||
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
|
||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||
#define WLAN_STA_NONERP BIT(31)
|
||||
@ -119,6 +120,7 @@ struct sta_info {
|
||||
unsigned int agreed_to_steer:1;
|
||||
unsigned int hs20_t_c_filtering:1;
|
||||
unsigned int ft_over_ds:1;
|
||||
unsigned int external_dh_updated:1;
|
||||
|
||||
u16 auth_alg;
|
||||
|
||||
@ -166,6 +168,8 @@ struct sta_info {
|
||||
struct ieee80211_vht_capabilities *vht_capabilities;
|
||||
struct ieee80211_vht_operation *vht_operation;
|
||||
u8 vht_opmode;
|
||||
struct ieee80211_he_capabilities *he_capab;
|
||||
size_t he_capab_len;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
int sa_query_count; /* number of pending SA Query requests;
|
||||
@ -275,6 +279,10 @@ struct sta_info {
|
||||
u8 last_tk[WPA_TK_MAX_LEN];
|
||||
size_t last_tk_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
unsigned int airtime_weight;
|
||||
struct os_reltime backlogged_until;
|
||||
#endif /* CONFIG_AIRTIME_POLICY */
|
||||
};
|
||||
|
||||
|
||||
|
@ -20,6 +20,13 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wmm.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
|
||||
{
|
||||
@ -39,6 +46,62 @@ static inline u8 wmm_ecw(int ecwmin, int ecwmax)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
wmm_set_regulatory_limit(const struct hostapd_wmm_ac_params *wmm_conf,
|
||||
struct hostapd_wmm_ac_params *wmm,
|
||||
const struct hostapd_wmm_rule *wmm_reg)
|
||||
{
|
||||
int ac;
|
||||
|
||||
for (ac = 0; ac < WMM_AC_NUM; ac++) {
|
||||
wmm[ac].cwmin = MAX(wmm_conf[ac].cwmin, wmm_reg[ac].min_cwmin);
|
||||
wmm[ac].cwmax = MAX(wmm_conf[ac].cwmax, wmm_reg[ac].min_cwmax);
|
||||
wmm[ac].aifs = MAX(wmm_conf[ac].aifs, wmm_reg[ac].min_aifs);
|
||||
wmm[ac].txop_limit =
|
||||
MIN(wmm_conf[ac].txop_limit, wmm_reg[ac].max_txop);
|
||||
wmm[ac].admission_control_mandatory =
|
||||
wmm_conf[ac].admission_control_mandatory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Calculate WMM regulatory limit if any.
|
||||
*/
|
||||
static void wmm_calc_regulatory_limit(struct hostapd_data *hapd,
|
||||
struct hostapd_wmm_ac_params *acp)
|
||||
{
|
||||
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
|
||||
int c;
|
||||
|
||||
os_memcpy(acp, hapd->iconf->wmm_ac_params,
|
||||
sizeof(hapd->iconf->wmm_ac_params));
|
||||
|
||||
for (c = 0; mode && c < mode->num_channels; c++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[c];
|
||||
|
||||
if (chan->freq != hapd->iface->freq)
|
||||
continue;
|
||||
|
||||
if (chan->wmm_rules_valid)
|
||||
wmm_set_regulatory_limit(hapd->iconf->wmm_ac_params,
|
||||
acp, chan->wmm_rules);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we need to update set count. Since both were initialized to
|
||||
* zero we can compare the whole array in one shot.
|
||||
*/
|
||||
if (os_memcmp(acp, hapd->iface->prev_wmm,
|
||||
sizeof(hapd->iconf->wmm_ac_params)) != 0) {
|
||||
os_memcpy(hapd->iface->prev_wmm, acp,
|
||||
sizeof(hapd->iconf->wmm_ac_params));
|
||||
hapd->parameter_set_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
|
||||
* Response frames.
|
||||
@ -48,10 +111,12 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
|
||||
u8 *pos = eid;
|
||||
struct wmm_parameter_element *wmm =
|
||||
(struct wmm_parameter_element *) (pos + 2);
|
||||
struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
|
||||
int e;
|
||||
|
||||
if (!hapd->conf->wmm_enabled)
|
||||
return eid;
|
||||
wmm_calc_regulatory_limit(hapd, wmmp);
|
||||
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
wmm->oui[0] = 0x00;
|
||||
wmm->oui[1] = 0x50;
|
||||
@ -70,8 +135,7 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
|
||||
/* fill in a parameter set record for each AC */
|
||||
for (e = 0; e < 4; e++) {
|
||||
struct wmm_ac_parameter *ac = &wmm->ac[e];
|
||||
struct hostapd_wmm_ac_params *acp =
|
||||
&hapd->iconf->wmm_ac_params[e];
|
||||
struct hostapd_wmm_ac_params *acp = &wmmp[e];
|
||||
|
||||
ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
|
||||
acp->admission_control_mandatory,
|
||||
|
@ -934,6 +934,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
|
||||
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
|
||||
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
|
||||
forced_memzero(&PTK, sizeof(PTK));
|
||||
sm->PTK_valid = TRUE;
|
||||
|
||||
return 0;
|
||||
@ -1407,6 +1408,8 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
|
||||
#endif /* CONFIG_SHA256 */
|
||||
#endif /* CONFIG_SHA384 */
|
||||
|
||||
forced_memzero(data, sizeof(data));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2046,7 +2049,7 @@ SM_STATE(WPA_PTK, INITPMK)
|
||||
sm->Disconnect = TRUE;
|
||||
return;
|
||||
}
|
||||
os_memset(msk, 0, sizeof(msk));
|
||||
forced_memzero(msk, sizeof(msk));
|
||||
|
||||
sm->req_replay_counter_used = 0;
|
||||
/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
|
||||
@ -2285,12 +2288,12 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
|
||||
pmk_r0_name, WPA_PMK_NAME_LEN);
|
||||
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
|
||||
os_memset(fils_ft, 0, sizeof(fils_ft));
|
||||
forced_memzero(fils_ft, sizeof(fils_ft));
|
||||
|
||||
res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
|
||||
sm->addr, sm->pmk_r1_name,
|
||||
use_sha384);
|
||||
os_memset(pmk_r0, 0, PMK_LEN_MAX);
|
||||
forced_memzero(pmk_r0, PMK_LEN_MAX);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
|
||||
@ -2308,7 +2311,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
sm->wpa_key_mgmt, sm->fils_key_auth_sta,
|
||||
sm->fils_key_auth_ap,
|
||||
&sm->fils_key_auth_len);
|
||||
os_memset(ick, 0, sizeof(ick));
|
||||
forced_memzero(ick, sizeof(ick));
|
||||
|
||||
/* Store nonces for (Re)Association Request/Response frame processing */
|
||||
os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
|
||||
@ -2610,7 +2613,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
|
||||
if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Not enough room for FILS elements");
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2620,7 +2623,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
|
||||
if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
|
||||
wpabuf_head(plain), wpabuf_len(plain),
|
||||
5, aad, aad_len, pos) < 0) {
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2628,7 +2631,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
|
||||
"FILS: Encrypted Association Response elements",
|
||||
pos, AES_BLOCK_SIZE + wpabuf_len(plain));
|
||||
current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
|
||||
sm->fils_completed = 1;
|
||||
|
||||
@ -2682,7 +2685,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
|
||||
* of GTK in the BSS.
|
||||
*/
|
||||
if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
return NULL;
|
||||
}
|
||||
gtk = dummy_gtk;
|
||||
@ -2709,13 +2712,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
|
||||
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"FILS: Failed to get channel info for OCI element");
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
|
||||
if (ocv_insert_extended_oci(&ci, pos) < 0) {
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -2778,7 +2781,7 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
|
||||
(unsigned int) wpabuf_len(plain));
|
||||
wpabuf_free(plain);
|
||||
wpabuf_clear_free(plain);
|
||||
sm->fils_completed = 1;
|
||||
return pos;
|
||||
}
|
||||
@ -3030,6 +3033,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
sm->MICVerified = TRUE;
|
||||
|
||||
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
|
||||
forced_memzero(&PTK, sizeof(PTK));
|
||||
sm->PTK_valid = TRUE;
|
||||
}
|
||||
|
||||
@ -4246,8 +4250,12 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
|
||||
|
||||
/* Private MIB */
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"wpa=%d\n"
|
||||
"AKMSuiteSelector=" RSN_SUITE "\n"
|
||||
"hostapdWPAPTKState=%d\n"
|
||||
"hostapdWPAPTKGroupState=%d\n",
|
||||
sm->wpa,
|
||||
RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
|
||||
sm->wpa_ptk_state,
|
||||
sm->wpa_ptk_group_state);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
@ -4359,6 +4367,15 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
sm->wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
|
||||
wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
|
||||
!wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
|
||||
/* Cache MPMK/XXKey instead of initial part from MSK */
|
||||
pmk = pmk + PMK_LEN;
|
||||
pmk_len = PMK_LEN;
|
||||
} else
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
|
||||
if (pmk_len > PMK_LEN_SUITE_B_192)
|
||||
pmk_len = PMK_LEN_SUITE_B_192;
|
||||
@ -4366,6 +4383,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
pmk_len = PMK_LEN;
|
||||
}
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
|
||||
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
|
||||
sm->PTK.kck, sm->PTK.kck_len,
|
||||
sm->wpa_auth->addr, sm->addr, session_timeout,
|
||||
@ -4384,6 +4402,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
if (wpa_auth == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
|
||||
NULL, 0,
|
||||
wpa_auth->addr,
|
||||
@ -4401,6 +4420,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
if (wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
|
||||
NULL, 0,
|
||||
wpa_auth->addr, addr, 0, NULL,
|
||||
@ -4425,6 +4445,7 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
if (wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
|
||||
NULL, 0, wpa_auth->addr, addr, session_timeout,
|
||||
NULL, akmp))
|
||||
|
@ -475,6 +475,9 @@ void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
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);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "wmm.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_i.h"
|
||||
#include "pmksa_cache_auth.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
@ -2094,8 +2095,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
|
||||
const u8 *identity, *radius_cui;
|
||||
size_t identity_len, radius_cui_len;
|
||||
int session_timeout;
|
||||
const u8 *mpmk;
|
||||
size_t mpmk_len;
|
||||
|
||||
if (sm->xxkey_len == 0) {
|
||||
if (sm->xxkey_len > 0) {
|
||||
mpmk = sm->xxkey;
|
||||
mpmk_len = sm->xxkey_len;
|
||||
} else if (sm->pmksa) {
|
||||
mpmk = sm->pmksa->pmk;
|
||||
mpmk_len = sm->pmksa->pmk_len;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
|
||||
"derivation");
|
||||
return -1;
|
||||
@ -2112,7 +2121,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
|
||||
&radius_cui);
|
||||
session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
|
||||
|
||||
if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
|
||||
if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
|
||||
r0kh, r0kh_len, sm->addr,
|
||||
pmk_r0, pmk_r0_name,
|
||||
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
|
||||
@ -2217,6 +2226,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
forced_memzero(keybuf, sizeof(keybuf));
|
||||
*len = subelem_len;
|
||||
return subelem;
|
||||
}
|
||||
@ -3090,8 +3100,9 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
|
||||
status = res;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
|
||||
" auth_transaction=%d status=%d",
|
||||
MAC2STR(sm->addr), auth_transaction + 1, status);
|
||||
" auth_transaction=%d status=%u (%s)",
|
||||
MAC2STR(sm->addr), auth_transaction + 1, status,
|
||||
status2str(status));
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
|
||||
cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
|
||||
resp_ies, resp_ies_len);
|
||||
@ -3449,8 +3460,9 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
|
||||
u8 *pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
|
||||
" CurrentAP=" MACSTR " status=%d",
|
||||
MAC2STR(sm->addr), MAC2STR(current_ap), status);
|
||||
" CurrentAP=" MACSTR " status=%u (%s)",
|
||||
MAC2STR(sm->addr), MAC2STR(current_ap), status,
|
||||
status2str(status));
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
|
||||
|
||||
/* RRB - Forward action frame response to the Current AP */
|
||||
@ -3556,7 +3568,7 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
|
||||
pmk_r0->vlan, src_addr, type,
|
||||
packet, packet_len);
|
||||
|
||||
os_memset(pmk_r1, 0, sizeof(pmk_r1));
|
||||
forced_memzero(pmk_r1, sizeof(pmk_r1));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -3882,10 +3894,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (plain) {
|
||||
os_memset(plain, 0, plain_len);
|
||||
os_free(plain);
|
||||
}
|
||||
bin_clear_free(plain, plain_len);
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -53,6 +53,10 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->rsn_pairwise = conf->rsn_pairwise;
|
||||
wconf->rsn_preauth = conf->rsn_preauth;
|
||||
wconf->eapol_version = conf->eapol_version;
|
||||
#ifdef CONFIG_MACSEC
|
||||
if (wconf->eapol_version > 2)
|
||||
wconf->eapol_version = 2;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
wconf->wmm_enabled = conf->wmm_enabled;
|
||||
wconf->wmm_uapsd = conf->wmm_uapsd;
|
||||
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
|
||||
|
@ -1176,3 +1176,23 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||
return pos + res;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
const u8 *req_ies, size_t req_ies_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!sm ||
|
||||
sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384))
|
||||
return pos;
|
||||
|
||||
res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL);
|
||||
if (res < 0)
|
||||
return pos;
|
||||
return pos + res;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
523
contrib/wpa/src/ap/wpa_auth_kay.c
Normal file
523
contrib/wpa/src/ap/wpa_auth_kay.c
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* IEEE 802.1X-2010 KaY Interface
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "pae/ieee802_1x_key.h"
|
||||
#include "pae/ieee802_1x_kay.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "wpa_auth_kay.h"
|
||||
#include "ieee802_1x.h"
|
||||
|
||||
|
||||
#define DEFAULT_KEY_LEN 16
|
||||
/* secure Connectivity Association Key Name (CKN) */
|
||||
#define DEFAULT_CKN_LEN 16
|
||||
|
||||
|
||||
static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->macsec_init)
|
||||
return -1;
|
||||
return hapd->driver->macsec_init(hapd->drv_priv, params);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_macsec_deinit(void *priv)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->macsec_deinit)
|
||||
return -1;
|
||||
return hapd->driver->macsec_deinit(hapd->drv_priv);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->macsec_get_capability)
|
||||
return -1;
|
||||
return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_protect_frames(void *priv, Boolean enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->enable_protect_frames)
|
||||
return -1;
|
||||
return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_encrypt(void *priv, Boolean enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->enable_encrypt)
|
||||
return -1;
|
||||
return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->set_replay_protect)
|
||||
return -1;
|
||||
return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
|
||||
window);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_set_current_cipher_suite(void *priv, u64 cs)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->set_current_cipher_suite)
|
||||
return -1;
|
||||
return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_controlled_port(void *priv, Boolean enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->enable_controlled_port)
|
||||
return -1;
|
||||
return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->get_receive_lowest_pn)
|
||||
return -1;
|
||||
return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->get_transmit_next_pn)
|
||||
return -1;
|
||||
return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->set_transmit_next_pn)
|
||||
return -1;
|
||||
return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int conf_offset_val(enum confidentiality_offset co)
|
||||
{
|
||||
switch (co) {
|
||||
case CONFIDENTIALITY_OFFSET_30:
|
||||
return 30;
|
||||
break;
|
||||
case CONFIDENTIALITY_OFFSET_50:
|
||||
return 50;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
|
||||
enum validate_frames vf,
|
||||
enum confidentiality_offset co)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->create_receive_sc)
|
||||
return -1;
|
||||
return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
|
||||
conf_offset_val(co), vf);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->delete_receive_sc)
|
||||
return -1;
|
||||
return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->create_receive_sa)
|
||||
return -1;
|
||||
return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->delete_receive_sa)
|
||||
return -1;
|
||||
return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->enable_receive_sa)
|
||||
return -1;
|
||||
return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->disable_receive_sa)
|
||||
return -1;
|
||||
return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
|
||||
enum confidentiality_offset co)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->create_transmit_sc)
|
||||
return -1;
|
||||
return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
|
||||
conf_offset_val(co));
|
||||
}
|
||||
|
||||
|
||||
static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->delete_transmit_sc)
|
||||
return -1;
|
||||
return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->create_transmit_sa)
|
||||
return -1;
|
||||
return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->delete_transmit_sa)
|
||||
return -1;
|
||||
return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->enable_transmit_sa)
|
||||
return -1;
|
||||
return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
if (!hapd->driver->disable_transmit_sa)
|
||||
return -1;
|
||||
return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
|
||||
}
|
||||
|
||||
|
||||
int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee802_1x_kay_ctx *kay_ctx;
|
||||
struct ieee802_1x_kay *res = NULL;
|
||||
enum macsec_policy policy;
|
||||
|
||||
ieee802_1x_dealloc_kay_sm_hapd(hapd);
|
||||
|
||||
if (!hapd->conf || hapd->conf->macsec_policy == 0)
|
||||
return 0;
|
||||
|
||||
if (hapd->conf->macsec_policy == 1) {
|
||||
if (hapd->conf->macsec_integ_only == 1)
|
||||
policy = SHOULD_SECURE;
|
||||
else
|
||||
policy = SHOULD_ENCRYPT;
|
||||
} else {
|
||||
policy = DO_NOT_SECURE;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
|
||||
kay_ctx = os_zalloc(sizeof(*kay_ctx));
|
||||
if (!kay_ctx)
|
||||
return -1;
|
||||
|
||||
kay_ctx->ctx = hapd;
|
||||
|
||||
kay_ctx->macsec_init = hapd_macsec_init;
|
||||
kay_ctx->macsec_deinit = hapd_macsec_deinit;
|
||||
kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
|
||||
kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
|
||||
kay_ctx->enable_encrypt = hapd_enable_encrypt;
|
||||
kay_ctx->set_replay_protect = hapd_set_replay_protect;
|
||||
kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
|
||||
kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
|
||||
kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
|
||||
kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
|
||||
kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
|
||||
kay_ctx->create_receive_sc = hapd_create_receive_sc;
|
||||
kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
|
||||
kay_ctx->create_receive_sa = hapd_create_receive_sa;
|
||||
kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
|
||||
kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
|
||||
kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
|
||||
kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
|
||||
kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
|
||||
kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
|
||||
kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
|
||||
kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
|
||||
kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
|
||||
|
||||
res = ieee802_1x_kay_init(kay_ctx, policy,
|
||||
hapd->conf->macsec_replay_protect,
|
||||
hapd->conf->macsec_replay_window,
|
||||
hapd->conf->macsec_port,
|
||||
hapd->conf->mka_priority, hapd->conf->iface,
|
||||
hapd->own_addr);
|
||||
/* ieee802_1x_kay_init() frees kay_ctx on failure */
|
||||
if (!res)
|
||||
return -1;
|
||||
|
||||
hapd->kay = res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->kay)
|
||||
return;
|
||||
|
||||
ieee802_1x_kay_deinit(hapd->kay);
|
||||
hapd->kay = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *sid,
|
||||
size_t *len)
|
||||
{
|
||||
const u8 *session_id;
|
||||
size_t id_len, need_len;
|
||||
|
||||
session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
|
||||
if (!session_id) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MACsec: Failed to get SessionID from EAPOL state machines");
|
||||
return -1;
|
||||
}
|
||||
|
||||
need_len = 1 + 2 * 32 /* random size */;
|
||||
if (need_len > id_len) {
|
||||
wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(sid, session_id, need_len);
|
||||
*len = need_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *msk, size_t *len)
|
||||
{
|
||||
const u8 *key;
|
||||
size_t keylen;
|
||||
|
||||
if (!sta->eapol_sm)
|
||||
return -1;
|
||||
|
||||
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
|
||||
if (key == NULL) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MACsec: Failed to get MSK from EAPOL state machines");
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
|
||||
(unsigned long) keylen);
|
||||
wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
|
||||
|
||||
if (keylen > *len)
|
||||
keylen = *len;
|
||||
os_memcpy(msk, key, keylen);
|
||||
*len = keylen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
u8 *sid;
|
||||
size_t sid_len = 128;
|
||||
struct mka_key_name *ckn;
|
||||
struct mka_key *cak;
|
||||
struct mka_key *msk;
|
||||
void *res = NULL;
|
||||
|
||||
if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
|
||||
return NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"IEEE 802.1X: External notification - Create MKA for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
|
||||
msk = os_zalloc(sizeof(*msk));
|
||||
sid = os_zalloc(sid_len);
|
||||
ckn = os_zalloc(sizeof(*ckn));
|
||||
cak = os_zalloc(sizeof(*cak));
|
||||
if (!msk || !sid || !ckn || !cak)
|
||||
goto fail;
|
||||
|
||||
msk->len = DEFAULT_KEY_LEN;
|
||||
if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
|
||||
wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
|
||||
{
|
||||
wpa_printf(MSG_ERROR,
|
||||
"IEEE 802.1X: Could not get EAP Session Id");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
|
||||
wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
|
||||
|
||||
/* Derive CAK from MSK */
|
||||
cak->len = DEFAULT_KEY_LEN;
|
||||
if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
|
||||
sta->addr, cak->key, cak->len)) {
|
||||
wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
|
||||
|
||||
/* Derive CKN from MSK */
|
||||
ckn->len = DEFAULT_CKN_LEN;
|
||||
if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
|
||||
sta->addr, sid, sid_len, ckn->name)) {
|
||||
wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
|
||||
|
||||
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
|
||||
TRUE);
|
||||
|
||||
fail:
|
||||
bin_clear_free(msk, sizeof(*msk));
|
||||
os_free(sid);
|
||||
os_free(ckn);
|
||||
bin_clear_free(cak, sizeof(*cak));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct mka_key *cak;
|
||||
struct mka_key_name *ckn;
|
||||
void *res = NULL;
|
||||
|
||||
if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
|
||||
goto end;
|
||||
|
||||
ckn = os_zalloc(sizeof(*ckn));
|
||||
if (!ckn)
|
||||
goto end;
|
||||
|
||||
cak = os_zalloc(sizeof(*cak));
|
||||
if (!cak)
|
||||
goto free_ckn;
|
||||
|
||||
if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
|
||||
goto free_cak;
|
||||
|
||||
if (hapd->kay->policy == DO_NOT_SECURE)
|
||||
goto dealloc;
|
||||
|
||||
cak->len = hapd->conf->mka_cak_len;
|
||||
os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
|
||||
|
||||
ckn->len = hapd->conf->mka_ckn_len;;
|
||||
os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
|
||||
|
||||
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
|
||||
if (res)
|
||||
goto free_cak;
|
||||
|
||||
dealloc:
|
||||
/* Failed to create MKA */
|
||||
ieee802_1x_dealloc_kay_sm_hapd(hapd);
|
||||
free_cak:
|
||||
os_free(cak);
|
||||
free_ckn:
|
||||
os_free(ckn);
|
||||
end:
|
||||
return res;
|
||||
}
|
51
contrib/wpa/src/ap/wpa_auth_kay.h
Normal file
51
contrib/wpa/src/ap/wpa_auth_kay.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* IEEE 802.1X-2010 KaY Interface
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_AUTH_KAY_H
|
||||
#define WPA_AUTH_KAY_H
|
||||
|
||||
#ifdef CONFIG_MACSEC
|
||||
|
||||
int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd);
|
||||
|
||||
void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
#else /* CONFIG_MACSEC */
|
||||
|
||||
static inline int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void *
|
||||
ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MACSEC */
|
||||
|
||||
#endif /* WPA_AUTH_KAY_H */
|
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,11 @@
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
struct crypto_ecdh;
|
||||
struct hostapd_ip_addr;
|
||||
struct dpp_global;
|
||||
|
||||
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
|
||||
#define DPP_TCP_PORT 7871
|
||||
|
||||
enum dpp_public_action_frame_type {
|
||||
DPP_PA_AUTHENTICATION_REQ = 0,
|
||||
@ -259,6 +261,22 @@ struct dpp_introduction {
|
||||
size_t pmk_len;
|
||||
};
|
||||
|
||||
struct dpp_relay_config {
|
||||
const struct hostapd_ip_addr *ipaddr;
|
||||
const u8 *pkhash;
|
||||
|
||||
void *cb_ctx;
|
||||
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
|
||||
size_t len);
|
||||
void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, int prot,
|
||||
struct wpabuf *buf);
|
||||
};
|
||||
|
||||
struct dpp_controller_config {
|
||||
const char *configurator_params;
|
||||
int tcp_port;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
enum dpp_test_behavior {
|
||||
DPP_TEST_DISABLED = 0,
|
||||
@ -497,7 +515,26 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
|
||||
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
|
||||
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
|
||||
char *buf, size_t buflen);
|
||||
struct dpp_global * dpp_global_init(void);
|
||||
int dpp_relay_add_controller(struct dpp_global *dpp,
|
||||
struct dpp_relay_config *config);
|
||||
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
|
||||
const u8 *buf, size_t len, unsigned int freq,
|
||||
const u8 *i_bootstrap, const u8 *r_bootstrap);
|
||||
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
|
||||
size_t data_len);
|
||||
int dpp_controller_start(struct dpp_global *dpp,
|
||||
struct dpp_controller_config *config);
|
||||
void dpp_controller_stop(struct dpp_global *dpp);
|
||||
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
|
||||
const struct hostapd_ip_addr *addr, int port);
|
||||
|
||||
struct dpp_global_config {
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
};
|
||||
|
||||
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
|
||||
void dpp_global_clear(struct dpp_global *dpp);
|
||||
void dpp_global_deinit(struct dpp_global *dpp);
|
||||
|
||||
|
215
contrib/wpa/src/common/dragonfly.c
Normal file
215
contrib/wpa/src/common/dragonfly.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Shared Dragonfly functionality
|
||||
* Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/const_time.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "dragonfly.h"
|
||||
|
||||
|
||||
int dragonfly_suitable_group(int group, int ecc_only)
|
||||
{
|
||||
/* Enforce REVmd rules on which SAE groups are suitable for production
|
||||
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
|
||||
* defined over a prime field whose prime is >= 256 bits. Furthermore,
|
||||
* ECC groups defined over a characteristic 2 finite field and ECC
|
||||
* groups with a co-factor greater than 1 are not suitable. Disable
|
||||
* groups that use Brainpool curves as well for now since they leak more
|
||||
* timing information due to the prime not being close to a power of
|
||||
* two. */
|
||||
return group == 19 || group == 20 || group == 21 ||
|
||||
(!ecc_only &&
|
||||
(group == 15 || group == 16 || group == 17 || group == 18));
|
||||
}
|
||||
|
||||
|
||||
unsigned int dragonfly_min_pwe_loop_iter(int group)
|
||||
{
|
||||
if (group == 22 || group == 23 || group == 24) {
|
||||
/* FFC groups for which pwd-value is likely to be >= p
|
||||
* frequently */
|
||||
return 40;
|
||||
}
|
||||
|
||||
if (group == 1 || group == 2 || group == 5 || group == 14 ||
|
||||
group == 15 || group == 16 || group == 17 || group == 18) {
|
||||
/* FFC groups that have prime that is close to a power of two */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Default to 40 (this covers most ECC groups) */
|
||||
return 40;
|
||||
}
|
||||
|
||||
|
||||
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
|
||||
struct crypto_bignum **qr,
|
||||
struct crypto_bignum **qnr)
|
||||
{
|
||||
*qr = *qnr = NULL;
|
||||
|
||||
while (!(*qr) || !(*qnr)) {
|
||||
struct crypto_bignum *tmp;
|
||||
int res;
|
||||
|
||||
tmp = crypto_bignum_init();
|
||||
if (!tmp || crypto_bignum_rand(tmp, prime) < 0) {
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
res = crypto_bignum_legendre(tmp, prime);
|
||||
if (res == 1 && !(*qr))
|
||||
*qr = tmp;
|
||||
else if (res == -1 && !(*qnr))
|
||||
*qnr = tmp;
|
||||
else
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
}
|
||||
|
||||
if (*qr && *qnr)
|
||||
return 0;
|
||||
crypto_bignum_deinit(*qr, 0);
|
||||
crypto_bignum_deinit(*qnr, 0);
|
||||
*qr = *qnr = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_bignum *
|
||||
dragonfly_get_rand_1_to_p_1(const struct crypto_bignum *prime)
|
||||
{
|
||||
struct crypto_bignum *tmp, *pm1, *one;
|
||||
|
||||
tmp = crypto_bignum_init();
|
||||
pm1 = crypto_bignum_init();
|
||||
one = crypto_bignum_init_set((const u8 *) "\x01", 1);
|
||||
if (!tmp || !pm1 || !one ||
|
||||
crypto_bignum_sub(prime, one, pm1) < 0 ||
|
||||
crypto_bignum_rand(tmp, pm1) < 0 ||
|
||||
crypto_bignum_add(tmp, one, tmp) < 0) {
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
crypto_bignum_deinit(pm1, 0);
|
||||
crypto_bignum_deinit(one, 0);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
|
||||
const u8 *qr, const u8 *qnr,
|
||||
const struct crypto_bignum *val)
|
||||
{
|
||||
struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
|
||||
int check, res = -1;
|
||||
u8 qr_or_qnr_bin[DRAGONFLY_MAX_ECC_PRIME_LEN];
|
||||
const struct crypto_bignum *prime;
|
||||
size_t prime_len;
|
||||
unsigned int mask;
|
||||
|
||||
prime = crypto_ec_get_prime(ec);
|
||||
prime_len = crypto_ec_prime_len(ec);
|
||||
|
||||
/*
|
||||
* Use a blinding technique to mask val while determining whether it is
|
||||
* a quadratic residue modulo p to avoid leaking timing information
|
||||
* while determining the Legendre symbol.
|
||||
*
|
||||
* v = val
|
||||
* r = a random number between 1 and p-1, inclusive
|
||||
* num = (v * r * r) modulo p
|
||||
*/
|
||||
r = dragonfly_get_rand_1_to_p_1(prime);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
num = crypto_bignum_init();
|
||||
if (!num ||
|
||||
crypto_bignum_mulmod(val, r, prime, num) < 0 ||
|
||||
crypto_bignum_mulmod(num, r, prime, num) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Need to minimize differences in handling different cases, so try to
|
||||
* avoid branches and timing differences.
|
||||
*
|
||||
* If r is odd:
|
||||
* num = (num * qr) module p
|
||||
* LGR(num, p) = 1 ==> quadratic residue
|
||||
* else:
|
||||
* num = (num * qnr) module p
|
||||
* LGR(num, p) = -1 ==> quadratic residue
|
||||
*
|
||||
* mask is set to !odd(r)
|
||||
*/
|
||||
mask = const_time_is_zero(crypto_bignum_is_odd(r));
|
||||
const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
|
||||
qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
|
||||
if (!qr_or_qnr ||
|
||||
crypto_bignum_mulmod(num, qr_or_qnr, prime, num) < 0)
|
||||
goto fail;
|
||||
/* branchless version of check = odd(r) ? 1 : -1, */
|
||||
check = const_time_select_int(mask, -1, 1);
|
||||
|
||||
/* Determine the Legendre symbol on the masked value */
|
||||
res = crypto_bignum_legendre(num, prime);
|
||||
if (res == -2) {
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
/* branchless version of res = res == check
|
||||
* (res is -1, 0, or 1; check is -1 or 1) */
|
||||
mask = const_time_eq(res, check);
|
||||
res = const_time_select_int(mask, 1, 0);
|
||||
fail:
|
||||
crypto_bignum_deinit(num, 1);
|
||||
crypto_bignum_deinit(r, 1);
|
||||
crypto_bignum_deinit(qr_or_qnr, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int dragonfly_get_rand_2_to_r_1(struct crypto_bignum *val,
|
||||
const struct crypto_bignum *order)
|
||||
{
|
||||
return crypto_bignum_rand(val, order) == 0 &&
|
||||
!crypto_bignum_is_zero(val) &&
|
||||
!crypto_bignum_is_one(val);
|
||||
}
|
||||
|
||||
|
||||
int dragonfly_generate_scalar(const struct crypto_bignum *order,
|
||||
struct crypto_bignum *_rand,
|
||||
struct crypto_bignum *_mask,
|
||||
struct crypto_bignum *scalar)
|
||||
{
|
||||
int count;
|
||||
|
||||
/* Select two random values rand,mask such that 1 < rand,mask < r and
|
||||
* rand + mask mod r > 1. */
|
||||
for (count = 0; count < 100; count++) {
|
||||
if (dragonfly_get_rand_2_to_r_1(_rand, order) &&
|
||||
dragonfly_get_rand_2_to_r_1(_mask, order) &&
|
||||
crypto_bignum_add(_rand, _mask, scalar) == 0 &&
|
||||
crypto_bignum_mod(scalar, order, scalar) == 0 &&
|
||||
!crypto_bignum_is_zero(scalar) &&
|
||||
!crypto_bignum_is_one(scalar))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This should not be reachable in practice if the random number
|
||||
* generation is working. */
|
||||
wpa_printf(MSG_INFO,
|
||||
"dragonfly: Unable to get randomness for own scalar");
|
||||
return -1;
|
||||
}
|
31
contrib/wpa/src/common/dragonfly.h
Normal file
31
contrib/wpa/src/common/dragonfly.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Shared Dragonfly functionality
|
||||
* Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DRAGONFLY_H
|
||||
#define DRAGONFLY_H
|
||||
|
||||
#define DRAGONFLY_MAX_ECC_PRIME_LEN 66
|
||||
|
||||
struct crypto_bignum;
|
||||
struct crypto_ec;
|
||||
|
||||
int dragonfly_suitable_group(int group, int ecc_only);
|
||||
unsigned int dragonfly_min_pwe_loop_iter(int group);
|
||||
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
|
||||
struct crypto_bignum **qr,
|
||||
struct crypto_bignum **qnr);
|
||||
int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
|
||||
const u8 *qr, const u8 *qnr,
|
||||
const struct crypto_bignum *val);
|
||||
int dragonfly_generate_scalar(const struct crypto_bignum *order,
|
||||
struct crypto_bignum *_rand,
|
||||
struct crypto_bignum *_mask,
|
||||
struct crypto_bignum *scalar);
|
||||
|
||||
#endif /* DRAGONFLY_H */
|
@ -361,30 +361,35 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int ht_enabled,
|
||||
int vht_enabled, int sec_channel_offset,
|
||||
int vht_oper_chwidth, int center_segment0,
|
||||
int center_segment1, u32 vht_caps)
|
||||
int vht_enabled, int he_enabled,
|
||||
int sec_channel_offset,
|
||||
int oper_chwidth, int center_segment0,
|
||||
int center_segment1, u32 vht_caps,
|
||||
struct he_capabilities *he_cap)
|
||||
{
|
||||
if (!he_cap)
|
||||
he_enabled = 0;
|
||||
os_memset(data, 0, sizeof(*data));
|
||||
data->mode = mode;
|
||||
data->freq = freq;
|
||||
data->channel = channel;
|
||||
data->ht_enabled = ht_enabled;
|
||||
data->vht_enabled = vht_enabled;
|
||||
data->he_enabled = he_enabled;
|
||||
data->sec_channel_offset = sec_channel_offset;
|
||||
data->center_freq1 = freq + sec_channel_offset * 10;
|
||||
data->center_freq2 = 0;
|
||||
data->bandwidth = sec_channel_offset ? 40 : 20;
|
||||
|
||||
if (data->vht_enabled) switch (vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
if (data->vht_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (center_segment1 ||
|
||||
(center_segment0 != 0 &&
|
||||
5000 + center_segment0 * 5 != data->center_freq1 &&
|
||||
2407 + center_segment0 * 5 != data->center_freq1))
|
||||
return -1;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 channel width is not supported!");
|
||||
@ -395,11 +400,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
data->center_freq2 = 5000 + center_segment1 * 5;
|
||||
/* fall through */
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_80MHZ:
|
||||
data->bandwidth = 80;
|
||||
if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
|
||||
if ((oper_chwidth == CHANWIDTH_80MHZ &&
|
||||
center_segment1) ||
|
||||
(vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
|
||||
(oper_chwidth == CHANWIDTH_80P80MHZ &&
|
||||
!center_segment1) ||
|
||||
!sec_channel_offset)
|
||||
return -1;
|
||||
@ -432,7 +437,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
data->bandwidth = 160;
|
||||
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
|
||||
|
@ -32,9 +32,11 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
enum hostapd_hw_mode mode,
|
||||
int freq, int channel, int ht_enabled,
|
||||
int vht_enabled, int sec_channel_offset,
|
||||
int vht_oper_chwidth, int center_segment0,
|
||||
int center_segment1, u32 vht_caps);
|
||||
int vht_enabled, int he_enabled,
|
||||
int sec_channel_offset,
|
||||
int oper_chwidth, int center_segment0,
|
||||
int center_segment1, u32 vht_caps,
|
||||
struct he_capabilities *he_caps);
|
||||
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
|
||||
int disabled);
|
||||
int ieee80211ac_cap_check(u32 hw, u32 conf);
|
||||
|
@ -274,6 +274,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
elems->he_capabilities = pos;
|
||||
elems->he_capabilities_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_HE_OPERATION:
|
||||
elems->he_operation = pos;
|
||||
elems->he_operation_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_OCV_OCI:
|
||||
elems->oci = pos;
|
||||
elems->oci_len = elen;
|
||||
@ -702,7 +706,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
{
|
||||
u8 op_class;
|
||||
|
||||
return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
|
||||
return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
|
||||
&op_class, channel);
|
||||
}
|
||||
|
||||
@ -712,7 +716,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
* for HT40 and VHT. DFS channels are not covered.
|
||||
* @freq: Frequency (MHz) to convert
|
||||
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
|
||||
* @vht: VHT channel width (VHT_CHANWIDTH_*)
|
||||
* @vht: VHT channel width (CHANWIDTH_*)
|
||||
* @op_class: Buffer for returning operating class
|
||||
* @channel: Buffer for returning channel number
|
||||
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
|
||||
@ -767,13 +771,13 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
}
|
||||
|
||||
switch (vht) {
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
case CHANWIDTH_80MHZ:
|
||||
vht_opclass = 128;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
case CHANWIDTH_160MHZ:
|
||||
vht_opclass = 129;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
vht_opclass = 130;
|
||||
break;
|
||||
default:
|
||||
@ -892,16 +896,16 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
case CHAN_WIDTH_20:
|
||||
case CHAN_WIDTH_40:
|
||||
vht = VHT_CHANWIDTH_USE_HT;
|
||||
vht = CHANWIDTH_USE_HT;
|
||||
break;
|
||||
case CHAN_WIDTH_80:
|
||||
vht = VHT_CHANWIDTH_80MHZ;
|
||||
vht = CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_80P80:
|
||||
vht = VHT_CHANWIDTH_80P80MHZ;
|
||||
vht = CHANWIDTH_80P80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
vht = VHT_CHANWIDTH_160MHZ;
|
||||
vht = CHANWIDTH_160MHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1315,6 +1319,185 @@ const char * fc2str(u16 fc)
|
||||
}
|
||||
|
||||
|
||||
const char * reason2str(u16 reason)
|
||||
{
|
||||
#define R2S(r) case WLAN_REASON_ ## r: return #r;
|
||||
switch (reason) {
|
||||
R2S(UNSPECIFIED)
|
||||
R2S(PREV_AUTH_NOT_VALID)
|
||||
R2S(DEAUTH_LEAVING)
|
||||
R2S(DISASSOC_DUE_TO_INACTIVITY)
|
||||
R2S(DISASSOC_AP_BUSY)
|
||||
R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
|
||||
R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
|
||||
R2S(DISASSOC_STA_HAS_LEFT)
|
||||
R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
|
||||
R2S(PWR_CAPABILITY_NOT_VALID)
|
||||
R2S(SUPPORTED_CHANNEL_NOT_VALID)
|
||||
R2S(BSS_TRANSITION_DISASSOC)
|
||||
R2S(INVALID_IE)
|
||||
R2S(MICHAEL_MIC_FAILURE)
|
||||
R2S(4WAY_HANDSHAKE_TIMEOUT)
|
||||
R2S(GROUP_KEY_UPDATE_TIMEOUT)
|
||||
R2S(IE_IN_4WAY_DIFFERS)
|
||||
R2S(GROUP_CIPHER_NOT_VALID)
|
||||
R2S(PAIRWISE_CIPHER_NOT_VALID)
|
||||
R2S(AKMP_NOT_VALID)
|
||||
R2S(UNSUPPORTED_RSN_IE_VERSION)
|
||||
R2S(INVALID_RSN_IE_CAPAB)
|
||||
R2S(IEEE_802_1X_AUTH_FAILED)
|
||||
R2S(CIPHER_SUITE_REJECTED)
|
||||
R2S(TDLS_TEARDOWN_UNREACHABLE)
|
||||
R2S(TDLS_TEARDOWN_UNSPECIFIED)
|
||||
R2S(SSP_REQUESTED_DISASSOC)
|
||||
R2S(NO_SSP_ROAMING_AGREEMENT)
|
||||
R2S(BAD_CIPHER_OR_AKM)
|
||||
R2S(NOT_AUTHORIZED_THIS_LOCATION)
|
||||
R2S(SERVICE_CHANGE_PRECLUDES_TS)
|
||||
R2S(UNSPECIFIED_QOS_REASON)
|
||||
R2S(NOT_ENOUGH_BANDWIDTH)
|
||||
R2S(DISASSOC_LOW_ACK)
|
||||
R2S(EXCEEDED_TXOP)
|
||||
R2S(STA_LEAVING)
|
||||
R2S(END_TS_BA_DLS)
|
||||
R2S(UNKNOWN_TS_BA)
|
||||
R2S(TIMEOUT)
|
||||
R2S(PEERKEY_MISMATCH)
|
||||
R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
|
||||
R2S(EXTERNAL_SERVICE_REQUIREMENTS)
|
||||
R2S(INVALID_FT_ACTION_FRAME_COUNT)
|
||||
R2S(INVALID_PMKID)
|
||||
R2S(INVALID_MDE)
|
||||
R2S(INVALID_FTE)
|
||||
R2S(MESH_PEERING_CANCELLED)
|
||||
R2S(MESH_MAX_PEERS)
|
||||
R2S(MESH_CONFIG_POLICY_VIOLATION)
|
||||
R2S(MESH_CLOSE_RCVD)
|
||||
R2S(MESH_MAX_RETRIES)
|
||||
R2S(MESH_CONFIRM_TIMEOUT)
|
||||
R2S(MESH_INVALID_GTK)
|
||||
R2S(MESH_INCONSISTENT_PARAMS)
|
||||
R2S(MESH_INVALID_SECURITY_CAP)
|
||||
R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
|
||||
R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
|
||||
R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
|
||||
R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
|
||||
R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
|
||||
R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
|
||||
}
|
||||
return "UNKNOWN";
|
||||
#undef R2S
|
||||
}
|
||||
|
||||
|
||||
const char * status2str(u16 status)
|
||||
{
|
||||
#define S2S(s) case WLAN_STATUS_ ## s: return #s;
|
||||
switch (status) {
|
||||
S2S(SUCCESS)
|
||||
S2S(UNSPECIFIED_FAILURE)
|
||||
S2S(TDLS_WAKEUP_ALTERNATE)
|
||||
S2S(TDLS_WAKEUP_REJECT)
|
||||
S2S(SECURITY_DISABLED)
|
||||
S2S(UNACCEPTABLE_LIFETIME)
|
||||
S2S(NOT_IN_SAME_BSS)
|
||||
S2S(CAPS_UNSUPPORTED)
|
||||
S2S(REASSOC_NO_ASSOC)
|
||||
S2S(ASSOC_DENIED_UNSPEC)
|
||||
S2S(NOT_SUPPORTED_AUTH_ALG)
|
||||
S2S(UNKNOWN_AUTH_TRANSACTION)
|
||||
S2S(CHALLENGE_FAIL)
|
||||
S2S(AUTH_TIMEOUT)
|
||||
S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
|
||||
S2S(ASSOC_DENIED_RATES)
|
||||
S2S(ASSOC_DENIED_NOSHORT)
|
||||
S2S(SPEC_MGMT_REQUIRED)
|
||||
S2S(PWR_CAPABILITY_NOT_VALID)
|
||||
S2S(SUPPORTED_CHANNEL_NOT_VALID)
|
||||
S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
|
||||
S2S(ASSOC_DENIED_NO_HT)
|
||||
S2S(R0KH_UNREACHABLE)
|
||||
S2S(ASSOC_DENIED_NO_PCO)
|
||||
S2S(ASSOC_REJECTED_TEMPORARILY)
|
||||
S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
|
||||
S2S(UNSPECIFIED_QOS_FAILURE)
|
||||
S2S(DENIED_INSUFFICIENT_BANDWIDTH)
|
||||
S2S(DENIED_POOR_CHANNEL_CONDITIONS)
|
||||
S2S(DENIED_QOS_NOT_SUPPORTED)
|
||||
S2S(REQUEST_DECLINED)
|
||||
S2S(INVALID_PARAMETERS)
|
||||
S2S(REJECTED_WITH_SUGGESTED_CHANGES)
|
||||
S2S(INVALID_IE)
|
||||
S2S(GROUP_CIPHER_NOT_VALID)
|
||||
S2S(PAIRWISE_CIPHER_NOT_VALID)
|
||||
S2S(AKMP_NOT_VALID)
|
||||
S2S(UNSUPPORTED_RSN_IE_VERSION)
|
||||
S2S(INVALID_RSN_IE_CAPAB)
|
||||
S2S(CIPHER_REJECTED_PER_POLICY)
|
||||
S2S(TS_NOT_CREATED)
|
||||
S2S(DIRECT_LINK_NOT_ALLOWED)
|
||||
S2S(DEST_STA_NOT_PRESENT)
|
||||
S2S(DEST_STA_NOT_QOS_STA)
|
||||
S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
|
||||
S2S(INVALID_FT_ACTION_FRAME_COUNT)
|
||||
S2S(INVALID_PMKID)
|
||||
S2S(INVALID_MDIE)
|
||||
S2S(INVALID_FTIE)
|
||||
S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
|
||||
S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
|
||||
S2S(TRY_ANOTHER_BSS)
|
||||
S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
|
||||
S2S(NO_OUTSTANDING_GAS_REQ)
|
||||
S2S(GAS_RESP_NOT_RECEIVED)
|
||||
S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
|
||||
S2S(GAS_RESP_LARGER_THAN_LIMIT)
|
||||
S2S(REQ_REFUSED_HOME)
|
||||
S2S(ADV_SRV_UNREACHABLE)
|
||||
S2S(REQ_REFUSED_SSPN)
|
||||
S2S(REQ_REFUSED_UNAUTH_ACCESS)
|
||||
S2S(INVALID_RSNIE)
|
||||
S2S(U_APSD_COEX_NOT_SUPPORTED)
|
||||
S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
|
||||
S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
|
||||
S2S(ANTI_CLOGGING_TOKEN_REQ)
|
||||
S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
|
||||
S2S(CANNOT_FIND_ALT_TBTT)
|
||||
S2S(TRANSMISSION_FAILURE)
|
||||
S2S(REQ_TCLAS_NOT_SUPPORTED)
|
||||
S2S(TCLAS_RESOURCES_EXCHAUSTED)
|
||||
S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
|
||||
S2S(REJECT_WITH_SCHEDULE)
|
||||
S2S(REJECT_NO_WAKEUP_SPECIFIED)
|
||||
S2S(SUCCESS_POWER_SAVE_MODE)
|
||||
S2S(PENDING_ADMITTING_FST_SESSION)
|
||||
S2S(PERFORMING_FST_NOW)
|
||||
S2S(PENDING_GAP_IN_BA_WINDOW)
|
||||
S2S(REJECT_U_PID_SETTING)
|
||||
S2S(REFUSED_EXTERNAL_REASON)
|
||||
S2S(REFUSED_AP_OUT_OF_MEMORY)
|
||||
S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
|
||||
S2S(QUERY_RESP_OUTSTANDING)
|
||||
S2S(REJECT_DSE_BAND)
|
||||
S2S(TCLAS_PROCESSING_TERMINATED)
|
||||
S2S(TS_SCHEDULE_CONFLICT)
|
||||
S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
|
||||
S2S(MCCAOP_RESERVATION_CONFLICT)
|
||||
S2S(MAF_LIMIT_EXCEEDED)
|
||||
S2S(MCCA_TRACK_LIMIT_EXCEEDED)
|
||||
S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
|
||||
S2S(ASSOC_DENIED_NO_VHT)
|
||||
S2S(ENABLEMENT_DENIED)
|
||||
S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
|
||||
S2S(AUTHORIZATION_DEENABLED)
|
||||
S2S(FILS_AUTHENTICATION_FAILURE)
|
||||
S2S(UNKNOWN_AUTHENTICATION_SERVER)
|
||||
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
|
||||
}
|
||||
return "UNKNOWN";
|
||||
#undef S2S
|
||||
}
|
||||
|
||||
|
||||
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
size_t ies_len)
|
||||
{
|
||||
|
@ -94,6 +94,7 @@ struct ieee802_11_elems {
|
||||
const u8 *oci;
|
||||
const u8 *multi_ap;
|
||||
const u8 *he_capabilities;
|
||||
const u8 *he_operation;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
@ -143,6 +144,7 @@ struct ieee802_11_elems {
|
||||
u8 oci_len;
|
||||
u8 multi_ap_len;
|
||||
u8 he_capabilities_len;
|
||||
u8 he_operation_len;
|
||||
|
||||
struct mb_ies_info mb_ies;
|
||||
};
|
||||
@ -185,6 +187,8 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
|
||||
|
||||
const char * fc2str(u16 fc);
|
||||
const char * reason2str(u16 reason);
|
||||
const char * status2str(u16 status);
|
||||
|
||||
struct oper_class_map {
|
||||
enum hostapd_hw_mode mode;
|
||||
|
@ -468,6 +468,7 @@
|
||||
#define WLAN_EID_EXT_HE_CAPABILITIES 35
|
||||
#define WLAN_EID_EXT_HE_OPERATION 36
|
||||
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
|
||||
#define WLAN_EID_EXT_SPATIAL_REUSE 39
|
||||
#define WLAN_EID_EXT_OCV_OCI 54
|
||||
|
||||
/* Extended Capabilities field */
|
||||
@ -1274,10 +1275,12 @@ struct ieee80211_ampe_ie {
|
||||
#define VHT_RX_NSS_MAX_STREAMS 8
|
||||
|
||||
/* VHT channel widths */
|
||||
#define VHT_CHANWIDTH_USE_HT 0
|
||||
#define VHT_CHANWIDTH_80MHZ 1
|
||||
#define VHT_CHANWIDTH_160MHZ 2
|
||||
#define VHT_CHANWIDTH_80P80MHZ 3
|
||||
#define CHANWIDTH_USE_HT 0
|
||||
#define CHANWIDTH_80MHZ 1
|
||||
#define CHANWIDTH_160MHZ 2
|
||||
#define CHANWIDTH_80P80MHZ 3
|
||||
|
||||
#define HE_NSS_MAX_STREAMS 8
|
||||
|
||||
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
|
||||
* 00:50:F2 */
|
||||
@ -2091,7 +2094,7 @@ enum phy_type {
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
|
||||
* subfields.
|
||||
* Note: These definitions are not the same as other VHT_CHANWIDTH_*.
|
||||
* Note: These definitions are not the same as other CHANWIDTH_*.
|
||||
*/
|
||||
enum nr_chan_width {
|
||||
NR_CHAN_WIDTH_20 = 0,
|
||||
@ -2104,21 +2107,46 @@ enum nr_chan_width {
|
||||
struct ieee80211_he_capabilities {
|
||||
u8 he_mac_capab_info[6];
|
||||
u8 he_phy_capab_info[11];
|
||||
u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
|
||||
/* PPE Thresholds (optional) */
|
||||
/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
|
||||
* and optional variable length PPE Thresholds field. */
|
||||
u8 optional[];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct ieee80211_he_operation {
|
||||
u32 he_oper_params; /* HE Operation Parameters[3] and
|
||||
* BSS Color Information[1] */
|
||||
u8 he_mcs_nss_set[2];
|
||||
le32 he_oper_params; /* HE Operation Parameters[3] and
|
||||
* BSS Color Information[1] */
|
||||
le16 he_mcs_nss_set;
|
||||
u8 vht_op_info_chwidth;
|
||||
u8 vht_op_info_chan_center_freq_seg0_idx;
|
||||
u8 vht_op_info_chan_center_freq_seg1_idx;
|
||||
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/*
|
||||
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
|
||||
*/
|
||||
struct ieee80211_spatial_reuse {
|
||||
u8 sr_ctrl; /* SR Control */
|
||||
/* Up to 19 octets of parameters:
|
||||
* Non-SRG OBSS PD Max Offset[0 or 1]
|
||||
* SRG OBSS PD Min Offset[0 or 1]
|
||||
* SRG OBSS PD Max Offset[0 or 1]
|
||||
* SRG BSS Color Bitmap[0 or 8]
|
||||
* SRG Partial BSSID Bitmap[0 or 8]
|
||||
*/
|
||||
u8 params[19];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* HE Capabilities Information defines */
|
||||
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
|
||||
BIT(3) | BIT(4)))
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G ((u8) BIT(1))
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G ((u8) BIT(2))
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G ((u8) BIT(3))
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G ((u8) BIT(4))
|
||||
|
||||
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
|
||||
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
|
||||
#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
|
||||
@ -2126,23 +2154,39 @@ struct ieee80211_he_operation {
|
||||
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
|
||||
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
|
||||
|
||||
#define HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 6
|
||||
#define HE_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(7))
|
||||
|
||||
/* HE PPE Threshold define */
|
||||
#define HE_PPE_THRES_RU_INDEX_BITMASK_MASK 0xf
|
||||
#define HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT 3
|
||||
#define HE_PPE_THRES_NSS_MASK 0x7
|
||||
|
||||
/* HE Operation defines */
|
||||
/* HE Operation Parameters and BSS Color Information fields */
|
||||
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
|
||||
BIT(2) | BIT(3) | \
|
||||
BIT(4) | BIT(5)))
|
||||
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(6))
|
||||
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(7))
|
||||
#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(8) | BIT(9) | \
|
||||
BIT(10)))
|
||||
#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 8
|
||||
#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(11))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(12) | BIT(13) | \
|
||||
BIT(14) | BIT(15) | \
|
||||
BIT(16) | BIT(17) | \
|
||||
BIT(18) | BIT(19) | \
|
||||
BIT(20) | BIT(21)))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
|
||||
#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(0) | BIT(1) | \
|
||||
BIT(2)))
|
||||
#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 0
|
||||
#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(3))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(4) | BIT(5) | \
|
||||
BIT(6) | BIT(7) | \
|
||||
BIT(8) | BIT(9) | \
|
||||
BIT(10) | BIT(11) | \
|
||||
BIT(12) | BIT(13)))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
|
||||
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
|
||||
BIT(26) | BIT(27) | \
|
||||
BIT(28) | BIT(29)))
|
||||
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
|
||||
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
|
||||
#define HE_OPERATION_BSS_COLOR_OFFSET 24
|
||||
|
||||
/* Spatial Reuse defines */
|
||||
#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
|
||||
#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
|
||||
#define SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT BIT(2)
|
||||
#define SPATIAL_REUSE_SRG_INFORMATION_PRESENT BIT(3)
|
||||
#define SPATIAL_REUSE_HESIGA_SR_VAL15_ALLOWED BIT(4)
|
||||
|
||||
struct ieee80211_he_mu_edca_parameter_set {
|
||||
u8 he_qos_info;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Qualcomm Atheros OUI and vendor specific assignments
|
||||
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation
|
||||
* Copyright (c) 2018-2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -98,6 +98,9 @@ enum qca_radiotap_vendor_ids {
|
||||
* which supports DFS offloading, to indicate a radar pattern has been
|
||||
* detected. The channel is now unusable.
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: Get information from the driver.
|
||||
* Attributes defined in enum qca_wlan_vendor_attr_get_wifi_info.
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap
|
||||
* based on enum wifi_logger_supported_features. Attributes defined in
|
||||
* enum qca_wlan_vendor_attr_get_logger_features.
|
||||
@ -373,7 +376,9 @@ enum qca_radiotap_vendor_ids {
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START: Start spectral scan. The scan
|
||||
* parameters are specified by enum qca_wlan_vendor_attr_spectral_scan.
|
||||
* This returns a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE)
|
||||
* identifying the operation in success case.
|
||||
* identifying the operation in success case. In failure cases an
|
||||
* error code (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE)
|
||||
* describing the reason for the failure is returned.
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP: Stop spectral scan. This uses
|
||||
* a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE) from
|
||||
@ -524,6 +529,65 @@ enum qca_radiotap_vendor_ids {
|
||||
* parameters including Zigbee state and specific WLAN periods to enhance
|
||||
* PTA master. All these parameters are delivered by the attributes
|
||||
* defined in enum qca_mpta_helper_vendor_attr.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING: This sub command is used to
|
||||
* implement Beacon frame reporting feature.
|
||||
*
|
||||
* Userspace can request the driver/firmware to periodically report
|
||||
* received Beacon frames whose BSSID is same as the current connected
|
||||
* BSS's MAC address.
|
||||
*
|
||||
* In case the STA seamlessly (without sending disconnect indication to
|
||||
* userspace) roams to a different BSS, Beacon frame reporting will be
|
||||
* automatically enabled for the Beacon frames whose BSSID is same as the
|
||||
* MAC address of the new BSS. Beacon reporting will be stopped when the
|
||||
* STA is disconnected (when the disconnect indication is sent to
|
||||
* userspace) and need to be explicitly enabled by userspace for next
|
||||
* connection.
|
||||
*
|
||||
* When a Beacon frame matching configured conditions is received, and if
|
||||
* userspace has requested to send asynchronous beacon reports, the
|
||||
* driver/firmware will encapsulate the details of the Beacon frame in an
|
||||
* event and send it to userspace along with updating the BSS information
|
||||
* in cfg80211 scan cache, otherwise driver will only update the cfg80211
|
||||
* scan cache with the information from the received Beacon frame but will
|
||||
* not send any active report to userspace.
|
||||
*
|
||||
* The userspace can request the driver/firmware to stop reporting Beacon
|
||||
* frames. If the driver/firmware is not able to receive Beacon frames due
|
||||
* to other Wi-Fi operations such as off-channel activities, etc., the
|
||||
* driver/firmware will send a pause event to userspace and stop reporting
|
||||
* Beacon frames. Whether the beacon reporting will be automatically
|
||||
* resumed or not by the driver/firmware later will be reported to
|
||||
* userspace using the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
|
||||
* flag. The beacon reporting shall be resumed for all the cases except
|
||||
* either when userspace sets
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME flag in the command
|
||||
* which triggered the current beacon reporting or during any disconnection
|
||||
* case as indicated by setting
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED by the
|
||||
* driver.
|
||||
*
|
||||
* After QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_PAUSE event is received
|
||||
* by userspace with QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
|
||||
* flag not set, the next first
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO event from the driver
|
||||
* shall be considered as un-pause event.
|
||||
*
|
||||
* All the attributes used with this command are defined in
|
||||
* enum qca_wlan_vendor_attr_beacon_reporting_params.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP: In practice, some APs have
|
||||
* interop issues with the DUT. This sub command is used to transfer the
|
||||
* AP info between the driver and user space. This works both as a command
|
||||
* and an event. As a command, it configures the stored list of APs from
|
||||
* user space to firmware; as an event, it indicates the AP info detected
|
||||
* by the firmware to user space for persistent storage. The attributes
|
||||
* defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
|
||||
* the parameters.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command is used to send OEM data
|
||||
* binary blobs from application/service to firmware. The attributes
|
||||
* defined in enum qca_wlan_vendor_attr_oem_data_params are used to deliver
|
||||
* the parameters.
|
||||
*/
|
||||
enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
||||
@ -692,6 +756,9 @@ enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE = 177,
|
||||
QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH = 178,
|
||||
QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
|
||||
QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
|
||||
QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
|
||||
};
|
||||
|
||||
enum qca_wlan_vendor_attr {
|
||||
@ -1788,6 +1855,30 @@ enum qca_wlan_vendor_attr_config {
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
|
||||
|
||||
/* Attribute to configure disconnect IEs to the driver.
|
||||
* This carries an array of unsigned 8-bit characters.
|
||||
*
|
||||
* If this is configured, driver shall fill the IEs in disassoc/deauth
|
||||
* frame.
|
||||
* These IEs are expected to be considered only for the next
|
||||
* immediate disconnection (disassoc/deauth frame) originated by
|
||||
* the DUT, irrespective of the entity (user space/driver/firmware)
|
||||
* triggering the disconnection.
|
||||
* The host drivers are not expected to use the IEs set through
|
||||
* this interface for further disconnections after the first immediate
|
||||
* disconnection initiated post the configuration.
|
||||
* If the IEs are also updated through cfg80211 interface (after the
|
||||
* enhancement to cfg80211_disconnect), host driver is expected to
|
||||
* take the union of IEs from both of these interfaces and send in
|
||||
* further disassoc/deauth frames.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
|
||||
|
||||
/* 8-bit unsigned value for ELNA bypass.
|
||||
* 1-Enable, 0-Disable
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
|
||||
@ -3204,11 +3295,28 @@ enum qca_vendor_attr_sar_limits {
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
|
||||
* QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION: In a request this attribute
|
||||
* should be set to any U8 value to indicate that the driver version
|
||||
* should be returned. When enabled in this manner, in a response this
|
||||
* attribute will contain a string representation of the driver version.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION: In a request this attribute
|
||||
* should be set to any U8 value to indicate that the firmware version
|
||||
* should be returned. When enabled in this manner, in a response this
|
||||
* attribute will contain a string representation of the firmware version.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX: In a request this attribute
|
||||
* should be set to any U32 value to indicate that the current radio
|
||||
* index should be returned. When enabled in this manner, in a response
|
||||
* this attribute will contain a U32 radio index value.
|
||||
*
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_get_wifi_info {
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX = 3,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
|
||||
@ -4481,6 +4589,44 @@ enum qca_wlan_vendor_attr_spectral_scan {
|
||||
* qca_wlan_vendor_attr_spectral_scan_request_type.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
|
||||
/* This specifies the frequency span over which spectral
|
||||
* scan would be carried out. Its value depends on the
|
||||
* value of QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE and
|
||||
* the relation is as follows.
|
||||
* QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL
|
||||
* Not applicable. Spectral scan would happen in the
|
||||
* operating span.
|
||||
* QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
|
||||
* Center frequency (in MHz) of the span of interest or
|
||||
* for convenience, center frequency (in MHz) of any channel
|
||||
* in the span of interest. If agile spectral scan is initiated
|
||||
* without setting a valid frequency it returns the error code
|
||||
* (QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED).
|
||||
* u32 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY = 24,
|
||||
/* Spectral scan mode. u32 attribute.
|
||||
* It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
|
||||
* If this attribute is not present, it is assumed to be
|
||||
* normal mode (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL).
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE = 25,
|
||||
/* Spectral scan error code. u32 attribute.
|
||||
* It uses values defined in enum
|
||||
* qca_wlan_vendor_spectral_scan_error_code.
|
||||
* This attribute is included only in failure scenarios.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE = 26,
|
||||
/* 8-bit unsigned value to enable/disable debug of the
|
||||
* Spectral DMA ring.
|
||||
* 1-enable, 0-disable
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_RING_DEBUG = 27,
|
||||
/* 8-bit unsigned value to enable/disable debug of the
|
||||
* Spectral DMA buffers.
|
||||
* 1-enable, 0-disable
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_BUFFER_DEBUG = 28,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
|
||||
@ -4559,6 +4705,8 @@ enum qca_wlan_vendor_attr_spectral_cap {
|
||||
* u8 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
|
||||
/* Flag attribute to indicate agile spectral scan capability */
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
|
||||
@ -4575,6 +4723,13 @@ enum qca_wlan_vendor_attr_spectral_scan_status {
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED = 1,
|
||||
/* Flag attribute to indicate whether spectral scan is in progress*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE = 2,
|
||||
/* Spectral scan mode. u32 attribute.
|
||||
* It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
|
||||
* If this attribute is not present, normal mode
|
||||
* (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL is assumed to be
|
||||
* requested.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE = 3,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
|
||||
@ -4599,6 +4754,43 @@ enum qca_wlan_vendor_attr_spectral_scan_request_type {
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG,
|
||||
};
|
||||
|
||||
/**
|
||||
* qca_wlan_vendor_spectral_scan_mode: Attribute values for
|
||||
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE in the vendor subcmd
|
||||
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START and
|
||||
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE in the vendor subcmd
|
||||
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS. This represents the
|
||||
* spectral scan modes.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL: Normal spectral scan:
|
||||
* spectral scan in the current operating span.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE: Agile spectral scan:
|
||||
* spectral scan in the configured agile span.
|
||||
*/
|
||||
enum qca_wlan_vendor_spectral_scan_mode {
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL = 0,
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* qca_wlan_vendor_spectral_scan_error_code: Attribute values for
|
||||
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE in the vendor subcmd
|
||||
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED: Changing the value
|
||||
* of a parameter is not supported.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED: Requested spectral scan
|
||||
* mode is not supported.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE: A parameter
|
||||
* has invalid value.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED: A parameter
|
||||
* is not initialized.
|
||||
*/
|
||||
enum qca_wlan_vendor_spectral_scan_error_code {
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED = 0,
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED = 1,
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE = 2,
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* qca_wlan_vendor_spectral_scan_cap_hw_gen: Attribute values for
|
||||
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN to the vendor subcmd
|
||||
@ -6709,4 +6901,251 @@ enum qca_mpta_helper_vendor_attr {
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_beacon_reporting_op_types - Defines different types of
|
||||
* operations for which %QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING can be used.
|
||||
* Will be used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: Sent by userspace to the driver
|
||||
* to request the driver to start reporting Beacon frames.
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: Sent by userspace to the driver to
|
||||
* request the driver to stop reporting Beacon frames.
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO: Sent by the driver to
|
||||
* userspace to report received Beacon frames.
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE: Sent by the driver to userspace
|
||||
* to indicate that the driver is going to pause reporting Beacon frames.
|
||||
*/
|
||||
enum qca_wlan_vendor_beacon_reporting_op_types {
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START = 0,
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP = 1,
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO = 2,
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_beacon_reporting_pause_reasons - Defines different types
|
||||
* of reasons for which the driver is pausing reporting Beacon frames. Will be
|
||||
* used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED: For unspecified
|
||||
* reasons.
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED: When the
|
||||
* driver/firmware is starting a scan.
|
||||
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED: When the
|
||||
* driver/firmware disconnects from the ESS and indicates the disconnection to
|
||||
* userspace (non-seamless roaming case). This reason code will be used by the
|
||||
* driver/firmware to indicate stopping of beacon report events. Userspace will
|
||||
* need to start beacon reporting again (if desired) by sending vendor command
|
||||
* QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING with
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START after the next connection is
|
||||
* completed.
|
||||
*/
|
||||
enum qca_wlan_vendor_beacon_reporting_pause_reasons {
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED = 0,
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED = 1,
|
||||
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* enum qca_wlan_vendor_attr_beacon_reporting_params - List of attributes used
|
||||
* in vendor sub-command QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_beacon_reporting_params {
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_INVALID = 0,
|
||||
/* Specifies the type of operation that the vendor command/event is
|
||||
* intended for. Possible values for this attribute are defined in
|
||||
* enum qca_wlan_vendor_beacon_reporting_op_types. u32 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE = 1,
|
||||
/* Optionally set by userspace to request the driver to report Beacon
|
||||
* frames using asynchronous vendor events when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
|
||||
* If this flag is not set, the driver will only update Beacon frames in
|
||||
* cfg80211 scan cache but not send any vendor events.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING = 2,
|
||||
/* Optionally used by userspace to request the driver/firmware to report
|
||||
* Beacon frames periodically when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START.
|
||||
* u32 attribute, indicates the period of Beacon frames to be reported
|
||||
* and in the units of beacon interval.
|
||||
* If this attribute is missing in the command, then the default value
|
||||
* of 1 will be assumed by driver, i.e., to report every Beacon frame.
|
||||
* Zero is an invalid value.
|
||||
* If a valid value is received for this attribute, the driver will
|
||||
* update the cfg80211 scan cache periodically as per the value received
|
||||
* in this attribute in addition to updating the cfg80211 scan cache
|
||||
* when there is significant change in Beacon frame IEs.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD = 3,
|
||||
/* Used by the driver to encapsulate the SSID when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
|
||||
* u8 array with a maximum size of 32.
|
||||
*
|
||||
* When generating beacon report from non-MBSSID Beacon frame, the SSID
|
||||
* will be taken from the SSID element of the received Beacon frame.
|
||||
*
|
||||
* When generating beacon report from Multiple BSSID Beacon frame and if
|
||||
* the BSSID of the current connected BSS matches the BSSID of the
|
||||
* transmitting BSS, the SSID will be taken from the SSID element of the
|
||||
* received Beacon frame.
|
||||
*
|
||||
* When generating beacon report from Multiple BSSID Beacon frame and if
|
||||
* the BSSID of the current connected BSS matches the BSSID of one of
|
||||
* the* nontransmitting BSSs, the SSID will be taken from the SSID field
|
||||
* included in the nontransmitted BSS profile whose derived BSSID is
|
||||
* same as the BSSID of the current connected BSS. When there is no
|
||||
* nontransmitted BSS profile whose derived BSSID is same as the BSSID
|
||||
* of current connected* BSS, this attribute will not be present.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID = 4,
|
||||
/* Used by the driver to encapsulate the BSSID of the AP to which STA is
|
||||
* currently connected to when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array with a
|
||||
* fixed size of 6 bytes.
|
||||
*
|
||||
* When generating beacon report from a Multiple BSSID beacon and the
|
||||
* current connected BSSID matches one of the nontransmitted BSSIDs in a
|
||||
* Multiple BSSID set, this BSSID will be that particular nontransmitted
|
||||
* BSSID and not the transmitted BSSID (i.e., the transmitting address
|
||||
* of the Beacon frame).
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID = 5,
|
||||
/* Used by the driver to encapsulate the frequency in MHz on which
|
||||
* the Beacon frame was received when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is
|
||||
* set to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
|
||||
* u32 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ = 6,
|
||||
/* Used by the driver to encapsulate the Beacon interval
|
||||
* when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
|
||||
* u16 attribute. The value will be copied from the Beacon frame and the
|
||||
* units are TUs.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI = 7,
|
||||
/* Used by the driver to encapsulate the Timestamp field from the Beacon
|
||||
* frame when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set
|
||||
* to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
|
||||
* u64 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF = 8,
|
||||
/* Used by the driver to encapsulate the CLOCK_BOOTTIME when this
|
||||
* Beacon frame is received in the driver when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u64 attribute, in
|
||||
* the units of nanoseconds. This value is expected to have accuracy of
|
||||
* about 10 ms.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED = 9,
|
||||
/* Used by the driver to encapsulate the IEs of the Beacon frame from
|
||||
* which this event is generated when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_IES = 10,
|
||||
/* Used by the driver to specify the reason for the driver/firmware to
|
||||
* pause sending beacons to userspace when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. Possible values are
|
||||
* defined in enum qca_wlan_vendor_beacon_reporting_pause_reasons, u32
|
||||
* attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON = 11,
|
||||
/* Used by the driver to specify whether the driver will automatically
|
||||
* resume reporting beacon events to userspace later (for example after
|
||||
* the ongoing off-channel activity is completed etc.) when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. NLA_FLAG attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES = 12,
|
||||
/* Optionally set by userspace to request the driver not to resume
|
||||
* beacon reporting after a pause is completed, when the
|
||||
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
|
||||
* If this flag is set, the driver will not resume beacon reporting
|
||||
* after any pause in beacon reporting is completed. Userspace has to
|
||||
* send QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command again in order
|
||||
* to initiate beacon reporting again. If this flag is set in the recent
|
||||
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the
|
||||
* subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any)
|
||||
* the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be
|
||||
* set by the driver. Setting this flag until and unless there is a
|
||||
* specific need is not recommended as there is a chance of some beacons
|
||||
* received after pause command and next start command being not
|
||||
* reported.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME = 13,
|
||||
|
||||
/* Keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_interop_issues_ap_type - Interop issue types
|
||||
* This enum defines the valid set of values of interop issue types. These
|
||||
* values are used by attribute %QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE.
|
||||
*
|
||||
* @QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS: The AP has power save interop issue
|
||||
* when the STA's Qpower feature is enabled.
|
||||
*/
|
||||
enum qca_vendor_interop_issues_ap_type {
|
||||
QCA_VENDOR_INTEROP_ISSUES_AP_INVALID = 0,
|
||||
QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_interop_issues_ap - attribute for AP with interop issues
|
||||
* Values are used by %QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID: Invalid value
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE: Interop issue type
|
||||
* 32-bit unsigned value. The values defined in enum
|
||||
* qca_vendor_interop_issues_ap_type are used.
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST: APs' BSSID container
|
||||
* array of nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID attributes.
|
||||
* It is present and mandatory for the command but is not used for the event
|
||||
* since only a single BSSID is reported in an event.
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID: AP's BSSID 6-byte MAC address.
|
||||
* It is used within the nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST
|
||||
* attribute in command case and without such encapsulation in the event case.
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST: last value
|
||||
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX: max value
|
||||
*/
|
||||
enum qca_vendor_attr_interop_issues_ap {
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID,
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE,
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST,
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/*
|
||||
* enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command
|
||||
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
|
||||
* command QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this attribute.
|
||||
* NLA_BINARY attribute, the max size is 1024 bytes.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_oem_data_params {
|
||||
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
|
||||
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
|
||||
};
|
||||
#endif /* QCA_VENDOR_H */
|
||||
|
@ -15,35 +15,22 @@
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/dh_groups.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "dragonfly.h"
|
||||
#include "sae.h"
|
||||
|
||||
|
||||
static int sae_suitable_group(int group)
|
||||
{
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
/* Allow all groups for testing purposes in non-production builds. */
|
||||
return 1;
|
||||
#else /* CONFIG_TESTING_OPTIONS */
|
||||
/* Enforce REVmd rules on which SAE groups are suitable for production
|
||||
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
|
||||
* defined over a prime field whose prime is >= 256 bits. Furthermore,
|
||||
* ECC groups defined over a characteristic 2 finite field and ECC
|
||||
* groups with a co-factor greater than 1 are not suitable. */
|
||||
return group == 19 || group == 20 || group == 21 ||
|
||||
group == 28 || group == 29 || group == 30 ||
|
||||
group == 15 || group == 16 || group == 17 || group == 18;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
}
|
||||
|
||||
|
||||
int sae_set_group(struct sae_data *sae, int group)
|
||||
{
|
||||
struct sae_temporary_data *tmp;
|
||||
|
||||
if (!sae_suitable_group(group)) {
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
/* Allow all groups for testing purposes in non-production builds. */
|
||||
#else /* CONFIG_TESTING_OPTIONS */
|
||||
if (!dragonfly_suitable_group(group, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
sae_clear_data(sae);
|
||||
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
|
||||
@ -58,6 +45,7 @@ int sae_set_group(struct sae_data *sae, int group)
|
||||
sae->group = group;
|
||||
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
|
||||
tmp->prime = crypto_ec_get_prime(tmp->ec);
|
||||
tmp->order_len = crypto_ec_order_len(tmp->ec);
|
||||
tmp->order = crypto_ec_get_order(tmp->ec);
|
||||
return 0;
|
||||
}
|
||||
@ -82,6 +70,7 @@ int sae_set_group(struct sae_data *sae, int group)
|
||||
}
|
||||
tmp->prime = tmp->prime_buf;
|
||||
|
||||
tmp->order_len = tmp->dh->order_len;
|
||||
tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
|
||||
tmp->dh->order_len);
|
||||
if (tmp->order_buf == NULL) {
|
||||
@ -134,58 +123,6 @@ void sae_clear_data(struct sae_data *sae)
|
||||
}
|
||||
|
||||
|
||||
static void buf_shift_right(u8 *buf, size_t len, size_t bits)
|
||||
{
|
||||
size_t i;
|
||||
for (i = len - 1; i > 0; i--)
|
||||
buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
|
||||
buf[0] >>= bits;
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
|
||||
{
|
||||
u8 val[SAE_MAX_PRIME_LEN];
|
||||
int iter = 0;
|
||||
struct crypto_bignum *bn = NULL;
|
||||
int order_len_bits = crypto_bignum_bits(sae->tmp->order);
|
||||
size_t order_len = (order_len_bits + 7) / 8;
|
||||
|
||||
if (order_len > sizeof(val))
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
|
||||
return NULL;
|
||||
if (order_len_bits % 8)
|
||||
buf_shift_right(val, order_len, 8 - order_len_bits % 8);
|
||||
bn = crypto_bignum_init_set(val, order_len);
|
||||
if (bn == NULL)
|
||||
return NULL;
|
||||
if (crypto_bignum_is_zero(bn) ||
|
||||
crypto_bignum_is_one(bn) ||
|
||||
crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
|
||||
crypto_bignum_deinit(bn, 0);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
os_memset(val, 0, order_len);
|
||||
return bn;
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
|
||||
{
|
||||
crypto_bignum_deinit(sae->tmp->sae_rand, 1);
|
||||
sae->tmp->sae_rand = sae_get_rand(sae);
|
||||
if (sae->tmp->sae_rand == NULL)
|
||||
return NULL;
|
||||
return sae_get_rand(sae);
|
||||
}
|
||||
|
||||
|
||||
static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
|
||||
@ -200,103 +137,6 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_bignum *
|
||||
get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
|
||||
int *r_odd)
|
||||
{
|
||||
for (;;) {
|
||||
struct crypto_bignum *r;
|
||||
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
|
||||
|
||||
if (random_get_bytes(tmp, prime_len) < 0)
|
||||
break;
|
||||
if (prime_bits % 8)
|
||||
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
|
||||
if (os_memcmp(tmp, prime, prime_len) >= 0)
|
||||
continue;
|
||||
r = crypto_bignum_init_set(tmp, prime_len);
|
||||
if (!r)
|
||||
break;
|
||||
if (crypto_bignum_is_zero(r)) {
|
||||
crypto_bignum_deinit(r, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
*r_odd = tmp[prime_len - 1] & 0x01;
|
||||
return r;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int is_quadratic_residue_blind(struct sae_data *sae,
|
||||
const u8 *prime, size_t bits,
|
||||
const u8 *qr, const u8 *qnr,
|
||||
const struct crypto_bignum *y_sqr)
|
||||
{
|
||||
struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
|
||||
int r_odd, check, res = -1;
|
||||
u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN];
|
||||
size_t prime_len = sae->tmp->prime_len;
|
||||
unsigned int mask;
|
||||
|
||||
/*
|
||||
* Use the blinding technique to mask y_sqr while determining
|
||||
* whether it is a quadratic residue modulo p to avoid leaking
|
||||
* timing information while determining the Legendre symbol.
|
||||
*
|
||||
* v = y_sqr
|
||||
* r = a random number between 1 and p-1, inclusive
|
||||
* num = (v * r * r) modulo p
|
||||
*/
|
||||
r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
num = crypto_bignum_init();
|
||||
if (!num ||
|
||||
crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
|
||||
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Need to minimize differences in handling different cases, so try to
|
||||
* avoid branches and timing differences.
|
||||
*
|
||||
* If r_odd:
|
||||
* num = (num * qr) module p
|
||||
* LGR(num, p) = 1 ==> quadratic residue
|
||||
* else:
|
||||
* num = (num * qnr) module p
|
||||
* LGR(num, p) = -1 ==> quadratic residue
|
||||
*/
|
||||
mask = const_time_is_zero(r_odd);
|
||||
const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
|
||||
qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
|
||||
if (!qr_or_qnr ||
|
||||
crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
/* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
|
||||
check = const_time_select_int(mask, -1, 1);
|
||||
|
||||
res = crypto_bignum_legendre(num, sae->tmp->prime);
|
||||
if (res == -2) {
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
/* branchless version of res = res == check
|
||||
* (res is -1, 0, or 1; check is -1 or 1) */
|
||||
mask = const_time_eq(res, check);
|
||||
res = const_time_select_int(mask, 1, 0);
|
||||
fail:
|
||||
crypto_bignum_deinit(num, 1);
|
||||
crypto_bignum_deinit(r, 1);
|
||||
crypto_bignum_deinit(qr_or_qnr, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
const u8 *prime, const u8 *qr, const u8 *qnr,
|
||||
u8 *pwd_value)
|
||||
@ -304,6 +144,8 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
struct crypto_bignum *y_sqr, *x_cand;
|
||||
int res;
|
||||
size_t bits;
|
||||
int cmp_prime;
|
||||
unsigned int in_range;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
|
||||
|
||||
@ -317,8 +159,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
|
||||
pwd_value, sae->tmp->prime_len);
|
||||
|
||||
if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
|
||||
return 0;
|
||||
cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
|
||||
/* Create a const_time mask for selection based on prf result
|
||||
* being smaller than prime. */
|
||||
in_range = const_time_fill_msb((unsigned int) cmp_prime);
|
||||
/* The algorithm description would skip the next steps if
|
||||
* cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
|
||||
* minimize externally observable differences in behavior. */
|
||||
|
||||
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
|
||||
if (!x_cand)
|
||||
@ -328,9 +175,12 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
if (!y_sqr)
|
||||
return -1;
|
||||
|
||||
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
|
||||
res = dragonfly_is_quadratic_residue_blind(sae->tmp->ec, qr, qnr,
|
||||
y_sqr);
|
||||
crypto_bignum_deinit(y_sqr, 1);
|
||||
return res;
|
||||
if (res < 0)
|
||||
return res;
|
||||
return const_time_select_int(in_range, res, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -423,47 +273,11 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
}
|
||||
|
||||
|
||||
static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
|
||||
const struct crypto_bignum *prime_bn,
|
||||
size_t prime_bits, struct crypto_bignum **qr,
|
||||
struct crypto_bignum **qnr)
|
||||
{
|
||||
*qr = NULL;
|
||||
*qnr = NULL;
|
||||
|
||||
while (!(*qr) || !(*qnr)) {
|
||||
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *q;
|
||||
int res;
|
||||
|
||||
if (random_get_bytes(tmp, prime_len) < 0)
|
||||
break;
|
||||
if (prime_bits % 8)
|
||||
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
|
||||
if (os_memcmp(tmp, prime, prime_len) >= 0)
|
||||
continue;
|
||||
q = crypto_bignum_init_set(tmp, prime_len);
|
||||
if (!q)
|
||||
break;
|
||||
res = crypto_bignum_legendre(q, prime_bn);
|
||||
|
||||
if (res == 1 && !(*qr))
|
||||
*qr = q;
|
||||
else if (res == -1 && !(*qnr))
|
||||
*qnr = q;
|
||||
else
|
||||
crypto_bignum_deinit(q, 0);
|
||||
}
|
||||
|
||||
return (*qr && *qnr) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
const u8 *addr2, const u8 *password,
|
||||
size_t password_len, const char *identifier)
|
||||
{
|
||||
u8 counter, k = 40;
|
||||
u8 counter, k;
|
||||
u8 addrs[2 * ETH_ALEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
@ -477,7 +291,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
|
||||
u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
|
||||
u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
|
||||
size_t bits;
|
||||
int res = -1;
|
||||
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
|
||||
* mask */
|
||||
@ -494,14 +307,12 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
|
||||
prime_len) < 0)
|
||||
goto fail;
|
||||
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
|
||||
|
||||
/*
|
||||
* Create a random quadratic residue (qr) and quadratic non-residue
|
||||
* (qnr) modulo p for blinding purposes during the loop.
|
||||
*/
|
||||
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
|
||||
&qr, &qnr) < 0 ||
|
||||
if (dragonfly_get_random_qr_qnr(sae->tmp->prime, &qr, &qnr) < 0 ||
|
||||
crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
|
||||
crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
|
||||
goto fail;
|
||||
@ -537,6 +348,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
* attacks that attempt to determine the number of iterations required
|
||||
* in the loop.
|
||||
*/
|
||||
k = dragonfly_min_pwe_loop_iter(sae->group);
|
||||
|
||||
for (counter = 1; counter <= k || !found; counter++) {
|
||||
u8 pwd_seed[SHA256_MAC_LEN];
|
||||
|
||||
@ -618,13 +431,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
}
|
||||
|
||||
|
||||
static int sae_modp_group_require_masking(int group)
|
||||
{
|
||||
/* Groups for which pwd-value is likely to be >= p frequently */
|
||||
return group == 22 || group == 23 || group == 24;
|
||||
}
|
||||
|
||||
|
||||
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
||||
const u8 *addr2, const u8 *password,
|
||||
size_t password_len, const char *identifier)
|
||||
@ -673,7 +479,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
||||
len[num_elem] = sizeof(counter);
|
||||
num_elem++;
|
||||
|
||||
k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
|
||||
k = dragonfly_min_pwe_loop_iter(sae->group);
|
||||
|
||||
for (counter = 1; counter <= k || !found; counter++) {
|
||||
u8 pwd_seed[SHA256_MAC_LEN];
|
||||
@ -768,48 +574,23 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae,
|
||||
static int sae_derive_commit(struct sae_data *sae)
|
||||
{
|
||||
struct crypto_bignum *mask;
|
||||
int ret = -1;
|
||||
unsigned int counter = 0;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
counter++;
|
||||
if (counter > 100) {
|
||||
/*
|
||||
* This cannot really happen in practice if the random
|
||||
* number generator is working. Anyway, to avoid even a
|
||||
* theoretical infinite loop, break out after 100
|
||||
* attemps.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
mask = sae_get_rand_and_mask(sae);
|
||||
if (mask == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* commit-scalar = (rand + mask) modulo r */
|
||||
if (!sae->tmp->own_commit_scalar) {
|
||||
sae->tmp->own_commit_scalar = crypto_bignum_init();
|
||||
if (!sae->tmp->own_commit_scalar)
|
||||
goto fail;
|
||||
}
|
||||
crypto_bignum_add(sae->tmp->sae_rand, mask,
|
||||
sae->tmp->own_commit_scalar);
|
||||
crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
|
||||
sae->tmp->own_commit_scalar);
|
||||
} while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
|
||||
crypto_bignum_is_one(sae->tmp->own_commit_scalar));
|
||||
|
||||
if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
|
||||
(sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
mask = crypto_bignum_init();
|
||||
if (!sae->tmp->sae_rand)
|
||||
sae->tmp->sae_rand = crypto_bignum_init();
|
||||
if (!sae->tmp->own_commit_scalar)
|
||||
sae->tmp->own_commit_scalar = crypto_bignum_init();
|
||||
ret = !mask || !sae->tmp->sae_rand || !sae->tmp->own_commit_scalar ||
|
||||
dragonfly_generate_scalar(sae->tmp->order, sae->tmp->sae_rand,
|
||||
mask,
|
||||
sae->tmp->own_commit_scalar) < 0 ||
|
||||
(sae->tmp->ec &&
|
||||
sae_derive_commit_element_ecc(sae, mask) < 0) ||
|
||||
(sae->tmp->dh &&
|
||||
sae_derive_commit_element_ffc(sae, mask) < 0);
|
||||
crypto_bignum_deinit(mask, 1);
|
||||
return ret;
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
@ -930,10 +711,16 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
|
||||
crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
|
||||
tmp);
|
||||
crypto_bignum_mod(tmp, sae->tmp->order, tmp);
|
||||
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
|
||||
/* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
|
||||
* string that is needed for KCK, PMK, and PMKID derivation, but it
|
||||
* seems to make most sense to encode the
|
||||
* (commit-scalar + peer-commit-scalar) mod r part as a bit string by
|
||||
* zero padding it from left to the length of the order (in full
|
||||
* octets). */
|
||||
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
|
||||
if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
|
||||
val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
|
||||
val, sae->tmp->order_len, keys, sizeof(keys)) < 0)
|
||||
goto fail;
|
||||
os_memset(keyseed, 0, sizeof(keyseed));
|
||||
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
|
||||
|
@ -33,6 +33,7 @@ struct sae_temporary_data {
|
||||
struct crypto_bignum *sae_rand;
|
||||
struct crypto_ec *ec;
|
||||
int prime_len;
|
||||
int order_len;
|
||||
const struct dh_group *dh;
|
||||
const struct crypto_bignum *prime;
|
||||
const struct crypto_bignum *order;
|
||||
|
@ -9,6 +9,6 @@
|
||||
#define GIT_VERSION_STR_POSTFIX ""
|
||||
#endif /* GIT_VERSION_STR_POSTFIX */
|
||||
|
||||
#define VERSION_STR "2.8" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
|
||||
#define VERSION_STR "2.9" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
|
||||
|
||||
#endif /* VERSION_H */
|
||||
|
@ -2075,6 +2075,16 @@ u32 wpa_akm_to_suite(int akm)
|
||||
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
|
||||
if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
|
||||
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
|
||||
if (akm & WPA_KEY_MGMT_SAE)
|
||||
return RSN_AUTH_KEY_MGMT_SAE;
|
||||
if (akm & WPA_KEY_MGMT_FT_SAE)
|
||||
return RSN_AUTH_KEY_MGMT_FT_SAE;
|
||||
if (akm & WPA_KEY_MGMT_OWE)
|
||||
return RSN_AUTH_KEY_MGMT_OWE;
|
||||
if (akm & WPA_KEY_MGMT_DPP)
|
||||
return RSN_AUTH_KEY_MGMT_DPP;
|
||||
if (akm & WPA_KEY_MGMT_OSEN)
|
||||
return RSN_AUTH_KEY_MGMT_OSEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,9 @@ extern "C" {
|
||||
#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
|
||||
/** Regulatory domain channel */
|
||||
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
|
||||
/** Channel switch started (followed by freq=<MHz> and other channel parameters)
|
||||
*/
|
||||
#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
|
||||
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
|
||||
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
|
||||
/** SAE authentication failed due to unknown password identifier */
|
||||
|
@ -65,7 +65,7 @@ extern const u8 rcons[10];
|
||||
|
||||
#else /* AES_SMALL_TABLES */
|
||||
|
||||
#define RCON(i) (rcons[(i)] << 24)
|
||||
#define RCON(i) ((u32) rcons[(i)] << 24)
|
||||
|
||||
static inline u32 rotr(u32 val, int bits)
|
||||
{
|
||||
@ -94,10 +94,10 @@ static inline u32 rotr(u32 val, int bits)
|
||||
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
|
||||
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
|
||||
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
|
||||
#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
|
||||
#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
|
||||
#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
|
||||
#define TD44(i) (Td4s[(i) & 0xff])
|
||||
#define TD41(i) ((u32) Td4s[((i) >> 24) & 0xff] << 24)
|
||||
#define TD42(i) ((u32) Td4s[((i) >> 16) & 0xff] << 16)
|
||||
#define TD43(i) ((u32) Td4s[((i) >> 8) & 0xff] << 8)
|
||||
#define TD44(i) ((u32) Td4s[(i) & 0xff])
|
||||
#define TD0_(i) Td0[(i) & 0xff]
|
||||
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
|
||||
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
|
||||
|
@ -644,13 +644,6 @@ int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
|
||||
int crypto_bignum_cmp(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b);
|
||||
|
||||
/**
|
||||
* crypto_bignum_bits - Get size of a bignum in bits
|
||||
* @a: Bignum
|
||||
* Returns: Number of bits in the bignum
|
||||
*/
|
||||
int crypto_bignum_bits(const struct crypto_bignum *a);
|
||||
|
||||
/**
|
||||
* crypto_bignum_is_zero - Is the given bignum zero
|
||||
* @a: Bignum
|
||||
|
@ -570,8 +570,8 @@ int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
failed = !q || !ctx || !tmp ||
|
||||
!BN_mod_exp(tmp, pub, q, p, ctx) ||
|
||||
!BN_is_one(tmp);
|
||||
BN_clear(q);
|
||||
BN_clear(tmp);
|
||||
BN_clear_free(q);
|
||||
BN_clear_free(tmp);
|
||||
BN_CTX_free(ctx);
|
||||
if (failed)
|
||||
goto fail;
|
||||
@ -580,8 +580,8 @@ int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
fail:
|
||||
BN_clear(pub);
|
||||
BN_clear(p);
|
||||
BN_clear_free(pub);
|
||||
BN_clear_free(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1303,6 +1303,18 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
|
||||
if (padlen > buflen)
|
||||
return -1;
|
||||
|
||||
if (padlen) {
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
|
||||
return -1;
|
||||
return padlen;
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
num_bytes = BN_num_bytes((const BIGNUM *) a);
|
||||
if ((size_t) num_bytes > buflen)
|
||||
return -1;
|
||||
@ -1476,12 +1488,6 @@ int crypto_bignum_cmp(const struct crypto_bignum *a,
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_bits(const struct crypto_bignum *a)
|
||||
{
|
||||
return BN_num_bits((const BIGNUM *) a);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_zero(const struct crypto_bignum *a)
|
||||
{
|
||||
return BN_is_zero((const BIGNUM *) a);
|
||||
@ -1870,7 +1876,7 @@ struct crypto_ecdh * crypto_ecdh_init(int group)
|
||||
{
|
||||
struct crypto_ecdh *ecdh;
|
||||
EVP_PKEY *params = NULL;
|
||||
EC_KEY *ec_params;
|
||||
EC_KEY *ec_params = NULL;
|
||||
EVP_PKEY_CTX *kctx = NULL;
|
||||
|
||||
ecdh = os_zalloc(sizeof(*ecdh));
|
||||
@ -1913,6 +1919,7 @@ struct crypto_ecdh * crypto_ecdh_init(int group)
|
||||
}
|
||||
|
||||
done:
|
||||
EC_KEY_free(ec_params);
|
||||
EVP_PKEY_free(params);
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
|
||||
@ -2052,13 +2059,17 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
|
||||
secret = wpabuf_alloc(secret_len);
|
||||
if (!secret)
|
||||
goto fail;
|
||||
if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
|
||||
&secret_len) != 1) {
|
||||
if (EVP_PKEY_derive(ctx, wpabuf_put(secret, 0), &secret_len) != 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OpenSSL: EVP_PKEY_derive(2) failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto fail;
|
||||
}
|
||||
if (secret->size != secret_len)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: EVP_PKEY_derive(2) changed secret_len %d -> %d",
|
||||
(int) secret->size, (int) secret_len);
|
||||
wpabuf_put(secret, secret_len);
|
||||
|
||||
done:
|
||||
BN_free(x);
|
||||
|
@ -1198,12 +1198,6 @@ int crypto_bignum_cmp(const struct crypto_bignum *a,
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_bits(const struct crypto_bignum *a)
|
||||
{
|
||||
return mp_count_bits((mp_int *) a);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_zero(const struct crypto_bignum *a)
|
||||
{
|
||||
return mp_iszero((mp_int *) a);
|
||||
|
@ -224,7 +224,7 @@ void SHA1Transform(u32 state[5], const unsigned char buffer[64])
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
#ifdef SHA1HANDSOFF
|
||||
os_memset(block, 0, 64);
|
||||
forced_memzero(block, 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -300,7 +300,7 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
|
||||
os_memset(context->buffer, 0, 64);
|
||||
os_memset(context->state, 0, 20);
|
||||
os_memset(context->count, 0, 8);
|
||||
os_memset(finalcount, 0, 8);
|
||||
forced_memzero(finalcount, sizeof(finalcount));
|
||||
}
|
||||
|
||||
/* ===== end - public domain SHA1 implementation ===== */
|
||||
|
@ -61,7 +61,7 @@ int sha1_prf(const u8 *key, size_t key_len, const char *label,
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
os_memset(hash, 0, sizeof(hash));
|
||||
forced_memzero(hash, sizeof(hash));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -92,10 +92,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
|
||||
SHA1_pos++;
|
||||
}
|
||||
|
||||
os_memset(A_MD5, 0, MD5_MAC_LEN);
|
||||
os_memset(P_MD5, 0, MD5_MAC_LEN);
|
||||
os_memset(A_SHA1, 0, SHA1_MAC_LEN);
|
||||
os_memset(P_SHA1, 0, SHA1_MAC_LEN);
|
||||
forced_memzero(A_MD5, MD5_MAC_LEN);
|
||||
forced_memzero(P_MD5, MD5_MAC_LEN);
|
||||
forced_memzero(A_SHA1, SHA1_MAC_LEN);
|
||||
forced_memzero(P_SHA1, SHA1_MAC_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
|
||||
len[0] = SHA1_MAC_LEN;
|
||||
}
|
||||
|
||||
os_memset(hash, 0, SHA1_MAC_LEN);
|
||||
forced_memzero(hash, SHA1_MAC_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -86,7 +86,8 @@ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
_addr[1] = mac;
|
||||
_len[1] = SHA1_MAC_LEN;
|
||||
ret = sha1_vector(2, _addr, _len, mac);
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
forced_memzero(k_pad, sizeof(k_pad));
|
||||
forced_memzero(tk, sizeof(tk));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
|
||||
|
||||
if (iter == 255) {
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
forced_memzero(T, SHA256_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
iter++;
|
||||
@ -77,11 +77,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
|
||||
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
|
||||
{
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
forced_memzero(T, SHA256_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
forced_memzero(T, SHA256_MAC_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
|
||||
buf[pos - 1] &= mask;
|
||||
}
|
||||
|
||||
os_memset(hash, 0, sizeof(hash));
|
||||
forced_memzero(hash, sizeof(hash));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,8 +26,8 @@
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
|
||||
*/
|
||||
void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
{
|
||||
size_t clen;
|
||||
u8 A[SHA256_MAC_LEN];
|
||||
@ -50,12 +50,15 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
|
||||
* PRF(secret, label, seed) = P_SHA256(secret, label + seed)
|
||||
*/
|
||||
|
||||
hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
|
||||
if (hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
|
||||
return -1;
|
||||
|
||||
pos = 0;
|
||||
while (pos < outlen) {
|
||||
hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
|
||||
hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
|
||||
if (hmac_sha256_vector(secret, secret_len, 3, addr, len, P) <
|
||||
0 ||
|
||||
hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A) < 0)
|
||||
return -1;
|
||||
|
||||
clen = outlen - pos;
|
||||
if (clen > SHA256_MAC_LEN)
|
||||
@ -63,4 +66,6 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
|
||||
os_memcpy(out + pos, P, clen);
|
||||
pos += clen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,9 +20,9 @@ int sha256_prf(const u8 *key, size_t key_len, const char *label,
|
||||
int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf,
|
||||
size_t buf_len_bits);
|
||||
void tls_prf_sha256(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen);
|
||||
int tls_prf_sha256(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen);
|
||||
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen);
|
||||
|
@ -69,7 +69,7 @@ int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
|
||||
|
||||
if (iter == 255) {
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA384_MAC_LEN);
|
||||
forced_memzero(T, SHA384_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
iter++;
|
||||
@ -77,11 +77,11 @@ int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
|
||||
if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
|
||||
{
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA384_MAC_LEN);
|
||||
forced_memzero(T, SHA384_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
os_memset(T, 0, SHA384_MAC_LEN);
|
||||
forced_memzero(T, SHA384_MAC_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
|
||||
buf[pos - 1] &= mask;
|
||||
}
|
||||
|
||||
os_memset(hash, 0, sizeof(hash));
|
||||
forced_memzero(hash, sizeof(hash));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
|
||||
|
||||
if (iter == 255) {
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA512_MAC_LEN);
|
||||
forced_memzero(T, SHA512_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
iter++;
|
||||
@ -77,11 +77,11 @@ int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
|
||||
if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
|
||||
{
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA512_MAC_LEN);
|
||||
forced_memzero(T, SHA512_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
os_memset(T, 0, SHA512_MAC_LEN);
|
||||
forced_memzero(T, SHA512_MAC_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
|
||||
buf[pos - 1] &= mask;
|
||||
}
|
||||
|
||||
os_memset(hash, 0, sizeof(hash));
|
||||
forced_memzero(hash, sizeof(hash));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,6 +48,18 @@ enum tls_fail_reason {
|
||||
|
||||
#define TLS_MAX_ALT_SUBJECT 10
|
||||
|
||||
struct tls_cert_data {
|
||||
int depth;
|
||||
const char *subject;
|
||||
const struct wpabuf *cert;
|
||||
const u8 *hash;
|
||||
size_t hash_len;
|
||||
const char *altsubject[TLS_MAX_ALT_SUBJECT];
|
||||
int num_altsubject;
|
||||
const char *serial_num;
|
||||
int tod;
|
||||
};
|
||||
|
||||
union tls_event_data {
|
||||
struct {
|
||||
int depth;
|
||||
@ -57,16 +69,7 @@ union tls_event_data {
|
||||
const struct wpabuf *cert;
|
||||
} cert_fail;
|
||||
|
||||
struct {
|
||||
int depth;
|
||||
const char *subject;
|
||||
const struct wpabuf *cert;
|
||||
const u8 *hash;
|
||||
size_t hash_len;
|
||||
const char *altsubject[TLS_MAX_ALT_SUBJECT];
|
||||
int num_altsubject;
|
||||
const char *serial_num;
|
||||
} peer_cert;
|
||||
struct tls_cert_data peer_cert;
|
||||
|
||||
struct {
|
||||
int is_local;
|
||||
@ -108,6 +111,7 @@ struct tls_config {
|
||||
#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
|
||||
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
|
||||
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
|
||||
#define TLS_CONN_TEAP_ANON_DH BIT(17)
|
||||
|
||||
/**
|
||||
* struct tls_connection_params - Parameters for TLS connection
|
||||
@ -184,12 +188,15 @@ struct tls_connection_params {
|
||||
const char *suffix_match;
|
||||
const char *domain_match;
|
||||
const char *client_cert;
|
||||
const char *client_cert2;
|
||||
const u8 *client_cert_blob;
|
||||
size_t client_cert_blob_len;
|
||||
const char *private_key;
|
||||
const char *private_key2;
|
||||
const u8 *private_key_blob;
|
||||
size_t private_key_blob_len;
|
||||
const char *private_key_passwd;
|
||||
const char *private_key_passwd2;
|
||||
const char *dh_file;
|
||||
const u8 *dh_blob;
|
||||
size_t dh_blob_len;
|
||||
@ -643,4 +650,24 @@ tls_connection_get_success_data(struct tls_connection *conn);
|
||||
|
||||
void tls_connection_remove_session(struct tls_connection *conn);
|
||||
|
||||
/**
|
||||
* tls_get_tls_unique - Fetch "tls-unique" for channel binding
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @buf: Buffer for returning the value
|
||||
* @max_len: Maximum length of the buffer in bytes
|
||||
* Returns: Number of bytes written to buf or -1 on error
|
||||
*
|
||||
* This function can be used to fetch "tls-unique" (RFC 5929, Section 3) which
|
||||
* is the first TLS Finished message sent in the most recent TLS handshake of
|
||||
* the TLS connection.
|
||||
*/
|
||||
int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
|
||||
|
||||
/**
|
||||
* tls_connection_get_cipher_suite - Get current TLS cipher suite
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* Returns: TLS cipher suite of the current connection or 0 on error
|
||||
*/
|
||||
u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
|
||||
|
||||
#endif /* TLS_H */
|
||||
|
@ -44,6 +44,13 @@
|
||||
#define OPENSSL_NEED_EAP_FAST_PRF
|
||||
#endif
|
||||
|
||||
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
|
||||
defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
|
||||
defined(EAP_SERVER_TEAP)
|
||||
#define EAP_FAST_OR_TEAP
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_IS_BORINGSSL)
|
||||
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
|
||||
typedef size_t stack_index_t;
|
||||
@ -1071,11 +1078,8 @@ void * tls_init(const struct tls_config *conf)
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
ERR_load_ENGINE_strings();
|
||||
ENGINE_load_dynamic();
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
|
||||
ENGINE_load_builtin_engines();
|
||||
|
||||
if (conf &&
|
||||
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
|
||||
@ -1331,6 +1335,8 @@ static const char * openssl_content_type(int content_type)
|
||||
return "heartbeat";
|
||||
case 256:
|
||||
return "TLS header info"; /* pseudo content type */
|
||||
case 257:
|
||||
return "inner content type"; /* pseudo content type */
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
@ -1340,6 +1346,8 @@ static const char * openssl_content_type(int content_type)
|
||||
static const char * openssl_handshake_type(int content_type, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (content_type == 257 && buf && len == 1)
|
||||
return openssl_content_type(buf[0]);
|
||||
if (content_type != 22 || !buf || len == 0)
|
||||
return "";
|
||||
switch (buf[0]) {
|
||||
@ -1570,6 +1578,11 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif /* SSL_OP_NO_COMPRESSION */
|
||||
SSL_set_options(conn->ssl, options);
|
||||
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
|
||||
/* Hopefully there is no need for middlebox compatibility mechanisms
|
||||
* when going through EAP authentication. */
|
||||
SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
|
||||
#endif
|
||||
|
||||
conn->ssl_in = BIO_new(BIO_s_mem());
|
||||
if (!conn->ssl_in) {
|
||||
@ -2152,6 +2165,34 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static int openssl_cert_tod(X509 *cert)
|
||||
{
|
||||
CERTIFICATEPOLICIES *ext;
|
||||
stack_index_t i;
|
||||
char buf[100];
|
||||
int res;
|
||||
int tod = 0;
|
||||
|
||||
ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
|
||||
if (!ext)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
|
||||
POLICYINFO *policy;
|
||||
|
||||
policy = sk_POLICYINFO_value(ext, i);
|
||||
res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
|
||||
if (res < 0 || (size_t) res >= sizeof(buf))
|
||||
continue;
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
|
||||
if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
|
||||
tod = 1;
|
||||
}
|
||||
|
||||
return tod;
|
||||
}
|
||||
|
||||
|
||||
static void openssl_tls_cert_event(struct tls_connection *conn,
|
||||
X509 *err_cert, int depth,
|
||||
const char *subject)
|
||||
@ -2244,6 +2285,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
|
||||
ev.peer_cert.altsubject[alt] = altsubject[alt];
|
||||
ev.peer_cert.num_altsubject = num_altsubject;
|
||||
|
||||
ev.peer_cert.tod = openssl_cert_tod(err_cert);
|
||||
|
||||
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
|
||||
wpabuf_free(cert);
|
||||
for (alt = 0; alt < num_altsubject; alt++)
|
||||
@ -2348,7 +2391,30 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
}
|
||||
#endif /* CONFIG_SHA256 */
|
||||
|
||||
openssl_tls_cert_event(conn, err_cert, depth, buf);
|
||||
|
||||
if (!preverify_ok) {
|
||||
if (depth > 0) {
|
||||
/* Send cert event for the peer certificate so that
|
||||
* the upper layers get information about it even if
|
||||
* validation of a CA certificate fails. */
|
||||
STACK_OF(X509) *chain;
|
||||
|
||||
chain = X509_STORE_CTX_get1_chain(x509_ctx);
|
||||
if (chain && sk_X509_num(chain) > 0) {
|
||||
char buf2[256];
|
||||
X509 *cert;
|
||||
|
||||
cert = sk_X509_value(chain, 0);
|
||||
X509_NAME_oneline(X509_get_subject_name(cert),
|
||||
buf2, sizeof(buf2));
|
||||
|
||||
openssl_tls_cert_event(conn, cert, 0, buf2);
|
||||
}
|
||||
if (chain)
|
||||
sk_X509_pop_free(chain, X509_free);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
|
||||
" error %d (%s) depth %d for '%s'", err, err_str,
|
||||
depth, buf);
|
||||
@ -2404,8 +2470,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
"Domain mismatch",
|
||||
TLS_FAIL_DOMAIN_MISMATCH);
|
||||
} else
|
||||
openssl_tls_cert_event(conn, err_cert, depth, buf);
|
||||
}
|
||||
|
||||
if (conn->cert_probe && preverify_ok && depth == 0) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
|
||||
@ -2580,9 +2645,23 @@ static int tls_connection_ca_cert(struct tls_data *data,
|
||||
(const unsigned char **) &ca_cert_blob,
|
||||
ca_cert_blob_len);
|
||||
if (cert == NULL) {
|
||||
tls_show_errors(MSG_WARNING, __func__,
|
||||
"Failed to parse ca_cert_blob");
|
||||
return -1;
|
||||
BIO *bio = BIO_new_mem_buf(ca_cert_blob,
|
||||
ca_cert_blob_len);
|
||||
|
||||
if (bio) {
|
||||
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
if (!cert) {
|
||||
tls_show_errors(MSG_WARNING, __func__,
|
||||
"Failed to parse ca_cert_blob");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (ERR_get_error()) {
|
||||
/* Ignore errors from DER conversion. */
|
||||
}
|
||||
}
|
||||
|
||||
if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
|
||||
@ -3016,6 +3095,40 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
|
||||
}
|
||||
#endif /* CONFIG_SUITEB */
|
||||
|
||||
if (flags & TLS_CONN_TEAP_ANON_DH) {
|
||||
#ifndef TEAP_DH_ANON_CS
|
||||
#define TEAP_DH_ANON_CS \
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
|
||||
"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
|
||||
"ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
|
||||
"DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
|
||||
"DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
|
||||
"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
|
||||
"ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
|
||||
"ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
|
||||
#endif
|
||||
static const char *cs = TEAP_DH_ANON_CS;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
!defined(OPENSSL_IS_BORINGSSL)
|
||||
/*
|
||||
* Need to drop to security level 0 to allow anonymous
|
||||
* cipher suites for EAP-TEAP.
|
||||
*/
|
||||
SSL_set_security_level(conn->ssl, 0);
|
||||
#endif
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
|
||||
cs);
|
||||
if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
|
||||
tls_show_errors(MSG_INFO, __func__,
|
||||
"Cipher suite configuration failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4002,7 +4115,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
_out, skip + out_len) == 0) {
|
||||
ret = 0;
|
||||
}
|
||||
os_memset(master_key, 0, sizeof(master_key));
|
||||
forced_memzero(master_key, sizeof(master_key));
|
||||
os_free(rnd);
|
||||
if (ret == 0)
|
||||
os_memcpy(out, _out + skip, out_len);
|
||||
@ -4192,6 +4305,22 @@ openssl_connection_handshake(struct tls_connection *conn,
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Handshake finished - resumed=%d",
|
||||
tls_connection_resumed(conn->ssl_ctx, conn));
|
||||
if (conn->server) {
|
||||
char *buf;
|
||||
size_t buflen = 2000;
|
||||
|
||||
buf = os_malloc(buflen);
|
||||
if (buf) {
|
||||
if (SSL_get_shared_ciphers(conn->ssl, buf,
|
||||
buflen)) {
|
||||
buf[buflen - 1] = '\0';
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Shared ciphers: %s",
|
||||
buf);
|
||||
}
|
||||
os_free(buf);
|
||||
}
|
||||
}
|
||||
if (appl_data && in_data)
|
||||
*appl_data = openssl_get_appl_data(conn,
|
||||
wpabuf_len(in_data));
|
||||
@ -4374,11 +4503,15 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
|
||||
|
||||
c++;
|
||||
}
|
||||
if (!buf[0]) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
|
||||
#ifdef EAP_FAST_OR_TEAP
|
||||
if (os_strstr(buf, ":ADH-")) {
|
||||
/*
|
||||
* Need to drop to security level 0 to allow anonymous
|
||||
@ -4389,7 +4522,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
|
||||
/* Force at least security level 1 */
|
||||
SSL_set_security_level(conn->ssl, 1);
|
||||
}
|
||||
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
|
||||
#endif /* EAP_FAST_OR_TEAP */
|
||||
#endif
|
||||
|
||||
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
|
||||
@ -4443,7 +4576,7 @@ int tls_connection_enable_workaround(void *ssl_ctx,
|
||||
}
|
||||
|
||||
|
||||
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
|
||||
#ifdef EAP_FAST_OR_TEAP
|
||||
/* ClientHello TLS extensions require a patch to openssl, so this function is
|
||||
* commented out unless explicitly needed for EAP-FAST in order to be able to
|
||||
* build this file with unmodified openssl. */
|
||||
@ -4460,7 +4593,7 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
|
||||
#endif /* EAP_FAST_OR_TEAP */
|
||||
|
||||
|
||||
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
|
||||
@ -4669,6 +4802,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
|
||||
res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
|
||||
&this_update, &next_update);
|
||||
if (!res) {
|
||||
OCSP_CERTID_free(id);
|
||||
id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
|
||||
if (!id) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -4979,6 +5113,114 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
SSL *ssl;
|
||||
int i;
|
||||
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
if (!ssl)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Enabled cipher suites in priority order");
|
||||
for (i = 0; ; i++) {
|
||||
const char *cipher;
|
||||
|
||||
cipher = SSL_get_cipher_list(ssl, i);
|
||||
if (!cipher)
|
||||
break;
|
||||
wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
|
||||
}
|
||||
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
|
||||
#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
|
||||
|
||||
static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
|
||||
{
|
||||
if (!pkey)
|
||||
return "NULL";
|
||||
switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
|
||||
case EVP_PKEY_RSA:
|
||||
return "RSA";
|
||||
case EVP_PKEY_DSA:
|
||||
return "DSA";
|
||||
case EVP_PKEY_DH:
|
||||
return "DH";
|
||||
case EVP_PKEY_EC:
|
||||
return "EC";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
static void openssl_debug_dump_certificate(int i, X509 *cert)
|
||||
{
|
||||
char buf[256];
|
||||
EVP_PKEY *pkey;
|
||||
ASN1_INTEGER *ser;
|
||||
char serial_num[128];
|
||||
|
||||
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
|
||||
|
||||
ser = X509_get_serialNumber(cert);
|
||||
if (ser)
|
||||
wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
|
||||
ASN1_STRING_get0_data(ser),
|
||||
ASN1_STRING_length(ser));
|
||||
else
|
||||
serial_num[0] = '\0';
|
||||
|
||||
pkey = X509_get_pubkey(cert);
|
||||
wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
|
||||
openssl_pkey_type_str(pkey), serial_num);
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
|
||||
|
||||
static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
STACK_OF(X509) *certs;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
|
||||
if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
|
||||
int i;
|
||||
|
||||
for (i = sk_X509_num(certs); i > 0; i--)
|
||||
openssl_debug_dump_certificate(i, sk_X509_value(certs,
|
||||
i - 1));
|
||||
}
|
||||
openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
|
||||
int res;
|
||||
|
||||
for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
|
||||
res == 1;
|
||||
res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
|
||||
openssl_debug_dump_certificates(ssl_ctx);
|
||||
|
||||
SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
openssl_debug_dump_cipher_list(ssl_ctx);
|
||||
openssl_debug_dump_certificate_chains(ssl_ctx);
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_params(void *tls_ctx,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
@ -5004,6 +5246,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
tls_global_client_cert(data, params->client_cert) ||
|
||||
tls_global_private_key(data, params->private_key,
|
||||
params->private_key_passwd) ||
|
||||
tls_global_client_cert(data, params->client_cert2) ||
|
||||
tls_global_private_key(data, params->private_key2,
|
||||
params->private_key_passwd2) ||
|
||||
tls_global_dh(data, params->dh_file)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
|
||||
return -1;
|
||||
@ -5073,11 +5318,13 @@ int tls_global_set_params(void *tls_ctx,
|
||||
tls_global->ocsp_stapling_response = NULL;
|
||||
#endif /* HAVE_OCSP */
|
||||
|
||||
openssl_debug_dump_ctx(ssl_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
|
||||
#ifdef EAP_FAST_OR_TEAP
|
||||
/* Pre-shared secred requires a patch to openssl, so this function is
|
||||
* commented out unless explicitly needed for EAP-FAST in order to be able to
|
||||
* build this file with unmodified openssl. */
|
||||
@ -5158,7 +5405,7 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
|
||||
#endif /* EAP_FAST_OR_TEAP */
|
||||
|
||||
|
||||
int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
@ -5166,7 +5413,7 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
tls_session_ticket_cb cb,
|
||||
void *ctx)
|
||||
{
|
||||
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
|
||||
#ifdef EAP_FAST_OR_TEAP
|
||||
conn->session_ticket_cb = cb;
|
||||
conn->session_ticket_cb_ctx = ctx;
|
||||
|
||||
@ -5183,9 +5430,9 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
|
||||
#else /* EAP_FAST_OR_TEAP */
|
||||
return -1;
|
||||
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
|
||||
#endif /* EAP_FAST_OR_TEAP */
|
||||
}
|
||||
|
||||
|
||||
@ -5268,3 +5515,36 @@ void tls_connection_remove_session(struct tls_connection *conn)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Removed cached session to disable session resumption");
|
||||
}
|
||||
|
||||
|
||||
int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
|
||||
{
|
||||
size_t len;
|
||||
int reused;
|
||||
|
||||
reused = SSL_session_reused(conn->ssl);
|
||||
if ((conn->server && !reused) || (!conn->server && reused))
|
||||
len = SSL_get_peer_finished(conn->ssl, buf, max_len);
|
||||
else
|
||||
len = SSL_get_finished(conn->ssl, buf, max_len);
|
||||
|
||||
if (len == 0 || len > max_len)
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
|
||||
{
|
||||
const SSL_CIPHER *cipher;
|
||||
|
||||
cipher = SSL_get_current_cipher(conn->ssl);
|
||||
if (!cipher)
|
||||
return 0;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
return SSL_CIPHER_get_protocol_id(cipher);
|
||||
#else
|
||||
return SSL_CIPHER_get_id(cipher) & 0xFFFF;
|
||||
#endif
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
||||
if (get > (wpabuf_len(data->in_data) - data->consumed))
|
||||
get = wpabuf_len(data->in_data) - data->consumed;
|
||||
|
||||
os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
|
||||
os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
|
||||
data->consumed += get;
|
||||
|
||||
if (get == 0)
|
||||
@ -2044,7 +2044,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
_out, skip + out_len);
|
||||
}
|
||||
|
||||
os_memset(master_key, 0, master_key_len);
|
||||
forced_memzero(master_key, master_key_len);
|
||||
if (ret == 0)
|
||||
os_memcpy(out, _out + skip, out_len);
|
||||
bin_clear_free(tmp_out, skip + out_len);
|
||||
|
@ -101,6 +101,20 @@ enum reg_type {
|
||||
REGDOM_TYPE_INTERSECTION,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_wmm_rule - WMM regulatory rule
|
||||
* @min_cwmin: Lower bound of CW_min value
|
||||
* @min_cwmax: Lower bound of CW_max value
|
||||
* @min_aifs: Lower bound of AIFS value
|
||||
* @max_txop: Upper bound of TXOP, value in units of 32 usec
|
||||
*/
|
||||
struct hostapd_wmm_rule {
|
||||
int min_cwmin;
|
||||
int min_cwmax;
|
||||
int min_aifs;
|
||||
int max_txop;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_channel_data - Channel information
|
||||
*/
|
||||
@ -156,34 +170,48 @@ struct hostapd_channel_data {
|
||||
* dfs_cac_ms - DFS CAC time in milliseconds
|
||||
*/
|
||||
unsigned int dfs_cac_ms;
|
||||
|
||||
/**
|
||||
* wmm_rules_valid - Indicates wmm_rules state
|
||||
*/
|
||||
int wmm_rules_valid;
|
||||
|
||||
/**
|
||||
* wmm_rules - WMM regulatory rules
|
||||
*/
|
||||
struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
|
||||
};
|
||||
|
||||
#define HE_MAX_NUM_SS 8
|
||||
#define HE_MAX_PHY_CAPAB_SIZE 3
|
||||
|
||||
/**
|
||||
* struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
|
||||
*/
|
||||
struct he_ppe_threshold {
|
||||
u32 numss_m1;
|
||||
u32 ru_count;
|
||||
u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
|
||||
};
|
||||
#define HE_MAX_MAC_CAPAB_SIZE 6
|
||||
#define HE_MAX_PHY_CAPAB_SIZE 11
|
||||
#define HE_MAX_MCS_CAPAB_SIZE 12
|
||||
#define HE_MAX_PPET_CAPAB_SIZE 25
|
||||
|
||||
/**
|
||||
* struct he_capabilities - IEEE 802.11ax HE capabilities
|
||||
*/
|
||||
struct he_capabilities {
|
||||
u8 he_supported;
|
||||
u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
|
||||
u32 mac_cap;
|
||||
u32 mcs;
|
||||
struct he_ppe_threshold ppet;
|
||||
u8 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
|
||||
u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
|
||||
u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
|
||||
u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
|
||||
};
|
||||
|
||||
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
|
||||
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
|
||||
|
||||
|
||||
enum ieee80211_op_mode {
|
||||
IEEE80211_MODE_INFRA = 0,
|
||||
IEEE80211_MODE_IBSS = 1,
|
||||
IEEE80211_MODE_AP = 2,
|
||||
IEEE80211_MODE_MESH = 5,
|
||||
|
||||
/* only add new entries before IEEE80211_MODE_NUM */
|
||||
IEEE80211_MODE_NUM
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_hw_modes - Supported hardware mode information
|
||||
*/
|
||||
@ -243,15 +271,10 @@ struct hostapd_hw_modes {
|
||||
/**
|
||||
* he_capab - HE (IEEE 802.11ax) capabilities
|
||||
*/
|
||||
struct he_capabilities he_capab;
|
||||
struct he_capabilities he_capab[IEEE80211_MODE_NUM];
|
||||
};
|
||||
|
||||
|
||||
#define IEEE80211_MODE_INFRA 0
|
||||
#define IEEE80211_MODE_IBSS 1
|
||||
#define IEEE80211_MODE_AP 2
|
||||
#define IEEE80211_MODE_MESH 5
|
||||
|
||||
#define IEEE80211_CAP_ESS 0x0001
|
||||
#define IEEE80211_CAP_IBSS 0x0002
|
||||
#define IEEE80211_CAP_PRIVACY 0x0010
|
||||
@ -698,6 +721,11 @@ struct hostapd_freq_params {
|
||||
*/
|
||||
int vht_enabled;
|
||||
|
||||
/**
|
||||
* he_enabled - Whether HE is enabled
|
||||
*/
|
||||
int he_enabled;
|
||||
|
||||
/**
|
||||
* center_freq1 - Segment 0 center frequency in MHz
|
||||
*
|
||||
@ -1045,6 +1073,14 @@ struct wpa_driver_associate_params {
|
||||
*/
|
||||
int req_key_mgmt_offload;
|
||||
|
||||
/**
|
||||
* req_handshake_offload - Request EAPOL handshake offload
|
||||
*
|
||||
* Request EAPOL handshake offload for this connection if the device
|
||||
* supports it.
|
||||
*/
|
||||
int req_handshake_offload;
|
||||
|
||||
/**
|
||||
* Flag for indicating whether this association includes support for
|
||||
* RRM (Radio Resource Measurements)
|
||||
@ -1122,6 +1158,11 @@ enum hide_ssid {
|
||||
HIDDEN_SSID_ZERO_CONTENTS
|
||||
};
|
||||
|
||||
enum ch_switch_state {
|
||||
CH_SW_STARTED,
|
||||
CH_SW_FINISHED
|
||||
};
|
||||
|
||||
struct wowlan_triggers {
|
||||
u8 any;
|
||||
u8 disconnect;
|
||||
@ -1752,6 +1793,7 @@ struct hostapd_data;
|
||||
struct hostap_sta_driver_data {
|
||||
unsigned long rx_packets, tx_packets;
|
||||
unsigned long long rx_bytes, tx_bytes;
|
||||
unsigned long long rx_airtime, tx_airtime;
|
||||
int bytes_64bit; /* whether 64-bit byte counters are supported */
|
||||
unsigned long current_tx_rate;
|
||||
unsigned long current_rx_rate;
|
||||
@ -1761,6 +1803,8 @@ struct hostap_sta_driver_data {
|
||||
unsigned long tx_retry_failed;
|
||||
unsigned long tx_retry_count;
|
||||
s8 last_ack_rssi;
|
||||
unsigned long backlog_packets;
|
||||
unsigned long backlog_bytes;
|
||||
s8 signal;
|
||||
u8 rx_vhtmcs;
|
||||
u8 tx_vhtmcs;
|
||||
@ -1781,6 +1825,8 @@ struct hostapd_sta_add_params {
|
||||
const struct ieee80211_vht_capabilities *vht_capabilities;
|
||||
int vht_opmode_enabled;
|
||||
u8 vht_opmode;
|
||||
const struct ieee80211_he_capabilities *he_capab;
|
||||
size_t he_capab_len;
|
||||
u32 flags; /* bitmask of WPA_STA_* flags */
|
||||
u32 flags_mask; /* unset bits in flags */
|
||||
#ifdef CONFIG_MESH
|
||||
@ -2337,7 +2383,7 @@ struct wpa_driver_ops {
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
|
||||
int (*deauthenticate)(void *priv, const u8 *addr, u16 reason_code);
|
||||
|
||||
/**
|
||||
* associate - Request driver to associate
|
||||
@ -2806,7 +2852,7 @@ struct wpa_driver_ops {
|
||||
* a Deauthentication frame to be sent to it.
|
||||
*/
|
||||
int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
|
||||
int reason);
|
||||
u16 reason);
|
||||
|
||||
/**
|
||||
* sta_disassoc - Disassociate a station (AP only)
|
||||
@ -2820,7 +2866,7 @@ struct wpa_driver_ops {
|
||||
* a Disassociation frame to be sent to it.
|
||||
*/
|
||||
int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
|
||||
int reason);
|
||||
u16 reason);
|
||||
|
||||
/**
|
||||
* sta_remove - Remove a station entry (AP only)
|
||||
@ -2937,6 +2983,16 @@ struct wpa_driver_ops {
|
||||
unsigned int total_flags, unsigned int flags_or,
|
||||
unsigned int flags_and);
|
||||
|
||||
/**
|
||||
* sta_set_airtime_weight - Set station airtime weight (AP only)
|
||||
* @priv: Private driver interface data
|
||||
* @addr: Station address
|
||||
* @weight: New weight for station airtime assignment
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int (*sta_set_airtime_weight)(void *priv, const u8 *addr,
|
||||
unsigned int weight);
|
||||
|
||||
/**
|
||||
* set_tx_queue_params - Set TX queue parameters
|
||||
* @priv: Private driver interface data
|
||||
@ -3974,6 +4030,18 @@ struct wpa_driver_ops {
|
||||
*/
|
||||
int (*leave_mesh)(void *priv);
|
||||
|
||||
/**
|
||||
* probe_mesh_link - Inject a frame over direct mesh link to a given
|
||||
* peer skipping the next_hop lookup from mpath table.
|
||||
* @priv: Private driver interface data
|
||||
* @addr: Peer MAC address
|
||||
* @eth: Ethernet frame to be sent
|
||||
* @len: Ethernet frame lengtn in bytes
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int (*probe_mesh_link)(void *priv, const u8 *addr, const u8 *eth,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* do_acs - Automatically select channel
|
||||
* @priv: Private driver interface data
|
||||
@ -4167,6 +4235,21 @@ struct wpa_driver_ops {
|
||||
* Returns: 0 on success, < 0 on failure
|
||||
*/
|
||||
int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
|
||||
|
||||
/**
|
||||
* update_dh_ie - Update DH IE
|
||||
* @priv: Private driver interface data
|
||||
* @peer_mac: Peer MAC address
|
||||
* @reason_code: Reacon code
|
||||
* @ie: DH IE
|
||||
* @ie_len: DH IE length in bytes
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This callback is used to let the driver know the DH processing result
|
||||
* and DH IE for a pending association.
|
||||
*/
|
||||
int (*update_dh_ie)(void *priv, const u8 *peer_mac, u16 reason_code,
|
||||
const u8 *ie, size_t ie_len);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -4540,6 +4623,15 @@ enum wpa_event_type {
|
||||
* */
|
||||
EVENT_CH_SWITCH,
|
||||
|
||||
/**
|
||||
* EVENT_CH_SWITCH_STARTED - AP or GO started to switch channels
|
||||
*
|
||||
* This is a pre-switch event indicating the shortly following switch
|
||||
* of operating channels.
|
||||
*
|
||||
* Described in wpa_event_data.ch_switch
|
||||
*/
|
||||
EVENT_CH_SWITCH_STARTED,
|
||||
/**
|
||||
* EVENT_WNM - Request WNM operation
|
||||
*
|
||||
@ -4703,6 +4795,11 @@ enum wpa_event_type {
|
||||
* This event is emitted when an interface is added/removed for WDS STA.
|
||||
*/
|
||||
EVENT_WDS_STA_INTERFACE_STATUS,
|
||||
|
||||
/**
|
||||
* EVENT_UPDATE_DH - Notification of updated DH information
|
||||
*/
|
||||
EVENT_UPDATE_DH,
|
||||
};
|
||||
|
||||
|
||||
@ -5536,6 +5633,15 @@ union wpa_event_data {
|
||||
INTERFACE_REMOVED
|
||||
} istatus;
|
||||
} wds_sta_interface;
|
||||
|
||||
/**
|
||||
* struct update_dh - Data for EVENT_UPDATE_DH
|
||||
*/
|
||||
struct update_dh {
|
||||
const u8 *peer;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
} update_dh;
|
||||
};
|
||||
|
||||
/**
|
||||
|
2300
contrib/wpa/src/drivers/driver_atheros.c
Normal file
2300
contrib/wpa/src/drivers/driver_atheros.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -662,7 +662,7 @@ rtbuf_len(void)
|
||||
#undef WPA_OUI_TYPE
|
||||
|
||||
static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
|
||||
int reason_code);
|
||||
u16 reason_code);
|
||||
|
||||
static const char *
|
||||
ether_sprintf(const u8 *addr)
|
||||
@ -754,7 +754,7 @@ bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
|
||||
}
|
||||
|
||||
static int
|
||||
bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
|
||||
bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code)
|
||||
{
|
||||
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
|
||||
addr);
|
||||
@ -762,7 +762,7 @@ bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
|
||||
|
||||
static int
|
||||
bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
|
||||
int reason_code)
|
||||
u16 reason_code)
|
||||
{
|
||||
return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
|
||||
addr);
|
||||
@ -1025,7 +1025,7 @@ wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
|
||||
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, u16 reason_code)
|
||||
{
|
||||
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
|
||||
addr);
|
||||
|
@ -67,6 +67,7 @@ const char * event_to_string(enum wpa_event_type event)
|
||||
E2S(DRIVER_CLIENT_POLL_OK);
|
||||
E2S(EAPOL_TX_STATUS);
|
||||
E2S(CH_SWITCH);
|
||||
E2S(CH_SWITCH_STARTED);
|
||||
E2S(WNM);
|
||||
E2S(CONNECT_FAILED_REASON);
|
||||
E2S(DFS_RADAR_DETECTED);
|
||||
@ -87,6 +88,7 @@ const char * event_to_string(enum wpa_event_type event)
|
||||
E2S(STATION_OPMODE_CHANGED);
|
||||
E2S(INTERFACE_MAC_CHANGED);
|
||||
E2S(WDS_STA_INTERFACE_STATUS);
|
||||
E2S(UPDATE_DH);
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
|
1202
contrib/wpa/src/drivers/driver_hostap.c
Normal file
1202
contrib/wpa/src/drivers/driver_hostap.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Driver interaction with Linux MACsec kernel module
|
||||
* Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -22,6 +23,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "pae/ieee802_1x_kay.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wired_common.h"
|
||||
@ -57,6 +59,7 @@ struct macsec_drv_data {
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int ifi;
|
||||
int parent_ifi;
|
||||
int use_pae_group_addr;
|
||||
|
||||
Boolean created_link;
|
||||
|
||||
@ -1399,6 +1402,214 @@ static int macsec_drv_status(void *priv, char *buf, size_t buflen)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static void macsec_drv_handle_data(void *ctx, unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef HOSTAPD
|
||||
struct ieee8023_hdr *hdr;
|
||||
u8 *pos, *sa;
|
||||
size_t left;
|
||||
union wpa_event_data event;
|
||||
|
||||
/* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
|
||||
* 2 byte ethertype */
|
||||
if (len < 14) {
|
||||
wpa_printf(MSG_MSGDUMP, "%s: too short (%lu)",
|
||||
__func__, (unsigned long) len);
|
||||
return;
|
||||
}
|
||||
|
||||
hdr = (struct ieee8023_hdr *) buf;
|
||||
|
||||
switch (ntohs(hdr->ethertype)) {
|
||||
case ETH_P_PAE:
|
||||
wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
|
||||
sa = hdr->src;
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.new_sta.addr = sa;
|
||||
wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
left = len - sizeof(*hdr);
|
||||
drv_event_eapol_rx(ctx, sa, pos, left);
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
|
||||
ntohs(hdr->ethertype));
|
||||
break;
|
||||
}
|
||||
#endif /* HOSTAPD */
|
||||
}
|
||||
|
||||
|
||||
static void macsec_drv_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[3000];
|
||||
|
||||
len = recv(sock, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
wpa_printf(MSG_ERROR, "macsec_linux: recv: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
macsec_drv_handle_data(eloop_ctx, buf, len);
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
static int macsec_drv_init_sockets(struct macsec_drv_data *drv, u8 *own_addr)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_ll addr;
|
||||
|
||||
drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
|
||||
if (drv->common.sock < 0) {
|
||||
wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eloop_register_read_sock(drv->common.sock, macsec_drv_handle_read,
|
||||
drv->common.ctx, NULL)) {
|
||||
wpa_printf(MSG_INFO, "Could not register read socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sll_family = AF_PACKET;
|
||||
addr.sll_ifindex = ifr.ifr_ifindex;
|
||||
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
|
||||
addr.sll_ifindex);
|
||||
|
||||
if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||
{
|
||||
wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* filter multicast address */
|
||||
if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
|
||||
pae_group_addr, 1) < 0) {
|
||||
wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
|
||||
"membership");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
|
||||
wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
|
||||
ifr.ifr_hwaddr.sa_family);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
#else /* __linux__ */
|
||||
return -1;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
static void * macsec_drv_hapd_init(struct hostapd_data *hapd,
|
||||
struct wpa_init_params *params)
|
||||
{
|
||||
struct macsec_drv_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(struct macsec_drv_data));
|
||||
if (drv == NULL) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Could not allocate memory for wired driver data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->common.ctx = hapd;
|
||||
os_strlcpy(drv->common.ifname, params->ifname,
|
||||
sizeof(drv->common.ifname));
|
||||
drv->use_pae_group_addr = params->use_pae_group_addr;
|
||||
|
||||
if (macsec_drv_init_sockets(drv, params->own_addr)) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void macsec_drv_hapd_deinit(void *priv)
|
||||
{
|
||||
struct macsec_drv_data *drv = priv;
|
||||
|
||||
if (drv->common.sock >= 0) {
|
||||
eloop_unregister_read_sock(drv->common.sock);
|
||||
close(drv->common.sock);
|
||||
}
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
static int macsec_drv_send_eapol(void *priv, const u8 *addr,
|
||||
const u8 *data, size_t data_len, int encrypt,
|
||||
const u8 *own_addr, u32 flags)
|
||||
{
|
||||
struct macsec_drv_data *drv = priv;
|
||||
struct ieee8023_hdr *hdr;
|
||||
size_t len;
|
||||
u8 *pos;
|
||||
int res;
|
||||
|
||||
len = sizeof(*hdr) + data_len;
|
||||
hdr = os_zalloc(len);
|
||||
if (hdr == NULL) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: malloc() failed (len=%lu)",
|
||||
__func__, (unsigned long) len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hdr->src, own_addr, ETH_ALEN);
|
||||
hdr->ethertype = htons(ETH_P_PAE);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
os_memcpy(pos, data, data_len);
|
||||
|
||||
res = send(drv->common.sock, (u8 *) hdr, len, 0);
|
||||
os_free(hdr);
|
||||
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"%s: packet len: %lu - failed: send: %s",
|
||||
__func__, (unsigned long) len, strerror(errno));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
|
||||
.name = "macsec_linux",
|
||||
.desc = "MACsec Ethernet driver for Linux",
|
||||
@ -1407,6 +1618,9 @@ const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
|
||||
.get_capa = driver_wired_get_capa,
|
||||
.init = macsec_drv_wpa_init,
|
||||
.deinit = macsec_drv_wpa_deinit,
|
||||
.hapd_init = macsec_drv_hapd_init,
|
||||
.hapd_deinit = macsec_drv_hapd_deinit,
|
||||
.hapd_send_eapol = macsec_drv_send_eapol,
|
||||
|
||||
.macsec_init = macsec_drv_macsec_init,
|
||||
.macsec_deinit = macsec_drv_macsec_deinit,
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
|
||||
* Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -29,6 +30,7 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "common/defs.h"
|
||||
#include "common/ieee802_1x_defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "pae/ieee802_1x_kay.h"
|
||||
#include "driver.h"
|
||||
#include "driver_wired_common.h"
|
||||
@ -64,6 +66,7 @@ struct channel_map {
|
||||
struct macsec_qca_data {
|
||||
struct driver_wired_common_data common;
|
||||
|
||||
int use_pae_group_addr;
|
||||
u32 secy_id;
|
||||
|
||||
/* shadow */
|
||||
@ -126,6 +129,134 @@ static void __macsec_drv_deinit(struct macsec_qca_data *drv)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static void macsec_qca_handle_data(void *ctx, unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef HOSTAPD
|
||||
struct ieee8023_hdr *hdr;
|
||||
u8 *pos, *sa;
|
||||
size_t left;
|
||||
union wpa_event_data event;
|
||||
|
||||
/* at least 6 bytes src macaddress, 6 bytes dst macaddress
|
||||
* and 2 bytes ethertype
|
||||
*/
|
||||
if (len < 14) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"macsec_qca_handle_data: too short (%lu)",
|
||||
(unsigned long) len);
|
||||
return;
|
||||
}
|
||||
hdr = (struct ieee8023_hdr *) buf;
|
||||
|
||||
switch (ntohs(hdr->ethertype)) {
|
||||
case ETH_P_PAE:
|
||||
wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
|
||||
sa = hdr->src;
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.new_sta.addr = sa;
|
||||
wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
left = len - sizeof(*hdr);
|
||||
drv_event_eapol_rx(ctx, sa, pos, left);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
|
||||
ntohs(hdr->ethertype));
|
||||
break;
|
||||
}
|
||||
#endif /* HOSTAPD */
|
||||
}
|
||||
|
||||
|
||||
static void macsec_qca_handle_read(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[3000];
|
||||
|
||||
len = recv(sock, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
wpa_printf(MSG_ERROR, "macsec_qca: recv: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
macsec_qca_handle_data(eloop_ctx, buf, len);
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_ll addr;
|
||||
|
||||
drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
|
||||
if (drv->common.sock < 0) {
|
||||
wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eloop_register_read_sock(drv->common.sock, macsec_qca_handle_read,
|
||||
drv->common.ctx, NULL)) {
|
||||
wpa_printf(MSG_INFO, "Could not register read socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sll_family = AF_PACKET;
|
||||
addr.sll_ifindex = ifr.ifr_ifindex;
|
||||
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
|
||||
addr.sll_ifindex);
|
||||
|
||||
if (bind(drv->common.sock, (struct sockaddr *) &addr,
|
||||
sizeof(addr)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "macsec_qca: bind: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* filter multicast address */
|
||||
if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
|
||||
pae_group_addr, 1) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"macsec_qca_init_sockets: Failed to add multicast group membership");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
|
||||
wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
|
||||
ifr.ifr_hwaddr.sa_family);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
#else /* __linux__ */
|
||||
return -1;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
static void * macsec_qca_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct macsec_qca_data *drv;
|
||||
@ -160,6 +291,97 @@ static void macsec_qca_deinit(void *priv)
|
||||
}
|
||||
|
||||
|
||||
static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
|
||||
struct wpa_init_params *params)
|
||||
{
|
||||
struct macsec_qca_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(struct macsec_qca_data));
|
||||
if (!drv) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Could not allocate memory for macsec_qca driver data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Board specific settings */
|
||||
if (os_memcmp("eth2", params->ifname, 4) == 0)
|
||||
drv->secy_id = 1;
|
||||
else if (os_memcmp("eth3", params->ifname, 4) == 0)
|
||||
drv->secy_id = 2;
|
||||
else if (os_memcmp("eth4", params->ifname, 4) == 0)
|
||||
drv->secy_id = 0;
|
||||
else if (os_memcmp("eth5", params->ifname, 4) == 0)
|
||||
drv->secy_id = 1;
|
||||
else
|
||||
drv->secy_id = -1;
|
||||
|
||||
drv->common.ctx = hapd;
|
||||
os_strlcpy(drv->common.ifname, params->ifname,
|
||||
sizeof(drv->common.ifname));
|
||||
drv->use_pae_group_addr = params->use_pae_group_addr;
|
||||
|
||||
if (macsec_qca_init_sockets(drv, params->own_addr)) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void macsec_qca_hapd_deinit(void *priv)
|
||||
{
|
||||
struct macsec_qca_data *drv = priv;
|
||||
|
||||
if (drv->common.sock >= 0) {
|
||||
eloop_unregister_read_sock(drv->common.sock);
|
||||
close(drv->common.sock);
|
||||
}
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
static int macsec_qca_send_eapol(void *priv, const u8 *addr,
|
||||
const u8 *data, size_t data_len, int encrypt,
|
||||
const u8 *own_addr, u32 flags)
|
||||
{
|
||||
struct macsec_qca_data *drv = priv;
|
||||
struct ieee8023_hdr *hdr;
|
||||
size_t len;
|
||||
u8 *pos;
|
||||
int res;
|
||||
|
||||
len = sizeof(*hdr) + data_len;
|
||||
hdr = os_zalloc(len);
|
||||
if (!hdr) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"malloc() failed for macsec_qca_send_eapol(len=%lu)",
|
||||
(unsigned long) len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hdr->src, own_addr, ETH_ALEN);
|
||||
hdr->ethertype = htons(ETH_P_PAE);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
os_memcpy(pos, data, data_len);
|
||||
|
||||
res = send(drv->common.sock, (u8 *) hdr, len, 0);
|
||||
os_free(hdr);
|
||||
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"macsec_qca_send_eapol - packet len: %lu - failed: send: %s",
|
||||
(unsigned long) len, strerror(errno));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int macsec_qca_macsec_init(void *priv, struct macsec_init_params *params)
|
||||
{
|
||||
struct macsec_qca_data *drv = priv;
|
||||
@ -800,6 +1022,9 @@ const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
|
||||
.get_capa = driver_wired_get_capa,
|
||||
.init = macsec_qca_init,
|
||||
.deinit = macsec_qca_deinit,
|
||||
.hapd_init = macsec_qca_hapd_init,
|
||||
.hapd_deinit = macsec_qca_hapd_deinit,
|
||||
.hapd_send_eapol = macsec_qca_send_eapol,
|
||||
|
||||
.macsec_init = macsec_qca_macsec_init,
|
||||
.macsec_deinit = macsec_qca_macsec_deinit,
|
||||
|
@ -720,7 +720,7 @@ static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
|
||||
|
||||
|
||||
static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
u16 reason_code)
|
||||
{
|
||||
struct wpa_driver_ndis_data *drv = priv;
|
||||
return wpa_driver_ndis_disconnect(drv);
|
||||
|
@ -83,6 +83,12 @@ struct i802_bss {
|
||||
u8 rand_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct drv_nl80211_if_info {
|
||||
int ifindex;
|
||||
/* the AP/AP_VLAN iface that is in this bridge */
|
||||
int reason;
|
||||
};
|
||||
|
||||
struct wpa_driver_nl80211_data {
|
||||
struct nl80211_global *global;
|
||||
struct dl_list list;
|
||||
@ -163,7 +169,6 @@ struct wpa_driver_nl80211_data {
|
||||
unsigned int scan_vendor_cmd_avail:1;
|
||||
unsigned int connect_reassoc:1;
|
||||
unsigned int set_wifi_conf_vendor_cmd_avail:1;
|
||||
unsigned int he_capab_vendor_cmd_avail:1;
|
||||
unsigned int fetch_bss_trans_status:1;
|
||||
unsigned int roam_vendor_cmd_avail:1;
|
||||
unsigned int get_supported_akm_suites_avail:1;
|
||||
@ -188,11 +193,8 @@ struct wpa_driver_nl80211_data {
|
||||
|
||||
struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
|
||||
|
||||
int default_if_indices[16];
|
||||
/* the AP/AP_VLAN iface that is in this bridge */
|
||||
int default_if_indices_reason[16];
|
||||
int *if_indices;
|
||||
int *if_indices_reason;
|
||||
struct drv_nl80211_if_info default_if_indices[16];
|
||||
struct drv_nl80211_if_info *if_indices;
|
||||
int num_if_indices;
|
||||
|
||||
/* From failed authentication command */
|
||||
@ -215,8 +217,6 @@ struct wpa_driver_nl80211_data {
|
||||
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
|
||||
*/
|
||||
int last_scan_cmd;
|
||||
|
||||
struct he_capabilities he_capab;
|
||||
};
|
||||
|
||||
struct nl_msg;
|
||||
|
@ -778,9 +778,6 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
|
||||
case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
|
||||
drv->set_wifi_conf_vendor_cmd_avail = 1;
|
||||
break;
|
||||
case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
|
||||
drv->he_capab_vendor_cmd_avail = 1;
|
||||
break;
|
||||
case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS:
|
||||
drv->fetch_bss_trans_status = 1;
|
||||
break;
|
||||
@ -1082,100 +1079,6 @@ static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv)
|
||||
}
|
||||
|
||||
|
||||
static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||
struct he_capabilities *he_capab = arg;
|
||||
struct nlattr *nl_vend;
|
||||
struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
|
||||
size_t len;
|
||||
|
||||
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||
genlmsg_attrlen(gnlh, 0), NULL);
|
||||
|
||||
if (!tb[NL80211_ATTR_VENDOR_DATA])
|
||||
return NL_SKIP;
|
||||
|
||||
nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
|
||||
nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
|
||||
nla_data(nl_vend), nla_len(nl_vend), NULL);
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
|
||||
u8 he_supported;
|
||||
|
||||
he_supported = nla_get_u8(
|
||||
tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
|
||||
wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
|
||||
he_supported);
|
||||
he_capab->he_supported = he_supported;
|
||||
if (!he_supported)
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
|
||||
len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
|
||||
|
||||
if (len > sizeof(he_capab->phy_cap))
|
||||
len = sizeof(he_capab->phy_cap);
|
||||
os_memcpy(he_capab->phy_cap,
|
||||
nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
|
||||
len);
|
||||
}
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
|
||||
he_capab->mac_cap =
|
||||
nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
|
||||
he_capab->mcs =
|
||||
nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
|
||||
he_capab->ppet.numss_m1 =
|
||||
nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
|
||||
he_capab->ppet.ru_count =
|
||||
nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
|
||||
|
||||
if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
|
||||
len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
|
||||
|
||||
if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
|
||||
len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
|
||||
os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
|
||||
nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
|
||||
len);
|
||||
}
|
||||
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
|
||||
static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
int ret;
|
||||
|
||||
if (!drv->he_capab_vendor_cmd_avail)
|
||||
return;
|
||||
|
||||
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
|
||||
QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES)) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
|
||||
&drv->he_capab);
|
||||
if (!ret && drv->he_capab.he_supported)
|
||||
drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
|
||||
}
|
||||
|
||||
|
||||
struct features_info {
|
||||
u8 *flags;
|
||||
size_t flags_len;
|
||||
@ -1373,7 +1276,6 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
|
||||
if (!(info.capa->flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD))
|
||||
qca_nl80211_check_dfs_capa(drv);
|
||||
qca_nl80211_get_features(drv);
|
||||
qca_nl80211_check_he_capab(drv);
|
||||
|
||||
/*
|
||||
* To enable offchannel simultaneous support in wpa_supplicant, the
|
||||
@ -1492,6 +1394,57 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
|
||||
chan->dfs_cac_ms = nla_get_u32(
|
||||
tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
|
||||
}
|
||||
|
||||
chan->wmm_rules_valid = 0;
|
||||
if (tb_freq[NL80211_FREQUENCY_ATTR_WMM]) {
|
||||
static struct nla_policy wmm_policy[NL80211_WMMR_MAX + 1] = {
|
||||
[NL80211_WMMR_CW_MIN] = { .type = NLA_U16 },
|
||||
[NL80211_WMMR_CW_MAX] = { .type = NLA_U16 },
|
||||
[NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
|
||||
[NL80211_WMMR_TXOP] = { .type = NLA_U16 },
|
||||
};
|
||||
struct nlattr *nl_wmm;
|
||||
struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
|
||||
int rem_wmm, ac, count = 0;
|
||||
|
||||
nla_for_each_nested(nl_wmm, tb_freq[NL80211_FREQUENCY_ATTR_WMM],
|
||||
rem_wmm) {
|
||||
if (nla_parse_nested(tb_wmm, NL80211_WMMR_MAX, nl_wmm,
|
||||
wmm_policy)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Failed to parse WMM rules attribute");
|
||||
return;
|
||||
}
|
||||
if (!tb_wmm[NL80211_WMMR_CW_MIN] ||
|
||||
!tb_wmm[NL80211_WMMR_CW_MAX] ||
|
||||
!tb_wmm[NL80211_WMMR_AIFSN] ||
|
||||
!tb_wmm[NL80211_WMMR_TXOP]) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Channel is missing WMM rule attribute");
|
||||
return;
|
||||
}
|
||||
ac = nl_wmm->nla_type;
|
||||
if (ac < 0 || ac >= WMM_AC_NUM) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Invalid AC value %d", ac);
|
||||
return;
|
||||
}
|
||||
|
||||
chan->wmm_rules[ac].min_cwmin =
|
||||
nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
|
||||
chan->wmm_rules[ac].min_cwmax =
|
||||
nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]);
|
||||
chan->wmm_rules[ac].min_aifs =
|
||||
nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
|
||||
chan->wmm_rules[ac].max_txop =
|
||||
nla_get_u16(tb_wmm[NL80211_WMMR_TXOP]) / 32;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Set valid flag if all the AC rules are present */
|
||||
if (count == WMM_AC_NUM)
|
||||
chan->wmm_rules_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1598,6 +1551,101 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
|
||||
}
|
||||
|
||||
|
||||
static void phy_info_iftype_copy(struct he_capabilities *he_capab,
|
||||
enum ieee80211_op_mode opmode,
|
||||
struct nlattr **tb, struct nlattr **tb_flags)
|
||||
{
|
||||
enum nl80211_iftype iftype;
|
||||
size_t len;
|
||||
|
||||
switch (opmode) {
|
||||
case IEEE80211_MODE_INFRA:
|
||||
iftype = NL80211_IFTYPE_STATION;
|
||||
break;
|
||||
case IEEE80211_MODE_IBSS:
|
||||
iftype = NL80211_IFTYPE_ADHOC;
|
||||
break;
|
||||
case IEEE80211_MODE_AP:
|
||||
iftype = NL80211_IFTYPE_AP;
|
||||
break;
|
||||
case IEEE80211_MODE_MESH:
|
||||
iftype = NL80211_IFTYPE_MESH_POINT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nla_get_flag(tb_flags[iftype]))
|
||||
return;
|
||||
|
||||
he_capab->he_supported = 1;
|
||||
|
||||
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]) {
|
||||
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]);
|
||||
|
||||
if (len > sizeof(he_capab->phy_cap))
|
||||
len = sizeof(he_capab->phy_cap);
|
||||
os_memcpy(he_capab->phy_cap,
|
||||
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY]),
|
||||
len);
|
||||
}
|
||||
|
||||
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]) {
|
||||
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]);
|
||||
|
||||
if (len > sizeof(he_capab->mac_cap))
|
||||
len = sizeof(he_capab->mac_cap);
|
||||
os_memcpy(he_capab->mac_cap,
|
||||
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC]),
|
||||
len);
|
||||
}
|
||||
|
||||
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]) {
|
||||
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]);
|
||||
|
||||
if (len > sizeof(he_capab->mcs))
|
||||
len = sizeof(he_capab->mcs);
|
||||
os_memcpy(he_capab->mcs,
|
||||
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET]),
|
||||
len);
|
||||
}
|
||||
|
||||
if (tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]) {
|
||||
len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]);
|
||||
|
||||
if (len > sizeof(he_capab->ppet))
|
||||
len = sizeof(he_capab->ppet);
|
||||
os_memcpy(&he_capab->ppet,
|
||||
nla_data(tb[NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE]),
|
||||
len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int phy_info_iftype(struct hostapd_hw_modes *mode,
|
||||
struct nlattr *nl_iftype)
|
||||
{
|
||||
struct nlattr *tb[NL80211_BAND_IFTYPE_ATTR_MAX + 1];
|
||||
struct nlattr *tb_flags[NL80211_IFTYPE_MAX + 1];
|
||||
unsigned int i;
|
||||
|
||||
nla_parse(tb, NL80211_BAND_IFTYPE_ATTR_MAX,
|
||||
nla_data(nl_iftype), nla_len(nl_iftype), NULL);
|
||||
|
||||
if (!tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES])
|
||||
return NL_STOP;
|
||||
|
||||
if (nla_parse_nested(tb_flags, NL80211_IFTYPE_MAX,
|
||||
tb[NL80211_BAND_IFTYPE_ATTR_IFTYPES], NULL))
|
||||
return NL_STOP;
|
||||
|
||||
for (i = 0; i < IEEE80211_MODE_NUM; i++)
|
||||
phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
|
||||
static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
|
||||
{
|
||||
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
|
||||
@ -1654,6 +1702,19 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tb_band[NL80211_BAND_ATTR_IFTYPE_DATA]) {
|
||||
struct nlattr *nl_iftype;
|
||||
int rem_band;
|
||||
|
||||
nla_for_each_nested(nl_iftype,
|
||||
tb_band[NL80211_BAND_ATTR_IFTYPE_DATA],
|
||||
rem_band) {
|
||||
ret = phy_info_iftype(mode, nl_iftype);
|
||||
if (ret != NL_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
|
||||
C2S(NL80211_CMD_EXTERNAL_AUTH)
|
||||
C2S(NL80211_CMD_STA_OPMODE_CHANGED)
|
||||
C2S(NL80211_CMD_CONTROL_PORT_FRAME)
|
||||
C2S(NL80211_CMD_UPDATE_OWE_INFO)
|
||||
default:
|
||||
return "NL80211_CMD_UNKNOWN";
|
||||
}
|
||||
@ -534,7 +535,8 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
|
||||
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlattr *ifindex, struct nlattr *freq,
|
||||
struct nlattr *type, struct nlattr *bw,
|
||||
struct nlattr *cf1, struct nlattr *cf2)
|
||||
struct nlattr *cf1, struct nlattr *cf2,
|
||||
int finished)
|
||||
{
|
||||
struct i802_bss *bss;
|
||||
union wpa_event_data data;
|
||||
@ -542,7 +544,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
|
||||
int chan_offset = 0;
|
||||
int ifidx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event",
|
||||
finished ? "" : " started");
|
||||
|
||||
if (!freq)
|
||||
return;
|
||||
@ -593,10 +596,12 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
|
||||
if (cf2)
|
||||
data.ch_switch.cf2 = nla_get_u32(cf2);
|
||||
|
||||
bss->freq = data.ch_switch.freq;
|
||||
if (finished)
|
||||
bss->freq = data.ch_switch.freq;
|
||||
drv->assoc_freq = data.ch_switch.freq;
|
||||
|
||||
wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
|
||||
wpa_supplicant_event(bss->ctx, finished ?
|
||||
EVENT_CH_SWITCH : EVENT_CH_SWITCH_STARTED, &data);
|
||||
}
|
||||
|
||||
|
||||
@ -1101,6 +1106,29 @@ static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
|
||||
}
|
||||
|
||||
|
||||
static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv,
|
||||
struct i802_bss *bss,
|
||||
struct nlattr *tb[])
|
||||
{
|
||||
union wpa_event_data data;
|
||||
|
||||
if (!is_ap_interface(drv->nlmode))
|
||||
return;
|
||||
if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
data.update_dh.peer = nla_data(tb[NL80211_ATTR_MAC]);
|
||||
data.update_dh.ie = nla_data(tb[NL80211_ATTR_IE]);
|
||||
data.update_dh.ie_len = nla_len(tb[NL80211_ATTR_IE]);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "nl80211: DH event - peer " MACSTR,
|
||||
MAC2STR(data.update_dh.peer));
|
||||
|
||||
wpa_supplicant_event(bss->ctx, EVENT_UPDATE_DH, &data);
|
||||
}
|
||||
|
||||
|
||||
static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
|
||||
struct nlattr *tb[], int external_scan)
|
||||
{
|
||||
@ -2508,6 +2536,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||
tb[NL80211_ATTR_PMK],
|
||||
tb[NL80211_ATTR_PMKID]);
|
||||
break;
|
||||
case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
|
||||
mlme_event_ch_switch(drv,
|
||||
tb[NL80211_ATTR_IFINDEX],
|
||||
tb[NL80211_ATTR_WIPHY_FREQ],
|
||||
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
|
||||
tb[NL80211_ATTR_CHANNEL_WIDTH],
|
||||
tb[NL80211_ATTR_CENTER_FREQ1],
|
||||
tb[NL80211_ATTR_CENTER_FREQ2],
|
||||
0);
|
||||
break;
|
||||
case NL80211_CMD_CH_SWITCH_NOTIFY:
|
||||
mlme_event_ch_switch(drv,
|
||||
tb[NL80211_ATTR_IFINDEX],
|
||||
@ -2515,7 +2553,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
|
||||
tb[NL80211_ATTR_CHANNEL_WIDTH],
|
||||
tb[NL80211_ATTR_CENTER_FREQ1],
|
||||
tb[NL80211_ATTR_CENTER_FREQ2]);
|
||||
tb[NL80211_ATTR_CENTER_FREQ2],
|
||||
1);
|
||||
break;
|
||||
case NL80211_CMD_DISCONNECT:
|
||||
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
|
||||
@ -2586,6 +2625,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
|
||||
case NL80211_CMD_STA_OPMODE_CHANGED:
|
||||
nl80211_sta_opmode_change_event(drv, tb);
|
||||
break;
|
||||
case NL80211_CMD_UPDATE_OWE_INFO:
|
||||
mlme_event_dh_event(drv, bss, tb);
|
||||
break;
|
||||
default:
|
||||
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
|
||||
"(cmd=%d)", cmd);
|
||||
@ -2634,8 +2676,9 @@ int process_global_event(struct nl_msg *msg, void *arg)
|
||||
}
|
||||
}
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
|
||||
gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
|
||||
"nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx)",
|
||||
gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
|
||||
ifidx, (long long unsigned int) wdev_id);
|
||||
}
|
||||
|
||||
return NL_SKIP;
|
||||
|
@ -368,7 +368,7 @@ static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
|
||||
|
||||
|
||||
static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
u16 reason_code)
|
||||
{
|
||||
//struct wpa_driver_privsep_data *drv = priv;
|
||||
wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
|
||||
|
6467
contrib/wpa/src/drivers/nl80211_copy.h
Normal file
6467
contrib/wpa/src/drivers/nl80211_copy.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -92,6 +92,7 @@ typedef enum {
|
||||
EAP_TYPE_GPSK = 51 /* RFC 5433 */,
|
||||
EAP_TYPE_PWD = 52 /* RFC 5931 */,
|
||||
EAP_TYPE_EKE = 53 /* RFC 6124 */,
|
||||
EAP_TYPE_TEAP = 55 /* RFC 7170 */,
|
||||
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
|
||||
} EapType;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "includes.h"
|
||||
#include "common.h"
|
||||
#include "utils/const_time.h"
|
||||
#include "common/dragonfly.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "eap_defs.h"
|
||||
@ -85,20 +86,11 @@ static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label,
|
||||
}
|
||||
|
||||
|
||||
static int eap_pwd_suitable_group(u16 num)
|
||||
{
|
||||
/* Do not allow ECC groups with prime under 256 bits based on guidance
|
||||
* for the similar design in SAE. */
|
||||
return num == 19 || num == 20 || num == 21 ||
|
||||
num == 28 || num == 29 || num == 30;
|
||||
}
|
||||
|
||||
|
||||
EAP_PWD_group * get_eap_pwd_group(u16 num)
|
||||
{
|
||||
EAP_PWD_group *grp;
|
||||
|
||||
if (!eap_pwd_suitable_group(num)) {
|
||||
if (!dragonfly_suitable_group(num, 1)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unsuitable group %u", num);
|
||||
return NULL;
|
||||
}
|
||||
@ -119,15 +111,6 @@ EAP_PWD_group * get_eap_pwd_group(u16 num)
|
||||
}
|
||||
|
||||
|
||||
static void buf_shift_right(u8 *buf, size_t len, size_t bits)
|
||||
{
|
||||
size_t i;
|
||||
for (i = len - 1; i > 0; i--)
|
||||
buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
|
||||
buf[0] >>= bits;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compute a "random" secret point on an elliptic curve based
|
||||
* on the password and identities.
|
||||
@ -138,22 +121,24 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
const u8 *id_peer, size_t id_peer_len,
|
||||
const u8 *token)
|
||||
{
|
||||
struct crypto_bignum *qr = NULL, *qnr = NULL, *one = NULL;
|
||||
struct crypto_bignum *qr_or_qnr = NULL;
|
||||
struct crypto_bignum *qr = NULL, *qnr = NULL;
|
||||
u8 qr_bin[MAX_ECC_PRIME_LEN];
|
||||
u8 qnr_bin[MAX_ECC_PRIME_LEN];
|
||||
u8 qr_or_qnr_bin[MAX_ECC_PRIME_LEN];
|
||||
u8 x_bin[MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *tmp1 = NULL, *tmp2 = NULL, *pm1 = NULL;
|
||||
u8 prime_bin[MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *tmp2 = NULL;
|
||||
struct crypto_hash *hash;
|
||||
unsigned char pwe_digest[SHA256_MAC_LEN], *prfbuf = NULL, ctr;
|
||||
int ret = 0, check, res;
|
||||
int ret = 0, res;
|
||||
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
|
||||
* mask */
|
||||
size_t primebytelen = 0, primebitlen;
|
||||
struct crypto_bignum *x_candidate = NULL;
|
||||
const struct crypto_bignum *prime;
|
||||
u8 mask, found_ctr = 0, is_odd = 0;
|
||||
u8 found_ctr = 0, is_odd = 0;
|
||||
int cmp_prime;
|
||||
unsigned int in_range;
|
||||
|
||||
if (grp->pwe)
|
||||
return -1;
|
||||
@ -161,41 +146,26 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
os_memset(x_bin, 0, sizeof(x_bin));
|
||||
|
||||
prime = crypto_ec_get_prime(grp->group);
|
||||
primebitlen = crypto_ec_prime_len_bits(grp->group);
|
||||
primebytelen = crypto_ec_prime_len(grp->group);
|
||||
if (crypto_bignum_to_bin(prime, prime_bin, sizeof(prime_bin),
|
||||
primebytelen) < 0)
|
||||
return -1;
|
||||
grp->pwe = crypto_ec_point_init(grp->group);
|
||||
tmp1 = crypto_bignum_init();
|
||||
pm1 = crypto_bignum_init();
|
||||
one = crypto_bignum_init_set((const u8 *) "\x01", 1);
|
||||
if (!grp->pwe || !tmp1 || !pm1 || !one) {
|
||||
if (!grp->pwe) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
primebitlen = crypto_ec_prime_len_bits(grp->group);
|
||||
primebytelen = crypto_ec_prime_len(grp->group);
|
||||
if ((prfbuf = os_malloc(primebytelen)) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
|
||||
"buffer");
|
||||
goto fail;
|
||||
}
|
||||
if (crypto_bignum_sub(prime, one, pm1) < 0)
|
||||
goto fail;
|
||||
|
||||
/* get a random quadratic residue and nonresidue */
|
||||
while (!qr || !qnr) {
|
||||
if (crypto_bignum_rand(tmp1, prime) < 0)
|
||||
goto fail;
|
||||
res = crypto_bignum_legendre(tmp1, prime);
|
||||
if (!qr && res == 1) {
|
||||
qr = tmp1;
|
||||
tmp1 = crypto_bignum_init();
|
||||
} else if (!qnr && res == -1) {
|
||||
qnr = tmp1;
|
||||
tmp1 = crypto_bignum_init();
|
||||
}
|
||||
if (!tmp1)
|
||||
goto fail;
|
||||
}
|
||||
if (crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
|
||||
if (dragonfly_get_random_qr_qnr(prime, &qr, &qnr) < 0 ||
|
||||
crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin),
|
||||
primebytelen) < 0 ||
|
||||
crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin),
|
||||
primebytelen) < 0)
|
||||
@ -237,6 +207,13 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
if (primebitlen % 8)
|
||||
buf_shift_right(prfbuf, primebytelen,
|
||||
8 - primebitlen % 8);
|
||||
cmp_prime = const_time_memcmp(prfbuf, prime_bin, primebytelen);
|
||||
/* Create a const_time mask for selection based on prf result
|
||||
* being smaller than prime. */
|
||||
in_range = const_time_fill_msb((unsigned int) cmp_prime);
|
||||
/* The algorithm description would skip the next steps if
|
||||
* cmp_prime >= 0, but go through them regardless to minimize
|
||||
* externally observable differences in behavior. */
|
||||
|
||||
crypto_bignum_deinit(x_candidate, 1);
|
||||
x_candidate = crypto_bignum_init_set(prfbuf, primebytelen);
|
||||
@ -246,9 +223,6 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (crypto_bignum_cmp(x_candidate, prime) >= 0)
|
||||
continue;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-pwd: x_candidate",
|
||||
prfbuf, primebytelen);
|
||||
const_time_select_bin(found, x_bin, prfbuf, primebytelen,
|
||||
@ -264,46 +238,16 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
if (!tmp2)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* mask tmp2 so doing legendre won't leak timing info
|
||||
*
|
||||
* tmp1 is a random number between 1 and p-1
|
||||
*/
|
||||
if (crypto_bignum_rand(tmp1, pm1) < 0 ||
|
||||
crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0 ||
|
||||
crypto_bignum_mulmod(tmp2, tmp1, prime, tmp2) < 0)
|
||||
res = dragonfly_is_quadratic_residue_blind(grp->group, qr_bin,
|
||||
qnr_bin, tmp2);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Now tmp2 (y^2) is masked, all values between 1 and p-1
|
||||
* are equally probable. Multiplying by r^2 does not change
|
||||
* whether or not tmp2 is a quadratic residue, just masks it.
|
||||
*
|
||||
* Flip a coin, multiply by the random quadratic residue or the
|
||||
* random quadratic nonresidue and record heads or tails.
|
||||
*/
|
||||
mask = const_time_eq_u8(crypto_bignum_is_odd(tmp1), 1);
|
||||
check = const_time_select_s8(mask, 1, -1);
|
||||
const_time_select_bin(mask, qr_bin, qnr_bin, primebytelen,
|
||||
qr_or_qnr_bin);
|
||||
crypto_bignum_deinit(qr_or_qnr, 1);
|
||||
qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, primebytelen);
|
||||
if (!qr_or_qnr ||
|
||||
crypto_bignum_mulmod(tmp2, qr_or_qnr, prime, tmp2) < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Now it's safe to do legendre, if check is 1 then it's
|
||||
* a straightforward test (multiplying by qr does not
|
||||
* change result), if check is -1 then it's the opposite test
|
||||
* (multiplying a qr by qnr would make a qnr).
|
||||
*/
|
||||
res = crypto_bignum_legendre(tmp2, prime);
|
||||
if (res == -2)
|
||||
goto fail;
|
||||
mask = const_time_eq(res, check);
|
||||
found_ctr = const_time_select_u8(found, found_ctr, ctr);
|
||||
found |= mask;
|
||||
/* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
|
||||
* (with res converted to 0/0xff and masked with prf being below
|
||||
* prime) handles this in constant time.
|
||||
*/
|
||||
found |= (res & in_range) * 0xff;
|
||||
}
|
||||
if (found == 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
@ -344,13 +288,9 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
}
|
||||
/* cleanliness and order.... */
|
||||
crypto_bignum_deinit(x_candidate, 1);
|
||||
crypto_bignum_deinit(pm1, 0);
|
||||
crypto_bignum_deinit(tmp1, 1);
|
||||
crypto_bignum_deinit(tmp2, 1);
|
||||
crypto_bignum_deinit(qr, 1);
|
||||
crypto_bignum_deinit(qnr, 1);
|
||||
crypto_bignum_deinit(qr_or_qnr, 1);
|
||||
crypto_bignum_deinit(one, 0);
|
||||
bin_clear_free(prfbuf, primebytelen);
|
||||
os_memset(qr_bin, 0, sizeof(qr_bin));
|
||||
os_memset(qnr_bin, 0, sizeof(qnr_bin));
|
||||
@ -504,25 +444,6 @@ int eap_pwd_get_rand_mask(EAP_PWD_group *group, struct crypto_bignum *_rand,
|
||||
struct crypto_bignum *_mask,
|
||||
struct crypto_bignum *scalar)
|
||||
{
|
||||
const struct crypto_bignum *order;
|
||||
int count;
|
||||
|
||||
order = crypto_ec_get_order(group->group);
|
||||
|
||||
/* Select two random values rand,mask such that 1 < rand,mask < r and
|
||||
* rand + mask mod r > 1. */
|
||||
for (count = 0; count < 100; count++) {
|
||||
if (crypto_bignum_rand(_rand, order) == 0 &&
|
||||
!crypto_bignum_is_zero(_rand) &&
|
||||
crypto_bignum_rand(_mask, order) == 0 &&
|
||||
!crypto_bignum_is_zero(_mask) &&
|
||||
crypto_bignum_add(_rand, _mask, scalar) == 0 &&
|
||||
crypto_bignum_mod(scalar, order, scalar) == 0 &&
|
||||
!crypto_bignum_is_zero(scalar) &&
|
||||
!crypto_bignum_is_one(scalar))
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to get randomness");
|
||||
return -1;
|
||||
return dragonfly_generate_scalar(crypto_ec_get_order(group->group),
|
||||
_rand, _mask, scalar);
|
||||
}
|
||||
|
@ -945,10 +945,15 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
|
||||
if (decrypted == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef TEST_FUZZ
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Skip AES-128-CBC decryption for fuzz testing");
|
||||
#else /* TEST_FUZZ */
|
||||
if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) {
|
||||
os_free(decrypted);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* TEST_FUZZ */
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
|
||||
decrypted, encr_data_len);
|
||||
|
||||
@ -1203,3 +1208,19 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int eap_sim_anonymous_username(const u8 *id, size_t id_len)
|
||||
{
|
||||
static const char *anonymous_id_prefix = "anonymous@";
|
||||
size_t anonymous_id_len = os_strlen(anonymous_id_prefix);
|
||||
|
||||
if (id_len > anonymous_id_len &&
|
||||
os_memcmp(id, anonymous_id_prefix, anonymous_id_len) == 0)
|
||||
return 1; /* 'anonymous@realm' */
|
||||
|
||||
if (id_len > 1 && id[0] == '@')
|
||||
return 1; /* '@realm' */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -226,5 +226,6 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
|
||||
int attr_pad);
|
||||
|
||||
void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
|
||||
int eap_sim_anonymous_username(const u8 *id, size_t id_len);
|
||||
|
||||
#endif /* EAP_SIM_COMMON_H */
|
||||
|
698
contrib/wpa/src/eap_common/eap_teap_common.c
Normal file
698
contrib/wpa/src/eap_common/eap_teap_common.c
Normal file
@ -0,0 +1,698 @@
|
||||
/*
|
||||
* EAP-TEAP common helper functions (RFC 7170)
|
||||
* Copyright (c) 2008-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/sha384.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "eap_defs.h"
|
||||
#include "eap_teap_common.h"
|
||||
|
||||
|
||||
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
|
||||
{
|
||||
struct teap_tlv_hdr hdr;
|
||||
|
||||
hdr.tlv_type = host_to_be16(type);
|
||||
hdr.length = host_to_be16(len);
|
||||
wpabuf_put_data(buf, &hdr, sizeof(hdr));
|
||||
}
|
||||
|
||||
|
||||
void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len)
|
||||
{
|
||||
eap_teap_put_tlv_hdr(buf, type, len);
|
||||
wpabuf_put_data(buf, data, len);
|
||||
}
|
||||
|
||||
|
||||
void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
|
||||
const struct wpabuf *data)
|
||||
{
|
||||
eap_teap_put_tlv_hdr(buf, type, wpabuf_len(data));
|
||||
wpabuf_put_buf(buf, data);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf)
|
||||
{
|
||||
struct wpabuf *e;
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
/* Encapsulate EAP packet in EAP-Payload TLV */
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: Add EAP-Payload TLV");
|
||||
e = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + wpabuf_len(buf));
|
||||
if (!e) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EAP-TEAP: Failed to allocate memory for TLV encapsulation");
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
eap_teap_put_tlv_buf(e, TEAP_TLV_MANDATORY | TEAP_TLV_EAP_PAYLOAD, buf);
|
||||
wpabuf_free(buf);
|
||||
|
||||
/* TODO: followed by optional TLVs associated with the EAP packet */
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
static int eap_teap_tls_prf(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen)
|
||||
{
|
||||
/* TODO: TLS-PRF for TLSv1.3 */
|
||||
return tls_prf_sha256(secret, secret_len, label, seed, seed_len,
|
||||
out, outlen);
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk)
|
||||
{
|
||||
/*
|
||||
* RFC 7170, Section 5.4: EAP Master Session Key Generation
|
||||
* MSK = TLS-PRF(S-IMCK[j], "Session Key Generating Function", 64)
|
||||
*/
|
||||
|
||||
if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
|
||||
"Session Key Generating Function", (u8 *) "", 0,
|
||||
msk, EAP_TEAP_KEY_LEN) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (MSK)",
|
||||
msk, EAP_TEAP_KEY_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk)
|
||||
{
|
||||
/*
|
||||
* RFC 7170, Section 5.4: EAP Master Session Key Generation
|
||||
* EMSK = TLS-PRF(S-IMCK[j],
|
||||
* "Extended Session Key Generating Function", 64)
|
||||
*/
|
||||
|
||||
if (eap_teap_tls_prf(simck, EAP_TEAP_SIMCK_LEN,
|
||||
"Extended Session Key Generating Function",
|
||||
(u8 *) "", 0, emsk, EAP_EMSK_LEN) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Derived key (EMSK)",
|
||||
emsk, EAP_EMSK_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk)
|
||||
{
|
||||
u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
|
||||
int res;
|
||||
|
||||
/* FIX: The Basic-Password-Auth (i.e., no inner EAP) case is
|
||||
* not fully defined in RFC 7170, so this CMK derivation may
|
||||
* need to be changed if a fixed definition is eventually
|
||||
* published. For now, derive CMK[0] based on S-IMCK[0] and
|
||||
* IMSK of 32 octets of zeros. */
|
||||
os_memset(imsk, 0, 32);
|
||||
res = eap_teap_tls_prf(s_imck_msk, EAP_TEAP_SIMCK_LEN,
|
||||
"Inner Methods Compound Keys",
|
||||
imsk, 32, imck, sizeof(imck));
|
||||
if (res < 0)
|
||||
return -1;
|
||||
os_memcpy(cmk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: CMK[no-inner-EAP]",
|
||||
cmk, EAP_TEAP_CMK_LEN);
|
||||
forced_memzero(imck, sizeof(imck));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
|
||||
const u8 *msk, size_t msk_len,
|
||||
const u8 *emsk, size_t emsk_len,
|
||||
u8 *s_imck_msk, u8 *cmk_msk,
|
||||
u8 *s_imck_emsk, u8 *cmk_emsk)
|
||||
{
|
||||
u8 imsk[64], imck[EAP_TEAP_IMCK_LEN];
|
||||
int res;
|
||||
|
||||
/*
|
||||
* RFC 7170, Section 5.2:
|
||||
* IMSK = First 32 octets of TLS-PRF(EMSK, "TEAPbindkey@ietf.org" |
|
||||
* "\0" | 64)
|
||||
* (if EMSK is not available, MSK is used instead; if neither is
|
||||
* available, IMSK is 32 octets of zeros; MSK is truncated to 32 octets
|
||||
* or padded to 32 octets, if needed)
|
||||
* (64 is encoded as a 2-octet field in network byte order)
|
||||
*
|
||||
* S-IMCK[0] = session_key_seed
|
||||
* IMCK[j] = TLS-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
|
||||
* IMSK[j], 60)
|
||||
* S-IMCK[j] = first 40 octets of IMCK[j]
|
||||
* CMK[j] = last 20 octets of IMCK[j]
|
||||
*/
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK[j]", msk, msk_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK[j]", emsk, emsk_len);
|
||||
|
||||
if (emsk && emsk_len > 0) {
|
||||
u8 context[3];
|
||||
|
||||
context[0] = 0;
|
||||
context[1] = 0;
|
||||
context[2] = 64;
|
||||
if (eap_teap_tls_prf(emsk, emsk_len, "TEAPbindkey@ietf.org",
|
||||
context, sizeof(context), imsk, 64) < 0)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from EMSK",
|
||||
imsk, 32);
|
||||
|
||||
res = eap_teap_tls_prf(prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
|
||||
"Inner Methods Compound Keys",
|
||||
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
|
||||
forced_memzero(imsk, sizeof(imsk));
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
os_memcpy(s_imck_emsk, imck, EAP_TEAP_SIMCK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK S-IMCK[j]",
|
||||
s_imck_emsk, EAP_TEAP_SIMCK_LEN);
|
||||
os_memcpy(cmk_emsk, &imck[EAP_TEAP_SIMCK_LEN],
|
||||
EAP_TEAP_CMK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: EMSK CMK[j]",
|
||||
cmk_emsk, EAP_TEAP_CMK_LEN);
|
||||
forced_memzero(imck, EAP_TEAP_IMCK_LEN);
|
||||
}
|
||||
|
||||
if (msk && msk_len > 0) {
|
||||
size_t copy_len = msk_len;
|
||||
|
||||
os_memset(imsk, 0, 32); /* zero pad, if needed */
|
||||
if (copy_len > 32)
|
||||
copy_len = 32;
|
||||
os_memcpy(imsk, msk, copy_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: IMSK from MSK", imsk, 32);
|
||||
} else {
|
||||
os_memset(imsk, 0, 32);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
|
||||
}
|
||||
|
||||
res = eap_teap_tls_prf(prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
|
||||
"Inner Methods Compound Keys",
|
||||
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
|
||||
forced_memzero(imsk, sizeof(imsk));
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
os_memcpy(s_imck_msk, imck, EAP_TEAP_SIMCK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK S-IMCK[j]",
|
||||
s_imck_msk, EAP_TEAP_SIMCK_LEN);
|
||||
os_memcpy(cmk_msk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: MSK CMK[j]",
|
||||
cmk_msk, EAP_TEAP_CMK_LEN);
|
||||
forced_memzero(imck, EAP_TEAP_IMCK_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_cipher_suite_match(const u16 *list, size_t count, u16 cs)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (list[i] == cs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_cipher_suite_mac_sha1(u16 cs)
|
||||
{
|
||||
static const u16 sha1_cs[] = {
|
||||
0x0005, 0x0007, 0x000a, 0x000d, 0x0010, 0x0013, 0x0016, 0x001b,
|
||||
0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
|
||||
0x0037, 0x0038, 0x0039, 0x003a, 0x0041, 0x0042, 0x0043, 0x0044,
|
||||
0x0045, 0x0046, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089,
|
||||
0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091,
|
||||
0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099,
|
||||
0x009a, 0x009b,
|
||||
0xc002, 0xc003, 0xc004, 0xc005, 0xc007, 0xc008, 0xc009, 0xc009,
|
||||
0xc00a, 0xc00c, 0xc00d, 0xc00e, 0xc00f, 0xc011, 0xc012, 0xc013,
|
||||
0xc014, 0xc016, 0xc017, 0xc018, 0xc019, 0xc01a, 0xc01b, 0xc01c,
|
||||
0xc014, 0xc01e, 0xc01f, 0xc020, 0xc021, 0xc022, 0xc033, 0xc034,
|
||||
0xc035, 0xc036
|
||||
};
|
||||
|
||||
return tls_cipher_suite_match(sha1_cs, ARRAY_SIZE(sha1_cs), cs);
|
||||
}
|
||||
|
||||
|
||||
static int tls_cipher_suite_mac_sha256(u16 cs)
|
||||
{
|
||||
static const u16 sha256_cs[] = {
|
||||
0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0067, 0x0068, 0x0069,
|
||||
0x006a, 0x006b, 0x006c, 0x006d, 0x009c, 0x009e, 0x00a0, 0x00a2,
|
||||
0x00a4, 0x00a6, 0x00a8, 0x00aa, 0x00ac, 0x00ae, 0x00b2, 0x00b6,
|
||||
0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bd, 0x00be, 0x00be,
|
||||
0x00bf, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5,
|
||||
0x1301, 0x1303, 0x1304, 0x1305,
|
||||
0xc023, 0xc025, 0xc027, 0xc029, 0xc02b, 0xc02d, 0xc02f, 0xc031,
|
||||
0xc037, 0xc03c, 0xc03e, 0xc040, 0xc040, 0xc042, 0xc044, 0xc046,
|
||||
0xc048, 0xc04a, 0xc04c, 0xc04e, 0xc050, 0xc052, 0xc054, 0xc056,
|
||||
0xc058, 0xc05a, 0xc05c, 0xc05e, 0xc060, 0xc062, 0xc064, 0xc066,
|
||||
0xc068, 0xc06a, 0xc06c, 0xc06e, 0xc070, 0xc072, 0xc074, 0xc076,
|
||||
0xc078, 0xc07a, 0xc07c, 0xc07e, 0xc080, 0xc082, 0xc084, 0xc086,
|
||||
0xc088, 0xc08a, 0xc08c, 0xc08e, 0xc090, 0xc092, 0xc094, 0xc096,
|
||||
0xc098, 0xc09a, 0xc0b0, 0xc0b2, 0xc0b4,
|
||||
0xcca8, 0xcca9, 0xccaa, 0xccab, 0xccac, 0xccad, 0xccae,
|
||||
0xd001, 0xd003, 0xd005
|
||||
};
|
||||
|
||||
return tls_cipher_suite_match(sha256_cs, ARRAY_SIZE(sha256_cs), cs);
|
||||
}
|
||||
|
||||
|
||||
static int tls_cipher_suite_mac_sha384(u16 cs)
|
||||
{
|
||||
static const u16 sha384_cs[] = {
|
||||
0x009d, 0x009f, 0x00a1, 0x00a3, 0x00a5, 0x00a7, 0x00a9, 0x00ab,
|
||||
0x00ad, 0x00af, 0x00b3, 0x00b7, 0x1302,
|
||||
0xc024, 0xc026, 0xc028, 0xc02a, 0xc02c, 0xc02e, 0xc030, 0xc032,
|
||||
0xc038, 0xc03d, 0xc03f, 0xc041, 0xc043, 0xc045, 0xc047, 0xc049,
|
||||
0xc04b, 0xc04d, 0xc04f, 0xc051, 0xc053, 0xc055, 0xc057, 0xc059,
|
||||
0xc05b, 0xc05d, 0xc05f, 0xc061, 0xc063, 0xc065, 0xc067, 0xc069,
|
||||
0xc06b, 0xc06d, 0xc06f, 0xc071, 0xc073, 0xc075, 0xc077, 0xc079,
|
||||
0xc07b, 0xc07d, 0xc07f, 0xc081, 0xc083, 0xc085, 0xc087, 0xc089,
|
||||
0xc08b, 0xc08d, 0xc08f, 0xc091, 0xc093, 0xc095, 0xc097, 0xc099,
|
||||
0xc09b, 0xc0b1, 0xc0b3, 0xc0b5,
|
||||
0xd002
|
||||
};
|
||||
|
||||
return tls_cipher_suite_match(sha384_cs, ARRAY_SIZE(sha384_cs), cs);
|
||||
}
|
||||
|
||||
|
||||
static int eap_teap_tls_mac(u16 tls_cs, const u8 *cmk, size_t cmk_len,
|
||||
const u8 *buffer, size_t buffer_len,
|
||||
u8 *mac, size_t mac_len)
|
||||
{
|
||||
int res;
|
||||
u8 tmp[48];
|
||||
|
||||
os_memset(tmp, 0, sizeof(tmp));
|
||||
os_memset(mac, 0, mac_len);
|
||||
|
||||
if (tls_cipher_suite_mac_sha1(tls_cs)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA1");
|
||||
res = hmac_sha1(cmk, cmk_len, buffer, buffer_len, tmp);
|
||||
} else if (tls_cipher_suite_mac_sha256(tls_cs)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA256");
|
||||
res = hmac_sha256(cmk, cmk_len, buffer, buffer_len, tmp);
|
||||
} else if (tls_cipher_suite_mac_sha384(tls_cs)) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: MAC algorithm: HMAC-SHA384");
|
||||
res = hmac_sha384(cmk, cmk_len, buffer, buffer_len, tmp);
|
||||
} else {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: Unsupported TLS cipher suite 0x%04x",
|
||||
tls_cs);
|
||||
res = -1;
|
||||
}
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
/* FIX: RFC 7170 does not describe how to handle truncation of the
|
||||
* Compound MAC or if the fields are supposed to be of variable length
|
||||
* based on the negotiated TLS cipher suite (they are defined as having
|
||||
* fixed size of 20 octets in the TLV description) */
|
||||
if (mac_len > sizeof(tmp))
|
||||
mac_len = sizeof(tmp);
|
||||
os_memcpy(mac, tmp, mac_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
|
||||
const struct wpabuf *server_outer_tlvs,
|
||||
const struct wpabuf *peer_outer_tlvs,
|
||||
const u8 *cmk, u8 *compound_mac)
|
||||
{
|
||||
u8 *pos, *buffer;
|
||||
size_t bind_len, buffer_len;
|
||||
struct teap_tlv_crypto_binding *tmp_cb;
|
||||
int res;
|
||||
|
||||
/* RFC 7170, Section 5.3 */
|
||||
bind_len = sizeof(struct teap_tlv_hdr) + be_to_host16(cb->length);
|
||||
buffer_len = bind_len + 1;
|
||||
if (server_outer_tlvs)
|
||||
buffer_len += wpabuf_len(server_outer_tlvs);
|
||||
if (peer_outer_tlvs)
|
||||
buffer_len += wpabuf_len(peer_outer_tlvs);
|
||||
buffer = os_malloc(buffer_len);
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
pos = buffer;
|
||||
/* 1. The entire Crypto-Binding TLV attribute with both the EMSK and MSK
|
||||
* Compound MAC fields zeroed out. */
|
||||
os_memcpy(pos, cb, bind_len);
|
||||
pos += bind_len;
|
||||
tmp_cb = (struct teap_tlv_crypto_binding *) buffer;
|
||||
os_memset(tmp_cb->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
|
||||
os_memset(tmp_cb->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
|
||||
|
||||
/* 2. The EAP Type sent by the other party in the first TEAP message. */
|
||||
/* This is supposed to be the EAP Type sent by the other party in the
|
||||
* first TEAP message, but since we cannot get here without having
|
||||
* successfully negotiated use of TEAP, this can only be the fixed EAP
|
||||
* Type of TEAP. */
|
||||
*pos++ = EAP_TYPE_TEAP;
|
||||
|
||||
/* 3. All the Outer TLVs from the first TEAP message sent by EAP server
|
||||
* to peer. */
|
||||
if (server_outer_tlvs) {
|
||||
os_memcpy(pos, wpabuf_head(server_outer_tlvs),
|
||||
wpabuf_len(server_outer_tlvs));
|
||||
pos += wpabuf_len(server_outer_tlvs);
|
||||
}
|
||||
|
||||
/* 4. All the Outer TLVs from the first TEAP message sent by the peer to
|
||||
* the EAP server. */
|
||||
if (peer_outer_tlvs) {
|
||||
os_memcpy(pos, wpabuf_head(peer_outer_tlvs),
|
||||
wpabuf_len(peer_outer_tlvs));
|
||||
pos += wpabuf_len(peer_outer_tlvs);
|
||||
}
|
||||
|
||||
buffer_len = pos - buffer;
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP,
|
||||
"EAP-TEAP: CMK for Compound MAC calculation",
|
||||
cmk, EAP_TEAP_CMK_LEN);
|
||||
wpa_hexdump(MSG_MSGDUMP,
|
||||
"EAP-TEAP: BUFFER for Compound MAC calculation",
|
||||
buffer, buffer_len);
|
||||
res = eap_teap_tls_mac(tls_cs, cmk, EAP_TEAP_CMK_LEN,
|
||||
buffer, buffer_len,
|
||||
compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
|
||||
os_free(buffer);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
|
||||
int tlv_type, u8 *pos, size_t len)
|
||||
{
|
||||
switch (tlv_type) {
|
||||
case TEAP_TLV_RESULT:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Result TLV", pos, len);
|
||||
if (tlv->result) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Result TLV in the message");
|
||||
tlv->result = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_INFO, "EAP-TEAP: Too short Result TLV");
|
||||
tlv->result = TEAP_STATUS_FAILURE;
|
||||
break;
|
||||
}
|
||||
tlv->result = WPA_GET_BE16(pos);
|
||||
if (tlv->result != TEAP_STATUS_SUCCESS &&
|
||||
tlv->result != TEAP_STATUS_FAILURE) {
|
||||
wpa_printf(MSG_INFO, "EAP-TEAP: Unknown Result %d",
|
||||
tlv->result);
|
||||
tlv->result = TEAP_STATUS_FAILURE;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: Result: %s",
|
||||
tlv->result == TEAP_STATUS_SUCCESS ?
|
||||
"Success" : "Failure");
|
||||
break;
|
||||
case TEAP_TLV_NAK:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: NAK TLV", pos, len);
|
||||
if (len < 6) {
|
||||
wpa_printf(MSG_INFO, "EAP-TEAP: Too short NAK TLV");
|
||||
tlv->result = TEAP_STATUS_FAILURE;
|
||||
break;
|
||||
}
|
||||
tlv->nak = pos;
|
||||
tlv->nak_len = len;
|
||||
break;
|
||||
case TEAP_TLV_REQUEST_ACTION:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Request-Action TLV",
|
||||
pos, len);
|
||||
if (tlv->request_action) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Request-Action TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: Too short Request-Action TLV");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
break;
|
||||
}
|
||||
tlv->request_action_status = pos[0];
|
||||
tlv->request_action = pos[1];
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"EAP-TEAP: Request-Action: Status=%u Action=%u",
|
||||
tlv->request_action_status, tlv->request_action);
|
||||
break;
|
||||
case TEAP_TLV_EAP_PAYLOAD:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EAP-Payload TLV",
|
||||
pos, len);
|
||||
if (tlv->eap_payload_tlv) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one EAP-Payload TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->eap_payload_tlv = pos;
|
||||
tlv->eap_payload_tlv_len = len;
|
||||
break;
|
||||
case TEAP_TLV_INTERMEDIATE_RESULT:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Intermediate-Result TLV",
|
||||
pos, len);
|
||||
if (len < 2) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: Too short Intermediate-Result TLV");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
break;
|
||||
}
|
||||
if (tlv->iresult) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Intermediate-Result TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->iresult = WPA_GET_BE16(pos);
|
||||
if (tlv->iresult != TEAP_STATUS_SUCCESS &&
|
||||
tlv->iresult != TEAP_STATUS_FAILURE) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: Unknown Intermediate Result %d",
|
||||
tlv->iresult);
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: Intermediate Result: %s",
|
||||
tlv->iresult == TEAP_STATUS_SUCCESS ?
|
||||
"Success" : "Failure");
|
||||
break;
|
||||
case TEAP_TLV_PAC:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: PAC TLV", pos, len);
|
||||
if (tlv->pac) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one PAC TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->pac = pos;
|
||||
tlv->pac_len = len;
|
||||
break;
|
||||
case TEAP_TLV_CRYPTO_BINDING:
|
||||
wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Crypto-Binding TLV",
|
||||
pos, len);
|
||||
if (tlv->crypto_binding) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Crypto-Binding TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->crypto_binding_len = sizeof(struct teap_tlv_hdr) + len;
|
||||
if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: Too short Crypto-Binding TLV");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->crypto_binding = (struct teap_tlv_crypto_binding *)
|
||||
(pos - sizeof(struct teap_tlv_hdr));
|
||||
break;
|
||||
case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP,
|
||||
"EAP-TEAP: Basic-Password-Auth-Req TLV",
|
||||
pos, len);
|
||||
if (tlv->basic_auth_req) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Basic-Password-Auth-Req TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->basic_auth_req = pos;
|
||||
tlv->basic_auth_req_len = len;
|
||||
break;
|
||||
case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP,
|
||||
"EAP-TEAP: Basic-Password-Auth-Resp TLV",
|
||||
pos, len);
|
||||
if (tlv->basic_auth_resp) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"EAP-TEAP: More than one Basic-Password-Auth-Resp TLV in the message");
|
||||
tlv->iresult = TEAP_STATUS_FAILURE;
|
||||
return -2;
|
||||
}
|
||||
tlv->basic_auth_resp = pos;
|
||||
tlv->basic_auth_resp_len = len;
|
||||
break;
|
||||
default:
|
||||
/* Unknown TLV */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char * eap_teap_tlv_type_str(enum teap_tlv_types type)
|
||||
{
|
||||
switch (type) {
|
||||
case TEAP_TLV_AUTHORITY_ID:
|
||||
return "Authority-ID";
|
||||
case TEAP_TLV_IDENTITY_TYPE:
|
||||
return "Identity-Type";
|
||||
case TEAP_TLV_RESULT:
|
||||
return "Result";
|
||||
case TEAP_TLV_NAK:
|
||||
return "NAK";
|
||||
case TEAP_TLV_ERROR:
|
||||
return "Error";
|
||||
case TEAP_TLV_CHANNEL_BINDING:
|
||||
return "Channel-Binding";
|
||||
case TEAP_TLV_VENDOR_SPECIFIC:
|
||||
return "Vendor-Specific";
|
||||
case TEAP_TLV_REQUEST_ACTION:
|
||||
return "Request-Action";
|
||||
case TEAP_TLV_EAP_PAYLOAD:
|
||||
return "EAP-Payload";
|
||||
case TEAP_TLV_INTERMEDIATE_RESULT:
|
||||
return "Intermediate-Result";
|
||||
case TEAP_TLV_PAC:
|
||||
return "PAC";
|
||||
case TEAP_TLV_CRYPTO_BINDING:
|
||||
return "Crypto-Binding";
|
||||
case TEAP_TLV_BASIC_PASSWORD_AUTH_REQ:
|
||||
return "Basic-Password-Auth-Req";
|
||||
case TEAP_TLV_BASIC_PASSWORD_AUTH_RESP:
|
||||
return "Basic-Password-Auth-Resp";
|
||||
case TEAP_TLV_PKCS7:
|
||||
return "PKCS#7";
|
||||
case TEAP_TLV_PKCS10:
|
||||
return "PKCS#10";
|
||||
case TEAP_TLV_TRUSTED_SERVER_ROOT:
|
||||
return "Trusted-Server-Root";
|
||||
}
|
||||
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * eap_teap_tlv_result(int status, int intermediate)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct teap_tlv_result *result;
|
||||
|
||||
if (status != TEAP_STATUS_FAILURE && status != TEAP_STATUS_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
buf = wpabuf_alloc(sizeof(*result));
|
||||
if (!buf)
|
||||
return NULL;
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: Add %sResult TLV(status=%s)",
|
||||
intermediate ? "Intermediate-" : "",
|
||||
status == TEAP_STATUS_SUCCESS ? "Success" : "Failure");
|
||||
result = wpabuf_put(buf, sizeof(*result));
|
||||
result->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
|
||||
(intermediate ?
|
||||
TEAP_TLV_INTERMEDIATE_RESULT :
|
||||
TEAP_TLV_RESULT));
|
||||
result->length = host_to_be16(2);
|
||||
result->status = host_to_be16(status);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(4 + 4);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Error TLV(Error Code=%d)",
|
||||
error);
|
||||
wpabuf_put_be16(buf, TEAP_TLV_MANDATORY | TEAP_TLV_ERROR);
|
||||
wpabuf_put_be16(buf, 4);
|
||||
wpabuf_put_be32(buf, error);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_allowed_anon_prov_phase2_method(u8 type)
|
||||
{
|
||||
/* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
|
||||
* provide key generation, and be resistant to dictionary attack.
|
||||
* Section 3.8 also mentions requirement for using EMSK Compound MAC. */
|
||||
return type == EAP_TYPE_PWD || type == EAP_TYPE_EKE;
|
||||
}
|
||||
|
||||
|
||||
int eap_teap_allowed_anon_prov_cipher_suite(u16 cs)
|
||||
{
|
||||
/* RFC 7170, Section 3.8.3: anonymous ciphersuites MAY be supported as
|
||||
* long as the TLS pre-master secret is generated form contribution from
|
||||
* both peers. Accept the recommended TLS_DH_anon_WITH_AES_128_CBC_SHA
|
||||
* cipher suite and other ciphersuites that use DH in some form, have
|
||||
* SHA-1 or stronger MAC function, and use reasonable strong cipher. */
|
||||
static const u16 ok_cs[] = {
|
||||
/* DH-anon */
|
||||
0x0034, 0x003a, 0x006c, 0x006d, 0x00a6, 0x00a7,
|
||||
/* DHE-RSA */
|
||||
0x0033, 0x0039, 0x0067, 0x006b, 0x009e, 0x009f,
|
||||
/* ECDH-anon */
|
||||
0xc018, 0xc019,
|
||||
/* ECDH-RSA */
|
||||
0xc003, 0xc00f, 0xc029, 0xc02a, 0xc031, 0xc032,
|
||||
/* ECDH-ECDSA */
|
||||
0xc004, 0xc005, 0xc025, 0xc026, 0xc02d, 0xc02e,
|
||||
/* ECDHE-RSA */
|
||||
0xc013, 0xc014, 0xc027, 0xc028, 0xc02f, 0xc030,
|
||||
/* ECDHE-ECDSA */
|
||||
0xc009, 0xc00a, 0xc023, 0xc024, 0xc02b, 0xc02c,
|
||||
};
|
||||
|
||||
return tls_cipher_suite_match(ok_cs, ARRAY_SIZE(ok_cs), cs);
|
||||
}
|
218
contrib/wpa/src/eap_common/eap_teap_common.h
Normal file
218
contrib/wpa/src/eap_common/eap_teap_common.h
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* EAP-TEAP definitions (RFC 7170)
|
||||
* Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_TEAP_H
|
||||
#define EAP_TEAP_H
|
||||
|
||||
#define EAP_TEAP_VERSION 1
|
||||
#define EAP_TEAP_KEY_LEN 64
|
||||
#define EAP_TEAP_IMCK_LEN 60
|
||||
#define EAP_TEAP_SIMCK_LEN 40
|
||||
#define EAP_TEAP_CMK_LEN 20
|
||||
#define EAP_TEAP_COMPOUND_MAC_LEN 20
|
||||
#define EAP_TEAP_NONCE_LEN 32
|
||||
|
||||
#define TEAP_TLS_EXPORTER_LABEL_SKS "EXPORTER: teap session key seed"
|
||||
|
||||
#define TLS_EXT_PAC_OPAQUE 35
|
||||
|
||||
/*
|
||||
* RFC 7170: Section 4.2.12.1 - Formats for PAC Attributes
|
||||
* Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
|
||||
* in the general TLV format (Section 4.2.1).
|
||||
*/
|
||||
#define PAC_TYPE_PAC_KEY 1
|
||||
#define PAC_TYPE_PAC_OPAQUE 2
|
||||
#define PAC_TYPE_CRED_LIFETIME 3
|
||||
#define PAC_TYPE_A_ID 4
|
||||
#define PAC_TYPE_I_ID 5
|
||||
/* 6 - Reserved */
|
||||
#define PAC_TYPE_A_ID_INFO 7
|
||||
#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
|
||||
#define PAC_TYPE_PAC_INFO 9
|
||||
#define PAC_TYPE_PAC_TYPE 10
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
struct pac_attr_hdr {
|
||||
be16 type;
|
||||
be16 len;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct teap_tlv_hdr {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* Result TLV and Intermediate-Result TLV */
|
||||
struct teap_tlv_result {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 status;
|
||||
/* for Intermediate-Result TLV, followed by optional TLVs */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct teap_tlv_nak {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be32 vendor_id;
|
||||
be16 nak_type;
|
||||
/* followed by optional TLVs */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct teap_tlv_crypto_binding {
|
||||
be16 tlv_type; /* TLV Type[14b] and M/R flags */
|
||||
be16 length;
|
||||
u8 reserved;
|
||||
u8 version;
|
||||
u8 received_version;
|
||||
u8 subtype; /* Flags[4b] and Sub-Type[4b] */
|
||||
u8 nonce[EAP_TEAP_NONCE_LEN];
|
||||
u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
|
||||
u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct teap_tlv_request_action {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
u8 status;
|
||||
u8 action;
|
||||
/* followed by optional TLVs */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
enum teap_request_action {
|
||||
TEAP_REQUEST_ACTION_PROCESS_TLV = 1,
|
||||
TEAP_REQUEST_ACTION_NEGOTIATE_EAP = 2,
|
||||
};
|
||||
|
||||
/* PAC TLV with PAC-Acknowledgement TLV attribute */
|
||||
struct teap_tlv_pac_ack {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 pac_type;
|
||||
be16 pac_len;
|
||||
be16 result;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct teap_attr_pac_type {
|
||||
be16 type; /* PAC_TYPE_PAC_TYPE */
|
||||
be16 length; /* 2 */
|
||||
be16 pac_type;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST 0
|
||||
#define TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
|
||||
|
||||
#define TEAP_CRYPTO_BINDING_EMSK_CMAC 1
|
||||
#define TEAP_CRYPTO_BINDING_MSK_CMAC 2
|
||||
#define TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC 3
|
||||
|
||||
|
||||
#define EAP_TEAP_PAC_KEY_LEN 48
|
||||
|
||||
/* RFC 7170: 4.2.12.6 PAC-Type TLV */
|
||||
#define PAC_TYPE_TUNNEL_PAC 1
|
||||
|
||||
|
||||
/* RFC 7170, 4.2.1: General TLV Format */
|
||||
enum teap_tlv_types {
|
||||
TEAP_TLV_AUTHORITY_ID = 1,
|
||||
TEAP_TLV_IDENTITY_TYPE = 2,
|
||||
TEAP_TLV_RESULT = 3,
|
||||
TEAP_TLV_NAK = 4,
|
||||
TEAP_TLV_ERROR = 5,
|
||||
TEAP_TLV_CHANNEL_BINDING = 6,
|
||||
TEAP_TLV_VENDOR_SPECIFIC = 7,
|
||||
TEAP_TLV_REQUEST_ACTION = 8,
|
||||
TEAP_TLV_EAP_PAYLOAD = 9,
|
||||
TEAP_TLV_INTERMEDIATE_RESULT = 10,
|
||||
TEAP_TLV_PAC = 11,
|
||||
TEAP_TLV_CRYPTO_BINDING = 12,
|
||||
TEAP_TLV_BASIC_PASSWORD_AUTH_REQ = 13,
|
||||
TEAP_TLV_BASIC_PASSWORD_AUTH_RESP = 14,
|
||||
TEAP_TLV_PKCS7 = 15,
|
||||
TEAP_TLV_PKCS10 = 16,
|
||||
TEAP_TLV_TRUSTED_SERVER_ROOT = 17,
|
||||
};
|
||||
|
||||
enum teap_tlv_result_status {
|
||||
TEAP_STATUS_SUCCESS = 1,
|
||||
TEAP_STATUS_FAILURE = 2
|
||||
};
|
||||
|
||||
#define TEAP_TLV_MANDATORY 0x8000
|
||||
#define TEAP_TLV_TYPE_MASK 0x3fff
|
||||
|
||||
/* RFC 7170, 4.2.6: Error TLV */
|
||||
enum teap_error_codes {
|
||||
TEAP_ERROR_INNER_METHOD = 1001,
|
||||
TEAP_ERROR_UNSPEC_AUTH_INFRA_PROBLEM = 1002,
|
||||
TEAP_ERROR_UNSPEC_AUTHENTICATION_FAILURE = 1003,
|
||||
TEAP_ERROR_UNSPEC_AUTHORIZATION_FAILURE = 1004,
|
||||
TEAP_ERROR_USER_ACCOUNT_CRED_UNAVAILABLE = 1005,
|
||||
TEAP_ERROR_USER_ACCOUNT_EXPIRED = 1006,
|
||||
TEAP_ERROR_USER_ACCOUNT_LOCKED_TRY_AGAIN_LATER = 1007,
|
||||
TEAP_ERROR_USER_ACCOUNT_LOCKED_ADMIN_REQ = 1008,
|
||||
TEAP_ERROR_TUNNEL_COMPROMISE_ERROR = 2001,
|
||||
TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED = 2002,
|
||||
};
|
||||
|
||||
struct wpabuf;
|
||||
struct tls_connection;
|
||||
|
||||
struct eap_teap_tlv_parse {
|
||||
u8 *eap_payload_tlv;
|
||||
size_t eap_payload_tlv_len;
|
||||
struct teap_tlv_crypto_binding *crypto_binding;
|
||||
size_t crypto_binding_len;
|
||||
int iresult;
|
||||
int result;
|
||||
u8 *nak;
|
||||
size_t nak_len;
|
||||
u8 request_action;
|
||||
u8 request_action_status;
|
||||
u8 *pac;
|
||||
size_t pac_len;
|
||||
u8 *basic_auth_req;
|
||||
size_t basic_auth_req_len;
|
||||
u8 *basic_auth_resp;
|
||||
size_t basic_auth_resp_len;
|
||||
};
|
||||
|
||||
void eap_teap_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
|
||||
void eap_teap_put_tlv(struct wpabuf *buf, u16 type, const void *data, u16 len);
|
||||
void eap_teap_put_tlv_buf(struct wpabuf *buf, u16 type,
|
||||
const struct wpabuf *data);
|
||||
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
|
||||
int eap_teap_derive_eap_msk(const u8 *simck, u8 *msk);
|
||||
int eap_teap_derive_eap_emsk(const u8 *simck, u8 *emsk);
|
||||
int eap_teap_derive_cmk_basic_pw_auth(const u8 *s_imck_msk, u8 *cmk);
|
||||
int eap_teap_derive_imck(const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
|
||||
const u8 *msk, size_t msk_len,
|
||||
const u8 *emsk, size_t emsk_len,
|
||||
u8 *s_imck_msk, u8 *cmk_msk,
|
||||
u8 *s_imck_emsk, u8 *cmk_emsk);
|
||||
int eap_teap_compound_mac(u16 tls_cs, const struct teap_tlv_crypto_binding *cb,
|
||||
const struct wpabuf *server_outer_tlvs,
|
||||
const struct wpabuf *peer_outer_tlvs,
|
||||
const u8 *cmk, u8 *compound_mac);
|
||||
int eap_teap_parse_tlv(struct eap_teap_tlv_parse *tlv,
|
||||
int tlv_type, u8 *pos, size_t len);
|
||||
const char * eap_teap_tlv_type_str(enum teap_tlv_types type);
|
||||
struct wpabuf * eap_teap_tlv_result(int status, int intermediate);
|
||||
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
|
||||
int eap_teap_allowed_anon_prov_phase2_method(u8 type);
|
||||
int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
|
||||
|
||||
#endif /* EAP_TEAP_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user