MFV r346563:
Update wpa_supplicant/hostapd 2.7 --> 2.8 Upstream documents the following advisories: - https://w1.fi/security/2019-1/sae-side-channel-attacks.txt - https://w1.fi/security/2019-2/eap-pwd-side-channel-attack.txt - https://w1.fi/security/2019-3/sae-confirm-missing-state-validation.txt - https://w1.fi/security/2019-4/eap-pwd-missing-commit-validation.txt - https://w1.fi/security/2019-5/eap-pwd-message-reassembly-issue-\ with-unexpected-fragment.txt Relnotes: yes MFC after: 1 week (or less) Security: CVE-2019-9494, VU#871675, CVE-2019-9495, CVE-2019-9496, CVE-2019-9497, CVE-2019-9498, CVE-2019-9499
This commit is contained in:
commit
4bc523382c
@ -140,7 +140,7 @@ The license terms used for hostap.git files
|
||||
|
||||
Modified BSD license (no advertisement clause):
|
||||
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
|
@ -1,5 +1,60 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2019-04-21 - v2.8
|
||||
* SAE changes
|
||||
- added support for SAE Password Identifier
|
||||
- changed default configuration to enable only group 19
|
||||
(i.e., disable groups 20, 21, 25, 26 from default configuration) and
|
||||
disable all unsuitable groups completely based on REVmd changes
|
||||
- improved anti-clogging token mechanism and SAE authentication
|
||||
frame processing during heavy CPU load; this mitigates some issues
|
||||
with potential DoS attacks trying to flood an AP with large number
|
||||
of SAE messages
|
||||
- added Finite Cyclic Group field in status code 77 responses
|
||||
- reject use of unsuitable groups based on new implementation guidance
|
||||
in REVmd (allow only FFC groups with prime >= 3072 bits and ECC
|
||||
groups with prime >= 256)
|
||||
- minimize timing and memory use differences in PWE derivation
|
||||
[https://w1.fi/security/2019-1/] (CVE-2019-9494)
|
||||
- fixed confirm message validation in error cases
|
||||
[https://w1.fi/security/2019-3/] (CVE-2019-9496)
|
||||
* EAP-pwd changes
|
||||
- minimize timing and memory use differences in PWE derivation
|
||||
[https://w1.fi/security/2019-2/] (CVE-2019-9495)
|
||||
- verify peer scalar/element
|
||||
[https://w1.fi/security/2019-4/] (CVE-2019-9497 and CVE-2019-9498)
|
||||
- fix message reassembly issue with unexpected fragment
|
||||
[https://w1.fi/security/2019-5/]
|
||||
- enforce rand,mask generation rules more strictly
|
||||
- fix a memory leak in PWE derivation
|
||||
- disallow ECC groups with a prime under 256 bits (groups 25, 26, and
|
||||
27)
|
||||
* Hotspot 2.0 changes
|
||||
- added support for release number 3
|
||||
- reject release 2 or newer association without PMF
|
||||
* added support for RSN operating channel validation
|
||||
(CONFIG_OCV=y and configuration parameter ocv=1)
|
||||
* added Multi-AP protocol support
|
||||
* added FTM responder configuration
|
||||
* fixed build with LibreSSL
|
||||
* added FT/RRB workaround for short Ethernet frame padding
|
||||
* fixed KEK2 derivation for FILS+FT
|
||||
* added RSSI-based association rejection from OCE
|
||||
* extended beacon reporting functionality
|
||||
* VLAN changes
|
||||
- allow local VLAN management with remote RADIUS authentication
|
||||
- add WPA/WPA2 passphrase/PSK -based VLAN assignment
|
||||
* OpenSSL: allow systemwide policies to be overridden
|
||||
* extended PEAP to derive EMSK to enable use with ERP/FILS
|
||||
* extended WPS to allow SAE configuration to be added automatically
|
||||
for PSK (wps_cred_add_sae=1)
|
||||
* fixed FT and SA Query Action frame with AP-MLME-in-driver cases
|
||||
* OWE: allow Diffie-Hellman Parameter element to be included with DPP
|
||||
in preparation for DPP protocol extension
|
||||
* RADIUS server: started to accept ERP keyName-NAI as user identity
|
||||
automatically without matching EAP database entry
|
||||
* fixed PTK rekeying with FILS and FT
|
||||
|
||||
2018-12-02 - v2.7
|
||||
* fixed WPA packet number reuse with replayed messages and key
|
||||
reinstallation
|
||||
|
@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||
Authenticator and RADIUS authentication server
|
||||
================================================================
|
||||
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is licensed under the BSD license (the one with
|
||||
|
160
contrib/wpa/hostapd/README-MULTI-AP
Normal file
160
contrib/wpa/hostapd/README-MULTI-AP
Normal file
@ -0,0 +1,160 @@
|
||||
hostapd, wpa_supplicant and the Multi-AP Specification
|
||||
======================================================
|
||||
|
||||
This document describes how hostapd and wpa_supplicant can be configured to
|
||||
support the Multi-AP Specification.
|
||||
|
||||
Introduction to Multi-AP
|
||||
------------------------
|
||||
|
||||
The Wi-Fi Alliance Multi-AP Specification is the technical specification for
|
||||
Wi-Fi CERTIFIED EasyMesh(TM) [1], the Wi-Fi Alliance® certification program for
|
||||
Multi-AP. It defines control protocols between Wi-Fi® access points (APs) to
|
||||
join them into a network with centralized control and operation. It is targeted
|
||||
only at routers (repeaters, gateways, ...), not at clients. Clients are not
|
||||
involved at all in the protocols.
|
||||
|
||||
Most of the Multi-AP specification falls outside of the scope of
|
||||
hostapd/wpa_supplicant. hostapd/wpa_supplicant is only involved for the items
|
||||
summarized below. The rest of the protocol must be implemented by a separate
|
||||
daemon, e.g., prplMesh [2]. That daemon also needs to communicate with hostapd,
|
||||
e.g., to get a list of associated clients, but this can be done using the normal
|
||||
hostapd interfaces.
|
||||
|
||||
hostapd/wpa_supplicant needs to be configured specifically to support:
|
||||
- the WPS onboarding process;
|
||||
- configuring backhaul links.
|
||||
|
||||
The text below refers to "Multi-AP Specification v1.0" [3].
|
||||
|
||||
|
||||
Fronthaul and backhaul links
|
||||
----------------------------
|
||||
|
||||
In a Multi-AP network, the central controller can configure the BSSs on the
|
||||
devices that are joined into the network. These are called fronthaul BSSs.
|
||||
From the point of view of hostapd, there is nothing special about these
|
||||
fronthaul BSSs.
|
||||
|
||||
In addition to fronthaul BSSs, the controller can also configure backhaul
|
||||
links. A backhaul link is a link between two access point devices, giving
|
||||
internet access to access point devices that don't have a wired link. The
|
||||
Multi-AP specification doesn't dictate this, but typically the backhaul link
|
||||
will be bridged into a LAN together with (one of) the fronthaul BSS(s) and the
|
||||
wired Ethernet ports.
|
||||
|
||||
A backhaul link must be treated specially by hostapd and wpa_supplicant. One
|
||||
side of the backhaul link is configured through the Multi-AP protocol as the
|
||||
"backhaul STA", i.e., the client side of the link. A backhaul STA is like any
|
||||
station and is handled appropriately by wpa_supplicant, but two additional
|
||||
features are required. It must send an additional information element in each
|
||||
(Re)Association Request frame ([3], section 5.2, paragraph 4). In addition, it
|
||||
must use 4-address mode for all frames sent over this link ([3], section 14).
|
||||
Therefore, wpa_supplicant must be configured explicitly as the backhaul STA
|
||||
role, by setting 'multi_ap_backhaul_sta=1' in the network configuration block
|
||||
or when configuring the network profile through the control interface. When
|
||||
'multi_ap_backhaul_sta=1', wpa_supplicant includes the Multi-AP IE in
|
||||
(Re)Association Request frame and verifies that it is included in the
|
||||
(Re)Association Response frame. If it is not, association fails. If it is,
|
||||
wpa_supplicant sets 4-address mode for this interface through a driver
|
||||
callback.
|
||||
|
||||
The AP side of the backhaul link is called a "backhaul BSS". Such a BSS must
|
||||
be handled specially by hostapd, because it must add an additional information
|
||||
element in each (Re)Association Response frame, but only to stations that have
|
||||
identified themselves as backhaul stations ([3], section 5.2, paragraph 5-6).
|
||||
This is important because it is possible to use the same BSS and SSID for
|
||||
fronthaul and backhaul at the same time. The additional information element must
|
||||
only be used for frames sent to a backhaul STA, not to a normal STA. Also,
|
||||
frames sent to a backhaul STA must use 4-address mode, while frames sent to a
|
||||
normal STA (fronthaul, when it's a fronthaul and backhaul BSS) must use
|
||||
3-address mode.
|
||||
|
||||
A BSS is configured in Multi-AP mode in hostapd by setting the 'multi_ap'
|
||||
configuration option to 1 (backhaul BSS), 2 (fronthaul BSS), or 3
|
||||
(simultaneous backhaul and fronthaul BSS). If this option is set, hostapd
|
||||
parses the Multi-AP information element in the Association Request frame. If the
|
||||
station is a backhaul STA and the BSS is configured as a backhaul BSS,
|
||||
hostapd sets up 4-address mode. Since there may be multiple stations connected
|
||||
simultaneously, and each of them has a different RA (receiver address), a VLAN
|
||||
is created for each backhaul STA and it is automatically added to a bridge.
|
||||
This is the same behavior as for WDS, and the relevant option ('bridge' or
|
||||
'wds_bridge') applies here as well.
|
||||
|
||||
If 'multi_ap' is 1 (backhaul BSS only), any station that tries to associate
|
||||
without the Multi-AP information element will be denied.
|
||||
|
||||
If 'multi_ap' is 2 (fronthaul BSS only), any station that tries to associate
|
||||
with the Multi-AP information element will be denied. That is also the only
|
||||
difference with 'multi_ap' set to 0: in the latter case, the Multi-AP
|
||||
information element is simply ignored.
|
||||
|
||||
In summary, this is the end-to-end behavior for a backhaul BSS (i.e.,
|
||||
multi_ap_backhaul_sta=1 in wpa_supplicant on STA, and multi_ap=1 or 3 in
|
||||
hostapd on AP). Note that point 1 means that hostapd must not be configured
|
||||
with WPS support on the backhaul BSS (multi_ap=1). hostapd does not check for
|
||||
that.
|
||||
|
||||
1. Backhaul BSS beacons do not advertise WPS support (other than that, nothing
|
||||
Multi-AP specific).
|
||||
2. STA sends Authentication frame (nothing Multi-AP specific).
|
||||
3. AP sends Authentication frame (nothing Multi-AP specific).
|
||||
4. STA sends Association Request frame with Multi-AP IE.
|
||||
5. AP sends Association Response frame with Multi-AP IE.
|
||||
6. STA and AP both use 4-address mode for Data frames.
|
||||
|
||||
|
||||
WPS support
|
||||
-----------
|
||||
|
||||
WPS requires more special handling. WPS must only be advertised on fronthaul
|
||||
BSSs, not on backhaul BSSs, so WPS should not be enabled on a backhaul-only
|
||||
BSS in hostapd.conf. The WPS configuration purely works on the fronthaul BSS.
|
||||
When a WPS M1 message has an additional subelement that indicates a request for
|
||||
a Multi-AP backhaul link, hostapd must not respond with the normal fronthaul
|
||||
BSS credentials; instead, it should respond with the (potentially different)
|
||||
backhaul BSS credentials.
|
||||
|
||||
To support this, hostapd has the 'multi_ap_backhaul_ssid',
|
||||
'multi_ap_backhaul_wpa_psk' and 'multi_ap_backhaul_wpa_passphrase' options.
|
||||
When these are set on an BSS with WPS, they are used instead of the normal
|
||||
credentials when hostapd receives a WPS M1 message with the Multi-AP IE. Only
|
||||
WPA2-Personal is supported in the Multi-AP specification, so there is no need
|
||||
to specify authentication or encryption options. For the backhaul credentials,
|
||||
per-device PSK is not supported.
|
||||
|
||||
If the BSS is a simultaneous backhaul and fronthaul BSS, there is no need to
|
||||
specify the backhaul credentials, since the backhaul and fronthaul credentials
|
||||
are identical.
|
||||
|
||||
To enable the Multi-AP backhaul STA feature when it performs WPS, a new
|
||||
parameter has been introduced to the WPS_PBC control interface call. When this
|
||||
"multi_ap=1" option is set, it adds the Multi-AP backhaul subelement to the
|
||||
Association Request frame and the M1 message. It then configures the new network
|
||||
profile with 'multi_ap_backhaul_sta=1'. Note that this means that if the AP does
|
||||
not follow the Multi-AP specification, wpa_supplicant will fail to associate.
|
||||
|
||||
In summary, this is the end-to-end behavior for WPS of a backhaul link (i.e.,
|
||||
multi_ap=1 option is given in the wps_pbc call on the STA side, and multi_ap=2
|
||||
and multi_ap_backhaul_ssid and either multi_ap_backhaul_wpa_psk or
|
||||
multi_ap_backhaul_wpa_passphrase are set to the credentials of a backhaul BSS
|
||||
in hostapd on Registrar AP).
|
||||
|
||||
1. Fronthaul BSS Beacon frames advertise WPS support (nothing Multi-AP
|
||||
specific).
|
||||
2. Enrollee sends Authentication frame (nothing Multi-AP specific).
|
||||
3. AP sends Authentication frame (nothing Multi-AP specific).
|
||||
4. Enrollee sends Association Request frame with Multi-AP IE.
|
||||
5. AP sends Association Response frame with Multi-AP IE.
|
||||
6. Enrollee sends M1 with additional Multi-AP subelement.
|
||||
7. AP sends M8 with backhaul instead of fronthaul credentials.
|
||||
8. Enrollee sends Deauthentication frame.
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh
|
||||
[2] https://github.com/prplfoundation/prplMesh
|
||||
[3] https://www.wi-fi.org/file/multi-ap-specification-v10
|
||||
(requires registration)
|
@ -37,7 +37,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[128], *pos, *pos2;
|
||||
char buf[128], *pos, *pos2, *pos3;
|
||||
int line = 0, vlan_id;
|
||||
struct hostapd_vlan *vlan;
|
||||
|
||||
@ -82,7 +82,10 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
pos2 = pos;
|
||||
while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
|
||||
pos2++;
|
||||
*pos2 = '\0';
|
||||
|
||||
if (*pos2 != '\0')
|
||||
*(pos2++) = '\0';
|
||||
|
||||
if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
|
||||
wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
|
||||
"in '%s'", line, fname);
|
||||
@ -90,6 +93,13 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*pos2 == ' ' || *pos2 == '\t')
|
||||
pos2++;
|
||||
pos3 = pos2;
|
||||
while (*pos3 != ' ' && *pos3 != '\t' && *pos3 != '\0')
|
||||
pos3++;
|
||||
*pos3 = '\0';
|
||||
|
||||
vlan = os_zalloc(sizeof(*vlan));
|
||||
if (vlan == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Out of memory while reading "
|
||||
@ -102,6 +112,7 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
vlan->vlan_desc.untagged = vlan_id;
|
||||
vlan->vlan_desc.notempty = !!vlan_id;
|
||||
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
|
||||
os_strlcpy(vlan->bridge, pos2, sizeof(vlan->bridge));
|
||||
vlan->next = bss->vlan;
|
||||
bss->vlan = vlan;
|
||||
}
|
||||
@ -1368,6 +1379,30 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
|
||||
static u8 find_bit_offset(u8 val)
|
||||
{
|
||||
u8 res = 0;
|
||||
|
||||
for (; val; val >>= 1) {
|
||||
if (val & 1)
|
||||
break;
|
||||
res++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static u8 set_he_cap(int val, u8 mask)
|
||||
{
|
||||
return (u8) (mask & (val << find_bit_offset(mask)));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
|
||||
int line)
|
||||
@ -2254,10 +2289,16 @@ static unsigned int parse_tls_flags(const char *val)
|
||||
flags |= TLS_CONN_DISABLE_TIME_CHECKS;
|
||||
if (os_strstr(val, "[DISABLE-TLSv1.0]"))
|
||||
flags |= TLS_CONN_DISABLE_TLSv1_0;
|
||||
if (os_strstr(val, "[ENABLE-TLSv1.0]"))
|
||||
flags |= TLS_CONN_ENABLE_TLSv1_0;
|
||||
if (os_strstr(val, "[DISABLE-TLSv1.1]"))
|
||||
flags |= TLS_CONN_DISABLE_TLSv1_1;
|
||||
if (os_strstr(val, "[ENABLE-TLSv1.1]"))
|
||||
flags |= TLS_CONN_ENABLE_TLSv1_1;
|
||||
if (os_strstr(val, "[DISABLE-TLSv1.2]"))
|
||||
flags |= TLS_CONN_DISABLE_TLSv1_2;
|
||||
if (os_strstr(val, "[ENABLE-TLSv1.2]"))
|
||||
flags |= TLS_CONN_ENABLE_TLSv1_2;
|
||||
if (os_strstr(val, "[DISABLE-TLSv1.3]"))
|
||||
flags |= TLS_CONN_DISABLE_TLSv1_3;
|
||||
if (os_strstr(val, "[ENABLE-TLSv1.3]"))
|
||||
@ -2292,6 +2333,14 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
pos = pos2 + ETH_ALEN * 3 - 1;
|
||||
}
|
||||
|
||||
pos2 = os_strstr(pos, "|vlanid=");
|
||||
if (pos2) {
|
||||
if (!end)
|
||||
end = pos2;
|
||||
pos2 += 8;
|
||||
pw->vlan_id = atoi(pos2);
|
||||
}
|
||||
|
||||
pos2 = os_strstr(pos, "|id=");
|
||||
if (pos2) {
|
||||
if (!end)
|
||||
@ -2476,8 +2525,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} 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, "check_cert_subject") == 0) {
|
||||
if (!pos[0]) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
os_free(bss->check_cert_subject);
|
||||
bss->check_cert_subject = os_strdup(pos);
|
||||
if (!bss->check_cert_subject)
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "check_crl") == 0) {
|
||||
bss->check_crl = atoi(pos);
|
||||
} else if (os_strcmp(buf, "check_crl_strict") == 0) {
|
||||
bss->check_crl_strict = atoi(pos);
|
||||
} else if (os_strcmp(buf, "crl_reload_interval") == 0) {
|
||||
bss->crl_reload_interval = atoi(pos);
|
||||
} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
|
||||
bss->tls_session_lifetime = atoi(pos);
|
||||
} else if (os_strcmp(buf, "tls_flags") == 0) {
|
||||
@ -2494,6 +2557,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "openssl_ciphers") == 0) {
|
||||
os_free(bss->openssl_ciphers);
|
||||
bss->openssl_ciphers = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "openssl_ecdh_curves") == 0) {
|
||||
os_free(bss->openssl_ecdh_curves);
|
||||
bss->openssl_ecdh_curves = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "fragment_size") == 0) {
|
||||
bss->fragment_size = atoi(pos);
|
||||
#ifdef EAP_SERVER_FAST
|
||||
@ -3070,9 +3136,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
* cause problems with the current implementation.
|
||||
* Since it is unlikely that this small numbers are
|
||||
* useful in real life scenarios, do not allow beacon
|
||||
* period to be set below 15 TU. */
|
||||
if (val < 15 || val > 65535) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid beacon_int %d (expected 15..65535)",
|
||||
* period to be set below 10 TU. */
|
||||
if (val < 10 || val > 65535) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid beacon_int %d (expected 10..65535)",
|
||||
line, val);
|
||||
return 1;
|
||||
}
|
||||
@ -3148,7 +3215,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, val);
|
||||
return 1;
|
||||
}
|
||||
conf->send_probe_response = val;
|
||||
bss->send_probe_response = val;
|
||||
} else if (os_strcmp(buf, "supported_rates") == 0) {
|
||||
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
|
||||
@ -3316,6 +3383,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
} else if (os_strcmp(buf, "ocv") == 0) {
|
||||
bss->ocv = atoi(pos);
|
||||
if (bss->ocv && !bss->ieee80211w)
|
||||
bss->ieee80211w = 1;
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
} else if (os_strcmp(buf, "ieee80211n") == 0) {
|
||||
conf->ieee80211n = atoi(pos);
|
||||
@ -3369,6 +3442,90 @@ 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_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);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) {
|
||||
conf->he_mu_edca.he_qos_info |=
|
||||
set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) {
|
||||
conf->he_mu_edca.he_qos_info |=
|
||||
set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) {
|
||||
conf->he_mu_edca.he_qos_info |=
|
||||
set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] =
|
||||
atoi(pos) & 0xff;
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] =
|
||||
atoi(pos) & 0xff;
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] =
|
||||
atoi(pos) & 0xff;
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
|
||||
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) {
|
||||
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
|
||||
set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
|
||||
} 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;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
|
||||
bss->max_listen_interval = atoi(pos);
|
||||
@ -3466,6 +3623,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
|
||||
bss->wps_cred_processing = atoi(pos);
|
||||
} else if (os_strcmp(buf, "wps_cred_add_sae") == 0) {
|
||||
bss->wps_cred_add_sae = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ap_settings") == 0) {
|
||||
os_free(bss->ap_settings);
|
||||
bss->ap_settings =
|
||||
@ -3475,6 +3634,56 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "multi_ap_backhaul_ssid") == 0) {
|
||||
size_t slen;
|
||||
char *str = wpa_config_parse_string(pos, &slen);
|
||||
|
||||
if (!str || slen < 1 || slen > SSID_MAX_LEN) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
|
||||
line, pos);
|
||||
os_free(str);
|
||||
return 1;
|
||||
}
|
||||
os_memcpy(bss->multi_ap_backhaul_ssid.ssid, str, slen);
|
||||
bss->multi_ap_backhaul_ssid.ssid_len = slen;
|
||||
bss->multi_ap_backhaul_ssid.ssid_set = 1;
|
||||
os_free(str);
|
||||
} else if (os_strcmp(buf, "multi_ap_backhaul_wpa_passphrase") == 0) {
|
||||
int len = os_strlen(pos);
|
||||
|
||||
if (len < 8 || len > 63) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid WPA passphrase length %d (expected 8..63)",
|
||||
line, len);
|
||||
return 1;
|
||||
}
|
||||
os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
|
||||
bss->multi_ap_backhaul_ssid.wpa_passphrase = os_strdup(pos);
|
||||
if (bss->multi_ap_backhaul_ssid.wpa_passphrase) {
|
||||
hostapd_config_clear_wpa_psk(
|
||||
&bss->multi_ap_backhaul_ssid.wpa_psk);
|
||||
bss->multi_ap_backhaul_ssid.wpa_passphrase_set = 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "multi_ap_backhaul_wpa_psk") == 0) {
|
||||
hostapd_config_clear_wpa_psk(
|
||||
&bss->multi_ap_backhaul_ssid.wpa_psk);
|
||||
bss->multi_ap_backhaul_ssid.wpa_psk =
|
||||
os_zalloc(sizeof(struct hostapd_wpa_psk));
|
||||
if (!bss->multi_ap_backhaul_ssid.wpa_psk)
|
||||
return 1;
|
||||
if (hexstr2bin(pos, bss->multi_ap_backhaul_ssid.wpa_psk->psk,
|
||||
PMK_LEN) ||
|
||||
pos[PMK_LEN * 2] != '\0') {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
|
||||
line, pos);
|
||||
hostapd_config_clear_wpa_psk(
|
||||
&bss->multi_ap_backhaul_ssid.wpa_psk);
|
||||
return 1;
|
||||
}
|
||||
bss->multi_ap_backhaul_ssid.wpa_psk->group = 1;
|
||||
os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase);
|
||||
bss->multi_ap_backhaul_ssid.wpa_passphrase = NULL;
|
||||
bss->multi_ap_backhaul_ssid.wpa_psk_set = 1;
|
||||
} else if (os_strcmp(buf, "upnp_iface") == 0) {
|
||||
os_free(bss->upnp_iface);
|
||||
bss->upnp_iface = os_strdup(pos);
|
||||
@ -3717,6 +3926,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
#ifdef CONFIG_HS20
|
||||
} else if (os_strcmp(buf, "hs20") == 0) {
|
||||
bss->hs20 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "hs20_release") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 1 || val > (HS20_VERSION >> 4) + 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Unsupported hs20_release: %s",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
bss->hs20_release = val;
|
||||
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
|
||||
bss->disable_dgaf = atoi(pos);
|
||||
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
|
||||
@ -3807,6 +4026,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
|
||||
os_free(bss->t_c_server_url);
|
||||
bss->t_c_server_url = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "hs20_sim_provisioning_url") == 0) {
|
||||
os_free(bss->hs20_sim_provisioning_url);
|
||||
bss->hs20_sim_provisioning_url = os_strdup(pos);
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
} else if (os_strcmp(buf, "mbo") == 0) {
|
||||
@ -4111,6 +4333,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
|
||||
bss->coloc_intf_reporting = atoi(pos);
|
||||
#endif /* CONFIG_OWE */
|
||||
} else if (os_strcmp(buf, "multi_ap") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 3) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'",
|
||||
line, buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bss->multi_ap = val;
|
||||
} else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
|
||||
conf->rssi_reject_assoc_rssi = atoi(pos);
|
||||
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
|
||||
conf->rssi_reject_assoc_timeout = atoi(pos);
|
||||
} else if (os_strcmp(buf, "pbss") == 0) {
|
||||
bss->pbss = atoi(pos);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
|
@ -883,7 +883,7 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
|
||||
/* TODO: TSF configurable/learnable */
|
||||
bss_term_dur[0] = 4; /* Subelement ID */
|
||||
bss_term_dur[1] = 10; /* Length */
|
||||
os_memset(bss_term_dur, 2, 8);
|
||||
os_memset(&bss_term_dur[2], 0, 8);
|
||||
end = os_strchr(pos, ',');
|
||||
if (end == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Invalid bss_term data");
|
||||
@ -1488,6 +1488,63 @@ static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *ctx)
|
||||
{
|
||||
struct hostapd_wpa_psk *psk;
|
||||
const u8 *pmk;
|
||||
int pmk_len;
|
||||
int pmk_match;
|
||||
int sta_match;
|
||||
int bss_match;
|
||||
int reason;
|
||||
|
||||
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
|
||||
|
||||
for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
|
||||
pmk_match = PMK_LEN == pmk_len &&
|
||||
os_memcmp(psk->psk, pmk, pmk_len) == 0;
|
||||
sta_match = psk->group == 0 &&
|
||||
os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
|
||||
bss_match = psk->group == 1;
|
||||
|
||||
if (pmk_match && (sta_match || bss_match))
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "STA " MACSTR
|
||||
" PSK/passphrase no longer valid - disconnect",
|
||||
MAC2STR(sta->addr));
|
||||
reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
|
||||
hostapd_drv_sta_deauth(hapd, sta->addr, reason);
|
||||
ap_sta_deauthenticate(hapd, sta, reason);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
int err;
|
||||
|
||||
hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
|
||||
|
||||
err = hostapd_setup_wpa_psk(conf);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
|
||||
err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
|
||||
static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
|
||||
@ -2826,6 +2883,34 @@ static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
|
||||
const char *field, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (os_strcmp(field, "dpp") == 0) {
|
||||
int res;
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
res = os_snprintf(buf, buflen, "DPP=2");
|
||||
#else /* CONFIG_DPP2 */
|
||||
res = os_snprintf(buf, buflen, "DPP=1");
|
||||
#endif /* CONFIG_DPP2 */
|
||||
if (os_snprintf_error(buflen, res))
|
||||
return -1;
|
||||
return res;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
|
||||
field);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
char *buf, char *reply,
|
||||
int reply_size,
|
||||
@ -3013,6 +3098,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
|
||||
if (hostapd_ctrl_iface_enable(hapd->iface))
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
|
||||
if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
|
||||
if (hostapd_ctrl_iface_reload(hapd->iface))
|
||||
reply_len = -1;
|
||||
@ -3182,7 +3270,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
reply_len = -1;
|
||||
}
|
||||
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
|
||||
res = hostapd_dpp_bootstrap_gen(hapd, buf + 18);
|
||||
res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
|
||||
if (res < 0) {
|
||||
reply_len = -1;
|
||||
} else {
|
||||
@ -3191,12 +3279,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
reply_len = -1;
|
||||
}
|
||||
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
|
||||
if (hostapd_dpp_bootstrap_remove(hapd, buf + 21) < 0)
|
||||
if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
|
||||
buf + 21) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
|
||||
const char *uri;
|
||||
|
||||
uri = hostapd_dpp_bootstrap_get_uri(hapd, atoi(buf + 22));
|
||||
uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
|
||||
atoi(buf + 22));
|
||||
if (!uri) {
|
||||
reply_len = -1;
|
||||
} else {
|
||||
@ -3205,8 +3295,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
reply_len = -1;
|
||||
}
|
||||
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
|
||||
reply_len = hostapd_dpp_bootstrap_info(hapd, atoi(buf + 19),
|
||||
reply, reply_size);
|
||||
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
|
||||
atoi(buf + 19),
|
||||
reply, reply_size);
|
||||
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
|
||||
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
|
||||
reply_len = -1;
|
||||
@ -3217,7 +3308,8 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
hostapd_dpp_stop(hapd);
|
||||
hostapd_dpp_listen_stop(hapd);
|
||||
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
|
||||
res = hostapd_dpp_configurator_add(hapd, buf + 20);
|
||||
res = dpp_configurator_add(hapd->iface->interfaces->dpp,
|
||||
buf + 20);
|
||||
if (res < 0) {
|
||||
reply_len = -1;
|
||||
} else {
|
||||
@ -3226,15 +3318,17 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
reply_len = -1;
|
||||
}
|
||||
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
|
||||
if (hostapd_dpp_configurator_remove(hapd, buf + 24) < 0)
|
||||
if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
|
||||
buf + 24) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
|
||||
if (hostapd_dpp_configurator_sign(hapd, buf + 22) < 0)
|
||||
if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
|
||||
reply_len = hostapd_dpp_configurator_get_key(hapd,
|
||||
atoi(buf + 25),
|
||||
reply, reply_size);
|
||||
reply_len = dpp_configurator_get_key_id(
|
||||
hapd->iface->interfaces->dpp,
|
||||
atoi(buf + 25),
|
||||
reply, reply_size);
|
||||
} else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
|
||||
res = hostapd_dpp_pkex_add(hapd, buf + 12);
|
||||
if (res < 0) {
|
||||
@ -3253,6 +3347,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
|
||||
reply_len = -1;
|
||||
#endif /* RADIUS_SERVER */
|
||||
} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
|
||||
reply_len = hostapd_ctrl_iface_get_capability(
|
||||
hapd, buf + 15, reply, reply_size);
|
||||
} else {
|
||||
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
||||
reply_len = 16;
|
||||
@ -3506,18 +3603,18 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(hapd->conf->ctrl_interface, -1,
|
||||
hapd->conf->ctrl_interface_gid) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
|
||||
lchown(hapd->conf->ctrl_interface, -1,
|
||||
hapd->conf->ctrl_interface_gid) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!hapd->conf->ctrl_interface_gid_set &&
|
||||
hapd->iface->interfaces->ctrl_iface_group &&
|
||||
chown(hapd->conf->ctrl_interface, -1,
|
||||
hapd->iface->interfaces->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
|
||||
lchown(hapd->conf->ctrl_interface, -1,
|
||||
hapd->iface->interfaces->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@ -3590,16 +3687,16 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
if (hapd->conf->ctrl_interface_gid_set &&
|
||||
chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
|
||||
lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!hapd->conf->ctrl_interface_gid_set &&
|
||||
hapd->iface->interfaces->ctrl_iface_group &&
|
||||
chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
|
||||
lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
@ -3733,7 +3830,7 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit_global(interfaces);
|
||||
dpp_global_clear(interfaces->dpp);
|
||||
#endif /* CONFIG_DPP */
|
||||
}
|
||||
|
||||
@ -4273,9 +4370,9 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
|
||||
goto fail;
|
||||
}
|
||||
} else if (interface->ctrl_iface_group &&
|
||||
chown(interface->global_iface_path, -1,
|
||||
interface->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
|
||||
lchown(interface->global_iface_path, -1,
|
||||
interface->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
@ -4332,8 +4429,8 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
|
||||
}
|
||||
|
||||
if (interface->ctrl_iface_group &&
|
||||
chown(fname, -1, interface->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
|
||||
lchown(fname, -1, interface->ctrl_iface_group) < 0) {
|
||||
wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ CONFIG_RSN_PREAUTH=y
|
||||
# IEEE 802.11w (management frame protection)
|
||||
CONFIG_IEEE80211W=y
|
||||
|
||||
# Support Operating Channel Validation
|
||||
#CONFIG_OCV=y
|
||||
|
||||
# Integrated EAP server
|
||||
CONFIG_EAP=y
|
||||
|
||||
@ -249,6 +252,11 @@ CONFIG_IPV6=y
|
||||
# requirements described above.
|
||||
#CONFIG_NO_RANDOM_POOL=y
|
||||
|
||||
# Should we attempt to use the getrandom(2) call that provides more reliable
|
||||
# yet secure randomness source than /dev/random on Linux 3.17 and newer.
|
||||
# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
|
||||
#CONFIG_GETRANDOM=y
|
||||
|
||||
# Should we use poll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_POLL=y
|
||||
|
||||
@ -356,8 +364,6 @@ CONFIG_IPV6=y
|
||||
#CONFIG_TAXONOMY=y
|
||||
|
||||
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
|
||||
# Note: This is an experimental and not yet complete implementation. This
|
||||
# should not be enabled for production use.
|
||||
#CONFIG_FILS=y
|
||||
# FILS shared key authentication with PFS
|
||||
#CONFIG_FILS_SK_PFS=y
|
||||
|
@ -438,6 +438,13 @@ wmm_ac_vo_txop_limit=47
|
||||
wmm_ac_vo_acm=0
|
||||
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
|
||||
|
||||
# Enable Multi-AP functionality
|
||||
# 0 = disabled (default)
|
||||
# 1 = AP support backhaul BSS
|
||||
# 2 = AP support fronthaul BSS
|
||||
# 3 = AP supports both backhaul BSS and fronthaul BSS
|
||||
#multi_ap=0
|
||||
|
||||
# Static WEP key configuration
|
||||
#
|
||||
# The key number to use when transmitting.
|
||||
@ -794,6 +801,30 @@ wmm_ac_vo_acm=0
|
||||
# unsigned integer = duration in units of 16 us
|
||||
#he_rts_threshold=0
|
||||
|
||||
#he_mu_edca_qos_info_param_count
|
||||
#he_mu_edca_qos_info_q_ack
|
||||
#he_mu_edca_qos_info_queue_request=1
|
||||
#he_mu_edca_qos_info_txop_request
|
||||
#he_mu_edca_ac_be_aifsn=0
|
||||
#he_mu_edca_ac_be_ecwmin=15
|
||||
#he_mu_edca_ac_be_ecwmax=15
|
||||
#he_mu_edca_ac_be_timer=255
|
||||
#he_mu_edca_ac_bk_aifsn=0
|
||||
#he_mu_edca_ac_bk_aci=1
|
||||
#he_mu_edca_ac_bk_ecwmin=15
|
||||
#he_mu_edca_ac_bk_ecwmax=15
|
||||
#he_mu_edca_ac_bk_timer=255
|
||||
#he_mu_edca_ac_vi_ecwmin=15
|
||||
#he_mu_edca_ac_vi_ecwmax=15
|
||||
#he_mu_edca_ac_vi_aifsn=0
|
||||
#he_mu_edca_ac_vi_aci=2
|
||||
#he_mu_edca_ac_vi_timer=255
|
||||
#he_mu_edca_ac_vo_aifsn=0
|
||||
#he_mu_edca_ac_vo_aci=3
|
||||
#he_mu_edca_ac_vo_ecwmin=15
|
||||
#he_mu_edca_ac_vo_ecwmax=15
|
||||
#he_mu_edca_ac_vo_timer=255
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -891,18 +922,83 @@ eap_server=0
|
||||
# valid CRL signed by the CA is required to be included in the ca_cert file.
|
||||
# This can be done by using PEM format for CA certificate and CRL and
|
||||
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
|
||||
# restarted to take the new CRL into use.
|
||||
# restarted to take the new CRL into use. Alternatively, crl_reload_interval can
|
||||
# be used to configure periodic updating of the loaded CRL information.
|
||||
# 0 = do not verify CRLs (default)
|
||||
# 1 = check the CRL of the user certificate
|
||||
# 2 = check all CRLs in the certificate path
|
||||
#check_crl=1
|
||||
|
||||
# Specify whether to ignore certificate CRL validity time mismatches with
|
||||
# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
|
||||
#
|
||||
# 0 = ignore errors
|
||||
# 1 = do not ignore errors (default)
|
||||
#check_crl_strict=1
|
||||
|
||||
# CRL reload interval in seconds
|
||||
# This can be used to reload ca_cert file and the included CRL on every new TLS
|
||||
# session if difference between last reload and the current reload time in
|
||||
# seconds is greater than crl_reload_interval.
|
||||
# Note: If interval time is very short, CPU overhead may be negatively affected
|
||||
# and it is advised to not go below 300 seconds.
|
||||
# This is applicable only with check_crl values 1 and 2.
|
||||
# 0 = do not reload CRLs (default)
|
||||
# crl_reload_interval = 300
|
||||
|
||||
# If check_cert_subject is set, the value of every field will be checked
|
||||
# against the DN of the subject in the client certificate. If the values do
|
||||
# not match, the certificate verification will fail, rejecting the user.
|
||||
# This option allows hostapd to match every individual field in the right order
|
||||
# against the DN of the subject in the client certificate.
|
||||
#
|
||||
# For example, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234 will check
|
||||
# every individual DN field of the subject in the client certificate. If OU=XYZ
|
||||
# comes first in terms of the order in the client certificate (DN field of
|
||||
# client certificate C=US/O=XX/OU=XYZ/OU=ABC/CN=1234), hostapd will reject the
|
||||
# client because the order of 'OU' is not matching the specified string in
|
||||
# check_cert_subject.
|
||||
#
|
||||
# This option also allows '*' as a wildcard. This option has some limitation.
|
||||
# It can only be used as per the following example.
|
||||
#
|
||||
# For example, check_cert_subject=C=US/O=XX/OU=Production* and we have two
|
||||
# clients and DN of the subject in the first client certificate is
|
||||
# (C=US/O=XX/OU=Production Unit) and DN of the subject in the second client is
|
||||
# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both
|
||||
# clients because the value of 'OU' field in both client certificates matches
|
||||
# 'OU' value in 'check_cert_subject' up to 'wildcard'.
|
||||
#
|
||||
# * (Allow all clients, e.g., check_cert_subject=*)
|
||||
#check_cert_subject=string
|
||||
|
||||
# TLS Session Lifetime in seconds
|
||||
# This can be used to allow TLS sessions to be cached and resumed with an
|
||||
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
|
||||
# (default: 0 = session caching and resumption disabled)
|
||||
#tls_session_lifetime=3600
|
||||
|
||||
# TLS flags
|
||||
# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on
|
||||
# the TLS library, these may be disabled by default to enforce stronger
|
||||
# security)
|
||||
# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests
|
||||
# the TLS library to accept certificates even if they are not currently
|
||||
# valid, i.e., have expired or have not yet become valid; this should be
|
||||
# used only for testing purposes)
|
||||
# [DISABLE-TLSv1.0] = disable use of TLSv1.0
|
||||
# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows
|
||||
# systemwide TLS policies to be overridden)
|
||||
# [DISABLE-TLSv1.1] = disable use of TLSv1.1
|
||||
# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows
|
||||
# systemwide TLS policies to be overridden)
|
||||
# [DISABLE-TLSv1.2] = disable use of TLSv1.2
|
||||
# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows
|
||||
# systemwide TLS policies to be overridden)
|
||||
# [DISABLE-TLSv1.3] = disable use of TLSv1.3
|
||||
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
|
||||
#tls_flags=[flag1][flag2]...
|
||||
|
||||
# Cached OCSP stapling response (DER encoded)
|
||||
# If set, this file is sent as a certificate status response by the EAP server
|
||||
# if the EAP peer requests certificate status in the ClientHello message.
|
||||
@ -944,6 +1040,19 @@ eap_server=0
|
||||
# use OpenSSL.
|
||||
#openssl_ciphers=DEFAULT:!EXP:!LOW
|
||||
|
||||
# OpenSSL ECDH curves
|
||||
#
|
||||
# This is an OpenSSL specific configuration option for configuring the ECDH
|
||||
# curves for EAP-TLS/TTLS/PEAP/FAST server. If not set, automatic curve
|
||||
# selection is enabled. If set to an empty string, ECDH curve configuration is
|
||||
# not done (the exact library behavior depends on the library version).
|
||||
# Otherwise, this is a colon separated list of the supported curves (e.g.,
|
||||
# P-521:P-384:P-256). This is applicable only if hostapd is built to use
|
||||
# OpenSSL. This must not be used for Suite B cases since the same OpenSSL
|
||||
# parameter is set differently in those cases and this might conflict with that
|
||||
# design.
|
||||
#openssl_ecdh_curves=P-521:P-384:P-256
|
||||
|
||||
# Fragment size for EAP methods
|
||||
#fragment_size=1400
|
||||
|
||||
@ -1104,8 +1213,10 @@ own_ip_addr=127.0.0.1
|
||||
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
|
||||
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
|
||||
# be used to set static client MAC address to VLAN ID mapping.
|
||||
# 0 = disabled (default)
|
||||
# 1 = option; use default interface if RADIUS server does not include VLAN ID
|
||||
# Dynamic VLAN mode is also used with VLAN ID assignment based on WPA/WPA2
|
||||
# passphrase from wpa_psk_file or vlan_id parameter from sae_password.
|
||||
# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
|
||||
# 1 = optional; use default interface if RADIUS server does not include VLAN ID
|
||||
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
|
||||
#dynamic_vlan=0
|
||||
|
||||
@ -1128,6 +1239,7 @@ own_ip_addr=127.0.0.1
|
||||
# white space (space or tab).
|
||||
# If no entries are provided by this file, the station is statically mapped
|
||||
# to <bss-iface>.<vlan-id> interfaces.
|
||||
# Each line can optionally also contain the name of a bridge to add the VLAN to
|
||||
#vlan_file=/etc/hostapd.vlan
|
||||
|
||||
# Interface where 802.1q tagged packets should appear when a RADIUS server is
|
||||
@ -1418,6 +1530,13 @@ own_ip_addr=127.0.0.1
|
||||
# dot11AssociationSAQueryRetryTimeout, 1...4294967295
|
||||
#assoc_sa_query_retry_timeout=201
|
||||
|
||||
# ocv: Operating Channel Validation
|
||||
# This is a countermeasure against multi-channel man-in-the-middle attacks.
|
||||
# Enabling this automatically also enables ieee80211w, if not yet enabled.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ocv=1
|
||||
|
||||
# disable_pmksa_caching: Disable PMKSA caching
|
||||
# This parameter can be used to disable caching of PMKSA created through EAP
|
||||
# authentication. RSN preauthentication may still end up using PMKSA caching if
|
||||
@ -1445,21 +1564,29 @@ own_ip_addr=127.0.0.1
|
||||
# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
|
||||
# starts with the password (dot11RSNAConfigPasswordCredential). That value can
|
||||
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
|
||||
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). If the
|
||||
# peer MAC address is not included or is set to the wildcard address
|
||||
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
|
||||
# addition, an optional VLAN ID specification can be used to bind the station
|
||||
# to the specified VLAN whenver the specific SAE password entry is used.
|
||||
#
|
||||
# If the peer MAC address is not included or is set to the wildcard address
|
||||
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
|
||||
# specific peer MAC address is included, only a station with that MAC address
|
||||
# is allowed to use the entry. If the password identifier (with non-zero length)
|
||||
# is included, the entry is limited to be used only with that specified
|
||||
# identifier. The last matching (based on peer MAC address and identifier) entry
|
||||
# is used to select which password to use. Setting sae_password to an empty
|
||||
# string has a special meaning of removing all previously added entries.
|
||||
# is allowed to use the entry.
|
||||
#
|
||||
# If the password identifier (with non-zero length) is included, the entry is
|
||||
# limited to be used only with that specified identifier.
|
||||
|
||||
# The last matching (based on peer MAC address and identifier) entry is used to
|
||||
# select which password to use. Setting sae_password to an empty string has a
|
||||
# special meaning of removing all previously added entries.
|
||||
#
|
||||
# sae_password uses the following encoding:
|
||||
#<password/credential>[|mac=<peer mac>][|id=<identifier>]
|
||||
#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
|
||||
# Examples:
|
||||
#sae_password=secret
|
||||
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
|
||||
#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
|
||||
#sae_password=example secret|vlanid=3|id=pw identifier
|
||||
|
||||
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
|
||||
# This parameter defines how many open SAE instances can be in progress at the
|
||||
@ -1473,12 +1600,16 @@ own_ip_addr=127.0.0.1
|
||||
|
||||
# Enabled SAE finite cyclic groups
|
||||
# SAE implementation are required to support group 19 (ECC group defined over a
|
||||
# 256-bit prime order field). All groups that are supported by the
|
||||
# implementation are enabled by default. This configuration parameter can be
|
||||
# used to specify a limited set of allowed groups. The group values are listed
|
||||
# in the IANA registry:
|
||||
# 256-bit prime order field). This configuration parameter can be used to
|
||||
# specify a set of allowed groups. If not included, only the mandatory group 19
|
||||
# is enabled.
|
||||
# The group values are listed in the IANA registry:
|
||||
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
|
||||
#sae_groups=19 20 21 25 26
|
||||
# Note that groups 1, 2, 5, 22, 23, and 24 should not be used in production
|
||||
# purposes due limited security (see RFC 8247). Groups that are not as strong as
|
||||
# group 19 (ECC, NIST P-256) are unlikely to be useful for production use cases
|
||||
# since all implementations are required to support group 19.
|
||||
#sae_groups=19 20 21
|
||||
|
||||
# Require MFP for all associations using SAE
|
||||
# This parameter can be used to enforce negotiation of MFP for all associations
|
||||
@ -1837,6 +1968,14 @@ own_ip_addr=127.0.0.1
|
||||
# the configuration appropriately in this case.
|
||||
#wps_cred_processing=0
|
||||
|
||||
# Whether to enable SAE (WPA3-Personal transition mode) automatically for
|
||||
# WPA2-PSK credentials received using WPS.
|
||||
# 0 = only add the explicitly listed WPA2-PSK configuration (default)
|
||||
# 1 = add both the WPA2-PSK and SAE configuration and enable PMF so that the
|
||||
# AP gets configured in WPA3-Personal transition mode (supports both
|
||||
# WPA2-Personal (PSK) and WPA3-Personal (SAE) clients).
|
||||
#wps_cred_add_sae=0
|
||||
|
||||
# AP Settings Attributes for M7
|
||||
# By default, hostapd generates the AP Settings Attributes for M7 based on the
|
||||
# current configuration. It is possible to override this by providing a file
|
||||
@ -1845,6 +1984,15 @@ own_ip_addr=127.0.0.1
|
||||
# attribute.
|
||||
#ap_settings=hostapd.ap_settings
|
||||
|
||||
# Multi-AP backhaul BSS config
|
||||
# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials.
|
||||
# These are passed in WPS M8 instead of the normal (fronthaul) credentials
|
||||
# if the Enrollee has the Multi-AP subelement set. Backhaul SSID is formatted
|
||||
# like ssid2. The key is set like wpa_psk or wpa_passphrase.
|
||||
#multi_ap_backhaul_ssid="backhaul"
|
||||
#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
#multi_ap_backhaul_wpa_passphrase=secret passphrase
|
||||
|
||||
# WPS UPnP interface
|
||||
# If set, support for external Registrars is enabled.
|
||||
#upnp_iface=br0
|
||||
@ -2273,6 +2421,21 @@ own_ip_addr=127.0.0.1
|
||||
# Default is 0 = OCE disabled
|
||||
#oce=0
|
||||
|
||||
# RSSI-based assocition rejection
|
||||
#
|
||||
# Reject STA association if RSSI is below given threshold (in dBm)
|
||||
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
|
||||
# Note: This rejection happens based on a signal strength detected while
|
||||
# receiving a single frame and as such, there is significant risk of the value
|
||||
# not being accurate and this resulting in valid stations being rejected. As
|
||||
# such, this functionality is not recommended to be used for purposes other than
|
||||
# testing.
|
||||
#rssi_reject_assoc_rssi=-75
|
||||
#
|
||||
# Association retry delay in seconds allowed by the STA if RSSI has not met the
|
||||
# threshold (range: 0..255, default=30).
|
||||
#rssi_reject_assoc_timeout=30
|
||||
|
||||
##### Fast Session Transfer (FST) support #####################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
|
@ -3,7 +3,13 @@
|
||||
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
|
||||
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
|
||||
# characters or as a 256-bit hex PSK (64 hex digits).
|
||||
# An optional key identifier can be added by prefixing the line with
|
||||
# keyid=<keyid_string>
|
||||
# An optional VLAN ID can be specified by prefixing the line with
|
||||
# vlanid=<VLAN ID>.
|
||||
00:00:00:00:00:00 secret passphrase
|
||||
00:11:22:33:44:55 another passphrase
|
||||
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
|
||||
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
|
||||
00:00:00:00:00:00 another passphrase for all STAs
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - command line interface for hostapd daemon
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
* 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.
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> and contributors";
|
||||
"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
@ -1443,6 +1443,13 @@ static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -1480,6 +1487,20 @@ static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
@ -1640,6 +1661,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
|
||||
NULL,
|
||||
"<id> = Get DPP configurator's private key" },
|
||||
{ "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
|
||||
"conf=<role> configurator=<id> = generate self DPP configuration" },
|
||||
{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
|
||||
"add PKEX code" },
|
||||
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
|
||||
@ -1651,6 +1674,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"=Add/Delete/Show/Clear deny MAC ACL" },
|
||||
{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
|
||||
"<addr> = poll a STA to check connectivity with a QoS null frame" },
|
||||
{ "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
|
||||
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
|
||||
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
|
||||
"= reload wpa_psk_file only" },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / main()
|
||||
* Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -18,6 +18,7 @@
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "common/version.h"
|
||||
#include "common/dpp.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "eap_server/tncs.h"
|
||||
@ -456,7 +457,7 @@ static void show_version(void)
|
||||
"hostapd v" VERSION_STR "\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> "
|
||||
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
|
||||
@ -671,7 +672,9 @@ int main(int argc, char *argv[])
|
||||
dl_list_init(&interfaces.eth_p_oui);
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_init_global(&interfaces);
|
||||
interfaces.dpp = dpp_global_init();
|
||||
if (!interfaces.dpp)
|
||||
return -1;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
for (;;) {
|
||||
@ -901,7 +904,7 @@ int main(int argc, char *argv[])
|
||||
os_free(interfaces.iface);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit_global(&interfaces);
|
||||
dpp_global_deinit(interfaces.dpp);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (interfaces.eloop_initialized)
|
||||
|
@ -26,7 +26,7 @@
|
||||
success_file = None
|
||||
|
||||
def summary(txt):
|
||||
print txt
|
||||
print(txt)
|
||||
if summary_file:
|
||||
with open(summary_file, 'a') as f:
|
||||
f.write(txt + "\n")
|
||||
@ -42,19 +42,19 @@ def wpas_connect():
|
||||
if os.path.isdir(wpas_ctrl):
|
||||
try:
|
||||
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
|
||||
except OSError, error:
|
||||
print "Could not find hostapd: ", error
|
||||
except OSError as error:
|
||||
print("Could not find hostapd: ", error)
|
||||
return None
|
||||
|
||||
if len(ifaces) < 1:
|
||||
print "No hostapd control interface found"
|
||||
print("No hostapd control interface found")
|
||||
return None
|
||||
|
||||
for ctrl in ifaces:
|
||||
try:
|
||||
wpas = wpaspy.Ctrl(ctrl)
|
||||
return wpas
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
pass
|
||||
return None
|
||||
|
||||
@ -133,23 +133,23 @@ def _process_request(self, request):
|
||||
def process_request(self, request):
|
||||
summary("HandoverServer - request received")
|
||||
try:
|
||||
print "Parsed handover request: " + request.pretty()
|
||||
except Exception, e:
|
||||
print e
|
||||
print str(request).encode("hex")
|
||||
print("Parsed handover request: " + request.pretty())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(str(request).encode("hex"))
|
||||
|
||||
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
|
||||
|
||||
for carrier in request.carriers:
|
||||
print "Remote carrier type: " + carrier.type
|
||||
print("Remote carrier type: " + carrier.type)
|
||||
if carrier.type == "application/vnd.wfa.wsc":
|
||||
summary("WPS carrier type match - add WPS carrier record")
|
||||
data = wpas_get_handover_sel()
|
||||
if data is None:
|
||||
summary("Could not get handover select carrier record from hostapd")
|
||||
continue
|
||||
print "Handover select carrier record from hostapd:"
|
||||
print data.encode("hex")
|
||||
print("Handover select carrier record from hostapd:")
|
||||
print(data.encode("hex"))
|
||||
if "OK" in wpas_report_handover(carrier.record, data):
|
||||
success_report("Handover reported successfully")
|
||||
else:
|
||||
@ -158,12 +158,12 @@ def process_request(self, request):
|
||||
message = nfc.ndef.Message(data);
|
||||
sel.add_carrier(message[0], "active", message[1:])
|
||||
|
||||
print "Handover select:"
|
||||
print("Handover select:")
|
||||
try:
|
||||
print sel.pretty()
|
||||
except Exception, e:
|
||||
print e
|
||||
print str(sel).encode("hex")
|
||||
print(sel.pretty())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(str(sel).encode("hex"))
|
||||
|
||||
summary("Sending handover select")
|
||||
self.success = True
|
||||
@ -174,7 +174,7 @@ def wps_tag_read(tag):
|
||||
success = False
|
||||
if len(tag.ndef.message):
|
||||
for record in tag.ndef.message:
|
||||
print "record type " + record.type
|
||||
print("record type " + record.type)
|
||||
if record.type == "application/vnd.wfa.wsc":
|
||||
summary("WPS tag - send to hostapd")
|
||||
success = wpas_tag_read(tag.ndef.message)
|
||||
@ -193,7 +193,7 @@ def rdwr_connected_write(tag):
|
||||
global write_data
|
||||
tag.ndef.message = str(write_data)
|
||||
success_report("Tag write succeeded")
|
||||
print "Done - remove tag"
|
||||
print("Done - remove tag")
|
||||
global only_one
|
||||
if only_one:
|
||||
global continue_loop
|
||||
@ -211,7 +211,7 @@ def wps_write_config_tag(clf, wait_remove=True):
|
||||
summary("Could not get WPS config token from hostapd")
|
||||
return
|
||||
|
||||
print "Touch an NFC tag"
|
||||
print("Touch an NFC tag")
|
||||
clf.connect(rdwr={'on-connect': rdwr_connected_write})
|
||||
|
||||
|
||||
@ -224,7 +224,7 @@ def wps_write_password_tag(clf, wait_remove=True):
|
||||
summary("Could not get WPS password token from hostapd")
|
||||
return
|
||||
|
||||
print "Touch an NFC tag"
|
||||
print("Touch an NFC tag")
|
||||
clf.connect(rdwr={'on-connect': rdwr_connected_write})
|
||||
|
||||
|
||||
@ -233,11 +233,11 @@ def rdwr_connected(tag):
|
||||
summary("Tag connected: " + str(tag))
|
||||
|
||||
if tag.ndef:
|
||||
print "NDEF tag: " + tag.type
|
||||
print("NDEF tag: " + tag.type)
|
||||
try:
|
||||
print tag.ndef.message.pretty()
|
||||
except Exception, e:
|
||||
print e
|
||||
print(tag.ndef.message.pretty())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
success = wps_tag_read(tag)
|
||||
if only_one and success:
|
||||
global continue_loop
|
||||
@ -250,13 +250,13 @@ def rdwr_connected(tag):
|
||||
|
||||
|
||||
def llcp_startup(clf, llc):
|
||||
print "Start LLCP server"
|
||||
print("Start LLCP server")
|
||||
global srv
|
||||
srv = HandoverServer(llc)
|
||||
return llc
|
||||
|
||||
def llcp_connected(llc):
|
||||
print "P2P LLCP connected"
|
||||
print("P2P LLCP connected")
|
||||
global wait_connection
|
||||
wait_connection = False
|
||||
global srv
|
||||
@ -304,7 +304,7 @@ def main():
|
||||
|
||||
try:
|
||||
if not clf.open("usb"):
|
||||
print "Could not open connection with an NFC device"
|
||||
print("Could not open connection with an NFC device")
|
||||
raise SystemExit
|
||||
|
||||
if args.command == "write-config":
|
||||
@ -317,15 +317,15 @@ def main():
|
||||
|
||||
global continue_loop
|
||||
while continue_loop:
|
||||
print "Waiting for a tag or peer to be touched"
|
||||
print("Waiting for a tag or peer to be touched")
|
||||
wait_connection = True
|
||||
try:
|
||||
if not clf.connect(rdwr={'on-connect': rdwr_connected},
|
||||
llcp={'on-startup': llcp_startup,
|
||||
'on-connect': llcp_connected}):
|
||||
break
|
||||
except Exception, e:
|
||||
print "clf.connect failed"
|
||||
except Exception as e:
|
||||
print("clf.connect failed")
|
||||
|
||||
global srv
|
||||
if only_one and srv and srv.success:
|
||||
|
@ -8,12 +8,17 @@ ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
ifeq ($(QUIET), 1)
|
||||
Q=@
|
||||
E=true
|
||||
else
|
||||
Q=@
|
||||
E=echo
|
||||
ifeq ($(V), 1)
|
||||
Q=
|
||||
E=true
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include <openssl/buf.h>
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
@ -219,6 +220,10 @@ typedef struct {
|
||||
} d;
|
||||
} AttrOrOID;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
DEFINE_STACK_OF(AttrOrOID)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
STACK_OF(AttrOrOID) *attrs;
|
||||
@ -352,9 +357,17 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
|
||||
}
|
||||
}
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
num = sk_AttrOrOID_num(csrattrs->attrs);
|
||||
#else
|
||||
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
|
||||
#endif
|
||||
for (i = 0; i < num; i++) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
|
||||
AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
|
||||
#else
|
||||
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
|
||||
#endif
|
||||
switch (ao->type) {
|
||||
case 0:
|
||||
add_csrattrs_oid(ctx, ao->d.oid, exts);
|
||||
|
@ -117,8 +117,8 @@ static int android_update_permission(const char *path, mode_t mode)
|
||||
|
||||
/* Allow processes running with Group ID as AID_WIFI,
|
||||
* to read files from SP, SP/<fqdn>, Cert and osu-info directories */
|
||||
if (chown(path, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
|
||||
if (lchown(path, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@ -612,8 +612,8 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
|
||||
}
|
||||
}
|
||||
|
||||
android_update_permission("SP", S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
android_update_permission(fname, S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
android_update_permission("SP", S_IRWXU | S_IRWXG);
|
||||
android_update_permission(fname, S_IRWXU | S_IRWXG);
|
||||
|
||||
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "utils/list.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "hostapd.h"
|
||||
@ -362,7 +363,7 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
|
||||
static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
|
||||
{
|
||||
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
|
||||
157, 184, 192 };
|
||||
@ -376,7 +377,7 @@ static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
|
||||
static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
|
||||
{
|
||||
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
|
||||
unsigned int i;
|
||||
@ -389,6 +390,19 @@ static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
|
||||
{
|
||||
const int allowed[] = { 36, 100 };
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(allowed); i++)
|
||||
if (chan->chan == allowed[i])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int acs_survey_is_sufficient(struct freq_survey *survey)
|
||||
{
|
||||
if (!(survey->filled & SURVEY_HAS_NF)) {
|
||||
@ -565,6 +579,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
long double factor, ideal_factor = 0;
|
||||
int i, j;
|
||||
int n_chans = 1;
|
||||
u32 bw;
|
||||
unsigned int k;
|
||||
|
||||
/* TODO: HT40- support */
|
||||
@ -579,16 +594,23 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac &&
|
||||
iface->conf->vht_oper_chwidth == 1)
|
||||
n_chans = 4;
|
||||
if (iface->conf->ieee80211ac) {
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
|
||||
bw = num_chan_to_bw(n_chans);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
|
||||
n_chans == 1 ? 20 :
|
||||
n_chans == 2 ? 40 :
|
||||
80);
|
||||
/* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
double total_weight;
|
||||
@ -596,12 +618,23 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
|
||||
chan = &iface->current_mode->channels[i];
|
||||
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
/* Since in the current ACS implementation the first channel is
|
||||
* always a primary channel, skip channels not available as
|
||||
* primary until more sophisticated channel selection is
|
||||
* implemented. */
|
||||
if (!chan_pri_allowed(chan))
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
if (!chan_bw_allowed(chan, bw, 1, 1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: BW %u is not supported",
|
||||
chan->chan, bw);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* HT40 on 5 GHz has a limited set of primary channels as per
|
||||
* 11n Annex J */
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
@ -614,12 +647,24 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
iface->conf->ieee80211ac &&
|
||||
iface->conf->vht_oper_chwidth == 1 &&
|
||||
!acs_usable_vht80_chan(chan)) {
|
||||
wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
|
||||
chan->chan);
|
||||
continue;
|
||||
iface->conf->ieee80211ac) {
|
||||
if (iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_80MHZ &&
|
||||
!acs_usable_vht80_chan(chan)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for VHT80",
|
||||
chan->chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_160MHZ &&
|
||||
!acs_usable_vht160_chan(chan)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: not allowed as primary channel for VHT160",
|
||||
chan->chan);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
factor = 0;
|
||||
@ -632,6 +677,13 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
if (!adj_chan)
|
||||
break;
|
||||
|
||||
if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
|
||||
chan->chan, adj_chan->chan, bw);
|
||||
break;
|
||||
}
|
||||
|
||||
if (acs_usable_chan(adj_chan)) {
|
||||
factor += adj_chan->interference_factor;
|
||||
total_weight += 1;
|
||||
@ -744,10 +796,14 @@ static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
offset = 6;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
offset = 14;
|
||||
break;
|
||||
default:
|
||||
/* TODO: How can this be calculated? Adjust
|
||||
* acs_find_ideal_chan() */
|
||||
wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
|
||||
wpa_printf(MSG_INFO,
|
||||
"ACS: Only VHT20/40/80/160 is supported now");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,15 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
* This can be enabled by default once the implementation has been fully
|
||||
* completed and tested with other implementations. */
|
||||
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
|
||||
|
||||
bss->send_probe_response = 1;
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
bss->hs20_release = (HS20_VERSION >> 4) + 1;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
/* Default to strict CRL checking. */
|
||||
bss->check_crl_strict = 1;
|
||||
}
|
||||
|
||||
|
||||
@ -191,9 +200,8 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->num_bss = 1;
|
||||
|
||||
conf->beacon_int = 100;
|
||||
conf->rts_threshold = -1; /* use driver default: 2347 */
|
||||
conf->fragm_threshold = -1; /* user driver default: 2346 */
|
||||
conf->send_probe_response = 1;
|
||||
conf->rts_threshold = -2; /* use driver default: 2347 */
|
||||
conf->fragm_threshold = -2; /* user driver default: 2346 */
|
||||
/* Set to invalid value means do not add Power Constraint IE */
|
||||
conf->local_pwr_constraint = -1;
|
||||
|
||||
@ -233,6 +241,9 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
* environments for the current frequency band in the country. */
|
||||
conf->country[2] = ' ';
|
||||
|
||||
conf->rssi_reject_assoc_rssi = 0;
|
||||
conf->rssi_reject_assoc_timeout = 30;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -248,6 +259,12 @@ static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
{
|
||||
FILE *f;
|
||||
char buf[128], *pos;
|
||||
const char *keyid;
|
||||
char *context;
|
||||
char *context2;
|
||||
char *token;
|
||||
char *name;
|
||||
char *value;
|
||||
int line = 0, ret = 0, len, ok;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct hostapd_wpa_psk *psk;
|
||||
@ -262,6 +279,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
int vlan_id = 0;
|
||||
|
||||
line++;
|
||||
|
||||
if (buf[0] == '#')
|
||||
@ -277,9 +296,39 @@ static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
if (buf[0] == '\0')
|
||||
continue;
|
||||
|
||||
if (hwaddr_aton(buf, addr)) {
|
||||
context = NULL;
|
||||
keyid = NULL;
|
||||
while ((token = str_token(buf, " ", &context))) {
|
||||
if (!os_strchr(token, '='))
|
||||
break;
|
||||
context2 = NULL;
|
||||
name = str_token(token, "=", &context2);
|
||||
if (!name)
|
||||
break;
|
||||
value = str_token(token, "", &context2);
|
||||
if (!value)
|
||||
value = "";
|
||||
if (!os_strcmp(name, "keyid")) {
|
||||
keyid = value;
|
||||
} else if (!os_strcmp(name, "vlanid")) {
|
||||
vlan_id = atoi(value);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Unrecognized '%s=%s' on line %d in '%s'",
|
||||
name, value, line, fname);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
if (!token)
|
||||
token = "";
|
||||
if (hwaddr_aton(token, addr)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
|
||||
"line %d in '%s'", buf, line, fname);
|
||||
"line %d in '%s'", token, line, fname);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
@ -290,20 +339,20 @@ static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
psk->vlan_id = vlan_id;
|
||||
if (is_zero_ether_addr(addr))
|
||||
psk->group = 1;
|
||||
else
|
||||
os_memcpy(psk->addr, addr, ETH_ALEN);
|
||||
|
||||
pos = buf + 17;
|
||||
if (*pos == '\0') {
|
||||
pos = str_token(buf, "", &context);
|
||||
if (!pos) {
|
||||
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
|
||||
line, fname);
|
||||
os_free(psk);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
|
||||
ok = 0;
|
||||
len = os_strlen(pos);
|
||||
@ -322,6 +371,18 @@ static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyid) {
|
||||
len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid));
|
||||
if ((size_t) len >= sizeof(psk->keyid)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"PSK keyid too long on line %d in '%s'",
|
||||
line, fname);
|
||||
os_free(psk);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
psk->next = ssid->wpa_psk;
|
||||
ssid->wpa_psk = psk;
|
||||
}
|
||||
@ -534,10 +595,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->server_cert);
|
||||
os_free(conf->private_key);
|
||||
os_free(conf->private_key_passwd);
|
||||
os_free(conf->check_cert_subject);
|
||||
os_free(conf->ocsp_stapling_response);
|
||||
os_free(conf->ocsp_stapling_response_multi);
|
||||
os_free(conf->dh_file);
|
||||
os_free(conf->openssl_ciphers);
|
||||
os_free(conf->openssl_ecdh_curves);
|
||||
os_free(conf->pac_opaque_encr_key);
|
||||
os_free(conf->eap_fast_a_id);
|
||||
os_free(conf->eap_fast_a_id_info);
|
||||
@ -582,6 +645,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->ap_pin);
|
||||
os_free(conf->extra_cred);
|
||||
os_free(conf->ap_settings);
|
||||
hostapd_config_clear_wpa_psk(&conf->multi_ap_backhaul_ssid.wpa_psk);
|
||||
str_clear_free(conf->multi_ap_backhaul_ssid.wpa_passphrase);
|
||||
os_free(conf->upnp_iface);
|
||||
os_free(conf->friendly_name);
|
||||
os_free(conf->manufacturer_url);
|
||||
@ -644,6 +709,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->hs20_operator_icon);
|
||||
}
|
||||
os_free(conf->subscr_remediation_url);
|
||||
os_free(conf->hs20_sim_provisioning_url);
|
||||
os_free(conf->t_c_filename);
|
||||
os_free(conf->t_c_server_url);
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -802,11 +868,14 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
|
||||
|
||||
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
const u8 *addr, const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk)
|
||||
const u8 *prev_psk, int *vlan_id)
|
||||
{
|
||||
struct hostapd_wpa_psk *psk;
|
||||
int next_ok = prev_psk == NULL;
|
||||
|
||||
if (vlan_id)
|
||||
*vlan_id = 0;
|
||||
|
||||
if (p2p_dev_addr && !is_zero_ether_addr(p2p_dev_addr)) {
|
||||
wpa_printf(MSG_DEBUG, "Searching a PSK for " MACSTR
|
||||
" p2p_dev_addr=" MACSTR " prev_psk=%p",
|
||||
@ -824,8 +893,11 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
(addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) ||
|
||||
(!addr && p2p_dev_addr &&
|
||||
os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
|
||||
0)))
|
||||
0))) {
|
||||
if (vlan_id)
|
||||
*vlan_id = psk->vlan_id;
|
||||
return psk->psk;
|
||||
}
|
||||
|
||||
if (psk->psk == prev_psk)
|
||||
next_ok = 1;
|
||||
@ -1003,6 +1075,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (full_config && bss->ieee80211w == NO_MGMT_FRAME_PROTECTION &&
|
||||
bss->ocv) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OCV: PMF needs to be enabled whenever using OCV");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1146,3 +1227,26 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
|
||||
{
|
||||
int with_id = 0, without_id = 0;
|
||||
struct sae_password_entry *pw;
|
||||
|
||||
if (conf->ssid.wpa_passphrase)
|
||||
without_id = 1;
|
||||
|
||||
for (pw = conf->sae_passwords; pw; pw = pw->next) {
|
||||
if (pw->identifier)
|
||||
with_id = 1;
|
||||
else
|
||||
without_id = 1;
|
||||
if (with_id && without_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (with_id && !without_id)
|
||||
return 2;
|
||||
return with_id;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ struct mesh_conf {
|
||||
#define MESH_CONF_SEC_AMPE BIT(2)
|
||||
unsigned int security;
|
||||
enum mfp_options ieee80211w;
|
||||
int ocv;
|
||||
unsigned int pairwise_cipher;
|
||||
unsigned int group_cipher;
|
||||
unsigned int mgmt_group_cipher;
|
||||
@ -122,6 +123,7 @@ struct hostapd_vlan {
|
||||
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
|
||||
struct vlan_description vlan_desc;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
char bridge[IFNAMSIZ + 1];
|
||||
int configured;
|
||||
int dynamic_vlan;
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
@ -132,6 +134,7 @@ struct hostapd_vlan {
|
||||
};
|
||||
|
||||
#define PMK_LEN 32
|
||||
#define KEYID_LEN 32
|
||||
#define MIN_PASSPHRASE_LEN 8
|
||||
#define MAX_PASSPHRASE_LEN 63
|
||||
struct hostapd_sta_wpa_psk_short {
|
||||
@ -145,9 +148,11 @@ struct hostapd_sta_wpa_psk_short {
|
||||
struct hostapd_wpa_psk {
|
||||
struct hostapd_wpa_psk *next;
|
||||
int group;
|
||||
char keyid[KEYID_LEN];
|
||||
u8 psk[PMK_LEN];
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 p2p_dev_addr[ETH_ALEN];
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
struct hostapd_eap_user {
|
||||
@ -244,6 +249,7 @@ struct sae_password_entry {
|
||||
char *password;
|
||||
char *identifier;
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
int vlan_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -335,6 +341,9 @@ struct hostapd_bss_config {
|
||||
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
|
||||
int assoc_sa_query_retry_timeout;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
int ocv; /* Operating Channel Validation */
|
||||
#endif /* CONFIG_OCV */
|
||||
enum {
|
||||
PSK_RADIUS_IGNORED = 0,
|
||||
PSK_RADIUS_ACCEPTED = 1,
|
||||
@ -383,13 +392,17 @@ struct hostapd_bss_config {
|
||||
char *server_cert;
|
||||
char *private_key;
|
||||
char *private_key_passwd;
|
||||
char *check_cert_subject;
|
||||
int check_crl;
|
||||
int check_crl_strict;
|
||||
unsigned int crl_reload_interval;
|
||||
unsigned int tls_session_lifetime;
|
||||
unsigned int tls_flags;
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
char *dh_file;
|
||||
char *openssl_ciphers;
|
||||
char *openssl_ecdh_curves;
|
||||
u8 *pac_opaque_encr_key;
|
||||
u8 *eap_fast_a_id;
|
||||
size_t eap_fast_a_id_len;
|
||||
@ -452,9 +465,11 @@ struct hostapd_bss_config {
|
||||
u8 *extra_cred;
|
||||
size_t extra_cred_len;
|
||||
int wps_cred_processing;
|
||||
int wps_cred_add_sae;
|
||||
int force_per_enrollee_psk;
|
||||
u8 *ap_settings;
|
||||
size_t ap_settings_len;
|
||||
struct hostapd_ssid multi_ap_backhaul_ssid;
|
||||
char *upnp_iface;
|
||||
char *friendly_name;
|
||||
char *manufacturer_url;
|
||||
@ -557,6 +572,7 @@ struct hostapd_bss_config {
|
||||
int na_mcast_to_ucast;
|
||||
#ifdef CONFIG_HS20
|
||||
int hs20;
|
||||
int hs20_release;
|
||||
int disable_dgaf;
|
||||
u16 anqp_domain_id;
|
||||
unsigned int hs20_oper_friendly_name_count;
|
||||
@ -596,6 +612,7 @@ struct hostapd_bss_config {
|
||||
unsigned int hs20_deauth_req_timeout;
|
||||
char *subscr_remediation_url;
|
||||
u8 subscr_remediation_method;
|
||||
char *hs20_sim_provisioning_url;
|
||||
char *t_c_filename;
|
||||
u32 t_c_timestamp;
|
||||
char *t_c_server_url;
|
||||
@ -686,6 +703,12 @@ struct hostapd_bss_config {
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
int coloc_intf_reporting;
|
||||
|
||||
u8 send_probe_response;
|
||||
|
||||
#define BACKHAUL_BSS 1
|
||||
#define FRONTHAUL_BSS 2
|
||||
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -717,7 +740,6 @@ struct hostapd_config {
|
||||
u16 beacon_int;
|
||||
int rts_threshold;
|
||||
int fragm_threshold;
|
||||
u8 send_probe_response;
|
||||
u8 channel;
|
||||
u8 acs;
|
||||
struct wpa_freq_range_list acs_ch_list;
|
||||
@ -829,12 +851,16 @@ struct hostapd_config {
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
struct he_phy_capabilities_info he_phy_capab;
|
||||
struct he_operation he_op;
|
||||
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* VHT enable/disable config from CHAN_SWITCH */
|
||||
#define CH_SWITCH_VHT_ENABLED BIT(0)
|
||||
#define CH_SWITCH_VHT_DISABLED BIT(1)
|
||||
unsigned int ch_switch_vht_config;
|
||||
|
||||
int rssi_reject_assoc_rssi;
|
||||
int rssi_reject_assoc_timeout;
|
||||
};
|
||||
|
||||
|
||||
@ -851,7 +877,7 @@ int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
|
||||
int hostapd_rate_found(int *list, int rate);
|
||||
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
const u8 *addr, const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk);
|
||||
const u8 *prev_psk, int *vlan_id);
|
||||
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
|
||||
int hostapd_vlan_valid(struct hostapd_vlan *vlan,
|
||||
struct vlan_description *vlan_desc);
|
||||
@ -862,5 +888,6 @@ hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
|
||||
int hostapd_config_check(struct hostapd_config *conf, int full_config);
|
||||
void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
int full_config);
|
||||
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
|
||||
|
||||
#endif /* HOSTAPD_CONFIG_H */
|
||||
|
@ -356,4 +356,22 @@ static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
|
||||
return hapd->driver->stop_ap(hapd->drv_priv);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
|
||||
struct wpa_channel_info *ci)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->channel_info)
|
||||
return -1;
|
||||
return hapd->driver->channel_info(hapd->drv_priv, ci);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
|
||||
struct external_auth *params)
|
||||
{
|
||||
if (!hapd->driver || !hapd->drv_priv ||
|
||||
!hapd->driver->send_external_auth_status)
|
||||
return -1;
|
||||
return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
|
||||
}
|
||||
|
||||
#endif /* AP_DRV_OPS */
|
||||
|
@ -136,6 +136,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#ifdef CONFIG_HS20
|
||||
srv.subscr_remediation_url = conf->subscr_remediation_url;
|
||||
srv.subscr_remediation_method = conf->subscr_remediation_method;
|
||||
srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
|
||||
srv.t_c_server_url = conf->t_c_server_url;
|
||||
#endif /* CONFIG_HS20 */
|
||||
srv.erp = conf->eap_server_erp;
|
||||
@ -200,6 +201,16 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
|
||||
os_memset(&conf, 0, sizeof(conf));
|
||||
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
if (hapd->conf->crl_reload_interval > 0 &&
|
||||
hapd->conf->check_crl <= 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Cannot enable CRL reload functionality - it depends on check_crl being set");
|
||||
} else if (hapd->conf->crl_reload_interval > 0) {
|
||||
conf.crl_reload_interval =
|
||||
hapd->conf->crl_reload_interval;
|
||||
wpa_printf(MSG_INFO,
|
||||
"Enabled CRL reload functionality");
|
||||
}
|
||||
conf.tls_flags = hapd->conf->tls_flags;
|
||||
conf.event_cb = authsrv_tls_event;
|
||||
conf.cb_ctx = hapd;
|
||||
@ -217,10 +228,12 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
params.private_key_passwd = hapd->conf->private_key_passwd;
|
||||
params.dh_file = hapd->conf->dh_file;
|
||||
params.openssl_ciphers = hapd->conf->openssl_ciphers;
|
||||
params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
|
||||
params.ocsp_stapling_response =
|
||||
hapd->conf->ocsp_stapling_response;
|
||||
params.ocsp_stapling_response_multi =
|
||||
hapd->conf->ocsp_stapling_response_multi;
|
||||
params.check_cert_subject = hapd->conf->check_cert_subject;
|
||||
|
||||
if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
|
||||
@ -229,7 +242,8 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
if (tls_global_set_verify(hapd->ssl_ctx,
|
||||
hapd->conf->check_crl)) {
|
||||
hapd->conf->check_crl,
|
||||
hapd->conf->check_crl_strict)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to enable check_crl");
|
||||
authsrv_deinit(hapd);
|
||||
return -1;
|
||||
|
@ -397,7 +397,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -510,6 +511,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
pos = hostapd_eid_he_capab(hapd, pos);
|
||||
pos = hostapd_eid_he_operation(hapd, pos);
|
||||
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -767,7 +769,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
ie, ie_len, ssi_signal) > 0)
|
||||
return;
|
||||
|
||||
if (!hapd->iconf->send_probe_response)
|
||||
if (!hapd->conf->send_probe_response)
|
||||
return;
|
||||
|
||||
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
|
||||
@ -1085,7 +1087,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -1222,6 +1225,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_operation(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -1357,6 +1361,18 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
|
||||
params->pbss = hapd->conf->pbss;
|
||||
|
||||
if (hapd->conf->ftm_responder) {
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
|
||||
params->ftm_responder = 1;
|
||||
params->lci = hapd->iface->conf->lci;
|
||||
params->civic = hapd->iface->conf->civic;
|
||||
} else {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Not configuring FTM responder as the driver doesn't advertise support for it");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Control interface for shared AP commands
|
||||
* Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
|
||||
* 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.
|
||||
@ -207,6 +207,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
int len, res, ret, i;
|
||||
const char *keyid;
|
||||
|
||||
if (!sta)
|
||||
return 0;
|
||||
@ -341,6 +342,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += ret;
|
||||
}
|
||||
|
||||
keyid = ap_sta_wpa_get_keyid(hapd, sta);
|
||||
if (keyid) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -443,11 +451,11 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
|
||||
if (stype == WLAN_FC_STYPE_DEAUTH) {
|
||||
mgmt->u.deauth.reason_code =
|
||||
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
|
||||
pos = mgmt->u.deauth.variable;
|
||||
} else {
|
||||
mgmt->u.disassoc.reason_code =
|
||||
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
|
||||
pos = mgmt->u.disassoc.variable;
|
||||
}
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
|
@ -142,18 +142,30 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
{
|
||||
struct hostapd_channel_data *first_chan, *chan;
|
||||
int i;
|
||||
u32 bw = num_chan_to_bw(num_chans);
|
||||
|
||||
if (first_chan_idx + num_chans > mode->num_channels)
|
||||
return 0;
|
||||
|
||||
first_chan = &mode->channels[first_chan_idx];
|
||||
|
||||
/* hostapd DFS implementation assumes the first channel as primary.
|
||||
* If it's not allowed to use the first channel as primary, decline the
|
||||
* whole channel range. */
|
||||
if (!chan_pri_allowed(first_chan))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < num_chans; i++) {
|
||||
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
|
||||
first_chan_idx);
|
||||
if (!chan)
|
||||
return 0;
|
||||
|
||||
/* HT 40 MHz secondary channel availability checked only for
|
||||
* primary channel */
|
||||
if (!chan_bw_allowed(chan, bw, 1, !i))
|
||||
return 0;
|
||||
|
||||
if (!dfs_channel_available(chan, skip_radar))
|
||||
return 0;
|
||||
}
|
||||
@ -197,7 +209,8 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
/* Skip HT40/VHT incompatible channels */
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel &&
|
||||
!dfs_is_chan_allowed(chan, n_chans))
|
||||
(!dfs_is_chan_allowed(chan, n_chans) ||
|
||||
!(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
|
||||
continue;
|
||||
|
||||
/* Skip incompatible chandefs */
|
||||
|
@ -88,6 +88,15 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (!(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
continue;
|
||||
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
|
||||
(u8 *) buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (msgtype == DHCPACK) {
|
||||
if (b->your_ip == 0)
|
||||
return;
|
||||
@ -124,15 +133,6 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
}
|
||||
sta->ipaddr = b->your_ip;
|
||||
}
|
||||
|
||||
if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (!(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
continue;
|
||||
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
|
||||
(u8 *) buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,34 +28,6 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
|
||||
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
|
||||
static struct dpp_configurator *
|
||||
hostapd_dpp_configurator_get_id(struct hostapd_data *hapd, unsigned int id)
|
||||
{
|
||||
struct dpp_configurator *conf;
|
||||
|
||||
dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
|
||||
struct dpp_configurator, list) {
|
||||
if (conf->id == id)
|
||||
return conf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int hapd_dpp_next_id(struct hostapd_data *hapd)
|
||||
{
|
||||
struct dpp_bootstrap_info *bi;
|
||||
unsigned int max_id = 0;
|
||||
|
||||
dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
|
||||
struct dpp_bootstrap_info, list) {
|
||||
if (bi->id > max_id)
|
||||
max_id = bi->id;
|
||||
}
|
||||
return max_id + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
|
||||
* @hapd: Pointer to hostapd_data
|
||||
@ -67,13 +39,10 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
|
||||
struct dpp_bootstrap_info *bi;
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
|
||||
bi = dpp_parse_qr_code(cmd);
|
||||
bi = dpp_add_qr_code(hapd->iface->interfaces->dpp, cmd);
|
||||
if (!bi)
|
||||
return -1;
|
||||
|
||||
bi->id = hapd_dpp_next_id(hapd);
|
||||
dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
|
||||
|
||||
if (auth && auth->response_pending &&
|
||||
dpp_notify_new_qr_code(auth, bi) == 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -92,195 +61,6 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
|
||||
}
|
||||
|
||||
|
||||
static char * get_param(const char *cmd, const char *param)
|
||||
{
|
||||
const char *pos, *end;
|
||||
char *val;
|
||||
size_t len;
|
||||
|
||||
pos = os_strstr(cmd, param);
|
||||
if (!pos)
|
||||
return NULL;
|
||||
|
||||
pos += os_strlen(param);
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
val = os_malloc(len + 1);
|
||||
if (!val)
|
||||
return NULL;
|
||||
os_memcpy(val, pos, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
|
||||
char *key = NULL;
|
||||
u8 *privkey = NULL;
|
||||
size_t privkey_len = 0;
|
||||
size_t len;
|
||||
int ret = -1;
|
||||
struct dpp_bootstrap_info *bi;
|
||||
|
||||
bi = os_zalloc(sizeof(*bi));
|
||||
if (!bi)
|
||||
goto fail;
|
||||
|
||||
if (os_strstr(cmd, "type=qrcode"))
|
||||
bi->type = DPP_BOOTSTRAP_QR_CODE;
|
||||
else if (os_strstr(cmd, "type=pkex"))
|
||||
bi->type = DPP_BOOTSTRAP_PKEX;
|
||||
else
|
||||
goto fail;
|
||||
|
||||
chan = get_param(cmd, " chan=");
|
||||
mac = get_param(cmd, " mac=");
|
||||
info = get_param(cmd, " info=");
|
||||
curve = get_param(cmd, " curve=");
|
||||
key = get_param(cmd, " key=");
|
||||
|
||||
if (key) {
|
||||
privkey_len = os_strlen(key) / 2;
|
||||
privkey = os_malloc(privkey_len);
|
||||
if (!privkey ||
|
||||
hexstr2bin(key, privkey, privkey_len) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pk = dpp_keygen(bi, curve, privkey, privkey_len);
|
||||
if (!pk)
|
||||
goto fail;
|
||||
|
||||
len = 4; /* "DPP:" */
|
||||
if (chan) {
|
||||
if (dpp_parse_uri_chan_list(bi, chan) < 0)
|
||||
goto fail;
|
||||
len += 3 + os_strlen(chan); /* C:...; */
|
||||
}
|
||||
if (mac) {
|
||||
if (dpp_parse_uri_mac(bi, mac) < 0)
|
||||
goto fail;
|
||||
len += 3 + os_strlen(mac); /* M:...; */
|
||||
}
|
||||
if (info) {
|
||||
if (dpp_parse_uri_info(bi, info) < 0)
|
||||
goto fail;
|
||||
len += 3 + os_strlen(info); /* I:...; */
|
||||
}
|
||||
len += 4 + os_strlen(pk);
|
||||
bi->uri = os_malloc(len + 1);
|
||||
if (!bi->uri)
|
||||
goto fail;
|
||||
os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
|
||||
chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
|
||||
mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
|
||||
info ? "I:" : "", info ? info : "", info ? ";" : "",
|
||||
pk);
|
||||
bi->id = hapd_dpp_next_id(hapd);
|
||||
dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
|
||||
ret = bi->id;
|
||||
bi = NULL;
|
||||
fail:
|
||||
os_free(curve);
|
||||
os_free(pk);
|
||||
os_free(chan);
|
||||
os_free(mac);
|
||||
os_free(info);
|
||||
str_clear_free(key);
|
||||
bin_clear_free(privkey, privkey_len);
|
||||
dpp_bootstrap_info_free(bi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct dpp_bootstrap_info *
|
||||
dpp_bootstrap_get_id(struct hostapd_data *hapd, unsigned int id)
|
||||
{
|
||||
struct dpp_bootstrap_info *bi;
|
||||
|
||||
dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
|
||||
struct dpp_bootstrap_info, list) {
|
||||
if (bi->id == id)
|
||||
return bi;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int dpp_bootstrap_del(struct hapd_interfaces *ifaces, unsigned int id)
|
||||
{
|
||||
struct dpp_bootstrap_info *bi, *tmp;
|
||||
int found = 0;
|
||||
|
||||
dl_list_for_each_safe(bi, tmp, &ifaces->dpp_bootstrap,
|
||||
struct dpp_bootstrap_info, list) {
|
||||
if (id && bi->id != id)
|
||||
continue;
|
||||
found = 1;
|
||||
dl_list_del(&bi->list);
|
||||
dpp_bootstrap_info_free(bi);
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
return 0; /* flush succeeds regardless of entries found */
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id)
|
||||
{
|
||||
unsigned int id_val;
|
||||
|
||||
if (os_strcmp(id, "*") == 0) {
|
||||
id_val = 0;
|
||||
} else {
|
||||
id_val = atoi(id);
|
||||
if (id_val == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dpp_bootstrap_del(hapd->iface->interfaces, id_val);
|
||||
}
|
||||
|
||||
|
||||
const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
|
||||
unsigned int id)
|
||||
{
|
||||
struct dpp_bootstrap_info *bi;
|
||||
|
||||
bi = dpp_bootstrap_get_id(hapd, id);
|
||||
if (!bi)
|
||||
return NULL;
|
||||
return bi->uri;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
|
||||
char *reply, int reply_size)
|
||||
{
|
||||
struct dpp_bootstrap_info *bi;
|
||||
|
||||
bi = dpp_bootstrap_get_id(hapd, id);
|
||||
if (!bi)
|
||||
return -1;
|
||||
return os_snprintf(reply, reply_size, "type=%s\n"
|
||||
"mac_addr=" MACSTR "\n"
|
||||
"info=%s\n"
|
||||
"num_freq=%u\n"
|
||||
"curve=%s\n",
|
||||
dpp_bootstrap_type_txt(bi->type),
|
||||
MAC2STR(bi->mac_addr),
|
||||
bi->info ? bi->info : "",
|
||||
bi->num_freq,
|
||||
bi->curve->name);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
@ -354,6 +134,16 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (auth->connect_on_tx_status) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Complete exchange on configuration result");
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
if (hapd->dpp_auth->remove_on_tx_status) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Terminate authentication exchange due to an earlier error");
|
||||
@ -505,178 +295,6 @@ static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dpp_set_configurator(struct hostapd_data *hapd,
|
||||
struct dpp_authentication *auth,
|
||||
const char *cmd)
|
||||
{
|
||||
const char *pos, *end;
|
||||
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
|
||||
struct dpp_configurator *conf = NULL;
|
||||
u8 ssid[32] = { "test" };
|
||||
size_t ssid_len = 4;
|
||||
char pass[64] = { };
|
||||
size_t pass_len = 0;
|
||||
u8 psk[PMK_LEN];
|
||||
int psk_set = 0;
|
||||
char *group_id = NULL;
|
||||
|
||||
if (!cmd)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
|
||||
pos = os_strstr(cmd, " ssid=");
|
||||
if (pos) {
|
||||
pos += 6;
|
||||
end = os_strchr(pos, ' ');
|
||||
ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
|
||||
ssid_len /= 2;
|
||||
if (ssid_len > sizeof(ssid) ||
|
||||
hexstr2bin(pos, ssid, ssid_len) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " pass=");
|
||||
if (pos) {
|
||||
pos += 6;
|
||||
end = os_strchr(pos, ' ');
|
||||
pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
|
||||
pass_len /= 2;
|
||||
if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
|
||||
hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " psk=");
|
||||
if (pos) {
|
||||
pos += 5;
|
||||
if (hexstr2bin(pos, psk, PMK_LEN) < 0)
|
||||
goto fail;
|
||||
psk_set = 1;
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " group_id=");
|
||||
if (pos) {
|
||||
size_t group_id_len;
|
||||
|
||||
pos += 10;
|
||||
end = os_strchr(pos, ' ');
|
||||
group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
|
||||
group_id = os_malloc(group_id_len + 1);
|
||||
if (!group_id)
|
||||
goto fail;
|
||||
os_memcpy(group_id, pos, group_id_len);
|
||||
group_id[group_id_len] = '\0';
|
||||
}
|
||||
|
||||
if (os_strstr(cmd, " conf=sta-")) {
|
||||
conf_sta = os_zalloc(sizeof(struct dpp_configuration));
|
||||
if (!conf_sta)
|
||||
goto fail;
|
||||
os_memcpy(conf_sta->ssid, ssid, ssid_len);
|
||||
conf_sta->ssid_len = ssid_len;
|
||||
if (os_strstr(cmd, " conf=sta-psk") ||
|
||||
os_strstr(cmd, " conf=sta-sae") ||
|
||||
os_strstr(cmd, " conf=sta-psk-sae")) {
|
||||
if (os_strstr(cmd, " conf=sta-psk-sae"))
|
||||
conf_sta->akm = DPP_AKM_PSK_SAE;
|
||||
else if (os_strstr(cmd, " conf=sta-sae"))
|
||||
conf_sta->akm = DPP_AKM_SAE;
|
||||
else
|
||||
conf_sta->akm = DPP_AKM_PSK;
|
||||
if (psk_set) {
|
||||
os_memcpy(conf_sta->psk, psk, PMK_LEN);
|
||||
} else {
|
||||
conf_sta->passphrase = os_strdup(pass);
|
||||
if (!conf_sta->passphrase)
|
||||
goto fail;
|
||||
}
|
||||
} else if (os_strstr(cmd, " conf=sta-dpp")) {
|
||||
conf_sta->akm = DPP_AKM_DPP;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
if (os_strstr(cmd, " group_id=")) {
|
||||
conf_sta->group_id = group_id;
|
||||
group_id = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (os_strstr(cmd, " conf=ap-")) {
|
||||
conf_ap = os_zalloc(sizeof(struct dpp_configuration));
|
||||
if (!conf_ap)
|
||||
goto fail;
|
||||
os_memcpy(conf_ap->ssid, ssid, ssid_len);
|
||||
conf_ap->ssid_len = ssid_len;
|
||||
if (os_strstr(cmd, " conf=ap-psk") ||
|
||||
os_strstr(cmd, " conf=ap-sae") ||
|
||||
os_strstr(cmd, " conf=ap-psk-sae")) {
|
||||
if (os_strstr(cmd, " conf=ap-psk-sae"))
|
||||
conf_ap->akm = DPP_AKM_PSK_SAE;
|
||||
else if (os_strstr(cmd, " conf=ap-sae"))
|
||||
conf_ap->akm = DPP_AKM_SAE;
|
||||
else
|
||||
conf_ap->akm = DPP_AKM_PSK;
|
||||
if (psk_set) {
|
||||
os_memcpy(conf_ap->psk, psk, PMK_LEN);
|
||||
} else if (pass_len > 0) {
|
||||
conf_ap->passphrase = os_strdup(pass);
|
||||
if (!conf_ap->passphrase)
|
||||
goto fail;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
} else if (os_strstr(cmd, " conf=ap-dpp")) {
|
||||
conf_ap->akm = DPP_AKM_DPP;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
if (os_strstr(cmd, " group_id=")) {
|
||||
conf_ap->group_id = group_id;
|
||||
group_id = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " expiry=");
|
||||
if (pos) {
|
||||
long int val;
|
||||
|
||||
pos += 8;
|
||||
val = strtol(pos, NULL, 0);
|
||||
if (val <= 0)
|
||||
goto fail;
|
||||
if (conf_sta)
|
||||
conf_sta->netaccesskey_expiry = val;
|
||||
if (conf_ap)
|
||||
conf_ap->netaccesskey_expiry = val;
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " configurator=");
|
||||
if (pos) {
|
||||
auth->configurator = 1;
|
||||
pos += 14;
|
||||
conf = hostapd_dpp_configurator_get_id(hapd, atoi(pos));
|
||||
if (!conf) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"DPP: Could not find the specified configurator");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
auth->conf_sta = conf_sta;
|
||||
auth->conf_ap = conf_ap;
|
||||
auth->conf = conf;
|
||||
os_free(group_id);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
"DPP: Failed to set configurator parameters");
|
||||
dpp_configuration_free(conf_sta);
|
||||
dpp_configuration_free(conf_ap);
|
||||
os_free(group_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
@ -786,7 +404,7 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos += 6;
|
||||
peer_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
|
||||
peer_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
|
||||
if (!peer_bi) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"DPP: Could not find bootstrapping info for the identified peer");
|
||||
@ -796,7 +414,8 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
pos = os_strstr(cmd, " own=");
|
||||
if (pos) {
|
||||
pos += 5;
|
||||
own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
|
||||
own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
|
||||
atoi(pos));
|
||||
if (!own_bi) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"DPP: Could not find bootstrapping info for the identified local entry");
|
||||
@ -846,7 +465,8 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
if (!hapd->dpp_auth)
|
||||
goto fail;
|
||||
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
|
||||
if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd) < 0) {
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
hapd->dpp_auth, cmd) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
goto fail;
|
||||
@ -905,7 +525,10 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
{
|
||||
const u8 *r_bootstrap, *i_bootstrap;
|
||||
u16 r_bootstrap_len, i_bootstrap_len;
|
||||
struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
|
||||
struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
|
||||
|
||||
if (!hapd->iface->interfaces->dpp)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
|
||||
MAC2STR(src));
|
||||
@ -932,28 +555,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
|
||||
/* Try to find own and peer bootstrapping key matches based on the
|
||||
* received hash values */
|
||||
dl_list_for_each(bi, &hapd->iface->interfaces->dpp_bootstrap,
|
||||
struct dpp_bootstrap_info, list) {
|
||||
if (!own_bi && bi->own &&
|
||||
os_memcmp(bi->pubkey_hash, r_bootstrap,
|
||||
SHA256_MAC_LEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Found matching own bootstrapping information");
|
||||
own_bi = bi;
|
||||
}
|
||||
|
||||
if (!peer_bi && !bi->own &&
|
||||
os_memcmp(bi->pubkey_hash, i_bootstrap,
|
||||
SHA256_MAC_LEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Found matching peer bootstrapping information");
|
||||
peer_bi = bi;
|
||||
}
|
||||
|
||||
if (own_bi && peer_bi)
|
||||
break;
|
||||
}
|
||||
|
||||
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
|
||||
r_bootstrap, &own_bi, &peer_bi);
|
||||
if (!own_bi) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||
"No matching own bootstrapping key found - ignore message");
|
||||
@ -975,8 +578,9 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
return;
|
||||
}
|
||||
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
|
||||
if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
|
||||
hapd->dpp_configurator_params) < 0) {
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
hapd->dpp_auth,
|
||||
hapd->dpp_configurator_params) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
return;
|
||||
@ -1072,6 +676,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
|
||||
struct hostapd_data *hapd = ctx;
|
||||
const u8 *pos;
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
|
||||
|
||||
if (!auth || !auth->auth_success) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
|
||||
@ -1107,12 +712,41 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
|
||||
}
|
||||
|
||||
hostapd_dpp_handle_config_obj(hapd, auth);
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
return;
|
||||
|
||||
status = DPP_STATUS_OK;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
|
||||
wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
|
||||
status = DPP_STATUS_CONFIG_REJECTED;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
fail:
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
|
||||
if (status != DPP_STATUS_OK)
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
|
||||
#ifdef CONFIG_DPP2
|
||||
if (auth->peer_version >= 2 &&
|
||||
auth->conf_resp_status == DPP_STATUS_OK) {
|
||||
struct wpabuf *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
|
||||
msg = dpp_build_conf_result(auth, status);
|
||||
if (!msg)
|
||||
goto fail2;
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
|
||||
MAC2STR(addr), auth->curr_freq,
|
||||
DPP_PA_CONFIGURATION_RESULT);
|
||||
hostapd_drv_send_action(hapd, auth->curr_freq, 0,
|
||||
addr, wpabuf_head(msg),
|
||||
wpabuf_len(msg));
|
||||
wpabuf_free(msg);
|
||||
|
||||
/* This exchange will be terminated in the TX status handler */
|
||||
auth->connect_on_tx_status = 1;
|
||||
return;
|
||||
}
|
||||
fail2:
|
||||
#endif /* CONFIG_DPP2 */
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
}
|
||||
@ -1121,7 +755,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
|
||||
static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
|
||||
{
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
struct wpabuf *buf, *conf_req;
|
||||
struct wpabuf *buf;
|
||||
char json[100];
|
||||
int res;
|
||||
int netrole_ap = 1;
|
||||
@ -1133,34 +767,13 @@ static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
|
||||
netrole_ap ? "ap" : "sta");
|
||||
wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
|
||||
|
||||
conf_req = dpp_build_conf_req(auth, json);
|
||||
if (!conf_req) {
|
||||
buf = dpp_build_conf_req(auth, json);
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: No configuration request data available");
|
||||
return;
|
||||
}
|
||||
|
||||
buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
|
||||
if (!buf) {
|
||||
wpabuf_free(conf_req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advertisement Protocol IE */
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 8); /* Length */
|
||||
wpabuf_put_u8(buf, 0x7f);
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 5);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, DPP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, 0x01);
|
||||
|
||||
/* GAS Query */
|
||||
wpabuf_put_le16(buf, wpabuf_len(conf_req));
|
||||
wpabuf_put_buf(buf, conf_req);
|
||||
wpabuf_free(conf_req);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
|
||||
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
|
||||
|
||||
@ -1281,6 +894,63 @@ static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
|
||||
static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
|
||||
if (!auth || !auth->waiting_conf_result)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Timeout while waiting for Configuration Result");
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
|
||||
dpp_auth_deinit(auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *hdr, const u8 *buf, size_t len)
|
||||
{
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
enum dpp_status_error status;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
|
||||
MAC2STR(src));
|
||||
|
||||
if (!auth || !auth->waiting_conf_result) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: No DPP Configuration waiting for result - drop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
|
||||
MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
status = dpp_conf_result_rx(auth, hdr, buf, len);
|
||||
|
||||
hostapd_drv_send_action_cancel_wait(hapd);
|
||||
hostapd_dpp_listen_stop(hapd);
|
||||
if (status == DPP_STATUS_OK)
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
|
||||
else
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
|
||||
dpp_auth_deinit(auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
|
||||
NULL);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
|
||||
const u8 *src, unsigned int freq,
|
||||
u8 trans_id,
|
||||
@ -1596,24 +1266,10 @@ hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
|
||||
wpabuf_head(msg), wpabuf_len(msg));
|
||||
wpabuf_free(msg);
|
||||
|
||||
bi = os_zalloc(sizeof(*bi));
|
||||
bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
|
||||
if (!bi)
|
||||
return;
|
||||
bi->id = hapd_dpp_next_id(hapd);
|
||||
bi->type = DPP_BOOTSTRAP_PKEX;
|
||||
os_memcpy(bi->mac_addr, src, ETH_ALEN);
|
||||
bi->num_freq = 1;
|
||||
bi->freq[0] = freq;
|
||||
bi->curve = pkex->own_bi->curve;
|
||||
bi->pubkey = pkex->peer_bootstrap_key;
|
||||
pkex->peer_bootstrap_key = NULL;
|
||||
dpp_pkex_free(pkex);
|
||||
hapd->dpp_pkex = NULL;
|
||||
if (dpp_bootstrap_key_hash(bi) < 0) {
|
||||
dpp_bootstrap_info_free(bi);
|
||||
return;
|
||||
}
|
||||
dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
|
||||
}
|
||||
|
||||
|
||||
@ -1623,7 +1279,7 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
|
||||
unsigned int freq)
|
||||
{
|
||||
int res;
|
||||
struct dpp_bootstrap_info *bi, *own_bi;
|
||||
struct dpp_bootstrap_info *bi;
|
||||
struct dpp_pkex *pkex = hapd->dpp_pkex;
|
||||
char cmd[500];
|
||||
|
||||
@ -1641,26 +1297,10 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
|
||||
return;
|
||||
}
|
||||
|
||||
own_bi = pkex->own_bi;
|
||||
|
||||
bi = os_zalloc(sizeof(*bi));
|
||||
bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
|
||||
if (!bi)
|
||||
return;
|
||||
bi->id = hapd_dpp_next_id(hapd);
|
||||
bi->type = DPP_BOOTSTRAP_PKEX;
|
||||
os_memcpy(bi->mac_addr, src, ETH_ALEN);
|
||||
bi->num_freq = 1;
|
||||
bi->freq[0] = freq;
|
||||
bi->curve = own_bi->curve;
|
||||
bi->pubkey = pkex->peer_bootstrap_key;
|
||||
pkex->peer_bootstrap_key = NULL;
|
||||
dpp_pkex_free(pkex);
|
||||
hapd->dpp_pkex = NULL;
|
||||
if (dpp_bootstrap_key_hash(bi) < 0) {
|
||||
dpp_bootstrap_info_free(bi);
|
||||
return;
|
||||
}
|
||||
dl_list_add(&hapd->iface->interfaces->dpp_bootstrap, &bi->list);
|
||||
|
||||
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
|
||||
bi->id,
|
||||
@ -1744,6 +1384,11 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
|
||||
freq);
|
||||
break;
|
||||
#ifdef CONFIG_DPP2
|
||||
case DPP_PA_CONFIGURATION_RESULT:
|
||||
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
|
||||
break;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Ignored unsupported frame subtype %d", type);
|
||||
@ -1790,11 +1435,28 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
|
||||
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
|
||||
{
|
||||
if (!hapd->dpp_auth)
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
|
||||
if (!auth)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
|
||||
ok);
|
||||
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
if (ok && auth->peer_version >= 2 &&
|
||||
auth->conf_resp_status == DPP_STATUS_OK) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
|
||||
auth->waiting_conf_result = 1;
|
||||
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
|
||||
hapd, NULL);
|
||||
eloop_register_timeout(2, 0,
|
||||
hostapd_dpp_config_result_wait_timeout,
|
||||
hapd, NULL);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
hostapd_drv_send_action_cancel_wait(hapd);
|
||||
|
||||
if (ok)
|
||||
@ -1806,93 +1468,6 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
|
||||
}
|
||||
|
||||
|
||||
static unsigned int hostapd_dpp_next_configurator_id(struct hostapd_data *hapd)
|
||||
{
|
||||
struct dpp_configurator *conf;
|
||||
unsigned int max_id = 0;
|
||||
|
||||
dl_list_for_each(conf, &hapd->iface->interfaces->dpp_configurator,
|
||||
struct dpp_configurator, list) {
|
||||
if (conf->id > max_id)
|
||||
max_id = conf->id;
|
||||
}
|
||||
return max_id + 1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
char *curve = NULL;
|
||||
char *key = NULL;
|
||||
u8 *privkey = NULL;
|
||||
size_t privkey_len = 0;
|
||||
int ret = -1;
|
||||
struct dpp_configurator *conf = NULL;
|
||||
|
||||
curve = get_param(cmd, " curve=");
|
||||
key = get_param(cmd, " key=");
|
||||
|
||||
if (key) {
|
||||
privkey_len = os_strlen(key) / 2;
|
||||
privkey = os_malloc(privkey_len);
|
||||
if (!privkey ||
|
||||
hexstr2bin(key, privkey, privkey_len) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
conf = dpp_keygen_configurator(curve, privkey, privkey_len);
|
||||
if (!conf)
|
||||
goto fail;
|
||||
|
||||
conf->id = hostapd_dpp_next_configurator_id(hapd);
|
||||
dl_list_add(&hapd->iface->interfaces->dpp_configurator, &conf->list);
|
||||
ret = conf->id;
|
||||
conf = NULL;
|
||||
fail:
|
||||
os_free(curve);
|
||||
str_clear_free(key);
|
||||
bin_clear_free(privkey, privkey_len);
|
||||
dpp_configurator_free(conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int dpp_configurator_del(struct hapd_interfaces *ifaces, unsigned int id)
|
||||
{
|
||||
struct dpp_configurator *conf, *tmp;
|
||||
int found = 0;
|
||||
|
||||
dl_list_for_each_safe(conf, tmp, &ifaces->dpp_configurator,
|
||||
struct dpp_configurator, list) {
|
||||
if (id && conf->id != id)
|
||||
continue;
|
||||
found = 1;
|
||||
dl_list_del(&conf->list);
|
||||
dpp_configurator_free(conf);
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
return 0; /* flush succeeds regardless of entries found */
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id)
|
||||
{
|
||||
unsigned int id_val;
|
||||
|
||||
if (os_strcmp(id, "*") == 0) {
|
||||
id_val = 0;
|
||||
} else {
|
||||
id_val = atoi(id);
|
||||
if (id_val == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dpp_configurator_del(hapd->iface->interfaces, id_val);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
struct dpp_authentication *auth;
|
||||
@ -1905,7 +1480,8 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
|
||||
|
||||
curve = get_param(cmd, " curve=");
|
||||
hostapd_dpp_set_testing_options(hapd, auth);
|
||||
if (hostapd_dpp_set_configurator(hapd, auth, cmd) == 0 &&
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
auth, cmd) == 0 &&
|
||||
dpp_configurator_own_config(auth, curve, 1) == 0) {
|
||||
hostapd_dpp_handle_config_obj(hapd, auth);
|
||||
ret = 0;
|
||||
@ -1918,19 +1494,6 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
struct dpp_configurator *conf;
|
||||
|
||||
conf = hostapd_dpp_configurator_get_id(hapd, id);
|
||||
if (!conf)
|
||||
return -1;
|
||||
|
||||
return dpp_configurator_get_key(conf, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
@ -1940,7 +1503,7 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos += 5;
|
||||
own_bi = dpp_bootstrap_get_id(hapd, atoi(pos));
|
||||
own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
|
||||
if (!own_bi) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Identified bootstrap info not found");
|
||||
@ -2070,6 +1633,10 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
|
||||
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
|
||||
NULL);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
hostapd_dpp_pkex_remove(hapd, "*");
|
||||
@ -2077,20 +1644,3 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
|
||||
os_free(hapd->dpp_configurator_params);
|
||||
hapd->dpp_configurator_params = NULL;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces)
|
||||
{
|
||||
dl_list_init(&ifaces->dpp_bootstrap);
|
||||
dl_list_init(&ifaces->dpp_configurator);
|
||||
ifaces->dpp_init_done = 1;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces)
|
||||
{
|
||||
if (!ifaces->dpp_init_done)
|
||||
return;
|
||||
dpp_bootstrap_del(ifaces, 0);
|
||||
dpp_configurator_del(ifaces, 0);
|
||||
}
|
||||
|
@ -10,12 +10,6 @@
|
||||
#define DPP_HOSTAPD_H
|
||||
|
||||
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id);
|
||||
const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
|
||||
unsigned int id);
|
||||
int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
|
||||
char *reply, int reply_size);
|
||||
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "common/dpp.h"
|
||||
#include "crypto/random.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "wps/wps.h"
|
||||
@ -38,6 +39,7 @@
|
||||
#include "mbo_ap.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "fils_hlp.h"
|
||||
#include "neighbor_db.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
@ -304,6 +306,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
return -1;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
hapd->iface->freq,
|
||||
ie, ielen,
|
||||
elems.mdie, elems.mdie_len,
|
||||
elems.owe_dh, elems.owe_dh_len);
|
||||
@ -563,6 +566,38 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
dpp_pfs_free(sta->dpp_pfs);
|
||||
sta->dpp_pfs = NULL;
|
||||
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
|
||||
hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
|
||||
elems.owe_dh) {
|
||||
sta->dpp_pfs = dpp_pfs_init(
|
||||
wpabuf_head(hapd->conf->dpp_netaccesskey),
|
||||
wpabuf_len(hapd->conf->dpp_netaccesskey));
|
||||
if (!sta->dpp_pfs) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Could not initialize PFS");
|
||||
/* Try to continue without PFS */
|
||||
goto pfs_fail;
|
||||
}
|
||||
|
||||
if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
|
||||
elems.owe_dh_len) < 0) {
|
||||
dpp_pfs_free(sta->dpp_pfs);
|
||||
sta->dpp_pfs = NULL;
|
||||
reason = WLAN_REASON_UNSPECIFIED;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
|
||||
sta->dpp_pfs->secret : NULL);
|
||||
pfs_fail:
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
|
||||
@ -739,9 +774,12 @@ 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)
|
||||
{
|
||||
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
int channel, chwidth, is_dfs;
|
||||
u8 seg0_idx = 0, seg1_idx = 0;
|
||||
size_t i;
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
@ -824,6 +862,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
|
||||
"freq=%d dfs=%d", freq, is_dfs);
|
||||
}
|
||||
|
||||
for (i = 0; i < hapd->iface->num_bss; i++)
|
||||
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
@ -1065,6 +1106,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifndef NEED_AP_MLME
|
||||
static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
struct rx_mgmt *drv_mgmt)
|
||||
{
|
||||
@ -1077,7 +1119,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
|
||||
return;
|
||||
|
||||
plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 1;
|
||||
plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
|
||||
fc = le_to_host16(mgmt->frame_control);
|
||||
@ -1097,22 +1139,20 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FT) {
|
||||
const u8 *payload = drv_mgmt->frame + 24 + 1;
|
||||
|
||||
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
|
||||
wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
|
||||
ieee802_11_sa_query_action(
|
||||
hapd, mgmt->sa,
|
||||
mgmt->u.action.u.sa_query_resp.action,
|
||||
mgmt->u.action.u.sa_query_resp.trans_id);
|
||||
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
|
||||
ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
|
||||
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
#ifdef CONFIG_FST
|
||||
@ -1122,7 +1162,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
#ifdef CONFIG_DPP
|
||||
if (plen >= 1 + 4 &&
|
||||
if (plen >= 2 + 4 &&
|
||||
mgmt->u.action.u.vs_public_action.action ==
|
||||
WLAN_PA_VENDOR_SPECIFIC &&
|
||||
WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
|
||||
@ -1139,6 +1179,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
@ -1600,10 +1641,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
if (!data->rx_mgmt.frame)
|
||||
break;
|
||||
#ifdef NEED_AP_MLME
|
||||
if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
|
||||
break;
|
||||
#endif /* NEED_AP_MLME */
|
||||
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
|
||||
#else /* NEED_AP_MLME */
|
||||
hostapd_action_rx(hapd, &data->rx_mgmt);
|
||||
#endif /* NEED_AP_MLME */
|
||||
break;
|
||||
case EVENT_RX_PROBE_REQ:
|
||||
if (data->rx_probe_req.sa == NULL ||
|
||||
@ -1725,6 +1766,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
hostapd_reconfig_encryption(hapd);
|
||||
hapd->reenable_beacon = 1;
|
||||
ieee802_11_set_beacon(hapd);
|
||||
#ifdef NEED_AP_MLME
|
||||
} else if (hapd->disabled && hapd->iface->cac_started) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
|
||||
hostapd_handle_dfs(hapd->iface);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
break;
|
||||
case EVENT_INTERFACE_DISABLED:
|
||||
|
@ -139,6 +139,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
struct hostapd_eap_user *user = NULL;
|
||||
char id_str[256], cmd[300];
|
||||
size_t i;
|
||||
int res;
|
||||
|
||||
if (identity_len >= sizeof(id_str)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
|
||||
@ -174,6 +175,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
if (hapd->tmp_eap_user.identity == NULL)
|
||||
return NULL;
|
||||
os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
|
||||
hapd->tmp_eap_user.identity_len = identity_len;
|
||||
|
||||
if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
|
||||
wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
|
||||
@ -182,9 +184,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_snprintf(cmd, sizeof(cmd),
|
||||
"SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
|
||||
id_str, phase2);
|
||||
res = os_snprintf(cmd, sizeof(cmd),
|
||||
"SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
|
||||
id_str, phase2);
|
||||
if (os_snprintf_error(sizeof(cmd), res))
|
||||
goto fail;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
|
||||
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
|
||||
SQLITE_OK) {
|
||||
@ -214,6 +219,7 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
sqlite3_close(db);
|
||||
|
||||
return user;
|
||||
|
@ -580,6 +580,19 @@ int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 *tmp, *tmp_pos;
|
||||
int ret = 0;
|
||||
|
||||
if (sta->fils_pending_assoc_req &&
|
||||
eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta)) {
|
||||
/* Do not process FILS HLP request again if the station
|
||||
* retransmits (Re)Association Request frame before the previous
|
||||
* HLP response has either been received or timed out. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Do not relay another HLP request from "
|
||||
MACSTR
|
||||
" before processing of the already pending one has been completed",
|
||||
MAC2STR(sta->addr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Initialization and configuration
|
||||
* Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -348,10 +348,11 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
|
||||
if (!hapd->started) {
|
||||
wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
|
||||
__func__, hapd->conf->iface);
|
||||
__func__, hapd->conf ? hapd->conf->iface : "N/A");
|
||||
return;
|
||||
}
|
||||
hapd->started = 0;
|
||||
hapd->beacon_set_done = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
|
||||
iapp_deinit(hapd->iapp);
|
||||
@ -417,6 +418,20 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
|
||||
hostapd_clean_rrm(hapd);
|
||||
fils_hlp_deinit(hapd);
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
{
|
||||
struct hostapd_sae_commit_queue *q;
|
||||
|
||||
while ((q = dl_list_first(&hapd->sae_commit_queue,
|
||||
struct hostapd_sae_commit_queue,
|
||||
list))) {
|
||||
dl_list_del(&q->list);
|
||||
os_free(q);
|
||||
}
|
||||
}
|
||||
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
|
||||
#endif /* CONFIG_SAE */
|
||||
}
|
||||
|
||||
|
||||
@ -431,7 +446,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
static void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
|
||||
hapd->conf->iface);
|
||||
hapd->conf ? hapd->conf->iface : "N/A");
|
||||
if (hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->ctrl_iface_deinit) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
|
||||
@ -506,7 +521,7 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
||||
|
||||
static void hostapd_clear_wep(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
|
||||
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
hostapd_broadcast_wep_clear(hapd);
|
||||
}
|
||||
@ -658,8 +673,10 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
|
||||
for (i = 5; i > 5 - j; i--)
|
||||
mask[i] = 0;
|
||||
j = bits % 8;
|
||||
while (j--)
|
||||
while (j) {
|
||||
j--;
|
||||
mask[i] <<= 1;
|
||||
}
|
||||
|
||||
skip_mask_ext:
|
||||
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
|
||||
@ -1668,127 +1685,6 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
||||
int ht, int vht)
|
||||
{
|
||||
if (!ht && !vht)
|
||||
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)
|
||||
return NR_CHAN_WIDTH_40;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
return NR_CHAN_WIDTH_80;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
|
||||
return NR_CHAN_WIDTH_160;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
|
||||
return NR_CHAN_WIDTH_80P80;
|
||||
return NR_CHAN_WIDTH_20;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef NEED_AP_MLME
|
||||
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;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
enum nr_chan_width width;
|
||||
u32 bssid_info;
|
||||
struct wpabuf *nr;
|
||||
|
||||
if (!(hapd->conf->radio_measurements[0] &
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||
return;
|
||||
|
||||
bssid_info = 3; /* AP is reachable */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
|
||||
|
||||
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
|
||||
|
||||
bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
|
||||
|
||||
if (hapd->conf->wmm_enabled) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_QOS;
|
||||
|
||||
if (hapd->conf->wmm_uapsd &&
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
|
||||
bssid_info |= NEI_REP_BSSID_INFO_APSD;
|
||||
}
|
||||
|
||||
if (ht) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HT |
|
||||
NEI_REP_BSSID_INFO_DELAYED_BA;
|
||||
|
||||
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
||||
if (vht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
||||
}
|
||||
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return;
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht);
|
||||
if (vht) {
|
||||
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
} else if (ht) {
|
||||
ieee80211_freq_to_chan(hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel,
|
||||
¢er_freq1_idx);
|
||||
}
|
||||
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
|
||||
|
||||
/*
|
||||
* Neighbor Report element size = BSSID + BSSID info + op_class + chan +
|
||||
* phy type + wide bandwidth channel subelement.
|
||||
*/
|
||||
nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
|
||||
wpabuf_put_le32(nr, bssid_info);
|
||||
wpabuf_put_u8(nr, op_class);
|
||||
wpabuf_put_u8(nr, channel);
|
||||
wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
|
||||
|
||||
/*
|
||||
* Wide Bandwidth Channel subelement may be needed to allow the
|
||||
* receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
|
||||
* Figure 9-301.
|
||||
*/
|
||||
wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
|
||||
wpabuf_put_u8(nr, 3);
|
||||
wpabuf_put_u8(nr, width);
|
||||
wpabuf_put_u8(nr, center_freq1_idx);
|
||||
wpabuf_put_u8(nr, center_freq2_idx);
|
||||
|
||||
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
||||
hapd->iconf->civic, hapd->iconf->stationary_ap);
|
||||
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
||||
static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
|
||||
@ -1988,15 +1884,17 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->iconf->rts_threshold > -1 &&
|
||||
hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
|
||||
if (hapd->iconf->rts_threshold >= -1 &&
|
||||
hostapd_set_rts(hapd, hapd->iconf->rts_threshold) &&
|
||||
hapd->iconf->rts_threshold >= -1) {
|
||||
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
|
||||
"kernel driver");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hapd->iconf->fragm_threshold > -1 &&
|
||||
hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
|
||||
if (hapd->iconf->fragm_threshold >= -1 &&
|
||||
hostapd_set_frag(hapd, hapd->iconf->fragm_threshold) &&
|
||||
hapd->iconf->fragm_threshold != -1) {
|
||||
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
|
||||
"for kernel driver");
|
||||
goto fail;
|
||||
@ -2009,11 +1907,14 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
if (j)
|
||||
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
|
||||
if (hostapd_setup_bss(hapd, j == 0)) {
|
||||
do {
|
||||
for (;;) {
|
||||
hapd = iface->bss[j];
|
||||
hostapd_bss_deinit_no_free(hapd);
|
||||
hostapd_free_hapd_data(hapd);
|
||||
} while (j-- > 0);
|
||||
if (j == 0)
|
||||
break;
|
||||
j--;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
if (is_zero_ether_addr(hapd->conf->bssid))
|
||||
@ -2085,7 +1986,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
iface->interfaces->terminate_on_error--;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++)
|
||||
hostapd_set_own_neighbor_report(iface->bss[j]);
|
||||
hostapd_neighbor_set_own_report(iface->bss[j]);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2266,6 +2167,9 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
dl_list_init(&hapd->l2_queue);
|
||||
dl_list_init(&hapd->l2_oui_queue);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_SAE
|
||||
dl_list_init(&hapd->sae_commit_queue);
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
return hapd;
|
||||
}
|
||||
@ -2276,7 +2180,7 @@ static void hostapd_bss_deinit(struct hostapd_data *hapd)
|
||||
if (!hapd)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
|
||||
hapd->conf->iface);
|
||||
hapd->conf ? hapd->conf->iface : "N/A");
|
||||
hostapd_bss_deinit_no_free(hapd);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||
hostapd_cleanup(hapd);
|
||||
@ -2303,7 +2207,7 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
for (j = iface->num_bss - 1; j >= 0; j--) {
|
||||
for (j = (int) iface->num_bss - 1; j >= 0; j--) {
|
||||
if (!iface->bss)
|
||||
break;
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
|
@ -66,9 +66,7 @@ struct hapd_interfaces {
|
||||
int eloop_initialized;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp_init_done;
|
||||
struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
|
||||
struct dl_list dpp_configurator; /* struct dpp_configurator */
|
||||
struct dpp_global *dpp;
|
||||
#endif /* CONFIG_DPP */
|
||||
};
|
||||
|
||||
@ -129,6 +127,13 @@ struct hostapd_neighbor_entry {
|
||||
int stationary;
|
||||
};
|
||||
|
||||
struct hostapd_sae_commit_queue {
|
||||
struct dl_list list;
|
||||
int rssi;
|
||||
size_t len;
|
||||
u8 msg[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_data - hostapd per-BSS data structure
|
||||
*/
|
||||
@ -307,7 +312,10 @@ struct hostapd_data {
|
||||
/** Key used for generating SAE anti-clogging tokens */
|
||||
u8 sae_token_key[8];
|
||||
struct os_reltime last_sae_token_key_update;
|
||||
u16 sae_token_idx;
|
||||
u16 sae_pending_token_idx[256];
|
||||
int dot11RSNASAERetransPeriod; /* msec */
|
||||
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
|
@ -25,17 +25,20 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
|
||||
if (!hapd->conf->hs20)
|
||||
return eid;
|
||||
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*eid++ = 7;
|
||||
*eid++ = hapd->conf->hs20_release < 2 ? 5 : 7;
|
||||
WPA_PUT_BE24(eid, OUI_WFA);
|
||||
eid += 3;
|
||||
*eid++ = HS20_INDICATION_OUI_TYPE;
|
||||
conf = HS20_VERSION; /* Release Number */
|
||||
conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
|
||||
conf = (hapd->conf->hs20_release - 1) << 4; /* Release Number */
|
||||
if (hapd->conf->hs20_release >= 2)
|
||||
conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
|
||||
if (hapd->conf->disable_dgaf)
|
||||
conf |= HS20_DGAF_DISABLED;
|
||||
*eid++ = conf;
|
||||
WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
|
||||
eid += 2;
|
||||
if (hapd->conf->hs20_release >= 2) {
|
||||
WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
|
||||
eid += 2;
|
||||
}
|
||||
|
||||
return eid;
|
||||
}
|
||||
@ -84,6 +87,10 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
|
||||
capab |= WPA_CAPABILITY_MFPR;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
if (hapd->conf->ocv)
|
||||
capab |= WPA_CAPABILITY_OCVC;
|
||||
#endif /* CONFIG_OCV */
|
||||
WPA_PUT_LE16(eid, capab);
|
||||
eid += 2;
|
||||
|
||||
|
@ -229,9 +229,6 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
|
||||
{
|
||||
int pri_chan, sec_chan;
|
||||
|
||||
if (!iface->conf->secondary_channel)
|
||||
return 1; /* HT40 not used */
|
||||
|
||||
pri_chan = iface->conf->channel;
|
||||
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
|
||||
|
||||
@ -697,30 +694,25 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
int channel, int primary)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
if (!iface->current_mode)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
if (chan->chan != channel)
|
||||
continue;
|
||||
chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
|
||||
if (!chan)
|
||||
return 0;
|
||||
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
return 1;
|
||||
if ((primary && chan_pri_allowed(chan)) ||
|
||||
(!primary && !(chan->flag & HOSTAPD_CHAN_DISABLED)))
|
||||
return 1;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
|
||||
primary ? "" : "Configured HT40 secondary ",
|
||||
i, chan->chan, chan->flag,
|
||||
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
|
||||
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
|
||||
channel, primary ? "primary" : "secondary");
|
||||
wpa_printf(MSG_INFO,
|
||||
"Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
|
||||
channel, primary ? "primary" : "secondary",
|
||||
chan->flag,
|
||||
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
|
||||
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -728,6 +720,12 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
int secondary_chan;
|
||||
struct hostapd_channel_data *pri_chan;
|
||||
|
||||
pri_chan = hw_get_channel_chan(iface->current_mode,
|
||||
iface->conf->channel, NULL);
|
||||
if (!pri_chan)
|
||||
return 0;
|
||||
|
||||
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
|
||||
return 0;
|
||||
@ -742,13 +740,15 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
|
||||
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
|
||||
secondary_chan = iface->conf->channel + 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
|
||||
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
|
||||
iface->conf->secondary_channel = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
secondary_chan = iface->conf->channel - 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
|
||||
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
|
||||
iface->conf->secondary_channel = -1;
|
||||
return 1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,7 @@ 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_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_mu_edca_parameter_set(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,
|
||||
@ -80,6 +81,8 @@ void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
|
||||
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
|
||||
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_capab);
|
||||
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);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -91,8 +94,8 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
|
||||
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u8 *eid);
|
||||
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
|
||||
const u8 *sa, const u8 action_type,
|
||||
const u8 *trans_id);
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len);
|
||||
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
|
||||
@ -120,6 +123,9 @@ u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
|
||||
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
|
||||
|
||||
u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len, int delta);
|
||||
|
||||
#else /* CONFIG_MBO */
|
||||
|
||||
static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
|
||||
@ -166,4 +172,9 @@ int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req);
|
||||
|
||||
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
|
||||
|
||||
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
||||
|
@ -289,6 +289,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
};
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
vlan_id = NULL;
|
||||
|
||||
/* Check whether ACL cache has an entry for this station */
|
||||
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval, vlan_id, psk,
|
||||
@ -516,7 +519,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct hostapd_acl_query_data *query, *prev;
|
||||
struct hostapd_cached_radius_acl *cache;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
int *untagged, *tagged, *notempty;
|
||||
|
||||
query = hapd->acl_queries;
|
||||
prev = NULL;
|
||||
@ -574,12 +576,10 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
cache->acct_interim_interval = 0;
|
||||
}
|
||||
|
||||
notempty = &cache->vlan_id.notempty;
|
||||
untagged = &cache->vlan_id.untagged;
|
||||
tagged = cache->vlan_id.tagged;
|
||||
*notempty = !!radius_msg_get_vlanid(msg, untagged,
|
||||
MAX_NUM_TAGGED_VLAN,
|
||||
tagged);
|
||||
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
|
||||
cache->vlan_id.notempty = !!radius_msg_get_vlanid(
|
||||
msg, &cache->vlan_id.untagged,
|
||||
MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
|
||||
|
||||
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
|
||||
msg, req, cache);
|
||||
|
@ -86,3 +86,34 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_mu_edca_parameter_set *edca;
|
||||
u8 *pos;
|
||||
size_t i;
|
||||
|
||||
pos = (u8 *) &hapd->iface->conf->he_mu_edca;
|
||||
for (i = 0; i < sizeof(*edca); i++) {
|
||||
if (pos[i])
|
||||
break;
|
||||
}
|
||||
if (i == sizeof(*edca))
|
||||
return eid; /* no MU EDCA Parameters configured */
|
||||
|
||||
pos = eid;
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(*edca);
|
||||
*pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
|
||||
|
||||
edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
|
||||
os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
|
||||
pos, sizeof(*edca));
|
||||
|
||||
pos += sizeof(*edca);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
@ -10,10 +10,12 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ocv.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "ieee802_11.h"
|
||||
|
||||
|
||||
@ -49,7 +51,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *trans_id)
|
||||
{
|
||||
struct ieee80211_mgmt mgmt;
|
||||
#ifdef CONFIG_OCV
|
||||
struct sta_info *sta;
|
||||
#endif /* CONFIG_OCV */
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *oci_ie = NULL;
|
||||
u8 oci_ie_len = 0;
|
||||
u8 *end;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
|
||||
@ -57,19 +64,61 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
|
||||
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
|
||||
|
||||
os_memset(&mgmt, 0, sizeof(mgmt));
|
||||
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt.da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
|
||||
mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
|
||||
os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
|
||||
#ifdef CONFIG_OCV
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element in SA Query Request");
|
||||
return;
|
||||
}
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
if (!oci_ie) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to allocate buffer for OCI element in SA Query Request");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
|
||||
os_free(oci_ie);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
mgmt = os_zalloc(sizeof(*mgmt) + oci_ie_len);
|
||||
if (!mgmt) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to allocate buffer for SA Query Response frame");
|
||||
os_free(oci_ie);
|
||||
return;
|
||||
}
|
||||
|
||||
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
|
||||
mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
|
||||
os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
|
||||
WLAN_SA_QUERY_TR_ID_LEN);
|
||||
end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
|
||||
if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
|
||||
end = mgmt->u.action.u.sa_query_req.variable;
|
||||
#ifdef CONFIG_OCV
|
||||
if (oci_ie_len > 0) {
|
||||
os_memcpy(end, oci_ie, oci_ie_len);
|
||||
end += oci_ie_len;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
|
||||
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
|
||||
|
||||
os_free(mgmt);
|
||||
os_free(oci_ie);
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +126,9 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
|
||||
const u8 *sa, const u8 *trans_id)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct ieee80211_mgmt resp;
|
||||
struct ieee80211_mgmt *resp;
|
||||
u8 *oci_ie = NULL;
|
||||
u8 oci_ie_len = 0;
|
||||
u8 *end;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
|
||||
@ -92,30 +143,123 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element in SA Query Response");
|
||||
return;
|
||||
}
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
if (!oci_ie) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to allocate buffer for for OCI element in SA Query Response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
|
||||
os_free(oci_ie);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
resp = os_zalloc(sizeof(*resp) + oci_ie_len);
|
||||
if (!resp) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to allocate buffer for SA Query Response frame");
|
||||
os_free(oci_ie);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
|
||||
MACSTR, MAC2STR(sa));
|
||||
|
||||
os_memset(&resp, 0, sizeof(resp));
|
||||
resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(resp.da, sa, ETH_ALEN);
|
||||
os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
|
||||
resp.u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
|
||||
os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
|
||||
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(resp->da, sa, ETH_ALEN);
|
||||
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
|
||||
resp->u.action.category = WLAN_ACTION_SA_QUERY;
|
||||
resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
|
||||
os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
|
||||
WLAN_SA_QUERY_TR_ID_LEN);
|
||||
end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
|
||||
if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
|
||||
end = resp->u.action.u.sa_query_req.variable;
|
||||
#ifdef CONFIG_OCV
|
||||
if (oci_ie_len > 0) {
|
||||
os_memcpy(end, oci_ie, oci_ie_len);
|
||||
end += oci_ie_len;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
|
||||
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
|
||||
|
||||
os_free(resp);
|
||||
os_free(oci_ie);
|
||||
}
|
||||
|
||||
|
||||
void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 action_type, const u8 *trans_id)
|
||||
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
const u8 *sa = mgmt->sa;
|
||||
const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
|
||||
const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
|
||||
|
||||
if (((const u8 *) mgmt) + len <
|
||||
mgmt->u.action.u.sa_query_resp.variable) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"IEEE 802.11: Too short SA Query Action frame (len=%lu)",
|
||||
(unsigned long) len);
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, sa);
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct ieee802_11_elems elems;
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
size_t ies_len;
|
||||
const u8 *ies;
|
||||
|
||||
ies = mgmt->u.action.u.sa_query_resp.variable;
|
||||
ies_len = len - (ies - (u8 *) mgmt);
|
||||
if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) ==
|
||||
ParseFailed) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SA Query: Failed to parse elements");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info to validate received OCI in SA Query Action frame");
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_sta_tx_parameters(sta->wpa_sm,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx, &tx_chanwidth,
|
||||
&tx_seg1_idx) < 0)
|
||||
return;
|
||||
|
||||
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (action_type == WLAN_SA_QUERY_REQUEST) {
|
||||
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
|
||||
@ -135,7 +279,6 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
|
||||
|
||||
/* MLME-SAQuery.confirm */
|
||||
|
||||
sta = ap_get_sta(hapd, sa);
|
||||
if (sta == NULL || sta->sa_query_trans_id == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
|
||||
"pending SA Query request found");
|
||||
@ -237,6 +380,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
*pos |= 0x01;
|
||||
#endif /* CONFIG_FILS */
|
||||
break;
|
||||
case 10: /* Bits 80-87 */
|
||||
#ifdef CONFIG_SAE
|
||||
if (hapd->conf->wpa &&
|
||||
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
|
||||
int in_use = hostapd_sae_pw_id_in_use(hapd->conf);
|
||||
|
||||
if (in_use)
|
||||
*pos |= 0x02; /* Bit 81 - SAE Password
|
||||
* Identifiers In Use */
|
||||
if (in_use == 2)
|
||||
*pos |= 0x04; /* Bit 82 - SAE Password
|
||||
* Identifiers Used Exclusively */
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,6 +434,12 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
|
||||
len = 10;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_SAE
|
||||
if (len < 11 && hapd->conf->wpa &&
|
||||
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
|
||||
hostapd_sae_pw_id_in_use(hapd->conf))
|
||||
len = 11;
|
||||
#endif /* CONFIG_SAE */
|
||||
if (len < hapd->iface->extended_capa_len)
|
||||
len = hapd->iface->extended_capa_len;
|
||||
if (len == 0)
|
||||
@ -547,6 +711,22 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len, int delta)
|
||||
{
|
||||
u8 mbo[4];
|
||||
|
||||
mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
|
||||
mbo[1] = 2;
|
||||
/* Delta RSSI */
|
||||
mbo[2] = delta;
|
||||
/* Retry delay */
|
||||
mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
|
||||
|
||||
return eid + mbo_add_ie(eid, len, mbo, 4);
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 mbo[9], *mbo_pos = mbo;
|
||||
@ -752,3 +932,71 @@ u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx)
|
||||
{
|
||||
int ht_40mhz = 0;
|
||||
int vht_80p80 = 0;
|
||||
int requested_bw;
|
||||
|
||||
if (sta->ht_capabilities)
|
||||
ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
|
||||
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
|
||||
|
||||
if (sta->vht_operation) {
|
||||
struct ieee80211_vht_operation *oper = sta->vht_operation;
|
||||
|
||||
/*
|
||||
* If a VHT Operation element was present, use it to determine
|
||||
* the supported channel bandwidth.
|
||||
*/
|
||||
if (oper->vht_op_info_chwidth == 0) {
|
||||
requested_bw = ht_40mhz ? 40 : 20;
|
||||
} else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
|
||||
requested_bw = 80;
|
||||
} else {
|
||||
int diff;
|
||||
|
||||
requested_bw = 160;
|
||||
diff = abs((int)
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx -
|
||||
(int)
|
||||
oper->vht_op_info_chan_center_freq_seg1_idx);
|
||||
vht_80p80 = oper->vht_op_info_chan_center_freq_seg1_idx
|
||||
!= 0 && diff > 16;
|
||||
}
|
||||
} else if (sta->vht_capabilities) {
|
||||
struct ieee80211_vht_capabilities *capab;
|
||||
int vht_chanwidth;
|
||||
|
||||
capab = sta->vht_capabilities;
|
||||
|
||||
/*
|
||||
* If only the VHT Capabilities element is present (e.g., for
|
||||
* normal clients), use it to determine the supported channel
|
||||
* bandwidth.
|
||||
*/
|
||||
vht_chanwidth = capab->vht_capabilities_info &
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_MASK;
|
||||
vht_80p80 = capab->vht_capabilities_info &
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
|
||||
|
||||
/* TODO: Also take into account Extended NSS BW Support field */
|
||||
requested_bw = vht_chanwidth ? 160 : 80;
|
||||
} else {
|
||||
requested_bw = ht_40mhz ? 40 : 20;
|
||||
}
|
||||
|
||||
*bandwidth = requested_bw < ap_max_chanwidth ?
|
||||
requested_bw : ap_max_chanwidth;
|
||||
|
||||
*seg1_idx = 0;
|
||||
if (ap_seg1_idx && vht_80p80)
|
||||
*seg1_idx = ap_seg1_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
@ -357,6 +357,29 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_oper)
|
||||
{
|
||||
if (!vht_oper) {
|
||||
os_free(sta->vht_operation);
|
||||
sta->vht_operation = NULL;
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!sta->vht_operation) {
|
||||
sta->vht_operation =
|
||||
os_zalloc(sizeof(struct ieee80211_vht_operation));
|
||||
if (!sta->vht_operation)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
os_memcpy(sta->vht_operation, vht_oper,
|
||||
sizeof(struct ieee80211_vht_operation));
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ie, size_t len)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.1X-2004 Authenticator
|
||||
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -682,9 +682,8 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (hapd->conf->hs20) {
|
||||
u8 ver = 1; /* Release 2 */
|
||||
if (HS20_VERSION > 0x10)
|
||||
ver = 2; /* Release 3 */
|
||||
u8 ver = hapd->conf->hs20_release - 1;
|
||||
|
||||
if (!radius_msg_add_wfa(
|
||||
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
|
||||
&ver, 1)) {
|
||||
@ -1237,6 +1236,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
@ -1743,6 +1743,45 @@ ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
static int ieee802_1x_update_vlan(struct radius_msg *msg,
|
||||
struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct vlan_description vlan_desc;
|
||||
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
|
||||
MAX_NUM_TAGGED_VLAN,
|
||||
vlan_desc.tagged);
|
||||
|
||||
if (vlan_desc.notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from RADIUS server",
|
||||
vlan_desc.untagged,
|
||||
vlan_desc.tagged[0] ? "+" : "");
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
ap_sta_set_vlan(hapd, sta, &vlan_desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!vlan_desc.notempty) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"authentication server did not include required VLAN ID in Access-Accept");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ap_sta_set_vlan(hapd, sta, &vlan_desc);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
|
||||
* @msg: RADIUS response message
|
||||
@ -1765,12 +1804,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct eapol_state_machine *sm;
|
||||
int override_eapReq = 0;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
struct vlan_description vlan_desc;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
int *untagged, *tagged, *notempty;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
|
||||
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
|
||||
if (sm == NULL) {
|
||||
@ -1835,56 +1868,21 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
switch (hdr->code) {
|
||||
case RADIUS_CODE_ACCESS_ACCEPT:
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
|
||||
notempty = &vlan_desc.notempty;
|
||||
untagged = &vlan_desc.untagged;
|
||||
tagged = vlan_desc.tagged;
|
||||
*notempty = !!radius_msg_get_vlanid(msg, untagged,
|
||||
MAX_NUM_TAGGED_VLAN,
|
||||
tagged);
|
||||
}
|
||||
|
||||
if (vlan_desc.notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from RADIUS server",
|
||||
vlan_desc.untagged,
|
||||
vlan_desc.tagged[0] ? "+" : "");
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
ap_sta_set_vlan(hapd, sta, &vlan_desc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!vlan_desc.notempty) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_INFO, "authentication "
|
||||
"server did not include required VLAN "
|
||||
"ID in Access-Accept");
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
|
||||
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
|
||||
ieee802_1x_update_vlan(msg, hapd, sta) < 0)
|
||||
break;
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id > 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"VLAN ID %d", sta->vlan_id);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
break;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
sta->session_timeout_set = !!session_timeout_set;
|
||||
os_get_reltime(&sta->session_timeout);
|
||||
@ -2597,6 +2595,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct os_reltime diff;
|
||||
const char *name1;
|
||||
const char *name2;
|
||||
char *identity_buf = NULL;
|
||||
|
||||
if (sm == NULL)
|
||||
return 0;
|
||||
@ -2712,6 +2711,14 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
/* dot1xAuthSessionStatsTable */
|
||||
os_reltime_age(&sta->acct_session_start, &diff);
|
||||
if (sm->eap && !sm->identity) {
|
||||
const u8 *id;
|
||||
size_t id_len;
|
||||
|
||||
id = eap_get_identity(sm->eap, &id_len);
|
||||
if (id)
|
||||
identity_buf = dup_binstr(id, id_len);
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
/* TODO: dot1xAuthSessionOctetsRx */
|
||||
/* TODO: dot1xAuthSessionOctetsTx */
|
||||
@ -2727,7 +2734,9 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
|
||||
1 : 2,
|
||||
(unsigned int) diff.sec,
|
||||
sm->identity);
|
||||
sm->identity ? (char *) sm->identity :
|
||||
(identity_buf ? identity_buf : "N/A"));
|
||||
os_free(identity_buf);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "neighbor_db.h"
|
||||
|
||||
|
||||
@ -123,7 +124,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
}
|
||||
|
||||
|
||||
void hostpad_free_neighbor_db(struct hostapd_data *hapd)
|
||||
void hostapd_free_neighbor_db(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr, *prev;
|
||||
|
||||
@ -134,3 +135,123 @@ void hostpad_free_neighbor_db(struct hostapd_data *hapd)
|
||||
os_free(nr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
||||
int ht, int vht)
|
||||
{
|
||||
if (!ht && !vht)
|
||||
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)
|
||||
return NR_CHAN_WIDTH_40;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
return NR_CHAN_WIDTH_80;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
|
||||
return NR_CHAN_WIDTH_160;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
|
||||
return NR_CHAN_WIDTH_80P80;
|
||||
return NR_CHAN_WIDTH_20;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef NEED_AP_MLME
|
||||
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;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
enum nr_chan_width width;
|
||||
u32 bssid_info;
|
||||
struct wpabuf *nr;
|
||||
|
||||
if (!(hapd->conf->radio_measurements[0] &
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||
return;
|
||||
|
||||
bssid_info = 3; /* AP is reachable */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
|
||||
|
||||
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
|
||||
|
||||
bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
|
||||
|
||||
if (hapd->conf->wmm_enabled) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_QOS;
|
||||
|
||||
if (hapd->conf->wmm_uapsd &&
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
|
||||
bssid_info |= NEI_REP_BSSID_INFO_APSD;
|
||||
}
|
||||
|
||||
if (ht) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HT |
|
||||
NEI_REP_BSSID_INFO_DELAYED_BA;
|
||||
|
||||
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
||||
if (vht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
||||
}
|
||||
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return;
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht);
|
||||
if (vht) {
|
||||
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
} else if (ht) {
|
||||
ieee80211_freq_to_chan(hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel,
|
||||
¢er_freq1_idx);
|
||||
}
|
||||
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
|
||||
|
||||
/*
|
||||
* Neighbor Report element size = BSSID + BSSID info + op_class + chan +
|
||||
* phy type + wide bandwidth channel subelement.
|
||||
*/
|
||||
nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
|
||||
wpabuf_put_le32(nr, bssid_info);
|
||||
wpabuf_put_u8(nr, op_class);
|
||||
wpabuf_put_u8(nr, channel);
|
||||
wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
|
||||
|
||||
/*
|
||||
* Wide Bandwidth Channel subelement may be needed to allow the
|
||||
* receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
|
||||
* Figure 9-301.
|
||||
*/
|
||||
wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
|
||||
wpabuf_put_u8(nr, 3);
|
||||
wpabuf_put_u8(nr, width);
|
||||
wpabuf_put_u8(nr, center_freq1_idx);
|
||||
wpabuf_put_u8(nr, center_freq2_idx);
|
||||
|
||||
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
||||
hapd->iconf->civic, hapd->iconf->stationary_ap);
|
||||
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
@ -17,8 +17,9 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
const struct wpabuf *nr, const struct wpabuf *lci,
|
||||
const struct wpabuf *civic, int stationary);
|
||||
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid);
|
||||
void hostpad_free_neighbor_db(struct hostapd_data *hapd);
|
||||
void hostapd_free_neighbor_db(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* NEIGHBOR_DB_H */
|
||||
|
@ -558,7 +558,7 @@ int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
void hostapd_clean_rrm(struct hostapd_data *hapd)
|
||||
{
|
||||
hostpad_free_neighbor_db(hapd);
|
||||
hostapd_free_neighbor_db(hapd);
|
||||
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
|
||||
hapd->lci_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "common/sae.h"
|
||||
#include "common/dpp.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
@ -166,7 +167,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
/* just in case */
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
|
||||
if (sta->flags & WLAN_STA_WDS)
|
||||
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
|
||||
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
|
||||
|
||||
if (sta->ipaddr)
|
||||
@ -328,6 +329,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);
|
||||
hostapd_free_psk_list(sta->psk);
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
@ -361,6 +363,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
crypto_ecdh_deinit(sta->owe_ecdh);
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
dpp_pfs_free(sta->dpp_pfs);
|
||||
sta->dpp_pfs = NULL;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
os_free(sta->ext_capability);
|
||||
|
||||
#ifdef CONFIG_WNM_AP
|
||||
@ -500,6 +507,13 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
} else if (sta->timeout_next != STA_REMOVE) {
|
||||
int deauth = sta->timeout_next == STA_DEAUTH;
|
||||
|
||||
if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
|
||||
/* Cannot disassociate not-associated STA, so move
|
||||
* directly to deauthentication. */
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
deauth = 1;
|
||||
}
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Timeout, sending %s info to STA " MACSTR,
|
||||
deauth ? "deauthentication" : "disassociation",
|
||||
@ -798,6 +812,8 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
sta->wpa_sm = NULL;
|
||||
|
||||
sta->disassoc_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
||||
@ -896,9 +912,6 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
|
||||
int old_vlan_id, vlan_id = 0, ret = 0;
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
vlan_desc = NULL;
|
||||
|
||||
/* Check if there is something to do */
|
||||
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
|
||||
/* This sta is lacking its own vif */
|
||||
@ -1165,6 +1178,32 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
|
||||
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct hostapd_wpa_psk *psk;
|
||||
struct hostapd_ssid *ssid;
|
||||
const u8 *pmk;
|
||||
int pmk_len;
|
||||
|
||||
ssid = &hapd->conf->ssid;
|
||||
|
||||
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
|
||||
if (!pmk || pmk_len != PMK_LEN)
|
||||
return NULL;
|
||||
|
||||
for (psk = ssid->wpa_psk; psk; psk = psk->next)
|
||||
if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
|
||||
break;
|
||||
if (!psk)
|
||||
return NULL;
|
||||
if (!psk || !psk->keyid[0])
|
||||
return NULL;
|
||||
|
||||
return psk->keyid;
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized)
|
||||
{
|
||||
@ -1203,7 +1242,11 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
sta->addr, authorized, dev_addr);
|
||||
|
||||
if (authorized) {
|
||||
const char *keyid;
|
||||
char keyid_buf[100];
|
||||
char ip_addr[100];
|
||||
|
||||
keyid_buf[0] = '\0';
|
||||
ip_addr[0] = '\0';
|
||||
#ifdef CONFIG_P2P
|
||||
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
|
||||
@ -1214,14 +1257,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
|
||||
buf, ip_addr);
|
||||
keyid = ap_sta_wpa_get_keyid(hapd, sta);
|
||||
if (keyid) {
|
||||
os_snprintf(keyid_buf, sizeof(keyid_buf),
|
||||
" keyid=%s", keyid);
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
|
||||
buf, ip_addr, keyid_buf);
|
||||
|
||||
if (hapd->msg_ctx_parent &&
|
||||
hapd->msg_ctx_parent != hapd->msg_ctx)
|
||||
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
|
||||
AP_STA_CONNECTED "%s%s",
|
||||
buf, ip_addr);
|
||||
AP_STA_CONNECTED "%s%s%s",
|
||||
buf, ip_addr, keyid_buf);
|
||||
} else {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
|
||||
#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_PENDING_DISASSOC_CB BIT(29)
|
||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||
#define WLAN_STA_NONERP BIT(31)
|
||||
@ -117,6 +118,7 @@ struct sta_info {
|
||||
unsigned int power_capab:1;
|
||||
unsigned int agreed_to_steer:1;
|
||||
unsigned int hs20_t_c_filtering:1;
|
||||
unsigned int ft_over_ds:1;
|
||||
|
||||
u16 auth_alg;
|
||||
|
||||
@ -162,6 +164,7 @@ struct sta_info {
|
||||
|
||||
struct ieee80211_ht_capabilities *ht_capabilities;
|
||||
struct ieee80211_vht_capabilities *vht_capabilities;
|
||||
struct ieee80211_vht_operation *vht_operation;
|
||||
u8 vht_opmode;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
@ -215,6 +218,7 @@ struct sta_info {
|
||||
u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
|
||||
* enum mbo_cellular_capa values */
|
||||
struct mbo_non_pref_chan_info *non_pref_chan;
|
||||
int auth_rssi; /* Last Authentication frame RSSI */
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
u8 *supp_op_classes; /* Supported Operating Classes element, if
|
||||
@ -261,6 +265,10 @@ struct sta_info {
|
||||
u8 *ext_capability;
|
||||
char *ifname_wds; /* WDS ifname, if in use */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dpp_pfs *dpp_pfs;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
enum wpa_alg last_tk_alg;
|
||||
int last_tk_key_idx;
|
||||
@ -320,6 +328,8 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "drivers/priv_netlink.h"
|
||||
#include "drivers/linux_ioctl.h"
|
||||
#include "common/linux_bridge.h"
|
||||
#include "common/linux_vlan.h"
|
||||
#include "utils/eloop.h"
|
||||
@ -143,6 +144,9 @@ static int br_delif(const char *br_name, const char *if_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (linux_br_del_if(fd, br_name, if_name) == 0)
|
||||
goto done;
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
@ -168,6 +172,7 @@ static int br_delif(const char *br_name, const char *if_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@ -194,6 +199,14 @@ static int br_addif(const char *br_name, const char *if_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (linux_br_add_if(fd, br_name, if_name) == 0)
|
||||
goto done;
|
||||
if (errno == EBUSY) {
|
||||
/* The interface is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
@ -224,6 +237,7 @@ static int br_addif(const char *br_name, const char *if_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@ -241,6 +255,9 @@ static int br_delbr(const char *br_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (linux_br_del(fd, br_name) == 0)
|
||||
goto done;
|
||||
|
||||
arg[0] = BRCTL_DEL_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
@ -252,6 +269,7 @@ static int br_delbr(const char *br_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@ -277,11 +295,19 @@ static int br_addbr(const char *br_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (linux_br_add(fd, br_name) == 0)
|
||||
goto done;
|
||||
if (errno == EEXIST) {
|
||||
/* The bridge is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_ADD_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (errno == EEXIST) {
|
||||
/* The bridge is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
@ -294,6 +320,7 @@ static int br_addbr(const char *br_name)
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* Decrease forwarding delay to avoid EAPOL timeouts. */
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
|
||||
@ -363,12 +390,18 @@ static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
int clean;
|
||||
int ret;
|
||||
|
||||
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
else
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
|
||||
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
|
||||
vid);
|
||||
if (ret >= (int) sizeof(vlan_ifname))
|
||||
wpa_printf(MSG_WARNING,
|
||||
"VLAN: Interface name was truncated to %s",
|
||||
vlan_ifname);
|
||||
|
||||
clean = 0;
|
||||
ifconfig_up(tagged_interface);
|
||||
@ -384,19 +417,28 @@ static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
|
||||
}
|
||||
|
||||
|
||||
static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
|
||||
static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan, int vid)
|
||||
{
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int ret;
|
||||
|
||||
if (hapd->conf->vlan_bridge[0]) {
|
||||
os_snprintf(br_name, IFNAMSIZ, "%s%d",
|
||||
hapd->conf->vlan_bridge, vid);
|
||||
if (vlan->bridge[0]) {
|
||||
os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
|
||||
ret = 0;
|
||||
} else if (hapd->conf->vlan_bridge[0]) {
|
||||
ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
|
||||
hapd->conf->vlan_bridge, vid);
|
||||
} else if (tagged_interface) {
|
||||
os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
|
||||
tagged_interface, vid);
|
||||
ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
|
||||
tagged_interface, vid);
|
||||
} else {
|
||||
os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
|
||||
ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
|
||||
}
|
||||
if (ret >= IFNAMSIZ)
|
||||
wpa_printf(MSG_WARNING,
|
||||
"VLAN: Interface name was truncated to %s",
|
||||
br_name);
|
||||
}
|
||||
|
||||
|
||||
@ -445,7 +487,7 @@ void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
|
||||
!br_addif(hapd->conf->bridge, ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
|
||||
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
|
||||
vlan_bridge_name(br_name, hapd, untagged);
|
||||
vlan_bridge_name(br_name, hapd, vlan, untagged);
|
||||
|
||||
vlan_get_bridge(br_name, hapd, untagged);
|
||||
|
||||
@ -458,7 +500,7 @@ void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
|
||||
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
|
||||
(i > 0 && tagged[i] == tagged[i - 1]))
|
||||
continue;
|
||||
vlan_bridge_name(br_name, hapd, tagged[i]);
|
||||
vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
|
||||
vlan_get_bridge(br_name, hapd, tagged[i]);
|
||||
vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
|
||||
ifname, br_name, tagged[i], hapd);
|
||||
@ -474,12 +516,19 @@ static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
int clean;
|
||||
int ret;
|
||||
|
||||
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
else
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
|
||||
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
|
||||
vid);
|
||||
if (ret >= (int) sizeof(vlan_ifname))
|
||||
wpa_printf(MSG_WARNING,
|
||||
"VLAN: Interface name was truncated to %s",
|
||||
vlan_ifname);
|
||||
|
||||
|
||||
clean = dyn_iface_put(hapd, vlan_ifname);
|
||||
|
||||
@ -543,7 +592,7 @@ void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
|
||||
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
|
||||
(i > 0 && tagged[i] == tagged[i - 1]))
|
||||
continue;
|
||||
vlan_bridge_name(br_name, hapd, tagged[i]);
|
||||
vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
|
||||
vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
|
||||
ifname, br_name, tagged[i], hapd);
|
||||
vlan_put_bridge(br_name, hapd, tagged[i]);
|
||||
@ -555,7 +604,7 @@ void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
|
||||
(vlan->clean & DVLAN_CLEAN_WLAN_PORT))
|
||||
br_delif(hapd->conf->bridge, ifname);
|
||||
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
|
||||
vlan_bridge_name(br_name, hapd, untagged);
|
||||
vlan_bridge_name(br_name, hapd, vlan, untagged);
|
||||
|
||||
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
|
||||
br_delif(br_name, vlan->ifname);
|
||||
|
@ -187,6 +187,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
{
|
||||
struct hostapd_vlan *n;
|
||||
char ifname[IFNAMSIZ + 1], *pos;
|
||||
int ret;
|
||||
|
||||
if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
|
||||
return NULL;
|
||||
@ -208,8 +209,13 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
n->vlan_desc = *vlan_desc;
|
||||
n->dynamic_vlan = 1;
|
||||
|
||||
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
|
||||
pos);
|
||||
ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
|
||||
ifname, vlan_id, pos);
|
||||
if (os_snprintf_error(sizeof(n->ifname), ret)) {
|
||||
os_free(n);
|
||||
return NULL;
|
||||
}
|
||||
os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
|
||||
|
||||
n->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = n;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "common/ocv.h"
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "ap/ap_config.h"
|
||||
@ -54,8 +55,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
size_t gtk_elem_len = 0;
|
||||
size_t igtk_elem_len = 0;
|
||||
struct wnm_sleep_element wnmsleep_ie;
|
||||
u8 *wnmtfs_ie;
|
||||
u8 wnmsleep_ie_len;
|
||||
u8 *wnmtfs_ie, *oci_ie;
|
||||
u8 wnmsleep_ie_len, oci_ie_len;
|
||||
u16 wnmtfs_ie_len;
|
||||
u8 *pos;
|
||||
struct sta_info *sta;
|
||||
@ -88,10 +89,42 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
wnmtfs_ie = NULL;
|
||||
}
|
||||
|
||||
oci_ie = NULL;
|
||||
oci_ie_len = 0;
|
||||
#ifdef CONFIG_OCV
|
||||
if (action_type == WNM_SLEEP_MODE_EXIT &&
|
||||
wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element in WNM-Sleep Mode frame");
|
||||
os_free(wnmtfs_ie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
if (!oci_ie) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
|
||||
os_free(wnmtfs_ie);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(oci_ie);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
#define MAX_GTK_SUBELEM_LEN 45
|
||||
#define MAX_IGTK_SUBELEM_LEN 26
|
||||
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
|
||||
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
|
||||
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
|
||||
oci_ie_len);
|
||||
if (mgmt == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
|
||||
"WNM-Sleep Response action frame");
|
||||
@ -134,11 +167,18 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
|
||||
/* copy TFS IE here */
|
||||
pos += wnmsleep_ie_len;
|
||||
if (wnmtfs_ie)
|
||||
if (wnmtfs_ie) {
|
||||
os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
|
||||
pos += wnmtfs_ie_len;
|
||||
}
|
||||
#ifdef CONFIG_OCV
|
||||
/* copy OCV OCI here */
|
||||
if (oci_ie_len > 0)
|
||||
os_memcpy(pos, oci_ie, oci_ie_len);
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
|
||||
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
|
||||
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
|
||||
|
||||
/* In driver, response frame should be forced to sent when STA is in
|
||||
* PS mode */
|
||||
@ -185,6 +225,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
#undef MAX_IGTK_SUBELEM_LEN
|
||||
fail:
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(oci_ie);
|
||||
os_free(mgmt);
|
||||
return res;
|
||||
}
|
||||
@ -201,6 +242,11 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
u8 *tfsreq_ie_start = NULL;
|
||||
u8 *tfsreq_ie_end = NULL;
|
||||
u16 tfsreq_ie_len = 0;
|
||||
#ifdef CONFIG_OCV
|
||||
struct sta_info *sta;
|
||||
const u8 *oci_ie = NULL;
|
||||
u8 oci_ie_len = 0;
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (!hapd->conf->wnm_sleep_mode) {
|
||||
wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
|
||||
@ -209,6 +255,13 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Ignore too short WNM-Sleep Mode Request from "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
dialog_token = *pos++;
|
||||
while (pos + 1 < frm + len) {
|
||||
u8 ie_len = pos[1];
|
||||
@ -221,6 +274,12 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
if (!tfsreq_ie_start)
|
||||
tfsreq_ie_start = (u8 *) pos;
|
||||
tfsreq_ie_end = (u8 *) pos;
|
||||
#ifdef CONFIG_OCV
|
||||
} else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
|
||||
pos[2] == WLAN_EID_EXT_OCV_OCI) {
|
||||
oci_ie = pos + 3;
|
||||
oci_ie_len = ie_len - 1;
|
||||
#endif /* CONFIG_OCV */
|
||||
} else
|
||||
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
|
||||
*pos);
|
||||
@ -232,6 +291,27 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
|
||||
sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx) != 0) {
|
||||
wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
|
||||
tfsreq_ie_start && tfsreq_ie_end &&
|
||||
tfsreq_ie_end - tfsreq_ie_start >= 0) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IEEE 802.11 RSN / WPA Authenticator
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
* 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.
|
||||
@ -13,6 +13,7 @@
|
||||
#include "utils/state_machine.h"
|
||||
#include "utils/bitfield.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ocv.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "crypto/sha384.h"
|
||||
#include "crypto/random.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "ap_config.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "wpa_auth.h"
|
||||
@ -112,12 +114,13 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
|
||||
static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *addr,
|
||||
const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk, size_t *psk_len)
|
||||
const u8 *prev_psk, size_t *psk_len,
|
||||
int *vlan_id)
|
||||
{
|
||||
if (wpa_auth->cb->get_psk == NULL)
|
||||
return NULL;
|
||||
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
|
||||
prev_psk, psk_len);
|
||||
prev_psk, psk_len, vlan_id);
|
||||
}
|
||||
|
||||
|
||||
@ -238,6 +241,26 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_channel_info *ci)
|
||||
{
|
||||
if (!wpa_auth->cb->channel_info)
|
||||
return -1;
|
||||
return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
|
||||
static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *addr, int vlan_id)
|
||||
{
|
||||
if (!wpa_auth->cb->update_vlan)
|
||||
return -1;
|
||||
return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
|
||||
}
|
||||
|
||||
|
||||
static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||
@ -297,6 +320,19 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
|
||||
|
||||
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
|
||||
{
|
||||
if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
|
||||
MACSTR " (%d seconds)", MAC2STR(sm->addr),
|
||||
sm->wpa_auth->conf.wpa_ptk_rekey);
|
||||
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
||||
eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
|
||||
wpa_rekey_ptk, sm->wpa_auth, sm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
|
||||
{
|
||||
if (sm->pmksa == ctx)
|
||||
@ -332,6 +368,10 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
|
||||
wpa_get_ntp_timestamp(buf + ETH_ALEN);
|
||||
ptr = (unsigned long) group;
|
||||
os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
|
||||
#ifdef TEST_FUZZ
|
||||
os_memset(buf + ETH_ALEN, 0xab, 8);
|
||||
os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
|
||||
#endif /* TEST_FUZZ */
|
||||
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
|
||||
return -1;
|
||||
|
||||
@ -669,7 +709,10 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
|
||||
os_free(sm->last_rx_eapol_key);
|
||||
os_free(sm->wpa_ie);
|
||||
wpa_group_put(sm->wpa_auth, sm->group);
|
||||
os_free(sm);
|
||||
#ifdef CONFIG_DPP2
|
||||
wpabuf_clear_free(sm->dpp_z);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
bin_clear_free(sm, sizeof(*sm));
|
||||
}
|
||||
|
||||
|
||||
@ -835,13 +878,15 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
int ok = 0;
|
||||
const u8 *pmk = NULL;
|
||||
size_t pmk_len;
|
||||
int vlan_id = 0;
|
||||
|
||||
os_memset(&PTK, 0, sizeof(PTK));
|
||||
for (;;) {
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
|
||||
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
|
||||
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
|
||||
sm->p2p_dev_addr, pmk, &pmk_len);
|
||||
sm->p2p_dev_addr, pmk, &pmk_len,
|
||||
&vlan_id);
|
||||
if (pmk == NULL)
|
||||
break;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
@ -860,6 +905,10 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
|
||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
|
||||
data, data_len) == 0) {
|
||||
if (sm->PMK != pmk) {
|
||||
os_memcpy(sm->PMK, pmk, pmk_len);
|
||||
sm->pmk_len = pmk_len;
|
||||
}
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
@ -878,6 +927,11 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Earlier SNonce resulted in matching MIC");
|
||||
sm->alt_snonce_valid = 0;
|
||||
|
||||
if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
|
||||
wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
|
||||
return -1;
|
||||
|
||||
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
|
||||
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
|
||||
sm->PTK_valid = TRUE;
|
||||
@ -1202,6 +1256,11 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
||||
wpa_try_alt_snonce(sm, data, data_len))) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"received EAPOL-Key with invalid MIC");
|
||||
#ifdef TEST_FUZZ
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Ignore Key MIC failure for fuzz testing");
|
||||
goto continue_fuzz;
|
||||
#endif /* TEST_FUZZ */
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_FILS
|
||||
@ -1210,9 +1269,17 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
||||
&key_data_length) < 0) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"received EAPOL-Key with invalid MIC");
|
||||
#ifdef TEST_FUZZ
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Ignore Key MIC failure for fuzz testing");
|
||||
goto continue_fuzz;
|
||||
#endif /* TEST_FUZZ */
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef TEST_FUZZ
|
||||
continue_fuzz:
|
||||
#endif /* TEST_FUZZ */
|
||||
sm->MICVerified = TRUE;
|
||||
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
|
||||
sm->pending_1_of_4_timeout = 0;
|
||||
@ -1317,6 +1384,9 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
|
||||
os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
|
||||
pos = data + ETH_ALEN + WPA_NONCE_LEN;
|
||||
wpa_get_ntp_timestamp(pos);
|
||||
#ifdef TEST_FUZZ
|
||||
os_memset(pos, 0xef, 8);
|
||||
#endif /* TEST_FUZZ */
|
||||
pos += 8;
|
||||
if (random_get_bytes(pos, gtk_len) < 0)
|
||||
ret = -1;
|
||||
@ -1596,6 +1666,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
timeout_ms = eapol_key_timeout_no_retrans;
|
||||
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
|
||||
sm->pending_1_of_4_timeout = 1;
|
||||
#ifdef TEST_FUZZ
|
||||
timeout_ms = 1;
|
||||
#endif /* TEST_FUZZ */
|
||||
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
|
||||
"counter %u)", timeout_ms, ctr);
|
||||
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
|
||||
@ -1670,6 +1743,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
|
||||
case WPA_DEAUTH:
|
||||
case WPA_DISASSOC:
|
||||
sm->DeauthenticationRequest = TRUE;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
os_memset(sm->PMK, 0, sizeof(sm->PMK));
|
||||
sm->pmk_len = 0;
|
||||
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
|
||||
sm->xxkey_len = 0;
|
||||
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
|
||||
sm->pmk_r1_len = 0;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
break;
|
||||
case WPA_REAUTH:
|
||||
case WPA_REAUTH_EAPOL:
|
||||
@ -1710,6 +1791,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
|
||||
|
||||
/* Using FT protocol, not WPA auth state machine */
|
||||
sm->ft_completed = 1;
|
||||
wpa_auth_set_ptk_rekey_timer(sm);
|
||||
return 0;
|
||||
#else /* CONFIG_IEEE80211R_AP */
|
||||
break;
|
||||
@ -1986,7 +2068,7 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
|
||||
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
|
||||
&psk_len);
|
||||
&psk_len, NULL);
|
||||
if (psk) {
|
||||
os_memcpy(sm->PMK, psk, psk_len);
|
||||
sm->pmk_len = psk_len;
|
||||
@ -2000,6 +2082,10 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||
wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
|
||||
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
|
||||
sm->pmk_len = sm->pmksa->pmk_len;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
|
||||
sm->xxkey_len = sm->pmksa->pmk_len;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
sm->req_replay_counter_used = 0;
|
||||
@ -2060,6 +2146,29 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: No KCK available to derive PMKID for message 1/4");
|
||||
pmkid = NULL;
|
||||
#ifdef CONFIG_FILS
|
||||
} else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
|
||||
if (sm->pmkid_set) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"RSN: Message 1/4 PMKID from FILS/ERP",
|
||||
sm->pmkid, PMKID_LEN);
|
||||
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
|
||||
sm->pmkid, PMKID_LEN);
|
||||
} else {
|
||||
/* No PMKID available */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: No FILS/ERP PMKID available for message 1/4");
|
||||
pmkid = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
} else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
|
||||
sm->ft_completed) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: No PMKID in message 1/4 when using FT protocol");
|
||||
pmkid = NULL;
|
||||
pmkid_len = 0;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_SAE
|
||||
} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
|
||||
if (sm->pmkid_set) {
|
||||
@ -2098,14 +2207,36 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||
const u8 *pmk, unsigned int pmk_len,
|
||||
struct wpa_ptk *ptk)
|
||||
{
|
||||
const u8 *z = NULL;
|
||||
size_t z_len = 0;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
|
||||
return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
if (sm->ft_completed) {
|
||||
u8 ptk_name[WPA_PMK_NAME_LEN];
|
||||
|
||||
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
|
||||
sm->SNonce, sm->ANonce,
|
||||
sm->addr, sm->wpa_auth->addr,
|
||||
sm->pmk_r1_name,
|
||||
ptk, ptk_name,
|
||||
sm->wpa_key_mgmt,
|
||||
sm->pairwise);
|
||||
}
|
||||
return wpa_auth_derive_ptk_ft(sm, ptk);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
|
||||
z = wpabuf_head(sm->dpp_z);
|
||||
z_len = wpabuf_len(sm->dpp_z);
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
|
||||
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
|
||||
ptk, sm->wpa_key_mgmt, sm->pairwise);
|
||||
ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
|
||||
}
|
||||
|
||||
|
||||
@ -2155,6 +2286,16 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
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));
|
||||
|
||||
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);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
|
||||
WPA_PMK_NAME_LEN);
|
||||
sm->pmk_r1_name_valid = 1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
@ -2559,6 +2700,27 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
|
||||
wpabuf_put(plain, tmp2 - tmp);
|
||||
|
||||
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
u8 *pos;
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
|
||||
if (ocv_insert_extended_oci(&ci, pos) < 0) {
|
||||
wpabuf_free(plain);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
return plain;
|
||||
}
|
||||
|
||||
@ -2624,6 +2786,21 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx)
|
||||
{
|
||||
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
|
||||
|
||||
if (!wpa_auth->cb->get_sta_tx_params)
|
||||
return -1;
|
||||
return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
|
||||
ap_max_chanwidth, ap_seg1_idx,
|
||||
bandwidth, seg1_idx);
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
|
||||
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
{
|
||||
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
|
||||
@ -2638,6 +2815,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
struct wpa_eapol_key *key;
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
int vlan_id = 0;
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||
sm->EAPOLKeyReceived = FALSE;
|
||||
@ -2653,7 +2831,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
|
||||
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
|
||||
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
|
||||
sm->p2p_dev_addr, pmk, &pmk_len);
|
||||
sm->p2p_dev_addr, pmk, &pmk_len,
|
||||
&vlan_id);
|
||||
if (pmk == NULL)
|
||||
break;
|
||||
psk_found = 1;
|
||||
@ -2668,6 +2847,12 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
pmk_len = sm->pmk_len;
|
||||
}
|
||||
|
||||
if ((!pmk || !pmk_len) && sm->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
|
||||
pmk = sm->pmksa->pmk;
|
||||
pmk_len = sm->pmksa->pmk_len;
|
||||
}
|
||||
|
||||
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
|
||||
break;
|
||||
|
||||
@ -2675,6 +2860,10 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
|
||||
sm->last_rx_eapol_key,
|
||||
sm->last_rx_eapol_key_len) == 0) {
|
||||
if (sm->PMK != pmk) {
|
||||
os_memcpy(sm->PMK, pmk, pmk_len);
|
||||
sm->pmk_len = pmk_len;
|
||||
}
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
@ -2746,6 +2935,32 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
|
||||
if (wpa_channel_info(wpa_auth, &ci) != 0) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_sta_tx_parameters(sm,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx, &tx_chanwidth,
|
||||
&tx_seg1_idx) < 0)
|
||||
return;
|
||||
|
||||
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
|
||||
wpa_sta_disconnect(wpa_auth, sm->addr,
|
||||
@ -2794,6 +3009,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
|
||||
wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
|
||||
wpa_sta_disconnect(wpa_auth, sm->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
return;
|
||||
}
|
||||
|
||||
sm->pending_1_of_4_timeout = 0;
|
||||
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
||||
|
||||
@ -2883,6 +3105,36 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
|
||||
static int ocv_oci_len(struct wpa_state_machine *sm)
|
||||
{
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm))
|
||||
return OCV_OCI_KDE_LEN;
|
||||
#endif /* CONFIG_OCV */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
|
||||
{
|
||||
#ifdef CONFIG_OCV
|
||||
struct wpa_channel_info ci;
|
||||
|
||||
if (!wpa_auth_uses_ocv(sm))
|
||||
return 0;
|
||||
|
||||
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ocv_insert_oci_kde(&ci, argpos);
|
||||
#else /* CONFIG_OCV */
|
||||
return 0;
|
||||
#endif /* CONFIG_OCV */
|
||||
}
|
||||
|
||||
|
||||
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
{
|
||||
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
|
||||
@ -2966,7 +3218,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
}
|
||||
}
|
||||
|
||||
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
|
||||
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
|
||||
if (gtk)
|
||||
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
@ -3011,6 +3263,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
gtk, gtk_len);
|
||||
}
|
||||
pos = ieee80211w_kde_add(sm, pos);
|
||||
if (ocv_oci_add(sm, &pos) < 0) {
|
||||
os_free(kde);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
@ -3094,12 +3350,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
|
||||
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
|
||||
sm->pairwise_set = TRUE;
|
||||
|
||||
if (sm->wpa_auth->conf.wpa_ptk_rekey) {
|
||||
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
||||
eloop_register_timeout(sm->wpa_auth->conf.
|
||||
wpa_ptk_rekey, 0, wpa_rekey_ptk,
|
||||
sm->wpa_auth, sm);
|
||||
}
|
||||
wpa_auth_set_ptk_rekey_timer(sm);
|
||||
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
|
||||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
|
||||
@ -3199,7 +3450,7 @@ SM_STEP(WPA_PTK)
|
||||
break;
|
||||
case WPA_PTK_INITPSK:
|
||||
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
|
||||
NULL, NULL)) {
|
||||
NULL, NULL, NULL)) {
|
||||
SM_ENTER(WPA_PTK, PTKSTART);
|
||||
#ifdef CONFIG_SAE
|
||||
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
|
||||
@ -3322,7 +3573,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
|
||||
}
|
||||
if (sm->wpa == WPA_VERSION_WPA2) {
|
||||
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
|
||||
ieee80211w_kde_len(sm);
|
||||
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
|
||||
kde_buf = os_malloc(kde_len);
|
||||
if (kde_buf == NULL)
|
||||
return;
|
||||
@ -3333,6 +3584,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
|
||||
gtk, gsm->GTK_len);
|
||||
pos = ieee80211w_kde_add(sm, pos);
|
||||
if (ocv_oci_add(sm, &pos) < 0) {
|
||||
os_free(kde_buf);
|
||||
return;
|
||||
}
|
||||
kde_len = pos - kde;
|
||||
} else {
|
||||
kde = gtk;
|
||||
@ -3353,8 +3608,67 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
|
||||
|
||||
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
|
||||
{
|
||||
#ifdef CONFIG_OCV
|
||||
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
|
||||
const u8 *key_data, *mic;
|
||||
struct ieee802_1x_hdr *hdr;
|
||||
struct wpa_eapol_key *key;
|
||||
struct wpa_eapol_ie_parse kde;
|
||||
size_t mic_len;
|
||||
u16 key_data_length;
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
|
||||
sm->EAPOLKeyReceived = FALSE;
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
|
||||
|
||||
/*
|
||||
* Note: last_rx_eapol_key length fields have already been validated in
|
||||
* wpa_receive().
|
||||
*/
|
||||
hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
|
||||
key = (struct wpa_eapol_key *) (hdr + 1);
|
||||
mic = (u8 *) (key + 1);
|
||||
key_data = mic + mic_len + 2;
|
||||
key_data_length = WPA_GET_BE16(mic + mic_len);
|
||||
if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
|
||||
sizeof(*key) - mic_len - 2)
|
||||
return;
|
||||
|
||||
if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"received EAPOL-Key group msg 2/2 with invalid Key Data contents");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
|
||||
if (wpa_channel_info(wpa_auth, &ci) != 0) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
"Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_sta_tx_parameters(sm,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx, &tx_chanwidth,
|
||||
&tx_seg1_idx) < 0)
|
||||
return;
|
||||
|
||||
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||
ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (sm->GUpdateStationKeys)
|
||||
sm->group->GKeyDoneStations--;
|
||||
sm->GUpdateStationKeys = FALSE;
|
||||
@ -3963,6 +4277,15 @@ int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
|
||||
}
|
||||
|
||||
|
||||
const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
|
||||
{
|
||||
if (!sm)
|
||||
return NULL;
|
||||
*len = sm->pmk_len;
|
||||
return sm->PMK;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
|
||||
{
|
||||
if (sm == NULL)
|
||||
@ -4575,9 +4898,37 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
|
||||
*fils_kek_len = sm->PTK.kek_len;
|
||||
}
|
||||
|
||||
|
||||
void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
size_t pmk_len, const u8 *pmkid)
|
||||
{
|
||||
os_memcpy(sm->PMK, pmk, pmk_len);
|
||||
sm->pmk_len = pmk_len;
|
||||
os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
|
||||
sm->pmkid_set = 1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
|
||||
{
|
||||
if (sm)
|
||||
sm->auth_alg = auth_alg;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
|
||||
{
|
||||
if (sm) {
|
||||
wpabuf_clear_free(sm->dpp_z);
|
||||
sm->dpp_z = z ? wpabuf_dup(z) : NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
|
||||
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
|
||||
@ -4666,7 +5017,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
|
||||
}
|
||||
}
|
||||
|
||||
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
|
||||
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
|
||||
if (gtk)
|
||||
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
@ -4715,6 +5066,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
|
||||
os_memset(opos, 0, 6); /* clear PN */
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
if (ocv_oci_add(sm, &pos) < 0) {
|
||||
os_free(kde);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
@ -4796,7 +5151,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
|
||||
gtk = gsm->GTK[gsm->GN - 1];
|
||||
if (sm->wpa == WPA_VERSION_WPA2) {
|
||||
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
|
||||
ieee80211w_kde_len(sm);
|
||||
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
|
||||
kde_buf = os_malloc(kde_len);
|
||||
if (kde_buf == NULL)
|
||||
return -1;
|
||||
@ -4816,6 +5171,10 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
|
||||
os_memset(opos, 0, 6); /* clear PN */
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
if (ocv_oci_add(sm, &pos) < 0) {
|
||||
os_free(kde_buf);
|
||||
return -1;
|
||||
}
|
||||
kde_len = pos - kde;
|
||||
} else {
|
||||
kde = gtk;
|
||||
|
@ -145,6 +145,7 @@ struct wpa_state_machine;
|
||||
struct rsn_pmksa_cache_entry;
|
||||
struct eapol_state_machine;
|
||||
struct ft_remote_seq;
|
||||
struct wpa_channel_info;
|
||||
|
||||
|
||||
struct ft_remote_r0kh {
|
||||
@ -191,6 +192,9 @@ struct wpa_auth_config {
|
||||
int group_mgmt_cipher;
|
||||
int sae_require_mfp;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
int ocv; /* Operating Channel Validation */
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
@ -250,7 +254,8 @@ struct wpa_auth_callbacks {
|
||||
int value);
|
||||
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
|
||||
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk, size_t *psk_len);
|
||||
const u8 *prev_psk, size_t *psk_len,
|
||||
int *vlan_id);
|
||||
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
|
||||
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
|
||||
const u8 *addr, int idx, u8 *key, size_t key_len);
|
||||
@ -265,6 +270,11 @@ struct wpa_auth_callbacks {
|
||||
size_t data_len);
|
||||
int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
|
||||
size_t data_len);
|
||||
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
|
||||
int (*update_vlan)(void *ctx, const u8 *addr, int vlan_id);
|
||||
int (*get_sta_tx_params)(void *ctx, const u8 *addr,
|
||||
int ap_max_chanwidth, int ap_seg1_idx,
|
||||
int *bandwidth, int *seg1_idx);
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||
int (*set_vlan)(void *ctx, const u8 *sta_addr,
|
||||
@ -308,7 +318,7 @@ enum {
|
||||
};
|
||||
|
||||
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
@ -316,6 +326,8 @@ int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
const u8 *osen_ie, size_t osen_ie_len);
|
||||
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
|
||||
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
|
||||
int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
|
||||
struct wpa_state_machine *
|
||||
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *p2p_dev_addr);
|
||||
@ -339,6 +351,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
|
||||
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
|
||||
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
|
||||
const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
|
||||
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
|
||||
@ -449,14 +462,21 @@ const u8 * wpa_fils_validate_fils_session(struct wpa_state_machine *sm,
|
||||
int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
|
||||
size_t ies_len);
|
||||
|
||||
int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
|
||||
|
||||
int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
|
||||
u8 *buf, size_t len);
|
||||
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
|
||||
u8 *fils_anonce, u8 *fils_snonce,
|
||||
u8 *fils_kek, size_t *fils_kek_len);
|
||||
void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
size_t pmk_len, const u8 *pmkid);
|
||||
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);
|
||||
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);
|
||||
|
||||
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
@ -468,5 +488,6 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
void *ctx1, void *ctx2);
|
||||
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
|
||||
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "utils/list.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/ocv.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
@ -64,7 +66,7 @@ struct tlv_list {
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
|
||||
const u8 *enc, const size_t enc_len,
|
||||
const u8 *enc, size_t enc_len,
|
||||
const u8 *auth, const size_t auth_len,
|
||||
const u8 *src_addr, u8 type,
|
||||
u8 **plain, size_t *plain_size)
|
||||
@ -72,7 +74,11 @@ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
|
||||
const u8 *ad[3] = { src_addr, auth, &type };
|
||||
size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
|
||||
MAC2STR(src_addr), type);
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
|
||||
|
||||
if (!key) { /* skip decryption */
|
||||
*plain = os_memdup(enc, enc_len);
|
||||
@ -95,8 +101,18 @@ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
|
||||
goto err;
|
||||
|
||||
if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
|
||||
*plain) < 0)
|
||||
goto err;
|
||||
*plain) < 0) {
|
||||
if (enc_len < AES_BLOCK_SIZE + 2)
|
||||
goto err;
|
||||
|
||||
/* Try to work around Ethernet devices that add extra
|
||||
* two octet padding even if the frame is longer than
|
||||
* the minimum Ethernet frame. */
|
||||
enc_len -= 2;
|
||||
if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
|
||||
*plain) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
*plain_size = enc_len - AES_BLOCK_SIZE;
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
|
||||
@ -461,9 +477,12 @@ static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len,
|
||||
const u8 *ad[3] = { src_addr, auth, &type };
|
||||
size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
|
||||
MAC2STR(src_addr), type);
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message",
|
||||
plain, plain_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
|
||||
|
||||
if (!key) {
|
||||
/* encryption not needed, return plaintext as packet */
|
||||
@ -473,6 +492,8 @@ static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len,
|
||||
wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs",
|
||||
enc, plain_len + AES_BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -501,9 +522,10 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
|
||||
const u8 *src_addr, u8 type,
|
||||
u8 **packet, size_t *packet_len)
|
||||
{
|
||||
u8 *plain = NULL, *auth = NULL, *pos;
|
||||
u8 *plain = NULL, *auth = NULL, *pos, *tmp;
|
||||
size_t plain_len = 0, auth_len = 0;
|
||||
int ret = -1;
|
||||
size_t pad_len = 0;
|
||||
|
||||
*packet = NULL;
|
||||
if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
|
||||
@ -515,6 +537,28 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
|
||||
*packet_len = sizeof(u16) + auth_len + plain_len;
|
||||
if (key)
|
||||
*packet_len += AES_BLOCK_SIZE;
|
||||
#define RRB_MIN_MSG_LEN 64
|
||||
if (*packet_len < RRB_MIN_MSG_LEN) {
|
||||
pad_len = RRB_MIN_MSG_LEN - *packet_len;
|
||||
if (pad_len < sizeof(struct ft_rrb_tlv))
|
||||
pad_len = sizeof(struct ft_rrb_tlv);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Pad message to minimum Ethernet frame length (%d --> %d)",
|
||||
(int) *packet_len, (int) (*packet_len + pad_len));
|
||||
*packet_len += pad_len;
|
||||
tmp = os_realloc(auth, auth_len + pad_len);
|
||||
if (!tmp)
|
||||
goto out;
|
||||
auth = tmp;
|
||||
pos = auth + auth_len;
|
||||
WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
|
||||
pos += 2;
|
||||
WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
|
||||
pos += 2;
|
||||
os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
|
||||
auth_len += pad_len;
|
||||
|
||||
}
|
||||
*packet = os_zalloc(*packet_len);
|
||||
if (!*packet)
|
||||
goto out;
|
||||
@ -527,6 +571,7 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
|
||||
if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
|
||||
auth_len, src_addr, type, pos) < 0)
|
||||
goto out;
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len);
|
||||
|
||||
ret = 0;
|
||||
|
||||
@ -594,8 +639,8 @@ static int wpa_ft_rrb_oui_send(struct wpa_authenticator *wpa_auth,
|
||||
{
|
||||
if (!wpa_auth->cb->send_oui)
|
||||
return -1;
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR,
|
||||
oui_suffix, MAC2STR(dst));
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)",
|
||||
oui_suffix, MAC2STR(dst), (unsigned int) data_len);
|
||||
return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
|
||||
data_len);
|
||||
}
|
||||
@ -618,7 +663,7 @@ static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth,
|
||||
if (wpa_auth->cb->get_psk == NULL)
|
||||
return NULL;
|
||||
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
|
||||
prev_psk, NULL);
|
||||
prev_psk, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -727,6 +772,17 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_channel_info *ci)
|
||||
{
|
||||
if (!wpa_auth->cb->channel_info)
|
||||
return -1;
|
||||
return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
|
||||
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
{
|
||||
u8 *pos = buf;
|
||||
@ -894,6 +950,8 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
|
||||
goto err;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
|
||||
MAC2STR(src_addr));
|
||||
item = os_zalloc(sizeof(*item));
|
||||
if (!item)
|
||||
goto err;
|
||||
@ -2016,8 +2074,7 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
struct wpa_ptk *ptk)
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
|
||||
{
|
||||
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
|
||||
size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
|
||||
@ -2373,10 +2430,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
|
||||
end = pos + max_len;
|
||||
|
||||
if (auth_alg == WLAN_AUTH_FT) {
|
||||
if (auth_alg == WLAN_AUTH_FT ||
|
||||
((auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
auth_alg == WLAN_AUTH_FILS_PK) &&
|
||||
(sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384)))) {
|
||||
if (!sm->pmk_r1_name_valid) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"FT: PMKR1Name is not valid for Assoc Resp RSNE");
|
||||
return NULL;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE",
|
||||
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
/*
|
||||
* RSN (only present if this is a Reassociation Response and
|
||||
* part of a fast BSS transition)
|
||||
* part of a fast BSS transition; or if this is a
|
||||
* (Re)Association Response frame during an FT initial mobility
|
||||
* domain association using FILS)
|
||||
*/
|
||||
res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
|
||||
if (res < 0)
|
||||
@ -2430,6 +2501,35 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
os_free(igtk);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
u8 *nbuf, *ocipos;
|
||||
|
||||
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info for OCI element");
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subelem_len += 2 + OCV_OCI_LEN;
|
||||
nbuf = os_realloc(subelem, subelem_len);
|
||||
if (!nbuf) {
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
subelem = nbuf;
|
||||
|
||||
ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
|
||||
*ocipos++ = FTIE_SUBELEM_OCI;
|
||||
*ocipos++ = OCV_OCI_LEN;
|
||||
if (ocv_insert_oci(&ci, &ocipos) < 0) {
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
} else {
|
||||
r0kh_id = conf->r0_key_holder;
|
||||
r0kh_id_len = conf->r0_key_holder_len;
|
||||
@ -2596,6 +2696,8 @@ static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
|
||||
os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
|
||||
if (out_pairwise)
|
||||
*out_pairwise = pairwise;
|
||||
os_memcpy(sm->PMK, pmk, PMK_LEN);
|
||||
sm->pmk_len = PMK_LEN;
|
||||
if (out_vlan &&
|
||||
wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
|
||||
@ -2881,6 +2983,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
|
||||
sm->pmk_r1_name_valid = 1;
|
||||
os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
|
||||
sm->pmk_r1_len = pmk_r1_len;
|
||||
|
||||
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
|
||||
@ -3178,6 +3282,32 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
|
||||
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Failed to get channel info to validate received OCI in (Re)Assoc Request");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
if (get_sta_tx_parameters(sm,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx, &tx_chanwidth,
|
||||
&tx_seg1_idx) < 0)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -4303,6 +4433,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
|
||||
MACSTR, MAC2STR(src_addr));
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
|
||||
|
||||
if (is_multicast_ether_addr(src_addr)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -4331,8 +4462,10 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
}
|
||||
|
||||
auth = data + sizeof(u16);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen);
|
||||
enc = data + sizeof(u16) + alen;
|
||||
elen = data_len - sizeof(u16) - alen;
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen);
|
||||
|
||||
switch (oui_suffix) {
|
||||
case FT_PACKET_R0KH_R1KH_PULL:
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "tkip_countermeasures.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "pmksa_cache_auth.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
@ -55,6 +56,9 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->wmm_enabled = conf->wmm_enabled;
|
||||
wconf->wmm_uapsd = conf->wmm_uapsd;
|
||||
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
|
||||
#ifdef CONFIG_OCV
|
||||
wconf->ocv = conf->ocv;
|
||||
#endif /* CONFIG_OCV */
|
||||
wconf->okc = conf->okc;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
wconf->ieee80211w = conf->ieee80211w;
|
||||
@ -242,12 +246,15 @@ static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
|
||||
|
||||
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk, size_t *psk_len)
|
||||
const u8 *prev_psk, size_t *psk_len,
|
||||
int *vlan_id)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
const u8 *psk;
|
||||
|
||||
if (vlan_id)
|
||||
*vlan_id = 0;
|
||||
if (psk_len)
|
||||
*psk_len = PMK_LEN;
|
||||
|
||||
@ -283,7 +290,8 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk);
|
||||
psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk,
|
||||
vlan_id);
|
||||
/*
|
||||
* This is about to iterate over all psks, prev_psk gives the last
|
||||
* returned psk which should not be returned again.
|
||||
@ -291,6 +299,9 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
*/
|
||||
if (sta && sta->psk && !psk) {
|
||||
struct hostapd_sta_wpa_psk_short *pos;
|
||||
|
||||
if (vlan_id)
|
||||
*vlan_id = 0;
|
||||
psk = sta->psk->psk;
|
||||
for (pos = sta->psk; pos; pos = pos->next) {
|
||||
if (pos->is_passphrase) {
|
||||
@ -776,6 +787,74 @@ static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
return hostapd_drv_channel_info(hapd, ci);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
|
||||
{
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
struct vlan_description vlan_desc;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
vlan_desc.notempty = 1;
|
||||
vlan_desc.untagged = vlan_id;
|
||||
if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
|
||||
wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
|
||||
vlan_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Failed to assign VLAN ID %d from wpa_psk_file to "
|
||||
MACSTR, vlan_id, MAC2STR(sta->addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"Assigned VLAN ID %d from wpa_psk_file to " MACSTR,
|
||||
vlan_id, MAC2STR(sta->addr));
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
return -1;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr,
|
||||
int ap_max_chanwidth, int ap_seg1_idx,
|
||||
int *bandwidth, int *seg1_idx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta) {
|
||||
hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO,
|
||||
"Failed to get STA info to validate received OCI");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth,
|
||||
seg1_idx);
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
|
||||
@ -814,12 +893,18 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
|
||||
" based on WPA authenticator callback",
|
||||
MAC2STR(sta_addr));
|
||||
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
|
||||
return NULL;
|
||||
|
||||
sta = ap_sta_add(hapd, sta_addr);
|
||||
if (sta == NULL)
|
||||
return NULL;
|
||||
if (hapd->driver && hapd->driver->add_sta_node)
|
||||
sta->added_unassoc = 1;
|
||||
sta->ft_over_ds = 1;
|
||||
if (sta->wpa_sm) {
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
return sta->wpa_sm;
|
||||
@ -1189,6 +1274,11 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
.for_each_auth = hostapd_wpa_auth_for_each_auth,
|
||||
.send_ether = hostapd_wpa_auth_send_ether,
|
||||
.send_oui = hostapd_wpa_auth_send_oui,
|
||||
.channel_info = hostapd_channel_info,
|
||||
.update_vlan = hostapd_wpa_auth_update_vlan,
|
||||
#ifdef CONFIG_OCV
|
||||
.get_sta_tx_params = hostapd_get_sta_tx_params,
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
.send_ft_action = hostapd_wpa_auth_send_ft_action,
|
||||
.add_sta = hostapd_wpa_auth_add_sta,
|
||||
|
@ -22,6 +22,7 @@ struct wpa_state_machine {
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 p2p_dev_addr[ETH_ALEN];
|
||||
u16 auth_alg;
|
||||
|
||||
enum {
|
||||
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
|
||||
@ -92,6 +93,9 @@ struct wpa_state_machine {
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
unsigned int is_wnmsleep:1;
|
||||
unsigned int pmkid_set:1;
|
||||
#ifdef CONFIG_OCV
|
||||
unsigned int ocv_enabled:1;
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
int req_replay_counter_used;
|
||||
@ -115,6 +119,8 @@ struct wpa_state_machine {
|
||||
u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
|
||||
* first 384 bits of MSK */
|
||||
size_t xxkey_len;
|
||||
u8 pmk_r1[PMK_LEN_MAX];
|
||||
unsigned int pmk_r1_len;
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
|
||||
* Request */
|
||||
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
|
||||
@ -147,6 +153,10 @@ struct wpa_state_machine {
|
||||
unsigned int fils_completed:1;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
struct wpabuf *dpp_z;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
void (*eapol_status_cb)(void *ctx1, void *ctx2);
|
||||
void *eapol_status_cb_ctx1;
|
||||
@ -282,8 +292,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
const u8 *anonce, const u8 *snonce,
|
||||
u8 *buf, size_t len, const u8 *subelem,
|
||||
size_t subelem_len);
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
struct wpa_ptk *ptk);
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
|
||||
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
|
||||
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
|
||||
|
@ -293,9 +293,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
capab |= WPA_CAPABILITY_MFPR;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
if (conf->ocv)
|
||||
capab |= WPA_CAPABILITY_OCVC;
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_RSN_TESTING
|
||||
if (rsn_testing)
|
||||
capab |= BIT(8) | BIT(14) | BIT(15);
|
||||
capab |= BIT(8) | BIT(15);
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
WPA_PUT_LE16(pos, capab);
|
||||
pos += 2;
|
||||
@ -414,6 +418,10 @@ static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
|
||||
capab |= WPA_CAPABILITY_MFPR;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
if (conf->ocv)
|
||||
capab |= WPA_CAPABILITY_OCVC;
|
||||
#endif /* CONFIG_OCV */
|
||||
WPA_PUT_LE16(eid, capab);
|
||||
eid += 2;
|
||||
|
||||
@ -522,7 +530,7 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
|
||||
|
||||
|
||||
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
@ -552,6 +560,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
|
||||
if (version == WPA_PROTO_RSN) {
|
||||
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
|
||||
if (!data.has_pairwise)
|
||||
data.pairwise_cipher = wpa_default_rsn_cipher(freq);
|
||||
if (!data.has_group)
|
||||
data.group_cipher = wpa_default_rsn_cipher(freq);
|
||||
|
||||
if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
|
||||
!wpa_key_mgmt_only_ft(data.key_mgmt)) {
|
||||
/* Workaround for some HP and Epson printers that seem
|
||||
* to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP
|
||||
* advertised RSNE to Association Request frame. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: FT set in RSNE AKM but MDE is missing from "
|
||||
MACSTR
|
||||
" - ignore FT AKM(s) because there's also a non-FT AKM",
|
||||
MAC2STR(sm->addr));
|
||||
data.key_mgmt &= ~WPA_KEY_MGMT_FT;
|
||||
}
|
||||
|
||||
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
|
||||
if (0) {
|
||||
@ -760,6 +785,17 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Management frame protection required with OCV, but client did not enable it");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
|
||||
(data.capabilities & WPA_CAPABILITY_OCVC));
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC))
|
||||
sm->mgmt_frame_prot = 0;
|
||||
@ -799,6 +835,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
"OWE: No Diffie-Hellman Parameter element");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
#ifdef CONFIG_DPP
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
|
||||
/* Diffie-Hellman Parameter element can be used with DPP as
|
||||
* well, so allow this to proceed. */
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
|
||||
@ -816,6 +858,21 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
else
|
||||
sm->wpa = WPA_VERSION_WPA;
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
|
||||
if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
|
||||
sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
|
||||
(sm->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sm->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sm->auth_alg == WLAN_AUTH_FILS_PK) &&
|
||||
(data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid ||
|
||||
os_memcmp_const(data.pmkid, sm->pmk_r1_name,
|
||||
WPA_PMK_NAME_LEN) != 0)) {
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"No PMKR1Name match for FILS+FT");
|
||||
return WPA_INVALID_PMKID;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */
|
||||
|
||||
sm->pmksa = NULL;
|
||||
for (i = 0; i < data.num_pmkid; i++) {
|
||||
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
|
||||
@ -995,6 +1052,15 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
|
||||
ie->oci = pos + 2 + RSN_SELECTOR_LEN;
|
||||
ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1062,6 +1128,23 @@ int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
|
||||
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
|
||||
{
|
||||
if (sm)
|
||||
sm->ocv_enabled = ocv;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_uses_ocv(struct wpa_state_machine *sm)
|
||||
{
|
||||
return sm ? sm->ocv_enabled : 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
|
||||
u8 *pos, size_t max_len,
|
||||
|
@ -33,6 +33,10 @@ struct wpa_eapol_ie_parse {
|
||||
const u8 *ip_addr_req;
|
||||
const u8 *ip_addr_alloc;
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_OCV
|
||||
const u8 *oci;
|
||||
size_t oci_len;
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
const u8 *osen;
|
||||
size_t osen_len;
|
||||
|
@ -354,6 +354,18 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
bss->wpa_pairwise,
|
||||
bss->rsn_pairwise);
|
||||
|
||||
if (hapd->conf->wps_cred_add_sae &&
|
||||
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
|
||||
cred->key_len != 2 * PMK_LEN) {
|
||||
bss->wpa_key_mgmt |= WPA_KEY_MGMT_SAE;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (bss->ieee80211w == NO_MGMT_FRAME_PROTECTION)
|
||||
bss->ieee80211w =
|
||||
MGMT_FRAME_PROTECTION_OPTIONAL;
|
||||
bss->sae_require_mfp = 1;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
}
|
||||
|
||||
if (cred->key_len >= 8 && cred->key_len < 64) {
|
||||
os_free(bss->ssid.wpa_passphrase);
|
||||
bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
|
||||
@ -401,6 +413,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
char buf[1024];
|
||||
int multi_bss;
|
||||
int wpa;
|
||||
int pmf_changed = 0;
|
||||
|
||||
if (hapd->wps == NULL)
|
||||
return 0;
|
||||
@ -520,6 +533,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
|
||||
if (wpa) {
|
||||
char *prefix;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
int sae = 0;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
fprintf(nconf, "wpa=%d\n", wpa);
|
||||
|
||||
fprintf(nconf, "wpa_key_mgmt=");
|
||||
@ -528,10 +545,30 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
fprintf(nconf, "WPA-EAP");
|
||||
prefix = " ";
|
||||
}
|
||||
if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
|
||||
if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
|
||||
fprintf(nconf, "%sWPA-PSK", prefix);
|
||||
prefix = " ";
|
||||
}
|
||||
if (hapd->conf->wps_cred_add_sae &&
|
||||
(cred->auth_type & WPS_AUTH_WPA2PSK) &&
|
||||
cred->key_len != 2 * PMK_LEN) {
|
||||
fprintf(nconf, "%sSAE", prefix);
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
sae = 1;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
}
|
||||
fprintf(nconf, "\n");
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (sae && hapd->conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
|
||||
fprintf(nconf, "ieee80211w=%d\n",
|
||||
MGMT_FRAME_PROTECTION_OPTIONAL);
|
||||
pmf_changed = 1;
|
||||
}
|
||||
if (sae)
|
||||
fprintf(nconf, "sae_require_mfp=1\n");
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
fprintf(nconf, "wpa_pairwise=");
|
||||
prefix = "";
|
||||
if (cred->encr_type & WPS_ENCR_AES) {
|
||||
@ -585,6 +622,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
str_starts(buf, "wep_default_key=") ||
|
||||
str_starts(buf, "wep_key") ||
|
||||
str_starts(buf, "wps_state=") ||
|
||||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
|
||||
str_starts(buf, "wpa=") ||
|
||||
str_starts(buf, "wpa_psk=") ||
|
||||
str_starts(buf, "wpa_pairwise=") ||
|
||||
@ -975,6 +1013,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
{
|
||||
struct wps_context *wps;
|
||||
struct wps_registrar_config cfg;
|
||||
u8 *multi_ap_netw_key = NULL;
|
||||
|
||||
if (conf->wps_state == 0) {
|
||||
hostapd_wps_clear_ies(hapd, 0);
|
||||
@ -1133,6 +1172,31 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
}
|
||||
|
||||
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
|
||||
hapd->conf->multi_ap_backhaul_ssid.ssid_len) {
|
||||
cfg.multi_ap_backhaul_ssid_len =
|
||||
hapd->conf->multi_ap_backhaul_ssid.ssid_len;
|
||||
cfg.multi_ap_backhaul_ssid =
|
||||
hapd->conf->multi_ap_backhaul_ssid.ssid;
|
||||
|
||||
if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
|
||||
cfg.multi_ap_backhaul_network_key = (const u8 *)
|
||||
conf->multi_ap_backhaul_ssid.wpa_passphrase;
|
||||
cfg.multi_ap_backhaul_network_key_len =
|
||||
os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
|
||||
} else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
|
||||
multi_ap_netw_key = os_malloc(2 * PMK_LEN + 1);
|
||||
if (!multi_ap_netw_key)
|
||||
goto fail;
|
||||
wpa_snprintf_hex((char *) multi_ap_netw_key,
|
||||
2 * PMK_LEN + 1,
|
||||
conf->multi_ap_backhaul_ssid.wpa_psk->psk,
|
||||
PMK_LEN);
|
||||
cfg.multi_ap_backhaul_network_key = multi_ap_netw_key;
|
||||
cfg.multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
wps->ap_settings = conf->ap_settings;
|
||||
wps->ap_settings_len = conf->ap_settings_len;
|
||||
|
||||
@ -1174,10 +1238,12 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
|
||||
|
||||
hapd->wps = wps;
|
||||
bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bin_clear_free(multi_ap_netw_key, 2 * PMK_LEN);
|
||||
hostapd_free_wps(wps);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* common module tests
|
||||
* Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2014-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -10,10 +10,12 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/module_tests.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "ieee802_11_common.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "gas.h"
|
||||
#include "wpa_common.h"
|
||||
#include "sae.h"
|
||||
|
||||
|
||||
struct ieee802_11_parse_test_data {
|
||||
@ -248,6 +250,179 @@ static int gas_tests(void)
|
||||
}
|
||||
|
||||
|
||||
static int sae_tests(void)
|
||||
{
|
||||
#ifdef CONFIG_SAE
|
||||
struct sae_data sae;
|
||||
int ret = -1;
|
||||
/* IEEE P802.11-REVmd/D2.1, Annex J.10 */
|
||||
const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
|
||||
const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
|
||||
const char *pw = "mekmitasdigoat";
|
||||
const char *pwid = "psk4internet";
|
||||
const u8 local_rand[] = {
|
||||
0xa9, 0x06, 0xf6, 0x1e, 0x4d, 0x3a, 0x5d, 0x4e,
|
||||
0xb2, 0x96, 0x5f, 0xf3, 0x4c, 0xf9, 0x17, 0xdd,
|
||||
0x04, 0x44, 0x45, 0xc8, 0x78, 0xc1, 0x7c, 0xa5,
|
||||
0xd5, 0xb9, 0x37, 0x86, 0xda, 0x9f, 0x83, 0xcf
|
||||
};
|
||||
const u8 local_mask[] = {
|
||||
0x42, 0x34, 0xb4, 0xfb, 0x17, 0xaa, 0x43, 0x5c,
|
||||
0x52, 0xfb, 0xfd, 0xeb, 0xe6, 0x40, 0x39, 0xb4,
|
||||
0x34, 0x78, 0x20, 0x0e, 0x54, 0xff, 0x7b, 0x6e,
|
||||
0x07, 0xb6, 0x9c, 0xad, 0x74, 0x15, 0x3c, 0x15
|
||||
};
|
||||
const u8 local_commit[] = {
|
||||
0x13, 0x00, 0xeb, 0x3b, 0xab, 0x19, 0x64, 0xe4,
|
||||
0xa0, 0xab, 0x05, 0x92, 0x5d, 0xdf, 0x33, 0x39,
|
||||
0x51, 0x91, 0x38, 0xbc, 0x65, 0xd6, 0xcd, 0xc0,
|
||||
0xf8, 0x13, 0xdd, 0x6f, 0xd4, 0x34, 0x4e, 0xb4,
|
||||
0xbf, 0xe4, 0x4b, 0x5c, 0x21, 0x59, 0x76, 0x58,
|
||||
0xf4, 0xe3, 0xed, 0xdf, 0xb4, 0xb9, 0x9f, 0x25,
|
||||
0xb4, 0xd6, 0x54, 0x0f, 0x32, 0xff, 0x1f, 0xd5,
|
||||
0xc5, 0x30, 0xc6, 0x0a, 0x79, 0x44, 0x48, 0x61,
|
||||
0x0b, 0xc6, 0xde, 0x3d, 0x92, 0xbd, 0xbb, 0xd4,
|
||||
0x7d, 0x93, 0x59, 0x80, 0xca, 0x6c, 0xf8, 0x98,
|
||||
0x8a, 0xb6, 0x63, 0x0b, 0xe6, 0x76, 0x4c, 0x88,
|
||||
0x5c, 0xeb, 0x97, 0x93, 0x97, 0x0f, 0x69, 0x52,
|
||||
0x17, 0xee, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
|
||||
0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||
0x74
|
||||
};
|
||||
const u8 peer_commit[] = {
|
||||
0x13, 0x00, 0x55, 0x64, 0xf0, 0x45, 0xb2, 0xea,
|
||||
0x1e, 0x56, 0x6c, 0xf1, 0xdd, 0x74, 0x1f, 0x70,
|
||||
0xd9, 0xbe, 0x35, 0xd2, 0xdf, 0x5b, 0x9a, 0x55,
|
||||
0x02, 0x94, 0x6e, 0xe0, 0x3c, 0xf8, 0xda, 0xe2,
|
||||
0x7e, 0x1e, 0x05, 0xb8, 0x43, 0x0e, 0xb7, 0xa9,
|
||||
0x9e, 0x24, 0x87, 0x7c, 0xe6, 0x9b, 0xaf, 0x3d,
|
||||
0xc5, 0x80, 0xe3, 0x09, 0x63, 0x3d, 0x6b, 0x38,
|
||||
0x5f, 0x83, 0xee, 0x1c, 0x3e, 0xc3, 0x59, 0x1f,
|
||||
0x1a, 0x53, 0x93, 0xc0, 0x6e, 0x80, 0x5d, 0xdc,
|
||||
0xeb, 0x2f, 0xde, 0x50, 0x93, 0x0d, 0xd7, 0xcf,
|
||||
0xeb, 0xb9, 0x87, 0xc6, 0xff, 0x96, 0x66, 0xaf,
|
||||
0x16, 0x4e, 0xb5, 0x18, 0x4d, 0x8e, 0x66, 0x62,
|
||||
0xed, 0x6a, 0xff, 0x0d, 0x21, 0x70, 0x73, 0x6b,
|
||||
0x34, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||
0x74
|
||||
};
|
||||
const u8 kck[] = {
|
||||
0x59, 0x9d, 0x6f, 0x1e, 0x27, 0x54, 0x8b, 0xe8,
|
||||
0x49, 0x9d, 0xce, 0xed, 0x2f, 0xec, 0xcf, 0x94,
|
||||
0x81, 0x8c, 0xe1, 0xc7, 0x9f, 0x1b, 0x4e, 0xb3,
|
||||
0xd6, 0xa5, 0x32, 0x28, 0xa0, 0x9b, 0xf3, 0xed
|
||||
};
|
||||
const u8 pmk[] = {
|
||||
0x7a, 0xea, 0xd8, 0x6f, 0xba, 0x4c, 0x32, 0x21,
|
||||
0xfc, 0x43, 0x7f, 0x5f, 0x14, 0xd7, 0x0d, 0x85,
|
||||
0x4e, 0xa5, 0xd5, 0xaa, 0xc1, 0x69, 0x01, 0x16,
|
||||
0x79, 0x30, 0x81, 0xed, 0xa4, 0xd5, 0x57, 0xc5
|
||||
};
|
||||
const u8 pmkid[] = {
|
||||
0x40, 0xa0, 0x9b, 0x60, 0x17, 0xce, 0xbf, 0x00,
|
||||
0x72, 0x84, 0x3b, 0x53, 0x52, 0xaa, 0x2b, 0x4f
|
||||
};
|
||||
const u8 local_confirm[] = {
|
||||
0x01, 0x00, 0x12, 0xd9, 0xd5, 0xc7, 0x8c, 0x50,
|
||||
0x05, 0x26, 0xd3, 0x6c, 0x41, 0xdb, 0xc5, 0x6a,
|
||||
0xed, 0xf2, 0x91, 0x4c, 0xed, 0xdd, 0xd7, 0xca,
|
||||
0xd4, 0xa5, 0x8c, 0x48, 0xf8, 0x3d, 0xbd, 0xe9,
|
||||
0xfc, 0x77
|
||||
};
|
||||
const u8 peer_confirm[] = {
|
||||
0x01, 0x00, 0x02, 0x87, 0x1c, 0xf9, 0x06, 0x89,
|
||||
0x8b, 0x80, 0x60, 0xec, 0x18, 0x41, 0x43, 0xbe,
|
||||
0x77, 0xb8, 0xc0, 0x8a, 0x80, 0x19, 0xb1, 0x3e,
|
||||
0xb6, 0xd0, 0xae, 0xf0, 0xd8, 0x38, 0x3d, 0xfa,
|
||||
0xc2, 0xfd
|
||||
};
|
||||
struct wpabuf *buf = NULL;
|
||||
struct crypto_bignum *mask = NULL;
|
||||
|
||||
os_memset(&sae, 0, sizeof(sae));
|
||||
buf = wpabuf_alloc(1000);
|
||||
if (!buf ||
|
||||
sae_set_group(&sae, 19) < 0 ||
|
||||
sae_prepare_commit(addr1, addr2, (const u8 *) pw, os_strlen(pw),
|
||||
pwid, &sae) < 0)
|
||||
goto fail;
|
||||
|
||||
/* Override local values based on SAE test vector */
|
||||
crypto_bignum_deinit(sae.tmp->sae_rand, 1);
|
||||
sae.tmp->sae_rand = crypto_bignum_init_set(local_rand,
|
||||
sizeof(local_rand));
|
||||
mask = crypto_bignum_init_set(local_mask, sizeof(local_mask));
|
||||
if (!sae.tmp->sae_rand || !mask)
|
||||
goto fail;
|
||||
|
||||
if (crypto_bignum_add(sae.tmp->sae_rand, mask,
|
||||
sae.tmp->own_commit_scalar) < 0 ||
|
||||
crypto_bignum_mod(sae.tmp->own_commit_scalar, sae.tmp->order,
|
||||
sae.tmp->own_commit_scalar) < 0 ||
|
||||
crypto_ec_point_mul(sae.tmp->ec, sae.tmp->pwe_ecc, mask,
|
||||
sae.tmp->own_commit_element_ecc) < 0 ||
|
||||
crypto_ec_point_invert(sae.tmp->ec,
|
||||
sae.tmp->own_commit_element_ecc) < 0)
|
||||
goto fail;
|
||||
|
||||
/* Check that output matches the test vector */
|
||||
sae_write_commit(&sae, buf, NULL, pwid);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
|
||||
|
||||
if (wpabuf_len(buf) != sizeof(local_commit) ||
|
||||
os_memcmp(wpabuf_head(buf), local_commit,
|
||||
sizeof(local_commit)) != 0) {
|
||||
wpa_printf(MSG_ERROR, "SAE: Mismatch in local commit");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
|
||||
NULL) != 0 ||
|
||||
sae_process_commit(&sae) < 0)
|
||||
goto fail;
|
||||
|
||||
if (os_memcmp(kck, sae.tmp->kck, SAE_KCK_LEN) != 0) {
|
||||
wpa_printf(MSG_ERROR, "SAE: Mismatch in KCK");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (os_memcmp(pmk, sae.pmk, SAE_PMK_LEN) != 0) {
|
||||
wpa_printf(MSG_ERROR, "SAE: Mismatch in PMK");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (os_memcmp(pmkid, sae.pmkid, SAE_PMKID_LEN) != 0) {
|
||||
wpa_printf(MSG_ERROR, "SAE: Mismatch in PMKID");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buf->used = 0;
|
||||
sae.send_confirm = 1;
|
||||
sae_write_confirm(&sae, buf);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE: Confirm message", buf);
|
||||
|
||||
if (wpabuf_len(buf) != sizeof(local_confirm) ||
|
||||
os_memcmp(wpabuf_head(buf), local_confirm,
|
||||
sizeof(local_confirm)) != 0) {
|
||||
wpa_printf(MSG_ERROR, "SAE: Mismatch in local confirm");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
sae_clear_data(&sae);
|
||||
wpabuf_free(buf);
|
||||
crypto_bignum_deinit(mask, 1);
|
||||
return ret;
|
||||
#else /* CONFIG_SAE */
|
||||
return 0;
|
||||
#endif /* CONFIG_SAE */
|
||||
}
|
||||
|
||||
|
||||
int common_module_tests(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -256,6 +431,7 @@ int common_module_tests(void)
|
||||
|
||||
if (ieee802_11_parse_tests() < 0 ||
|
||||
gas_tests() < 0 ||
|
||||
sae_tests() < 0 ||
|
||||
rsn_ie_parse_tests() < 0)
|
||||
ret = -1;
|
||||
|
||||
|
@ -59,6 +59,13 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
|
||||
#define WPA_KEY_MGMT_DPP BIT(23)
|
||||
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
|
||||
|
||||
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
|
||||
WPA_KEY_MGMT_FT_IEEE8021X | \
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
|
||||
WPA_KEY_MGMT_FT_SAE | \
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 | \
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384)
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
|
||||
@ -86,12 +93,14 @@ static inline int wpa_key_mgmt_wpa_psk(int akm)
|
||||
|
||||
static inline int wpa_key_mgmt_ft(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X |
|
||||
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
|
||||
WPA_KEY_MGMT_FT_SAE |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA256 |
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
return !!(akm & WPA_KEY_MGMT_FT);
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_only_ft(int akm)
|
||||
{
|
||||
int ft = wpa_key_mgmt_ft(akm);
|
||||
akm &= ~WPA_KEY_MGMT_FT;
|
||||
return ft && !akm;
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_ft_psk(int akm)
|
||||
@ -399,4 +408,15 @@ enum eap_proxy_sim_state {
|
||||
#define OCE_STA_CFON BIT(1)
|
||||
#define OCE_AP BIT(2)
|
||||
|
||||
/* enum chan_width - Channel width definitions */
|
||||
enum chan_width {
|
||||
CHAN_WIDTH_20_NOHT,
|
||||
CHAN_WIDTH_20,
|
||||
CHAN_WIDTH_40,
|
||||
CHAN_WIDTH_80,
|
||||
CHAN_WIDTH_80P80,
|
||||
CHAN_WIDTH_160,
|
||||
CHAN_WIDTH_UNKNOWN
|
||||
};
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* DPP functionality shared between hostapd and wpa_supplicant
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -9,12 +10,16 @@
|
||||
#ifndef DPP_H
|
||||
#define DPP_H
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "utils/list.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
struct crypto_ecdh;
|
||||
struct dpp_global;
|
||||
|
||||
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
|
||||
|
||||
enum dpp_public_action_frame_type {
|
||||
@ -27,6 +32,7 @@ enum dpp_public_action_frame_type {
|
||||
DPP_PA_PKEX_EXCHANGE_RESP = 8,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
|
||||
DPP_PA_CONFIGURATION_RESULT = 11,
|
||||
};
|
||||
|
||||
enum dpp_attribute_id {
|
||||
@ -54,6 +60,8 @@ enum dpp_attribute_id {
|
||||
DPP_ATTR_TRANSACTION_ID = 0x1016,
|
||||
DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
|
||||
DPP_ATTR_CHANNEL = 0x1018,
|
||||
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
|
||||
DPP_ATTR_ENVELOPED_DATA = 0x101A,
|
||||
};
|
||||
|
||||
enum dpp_status_error {
|
||||
@ -66,6 +74,7 @@ enum dpp_status_error {
|
||||
DPP_STATUS_RESPONSE_PENDING = 6,
|
||||
DPP_STATUS_INVALID_CONNECTOR = 7,
|
||||
DPP_STATUS_NO_MATCH = 8,
|
||||
DPP_STATUS_CONFIG_REJECTED = 9,
|
||||
};
|
||||
|
||||
#define DPP_CAPAB_ENROLLEE BIT(0)
|
||||
@ -141,7 +150,9 @@ enum dpp_akm {
|
||||
DPP_AKM_DPP,
|
||||
DPP_AKM_PSK,
|
||||
DPP_AKM_SAE,
|
||||
DPP_AKM_PSK_SAE
|
||||
DPP_AKM_PSK_SAE,
|
||||
DPP_AKM_SAE_DPP,
|
||||
DPP_AKM_PSK_SAE_DPP,
|
||||
};
|
||||
|
||||
struct dpp_configuration {
|
||||
@ -158,10 +169,12 @@ struct dpp_configuration {
|
||||
/* For legacy configuration */
|
||||
char *passphrase;
|
||||
u8 psk[32];
|
||||
int psk_set;
|
||||
};
|
||||
|
||||
struct dpp_authentication {
|
||||
void *msg_ctx;
|
||||
u8 peer_version;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
@ -169,6 +182,7 @@ struct dpp_authentication {
|
||||
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
|
||||
int response_pending;
|
||||
enum dpp_status_error auth_resp_status;
|
||||
enum dpp_status_error conf_resp_status;
|
||||
u8 peer_mac_addr[ETH_ALEN];
|
||||
u8 i_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 r_nonce[DPP_MAX_NONCE_LEN];
|
||||
@ -204,6 +218,8 @@ struct dpp_authentication {
|
||||
u8 allowed_roles;
|
||||
int configurator;
|
||||
int remove_on_tx_status;
|
||||
int connect_on_tx_status;
|
||||
int waiting_conf_result;
|
||||
int auth_success;
|
||||
struct wpabuf *conf_req;
|
||||
const struct wpabuf *conf_resp; /* owned by GAS server */
|
||||
@ -336,6 +352,7 @@ enum dpp_test_behavior {
|
||||
DPP_TEST_STOP_AT_AUTH_RESP = 88,
|
||||
DPP_TEST_STOP_AT_AUTH_CONF = 89,
|
||||
DPP_TEST_STOP_AT_CONF_REQ = 90,
|
||||
DPP_TEST_REJECT_CONFIG = 91,
|
||||
};
|
||||
|
||||
extern enum dpp_test_behavior dpp_test;
|
||||
@ -382,13 +399,28 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
struct dpp_configuration * dpp_configuration_alloc(const char *type);
|
||||
int dpp_akm_psk(enum dpp_akm akm);
|
||||
int dpp_akm_sae(enum dpp_akm akm);
|
||||
int dpp_akm_legacy(enum dpp_akm akm);
|
||||
int dpp_akm_dpp(enum dpp_akm akm);
|
||||
int dpp_akm_ver2(enum dpp_akm akm);
|
||||
int dpp_configuration_valid(const struct dpp_configuration *conf);
|
||||
void dpp_configuration_free(struct dpp_configuration *conf);
|
||||
int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_authentication *auth,
|
||||
const char *cmd);
|
||||
void dpp_auth_deinit(struct dpp_authentication *auth);
|
||||
struct wpabuf *
|
||||
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
const struct wpabuf *resp);
|
||||
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
|
||||
const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
|
||||
enum dpp_status_error status);
|
||||
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
|
||||
size_t len);
|
||||
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
|
||||
@ -432,4 +464,42 @@ void dpp_pkex_free(struct dpp_pkex *pkex);
|
||||
|
||||
char * dpp_corrupt_connector_signature(const char *connector);
|
||||
|
||||
|
||||
struct dpp_pfs {
|
||||
struct crypto_ecdh *ecdh;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct wpabuf *ie;
|
||||
struct wpabuf *secret;
|
||||
};
|
||||
|
||||
struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
|
||||
size_t net_access_key_len);
|
||||
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
|
||||
void dpp_pfs_free(struct dpp_pfs *pfs);
|
||||
|
||||
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
|
||||
const char *uri);
|
||||
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd);
|
||||
struct dpp_bootstrap_info *
|
||||
dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id);
|
||||
int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id);
|
||||
struct dpp_bootstrap_info *
|
||||
dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
|
||||
unsigned int freq);
|
||||
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
|
||||
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
|
||||
char *reply, int reply_size);
|
||||
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
|
||||
const u8 *r_bootstrap,
|
||||
struct dpp_bootstrap_info **own_bi,
|
||||
struct dpp_bootstrap_info **peer_bi);
|
||||
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);
|
||||
void dpp_global_clear(struct dpp_global *dpp);
|
||||
void dpp_global_deinit(struct dpp_global *dpp);
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* DPP_H */
|
||||
|
@ -87,13 +87,29 @@ int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
|
||||
int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
|
||||
int sec_chan)
|
||||
{
|
||||
int ok, j, first;
|
||||
int ok, first;
|
||||
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
|
||||
149, 157, 165, 184, 192 };
|
||||
size_t k;
|
||||
struct hostapd_channel_data *p_chan, *s_chan;
|
||||
const int ht40_plus = pri_chan < sec_chan;
|
||||
|
||||
if (pri_chan == sec_chan || !sec_chan)
|
||||
return 1; /* HT40 not used */
|
||||
p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
|
||||
if (!p_chan)
|
||||
return 0;
|
||||
|
||||
if (pri_chan == sec_chan || !sec_chan) {
|
||||
if (chan_pri_allowed(p_chan))
|
||||
return 1; /* HT40 not used */
|
||||
|
||||
wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
|
||||
pri_chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
|
||||
if (!s_chan)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HT40: control channel: %d secondary channel: %d",
|
||||
@ -101,16 +117,9 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
|
||||
|
||||
/* Verify that HT40 secondary channel is an allowed 20 MHz
|
||||
* channel */
|
||||
ok = 0;
|
||||
for (j = 0; j < mode->num_channels; j++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[j];
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
chan->chan == sec_chan) {
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
if ((s_chan->flag & HOSTAPD_CHAN_DISABLED) ||
|
||||
(ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
|
||||
(!ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
|
||||
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
|
||||
sec_chan);
|
||||
return 0;
|
||||
@ -553,3 +562,59 @@ int ieee80211ac_cap_check(u32 hw, u32 conf)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
|
||||
u32 num_chan_to_bw(int num_chans)
|
||||
{
|
||||
switch (num_chans) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
return num_chans * 20;
|
||||
default:
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* check if BW is applicable for channel */
|
||||
int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
|
||||
int ht40_plus, int pri)
|
||||
{
|
||||
u32 bw_mask;
|
||||
|
||||
switch (bw) {
|
||||
case 20:
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_20;
|
||||
break;
|
||||
case 40:
|
||||
/* HT 40 MHz support declared only for primary channel,
|
||||
* just skip 40 MHz secondary checking */
|
||||
if (pri && ht40_plus)
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_40P;
|
||||
else if (pri && !ht40_plus)
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_40M;
|
||||
else
|
||||
bw_mask = 0;
|
||||
break;
|
||||
case 80:
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_80;
|
||||
break;
|
||||
case 160:
|
||||
bw_mask = HOSTAPD_CHAN_WIDTH_160;
|
||||
break;
|
||||
default:
|
||||
bw_mask = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (chan->allowed_bw & bw_mask) == bw_mask;
|
||||
}
|
||||
|
||||
|
||||
/* check if channel is allowed to be used as primary */
|
||||
int chan_pri_allowed(const struct hostapd_channel_data *chan)
|
||||
{
|
||||
return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
|
||||
}
|
||||
|
@ -39,4 +39,9 @@ void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
|
||||
int disabled);
|
||||
int ieee80211ac_cap_check(u32 hw, u32 conf);
|
||||
|
||||
u32 num_chan_to_bw(int num_chans);
|
||||
int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
|
||||
int ht40_plus, int pri);
|
||||
int chan_pri_allowed(const struct hostapd_channel_data *chan);
|
||||
|
||||
#endif /* HW_FEATURES_COMMON_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -126,6 +126,10 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
elems->roaming_cons_sel = pos;
|
||||
elems->roaming_cons_sel_len = elen;
|
||||
break;
|
||||
case MULTI_AP_OUI_TYPE:
|
||||
elems->multi_ap = pos;
|
||||
elems->multi_ap_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
|
||||
"information element ignored "
|
||||
@ -266,6 +270,14 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
elems->password_id = pos;
|
||||
elems->password_id_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_HE_CAPABILITIES:
|
||||
elems->he_capabilities = pos;
|
||||
elems->he_capabilities_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_OCV_OCI:
|
||||
elems->oci = pos;
|
||||
elems->oci_len = elen;
|
||||
break;
|
||||
default:
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
@ -291,29 +303,17 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors)
|
||||
{
|
||||
size_t left = len;
|
||||
const u8 *pos = start;
|
||||
const struct element *elem;
|
||||
int unknown = 0;
|
||||
|
||||
os_memset(elems, 0, sizeof(*elems));
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
if (!start)
|
||||
return ParseOK;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
left -= 2;
|
||||
|
||||
if (elen > left) {
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
|
||||
"parse failed (id=%d elen=%d "
|
||||
"left=%lu)",
|
||||
id, elen, (unsigned long) left);
|
||||
wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
|
||||
}
|
||||
return ParseFailed;
|
||||
}
|
||||
for_each_element(elem, start, len) {
|
||||
u8 id = elem->id, elen = elem->datalen;
|
||||
const u8 *pos = elem->data;
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
@ -461,8 +461,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->mic = pos;
|
||||
elems->mic_len = elen;
|
||||
/* after mic everything is encrypted, so stop. */
|
||||
left = elen;
|
||||
break;
|
||||
goto done;
|
||||
case WLAN_EID_MULTI_BAND:
|
||||
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
@ -521,35 +520,33 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
id, elen);
|
||||
break;
|
||||
}
|
||||
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
if (left)
|
||||
if (!for_each_element_completed(elem, start, len)) {
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"IEEE 802.11 element parse failed @%d",
|
||||
(int) (start + len - (const u8 *) elem));
|
||||
wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
|
||||
}
|
||||
return ParseFailed;
|
||||
}
|
||||
|
||||
done:
|
||||
return unknown ? ParseUnknown : ParseOK;
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
|
||||
{
|
||||
const struct element *elem;
|
||||
int count = 0;
|
||||
const u8 *pos, *end;
|
||||
|
||||
if (ies == NULL)
|
||||
return 0;
|
||||
|
||||
pos = ies;
|
||||
end = ies + ies_len;
|
||||
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
for_each_element(elem, ies, ies_len)
|
||||
count++;
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -559,24 +556,17 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
u32 oui_type)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
const u8 *end, *pos, *ie;
|
||||
const struct element *elem, *found = NULL;
|
||||
|
||||
pos = ies;
|
||||
end = ies + ies_len;
|
||||
ie = NULL;
|
||||
|
||||
while (end - pos > 1) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
return NULL;
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||
WPA_GET_BE32(&pos[2]) == oui_type) {
|
||||
ie = pos;
|
||||
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
|
||||
if (elem->datalen >= 4 &&
|
||||
WPA_GET_BE32(elem->data) == oui_type) {
|
||||
found = elem;
|
||||
break;
|
||||
}
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
if (ie == NULL)
|
||||
if (!found)
|
||||
return NULL; /* No specified vendor IE found */
|
||||
|
||||
buf = wpabuf_alloc(ies_len);
|
||||
@ -587,13 +577,9 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
* There may be multiple vendor IEs in the message, so need to
|
||||
* concatenate their data fields.
|
||||
*/
|
||||
while (end - pos > 1) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||
WPA_GET_BE32(&pos[2]) == oui_type)
|
||||
wpabuf_put_data(buf, pos + 6, pos[1] - 4);
|
||||
pos += 2 + pos[1];
|
||||
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
|
||||
if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
|
||||
wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
|
||||
}
|
||||
|
||||
return buf;
|
||||
@ -896,6 +882,41 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
}
|
||||
|
||||
|
||||
int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
|
||||
int sec_channel, u8 *op_class, u8 *channel)
|
||||
{
|
||||
int vht = CHAN_WIDTH_UNKNOWN;
|
||||
|
||||
switch (chanwidth) {
|
||||
case CHAN_WIDTH_UNKNOWN:
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
case CHAN_WIDTH_20:
|
||||
case CHAN_WIDTH_40:
|
||||
vht = VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
case CHAN_WIDTH_80:
|
||||
vht = VHT_CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_80P80:
|
||||
vht = VHT_CHANWIDTH_80P80MHZ;
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
vht = VHT_CHANWIDTH_160MHZ;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
|
||||
channel) == NUM_HOSTAPD_MODES) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
|
||||
freq, chanwidth, sec_channel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *const us_op_class_cc[] = {
|
||||
"US", "CA", NULL
|
||||
};
|
||||
@ -1297,27 +1318,27 @@ const char * fc2str(u16 fc)
|
||||
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
size_t ies_len)
|
||||
{
|
||||
const struct element *elem;
|
||||
|
||||
os_memset(info, 0, sizeof(*info));
|
||||
|
||||
while (ies_buf && ies_len >= 2 &&
|
||||
info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
|
||||
size_t len = 2 + ies_buf[1];
|
||||
if (!ies_buf)
|
||||
return 0;
|
||||
|
||||
if (len > ies_len) {
|
||||
wpa_hexdump(MSG_DEBUG, "Truncated IEs",
|
||||
ies_buf, ies_len);
|
||||
return -1;
|
||||
}
|
||||
for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
|
||||
if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
|
||||
return 0;
|
||||
|
||||
if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
|
||||
wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
|
||||
info->ies[info->nof_ies].ie = ies_buf + 2;
|
||||
info->ies[info->nof_ies].ie_len = ies_buf[1];
|
||||
info->nof_ies++;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
|
||||
elem->datalen + 2);
|
||||
info->ies[info->nof_ies].ie = elem->data;
|
||||
info->ies[info->nof_ies].ie_len = elem->datalen;
|
||||
info->nof_ies++;
|
||||
}
|
||||
|
||||
ies_len -= len;
|
||||
ies_buf += len;
|
||||
if (!for_each_element_completed(elem, ies_buf, ies_len)) {
|
||||
wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1440,22 +1461,13 @@ size_t global_op_class_size = ARRAY_SIZE(global_op_class);
|
||||
*/
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
{
|
||||
const u8 *end;
|
||||
const struct element *elem;
|
||||
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
end = ies + len;
|
||||
|
||||
while (end - ies > 1) {
|
||||
if (2 + ies[1] > end - ies)
|
||||
break;
|
||||
|
||||
if (ies[0] == eid)
|
||||
return ies;
|
||||
|
||||
ies += 2 + ies[1];
|
||||
}
|
||||
for_each_element_id(elem, eid, ies, len)
|
||||
return &elem->id;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -1473,22 +1485,26 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
*/
|
||||
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
|
||||
{
|
||||
const u8 *end;
|
||||
const struct element *elem;
|
||||
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
end = ies + len;
|
||||
for_each_element_extid(elem, ext, ies, len)
|
||||
return &elem->id;
|
||||
|
||||
while (end - ies > 1) {
|
||||
if (2 + ies[1] > end - ies)
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ies[0] == WLAN_EID_EXTENSION && ies[1] >= 1 &&
|
||||
ies[2] == ext)
|
||||
return ies;
|
||||
|
||||
ies += 2 + ies[1];
|
||||
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
|
||||
{
|
||||
const struct element *elem;
|
||||
|
||||
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
|
||||
if (elem->datalen >= 4 &&
|
||||
vendor_type == WPA_GET_BE32(elem->data))
|
||||
return &elem->id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -1519,6 +1535,26 @@ size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||
}
|
||||
|
||||
|
||||
size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value)
|
||||
{
|
||||
u8 *pos = buf;
|
||||
|
||||
if (len < 9)
|
||||
return 0;
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = 7; /* len */
|
||||
WPA_PUT_BE24(pos, OUI_WFA);
|
||||
pos += 3;
|
||||
*pos++ = MULTI_AP_OUI_TYPE;
|
||||
*pos++ = MULTI_AP_SUB_ELEM_TYPE;
|
||||
*pos++ = 1; /* len */
|
||||
*pos++ = value;
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
static const struct country_op_class us_op_class[] = {
|
||||
{ 1, 115 },
|
||||
{ 2, 118 },
|
||||
@ -1664,6 +1700,27 @@ const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
|
||||
}
|
||||
|
||||
|
||||
int oper_class_bw_to_int(const struct oper_class_map *map)
|
||||
{
|
||||
switch (map->bw) {
|
||||
case BW20:
|
||||
return 20;
|
||||
case BW40PLUS:
|
||||
case BW40MINUS:
|
||||
return 40;
|
||||
case BW80:
|
||||
return 80;
|
||||
case BW80P80:
|
||||
case BW160:
|
||||
return 160;
|
||||
case BW2160:
|
||||
return 2160;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len)
|
||||
{
|
||||
@ -1764,3 +1821,11 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
|
||||
return nei_pos - nei_rep;
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
|
||||
{
|
||||
if (!ie || ie[1] <= capab / 8)
|
||||
return 0;
|
||||
return !!(ie[2 + capab / 8] & BIT(capab % 8));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -10,6 +10,13 @@
|
||||
#define IEEE802_11_COMMON_H
|
||||
|
||||
#include "defs.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
|
||||
struct element {
|
||||
u8 id;
|
||||
u8 datalen;
|
||||
u8 data[];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct hostapd_hw_modes;
|
||||
|
||||
@ -84,6 +91,9 @@ struct ieee802_11_elems {
|
||||
const u8 *power_capab;
|
||||
const u8 *roaming_cons_sel;
|
||||
const u8 *password_id;
|
||||
const u8 *oci;
|
||||
const u8 *multi_ap;
|
||||
const u8 *he_capabilities;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
@ -130,6 +140,9 @@ struct ieee802_11_elems {
|
||||
u8 power_capab_len;
|
||||
u8 roaming_cons_sel_len;
|
||||
u8 password_id_len;
|
||||
u8 oci_len;
|
||||
u8 multi_ap_len;
|
||||
u8 he_capabilities_len;
|
||||
|
||||
struct mb_ies_info mb_ies;
|
||||
};
|
||||
@ -160,6 +173,8 @@ int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
|
||||
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel);
|
||||
int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
|
||||
int sec_channel, u8 *op_class, u8 *channel);
|
||||
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
|
||||
u16 num_modes);
|
||||
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
|
||||
@ -186,9 +201,12 @@ extern size_t global_op_class_size;
|
||||
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
||||
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
|
||||
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
||||
|
||||
size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value);
|
||||
|
||||
struct country_op_class {
|
||||
u8 country_op_class;
|
||||
u8 global_op_class;
|
||||
@ -197,8 +215,58 @@ struct country_op_class {
|
||||
u8 country_to_global_op_class(const char *country, u8 op_class);
|
||||
|
||||
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
|
||||
int oper_class_bw_to_int(const struct oper_class_map *map);
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len);
|
||||
|
||||
int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
|
||||
|
||||
/* element iteration helpers */
|
||||
#define for_each_element(_elem, _data, _datalen) \
|
||||
for (_elem = (const struct element *) (_data); \
|
||||
(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
|
||||
(int) sizeof(*_elem) && \
|
||||
(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
|
||||
(int) sizeof(*_elem) + _elem->datalen; \
|
||||
_elem = (const struct element *) (_elem->data + _elem->datalen))
|
||||
|
||||
#define for_each_element_id(element, _id, data, datalen) \
|
||||
for_each_element(element, data, datalen) \
|
||||
if (element->id == (_id))
|
||||
|
||||
#define for_each_element_extid(element, extid, _data, _datalen) \
|
||||
for_each_element(element, _data, _datalen) \
|
||||
if (element->id == WLAN_EID_EXTENSION && \
|
||||
element->datalen > 0 && \
|
||||
element->data[0] == (extid))
|
||||
|
||||
#define for_each_subelement(sub, element) \
|
||||
for_each_element(sub, (element)->data, (element)->datalen)
|
||||
|
||||
#define for_each_subelement_id(sub, id, element) \
|
||||
for_each_element_id(sub, id, (element)->data, (element)->datalen)
|
||||
|
||||
#define for_each_subelement_extid(sub, extid, element) \
|
||||
for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
|
||||
|
||||
/**
|
||||
* for_each_element_completed - Determine if element parsing consumed all data
|
||||
* @element: Element pointer after for_each_element() or friends
|
||||
* @data: Same data pointer as passed to for_each_element() or friends
|
||||
* @datalen: Same data length as passed to for_each_element() or friends
|
||||
*
|
||||
* This function returns 1 if all the data was parsed or considered
|
||||
* while walking the elements. Only use this if your for_each_element()
|
||||
* loop cannot be broken out of, otherwise it always returns 0.
|
||||
*
|
||||
* If some data was malformed, this returns %false since the last parsed
|
||||
* element will not fill the whole remaining data.
|
||||
*/
|
||||
static inline int for_each_element_completed(const struct element *element,
|
||||
const void *data, size_t datalen)
|
||||
{
|
||||
return (const u8 *) element == (const u8 *) data + datalen;
|
||||
}
|
||||
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IEEE 802.11 Frame type definitions
|
||||
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
@ -334,7 +334,7 @@
|
||||
#define WLAN_EID_LOCATION_PARAMETERS 82
|
||||
#define WLAN_EID_NONTRANSMITTED_BSSID_CAPA 83
|
||||
#define WLAN_EID_SSID_LIST 84
|
||||
#define WLAN_EID_MLTIPLE_BSSID_INDEX 85
|
||||
#define WLAN_EID_MULTIPLE_BSSID_INDEX 85
|
||||
#define WLAN_EID_FMS_DESCRIPTOR 86
|
||||
#define WLAN_EID_FMS_REQUEST 87
|
||||
#define WLAN_EID_FMS_RESPONSE 88
|
||||
@ -467,7 +467,89 @@
|
||||
#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
|
||||
#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_OCV_OCI 54
|
||||
|
||||
/* Extended Capabilities field */
|
||||
#define WLAN_EXT_CAPAB_20_40_COEX 0
|
||||
#define WLAN_EXT_CAPAB_GLK 1
|
||||
#define WLAN_EXT_CAPAB_EXT_CHAN_SWITCH 2
|
||||
#define WLAN_EXT_CAPAB_GLK_GCR 3
|
||||
#define WLAN_EXT_CAPAB_PSMP 4
|
||||
/* 5 - Reserved */
|
||||
#define WLAN_EXT_CAPAB_S_PSMP 6
|
||||
#define WLAN_EXT_CAPAB_EVENT 7
|
||||
#define WLAN_EXT_CAPAB_DIAGNOSTICS 8
|
||||
#define WLAN_EXT_CAPAB_MULTICAST_DIAGNOSTICS 9
|
||||
#define WLAN_EXT_CAPAB_LOCATION_TRACKING 10
|
||||
#define WLAN_EXT_CAPAB_FMS 11
|
||||
#define WLAN_EXT_CAPAB_PROXY_ARP 12
|
||||
#define WLAN_EXT_CAPAB_COLL_INTERF_REP 13
|
||||
#define WLAN_EXT_CAPAB_CIVIC_LOCATION 14
|
||||
#define WLAN_EXT_CAPAB_GEOSPATIAL_LOCATION 15
|
||||
#define WLAN_EXT_CAPAB_TFS 16
|
||||
#define WLAN_EXT_CAPAB_WNM_SLEEP_MODE 17
|
||||
#define WLAN_EXT_CAPAB_TIM_BROADCAST 18
|
||||
#define WLAN_EXT_CAPAB_BSS_TRANSITION 19
|
||||
#define WLAN_EXT_CAPAB_QOS_TRAFFIC 20
|
||||
#define WLAN_EXT_CAPAB_AC_STA_COUNT 21
|
||||
#define WLAN_EXT_CAPAB_MULTIPLE_BSSID 22
|
||||
#define WLAN_EXT_CAPAB_TIMING_MEASUREMENT 23
|
||||
#define WLAN_EXT_CAPAB_CHANNEL_USAGE 24
|
||||
#define WLAN_EXT_CAPAB_SSID_LIST 25
|
||||
#define WLAN_EXT_CAPAB_DMS 26
|
||||
#define WLAN_EXT_CAPAB_UTF_TSF_OFFSET 27
|
||||
#define WLAN_EXT_CAPAB_TPU_BUFFER_STA 28
|
||||
#define WLAN_EXT_CAPAB_TDLS_PEER_PSM 29
|
||||
#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH 30
|
||||
#define WLAN_EXT_CAPAB_INTERWORKING 31
|
||||
#define WLAN_EXT_CAPAB_QOS_MAP 32
|
||||
#define WLAN_EXT_CAPAB_EBR 33
|
||||
#define WLAN_EXT_CAPAB_SSPN_INTERFACE 34
|
||||
/* 35 - Reserved */
|
||||
#define WLAN_EXT_CAPAB_MSGCF 36
|
||||
#define WLAN_EXT_CAPAB_TDLS 37
|
||||
#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
|
||||
#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
|
||||
#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
|
||||
#define WLAN_EXT_CAPAB_
|
||||
/* 41-43 - Service Interval Granularity */
|
||||
#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
|
||||
#define WLAN_EXT_CAPAB_U_APSD_COEX 45
|
||||
#define WLAN_EXT_CAPAB_WNM_NOTIFCATION 46
|
||||
#define WLAN_EXT_CAPAB_QAB 47
|
||||
#define WLAN_EXT_CAPAB_UTF_8_SSID 48
|
||||
#define WLAN_EXT_CAPAB_QMF 49
|
||||
#define WLAN_EXT_CAPAB_QMF_RECONFIG 50
|
||||
#define WLAN_EXT_CAPAB_ROBUST_AV_STREAMING 51
|
||||
#define WLAN_EXT_CAPAB_ADVANCED_GCR 52
|
||||
#define WLAN_EXT_CAPAB_MESH_GCR 53
|
||||
#define WLAN_EXT_CAPAB_SCS 54
|
||||
#define WLAN_EXT_CAPAB_QLOAD_REPORT 55
|
||||
#define WLAN_EXT_CAPAB_ALT_EDCA 56
|
||||
#define WLAN_EXT_CAPAB_UNPROT_TXOP_NEG 57
|
||||
#define WLAN_EXT_CAPAB_PROT_TXOP_NEG 58
|
||||
/* 59 - Reserved */
|
||||
#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
|
||||
#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
|
||||
#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
|
||||
#define WLAN_EXT_CAPAB_
|
||||
/* 63-64 - Max Number of MSDUs In A-MSDU */
|
||||
#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
|
||||
#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
|
||||
#define WLAN_EXT_CAPAB_NETWORK_CHANNEL_CTRL 67
|
||||
#define WLAN_EXT_CAPAB_WHITE_SPACE_MAP 68
|
||||
#define WLAN_EXT_CAPAB_CHANNEL_AVAIL_QUERY 69
|
||||
#define WLAN_EXT_CAPAB_FTM_RESPONDER 70
|
||||
#define WLAN_EXT_CAPAB_FTM_INITIATOR 71
|
||||
#define WLAN_EXT_CAPAB_FILS 72
|
||||
#define WLAN_EXT_CAPAB_EXT_SPECTRUM_MGMT 73
|
||||
#define WLAN_EXT_CAPAB_FUTURE_CHANNEL_GUIDANCE 74
|
||||
#define WLAN_EXT_CAPAB_PAD 75
|
||||
/* 76-79 - Reserved */
|
||||
#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
|
||||
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
|
||||
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
|
||||
|
||||
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
|
||||
#define WLAN_ACTION_SPECTRUM_MGMT 0
|
||||
@ -865,10 +947,12 @@ struct ieee80211_mgmt {
|
||||
struct {
|
||||
u8 action;
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
u8 variable[]; /* OCI element */
|
||||
} STRUCT_PACKED sa_query_req;
|
||||
struct {
|
||||
u8 action; /* */
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
u8 variable[]; /* OCI element */
|
||||
} STRUCT_PACKED sa_query_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
@ -1210,6 +1294,13 @@ struct ieee80211_ampe_ie {
|
||||
#define MBO_OUI_TYPE 22
|
||||
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
|
||||
#define OWE_OUI_TYPE 28
|
||||
#define MULTI_AP_OUI_TYPE 0x1B
|
||||
|
||||
#define MULTI_AP_SUB_ELEM_TYPE 0x06
|
||||
#define MULTI_AP_TEAR_DOWN BIT(4)
|
||||
#define MULTI_AP_FRONTHAUL_BSS BIT(5)
|
||||
#define MULTI_AP_BACKHAUL_BSS BIT(6)
|
||||
#define MULTI_AP_BACKHAUL_STA BIT(7)
|
||||
|
||||
#define WMM_OUI_TYPE 2
|
||||
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
@ -1347,13 +1438,15 @@ enum wmm_ac {
|
||||
#define HS20_PPS_MO_ID_PRESENT 0x02
|
||||
#define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
|
||||
#ifndef HS20_VERSION
|
||||
#define HS20_VERSION 0x10 /* Release 2 */
|
||||
#define HS20_VERSION 0x20 /* Release 3 */
|
||||
#endif /* HS20_VERSION */
|
||||
|
||||
/* WNM-Notification WFA vendors specific subtypes */
|
||||
#define HS20_WNM_SUB_REM_NEEDED 0
|
||||
#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
|
||||
#define HS20_WNM_T_C_ACCEPTANCE 2
|
||||
#define WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT 2
|
||||
#define WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA 3
|
||||
#define HS20_WNM_T_C_ACCEPTANCE 4
|
||||
|
||||
#define HS20_DEAUTH_REASON_CODE_BSS 0
|
||||
#define HS20_DEAUTH_REASON_CODE_ESS 1
|
||||
@ -1442,12 +1535,6 @@ enum mbo_transition_reject_reason {
|
||||
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */
|
||||
enum wfa_wnm_notif_subelem_id {
|
||||
WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2,
|
||||
WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r27, 4.3: MBO ANQP-elements */
|
||||
#define MBO_ANQP_OUI_TYPE 0x12
|
||||
#define MBO_ANQP_SUBTYPE_QUERY_LIST 1
|
||||
@ -1841,11 +1928,14 @@ enum beacon_report_mode {
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
|
||||
* Beacon request */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_SSID 0
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164
|
||||
#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221
|
||||
|
||||
/*
|
||||
@ -1895,9 +1985,21 @@ struct rrm_measurement_beacon_report {
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
|
||||
* Beacon report */
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164
|
||||
#define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221
|
||||
|
||||
/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
|
||||
* Reported Frame Body Fragment ID subelement */
|
||||
#define REPORTED_FRAME_BODY_SUBELEM_LEN 4
|
||||
#define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7)
|
||||
|
||||
/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */
|
||||
#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3
|
||||
|
||||
/* IEEE Std 802.11ad-2012 - Multi-band element */
|
||||
struct multi_band_ie {
|
||||
u8 eid; /* WLAN_EID_MULTI_BAND */
|
||||
@ -2000,14 +2102,15 @@ enum nr_chan_width {
|
||||
};
|
||||
|
||||
struct ieee80211_he_capabilities {
|
||||
u8 he_mac_capab_info[5];
|
||||
u8 he_phy_capab_info[9];
|
||||
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) */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct ieee80211_he_operation {
|
||||
u32 he_oper_params;
|
||||
u32 he_oper_params; /* HE Operation Parameters[3] and
|
||||
* BSS Color Information[1] */
|
||||
u8 he_mcs_nss_set[2];
|
||||
u8 vht_op_info_chwidth;
|
||||
u8 vht_op_info_chan_center_freq_seg0_idx;
|
||||
@ -2024,28 +2127,55 @@ struct ieee80211_he_operation {
|
||||
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
|
||||
|
||||
/* 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_DFLT_PE_DURATION_MASK ((u32) (BIT(6) | BIT(7) | \
|
||||
BIT(8)))
|
||||
#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 6
|
||||
#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(9))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(10) | BIT(11) | \
|
||||
BIT(12) | BIT(13) | \
|
||||
#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)))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 10
|
||||
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(20))
|
||||
#define HE_OPERATION_MAX_BSSID_INDICATOR_MASK ((u32) (BIT(21) | BIT(22) | \
|
||||
BIT(23) | BIT(24) | \
|
||||
BIT(25) | BIT(26) | \
|
||||
BIT(27) | BIT(28)))
|
||||
#define HE_OPERATION_MAX_BSSID_INDICATOR_OFFSET 21
|
||||
#define HE_OPERATION_TX_BSSID_INDICATOR ((u32) BIT(29))
|
||||
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(30))
|
||||
#define HE_OPERATION_BSS_DUAL_BEACON ((u32) BIT(31))
|
||||
BIT(18) | BIT(19) | \
|
||||
BIT(20) | BIT(21)))
|
||||
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
|
||||
|
||||
struct ieee80211_he_mu_edca_parameter_set {
|
||||
u8 he_qos_info;
|
||||
u8 he_mu_ac_be_param[3];
|
||||
u8 he_mu_ac_bk_param[3];
|
||||
u8 he_mu_ac_vi_param[3];
|
||||
u8 he_mu_ac_vo_param[3];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* HE MU AC parameter record field format */
|
||||
/* ACI/AIFSN */
|
||||
#define HE_MU_AC_PARAM_ACI_IDX 0
|
||||
#define HE_MU_AC_PARAM_AIFSN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
|
||||
#define HE_MU_AC_PARAM_ACM ((u8) BIT(4))
|
||||
#define HE_MU_AC_PARAM_ACI ((u8) (BIT(5) | BIT(6)))
|
||||
/* B7: Reserved */
|
||||
|
||||
/* ECWmin/ECWmax */
|
||||
#define HE_MU_AC_PARAM_ECW_IDX 1
|
||||
#define HE_MU_AC_PARAM_ECWMIN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
|
||||
#define HE_MU_AC_PARAM_ECWMAX ((u8) (BIT(4) | BIT(5) | BIT(6) | BIT(7)))
|
||||
|
||||
/* MU EDCA Timer */
|
||||
#define HE_MU_AC_PARAM_TIMER_IDX 2
|
||||
|
||||
/* HE QoS Info field */
|
||||
#define HE_QOS_INFO_EDCA_PARAM_SET_COUNT ((u8) (BIT(0) | BIT(1) | \
|
||||
BIT(2) | BIT(3)))
|
||||
#define HE_QOS_INFO_Q_ACK ((u8) (BIT(4)))
|
||||
#define HE_QOS_INFO_QUEUE_REQUEST ((u8) (BIT(5)))
|
||||
#define HE_QOS_INFO_TXOP_REQUEST ((u8) (BIT(6)))
|
||||
/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
|
||||
#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
|
||||
|
||||
/* DPP Public Action frame identifiers - OUI_WFA */
|
||||
#define DPP_OUI_TYPE 0x1A
|
||||
|
172
contrib/wpa/src/common/ocv.c
Normal file
172
contrib/wpa/src/common/ocv.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Operating Channel Validation (OCV)
|
||||
* Copyright (c) 2018, Mathy Vanhoef
|
||||
*
|
||||
* 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 "drivers/driver.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "ocv.h"
|
||||
|
||||
/**
|
||||
* Caller of OCV functionality may use various debug output functions, so store
|
||||
* the error here and let the caller use an appropriate debug output function.
|
||||
*/
|
||||
char ocv_errorstr[256];
|
||||
|
||||
|
||||
int ocv_derive_all_parameters(struct oci_info *oci)
|
||||
{
|
||||
const struct oper_class_map *op_class_map;
|
||||
|
||||
oci->freq = ieee80211_chan_to_freq(NULL, oci->op_class, oci->channel);
|
||||
if (oci->freq < 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Error interpreting OCI: unrecognized opclass/channel pair (%d/%d)",
|
||||
oci->op_class, oci->channel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
op_class_map = get_oper_class(NULL, oci->op_class);
|
||||
if (!op_class_map) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Error interpreting OCI: Unrecognized opclass (%d)",
|
||||
oci->op_class);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oci->chanwidth = oper_class_bw_to_int(op_class_map);
|
||||
oci->sec_channel = 0;
|
||||
if (op_class_map->bw == BW40PLUS)
|
||||
oci->sec_channel = 1;
|
||||
else if (op_class_map->bw == BW40MINUS)
|
||||
oci->sec_channel = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos)
|
||||
{
|
||||
u8 op_class, channel;
|
||||
u8 *pos = *argpos;
|
||||
|
||||
if (ieee80211_chaninfo_to_channel(ci->frequency, ci->chanwidth,
|
||||
ci->sec_channel,
|
||||
&op_class, &channel) < 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"Cannot determine operating class and channel for OCI element");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pos++ = op_class;
|
||||
*pos++ = channel;
|
||||
*pos++ = ci->seg1_idx;
|
||||
|
||||
*argpos = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos)
|
||||
{
|
||||
u8 *pos = *argpos;
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = RSN_SELECTOR_LEN + 3;
|
||||
RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_OCI);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
|
||||
*argpos = pos;
|
||||
return ocv_insert_oci(ci, argpos);
|
||||
}
|
||||
|
||||
|
||||
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
|
||||
{
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + OCV_OCI_LEN;
|
||||
*pos++ = WLAN_EID_EXT_OCV_OCI;
|
||||
return ocv_insert_oci(ci, &pos);
|
||||
}
|
||||
|
||||
|
||||
int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx)
|
||||
{
|
||||
struct oci_info oci;
|
||||
|
||||
if (!oci_ie) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: did not receive mandatory OCI");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (oci_ie_len != 3) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: received OCI of unexpected length (%d)",
|
||||
(int) oci_ie_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&oci, 0, sizeof(oci));
|
||||
oci.op_class = oci_ie[0];
|
||||
oci.channel = oci_ie[1];
|
||||
oci.seg1_idx = oci_ie[2];
|
||||
if (ocv_derive_all_parameters(&oci) != 0) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: unable to interpret received OCI");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Primary frequency used to send frames to STA must match the STA's */
|
||||
if ((int) ci->frequency != oci.freq) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
ci->frequency, oci.freq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We shouldn't transmit with a higher bandwidth than the STA supports
|
||||
*/
|
||||
if (tx_chanwidth > oci.chanwidth) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
|
||||
tx_chanwidth, oci.chanwidth);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Secondary channel only needs be checked for 40 MHz in the 2.4 GHz
|
||||
* band. In the 5 GHz band it's verified through the primary frequency.
|
||||
* Note that the field ci->sec_channel is only filled in when we use
|
||||
* 40 MHz.
|
||||
*/
|
||||
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
|
||||
ci->sec_channel != oci.sec_channel) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
ci->sec_channel, oci.sec_channel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When using a 160 or 80+80 MHz channel to transmit, verify that we use
|
||||
* the same segments as the receiver by comparing frequency segment 1.
|
||||
*/
|
||||
if ((ci->chanwidth == CHAN_WIDTH_160 ||
|
||||
ci->chanwidth == CHAN_WIDTH_80P80) &&
|
||||
tx_seg1_idx != oci.seg1_idx) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
tx_seg1_idx, oci.seg1_idx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
40
contrib/wpa/src/common/ocv.h
Normal file
40
contrib/wpa/src/common/ocv.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Operating Channel Validation (OCV)
|
||||
* Copyright (c) 2018, Mathy Vanhoef
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef OCV_H
|
||||
#define OCV_H
|
||||
|
||||
struct wpa_channel_info;
|
||||
|
||||
struct oci_info {
|
||||
/* Values in the OCI element */
|
||||
u8 op_class;
|
||||
u8 channel;
|
||||
u8 seg1_idx;
|
||||
|
||||
/* Derived values for easier verification */
|
||||
int freq;
|
||||
int sec_channel;
|
||||
int chanwidth;
|
||||
};
|
||||
|
||||
#define OCV_OCI_LEN 3
|
||||
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
|
||||
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
|
||||
|
||||
extern char ocv_errorstr[256];
|
||||
|
||||
int ocv_derive_all_parameters(struct oci_info *oci);
|
||||
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
|
||||
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
|
||||
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
|
||||
int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx);
|
||||
|
||||
#endif /* OCV_H */
|
@ -42,8 +42,12 @@ enum qca_radiotap_vendor_ids {
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
|
||||
* ranges to avoid to reduce issues due to interference or internal
|
||||
* co-existence information in the driver. The event data structure is
|
||||
* defined in struct qca_avoid_freq_list.
|
||||
* co-existence information in the driver. These frequencies aim to
|
||||
* minimize the traffic but not to totally avoid the traffic. That said
|
||||
* for a P2P use case, these frequencies are allowed for the P2P
|
||||
* discovery/negotiation but avoid the group to get formed on these
|
||||
* frequencies. The event data structure is defined in
|
||||
* struct qca_avoid_freq_list.
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: Command to check driver support
|
||||
* for DFS offloading.
|
||||
@ -499,6 +503,27 @@ enum qca_radiotap_vendor_ids {
|
||||
*
|
||||
* Based on the config provided, FW will boost the weight and prioritize
|
||||
* the traffic for that subsystem (WLAN/BT/Zigbee).
|
||||
*
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS: This command is used to query
|
||||
* the supported AKM suite selectorss from the driver. It returns the list
|
||||
* of supported AKMs in the attribute NL80211_ATTR_AKM_SUITES.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE: This command is used to get firmware
|
||||
* state from the driver. It returns the firmware state in the attribute
|
||||
* QCA_WLAN_VENDOR_ATTR_FW_STATE.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH: This vendor subcommand
|
||||
* is used by the driver to flush per-peer cached statistics to user space
|
||||
* application. This interface is used as an event from the driver to
|
||||
* user space application. Attributes for this event are specified in
|
||||
* enum qca_wlan_vendor_attr_peer_stats_cache_params.
|
||||
* QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA attribute is expected to be
|
||||
* sent in the event.
|
||||
* @QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG: This sub command is used to
|
||||
* improve the success rate of Zigbee joining network.
|
||||
* Due to PTA master limitation, Zigbee joining network success rate is
|
||||
* low while WLAN is working. The WLAN driver needs to configure some
|
||||
* 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.
|
||||
*/
|
||||
enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
||||
@ -663,6 +688,10 @@ enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173,
|
||||
QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT = 174,
|
||||
QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG = 175,
|
||||
QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS = 176,
|
||||
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,
|
||||
};
|
||||
|
||||
enum qca_wlan_vendor_attr {
|
||||
@ -843,6 +872,18 @@ enum qca_wlan_vendor_attr {
|
||||
* to report the corresponding antenna index to the chain RSSI value
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO = 40,
|
||||
/* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command to report
|
||||
* the specific antenna EVM value (unsigned 32 bit value). With a
|
||||
* determinate group of antennas, the driver specifies the EVM value
|
||||
* for each antenna ID, and application extract them in user space.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_CHAIN_EVM = 41,
|
||||
/*
|
||||
* Used in QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE command to report
|
||||
* wlan firmware current state. FW state is an unsigned 8 bit value,
|
||||
* one of the values in enum qca_wlan_vendor_attr_fw_state.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_FW_STATE = 42,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
|
||||
@ -854,6 +895,49 @@ enum qca_roaming_policy {
|
||||
QCA_ROAMING_ALLOWED_WITHIN_ESS,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_roam_reason - Represents the reason codes for roaming. Used by
|
||||
* QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON.
|
||||
*
|
||||
* @QCA_ROAM_REASON_UNKNOWN: Any reason that do not classify under the below
|
||||
* reasons.
|
||||
*
|
||||
* @QCA_ROAM_REASON_PER: Roam triggered when packet error rates (PER) breached
|
||||
* the configured threshold.
|
||||
*
|
||||
* @QCA_ROAM_REASON_BEACON_MISS: Roam triggered due to the continuous configured
|
||||
* beacon misses from the then connected AP.
|
||||
*
|
||||
* @QCA_ROAM_REASON_POOR_RSSI: Roam triggered due to the poor RSSI reported
|
||||
* by the connected AP.
|
||||
*
|
||||
* @QCA_ROAM_REASON_BETTER_RSSI: Roam triggered for finding a BSS with a better
|
||||
* RSSI than the connected BSS. Here the RSSI of the current BSS is not poor.
|
||||
*
|
||||
* @QCA_ROAM_REASON_CONGESTION: Roam triggered considering the connected channel
|
||||
* or environment being very noisy or congested.
|
||||
*
|
||||
* @QCA_ROAM_REASON_EXPLICIT_REQUEST: Roam triggered due to an explicit request
|
||||
* from the user (user space).
|
||||
*
|
||||
* @QCA_ROAM_REASON_BTM: Roam triggered due to BTM Request frame received from
|
||||
* the connected AP.
|
||||
*
|
||||
* @QCA_ROAM_REASON_BSS_LOAD: Roam triggered due to the channel utilization
|
||||
* breaching out the configured threshold.
|
||||
*/
|
||||
enum qca_roam_reason {
|
||||
QCA_ROAM_REASON_UNKNOWN,
|
||||
QCA_ROAM_REASON_PER,
|
||||
QCA_ROAM_REASON_BEACON_MISS,
|
||||
QCA_ROAM_REASON_POOR_RSSI,
|
||||
QCA_ROAM_REASON_BETTER_RSSI,
|
||||
QCA_ROAM_REASON_CONGESTION,
|
||||
QCA_ROAM_REASON_USER_TRIGGER,
|
||||
QCA_ROAM_REASON_BTM,
|
||||
QCA_ROAM_REASON_BSS_LOAD,
|
||||
};
|
||||
|
||||
enum qca_wlan_vendor_attr_roam_auth {
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
|
||||
@ -896,6 +980,11 @@ enum qca_wlan_vendor_attr_roam_auth {
|
||||
* doing subsequent ERP based connections in the same realm.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM = 13,
|
||||
/* A 16-bit unsigned value representing the reasons for the roaming.
|
||||
* Defined by enum qca_roam_reason.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON = 14,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
|
||||
@ -994,6 +1083,7 @@ enum qca_wlan_vendor_acs_hw_mode {
|
||||
* only OCE STA-CFON functionalities.
|
||||
* @QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY: Device supports self
|
||||
* managed regulatory.
|
||||
* @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time).
|
||||
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
|
||||
*/
|
||||
enum qca_wlan_vendor_features {
|
||||
@ -1005,6 +1095,7 @@ enum qca_wlan_vendor_features {
|
||||
QCA_WLAN_VENDOR_FEATURE_OCE_AP = 5,
|
||||
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
|
||||
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
|
||||
QCA_WLAN_VENDOR_FEATURE_TWT = 8,
|
||||
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
|
||||
};
|
||||
|
||||
@ -2437,6 +2528,18 @@ enum qca_wlan_vendor_attr_dmg_rf_sector_type {
|
||||
QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_fw_state - State of firmware
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR: FW is in bad state
|
||||
* @QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE: FW is active
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_fw_state {
|
||||
QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR,
|
||||
QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE,
|
||||
QCA_WLAN_VENDOR_ATTR_FW_STATE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* BRP antenna limit mode
|
||||
*
|
||||
@ -3181,6 +3284,8 @@ enum qca_wlan_vendor_attr_roaming_config_params {
|
||||
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
|
||||
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
|
||||
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
|
||||
/* Flag attribute indicates this BSSID blacklist as a hint */
|
||||
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT = 21,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
|
||||
@ -4433,6 +4538,27 @@ enum qca_wlan_vendor_attr_spectral_cap {
|
||||
* qca_wlan_vendor_spectral_scan_cap_hw_gen.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN = 5,
|
||||
/* Spectral bin scaling formula ID. u16 attribute.
|
||||
* It uses values defined in enum
|
||||
* qca_wlan_vendor_spectral_scan_cap_formula_id.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID = 6,
|
||||
/* Spectral bin scaling param - low level offset.
|
||||
* s16 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_LOW_LEVEL_OFFSET = 7,
|
||||
/* Spectral bin scaling param - high level offset.
|
||||
* s16 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HIGH_LEVEL_OFFSET = 8,
|
||||
/* Spectral bin scaling param - RSSI threshold.
|
||||
* s16 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RSSI_THR = 9,
|
||||
/* Spectral bin scaling param - default AGC max gain.
|
||||
* u8 attribute.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
|
||||
@ -4577,6 +4703,20 @@ enum qca_wlan_vendor_attr_flush_pending {
|
||||
QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* qca_wlan_vendor_spectral_scan_cap_formula_id: Attribute values for
|
||||
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID in the vendor subcmd
|
||||
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
|
||||
* Spectral bin scaling formula ID.
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING: No scaling
|
||||
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED: AGC gain
|
||||
* and RSSI threshold based formula.
|
||||
*/
|
||||
enum qca_wlan_vendor_spectral_scan_cap_formula_id {
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING = 0,
|
||||
QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_rropavail_info - Specifies whether Representative
|
||||
* RF Operating Parameter (RROP) information is available, and if so, at which
|
||||
@ -4836,6 +4976,10 @@ enum qca_wlan_vendor_attr_offloaded_packets {
|
||||
QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
|
||||
/* Unsigned 32-bit value, in milli seconds */
|
||||
QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
|
||||
/* This optional unsigned 16-bit attribute is used for specifying
|
||||
* ethernet protocol type. If not specified ethertype defaults to IPv4.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST,
|
||||
@ -5457,6 +5601,54 @@ enum qca_wlan_he_om_ctrl_ch_bw {
|
||||
QCA_WLAN_HE_OM_CTRL_BW_160M = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
|
||||
* HE operating mode control transmit request. These attributes are
|
||||
* sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
|
||||
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value
|
||||
* indicates the maximum number of spatial streams, NSS, that the STA
|
||||
* supports in reception for PPDU bandwidths less than or equal to 80 MHz
|
||||
* and is set to NSS - 1.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW: Mandatory 8-bit unsigned value
|
||||
* indicates the operating channel width supported by the STA for both
|
||||
* reception and transmission. Uses enum qca_wlan_he_om_ctrl_ch_bw values.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE: Mandatory 8-bit unsigned value
|
||||
* indicates the all trigger based UL MU operations by the STA.
|
||||
* 0 - UL MU operations are enabled by the STA.
|
||||
* 1 - All triggered UL MU transmissions are suspended by the STA.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS: Mandatory 8-bit unsigned value
|
||||
* indicates the maximum number of space-time streams, NSTS, that
|
||||
* the STA supports in transmission and is set to NSTS - 1.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE: 8-bit unsigned value
|
||||
* combined with the UL MU Disable subfield and the recipient's setting
|
||||
* of the OM Control UL MU Data Disable RX Support subfield in the HE MAC
|
||||
* capabilities to determine which HE TB PPDUs are possible by the
|
||||
* STA to transmit.
|
||||
* 0 - UL MU data operations are enabled by the STA.
|
||||
* 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable
|
||||
* bit is not set, else UL MU Tx is suspended.
|
||||
*
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_he_omi_tx {
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/* Attributes for data used by
|
||||
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
|
||||
*/
|
||||
@ -5703,6 +5895,43 @@ enum qca_wlan_vendor_attr_wifi_test_config {
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU = 32,
|
||||
|
||||
/* Nested attribute to indicate HE operating mode control field
|
||||
* transmission. It contains operating mode control field Nss,
|
||||
* channel bandwidth, Tx Nsts and UL MU disable attributes.
|
||||
* These nested attributes are used to send HE operating mode control
|
||||
* with configured values.
|
||||
* Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes.
|
||||
* This attribute is used to configure the testbed device.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33,
|
||||
|
||||
/* 8-bit unsigned value to configure +HTC_HE support to indicate the
|
||||
* support for the reception of a frame that carries an HE variant
|
||||
* HT Control field.
|
||||
* This attribute is used to configure the testbed device.
|
||||
* 1-enable, 0-disable
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP = 34,
|
||||
|
||||
/* 8-bit unsigned value to configure VHT support in 2.4G band.
|
||||
* This attribute is used to configure the testbed device.
|
||||
* 1-enable, 0-disable
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_2G_VHT = 35,
|
||||
|
||||
/* 8-bit unsigned value to configure HE testbed defaults.
|
||||
* This attribute is used to configure the testbed device.
|
||||
* 1-set the device HE capabilities to testbed defaults.
|
||||
* 0-reset the device HE capabilities to supported config.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_HE_TESTBED_DEFAULTS = 36,
|
||||
|
||||
/* 8-bit unsigned value to configure TWT request support.
|
||||
* This attribute is used to configure the testbed device.
|
||||
* 1-enable, 0-disable.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT = 37,
|
||||
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
|
||||
@ -6185,13 +6414,35 @@ enum qca_coex_config_profiles {
|
||||
QCA_WIFI_SAP_CLASS_3_MGMT = 7,
|
||||
QCA_WIFI_SAP_DATA = 8,
|
||||
QCA_WIFI_SAP_ALL = 9,
|
||||
QCA_WIFI_CASE_MAX = 31,
|
||||
/* 32 - 63 corresponds to BT */
|
||||
QCA_BT_A2DP = 32,
|
||||
QCA_BT_BLE = 33,
|
||||
QCA_BT_SCO = 34,
|
||||
QCA_BT_CASE_MAX = 63,
|
||||
/* 64 - 95 corresponds to Zigbee */
|
||||
QCA_ZB_LOW = 64,
|
||||
QCA_ZB_HIGH = 65
|
||||
QCA_ZB_HIGH = 65,
|
||||
QCA_ZB_CASE_MAX = 95,
|
||||
/* 0xff is default value if the u8 profile value is not set. */
|
||||
QCA_COEX_CONFIG_PROFILE_DEFAULT_VALUE = 255
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_coex_config_types - Coex configurations types.
|
||||
* This enum defines the valid set of values of coex configuration types. These
|
||||
* values may used by attribute
|
||||
* %QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET: Reset all the
|
||||
* weights to default values.
|
||||
* @QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START: Start to config
|
||||
* weights with configurability value.
|
||||
*/
|
||||
enum qca_vendor_attr_coex_config_types {
|
||||
QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
|
||||
QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET = 1,
|
||||
QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -6222,6 +6473,80 @@ enum qca_vendor_attr_coex_config {
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_coex_config_three_way - Specifies vendor coex config
|
||||
* attributes
|
||||
* Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG
|
||||
*
|
||||
* QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE: u32 attribute.
|
||||
* Indicate config type.
|
||||
* The config types are 32-bit values from qca_vendor_attr_coex_config_types
|
||||
*
|
||||
* @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1: u32 attribute.
|
||||
* Indicate the Priority 1 profiles.
|
||||
* The profiles are 8-bit values from enum qca_coex_config_profiles.
|
||||
* In same priority level, maximum to 4 profiles can be set here.
|
||||
* @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2: u32 attribute.
|
||||
* Indicate the Priority 2 profiles.
|
||||
* The profiles are 8-bit values from enum qca_coex_config_profiles.
|
||||
* In same priority level, maximum to 4 profiles can be set here.
|
||||
* @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3: u32 attribute.
|
||||
* Indicate the Priority 3 profiles.
|
||||
* The profiles are 8-bit values from enum qca_coex_config_profiles.
|
||||
* In same priority level, maximum to 4 profiles can be set here.
|
||||
* @QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4: u32 attribute.
|
||||
* Indicate the Priority 4 profiles.
|
||||
* The profiles are 8-bit values from enum qca_coex_config_profiles.
|
||||
* In same priority level, maximum to 4 profiles can be set here.
|
||||
* NOTE:
|
||||
* Limitations for QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_x priority
|
||||
* arrangement:
|
||||
* 1: In the same u32 attribute (priority x), the profiles enum values own
|
||||
* same priority level.
|
||||
* 2: 0xff is default value if the u8 profile value is not set.
|
||||
* 3: max to 4 rules/profiles in same priority level.
|
||||
* 4: max to 4 priority level (priority 1 - priority 4)
|
||||
* 5: one priority level only supports one scenario from WLAN/BT/ZB,
|
||||
* hybrid rules not support.
|
||||
* 6: if WMI_COEX_CONFIG_THREE_WAY_COEX_RESET called, priority x will
|
||||
* remain blank to reset all parameters.
|
||||
* For example:
|
||||
*
|
||||
* If the attributes as follow:
|
||||
* priority 1:
|
||||
* ------------------------------------
|
||||
* | 0xff | 0 | 1 | 2 |
|
||||
* ------------------------------------
|
||||
* priority 2:
|
||||
* -------------------------------------
|
||||
* | 0xff | 0xff | 0xff | 32 |
|
||||
* -------------------------------------
|
||||
* priority 3:
|
||||
* -------------------------------------
|
||||
* | 0xff | 0xff | 0xff | 65 |
|
||||
* -------------------------------------
|
||||
* then it means:
|
||||
* 1: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
|
||||
* owns same priority level.
|
||||
* 2: WIFI_STA_DISCOVERY, WIFI_STA_CLASS_3_MGMT and WIFI_STA_CONNECTION
|
||||
* has priority over BT_A2DP and ZB_HIGH.
|
||||
* 3: BT_A2DP has priority over ZB_HIGH.
|
||||
*/
|
||||
|
||||
enum qca_vendor_attr_coex_config_three_way {
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_INVALID = 0,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE = 1,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1 = 2,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2 = 3,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3 = 4,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4 = 5,
|
||||
|
||||
/* Keep last */
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST,
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX =
|
||||
QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_link_properties - Represent the link properties.
|
||||
*
|
||||
@ -6244,4 +6569,144 @@ enum qca_wlan_vendor_attr_link_properties {
|
||||
QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_vendor_attr_peer_stats_cache_type - Represents peer stats cache type
|
||||
* This enum defines the valid set of values of peer stats cache types. These
|
||||
* values are used by attribute
|
||||
* %QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS: Represents peer TX rate statistics
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS: Represents peer RX rate statistics
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS: Represents peer TX sojourn
|
||||
* statistics
|
||||
*/
|
||||
enum qca_vendor_attr_peer_stats_cache_type {
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE_INVALID = 0,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_TX_RATE_STATS,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_RX_RATE_STATS,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_TX_SOJOURN_STATS,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_wlan_vendor_attr_peer_stats_cache_params - This enum defines
|
||||
* attributes required for QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH
|
||||
* Information in these attributes is used to flush peer rate statistics from
|
||||
* the driver to user application.
|
||||
*
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE: Unsigned 32-bit attribute
|
||||
* Indicate peer statistics cache type.
|
||||
* The statistics types are 32-bit values from
|
||||
* enum qca_vendor_attr_peer_stats_cache_type.
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC: Unsigned 8-bit array
|
||||
* of size 6 octets, representing the peer MAC address.
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA: Opaque data attribute
|
||||
* containing buffer of statistics to send to application layer entity.
|
||||
* @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE: Unsigned 64-bit attribute
|
||||
* representing a cookie for peer unique session.
|
||||
*/
|
||||
enum qca_wlan_vendor_attr_peer_stats_cache_params {
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_INVALID = 0,
|
||||
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_TYPE = 1,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC = 2,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA = 3,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE = 4,
|
||||
|
||||
/* Keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qca_mpta_helper_attr_zigbee_state - Current Zigbee state
|
||||
* This enum defines all the possible states of Zigbee, which can be
|
||||
* delivered in the QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE attribute.
|
||||
*
|
||||
* @ZIGBEE_IDLE: Zigbee in idle state
|
||||
* @ZIGBEE_FORM_NETWORK: Zigbee forming network
|
||||
* @ZIGBEE_WAIT_JOIN: Zigbee waiting for joining network
|
||||
* @ZIGBEE_JOIN: Zigbee joining network
|
||||
* @ZIGBEE_NETWORK_UP: Zigbee network is up
|
||||
* @ZIGBEE_HMI: Zigbee in HMI mode
|
||||
*/
|
||||
enum qca_mpta_helper_attr_zigbee_state {
|
||||
ZIGBEE_IDLE = 0,
|
||||
ZIGBEE_FORM_NETWORK = 1,
|
||||
ZIGBEE_WAIT_JOIN = 2,
|
||||
ZIGBEE_JOIN = 3,
|
||||
ZIGBEE_NETWORK_UP = 4,
|
||||
ZIGBEE_HMI = 5,
|
||||
};
|
||||
|
||||
/*
|
||||
* enum qca_mpta_helper_vendor_attr - Attributes used in vendor sub-command
|
||||
* QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG.
|
||||
*/
|
||||
enum qca_mpta_helper_vendor_attr {
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_INVALID = 0,
|
||||
/* Optional attribute used to update Zigbee state.
|
||||
* enum qca_mpta_helper_attr_zigbee_state.
|
||||
* NLA_U32 attribute.
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE = 1,
|
||||
/* Optional attribute used to configure WLAN duration for Shape-OCS
|
||||
* during interrupt.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION.
|
||||
* Value range 0 ~ 300 (ms).
|
||||
* NLA_U32 attribute.
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION = 2,
|
||||
/* Optional attribute used to configure non-WLAN duration for Shape-OCS
|
||||
* during interrupt.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION.
|
||||
* Value range 0 ~ 300 (ms).
|
||||
* NLA_U32 attribute.
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION = 3,
|
||||
/* Optional attribute used to configure WLAN duration for Shape-OCS
|
||||
* monitor period.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION.
|
||||
* Value range 0 ~ 300 (ms)
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION = 4,
|
||||
/* Optional attribute used to configure non-WLAN duration for Shape-OCS
|
||||
* monitor period.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION.
|
||||
* Value range 0 ~ 300 (ms)
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION = 5,
|
||||
/* Optional attribute used to configure OCS interrupt duration.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION.
|
||||
* Value range 1000 ~ 20000 (ms)
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION = 6,
|
||||
/* Optional attribute used to configure OCS monitor duration.
|
||||
* Set in pair with QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION.
|
||||
* Value range 1000 ~ 20000 (ms)
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION = 7,
|
||||
/* Optional attribute used to notify WLAN firmware the current Zigbee
|
||||
* channel.
|
||||
* Value range 11 ~ 26
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN = 8,
|
||||
/* Optional attribute used to configure WLAN mute duration.
|
||||
* Value range 0 ~ 400 (ms)
|
||||
* NLA_U32 attribute
|
||||
*/
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION = 9,
|
||||
|
||||
/* keep last */
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST,
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_MAX =
|
||||
QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
#endif /* QCA_VENDOR_H */
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/const_time.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
@ -17,10 +18,33 @@
|
||||
#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)) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sae_clear_data(sae);
|
||||
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
|
||||
if (tmp == NULL)
|
||||
@ -208,12 +232,14 @@ get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
|
||||
|
||||
static int is_quadratic_residue_blind(struct sae_data *sae,
|
||||
const u8 *prime, size_t bits,
|
||||
const struct crypto_bignum *qr,
|
||||
const struct crypto_bignum *qnr,
|
||||
const u8 *qr, const u8 *qnr,
|
||||
const struct crypto_bignum *y_sqr)
|
||||
{
|
||||
struct crypto_bignum *r, *num;
|
||||
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
|
||||
@ -224,7 +250,7 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
|
||||
* r = a random number between 1 and p-1, inclusive
|
||||
* num = (v * r * r) modulo p
|
||||
*/
|
||||
r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
|
||||
r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
@ -234,50 +260,51 @@ static int is_quadratic_residue_blind(struct sae_data *sae,
|
||||
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
|
||||
if (r_odd) {
|
||||
/*
|
||||
* num = (num * qr) module p
|
||||
* LGR(num, p) = 1 ==> quadratic residue
|
||||
*/
|
||||
if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
check = 1;
|
||||
} else {
|
||||
/*
|
||||
* num = (num * qnr) module p
|
||||
* LGR(num, p) = -1 ==> quadratic residue
|
||||
*/
|
||||
if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
check = -1;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
res = res == check;
|
||||
/* 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 struct crypto_bignum *qr,
|
||||
const struct crypto_bignum *qnr,
|
||||
struct crypto_bignum **ret_x_cand)
|
||||
const u8 *prime, const u8 *qr, const u8 *qnr,
|
||||
u8 *pwd_value)
|
||||
{
|
||||
u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *y_sqr, *x_cand;
|
||||
int res;
|
||||
size_t bits;
|
||||
|
||||
*ret_x_cand = NULL;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
|
||||
|
||||
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
|
||||
@ -286,7 +313,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
prime, sae->tmp->prime_len, pwd_value, bits) < 0)
|
||||
return -1;
|
||||
if (bits % 8)
|
||||
buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
|
||||
buf_shift_right(pwd_value, sae->tmp->prime_len, 8 - bits % 8);
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
|
||||
pwd_value, sae->tmp->prime_len);
|
||||
|
||||
@ -297,31 +324,27 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
if (!x_cand)
|
||||
return -1;
|
||||
y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
|
||||
if (!y_sqr) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
if (!y_sqr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
|
||||
crypto_bignum_deinit(y_sqr, 1);
|
||||
if (res <= 0) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
*ret_x_cand = x_cand;
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Returns -1 on fatal failure, 0 if PWE cannot be derived from the provided
|
||||
* pwd-seed, or 1 if a valid PWE was derived from pwd-seed. */
|
||||
static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
struct crypto_bignum *pwe)
|
||||
{
|
||||
u8 pwd_value[SAE_MAX_PRIME_LEN];
|
||||
size_t bits = sae->tmp->prime_len * 8;
|
||||
u8 exp[1];
|
||||
struct crypto_bignum *a, *b;
|
||||
int res;
|
||||
struct crypto_bignum *a, *b = NULL;
|
||||
int res, is_val;
|
||||
u8 pwd_value_valid;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
|
||||
|
||||
@ -333,16 +356,29 @@ static int sae_test_pwd_seed_ffc(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, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
|
||||
return 0;
|
||||
}
|
||||
/* Check whether pwd-value < p */
|
||||
res = const_time_memcmp(pwd_value, sae->tmp->dh->prime,
|
||||
sae->tmp->prime_len);
|
||||
/* pwd-value >= p is invalid, so res is < 0 for the valid cases and
|
||||
* the negative sign can be used to fill the mask for constant time
|
||||
* selection */
|
||||
pwd_value_valid = const_time_fill_msb(res);
|
||||
|
||||
/* If pwd-value >= p, force pwd-value to be < p and perform the
|
||||
* calculations anyway to hide timing difference. The derived PWE will
|
||||
* be ignored in that case. */
|
||||
pwd_value[0] = const_time_select_u8(pwd_value_valid, pwd_value[0], 0);
|
||||
|
||||
/* PWE = pwd-value^((p-1)/r) modulo p */
|
||||
|
||||
res = -1;
|
||||
a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
|
||||
if (!a)
|
||||
goto fail;
|
||||
|
||||
/* This is an optimization based on the used group that does not depend
|
||||
* on the password in any way, so it is fine to use separate branches
|
||||
* for this step without constant time operations. */
|
||||
if (sae->tmp->dh->safe_prime) {
|
||||
/*
|
||||
* r = (p-1)/2 for the group used here, so this becomes:
|
||||
@ -356,33 +392,34 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
b = crypto_bignum_init_set(exp, sizeof(exp));
|
||||
if (b == NULL ||
|
||||
crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
|
||||
crypto_bignum_div(b, sae->tmp->order, b) < 0) {
|
||||
crypto_bignum_deinit(b, 0);
|
||||
b = NULL;
|
||||
}
|
||||
crypto_bignum_div(b, sae->tmp->order, b) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (a == NULL || b == NULL)
|
||||
res = -1;
|
||||
else
|
||||
res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
|
||||
if (!b)
|
||||
goto fail;
|
||||
|
||||
crypto_bignum_deinit(a, 0);
|
||||
crypto_bignum_deinit(b, 0);
|
||||
res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
|
||||
return -1;
|
||||
}
|
||||
/* There were no fatal errors in calculations, so determine the return
|
||||
* value using constant time operations. We get here for number of
|
||||
* invalid cases which are cleared here after having performed all the
|
||||
* computation. PWE is valid if pwd-value was less than prime and
|
||||
* PWE > 1. Start with pwd-value check first and then use constant time
|
||||
* operations to clear res to 0 if PWE is 0 or 1.
|
||||
*/
|
||||
res = const_time_select_u8(pwd_value_valid, 1, 0);
|
||||
is_val = crypto_bignum_is_zero(pwe);
|
||||
res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
|
||||
is_val = crypto_bignum_is_one(pwe);
|
||||
res = const_time_select_u8(const_time_is_zero(is_val), res, 0);
|
||||
|
||||
/* if (PWE > 1) --> found */
|
||||
if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: PWE found");
|
||||
return 1;
|
||||
fail:
|
||||
crypto_bignum_deinit(a, 1);
|
||||
crypto_bignum_deinit(b, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -431,25 +468,32 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
size_t num_elem;
|
||||
u8 dummy_password[32];
|
||||
size_t dummy_password_len;
|
||||
u8 *dummy_password, *tmp_password;
|
||||
int pwd_seed_odd = 0;
|
||||
u8 prime[SAE_MAX_ECC_PRIME_LEN];
|
||||
size_t prime_len;
|
||||
struct crypto_bignum *x = NULL, *qr, *qnr;
|
||||
struct crypto_bignum *x = NULL, *qr = NULL, *qnr = NULL;
|
||||
u8 x_bin[SAE_MAX_ECC_PRIME_LEN];
|
||||
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;
|
||||
int res = -1;
|
||||
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
|
||||
* mask */
|
||||
|
||||
dummy_password_len = password_len;
|
||||
if (dummy_password_len > sizeof(dummy_password))
|
||||
dummy_password_len = sizeof(dummy_password);
|
||||
if (random_get_bytes(dummy_password, dummy_password_len) < 0)
|
||||
return -1;
|
||||
os_memset(x_bin, 0, sizeof(x_bin));
|
||||
|
||||
dummy_password = os_malloc(password_len);
|
||||
tmp_password = os_malloc(password_len);
|
||||
if (!dummy_password || !tmp_password ||
|
||||
random_get_bytes(dummy_password, password_len) < 0)
|
||||
goto fail;
|
||||
|
||||
prime_len = sae->tmp->prime_len;
|
||||
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
|
||||
prime_len) < 0)
|
||||
return -1;
|
||||
goto fail;
|
||||
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
|
||||
|
||||
/*
|
||||
@ -457,8 +501,10 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
* (qnr) modulo p for blinding purposes during the loop.
|
||||
*/
|
||||
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
|
||||
&qr, &qnr) < 0)
|
||||
return -1;
|
||||
&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;
|
||||
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
|
||||
password, password_len);
|
||||
@ -474,7 +520,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
*/
|
||||
sae_pwd_seed_key(addr1, addr2, addrs);
|
||||
|
||||
addr[0] = password;
|
||||
addr[0] = tmp_password;
|
||||
len[0] = password_len;
|
||||
num_elem = 1;
|
||||
if (identifier) {
|
||||
@ -491,9 +537,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.
|
||||
*/
|
||||
for (counter = 1; counter <= k || !x; counter++) {
|
||||
for (counter = 1; counter <= k || !found; counter++) {
|
||||
u8 pwd_seed[SHA256_MAC_LEN];
|
||||
struct crypto_bignum *x_cand;
|
||||
|
||||
if (counter > 200) {
|
||||
/* This should not happen in practice */
|
||||
@ -501,40 +546,49 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
|
||||
wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
|
||||
const_time_select_bin(found, dummy_password, password,
|
||||
password_len, tmp_password);
|
||||
if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
|
||||
addr, len, pwd_seed) < 0)
|
||||
break;
|
||||
|
||||
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
|
||||
prime, qr, qnr, &x_cand);
|
||||
prime, qr_bin, qnr_bin, x_cand_bin);
|
||||
const_time_select_bin(found, x_bin, x_cand_bin, prime_len,
|
||||
x_bin);
|
||||
pwd_seed_odd = const_time_select_u8(
|
||||
found, pwd_seed_odd,
|
||||
pwd_seed[SHA256_MAC_LEN - 1] & 0x01);
|
||||
os_memset(pwd_seed, 0, sizeof(pwd_seed));
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
if (res > 0 && !x) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: Selected pwd-seed with counter %u",
|
||||
counter);
|
||||
x = x_cand;
|
||||
pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
|
||||
os_memset(pwd_seed, 0, sizeof(pwd_seed));
|
||||
/* Need to minimize differences in handling res == 0 and 1 here
|
||||
* to avoid differences in timing and instruction cache access,
|
||||
* so use const_time_select_*() to make local copies of the
|
||||
* values based on whether this loop iteration was the one that
|
||||
* found the pwd-seed/x. */
|
||||
|
||||
/*
|
||||
* Use a dummy password for the following rounds, if
|
||||
* any.
|
||||
*/
|
||||
addr[0] = dummy_password;
|
||||
len[0] = dummy_password_len;
|
||||
} else if (res > 0) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
}
|
||||
/* found is 0 or 0xff here and res is 0 or 1. Bitwise OR of them
|
||||
* (with res converted to 0/0xff) handles this in constant time.
|
||||
*/
|
||||
found |= res * 0xff;
|
||||
wpa_printf(MSG_DEBUG, "SAE: pwd-seed result %d found=0x%02x",
|
||||
res, found);
|
||||
}
|
||||
|
||||
if (!x) {
|
||||
if (!found) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
x = crypto_bignum_init_set(x_bin, prime_len);
|
||||
if (!x) {
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!sae->tmp->pwe_ecc)
|
||||
sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
|
||||
if (!sae->tmp->pwe_ecc)
|
||||
@ -543,7 +597,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
|
||||
sae->tmp->pwe_ecc, x,
|
||||
pwd_seed_odd);
|
||||
crypto_bignum_deinit(x, 1);
|
||||
if (res < 0) {
|
||||
/*
|
||||
* This should not happen since we already checked that there
|
||||
@ -555,27 +608,48 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
fail:
|
||||
crypto_bignum_deinit(qr, 0);
|
||||
crypto_bignum_deinit(qnr, 0);
|
||||
os_free(dummy_password);
|
||||
bin_clear_free(tmp_password, password_len);
|
||||
crypto_bignum_deinit(x, 1);
|
||||
os_memset(x_bin, 0, sizeof(x_bin));
|
||||
os_memset(x_cand_bin, 0, sizeof(x_cand_bin));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
u8 counter;
|
||||
u8 counter, k, sel_counter = 0;
|
||||
u8 addrs[2 * ETH_ALEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
size_t num_elem;
|
||||
int found = 0;
|
||||
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
|
||||
* mask */
|
||||
u8 mask;
|
||||
struct crypto_bignum *pwe;
|
||||
size_t prime_len = sae->tmp->prime_len * 8;
|
||||
u8 *pwe_buf;
|
||||
|
||||
if (sae->tmp->pwe_ffc == NULL) {
|
||||
sae->tmp->pwe_ffc = crypto_bignum_init();
|
||||
if (sae->tmp->pwe_ffc == NULL)
|
||||
return -1;
|
||||
}
|
||||
crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
|
||||
sae->tmp->pwe_ffc = NULL;
|
||||
|
||||
/* Allocate a buffer to maintain selected and candidate PWE for constant
|
||||
* time selection. */
|
||||
pwe_buf = os_zalloc(prime_len * 2);
|
||||
pwe = crypto_bignum_init();
|
||||
if (!pwe_buf || !pwe)
|
||||
goto fail;
|
||||
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
|
||||
password, password_len);
|
||||
@ -599,7 +673,9 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
||||
len[num_elem] = sizeof(counter);
|
||||
num_elem++;
|
||||
|
||||
for (counter = 1; !found; counter++) {
|
||||
k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
|
||||
|
||||
for (counter = 1; counter <= k || !found; counter++) {
|
||||
u8 pwd_seed[SHA256_MAC_LEN];
|
||||
int res;
|
||||
|
||||
@ -609,20 +685,37 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
|
||||
wpa_printf(MSG_DEBUG, "SAE: counter = %02u", counter);
|
||||
if (hmac_sha256_vector(addrs, sizeof(addrs), num_elem,
|
||||
addr, len, pwd_seed) < 0)
|
||||
break;
|
||||
res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
|
||||
res = sae_test_pwd_seed_ffc(sae, pwd_seed, pwe);
|
||||
/* res is -1 for fatal failure, 0 if a valid PWE was not found,
|
||||
* or 1 if a valid PWE was found. */
|
||||
if (res < 0)
|
||||
break;
|
||||
if (res > 0) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
|
||||
found = 1;
|
||||
}
|
||||
/* Store the candidate PWE into the second half of pwe_buf and
|
||||
* the selected PWE in the beginning of pwe_buf using constant
|
||||
* time selection. */
|
||||
if (crypto_bignum_to_bin(pwe, pwe_buf + prime_len, prime_len,
|
||||
prime_len) < 0)
|
||||
break;
|
||||
const_time_select_bin(found, pwe_buf, pwe_buf + prime_len,
|
||||
prime_len, pwe_buf);
|
||||
sel_counter = const_time_select_u8(found, sel_counter, counter);
|
||||
mask = const_time_eq_u8(res, 1);
|
||||
found = const_time_select_u8(found, found, mask);
|
||||
}
|
||||
|
||||
return found ? 0 : -1;
|
||||
if (!found)
|
||||
goto fail;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: Use PWE from counter = %02u", sel_counter);
|
||||
sae->tmp->pwe_ffc = crypto_bignum_init_set(pwe_buf, prime_len);
|
||||
fail:
|
||||
crypto_bignum_deinit(pwe, 1);
|
||||
bin_clear_free(pwe_buf, prime_len * 2);
|
||||
return sae->tmp->pwe_ffc ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
@ -1394,23 +1487,31 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
|
||||
|
||||
if (sae->tmp == NULL) {
|
||||
if (!sae->tmp || !sae->peer_commit_scalar ||
|
||||
!sae->tmp->own_commit_scalar) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sae->tmp->ec)
|
||||
if (sae->tmp->ec) {
|
||||
if (!sae->tmp->peer_commit_element_ecc ||
|
||||
!sae->tmp->own_commit_element_ecc)
|
||||
return -1;
|
||||
sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ecc,
|
||||
sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
verifier);
|
||||
else
|
||||
} else {
|
||||
if (!sae->tmp->peer_commit_element_ffc ||
|
||||
!sae->tmp->own_commit_element_ffc)
|
||||
return -1;
|
||||
sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ffc,
|
||||
sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ffc,
|
||||
verifier);
|
||||
}
|
||||
|
||||
if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
|
||||
|
@ -40,6 +40,8 @@ struct sae_temporary_data {
|
||||
struct crypto_bignum *order_buf;
|
||||
struct wpabuf *anti_clogging_token;
|
||||
char *pw_id;
|
||||
int vlan_id;
|
||||
u8 bssid[ETH_ALEN];
|
||||
};
|
||||
|
||||
enum sae_state {
|
||||
|
@ -9,6 +9,6 @@
|
||||
#define GIT_VERSION_STR_POSTFIX ""
|
||||
#endif /* GIT_VERSION_STR_POSTFIX */
|
||||
|
||||
#define VERSION_STR "2.7" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
|
||||
#define VERSION_STR "2.8" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
|
||||
|
||||
#endif /* VERSION_H */
|
||||
|
@ -340,14 +340,21 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
* PTK = PRF-X(PMK, "Pairwise key expansion",
|
||||
* Min(AA, SA) || Max(AA, SA) ||
|
||||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
|
||||
* Min(ANonce, SNonce) || Max(ANonce, SNonce)
|
||||
* [ || Z.x ])
|
||||
*
|
||||
* The optional Z.x component is used only with DPP and that part is not defined
|
||||
* in IEEE 802.11.
|
||||
*/
|
||||
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
const u8 *nonce1, const u8 *nonce2,
|
||||
struct wpa_ptk *ptk, int akmp, int cipher)
|
||||
struct wpa_ptk *ptk, int akmp, int cipher,
|
||||
const u8 *z, size_t z_len)
|
||||
{
|
||||
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
|
||||
#define MAX_Z_LEN 66 /* with NIST P-521 */
|
||||
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
|
||||
size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
|
||||
u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
|
||||
size_t ptk_len;
|
||||
|
||||
@ -356,6 +363,9 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (z_len > MAX_Z_LEN)
|
||||
return -1;
|
||||
|
||||
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
|
||||
os_memcpy(data, addr1, ETH_ALEN);
|
||||
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
|
||||
@ -374,6 +384,11 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
WPA_NONCE_LEN);
|
||||
}
|
||||
|
||||
if (z && z_len) {
|
||||
os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
|
||||
data_len += z_len;
|
||||
}
|
||||
|
||||
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
|
||||
ptk->kek_len = wpa_kek_len(akmp, pmk_len);
|
||||
ptk->tk_len = wpa_cipher_key_len(cipher);
|
||||
@ -388,7 +403,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
if (wpa_key_mgmt_sha384(akmp)) {
|
||||
#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
|
||||
if (sha384_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
if (sha384_prf(pmk, pmk_len, label, data, data_len,
|
||||
tmp, ptk_len) < 0)
|
||||
return -1;
|
||||
#else /* CONFIG_SUITEB192 || CONFIG_FILS */
|
||||
@ -397,7 +412,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
|
||||
#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
|
||||
if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
if (sha256_prf(pmk, pmk_len, label, data, data_len,
|
||||
tmp, ptk_len) < 0)
|
||||
return -1;
|
||||
#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
|
||||
@ -406,17 +421,17 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
#ifdef CONFIG_DPP
|
||||
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
|
||||
if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
if (sha256_prf(pmk, pmk_len, label, data, data_len,
|
||||
tmp, ptk_len) < 0)
|
||||
return -1;
|
||||
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
|
||||
if (sha384_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
if (sha384_prf(pmk, pmk_len, label, data, data_len,
|
||||
tmp, ptk_len) < 0)
|
||||
return -1;
|
||||
} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
|
||||
if (sha512_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
if (sha512_prf(pmk, pmk_len, label, data, data_len,
|
||||
tmp, ptk_len) < 0)
|
||||
return -1;
|
||||
} else if (akmp == WPA_KEY_MGMT_DPP) {
|
||||
@ -426,7 +441,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
#endif /* CONFIG_DPP */
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
|
||||
if (sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp,
|
||||
if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
|
||||
ptk_len) < 0)
|
||||
return -1;
|
||||
}
|
||||
@ -435,6 +450,8 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
MAC2STR(addr1), MAC2STR(addr2));
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
|
||||
if (z && z_len)
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
|
||||
|
||||
@ -451,6 +468,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
ptk->kck2_len = 0;
|
||||
|
||||
os_memset(tmp, 0, sizeof(tmp));
|
||||
os_memset(data, 0, data_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -880,6 +898,12 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
|
||||
parse->igtk_len = len;
|
||||
break;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_OCV
|
||||
case FTIE_SUBELEM_OCI:
|
||||
parse->oci = pos;
|
||||
parse->oci_len = len;
|
||||
break;
|
||||
#endif /* CONFIG_OCV */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
|
||||
break;
|
||||
@ -1203,6 +1227,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
left = rsn_ie_len - 6;
|
||||
|
||||
data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
|
||||
data->has_group = 1;
|
||||
data->key_mgmt = WPA_KEY_MGMT_OSEN;
|
||||
data->proto = WPA_PROTO_OSEN;
|
||||
} else {
|
||||
@ -1224,6 +1249,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
|
||||
if (left >= RSN_SELECTOR_LEN) {
|
||||
data->group_cipher = rsn_selector_to_bitfield(pos);
|
||||
data->has_group = 1;
|
||||
if (!wpa_cipher_valid_group(data->group_cipher)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: invalid group cipher 0x%x (%08x)",
|
||||
@ -1249,6 +1275,8 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
"count %u left %u", __func__, count, left);
|
||||
return -4;
|
||||
}
|
||||
if (count)
|
||||
data->has_pairwise = 1;
|
||||
for (i = 0; i < count; i++) {
|
||||
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
@ -1467,6 +1495,15 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
}
|
||||
|
||||
|
||||
int wpa_default_rsn_cipher(int freq)
|
||||
{
|
||||
if (freq > 56160)
|
||||
return WPA_CIPHER_GCMP; /* DMG */
|
||||
|
||||
return WPA_CIPHER_CCMP;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
|
||||
/**
|
||||
@ -1754,7 +1791,7 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
|
||||
os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
|
||||
offset += ptk->tk_len;
|
||||
os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
|
||||
offset = ptk->kck2_len;
|
||||
offset += ptk->kck2_len;
|
||||
os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
|
||||
|
@ -110,6 +110,7 @@ WPA_CIPHER_BIP_CMAC_256)
|
||||
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
|
||||
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
|
||||
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
|
||||
#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
|
||||
|
||||
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
|
||||
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
|
||||
@ -148,7 +149,8 @@ WPA_CIPHER_BIP_CMAC_256)
|
||||
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
|
||||
#define WPA_CAPABILITY_PBAC BIT(12)
|
||||
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
|
||||
/* B14-B15: Reserved */
|
||||
#define WPA_CAPABILITY_OCVC BIT(14)
|
||||
/* B15: Reserved */
|
||||
|
||||
|
||||
/* IEEE 802.11r */
|
||||
@ -326,6 +328,7 @@ struct rsn_ftie_sha384 {
|
||||
#define FTIE_SUBELEM_GTK 2
|
||||
#define FTIE_SUBELEM_R0KH_ID 3
|
||||
#define FTIE_SUBELEM_IGTK 4
|
||||
#define FTIE_SUBELEM_OCI 5
|
||||
|
||||
struct rsn_rdie {
|
||||
u8 id;
|
||||
@ -344,7 +347,8 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
|
||||
int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
const u8 *nonce1, const u8 *nonce2,
|
||||
struct wpa_ptk *ptk, int akmp, int cipher);
|
||||
struct wpa_ptk *ptk, int akmp, int cipher,
|
||||
const u8 *z, size_t z_len);
|
||||
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
|
||||
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
|
||||
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
|
||||
@ -389,7 +393,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
|
||||
struct wpa_ie_data {
|
||||
int proto;
|
||||
int pairwise_cipher;
|
||||
int has_pairwise;
|
||||
int group_cipher;
|
||||
int has_group;
|
||||
int key_mgmt;
|
||||
int capabilities;
|
||||
size_t num_pmkid;
|
||||
@ -402,6 +408,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
int wpa_default_rsn_cipher(int freq);
|
||||
|
||||
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||
u8 *pmkid, int akmp);
|
||||
@ -451,6 +458,10 @@ struct wpa_ft_ies {
|
||||
size_t tie_len;
|
||||
const u8 *igtk;
|
||||
size_t igtk_len;
|
||||
#ifdef CONFIG_OCV
|
||||
const u8 *oci;
|
||||
size_t oci_len;
|
||||
#endif /* CONFIG_OCV */
|
||||
const u8 *ric;
|
||||
size_t ric_len;
|
||||
int key_mgmt;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#ifdef CONFIG_CTRL_IFACE
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@ -133,6 +135,19 @@ struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
|
||||
return NULL;
|
||||
}
|
||||
tries++;
|
||||
#ifdef ANDROID
|
||||
/* Set client socket file permissions so that bind() creates the client
|
||||
* socket with these permissions and there is no need to try to change
|
||||
* them with chmod() after bind() which would have potential issues with
|
||||
* race conditions. These permissions are needed to make sure the server
|
||||
* side (wpa_supplicant or hostapd) can reply to the control interface
|
||||
* messages.
|
||||
*
|
||||
* The lchown() calls below after bind() are also part of the needed
|
||||
* operations to allow the response to go through. Those are using the
|
||||
* no-deference-symlinks version to avoid races. */
|
||||
fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
#endif /* ANDROID */
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
if (errno == EADDRINUSE && tries < 2) {
|
||||
@ -151,10 +166,9 @@ struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
/* Set group even if we do not have privileges to change owner */
|
||||
chown(ctrl->local.sun_path, -1, AID_WIFI);
|
||||
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
|
||||
lchown(ctrl->local.sun_path, -1, AID_WIFI);
|
||||
lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
|
||||
|
||||
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
|
||||
if (socket_local_client_connect(
|
||||
@ -540,7 +554,8 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
res = recv(ctrl->s, reply, *reply_len, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (res > 0 && reply[0] == '<') {
|
||||
if ((res > 0 && reply[0] == '<') ||
|
||||
(res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
|
||||
/* This is an unsolicited message from
|
||||
* wpa_supplicant, not the reply to the
|
||||
* request. Use msg_cb to report this to the
|
||||
|
@ -99,6 +99,10 @@ void * aes_encrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
u32 *rk;
|
||||
int res;
|
||||
|
||||
if (TEST_FAIL())
|
||||
return NULL;
|
||||
|
||||
rk = os_malloc(AES_PRIV_SIZE);
|
||||
if (rk == NULL)
|
||||
return NULL;
|
||||
|
@ -420,6 +420,7 @@ int __must_check crypto_public_key_decrypt_pkcs1(
|
||||
int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
u8 *pubkey);
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len);
|
||||
@ -702,14 +703,6 @@ struct crypto_ec * crypto_ec_init(int group);
|
||||
*/
|
||||
void crypto_ec_deinit(struct crypto_ec *e);
|
||||
|
||||
/**
|
||||
* crypto_ec_cofactor - Set the cofactor into the big number
|
||||
* @e: EC context from crypto_ec_init()
|
||||
* @cofactor: Cofactor of curve.
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor);
|
||||
|
||||
/**
|
||||
* crypto_ec_prime_len - Get length of the prime in octets
|
||||
* @e: EC context from crypto_ec_init()
|
||||
|
@ -310,12 +310,51 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
{
|
||||
return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
gcry_mpi_t pub = NULL;
|
||||
int res = -1;
|
||||
|
||||
if (pubkey_len > prime_len ||
|
||||
(pubkey_len == prime_len &&
|
||||
os_memcmp(pubkey, prime, prime_len) >= 0))
|
||||
return -1;
|
||||
|
||||
if (gcry_mpi_scan(&pub, GCRYMPI_FMT_USG, pubkey, pubkey_len, NULL) !=
|
||||
GPG_ERR_NO_ERROR ||
|
||||
gcry_mpi_cmp_ui(pub, 1) <= 0)
|
||||
goto fail;
|
||||
|
||||
if (order) {
|
||||
gcry_mpi_t p = NULL, q = NULL, tmp;
|
||||
int failed;
|
||||
|
||||
/* verify: pubkey^q == 1 mod p */
|
||||
tmp = gcry_mpi_new(prime_len * 8);
|
||||
failed = !tmp ||
|
||||
gcry_mpi_scan(&p, GCRYMPI_FMT_USG, prime, prime_len,
|
||||
NULL) != GPG_ERR_NO_ERROR ||
|
||||
gcry_mpi_scan(&q, GCRYMPI_FMT_USG, order, order_len,
|
||||
NULL) != GPG_ERR_NO_ERROR;
|
||||
if (!failed) {
|
||||
gcry_mpi_powm(tmp, pub, q, p);
|
||||
failed = gcry_mpi_cmp_ui(tmp, 1) != 0;
|
||||
}
|
||||
gcry_mpi_release(p);
|
||||
gcry_mpi_release(q);
|
||||
gcry_mpi_release(tmp);
|
||||
if (failed)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
fail:
|
||||
gcry_mpi_release(pub);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,12 +40,49 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
{
|
||||
return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
struct bignum *pub;
|
||||
int res = -1;
|
||||
|
||||
if (pubkey_len > prime_len ||
|
||||
(pubkey_len == prime_len &&
|
||||
os_memcmp(pubkey, prime, prime_len) >= 0))
|
||||
return -1;
|
||||
|
||||
pub = bignum_init();
|
||||
if (!pub || bignum_set_unsigned_bin(pub, pubkey, pubkey_len) < 0 ||
|
||||
bignum_cmp_d(pub, 1) <= 0)
|
||||
goto fail;
|
||||
|
||||
if (order) {
|
||||
struct bignum *p, *q, *tmp;
|
||||
int failed;
|
||||
|
||||
/* verify: pubkey^q == 1 mod p */
|
||||
p = bignum_init();
|
||||
q = bignum_init();
|
||||
tmp = bignum_init();
|
||||
failed = !p || !q || !tmp ||
|
||||
bignum_set_unsigned_bin(p, prime, prime_len) < 0 ||
|
||||
bignum_set_unsigned_bin(q, order, order_len) < 0 ||
|
||||
bignum_exptmod(pub, q, p, tmp) < 0 ||
|
||||
bignum_cmp_d(tmp, 1) != 0;
|
||||
bignum_deinit(p);
|
||||
bignum_deinit(q);
|
||||
bignum_deinit(tmp);
|
||||
if (failed)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
fail:
|
||||
bignum_deinit(pub);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,6 +310,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
|
||||
os_free(ctx);
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -278,6 +278,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
|
||||
os_free(ctx);
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -721,10 +724,12 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
{
|
||||
/* TODO: check pubkey */
|
||||
return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
}
|
||||
|
@ -386,6 +386,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
}
|
||||
|
||||
crypto_hash_deinit(ctx);
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -331,12 +331,44 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
{
|
||||
return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
mpz_t pub;
|
||||
int res = -1;
|
||||
|
||||
if (pubkey_len > prime_len ||
|
||||
(pubkey_len == prime_len &&
|
||||
os_memcmp(pubkey, prime, prime_len) >= 0))
|
||||
return -1;
|
||||
|
||||
mpz_init(pub);
|
||||
mpz_import(pub, pubkey_len, 1, 1, 1, 0, pubkey);
|
||||
if (mpz_cmp_d(pub, 1) <= 0)
|
||||
goto fail;
|
||||
|
||||
if (order) {
|
||||
mpz_t p, q, tmp;
|
||||
int failed;
|
||||
|
||||
/* verify: pubkey^q == 1 mod p */
|
||||
mpz_inits(p, q, tmp, NULL);
|
||||
mpz_import(p, prime_len, 1, 1, 1, 0, prime);
|
||||
mpz_import(q, order_len, 1, 1, 1, 0, order);
|
||||
mpz_powm(tmp, pub, q, p);
|
||||
failed = mpz_cmp_d(tmp, 1) != 0;
|
||||
mpz_clears(p, q, tmp, NULL);
|
||||
if (failed)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
fail:
|
||||
mpz_clear(pub);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#endif /* CONFIG_ECC */
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/const_time.h"
|
||||
#include "wpabuf.h"
|
||||
#include "dh_group5.h"
|
||||
#include "sha1.h"
|
||||
@ -111,6 +112,31 @@ static BIGNUM * get_group5_prime(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static BIGNUM * get_group5_order(void)
|
||||
{
|
||||
static const unsigned char RFC3526_ORDER_1536[] = {
|
||||
0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0x87,0xED,0x51,
|
||||
0x10,0xB4,0x61,0x1A,0x62,0x63,0x31,0x45,0xC0,0x6E,0x0E,0x68,
|
||||
0x94,0x81,0x27,0x04,0x45,0x33,0xE6,0x3A,0x01,0x05,0xDF,0x53,
|
||||
0x1D,0x89,0xCD,0x91,0x28,0xA5,0x04,0x3C,0xC7,0x1A,0x02,0x6E,
|
||||
0xF7,0xCA,0x8C,0xD9,0xE6,0x9D,0x21,0x8D,0x98,0x15,0x85,0x36,
|
||||
0xF9,0x2F,0x8A,0x1B,0xA7,0xF0,0x9A,0xB6,0xB6,0xA8,0xE1,0x22,
|
||||
0xF2,0x42,0xDA,0xBB,0x31,0x2F,0x3F,0x63,0x7A,0x26,0x21,0x74,
|
||||
0xD3,0x1B,0xF6,0xB5,0x85,0xFF,0xAE,0x5B,0x7A,0x03,0x5B,0xF6,
|
||||
0xF7,0x1C,0x35,0xFD,0xAD,0x44,0xCF,0xD2,0xD7,0x4F,0x92,0x08,
|
||||
0xBE,0x25,0x8F,0xF3,0x24,0x94,0x33,0x28,0xF6,0x72,0x2D,0x9E,
|
||||
0xE1,0x00,0x3E,0x5C,0x50,0xB1,0xDF,0x82,0xCC,0x6D,0x24,0x1B,
|
||||
0x0E,0x2A,0xE9,0xCD,0x34,0x8B,0x1F,0xD4,0x7E,0x92,0x67,0xAF,
|
||||
0xC1,0xB2,0xAE,0x91,0xEE,0x51,0xD6,0xCB,0x0E,0x31,0x79,0xAB,
|
||||
0x10,0x42,0xA9,0x5D,0xCF,0x6A,0x94,0x83,0xB8,0x4B,0x4B,0x36,
|
||||
0xB3,0x86,0x1A,0xA7,0x25,0x5E,0x4C,0x02,0x78,0xBA,0x36,0x04,
|
||||
0x65,0x11,0xB9,0x93,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
|
||||
}
|
||||
|
||||
|
||||
#ifdef OPENSSL_NO_SHA256
|
||||
#define NO_SHA256_WRAPPER
|
||||
#endif
|
||||
@ -518,12 +544,45 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
{
|
||||
return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
BIGNUM *pub, *p;
|
||||
int res = -1;
|
||||
|
||||
pub = BN_bin2bn(pubkey, pubkey_len, NULL);
|
||||
p = BN_bin2bn(prime, prime_len, NULL);
|
||||
if (!pub || !p || BN_is_zero(pub) || BN_is_one(pub) ||
|
||||
BN_cmp(pub, p) >= 0)
|
||||
goto fail;
|
||||
|
||||
if (order) {
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *q, *tmp;
|
||||
int failed;
|
||||
|
||||
/* verify: pubkey^q == 1 mod p */
|
||||
q = BN_bin2bn(order, order_len, NULL);
|
||||
ctx = BN_CTX_new();
|
||||
tmp = BN_new();
|
||||
failed = !q || !ctx || !tmp ||
|
||||
!BN_mod_exp(tmp, pub, q, p, ctx) ||
|
||||
!BN_is_one(tmp);
|
||||
BN_clear(q);
|
||||
BN_clear(tmp);
|
||||
BN_CTX_free(ctx);
|
||||
if (failed)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
|
||||
prime, prime_len, secret, len);
|
||||
fail:
|
||||
BN_clear(pub);
|
||||
BN_clear(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -549,7 +608,8 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
bn_result == NULL)
|
||||
goto error;
|
||||
|
||||
if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
|
||||
if (BN_mod_exp_mont_consttime(bn_result, bn_base, bn_exp, bn_modulus,
|
||||
ctx, NULL) != 1)
|
||||
goto error;
|
||||
|
||||
*result_len = BN_bn2bin(bn_result, result);
|
||||
@ -709,6 +769,10 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
|
||||
if (dh->p == NULL)
|
||||
goto err;
|
||||
|
||||
dh->q = get_group5_order();
|
||||
if (!dh->q)
|
||||
goto err;
|
||||
|
||||
if (DH_generate_key(dh) != 1)
|
||||
goto err;
|
||||
|
||||
@ -737,7 +801,7 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
|
||||
DH *dh;
|
||||
struct wpabuf *pubkey = NULL, *privkey = NULL;
|
||||
size_t publen, privlen;
|
||||
BIGNUM *p = NULL, *g;
|
||||
BIGNUM *p, *g, *q;
|
||||
const BIGNUM *priv_key = NULL, *pub_key = NULL;
|
||||
|
||||
*priv = NULL;
|
||||
@ -750,10 +814,12 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
|
||||
|
||||
g = BN_new();
|
||||
p = get_group5_prime();
|
||||
if (!g || BN_set_word(g, 2) != 1 || !p ||
|
||||
DH_set0_pqg(dh, p, NULL, g) != 1)
|
||||
q = get_group5_order();
|
||||
if (!g || BN_set_word(g, 2) != 1 || !p || !q ||
|
||||
DH_set0_pqg(dh, p, q, g) != 1)
|
||||
goto err;
|
||||
p = NULL;
|
||||
q = NULL;
|
||||
g = NULL;
|
||||
|
||||
if (DH_generate_key(dh) != 1)
|
||||
@ -778,6 +844,7 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
|
||||
|
||||
err:
|
||||
BN_free(p);
|
||||
BN_free(q);
|
||||
BN_free(g);
|
||||
wpabuf_clear_free(pubkey);
|
||||
wpabuf_clear_free(privkey);
|
||||
@ -987,6 +1054,9 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
HMAC_CTX_free(ctx->ctx);
|
||||
bin_clear_free(ctx, sizeof(*ctx));
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
|
||||
if (res == 1) {
|
||||
*len = mdlen;
|
||||
return 0;
|
||||
@ -1250,6 +1320,8 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
|
||||
|
||||
int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
|
||||
{
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
return BN_rand_range((BIGNUM *) r, (const BIGNUM *) m) == 1 ? 0 : -1;
|
||||
}
|
||||
|
||||
@ -1295,8 +1367,9 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
|
||||
bnctx = BN_CTX_new();
|
||||
if (bnctx == NULL)
|
||||
return -1;
|
||||
res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
|
||||
(const BIGNUM *) c, bnctx);
|
||||
res = BN_mod_exp_mont_consttime((BIGNUM *) d, (const BIGNUM *) a,
|
||||
(const BIGNUM *) b, (const BIGNUM *) c,
|
||||
bnctx, NULL);
|
||||
BN_CTX_free(bnctx);
|
||||
|
||||
return res ? 0 : -1;
|
||||
@ -1315,6 +1388,11 @@ int crypto_bignum_inverse(const struct crypto_bignum *a,
|
||||
bnctx = BN_CTX_new();
|
||||
if (bnctx == NULL)
|
||||
return -1;
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
/* TODO: use BN_mod_inverse_blinded() ? */
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
|
||||
(const BIGNUM *) b, bnctx);
|
||||
BN_CTX_free(bnctx);
|
||||
@ -1348,6 +1426,9 @@ int crypto_bignum_div(const struct crypto_bignum *a,
|
||||
bnctx = BN_CTX_new();
|
||||
if (bnctx == NULL)
|
||||
return -1;
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
BN_set_flags((BIGNUM *) a, BN_FLG_CONSTTIME);
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
|
||||
(const BIGNUM *) b, bnctx);
|
||||
BN_CTX_free(bnctx);
|
||||
@ -1425,6 +1506,7 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
BN_CTX *bnctx;
|
||||
BIGNUM *exp = NULL, *tmp = NULL;
|
||||
int res = -2;
|
||||
unsigned int mask;
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -2;
|
||||
@ -1439,16 +1521,17 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
/* exp = (p-1) / 2 */
|
||||
!BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
|
||||
!BN_rshift1(exp, exp) ||
|
||||
!BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
|
||||
bnctx))
|
||||
!BN_mod_exp_mont_consttime(tmp, (const BIGNUM *) a, exp,
|
||||
(const BIGNUM *) p, bnctx, NULL))
|
||||
goto fail;
|
||||
|
||||
if (BN_is_word(tmp, 1))
|
||||
res = 1;
|
||||
else if (BN_is_zero(tmp))
|
||||
res = 0;
|
||||
else
|
||||
res = -1;
|
||||
/* Return 1 if tmp == 1, 0 if tmp == 0, or -1 otherwise. Need to use
|
||||
* constant time selection to avoid branches here. */
|
||||
res = -1;
|
||||
mask = const_time_eq(BN_is_word(tmp, 1), 1);
|
||||
res = const_time_select_int(mask, 1, res);
|
||||
mask = const_time_eq(BN_is_zero(tmp), 1);
|
||||
res = const_time_select_int(mask, 0, res);
|
||||
|
||||
fail:
|
||||
BN_clear_free(tmp);
|
||||
@ -1553,13 +1636,6 @@ void crypto_ec_deinit(struct crypto_ec *e)
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
|
||||
{
|
||||
return EC_GROUP_get_cofactor(e->group, (BIGNUM *) cofactor,
|
||||
e->bnctx) == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
|
||||
{
|
||||
if (TEST_FAIL())
|
||||
|
@ -826,6 +826,7 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
|
||||
|
||||
|
||||
int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
|
||||
const u8 *order, size_t order_len,
|
||||
const u8 *privkey, size_t privkey_len,
|
||||
const u8 *pubkey, size_t pubkey_len,
|
||||
u8 *secret, size_t *len)
|
||||
@ -952,6 +953,8 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
ret = 0;
|
||||
done:
|
||||
bin_clear_free(ctx, sizeof(*ctx));
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1082,6 +1085,8 @@ int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
|
||||
int ret = 0;
|
||||
WC_RNG rng;
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
if (wc_InitRng(&rng) != 0)
|
||||
return -1;
|
||||
if (mp_rand_prime((mp_int *) r,
|
||||
@ -1347,16 +1352,6 @@ void crypto_ec_deinit(struct crypto_ec* e)
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_cofactor(struct crypto_ec *e, struct crypto_bignum *cofactor)
|
||||
{
|
||||
if (!e || !cofactor)
|
||||
return -1;
|
||||
|
||||
mp_set((mp_int *) cofactor, e->key.dp->cofactor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
|
||||
{
|
||||
if (TEST_FAIL())
|
||||
|
@ -1249,6 +1249,7 @@ struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
|
||||
if (shared == NULL)
|
||||
return NULL;
|
||||
if (crypto_dh_derive_secret(*dh->generator, dh->prime, dh->prime_len,
|
||||
dh->order, dh->order_len,
|
||||
wpabuf_head(own_private),
|
||||
wpabuf_len(own_private),
|
||||
wpabuf_head(peer_public),
|
||||
|
@ -85,7 +85,7 @@ MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
|
||||
(cp)[1] = (value) >> 8; \
|
||||
(cp)[0] = (value); } while (0)
|
||||
|
||||
static u8 PADDING[MD4_BLOCK_LENGTH] = {
|
||||
static const u8 PADDING[MD4_BLOCK_LENGTH] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "utils/includes.h"
|
||||
#ifdef __linux__
|
||||
#include <fcntl.h>
|
||||
#ifdef CONFIG_GETRANDOM
|
||||
#include <sys/random.h>
|
||||
#endif /* CONFIG_GETRANDOM */
|
||||
#endif /* __linux__ */
|
||||
|
||||
#include "utils/common.h"
|
||||
@ -228,30 +231,52 @@ int random_pool_ready(void)
|
||||
return 1; /* Already initialized - good to continue */
|
||||
|
||||
/*
|
||||
* Try to fetch some more data from the kernel high quality
|
||||
* /dev/random. There may not be enough data available at this point,
|
||||
* Try to fetch some more data from the kernel high quality RNG.
|
||||
* There may not be enough data available at this point,
|
||||
* so use non-blocking read to avoid blocking the application
|
||||
* completely.
|
||||
*/
|
||||
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_GETRANDOM
|
||||
res = getrandom(dummy_key + dummy_key_avail,
|
||||
sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
|
||||
if (res < 0) {
|
||||
if (errno == ENOSYS) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"random: getrandom() not supported, falling back to /dev/random");
|
||||
} else {
|
||||
wpa_printf(MSG_INFO,
|
||||
"random: no data from getrandom(): %s",
|
||||
strerror(errno));
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_GETRANDOM */
|
||||
res = -1;
|
||||
#endif /* CONFIG_GETRANDOM */
|
||||
if (res < 0) {
|
||||
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"random: Cannot open /dev/random: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = read(fd, dummy_key + dummy_key_avail,
|
||||
sizeof(dummy_key) - dummy_key_avail);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"random: Cannot read from /dev/random: %s",
|
||||
strerror(errno));
|
||||
res = 0;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
res = read(fd, dummy_key + dummy_key_avail,
|
||||
sizeof(dummy_key) - dummy_key_avail);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
|
||||
"%s", strerror(errno));
|
||||
res = 0;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
|
||||
"/dev/random", (unsigned) res,
|
||||
wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
|
||||
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
|
||||
dummy_key_avail += res;
|
||||
close(fd);
|
||||
|
||||
if (dummy_key_avail == sizeof(dummy_key)) {
|
||||
if (own_pool_ready < MIN_READY_MARK)
|
||||
@ -261,7 +286,7 @@ int random_pool_ready(void)
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
|
||||
"random data available from /dev/random",
|
||||
"random data available",
|
||||
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
|
||||
|
||||
if (own_pool_ready >= MIN_READY_MARK ||
|
||||
@ -413,6 +438,19 @@ void random_init(const char *entropy_file)
|
||||
if (random_fd >= 0)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_GETRANDOM
|
||||
{
|
||||
u8 dummy;
|
||||
|
||||
if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
|
||||
errno != ENOSYS) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"random: getrandom() support available");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_GETRANDOM */
|
||||
|
||||
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
|
||||
if (random_fd < 0) {
|
||||
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
|
||||
|
@ -40,9 +40,6 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
|
||||
const unsigned char *SHA1_addr[3];
|
||||
size_t SHA1_len[3];
|
||||
|
||||
if (secret_len & 1)
|
||||
return -1;
|
||||
|
||||
MD5_addr[0] = A_MD5;
|
||||
MD5_len[0] = MD5_MAC_LEN;
|
||||
MD5_addr[1] = (unsigned char *) label;
|
||||
|
@ -109,9 +109,14 @@ static const u64 K[80] = {
|
||||
/* compress 1024-bits */
|
||||
static int sha512_compress(struct sha512_state *md, unsigned char *buf)
|
||||
{
|
||||
u64 S[8], W[80], t0, t1;
|
||||
u64 S[8], t0, t1;
|
||||
u64 *W;
|
||||
int i;
|
||||
|
||||
W = os_malloc(80 * sizeof(u64));
|
||||
if (!W)
|
||||
return -1;
|
||||
|
||||
/* copy state into S */
|
||||
for (i = 0; i < 8; i++) {
|
||||
S[i] = md->state[i];
|
||||
@ -146,6 +151,7 @@ static int sha512_compress(struct sha512_state *md, unsigned char *buf)
|
||||
md->state[i] = md->state[i] + S[i];
|
||||
}
|
||||
|
||||
os_free(W);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
104
contrib/wpa/src/crypto/sha512.c
Normal file
104
contrib/wpa/src/crypto/sha512.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* SHA-512 hash implementation and interface functions
|
||||
* Copyright (c) 2003-2018, 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 "sha512.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha512_vector - HMAC-SHA512 over data vector (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @num_elem: Number of elements in the data vector
|
||||
* @addr: Pointers to the data areas
|
||||
* @len: Lengths of the data blocks
|
||||
* @mac: Buffer for the hash (64 bytes)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
|
||||
unsigned char tk[64];
|
||||
const u8 *_addr[6];
|
||||
size_t _len[6], i;
|
||||
|
||||
if (num_elem > 5) {
|
||||
/*
|
||||
* Fixed limit on the number of fragments to avoid having to
|
||||
* allocate memory (which could fail).
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if key is longer than 128 bytes reset it to key = SHA512(key) */
|
||||
if (key_len > 128) {
|
||||
if (sha512_vector(1, &key, &key_len, tk) < 0)
|
||||
return -1;
|
||||
key = tk;
|
||||
key_len = 64;
|
||||
}
|
||||
|
||||
/* the HMAC_SHA512 transform looks like:
|
||||
*
|
||||
* SHA512(K XOR opad, SHA512(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 128 times
|
||||
* opad is the byte 0x5c repeated 128 times
|
||||
* and text is the data being protected */
|
||||
|
||||
/* start out by storing key in ipad */
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
/* XOR key with ipad values */
|
||||
for (i = 0; i < 128; i++)
|
||||
k_pad[i] ^= 0x36;
|
||||
|
||||
/* perform inner SHA512 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 128;
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
_addr[i + 1] = addr[i];
|
||||
_len[i + 1] = len[i];
|
||||
}
|
||||
if (sha512_vector(1 + num_elem, _addr, _len, mac) < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
/* XOR key with opad values */
|
||||
for (i = 0; i < 128; i++)
|
||||
k_pad[i] ^= 0x5c;
|
||||
|
||||
/* perform outer SHA512 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 128;
|
||||
_addr[1] = mac;
|
||||
_len[1] = SHA512_MAC_LEN;
|
||||
return sha512_vector(2, _addr, _len, mac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha512 - HMAC-SHA512 over data buffer (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @data: Pointers to the data area
|
||||
* @data_len: Length of the data area
|
||||
* @mac: Buffer for the hash (64 bytes)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac)
|
||||
{
|
||||
return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
|
||||
}
|
@ -42,6 +42,7 @@ enum tls_fail_reason {
|
||||
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
|
||||
TLS_FAIL_DOMAIN_MISMATCH = 10,
|
||||
TLS_FAIL_INSUFFICIENT_KEY_LEN = 11,
|
||||
TLS_FAIL_DN_MISMATCH = 12,
|
||||
};
|
||||
|
||||
|
||||
@ -82,6 +83,7 @@ struct tls_config {
|
||||
int cert_in_cb;
|
||||
const char *openssl_ciphers;
|
||||
unsigned int tls_session_lifetime;
|
||||
unsigned int crl_reload_interval;
|
||||
unsigned int tls_flags;
|
||||
|
||||
void (*event_cb)(void *ctx, enum tls_event ev,
|
||||
@ -103,6 +105,9 @@ struct tls_config {
|
||||
#define TLS_CONN_SUITEB BIT(11)
|
||||
#define TLS_CONN_SUITEB_NO_ECDH BIT(12)
|
||||
#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
|
||||
#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
|
||||
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
|
||||
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
|
||||
|
||||
/**
|
||||
* struct tls_connection_params - Parameters for TLS connection
|
||||
@ -115,12 +120,19 @@ struct tls_config {
|
||||
* %NULL to allow all subjects
|
||||
* @altsubject_match: String to match in the alternative subject of the peer
|
||||
* certificate or %NULL to allow all alternative subjects
|
||||
* @suffix_match: String to suffix match in the dNSName or CN of the peer
|
||||
* certificate or %NULL to allow all domain names. This may allow subdomains an
|
||||
* wildcard certificates. Each domain name label must have a full match.
|
||||
* @suffix_match: Semicolon deliminated string of values to suffix match against
|
||||
* the dNSName or CN of the peer certificate or %NULL to allow all domain names.
|
||||
* This may allow subdomains and wildcard certificates. Each domain name label
|
||||
* must have a full case-insensitive match.
|
||||
* @domain_match: String to match in the dNSName or CN of the peer
|
||||
* certificate or %NULL to allow all domain names. This requires a full,
|
||||
* case-insensitive match.
|
||||
*
|
||||
* More than one match string can be provided by using semicolons to
|
||||
* separate the strings (e.g., example.org;example.com). When multiple
|
||||
* strings are specified, a match with any one of the values is
|
||||
* considered a sufficient match for the certificate, i.e., the
|
||||
* conditions are ORed together.
|
||||
* @client_cert: File or reference name for client X.509 certificate in PEM or
|
||||
* DER format
|
||||
* @client_cert_blob: client_cert as inlined data or %NULL if not used
|
||||
@ -144,12 +156,15 @@ struct tls_config {
|
||||
* @cert_id: the certificate's id when using engine
|
||||
* @ca_cert_id: the CA certificate's id when using engine
|
||||
* @openssl_ciphers: OpenSSL cipher configuration
|
||||
* @openssl_ecdh_curves: OpenSSL ECDH curve configuration. %NULL for auto if
|
||||
* supported, empty string to disable, or a colon-separated curve list.
|
||||
* @flags: Parameter options (TLS_CONN_*)
|
||||
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
|
||||
* or %NULL if OCSP is not enabled
|
||||
* @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
|
||||
* response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
|
||||
* ocsp_multi is not enabled
|
||||
* @check_cert_subject: Client certificate subject name matching string
|
||||
*
|
||||
* TLS connection parameters to be configured with tls_connection_set_params()
|
||||
* and tls_global_set_params().
|
||||
@ -187,10 +202,12 @@ struct tls_connection_params {
|
||||
const char *cert_id;
|
||||
const char *ca_cert_id;
|
||||
const char *openssl_ciphers;
|
||||
const char *openssl_ecdh_curves;
|
||||
|
||||
unsigned int flags;
|
||||
const char *ocsp_stapling_response;
|
||||
const char *ocsp_stapling_response_multi;
|
||||
const char *check_cert_subject;
|
||||
};
|
||||
|
||||
|
||||
@ -321,9 +338,11 @@ int __must_check tls_global_set_params(
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
|
||||
* 2 = verify CRL for all certificates
|
||||
* @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
|
||||
int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
|
||||
int strict);
|
||||
|
||||
/**
|
||||
* tls_connection_set_verify - Set certificate verification options
|
||||
@ -358,15 +377,21 @@ int __must_check tls_connection_get_random(void *tls_ctx,
|
||||
* @tls_ctx: TLS context data from tls_init()
|
||||
* @conn: Connection context data from tls_connection_init()
|
||||
* @label: Label (e.g., description of the key) for PRF
|
||||
* @context: Optional extra upper-layer context (max len 2^16)
|
||||
* @context_len: The length of the context value
|
||||
* @out: Buffer for output data from TLS-PRF
|
||||
* @out_len: Length of the output buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Exports keying material using the mechanism described in RFC 5705.
|
||||
* Exports keying material using the mechanism described in RFC 5705. If
|
||||
* context is %NULL, context is not provided; otherwise, context is provided
|
||||
* (including the case of empty context with context_len == 0).
|
||||
*/
|
||||
int __must_check tls_connection_export_key(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const char *label,
|
||||
const u8 *context,
|
||||
size_t context_len,
|
||||
u8 *out, size_t out_len);
|
||||
|
||||
/**
|
||||
|
@ -461,6 +461,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
if (params->openssl_ecdh_curves) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"GnuTLS: openssl_ecdh_curves not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
|
||||
* to force peer validation(?) */
|
||||
|
||||
@ -733,6 +739,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
struct tls_global *global = tls_ctx;
|
||||
int ret;
|
||||
|
||||
if (params->check_cert_subject)
|
||||
return -1; /* not yet supported */
|
||||
|
||||
/* Currently, global parameters are only set when running in server
|
||||
* mode. */
|
||||
global->server = 1;
|
||||
@ -842,7 +851,7 @@ int tls_global_set_params(void *tls_ctx,
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *ssl_ctx, int check_crl)
|
||||
int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
@ -889,14 +898,23 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
if (conn == NULL || conn->session == NULL)
|
||||
return -1;
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030404
|
||||
return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
|
||||
context_len, (const char *) context,
|
||||
out_len, (char *) out);
|
||||
#else /* 3.4.4 */
|
||||
if (context)
|
||||
return -1;
|
||||
return gnutls_prf(conn->session, os_strlen(label), label,
|
||||
0 /* client_random first */, 0, NULL, out_len,
|
||||
(char *) out);
|
||||
#endif /* 3.4.4 */
|
||||
}
|
||||
|
||||
|
||||
@ -1068,6 +1086,52 @@ static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
|
||||
}
|
||||
|
||||
|
||||
static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
|
||||
int full)
|
||||
{
|
||||
int res = -1;
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030300
|
||||
if (full)
|
||||
res = gnutls_x509_crt_check_hostname2(
|
||||
cert, match,
|
||||
GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
|
||||
#endif /* >= 3.3.0 */
|
||||
if (res == -1)
|
||||
res = gnutls_x509_crt_check_hostname(cert, match);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
|
||||
full ? "": "suffix ", match, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
|
||||
int full)
|
||||
{
|
||||
char *values, *token, *context = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!os_strchr(match, ';'))
|
||||
return tls_match_suffix_helper(cert, match, full);
|
||||
|
||||
values = os_strdup(match);
|
||||
if (!values)
|
||||
return 0;
|
||||
|
||||
/* Process each match alternative separately until a match is found */
|
||||
while ((token = str_token(values, ";", &context))) {
|
||||
if (tls_match_suffix_helper(cert, token, full)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
os_free(values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int tls_connection_verify_peer(gnutls_session_t session)
|
||||
{
|
||||
struct tls_connection *conn;
|
||||
@ -1263,8 +1327,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
|
||||
|
||||
if (i == 0) {
|
||||
if (conn->suffix_match &&
|
||||
!gnutls_x509_crt_check_hostname(
|
||||
cert, conn->suffix_match)) {
|
||||
!tls_match_suffix(cert, conn->suffix_match, 0)) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"TLS: Domain suffix match '%s' not found",
|
||||
conn->suffix_match);
|
||||
@ -1280,9 +1343,7 @@ static int tls_connection_verify_peer(gnutls_session_t session)
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030300
|
||||
if (conn->domain_match &&
|
||||
!gnutls_x509_crt_check_hostname2(
|
||||
cert, conn->domain_match,
|
||||
GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
|
||||
!tls_match_suffix(cert, conn->domain_match, 1)) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
"TLS: Domain match '%s' not found",
|
||||
conn->domain_match);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* TLS interface functions and an internal TLS implementation
|
||||
* Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
|
||||
* 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.
|
||||
@ -248,6 +248,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->openssl_ecdh_curves) {
|
||||
wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_ca_cert(cred, params->ca_cert,
|
||||
params->ca_cert_blob, params->ca_cert_blob_len,
|
||||
params->ca_path)) {
|
||||
@ -303,6 +309,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
struct tls_global *global = tls_ctx;
|
||||
struct tlsv1_credentials *cred;
|
||||
|
||||
if (params->check_cert_subject)
|
||||
return -1; /* not yet supported */
|
||||
|
||||
/* Currently, global parameters are only set when running in server
|
||||
* mode. */
|
||||
global->server = 1;
|
||||
@ -353,7 +362,7 @@ int tls_global_set_params(void *tls_ctx,
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
global->check_crl = check_crl;
|
||||
@ -403,7 +412,8 @@ static int tls_get_keyblock_size(struct tls_connection *conn)
|
||||
|
||||
|
||||
static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, int server_random_first,
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, int server_random_first,
|
||||
int skip_keyblock, u8 *out, size_t out_len)
|
||||
{
|
||||
int ret = -1, skip = 0;
|
||||
@ -422,15 +432,15 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
ret = tlsv1_client_prf(conn->client, label,
|
||||
server_random_first,
|
||||
ret = tlsv1_client_prf(conn->client, label, context,
|
||||
context_len, server_random_first,
|
||||
_out, skip + out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
ret = tlsv1_server_prf(conn->server, label,
|
||||
server_random_first,
|
||||
ret = tlsv1_server_prf(conn->server, label, context,
|
||||
context_len, server_random_first,
|
||||
_out, skip + out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
@ -443,17 +453,19 @@ static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
|
||||
return tls_connection_prf(tls_ctx, conn, label, context, context_len,
|
||||
0, 0, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out,
|
||||
out_len);
|
||||
return tls_connection_prf(tls_ctx, conn, "key expansion", NULL, 0,
|
||||
1, 1, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
@ -720,12 +732,20 @@ int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
|
||||
|
||||
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_failed(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_read_alerts(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -733,6 +753,10 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
|
||||
int tls_connection_get_write_alerts(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_write_alerts(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ int tls_global_set_params(void *tls_ctx,
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -94,7 +94,8 @@ int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -104,7 +104,9 @@ static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
|
||||
|
||||
#endif
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER < 0x20700000L)
|
||||
#ifdef CONFIG_SUITEB
|
||||
static int RSA_bits(const RSA *r)
|
||||
{
|
||||
@ -212,10 +214,17 @@ static struct tls_context *tls_global = NULL;
|
||||
struct tls_data {
|
||||
SSL_CTX *ssl;
|
||||
unsigned int tls_session_lifetime;
|
||||
int check_crl;
|
||||
int check_crl_strict;
|
||||
char *ca_cert;
|
||||
unsigned int crl_reload_interval;
|
||||
struct os_reltime crl_last_reload;
|
||||
char *check_cert_subject;
|
||||
};
|
||||
|
||||
struct tls_connection {
|
||||
struct tls_context *context;
|
||||
struct tls_data *data;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL *ssl;
|
||||
BIO *ssl_in, *ssl_out;
|
||||
@ -224,6 +233,7 @@ struct tls_connection {
|
||||
EVP_PKEY *private_key; /* the private key if using engine */
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
|
||||
char *check_cert_subject;
|
||||
int read_alerts, write_alerts, failed;
|
||||
|
||||
tls_session_ticket_cb session_ticket_cb;
|
||||
@ -301,6 +311,36 @@ static void tls_show_errors(int level, const char *func, const char *txt)
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
|
||||
{
|
||||
int flags;
|
||||
X509_STORE *store;
|
||||
|
||||
store = X509_STORE_new();
|
||||
if (!store) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: %s - failed to allocate new certificate store",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
|
||||
tls_show_errors(MSG_WARNING, __func__,
|
||||
"Failed to load root certificates");
|
||||
X509_STORE_free(store);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
|
||||
if (check_crl == 2)
|
||||
flags |= X509_V_FLAG_CRL_CHECK_ALL;
|
||||
|
||||
X509_STORE_set_flags(store, flags);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
/* Windows CryptoAPI and access to certificate stores */
|
||||
@ -989,8 +1029,10 @@ void * tls_init(const struct tls_config *conf)
|
||||
return NULL;
|
||||
}
|
||||
data->ssl = ssl;
|
||||
if (conf)
|
||||
if (conf) {
|
||||
data->tls_session_lifetime = conf->tls_session_lifetime;
|
||||
data->crl_reload_interval = conf->crl_reload_interval;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
|
||||
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
|
||||
@ -1072,6 +1114,7 @@ void tls_deinit(void *ssl_ctx)
|
||||
os_free(context);
|
||||
if (data->tls_session_lifetime > 0)
|
||||
SSL_CTX_flush_sessions(ssl, 0);
|
||||
os_free(data->ca_cert);
|
||||
SSL_CTX_free(ssl);
|
||||
|
||||
tls_openssl_ref_count--;
|
||||
@ -1093,6 +1136,7 @@ void tls_deinit(void *ssl_ctx)
|
||||
tls_global = NULL;
|
||||
}
|
||||
|
||||
os_free(data->check_cert_subject);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
@ -1305,8 +1349,16 @@ static const char * openssl_handshake_type(int content_type, const u8 *buf,
|
||||
return "client hello";
|
||||
case 2:
|
||||
return "server hello";
|
||||
case 3:
|
||||
return "hello verify request";
|
||||
case 4:
|
||||
return "new session ticket";
|
||||
case 5:
|
||||
return "end of early data";
|
||||
case 6:
|
||||
return "hello retry request";
|
||||
case 8:
|
||||
return "encrypted extensions";
|
||||
case 11:
|
||||
return "certificate";
|
||||
case 12:
|
||||
@ -1325,6 +1377,12 @@ static const char * openssl_handshake_type(int content_type, const u8 *buf,
|
||||
return "certificate url";
|
||||
case 22:
|
||||
return "certificate status";
|
||||
case 23:
|
||||
return "supplemental data";
|
||||
case 24:
|
||||
return "key update";
|
||||
case 254:
|
||||
return "message hash";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
@ -1467,11 +1525,32 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
|
||||
SSL_CTX *ssl = data->ssl;
|
||||
struct tls_connection *conn;
|
||||
long options;
|
||||
X509_STORE *new_cert_store;
|
||||
struct os_reltime now;
|
||||
struct tls_context *context = SSL_CTX_get_app_data(ssl);
|
||||
|
||||
/* Replace X509 store if it is time to update CRL. */
|
||||
if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
|
||||
os_reltime_expired(&now, &data->crl_last_reload,
|
||||
data->crl_reload_interval)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Flushing X509 store with ca_cert file");
|
||||
new_cert_store = tls_crl_cert_reload(data->ca_cert,
|
||||
data->check_crl);
|
||||
if (!new_cert_store) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OpenSSL: Error replacing X509 store with ca_cert file");
|
||||
} else {
|
||||
/* Replace old store */
|
||||
SSL_CTX_set_cert_store(ssl, new_cert_store);
|
||||
data->crl_last_reload = now;
|
||||
}
|
||||
}
|
||||
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
conn->data = data;
|
||||
conn->ssl_ctx = ssl;
|
||||
conn->ssl = SSL_new(ssl);
|
||||
if (conn->ssl == NULL) {
|
||||
@ -1535,6 +1614,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
|
||||
os_free(conn->altsubject_match);
|
||||
os_free(conn->suffix_match);
|
||||
os_free(conn->domain_match);
|
||||
os_free(conn->check_cert_subject);
|
||||
os_free(conn->session_ticket);
|
||||
os_free(conn);
|
||||
}
|
||||
@ -1655,9 +1735,9 @@ static int tls_match_altsubject(X509 *cert, const char *match)
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
static int domain_suffix_match(const u8 *val, size_t len, const char *match,
|
||||
int full)
|
||||
size_t match_len, int full)
|
||||
{
|
||||
size_t i, match_len;
|
||||
size_t i;
|
||||
|
||||
/* Check for embedded nuls that could mess up suffix matching */
|
||||
for (i = 0; i < len; i++) {
|
||||
@ -1667,7 +1747,6 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
|
||||
}
|
||||
}
|
||||
|
||||
match_len = os_strlen(match);
|
||||
if (match_len > len || (full && match_len != len))
|
||||
return 0;
|
||||
|
||||
@ -1687,12 +1766,223 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match,
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
|
||||
static int tls_match_suffix(X509 *cert, const char *match, int full)
|
||||
struct tls_dn_field_order_cnt {
|
||||
u8 cn;
|
||||
u8 c;
|
||||
u8 l;
|
||||
u8 st;
|
||||
u8 o;
|
||||
u8 ou;
|
||||
u8 email;
|
||||
};
|
||||
|
||||
|
||||
static int get_dn_field_index(const struct tls_dn_field_order_cnt *dn_cnt,
|
||||
int nid)
|
||||
{
|
||||
switch (nid) {
|
||||
case NID_commonName:
|
||||
return dn_cnt->cn;
|
||||
case NID_countryName:
|
||||
return dn_cnt->c;
|
||||
case NID_localityName:
|
||||
return dn_cnt->l;
|
||||
case NID_stateOrProvinceName:
|
||||
return dn_cnt->st;
|
||||
case NID_organizationName:
|
||||
return dn_cnt->o;
|
||||
case NID_organizationalUnitName:
|
||||
return dn_cnt->ou;
|
||||
case NID_pkcs9_emailAddress:
|
||||
return dn_cnt->email;
|
||||
default:
|
||||
wpa_printf(MSG_ERROR,
|
||||
"TLS: Unknown NID '%d' in check_cert_subject",
|
||||
nid);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* match_dn_field - Match configuration DN field against Certificate DN field
|
||||
* @cert: Certificate
|
||||
* @nid: NID of DN field
|
||||
* @field: Field name
|
||||
* @value DN field value which is passed from configuration
|
||||
* e.g., if configuration have C=US and this argument will point to US.
|
||||
* @dn_cnt: DN matching context
|
||||
* Returns: 1 on success and 0 on failure
|
||||
*/
|
||||
static int match_dn_field(const X509 *cert, int nid, const char *field,
|
||||
const char *value,
|
||||
const struct tls_dn_field_order_cnt *dn_cnt)
|
||||
{
|
||||
int i, ret = 0, len, config_dn_field_index, match_index = 0;
|
||||
X509_NAME *name;
|
||||
|
||||
len = os_strlen(value);
|
||||
name = X509_get_subject_name((X509 *) cert);
|
||||
|
||||
/* Assign incremented cnt for every field of DN to check DN field in
|
||||
* right order */
|
||||
config_dn_field_index = get_dn_field_index(dn_cnt, nid);
|
||||
if (config_dn_field_index < 0)
|
||||
return 0;
|
||||
|
||||
/* Fetch value based on NID */
|
||||
for (i = -1; (i = X509_NAME_get_index_by_NID(name, nid, i)) > -1;) {
|
||||
X509_NAME_ENTRY *e;
|
||||
ASN1_STRING *cn;
|
||||
|
||||
e = X509_NAME_get_entry(name, i);
|
||||
if (!e)
|
||||
continue;
|
||||
|
||||
cn = X509_NAME_ENTRY_get_data(e);
|
||||
if (!cn)
|
||||
continue;
|
||||
|
||||
match_index++;
|
||||
|
||||
/* check for more than one DN field with same name */
|
||||
if (match_index != config_dn_field_index)
|
||||
continue;
|
||||
|
||||
/* Check wildcard at the right end side */
|
||||
/* E.g., if OU=develop* mentioned in configuration, allow 'OU'
|
||||
* of the subject in the client certificate to start with
|
||||
* 'develop' */
|
||||
if (len > 0 && value[len - 1] == '*') {
|
||||
/* Compare actual certificate DN field value with
|
||||
* configuration DN field value up to the specified
|
||||
* length. */
|
||||
ret = ASN1_STRING_length(cn) >= len - 1 &&
|
||||
os_memcmp(ASN1_STRING_get0_data(cn), value,
|
||||
len - 1) == 0;
|
||||
} else {
|
||||
/* Compare actual certificate DN field value with
|
||||
* configuration DN field value */
|
||||
ret = ASN1_STRING_length(cn) == len &&
|
||||
os_memcmp(ASN1_STRING_get0_data(cn), value,
|
||||
len) == 0;
|
||||
}
|
||||
if (!ret) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OpenSSL: Failed to match %s '%s' with certificate DN field value '%s'",
|
||||
field, value, ASN1_STRING_get0_data(cn));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_value_from_field - Get value from DN field
|
||||
* @cert: Certificate
|
||||
* @field_str: DN field string which is passed from configuration file (e.g.,
|
||||
* C=US)
|
||||
* @dn_cnt: DN matching context
|
||||
* Returns: 1 on success and 0 on failure
|
||||
*/
|
||||
static int get_value_from_field(const X509 *cert, char *field_str,
|
||||
struct tls_dn_field_order_cnt *dn_cnt)
|
||||
{
|
||||
int nid;
|
||||
char *context = NULL, *name, *value;
|
||||
|
||||
if (os_strcmp(field_str, "*") == 0)
|
||||
return 1; /* wildcard matches everything */
|
||||
|
||||
name = str_token(field_str, "=", &context);
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
/* Compare all configured DN fields and assign nid based on that to
|
||||
* fetch correct value from certificate subject */
|
||||
if (os_strcmp(name, "CN") == 0) {
|
||||
nid = NID_commonName;
|
||||
dn_cnt->cn++;
|
||||
} else if(os_strcmp(name, "C") == 0) {
|
||||
nid = NID_countryName;
|
||||
dn_cnt->c++;
|
||||
} else if (os_strcmp(name, "L") == 0) {
|
||||
nid = NID_localityName;
|
||||
dn_cnt->l++;
|
||||
} else if (os_strcmp(name, "ST") == 0) {
|
||||
nid = NID_stateOrProvinceName;
|
||||
dn_cnt->st++;
|
||||
} else if (os_strcmp(name, "O") == 0) {
|
||||
nid = NID_organizationName;
|
||||
dn_cnt->o++;
|
||||
} else if (os_strcmp(name, "OU") == 0) {
|
||||
nid = NID_organizationalUnitName;
|
||||
dn_cnt->ou++;
|
||||
} else if (os_strcmp(name, "emailAddress") == 0) {
|
||||
nid = NID_pkcs9_emailAddress;
|
||||
dn_cnt->email++;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"TLS: Unknown field '%s' in check_cert_subject", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = str_token(field_str, "=", &context);
|
||||
if (!value) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"TLS: Distinguished Name field '%s' value is not defined in check_cert_subject",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return match_dn_field(cert, nid, name, value, dn_cnt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tls_match_dn_field - Match subject DN field with check_cert_subject
|
||||
* @cert: Certificate
|
||||
* @match: check_cert_subject string
|
||||
* Returns: Return 1 on success and 0 on failure
|
||||
*/
|
||||
static int tls_match_dn_field(X509 *cert, const char *match)
|
||||
{
|
||||
const char *token, *last = NULL;
|
||||
char field[256];
|
||||
struct tls_dn_field_order_cnt dn_cnt;
|
||||
|
||||
os_memset(&dn_cnt, 0, sizeof(dn_cnt));
|
||||
|
||||
/* Maximum length of each DN field is 255 characters */
|
||||
|
||||
/* Process each '/' delimited field */
|
||||
while ((token = cstr_token(match, "/", &last))) {
|
||||
if (last - token >= (int) sizeof(field)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"OpenSSL: Too long DN matching field value in '%s'",
|
||||
match);
|
||||
return 0;
|
||||
}
|
||||
os_memcpy(field, token, last - token);
|
||||
field[last - token] = '\0';
|
||||
|
||||
if (!get_value_from_field(cert, field, &dn_cnt)) {
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: No match for DN '%s'",
|
||||
field);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
static int tls_match_suffix_helper(X509 *cert, const char *match,
|
||||
size_t match_len, int full)
|
||||
{
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
/* wincrypt.h has conflicting X509_NAME definition */
|
||||
return -1;
|
||||
#else /* CONFIG_NATIVE_WINDOWS */
|
||||
GENERAL_NAME *gen;
|
||||
void *ext;
|
||||
int i;
|
||||
@ -1714,8 +2004,8 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
|
||||
gen->d.dNSName->data,
|
||||
gen->d.dNSName->length);
|
||||
if (domain_suffix_match(gen->d.dNSName->data,
|
||||
gen->d.dNSName->length, match, full) ==
|
||||
1) {
|
||||
gen->d.dNSName->length,
|
||||
match, match_len, full) == 1) {
|
||||
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
|
||||
full ? "Match" : "Suffix match");
|
||||
sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
|
||||
@ -1746,8 +2036,8 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
|
||||
continue;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
|
||||
cn->data, cn->length);
|
||||
if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
|
||||
{
|
||||
if (domain_suffix_match(cn->data, cn->length,
|
||||
match, match_len, full) == 1) {
|
||||
wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
|
||||
full ? "Match" : "Suffix match");
|
||||
return 1;
|
||||
@ -1757,6 +2047,25 @@ static int tls_match_suffix(X509 *cert, const char *match, int full)
|
||||
wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
|
||||
full ? "": "suffix ");
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
|
||||
static int tls_match_suffix(X509 *cert, const char *match, int full)
|
||||
{
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
/* wincrypt.h has conflicting X509_NAME definition */
|
||||
return -1;
|
||||
#else /* CONFIG_NATIVE_WINDOWS */
|
||||
const char *token, *last = NULL;
|
||||
|
||||
/* Process each match alternative separately until a match is found */
|
||||
while ((token = cstr_token(match, ";", &last))) {
|
||||
if (tls_match_suffix_helper(cert, token, last - token, full))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
}
|
||||
|
||||
@ -1951,6 +2260,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
struct tls_connection *conn;
|
||||
struct tls_context *context;
|
||||
char *match, *altmatch, *suffix_match, *domain_match;
|
||||
const char *check_cert_subject;
|
||||
const char *err_str;
|
||||
|
||||
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
@ -1991,6 +2301,13 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
"time mismatch");
|
||||
preverify_ok = 1;
|
||||
}
|
||||
if (!preverify_ok && !conn->data->check_crl_strict &&
|
||||
(err == X509_V_ERR_CRL_HAS_EXPIRED ||
|
||||
err == X509_V_ERR_CRL_NOT_YET_VALID)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Ignore certificate validity CRL time mismatch");
|
||||
preverify_ok = 1;
|
||||
}
|
||||
|
||||
err_str = X509_verify_cert_error_string(err);
|
||||
|
||||
@ -2044,6 +2361,18 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
"err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
|
||||
preverify_ok, err, err_str,
|
||||
conn->ca_cert_verify, depth, buf);
|
||||
check_cert_subject = conn->check_cert_subject;
|
||||
if (!check_cert_subject)
|
||||
check_cert_subject = conn->data->check_cert_subject;
|
||||
if (check_cert_subject) {
|
||||
if (depth == 0 &&
|
||||
!tls_match_dn_field(err_cert, check_cert_subject)) {
|
||||
preverify_ok = 0;
|
||||
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
|
||||
"Distinguished Name",
|
||||
TLS_FAIL_DN_MISMATCH);
|
||||
}
|
||||
}
|
||||
if (depth == 0 && match && os_strstr(buf, match) == NULL) {
|
||||
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
|
||||
"match with '%s'", buf, match);
|
||||
@ -2381,13 +2710,16 @@ static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
|
||||
SSL_CTX_set_client_CA_list(ssl_ctx,
|
||||
SSL_load_client_CA_file(ca_cert));
|
||||
#endif /* OPENSSL_NO_STDIO */
|
||||
|
||||
os_free(data->ca_cert);
|
||||
data->ca_cert = os_strdup(ca_cert);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *ssl_ctx, int check_crl)
|
||||
int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
|
||||
{
|
||||
int flags;
|
||||
|
||||
@ -2404,6 +2736,10 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
|
||||
if (check_crl == 2)
|
||||
flags |= X509_V_FLAG_CRL_CHECK_ALL;
|
||||
X509_STORE_set_flags(cs, flags);
|
||||
|
||||
data->check_crl = check_crl;
|
||||
data->check_crl_strict = strict;
|
||||
os_get_reltime(&data->crl_last_reload);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2413,7 +2749,8 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
|
||||
const char *subject_match,
|
||||
const char *altsubject_match,
|
||||
const char *suffix_match,
|
||||
const char *domain_match)
|
||||
const char *domain_match,
|
||||
const char *check_cert_subject)
|
||||
{
|
||||
os_free(conn->subject_match);
|
||||
conn->subject_match = NULL;
|
||||
@ -2447,6 +2784,14 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(conn->check_cert_subject);
|
||||
conn->check_cert_subject = NULL;
|
||||
if (check_cert_subject) {
|
||||
conn->check_cert_subject = os_strdup(check_cert_subject);
|
||||
if (!conn->check_cert_subject)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2519,6 +2864,38 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
|
||||
else
|
||||
SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
|
||||
#endif /* SSL_OP_NO_TLSv1_3 */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
|
||||
TLS_CONN_ENABLE_TLSv1_1 |
|
||||
TLS_CONN_ENABLE_TLSv1_2)) {
|
||||
int version = 0;
|
||||
|
||||
/* Explicit request to enable TLS versions even if needing to
|
||||
* override systemwide policies. */
|
||||
if (flags & TLS_CONN_ENABLE_TLSv1_0) {
|
||||
version = TLS1_VERSION;
|
||||
} else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
|
||||
if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
|
||||
version = TLS1_1_VERSION;
|
||||
} else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
|
||||
if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
|
||||
TLS_CONN_DISABLE_TLSv1_1)))
|
||||
version = TLS1_2_VERSION;
|
||||
}
|
||||
if (!version) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Invalid TLS version configuration");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_set_min_proto_version(ssl, version) != 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OpenSSL: Failed to set minimum TLS version");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* >= 1.1.0 */
|
||||
|
||||
#ifdef CONFIG_SUITEB
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
/* Start with defaults from BoringSSL */
|
||||
@ -2621,7 +2998,22 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
|
||||
openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set openssl_ciphers '%s'",
|
||||
openssl_ciphers);
|
||||
return -1;
|
||||
}
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
#else /* CONFIG_SUITEB */
|
||||
if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set openssl_ciphers '%s'",
|
||||
openssl_ciphers);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_SUITEB */
|
||||
|
||||
return 0;
|
||||
@ -2743,6 +3135,15 @@ static int tls_connection_client_cert(struct tls_connection *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
|
||||
if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
|
||||
ERR_clear_error();
|
||||
wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
|
||||
" --> OK");
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (SSL_use_certificate_file(conn->ssl, client_cert,
|
||||
SSL_FILETYPE_PEM) == 1) {
|
||||
ERR_clear_error();
|
||||
@ -2750,6 +3151,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
|
||||
" --> OK");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
tls_show_errors(MSG_DEBUG, __func__,
|
||||
"SSL_use_certificate_file failed");
|
||||
@ -3523,11 +3925,13 @@ static int openssl_get_keyblock_size(SSL *ssl)
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
if (!conn ||
|
||||
SSL_export_keying_material(conn->ssl, out, out_len, label,
|
||||
os_strlen(label), NULL, 0, 0) != 1)
|
||||
os_strlen(label), context, context_len,
|
||||
context != NULL) != 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@ -4445,7 +4849,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
params->subject_match,
|
||||
params->altsubject_match,
|
||||
params->suffix_match,
|
||||
params->domain_match))
|
||||
params->domain_match,
|
||||
params->check_cert_subject))
|
||||
return -1;
|
||||
|
||||
if (engine_id && ca_cert_id) {
|
||||
@ -4503,6 +4908,40 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!params->openssl_ecdh_curves) {
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
#ifndef OPENSSL_NO_EC
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
|
||||
(OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set ECDH curves to auto");
|
||||
return -1;
|
||||
}
|
||||
#endif /* >= 1.0.2 && < 1.1.0 */
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
} else if (params->openssl_ecdh_curves[0]) {
|
||||
#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: ECDH configuration nnot supported");
|
||||
return -1;
|
||||
#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
|
||||
#ifndef OPENSSL_NO_EC
|
||||
if (SSL_set1_curves_list(conn->ssl,
|
||||
params->openssl_ecdh_curves) != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set ECDH curves '%s'",
|
||||
params->openssl_ecdh_curves);
|
||||
return -1;
|
||||
}
|
||||
#else /* OPENSSL_NO_EC */
|
||||
wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
|
||||
return -1;
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
}
|
||||
|
||||
if (tls_set_conn_flags(conn, params->flags,
|
||||
params->openssl_ciphers) < 0)
|
||||
return -1;
|
||||
@ -4552,6 +4991,15 @@ int tls_global_set_params(void *tls_ctx,
|
||||
__func__, ERR_error_string(err, NULL));
|
||||
}
|
||||
|
||||
os_free(data->check_cert_subject);
|
||||
data->check_cert_subject = NULL;
|
||||
if (params->check_cert_subject) {
|
||||
data->check_cert_subject =
|
||||
os_strdup(params->check_cert_subject);
|
||||
if (!data->check_cert_subject)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls_global_ca_cert(data, params->ca_cert) ||
|
||||
tls_global_client_cert(data, params->client_cert) ||
|
||||
tls_global_private_key(data, params->private_key,
|
||||
@ -4569,6 +5017,44 @@ int tls_global_set_params(void *tls_ctx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!params->openssl_ecdh_curves) {
|
||||
#ifndef OPENSSL_IS_BORINGSSL
|
||||
#ifndef OPENSSL_NO_EC
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
|
||||
(OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set ECDH curves to auto");
|
||||
return -1;
|
||||
}
|
||||
#endif /* >= 1.0.2 && < 1.1.0 */
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
} else if (params->openssl_ecdh_curves[0]) {
|
||||
#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: ECDH configuration nnot supported");
|
||||
return -1;
|
||||
#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
|
||||
#ifndef OPENSSL_NO_EC
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
|
||||
#endif
|
||||
if (SSL_CTX_set1_curves_list(ssl_ctx,
|
||||
params->openssl_ecdh_curves) !=
|
||||
1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"OpenSSL: Failed to set ECDH curves '%s'",
|
||||
params->openssl_ecdh_curves);
|
||||
return -1;
|
||||
}
|
||||
#else /* OPENSSL_NO_EC */
|
||||
wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
|
||||
return -1;
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
}
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
|
||||
|
@ -643,9 +643,9 @@ static int tls_match_alt_subject(WOLFSSL_X509 *cert, const char *match)
|
||||
|
||||
|
||||
static int domain_suffix_match(const char *val, size_t len, const char *match,
|
||||
int full)
|
||||
size_t match_len, int full)
|
||||
{
|
||||
size_t i, match_len;
|
||||
size_t i;
|
||||
|
||||
/* Check for embedded nuls that could mess up suffix matching */
|
||||
for (i = 0; i < len; i++) {
|
||||
@ -656,7 +656,6 @@ static int domain_suffix_match(const char *val, size_t len, const char *match,
|
||||
}
|
||||
}
|
||||
|
||||
match_len = os_strlen(match);
|
||||
if (match_len > len || (full && match_len != len))
|
||||
return 0;
|
||||
|
||||
@ -674,7 +673,8 @@ static int domain_suffix_match(const char *val, size_t len, const char *match,
|
||||
}
|
||||
|
||||
|
||||
static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
|
||||
static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match,
|
||||
size_t match_len, int full)
|
||||
{
|
||||
WOLFSSL_ASN1_OBJECT *gen;
|
||||
void *ext;
|
||||
@ -690,14 +690,14 @@ static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
|
||||
|
||||
for (j = 0; ext && j < wolfSSL_sk_num(ext); j++) {
|
||||
gen = wolfSSL_sk_value(ext, j);
|
||||
if (gen->type != ALT_NAMES_OID)
|
||||
if (gen->type != ASN_DNS_TYPE)
|
||||
continue;
|
||||
dns_name++;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
|
||||
gen->obj, os_strlen((char *)gen->obj));
|
||||
if (domain_suffix_match((const char *) gen->obj,
|
||||
os_strlen((char *) gen->obj), match,
|
||||
full) == 1) {
|
||||
match_len, full) == 1) {
|
||||
wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
|
||||
full ? "Match" : "Suffix match");
|
||||
wolfSSL_sk_ASN1_OBJECT_free(ext);
|
||||
@ -729,8 +729,8 @@ static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
|
||||
continue;
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
|
||||
cn->data, cn->length);
|
||||
if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
|
||||
{
|
||||
if (domain_suffix_match(cn->data, cn->length,
|
||||
match, match_len, full) == 1) {
|
||||
wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
|
||||
full ? "Match" : "Suffix match");
|
||||
return 1;
|
||||
@ -743,6 +743,20 @@ static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
|
||||
}
|
||||
|
||||
|
||||
static int tls_match_suffix(WOLFSSL_X509 *cert, const char *match, int full)
|
||||
{
|
||||
const char *token, *last = NULL;
|
||||
|
||||
/* Process each match alternative separately until a match is found */
|
||||
while ((token = cstr_token(match, ";", &last))) {
|
||||
if (tls_match_suffix_helper(cert, token, last - token, full))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static enum tls_fail_reason wolfssl_tls_fail_reason(int err)
|
||||
{
|
||||
switch (err) {
|
||||
@ -1487,6 +1501,9 @@ int tls_global_set_params(void *tls_ctx,
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "SSL: global set params");
|
||||
|
||||
if (params->check_cert_subject)
|
||||
return -1; /* not yet supported */
|
||||
|
||||
if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
|
||||
wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
|
||||
params->ca_cert);
|
||||
@ -1524,6 +1541,12 @@ int tls_global_set_params(void *tls_ctx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (params->openssl_ecdh_curves) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"wolfSSL: openssl_ecdh_curves not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
/* Session ticket is off by default - can't disable once on. */
|
||||
if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
|
||||
@ -1543,7 +1566,7 @@ int tls_global_set_params(void *tls_ctx,
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
|
||||
|
||||
@ -1964,8 +1987,11 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
|
||||
|
||||
|
||||
int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, u8 *out, size_t out_len)
|
||||
const char *label, const u8 *context,
|
||||
size_t context_len, u8 *out, size_t out_len)
|
||||
{
|
||||
if (context)
|
||||
return -1;
|
||||
if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
@ -58,6 +58,16 @@
|
||||
#define HOSTAPD_CHAN_VHT_130_30 0x04000000
|
||||
#define HOSTAPD_CHAN_VHT_150_10 0x08000000
|
||||
|
||||
/* Allowed bandwidth mask */
|
||||
enum hostapd_chan_width_attr {
|
||||
HOSTAPD_CHAN_WIDTH_10 = BIT(0),
|
||||
HOSTAPD_CHAN_WIDTH_20 = BIT(1),
|
||||
HOSTAPD_CHAN_WIDTH_40P = BIT(2),
|
||||
HOSTAPD_CHAN_WIDTH_40M = BIT(3),
|
||||
HOSTAPD_CHAN_WIDTH_80 = BIT(4),
|
||||
HOSTAPD_CHAN_WIDTH_160 = BIT(5),
|
||||
};
|
||||
|
||||
/* Filter gratuitous ARP */
|
||||
#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
|
||||
/* Filter unsolicited Neighbor Advertisement */
|
||||
@ -110,6 +120,13 @@ struct hostapd_channel_data {
|
||||
*/
|
||||
int flag;
|
||||
|
||||
/**
|
||||
* allowed_bw - Allowed channel width bitmask
|
||||
*
|
||||
* See enum hostapd_chan_width_attr.
|
||||
*/
|
||||
u32 allowed_bw;
|
||||
|
||||
/**
|
||||
* max_tx_power - Regulatory transmit power limit in dBm
|
||||
*/
|
||||
@ -914,10 +931,10 @@ struct wpa_driver_associate_params {
|
||||
* passphrase - RSN passphrase for PSK
|
||||
*
|
||||
* This value is made available only for WPA/WPA2-Personal (PSK) and
|
||||
* only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
|
||||
* the 8..63 character ASCII passphrase, if available. Please note that
|
||||
* this can be %NULL if passphrase was not used to generate the PSK. In
|
||||
* that case, the psk field must be used to fetch the PSK.
|
||||
* only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
|
||||
* is the 8..63 character ASCII passphrase, if available. Please note
|
||||
* that this can be %NULL if passphrase was not used to generate the
|
||||
* PSK. In that case, the psk field must be used to fetch the PSK.
|
||||
*/
|
||||
const char *passphrase;
|
||||
|
||||
@ -925,9 +942,9 @@ struct wpa_driver_associate_params {
|
||||
* psk - RSN PSK (alternative for passphrase for PSK)
|
||||
*
|
||||
* This value is made available only for WPA/WPA2-Personal (PSK) and
|
||||
* only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
|
||||
* the 32-octet (256-bit) PSK, if available. The driver wrapper should
|
||||
* be prepared to handle %NULL value as an error.
|
||||
* only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
|
||||
* is the 32-octet (256-bit) PSK, if available. The driver wrapper
|
||||
* should be prepared to handle %NULL value as an error.
|
||||
*/
|
||||
const u8 *psk;
|
||||
|
||||
@ -1367,6 +1384,23 @@ struct wpa_driver_ap_params {
|
||||
* service).
|
||||
*/
|
||||
int multicast_to_unicast;
|
||||
|
||||
/**
|
||||
* ftm_responder - Whether FTM responder is enabled
|
||||
*/
|
||||
int ftm_responder;
|
||||
|
||||
/**
|
||||
* lci - Binary data, the content of an LCI report IE with type 8 as
|
||||
* defined in IEEE Std 802.11-2016, 9.4.2.22.10
|
||||
*/
|
||||
const struct wpabuf *lci;
|
||||
|
||||
/**
|
||||
* civic - Binary data, the content of a measurement report IE with
|
||||
* type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
|
||||
*/
|
||||
const struct wpabuf *civic;
|
||||
};
|
||||
|
||||
struct wpa_driver_mesh_bss_params {
|
||||
@ -1424,6 +1458,7 @@ struct wpa_driver_capa {
|
||||
#define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 0x00002000
|
||||
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
|
||||
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
|
||||
#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
|
||||
/** Bitfield of supported key management suites */
|
||||
unsigned int key_mgmt;
|
||||
|
||||
@ -1457,7 +1492,7 @@ struct wpa_driver_capa {
|
||||
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
|
||||
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
|
||||
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
|
||||
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
|
||||
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
|
||||
/** Driver is for a wired Ethernet interface */
|
||||
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
|
||||
/** Driver provides separate commands for authentication and association (SME in
|
||||
@ -1579,6 +1614,10 @@ struct wpa_driver_capa {
|
||||
#define WPA_DRIVER_FLAGS_MFP_OPTIONAL 0x0040000000000000ULL
|
||||
/** Driver is a self-managed regulatory device */
|
||||
#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY 0x0080000000000000ULL
|
||||
/** Driver supports FTM responder functionality */
|
||||
#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
|
||||
/** Driver support 4-way handshake offload for WPA-Personal */
|
||||
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
|
||||
u64 flags;
|
||||
|
||||
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
|
||||
@ -1902,17 +1941,6 @@ enum smps_mode {
|
||||
SMPS_INVALID,
|
||||
};
|
||||
|
||||
/* enum chan_width - Channel width definitions */
|
||||
enum chan_width {
|
||||
CHAN_WIDTH_20_NOHT,
|
||||
CHAN_WIDTH_20,
|
||||
CHAN_WIDTH_40,
|
||||
CHAN_WIDTH_80,
|
||||
CHAN_WIDTH_80P80,
|
||||
CHAN_WIDTH_160,
|
||||
CHAN_WIDTH_UNKNOWN
|
||||
};
|
||||
|
||||
#define WPA_INVALID_NOISE 9999
|
||||
|
||||
/**
|
||||
@ -1942,6 +1970,26 @@ struct wpa_signal_info {
|
||||
int center_frq2;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wpa_channel_info - Information about the current channel
|
||||
* @frequency: Center frequency of the primary 20 MHz channel
|
||||
* @chanwidth: Width of the current operating channel
|
||||
* @sec_channel: Location of the secondary 20 MHz channel (either +1 or -1).
|
||||
* This field is only filled in when using a 40 MHz channel.
|
||||
* @center_frq1: Center frequency of frequency segment 0
|
||||
* @center_frq2: Center frequency of frequency segment 1 (for 80+80 channels)
|
||||
* @seg1_idx: Frequency segment 1 index when using a 80+80 channel. This is
|
||||
* derived from center_frq2 for convenience.
|
||||
*/
|
||||
struct wpa_channel_info {
|
||||
u32 frequency;
|
||||
enum chan_width chanwidth;
|
||||
int sec_channel;
|
||||
int center_frq1;
|
||||
int center_frq2;
|
||||
u8 seg1_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct beacon_data - Beacon data
|
||||
* @head: Head portion of Beacon frame (before TIM IE)
|
||||
@ -2108,17 +2156,19 @@ enum wpa_drv_update_connect_params_mask {
|
||||
* use %WLAN_STATUS_UNSPECIFIED_FAILURE if wpa_supplicant cannot give
|
||||
* the real status code for failures. Used only for the request interface
|
||||
* from user space to the driver.
|
||||
* @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
|
||||
*/
|
||||
struct external_auth {
|
||||
enum {
|
||||
EXT_AUTH_START,
|
||||
EXT_AUTH_ABORT,
|
||||
} action;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
const u8 *bssid;
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
unsigned int key_mgmt_suite;
|
||||
u16 status;
|
||||
const u8 *pmkid;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3377,6 +3427,14 @@ struct wpa_driver_ops {
|
||||
*/
|
||||
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
|
||||
|
||||
/**
|
||||
* channel_info - Get parameters of the current operating channel
|
||||
* @priv: Private driver interface data
|
||||
* @channel_info: Channel info structure
|
||||
* Returns: 0 on success, negative (<0) on failure
|
||||
*/
|
||||
int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
|
||||
|
||||
/**
|
||||
* set_authmode - Set authentication algorithm(s) for static WEP
|
||||
* @priv: Private driver interface data
|
||||
@ -3658,7 +3716,7 @@ struct wpa_driver_ops {
|
||||
/**
|
||||
* status - Get driver interface status information
|
||||
* @priv: Private driver interface data
|
||||
* @buf: Buffer for printing tou the status information
|
||||
* @buf: Buffer for printing the status information
|
||||
* @buflen: Maximum length of the buffer
|
||||
* Returns: Length of written status information or -1 on failure
|
||||
*/
|
||||
@ -3781,6 +3839,14 @@ struct wpa_driver_ops {
|
||||
*/
|
||||
int (*set_transmit_next_pn)(void *priv, struct transmit_sa *sa);
|
||||
|
||||
/**
|
||||
* set_receive_lowest_pn - Set receive lowest PN
|
||||
* @priv: Private driver interface data
|
||||
* @sa: secure association
|
||||
* Returns: 0 on success, -1 on failure (or if not supported)
|
||||
*/
|
||||
int (*set_receive_lowest_pn)(void *priv, struct receive_sa *sa);
|
||||
|
||||
/**
|
||||
* create_receive_sc - create secure channel for receiving
|
||||
* @priv: Private driver interface data
|
||||
@ -4092,6 +4158,15 @@ struct wpa_driver_ops {
|
||||
*/
|
||||
int (*send_external_auth_status)(void *priv,
|
||||
struct external_auth *params);
|
||||
|
||||
/**
|
||||
* set_4addr_mode - Set 4-address mode
|
||||
* @priv: Private driver interface data
|
||||
* @bridge_ifname: Bridge interface name
|
||||
* @val: 0 - disable 4addr mode, 1 - enable 4addr mode
|
||||
* Returns: 0 on success, < 0 on failure
|
||||
*/
|
||||
int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -5534,6 +5609,8 @@ const char * event_to_string(enum wpa_event_type event);
|
||||
/* Convert chan_width to a string for logging and control interfaces */
|
||||
const char * channel_width_to_string(enum chan_width width);
|
||||
|
||||
int channel_width_to_int(enum chan_width width);
|
||||
|
||||
int ht_supported(const struct hostapd_hw_modes *mode);
|
||||
int vht_supported(const struct hostapd_hw_modes *mode);
|
||||
|
||||
|
@ -142,7 +142,7 @@ bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg,
|
||||
ireq->i_data = arg;
|
||||
|
||||
if (ioctl(drv->global->sock, SIOCG80211, ireq) < 0) {
|
||||
wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, "
|
||||
wpa_printf(MSG_ERROR, "ioctl[SIOCG80211, op=%u, "
|
||||
"arg_len=%u]: %s", op, arg_len, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user