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:
cy 2019-08-22 18:52:30 +00:00
commit 53d87406a6
187 changed files with 24116 additions and 1753 deletions

View File

@ -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

View File

@ -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'",

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,

View File

@ -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:

View 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);
}

View 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 */

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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"

View File

@ -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(&params, 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;

View File

@ -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, &params);

View File

@ -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))

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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(&params, 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, &params);
@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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)",

View File

@ -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 */
};

View File

@ -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,

View File

@ -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))

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View 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;
}

View 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

View File

@ -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);

View 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;
}

View 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 */

View File

@ -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))) {

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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 ===== */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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
}

View File

@ -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);

View File

@ -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;
};
/**

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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";

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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",

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 */

View 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);
}

View 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