aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2015-01-21 13:19:05 -0800
committerDmitry Shmidt <dimitrysh@google.com>2015-01-21 13:26:50 -0800
commit2f74e36e84064ffa32f82f3decf36b653c7e4fad (patch)
tree184eb654d7eeb89fbca4b8735baf64c07c1c721d
parentff787d557db719adea0fdf2679667500c65cf74d (diff)
downloadandroid_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.tar.gz
android_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.tar.bz2
android_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.zip
Cumulative patch from commit fb09ed338919db09f3990196171fa73b37e7a17f (DO NOT MERGE)
fb09ed3 Interworking: Notify the ANQP parsing status d10b01d HS20: Provide appropriate permission to the OSU related files 73f1ee0 HS20: Fix TrustRoot path for PolicyUpdate node in PPS MO 54a0ac0 HS20: Return result of cmd_sub_rem in hs20-osu-client b62b0cb WNM: Fix possible memory leak by free buf 9bd0273 EAP: Fix possible memory leak in eap_ttls_process_decrypted() b760e64 eap_server: Avoid NULL pointer dereference in eap_fast_encrypt_phase2() 948d3a8 hostapd: Remove unused variable from hostapd_get_hw_features dd09e42 Fix memory leak in wpa_supplicant global bgscan configuration 30f459c wpa_cli: Fix NULL dereference on printf string argument 414f23d Avoid NULL string in printf on EAP method names in authenticator b72b2ad P2P: Stop p2p_listen/find on wpas_p2p_invite 7b7b444 nl80211: Fix reading of the extended capabilities mask 7e608d1 P2P: Use the correct wpa_s interface to handle P2P state flush fd83335 AP: Enable HT Tx STBC for AP/GO if supported by driver d90bfa9 Move external_scan_running to wpa_radio 0c5f01f Clear reattach flag in fast associate flow 8ad8bc5 NFC: Redirect NFC commands on global control interface 57ae1f5 P2P: Fix P2P invitation with NFC 07565ab WNM: Fix the length of WNM_BSS_QUERY control interface command 2d9c99e Retry scan-for-connect if driver trigger fails 911942e Add a test framework for various wpa_supplicant failure cases 6b46bfa WPS: Re-fix an interoperability issue with mixed mode and AP Settings 1648cc6 ACS: Allow subset of channels to be configured 95ff306 nl80211: Allow HT/VHT to be disabled for IBSS 7451a21 mesh: Return negative value on join failed 5a2a6de mesh: Make inactivity timer configurable b9749ba AP: Expire STA without entry in kernel a114c72 AP: Remove redundant condition for STA expiration 0d787f0 Fix RADIUS client with out-of-memory and missing shared secret 0efcad2 Print in debug log whether attached monitor is for global interface 8266e6c HS 2.0: Try to use same BSS entry for storing GAS results 6c69991 Make wpa_supplicant FLUSH command more likely to clear all BSS entries 2dbe63a Write reason for scan only_new_results into debug log 242b83a eapol_test: Fix cert_cb() function arguments a8826b1 Interworking: Avoid busy loop in scan result mismatch corner cases edd5939 Interworking: Start ANQP fetch from eloop callback cbc210d RADIUS DAS: Allow PMKSA cache entry to be removed without association 4e871ed RADIUS DAS: Support Acct-Multi-Session-Id as a session identifier b52c0d4 Add authMultiSessionId into hostapd STA info 861beb7 RADIUS DAS: Check for single session match for Disconnect-Request 783b2a9 Interworking: Fix INTERWORKING_CONNECT with zero-length SSID BSS entry 1fef85c nl80211: Fix AP-scan-in-STA-mode error path behavior cebee30 Add domain_match network profile parameter d07d3fb Add peer certificate alt subject name information to EAP events 98a4cd4 D-Bus: Clear cached EAP data on network profile changes 483dd6a Include peer certificate always in EAP events dd5f902 Get rid of a compiler warning d29fa3a Extend VENDOR_ELEM parameters to cover non-P2P Association Request e7d0e97 hostapd: Add vendor specific VHT extension for the 2.4 GHz band Change-Id: I45436c49986cd6bddbd869db3f474871a29ce1dc Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/hostapd.conf5
-rw-r--r--hs20/client/osu_client.c36
-rw-r--r--src/ap/acs.c21
-rw-r--r--src/ap/ap_config.h2
-rw-r--r--src/ap/beacon.c28
-rw-r--r--src/ap/hostapd.c194
-rw-r--r--src/ap/hw_features.c25
-rw-r--r--src/ap/ieee802_11.c18
-rw-r--r--src/ap/ieee802_11.h4
-rw-r--r--src/ap/ieee802_11_vht.c83
-rw-r--r--src/ap/ieee802_1x.c24
-rw-r--r--src/ap/pmksa_cache_auth.c72
-rw-r--r--src/ap/pmksa_cache_auth.h2
-rw-r--r--src/ap/sta_info.c13
-rw-r--r--src/ap/sta_info.h2
-rw-r--r--src/ap/wnm_ap.c5
-rw-r--r--src/ap/wpa_auth.c7
-rw-r--r--src/ap/wpa_auth.h4
-rw-r--r--src/common/ieee802_11_common.c9
-rw-r--r--src/common/ieee802_11_common.h2
-rw-r--r--src/common/ieee802_11_defs.h3
-rw-r--r--src/common/wpa_ctrl.h6
-rw-r--r--src/crypto/tls.h15
-rw-r--r--src/crypto/tls_gnutls.c36
-rw-r--r--src/crypto/tls_internal.c5
-rw-r--r--src/crypto/tls_openssl.c104
-rw-r--r--src/crypto/tls_schannel.c5
-rw-r--r--src/drivers/driver.h1
-rw-r--r--src/drivers/driver_nl80211.c100
-rw-r--r--src/drivers/driver_nl80211_capa.c6
-rw-r--r--src/drivers/driver_nl80211_scan.c2
-rw-r--r--src/eap_peer/eap.c2
-rw-r--r--src/eap_peer/eap.h3
-rw-r--r--src/eap_peer/eap_config.h23
-rw-r--r--src/eap_peer/eap_tls_common.c2
-rw-r--r--src/eap_peer/eap_ttls.c1
-rw-r--r--src/eap_server/eap_server_fast.c3
-rw-r--r--src/eap_server/eap_server_methods.c4
-rw-r--r--src/eapol_supp/eapol_supp_sm.c7
-rw-r--r--src/eapol_supp/eapol_supp_sm.h3
-rw-r--r--src/radius/radius_client.c6
-rw-r--r--src/radius/radius_das.c13
-rw-r--r--src/radius/radius_das.h5
-rw-r--r--src/wps/wps_enrollee.c38
-rw-r--r--wpa_supplicant/ap.c1
-rw-r--r--wpa_supplicant/config.c8
-rw-r--r--wpa_supplicant/config.h18
-rw-r--r--wpa_supplicant/config_file.c9
-rw-r--r--wpa_supplicant/ctrl_iface.c68
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c12
-rw-r--r--wpa_supplicant/dbus/dbus_new.c5
-rw-r--r--wpa_supplicant/dbus/dbus_new.h4
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c13
-rw-r--r--wpa_supplicant/driver_i.h4
-rw-r--r--wpa_supplicant/eapol_test.c9
-rw-r--r--wpa_supplicant/events.c10
-rw-r--r--wpa_supplicant/hs20_supplicant.c35
-rw-r--r--wpa_supplicant/hs20_supplicant.h3
-rw-r--r--wpa_supplicant/interworking.c35
-rw-r--r--wpa_supplicant/mesh.c2
-rw-r--r--wpa_supplicant/notify.c17
-rw-r--r--wpa_supplicant/notify.h3
-rw-r--r--wpa_supplicant/p2p_supplicant.c18
-rw-r--r--wpa_supplicant/scan.c39
-rw-r--r--wpa_supplicant/sme.c14
-rw-r--r--wpa_supplicant/wpa_cli.c10
-rw-r--r--wpa_supplicant/wpa_supplicant.c18
-rw-r--r--wpa_supplicant/wpa_supplicant.conf24
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h10
-rw-r--r--wpa_supplicant/wpas_glue.c5
71 files changed, 1145 insertions, 200 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e30efbe3..99cd0528 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2690,6 +2690,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vendor_vht") == 0) {
+ bss->vendor_vht = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2f6126c3..b370f21f 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -158,10 +158,7 @@ channel=1
#acs_num_scans=5
# Channel list restriction. This option allows hostapd to select one of the
-# provided channels when a channel should be automatically selected. This
-# is currently only used for DFS when the current channels becomes unavailable
-# due to radar interference, and is currently only useful when ieee80211h=1 is
-# set.
+# provided channels when a channel should be automatically selected.
# Default: not set (allow any enabled channel to be selected)
#chanlist=100 104 108 112 116
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a439bdeb..e452aa70 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -397,9 +397,9 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
}
node = get_child_node(ctx->xml, pps,
- "PolicyUpdate/TrustRoot");
+ "Policy/PolicyUpdate/TrustRoot");
if (node == NULL) {
- wpa_printf(MSG_INFO, "No PolicyUpdate/TrustRoot/CertURL found from PPS");
+ wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
return -1;
}
@@ -2343,8 +2343,8 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
}
-static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname, const char *ca_fname)
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname, const char *ca_fname)
{
xml_node_t *pps, *node;
char pps_fname_buf[300];
@@ -2371,12 +2371,12 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
} else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
sizeof(buf)) < 0) {
wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
- return;
+ return -1;
}
os_free(ctx->fqdn);
ctx->fqdn = os_strdup(buf);
if (ctx->fqdn == NULL)
- return;
+ return -1;
wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
buf);
os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
@@ -2391,14 +2391,14 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
if (!os_file_exists(pps_fname)) {
wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
pps_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
if (ca_fname && !os_file_exists(ca_fname)) {
wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
ca_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
ctx->ca_fname = ca_fname;
@@ -2406,7 +2406,7 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
pps = node_from_file(ctx->xml, pps_fname);
if (pps == NULL) {
wpa_printf(MSG_INFO, "Could not read PPS MO");
- return;
+ return -1;
}
if (!ctx->fqdn) {
@@ -2414,18 +2414,18 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
if (node == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
- return;
+ return -1;
}
tmp = xml_node_get_text(ctx->xml, node);
if (tmp == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
- return;
+ return -1;
}
ctx->fqdn = os_strdup(tmp);
xml_node_get_text_free(ctx->xml, tmp);
if (!ctx->fqdn) {
wpa_printf(MSG_INFO, "No FQDN known");
- return;
+ return -1;
}
}
@@ -2474,7 +2474,7 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
}
if (!address) {
wpa_printf(MSG_INFO, "Server URL not known");
- return;
+ return -1;
}
write_summary(ctx, "Wait for IP address for subscriptiom remediation");
@@ -2497,6 +2497,7 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
xml_node_get_text_free(ctx->xml, cred_username);
str_clear_free(cred_password);
xml_node_free(ctx->xml, pps);
+ return 0;
}
@@ -3066,10 +3067,11 @@ int main(int argc, char *argv[])
if (argc - optind < 2)
wpa_printf(MSG_ERROR, "Server URL missing from command line");
else
- cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ? argv[optind + 2] : NULL,
- argc > optind + 3 ? argv[optind + 3] :
- NULL);
+ ret = cmd_sub_rem(&ctx, argv[optind + 1],
+ argc > optind + 2 ?
+ argv[optind + 2] : NULL,
+ argc > optind + 3 ?
+ argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "pol_upd") == 0) {
if (argc - optind < 2) {
usage();
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 97cf26fb..e4c834ce 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -455,6 +455,22 @@ static int acs_usable_chan(struct hostapd_channel_data *chan)
}
+static int is_in_chanlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ int *entry;
+
+ if (!iface->conf->chanlist)
+ return 1;
+
+ for (entry = iface->conf->chanlist; *entry != -1; entry++) {
+ if (*entry == chan->chan)
+ return 1;
+ }
+ return 0;
+}
+
+
static void acs_survey_all_chans_intereference_factor(
struct hostapd_iface *iface)
{
@@ -467,6 +483,9 @@ static void acs_survey_all_chans_intereference_factor(
if (!acs_usable_chan(chan))
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -543,6 +562,8 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 58af6cb1..e5215c52 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -551,6 +551,8 @@ struct hostapd_bss_config {
int mesh;
int radio_measurements;
+
+ int vendor_vht;
};
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4a8703ac..b0a74e01 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -379,6 +379,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
+ if (hapd->conf->vendor_vht) {
+ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -446,8 +450,12 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
#ifdef CONFIG_IEEE80211AC
- pos = hostapd_eid_vht_capabilities(hapd, pos);
- pos = hostapd_eid_vht_operation(hapd, pos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+ }
+ if (hapd->conf->vendor_vht)
+ pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -776,6 +784,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht) {
+ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -865,8 +881,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
#ifdef CONFIG_IEEE80211AC
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
- tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ }
+ if (hapd->conf->vendor_vht)
+ tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 6e4169ba..b641503c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -15,6 +15,8 @@
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "eap_server/tncs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@@ -614,51 +616,190 @@ static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
- struct radius_das_attrs *attr)
+ struct radius_das_attrs *attr,
+ int *multi)
{
- struct sta_info *sta = NULL;
+ struct sta_info *selected, *sta;
char buf[128];
+ int num_attr = 0;
+ int count;
- if (attr->sta_addr)
+ *multi = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta->radius_das_match = 1;
+
+ if (attr->sta_addr) {
+ num_attr++;
sta = ap_get_sta(hapd, attr->sta_addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No Calling-Station-Id match");
+ return NULL;
+ }
+
+ selected = sta;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta != selected)
+ sta->radius_das_match = 0;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
+ }
+
+ if (attr->acct_session_id) {
+ num_attr++;
+ if (attr->acct_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
- if (sta == NULL && attr->acct_session_id &&
- attr->acct_session_id_len == 17) {
for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
os_snprintf(buf, sizeof(buf), "%08X-%08X",
sta->acct_session_id_hi,
sta->acct_session_id_lo);
- if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
- break;
+ if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
+ }
+
+ if (attr->acct_multi_session_id) {
+ num_attr++;
+ if (attr->acct_multi_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
+ if (!sta->eapol_sm ||
+ !sta->eapol_sm->acct_multi_session_id_hi) {
+ sta->radius_das_match = 0;
+ continue;
+ }
+ os_snprintf(buf, sizeof(buf), "%08X+%08X",
+ sta->eapol_sm->acct_multi_session_id_hi,
+ sta->eapol_sm->acct_multi_session_id_lo);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+ 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
+ return NULL;
}
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id match");
}
- if (sta == NULL && attr->cui) {
+ if (attr->cui) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
struct wpabuf *cui;
+
+ if (!sta->radius_das_match)
+ continue;
cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
- if (cui && wpabuf_len(cui) == attr->cui_len &&
+ if (!cui || wpabuf_len(cui) != attr->cui_len ||
os_memcmp(wpabuf_head(cui), attr->cui,
- attr->cui_len) == 0)
- break;
+ attr->cui_len) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
+ return NULL;
}
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Chargeable-User-Identity match");
}
- if (sta == NULL && attr->user_name) {
+ if (attr->user_name) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
u8 *identity;
size_t identity_len;
+
+ if (!sta->radius_das_match)
+ continue;
identity = ieee802_1x_get_identity(sta->eapol_sm,
&identity_len);
- if (identity &&
- identity_len == attr->user_name_len &&
+ if (!identity ||
+ identity_len != attr->user_name_len ||
os_memcmp(identity, attr->user_name, identity_len)
- == 0)
- break;
+ != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after User-Name check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: User-Name match");
+ }
+
+ if (num_attr == 0) {
+ /*
+ * In theory, we could match all current associations, but it
+ * seems safer to just reject requests that do not include any
+ * session identification attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No session identification attributes included");
+ return NULL;
+ }
+
+ selected = NULL;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->radius_das_match) {
+ if (selected) {
+ *multi = 1;
+ return NULL;
+ }
+ selected = sta;
}
}
- return sta;
+ return selected;
+}
+
+
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ if (!hapd->wpa_auth)
+ return -1;
+ return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
}
@@ -667,14 +808,29 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int multi;
if (hostapd_das_nas_mismatch(hapd, attr))
return RADIUS_DAS_NAS_MISMATCH;
- sta = hostapd_das_find_sta(hapd, attr);
- if (sta == NULL)
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (sta == NULL) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: PMKSA cache entry matched");
+ return RADIUS_DAS_SUCCESS;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
return RADIUS_DAS_SESSION_NOT_FOUND;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+ " - disconnecting", MAC2STR(sta->addr));
wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
hostapd_drv_sta_deauth(hapd, sta->addr,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 6b0a72d8..05431d32 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -75,7 +75,7 @@ static char * dfs_info(struct hostapd_channel_data *chan)
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
- int ret = 0, i, j;
+ int i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
@@ -138,7 +138,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
}
- return ret;
+ return 0;
}
@@ -641,12 +641,31 @@ static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
- u32 hw = iface->current_mode->vht_capab;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ u32 hw = mode->vht_capab;
u32 conf = iface->conf->vht_capab;
wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
hw, conf);
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->bss[0]->vendor_vht &&
+ mode->vht_capab == 0 && iface->hw_features) {
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &iface->hw_features[i];
+ hw = mode->vht_capab;
+ wpa_printf(MSG_DEBUG,
+ "update hw vht capab based on 5 GHz band: 0x%x",
+ hw);
+ break;
+ }
+ }
+ }
+
#define VHT_CAP_CHECK(cap) \
do { \
if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 3d4488a1..89911b1f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1327,6 +1327,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"mandatory VHT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
}
+
+ if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+ resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+ elems.vendor_vht_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_P2P
@@ -1616,8 +1623,10 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- p = hostapd_eid_vht_capabilities(hapd, p);
- p = hostapd_eid_vht_operation(hapd, p);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+ }
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
@@ -1625,6 +1634,11 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+ p = hostapd_eid_vendor_vht(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index beaeac50..41c27d90 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -51,6 +51,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_vht(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,
const u8 *addr, const u8 *trans_id);
@@ -62,6 +63,9 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len);
+
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 437cf503..159693f6 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -22,12 +22,25 @@
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
- hapd->conf->disable_11ac)
+ if (!mode)
return eid;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+ mode->vht_capab == 0 && hapd->iface->hw_features) {
+ int i;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ if (hapd->iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &hapd->iface->hw_features[i];
+ break;
+ }
+ }
+ }
+
*pos++ = WLAN_EID_VHT_CAP;
*pos++ = sizeof(*cap);
@@ -37,8 +50,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
hapd->iface->conf->vht_capab);
/* Supported MCS set comes from hw */
- os_memcpy(&cap->vht_supported_mcs_set,
- hapd->iface->current_mode->vht_mcs_set, 8);
+ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
pos += sizeof(*cap);
@@ -51,9 +63,6 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
- return eid;
-
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@@ -109,6 +118,66 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len)
+{
+ const u8 *vht_capab;
+ unsigned int vht_capab_len;
+
+ if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+ hapd->conf->disable_11ac)
+ goto no_capab;
+
+ /* The VHT Capabilities element embedded in vendor VHT */
+ vht_capab = ie + 5;
+ if (vht_capab[0] != WLAN_EID_VHT_CAP)
+ goto no_capab;
+ vht_capab_len = vht_capab[1];
+ if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+ (int) vht_capab_len > ie + len - vht_capab - 2)
+ goto no_capab;
+ vht_capab += 2;
+
+ if (sta->vht_capabilities == NULL) {
+ sta->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (sta->vht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+ return WLAN_STATUS_SUCCESS;
+
+no_capab:
+ sta->flags &= ~WLAN_STA_VENDOR_VHT;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = (5 + /* The Vendor OUI, type and subtype */
+ 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation));
+
+ WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
+ pos += 4;
+ *pos++ = VENDOR_VHT_SUBTYPE;
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+
+ return pos;
+}
+
+
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper_notif)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 2287b281..9d257cc3 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1211,15 +1211,11 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
if (eap_type >= 0)
sm->eap_type_authsrv = eap_type;
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_RESPONSE:
os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_SUCCESS:
os_strlcpy(buf, "EAP Success", sizeof(buf));
@@ -2487,15 +2483,23 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
return len;
len += ret;
+ if (sm->acct_multi_session_id_hi) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "authMultiSessionId=%08X+%08X\n",
+ sm->acct_multi_session_id_hi,
+ sm->acct_multi_session_id_lo);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
name1 = eap_server_get_name(0, sm->eap_type_authsrv);
name2 = eap_server_get_name(0, sm->eap_type_supp);
ret = os_snprintf(buf + len, buflen - len,
"last_eap_type_as=%d (%s)\n"
"last_eap_type_sta=%d (%s)\n",
- sm->eap_type_authsrv,
- name1 ? name1 : "",
- sm->eap_type_supp,
- name2 ? name2 : "");
+ sm->eap_type_authsrv, name1,
+ sm->eap_type_supp, name2);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 42703821..650e9a81 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
#include "sta_info.h"
#include "ap_config.h"
#include "pmksa_cache_auth.h"
@@ -452,3 +453,74 @@ pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
return pmksa;
}
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+ struct radius_das_attrs *attr)
+{
+ int match = 0;
+
+ if (attr->sta_addr) {
+ if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->acct_multi_session_id) {
+ char buf[20];
+
+ if (attr->acct_multi_session_id_len != 17)
+ return 0;
+ os_snprintf(buf, sizeof(buf), "%08X+%08X",
+ entry->acct_multi_session_id_hi,
+ entry->acct_multi_session_id_lo);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->cui) {
+ if (!entry->cui ||
+ attr->cui_len != wpabuf_len(entry->cui) ||
+ os_memcmp(attr->cui, wpabuf_head(entry->cui),
+ attr->cui_len) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->user_name) {
+ if (!entry->identity ||
+ attr->user_name_len != entry->identity_len ||
+ os_memcmp(attr->user_name, entry->identity,
+ attr->user_name_len) != 0)
+ return 0;
+ match++;
+ }
+
+ return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr)
+{
+ int found = 0;
+ struct rsn_pmksa_cache_entry *entry, *prev;
+
+ if (attr->acct_session_id)
+ return -1;
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (das_attr_match(entry, attr)) {
+ found++;
+ prev = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, prev);
+ continue;
+ }
+ entry = entry->next;
+ }
+
+ return found ? 0 : -1;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 519555f8..8b7be129 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -61,5 +61,7 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 1c2197a4..bb432189 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -370,8 +370,14 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
* but do not disconnect the station now.
*/
next_time = hapd->conf->ap_max_inactivity + fuzz;
- } else if (inactive_sec < hapd->conf->ap_max_inactivity &&
- sta->flags & WLAN_STA_ASSOC) {
+ } else if (inactive_sec == -ENOENT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has lost its driver entry",
+ MAC2STR(sta->addr));
+
+ if (hapd->conf->skip_inactivity_poll)
+ sta->timeout_next = STA_DISASSOC;
+ } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
@@ -1101,7 +1107,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1119,6 +1125,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
if (os_snprintf_error(buflen, res))
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 588a9e2f..57551ab1 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -35,6 +35,7 @@
#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -84,6 +85,7 @@ struct sta_info {
unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
unsigned int session_timeout_set:1;
+ unsigned int radius_das_match:1;
u16 auth_alg;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 7e8fb5c6..4c8bc100 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -564,8 +564,11 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
if (url) {
/* Session Information URL */
url_len = os_strlen(url);
- if (url_len > 255)
+ if (url_len > 255) {
+ os_free(buf);
return -1;
+ }
+
*pos++ = url_len;
os_memcpy(pos, url, url_len);
pos += url_len;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 059b8848..f71b0285 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3340,3 +3340,10 @@ int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
return 0;
}
#endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr)
+{
+ return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 757e49e4..b34b84dd 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -315,4 +315,8 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
+struct radius_das_attrs;
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr);
+
#endif /* WPA_AUTH_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e1d45cf9..ed8d4661 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -128,6 +128,15 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
+ case VENDOR_VHT_TYPE:
+ if (elen > 4 &&
+ (pos[4] == VENDOR_VHT_SUBTYPE ||
+ pos[4] == VENDOR_VHT_SUBTYPE2)) {
+ elems->vendor_vht = pos;
+ elems->vendor_vht_len = elen;
+ } else
+ return -1;
+ break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2357afc5..05fe32b4 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -35,6 +35,7 @@ struct ieee802_11_elems {
const u8 *vht_operation;
const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
+ const u8 *vendor_vht;
const u8 *p2p;
const u8 *wfd;
const u8 *link_id;
@@ -71,6 +72,7 @@ struct ieee802_11_elems {
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
+ u8 vendor_vht_len;
u8 p2p_len;
u8 wfd_len;
u8 interworking_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index dfe0fafd..803b8ccc 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1155,6 +1155,9 @@ enum plink_action_field {
};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE 0x04
+#define VENDOR_VHT_SUBTYPE 0x08
+#define VENDOR_VHT_SUBTYPE2 0x00
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 1f747eb1..59a34126 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -42,6 +42,8 @@ extern "C" {
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP peer certificate alternative subject name component from TLS */
+#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
@@ -194,6 +196,9 @@ extern "C" {
/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
#define GAS_QUERY_DONE "GAS-QUERY-DONE "
+/* parameters: <addr> <result> */
+#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
@@ -277,6 +282,7 @@ enum wpa_vendor_elem_frame {
VENDOR_ELEM_P2P_INV_RESP = 10,
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+ VENDOR_ELEM_ASSOC_REQ = 13,
NUM_VENDOR_ELEM_FRAMES
};
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index a4f954c7..9ae95a66 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -41,9 +41,13 @@ enum tls_fail_reason {
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
TLS_FAIL_BAD_CERTIFICATE = 7,
TLS_FAIL_SERVER_CHAIN_PROBE = 8,
- TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+ TLS_FAIL_DOMAIN_MISMATCH = 10,
};
+
+#define TLS_MAX_ALT_SUBJECT 10
+
union tls_event_data {
struct {
int depth;
@@ -59,6 +63,8 @@ union tls_event_data {
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
+ const char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int num_altsubject;
} peer_cert;
struct {
@@ -102,7 +108,11 @@ struct tls_config {
* @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
+ * certificate or %NULL to allow all domain names. This may allow subdomains an
+ * wildcard certificates. Each domain name label must have a full 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.
* @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
@@ -146,6 +156,7 @@ struct tls_connection_params {
const char *subject_match;
const char *altsubject_match;
const char *suffix_match;
+ const char *domain_match;
const char *client_cert;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index f2eacb5d..65db6fcc 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -58,6 +58,7 @@ struct tls_connection {
gnutls_certificate_credentials_t xcred;
char *suffix_match;
+ char *domain_match;
unsigned int flags;
};
@@ -280,6 +281,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
wpabuf_free(conn->push_buf);
wpabuf_free(conn->pull_buf);
os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn);
}
@@ -363,6 +365,21 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (params->domain_match) {
+ conn->domain_match = os_strdup(params->domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+#else /* < 3.3.0 */
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
+ return -1;
+ }
+#endif /* >= 3.3.0 */
+
conn->flags = params->flags;
if (params->openssl_ciphers) {
@@ -1111,6 +1128,25 @@ static int tls_connection_verify_peer(gnutls_session_t session)
goto out;
}
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (conn->domain_match &&
+ !gnutls_x509_crt_check_hostname2(
+ cert, conn->domain_match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain match '%s' not found",
+ conn->domain_match);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+#endif /* >= 3.3.0 */
+
/* TODO: validate altsubject_match.
* For now, any such configuration is rejected in
* tls_connection_set_params() */
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 86375d11..0c955da2 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -205,6 +205,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
return -1;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 5433ebb2..e3ca0682 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -96,7 +96,7 @@ struct tls_connection {
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
- char *subject_match, *altsubject_match, *suffix_match;
+ char *subject_match, *altsubject_match, *suffix_match, *domain_match;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -1098,6 +1098,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
os_free(conn->subject_match);
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1190,7 +1191,8 @@ 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)
+static int domain_suffix_match(const u8 *val, size_t len, const char *match,
+ int full)
{
size_t i, match_len;
@@ -1203,7 +1205,7 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match)
}
match_len = os_strlen(match);
- if (match_len > len)
+ if (match_len > len || (full && match_len != len))
return 0;
if (os_strncasecmp((const char *) val + len - match_len, match,
@@ -1222,7 +1224,7 @@ 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)
+static int tls_match_suffix(X509 *cert, const char *match, int full)
{
#ifdef CONFIG_NATIVE_WINDOWS
/* wincrypt.h has conflicting X509_NAME definition */
@@ -1235,7 +1237,8 @@ static int tls_match_suffix(X509 *cert, const char *match)
int dns_name = 0;
X509_NAME *name;
- wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "": "suffix ", match);
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
@@ -1248,8 +1251,10 @@ static int tls_match_suffix(X509 *cert, const char *match)
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found");
+ gen->d.dNSName->length, match, full) ==
+ 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
return 1;
}
}
@@ -1276,13 +1281,16 @@ static int tls_match_suffix(X509 *cert, const char *match)
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found");
+ if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+ {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
return 1;
}
}
- wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "": "suffix ");
return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1377,6 +1385,11 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
struct wpabuf *cert = NULL;
union tls_event_data ev;
struct tls_context *context = conn->context;
+ char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_altsubject = 0;
+ GENERAL_NAME *gen;
+ void *ext;
+ stack_index_t i;
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
@@ -1403,8 +1416,52 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
#endif /* CONFIG_SHA256 */
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
+
+ ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
+ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+ char *pos;
+
+ if (num_altsubject == TLS_MAX_ALT_SUBJECT)
+ break;
+ gen = sk_GENERAL_NAME_value(ext, i);
+ if (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI)
+ continue;
+
+ pos = os_malloc(10 + gen->d.ia5->length + 1);
+ if (pos == NULL)
+ break;
+ altsubject[num_altsubject++] = pos;
+
+ switch (gen->type) {
+ case GEN_EMAIL:
+ os_memcpy(pos, "EMAIL:", 6);
+ pos += 6;
+ break;
+ case GEN_DNS:
+ os_memcpy(pos, "DNS:", 4);
+ pos += 4;
+ break;
+ case GEN_URI:
+ os_memcpy(pos, "URI:", 4);
+ pos += 4;
+ break;
+ }
+
+ os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
+ pos += gen->d.ia5->length;
+ *pos = '\0';
+ }
+
+ for (alt = 0; alt < num_altsubject; alt++)
+ ev.peer_cert.altsubject[alt] = altsubject[alt];
+ ev.peer_cert.num_altsubject = num_altsubject;
+
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
+ for (alt = 0; alt < num_altsubject; alt++)
+ os_free(altsubject[alt]);
}
@@ -1416,7 +1473,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
SSL *ssl;
struct tls_connection *conn;
struct tls_context *context;
- char *match, *altmatch, *suffix_match;
+ char *match, *altmatch, *suffix_match, *domain_match;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1444,6 +1501,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
match = conn->subject_match;
altmatch = conn->altsubject_match;
suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
if (!preverify_ok && !conn->ca_cert_verify)
preverify_ok = 1;
@@ -1513,13 +1571,21 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"AltSubject mismatch",
TLS_FAIL_ALTSUBJECT_MISMATCH);
} else if (depth == 0 && suffix_match &&
- !tls_match_suffix(err_cert, suffix_match)) {
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
suffix_match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain suffix mismatch",
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
@@ -1783,7 +1849,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
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 *suffix_match,
+ const char *domain_match)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1809,6 +1876,14 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
return -1;
}
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+
return 0;
}
@@ -3273,7 +3348,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match,
- params->suffix_match))
+ params->suffix_match,
+ params->domain_match))
return -1;
if (engine_id && ca_cert_id) {
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
index a43b4874..31a2c946 100644
--- a/src/crypto/tls_schannel.c
+++ b/src/crypto/tls_schannel.c
@@ -707,6 +707,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
return -1;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2c0c6850..b8a7c519 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1040,6 +1040,7 @@ struct wpa_driver_mesh_bss_params {
* See NL80211_MESHCONF_* for all the mesh config parameters.
*/
unsigned int flags;
+ int peer_link_timeout;
};
struct wpa_driver_mesh_join_params {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c180f15d..3ed98511 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4214,6 +4214,48 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
}
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+ struct wpa_driver_associate_params *params)
+{
+ if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+ return -1;
+
+ if (params->htcaps && params->htcaps_mask) {
+ int sz = sizeof(struct ieee80211_ht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
+ params->htcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+ params->htcaps) ||
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+ params->htcaps_mask))
+ return -1;
+ }
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+ return -1;
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
+ params->vhtcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+ params->vhtcaps) ||
+ nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask))
+ return -1;
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ return 0;
+}
+
+
static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
@@ -4274,6 +4316,9 @@ retry:
goto fail;
}
+ if (nl80211_ht_vht_overrides(msg, params) < 0)
+ return -1;
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -4455,41 +4500,9 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
return -1;
}
- if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+ if (nl80211_ht_vht_overrides(msg, params) < 0)
return -1;
- if (params->htcaps && params->htcaps_mask) {
- int sz = sizeof(struct ieee80211_ht_capabilities);
- wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
- wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
- params->htcaps_mask, sz);
- if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
- params->htcaps) ||
- nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
- params->htcaps_mask))
- return -1;
- }
-
-#ifdef CONFIG_VHT_OVERRIDES
- if (params->disable_vht) {
- wpa_printf(MSG_DEBUG, " * VHT disabled");
- if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
- return -1;
- }
-
- if (params->vhtcaps && params->vhtcaps_mask) {
- int sz = sizeof(struct ieee80211_vht_capabilities);
- wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
- wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
- params->vhtcaps_mask, sz);
- if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
- params->vhtcaps) ||
- nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
- params->vhtcaps_mask))
- return -1;
- }
-#endif /* CONFIG_VHT_OVERRIDES */
-
if (params->p2p)
wpa_printf(MSG_DEBUG, " * P2P group");
@@ -5219,6 +5232,8 @@ static int i802_get_inact_sec(void *priv, const u8 *addr)
data.inactive_msec = (unsigned long) -1;
ret = i802_read_sta_data(priv, &data, addr);
+ if (ret == -ENOENT)
+ return -ENOENT;
if (ret || data.inactive_msec == (unsigned long) -1)
return -1;
return data.inactive_msec / 1000;
@@ -7818,7 +7833,8 @@ wpa_driver_nl80211_join_mesh(void *priv,
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *container;
- int ret = 0;
+ int ret = -1;
+ u32 timeout;
wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
@@ -7866,6 +7882,22 @@ wpa_driver_nl80211_join_mesh(void *priv,
nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
params->max_peer_links))
goto fail;
+
+ /*
+ * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+ * the timer could disconnect stations even in that case.
+ *
+ * Set 0xffffffff instead of 0 because NL80211_MESHCONF_PLINK_TIMEOUT
+ * does not allow 0.
+ */
+ timeout = params->conf.peer_link_timeout;
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) || timeout == 0)
+ timeout = 0xffffffff;
+ if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, timeout)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+ goto fail;
+ }
+
nla_nest_end(msg, container);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 5c71603c..6e52bdef 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -520,11 +520,11 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
nla_len(tb[NL80211_ATTR_EXT_CAPA]);
}
drv->extended_capa_mask =
- os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
if (drv->extended_capa_mask) {
os_memcpy(drv->extended_capa_mask,
- nla_data(tb[NL80211_ATTR_EXT_CAPA]),
- nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
} else {
os_free(drv->extended_capa);
drv->extended_capa = NULL;
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index c35b4d7e..3911f485 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -266,7 +266,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
goto fail;
if (wpa_driver_nl80211_scan(bss, params)) {
- wpa_driver_nl80211_set_mode(bss, drv->nlmode);
+ wpa_driver_nl80211_set_mode(bss, old_mode);
goto fail;
}
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 31c1a29c..62cd4a18 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1858,6 +1858,8 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
sm->eapol_cb->notify_cert(sm->eapol_ctx,
data->peer_cert.depth,
data->peer_cert.subject,
+ data->peer_cert.altsubject,
+ data->peer_cert.num_altsubject,
hash_hex, data->peer_cert.cert);
break;
case TLS_ALERT:
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index bc207e74..8c4a42f6 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -228,10 +228,13 @@ struct eapol_callbacks {
* @ctx: eapol_ctx from eap_peer_sm_init() call
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*notify_cert)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 826ddca3..903412de 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -230,6 +230,21 @@ struct eap_peer_config {
char *domain_suffix_match;
/**
+ * domain_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a full match requirement for the
+ * server certificate in SubjectAltName dNSName element(s). If a
+ * matching dNSName is found, this constraint is met. If no dNSName
+ * values are present, this constraint is matched against SubjectName CN
+ * using same full match comparison. This behavior is similar to
+ * domain_suffix_match, but has the requirement of a full match, i.e.,
+ * no subdomains or wildcard matches are allowed. Case-insensitive
+ * comparison is used, so "Example.com" matches "example.com", but would
+ * not match "test.Example.com".
+ */
+ char *domain_match;
+
+ /**
* ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
*
* This file can have one or more trusted CA certificates. If ca_cert2
@@ -333,6 +348,14 @@ struct eap_peer_config {
char *domain_suffix_match2;
/**
+ * domain_match2 - Constraint for server domain name
+ *
+ * This field is like domain_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *domain_match2;
+
+ /**
* eap_methods - Allowed EAP methods
*
* (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 3641a2c8..87107816 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -91,6 +91,7 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
params->subject_match = (char *) config->subject_match;
params->altsubject_match = (char *) config->altsubject_match;
params->suffix_match = config->domain_suffix_match;
+ params->domain_match = config->domain_match;
params->engine = config->engine;
params->engine_id = config->engine_id;
params->pin = config->pin;
@@ -113,6 +114,7 @@ static void eap_tls_params_from_conf2(struct tls_connection_params *params,
params->subject_match = (char *) config->subject_match2;
params->altsubject_match = (char *) config->altsubject_match2;
params->suffix_match = config->domain_suffix_match2;
+ params->domain_match = config->domain_match2;
params->engine = config->engine2;
params->engine_id = config->engine2_id;
params->pin = config->pin2;
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 6fbc27b7..b5c028b5 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -995,6 +995,7 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm,
resp, out_data)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
"frame");
+ wpabuf_free(resp);
return -1;
}
wpabuf_free(resp);
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 56ac7f43..6745100d 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -819,6 +819,9 @@ static int eap_fast_encrypt_phase2(struct eap_sm *sm,
encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
wpabuf_free(plain);
+ if (!encr)
+ return -1;
+
if (data->ssl.tls_out && piggyback) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
"(len=%d) with last Phase 1 Message (len=%d "
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 0209fad6..9e9dc934 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -153,7 +153,7 @@ void eap_server_unregister_methods(void)
* eap_server_get_name - Get EAP method name for the given EAP type
* @vendor: EAP Vendor-Id (0 = IETF)
* @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ * Returns: EAP method name, e.g., TLS, or "unknown" if not found
*
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
@@ -167,5 +167,5 @@ const char * eap_server_get_name(int vendor, EapType type)
if (m->vendor == vendor && m->method == type)
return m->name;
}
- return NULL;
+ return "unknown";
}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 941a2694..621318ee 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1962,13 +1962,14 @@ static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
- const char *cert_hash,
+ const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
struct eapol_sm *sm = ctx;
if (sm->ctx->cert_cb)
- sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
- cert_hash, cert);
+ sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index e089e88b..d8ae9d4e 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -248,10 +248,13 @@ struct eapol_ctx {
* @ctx: Callback context (ctx)
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*cert_cb)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 1382c53b..34f56853 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -658,7 +658,8 @@ int radius_client_send(struct radius_client_data *radius,
}
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
- if (conf->acct_server == NULL || radius->acct_sock < 0) {
+ if (conf->acct_server == NULL || radius->acct_sock < 0 ||
+ conf->acct_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -672,7 +673,8 @@ int radius_client_send(struct radius_client_data *radius,
s = radius->acct_sock;
conf->acct_server->requests++;
} else {
- if (conf->auth_server == NULL || radius->auth_sock < 0) {
+ if (conf->auth_server == NULL || radius->auth_sock < 0 ||
+ conf->auth_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index 9655f4ce..39ceea87 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -42,6 +42,7 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
RADIUS_ATTR_CALLING_STATION_ID,
RADIUS_ATTR_NAS_IDENTIFIER,
RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
RADIUS_ATTR_EVENT_TIMESTAMP,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -129,6 +130,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
attrs.acct_session_id_len = len;
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_multi_session_id = buf;
+ attrs.acct_multi_session_id_len = len;
+ }
+
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
attrs.cui = buf;
@@ -147,6 +154,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
"%s:%d", abuf, from_port);
error = 503;
break;
+ case RADIUS_DAS_MULTI_SESSION_MATCH:
+ wpa_printf(MSG_INFO,
+ "DAS: Multiple sessions match for request from %s:%d",
+ abuf, from_port);
+ error = 508;
+ break;
case RADIUS_DAS_SUCCESS:
error = 0;
break;
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index e3ed5408..ce731d46 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -14,7 +14,8 @@ struct radius_das_data;
enum radius_das_res {
RADIUS_DAS_SUCCESS,
RADIUS_DAS_NAS_MISMATCH,
- RADIUS_DAS_SESSION_NOT_FOUND
+ RADIUS_DAS_SESSION_NOT_FOUND,
+ RADIUS_DAS_MULTI_SESSION_MATCH,
};
struct radius_das_attrs {
@@ -30,6 +31,8 @@ struct radius_das_attrs {
size_t user_name_len;
const u8 *acct_session_id;
size_t acct_session_id_len;
+ const u8 *acct_multi_session_id;
+ size_t acct_multi_session_id_len;
const u8 *cui;
size_t cui_len;
};
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9f5a90ce..89957b1a 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -247,22 +247,48 @@ static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)",
- wps->wps->ap_auth_type);
+ u16 auth_type = wps->wps->ap_auth_type;
+
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Authentication Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
+ if (auth_type & WPS_AUTH_WPA2PSK)
+ auth_type = WPS_AUTH_WPA2PSK;
+ else if (auth_type & WPS_AUTH_WPAPSK)
+ auth_type = WPS_AUTH_WPAPSK;
+ else if (auth_type & WPS_AUTH_OPEN)
+ auth_type = WPS_AUTH_OPEN;
+
+ wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type);
wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
wpabuf_put_be16(msg, 2);
- wpabuf_put_be16(msg, wps->wps->ap_auth_type);
+ wpabuf_put_be16(msg, auth_type);
return 0;
}
static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)",
- wps->wps->ap_encr_type);
+ u16 encr_type = wps->wps->ap_encr_type;
+
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Encryption Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
+ if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
+ if (encr_type & WPS_ENCR_AES)
+ encr_type = WPS_ENCR_AES;
+ else if (encr_type & WPS_ENCR_TKIP)
+ encr_type = WPS_ENCR_TKIP;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type);
wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
wpabuf_put_be16(msg, 2);
- wpabuf_put_be16(msg, wps->wps->ap_encr_type);
+ wpabuf_put_be16(msg, encr_type);
return 0;
}
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 2ebc7f62..65532e3c 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -132,6 +132,7 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ |
HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
if (mode->vht_capab && ssid->vht) {
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a8106324..5d7a063c 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1818,6 +1818,7 @@ static const struct parse_data ssid_fields[] = {
{ STRe(subject_match) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
+ { STRe(domain_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1827,6 +1828,7 @@ static const struct parse_data ssid_fields[] = {
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
+ { STRe(domain_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -2052,6 +2054,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->subject_match);
os_free(eap->altsubject_match);
os_free(eap->domain_suffix_match);
+ os_free(eap->domain_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
@@ -2061,6 +2064,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
os_free(eap->domain_suffix_match2);
+ os_free(eap->domain_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
@@ -2230,6 +2234,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->sae_groups);
wpabuf_free(config->ap_vendor_elements);
os_free(config->osu_dir);
+ os_free(config->bgscan);
os_free(config->wowlan_triggers);
os_free(config);
}
@@ -3472,6 +3477,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->ap_scan = DEFAULT_AP_SCAN;
config->user_mpm = DEFAULT_USER_MPM;
config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
+ config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
@@ -3490,6 +3496,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
+ config->cert_in_cb = DEFAULT_CERT_IN_CB;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -4021,6 +4028,7 @@ static const struct global_parse_data global_fields[] = {
#ifdef CONFIG_MESH
{ INT(user_mpm), 0 },
{ INT_RANGE(max_peer_links, 0, 255), 0 },
+ { INT(mesh_max_inactivity), 0 },
#endif /* CONFIG_MESH */
{ INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index dca17c28..eeb4ba7f 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -17,6 +17,7 @@
#endif /* CONFIG_NO_SCAN_PROCESSING */
#define DEFAULT_USER_MPM 1
#define DEFAULT_MAX_PEER_LINKS 99
+#define DEFAULT_MESH_MAX_INACTIVITY 300
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
@@ -31,6 +32,7 @@
#define DEFAULT_P2P_SEARCH_DELAY 500
#define DEFAULT_RAND_ADDR_LIFETIME 60
#define DEFAULT_KEY_MGMT_OFFLOAD 1
+#define DEFAULT_CERT_IN_CB 1
#include "config_ssid.h"
#include "wps/wps.h"
@@ -1119,6 +1121,22 @@ struct wpa_config {
* Maximum number of mesh peering currently maintained by the STA.
*/
int max_peer_links;
+
+ /**
+ * cert_in_cb - Whether to include a peer certificate dump in events
+ *
+ * This controls whether peer certificates for authentication server and
+ * its certificate chain are included in EAP peer certificate events.
+ */
+ int cert_in_cb;
+
+ /**
+ * mesh_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in mesh STA to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int mesh_max_inactivity;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index d8cbe8bd..9c9685a7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -691,6 +691,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(subject_match);
STR(altsubject_match);
STR(domain_suffix_match);
+ STR(domain_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -700,6 +701,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(subject_match2);
STR(altsubject_match2);
STR(domain_suffix_match2);
+ STR(domain_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
@@ -1218,6 +1220,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS)
fprintf(f, "max_peer_links=%d\n", config->max_peer_links);
+
+ if (config->cert_in_cb != DEFAULT_CERT_IN_CB)
+ fprintf(f, "cert_in_cb=%d\n", config->cert_in_cb);
+
+ if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY)
+ fprintf(f, "mesh_max_inactivity=%d\n",
+ config->mesh_max_inactivity);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 9c3f93d6..8e71727f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -437,6 +437,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_AP */
} else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
wpa_s->extra_roc_dur = atoi(value);
+ } else if (os_strcasecmp(cmd, "test_failure") == 0) {
+ wpa_s->test_failure = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
@@ -5526,6 +5528,27 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
return -1;
}
+ if (bss->ssid_len == 0) {
+ int found = 0;
+
+ wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
+ " does not have SSID information", MAC2STR(bssid));
+
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
+ list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+ bss->ssid_len > 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+ wpa_printf(MSG_DEBUG,
+ "Found another matching BSS entry with SSID");
+ }
+
return interworking_connect(wpa_s, bss);
}
@@ -6091,20 +6114,24 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
+ wpa_s->global->p2p_init_wpa_s : wpa_s;
+#endif /* CONFIG_P2P */
+
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
#ifdef CONFIG_P2P
- wpas_p2p_cancel(wpa_s);
- wpas_p2p_stop_find(wpa_s);
- p2p_ctrl_flush(wpa_s);
- wpas_p2p_group_remove(wpa_s, "*");
- wpas_p2p_service_flush(wpa_s);
- wpa_s->global->p2p_disabled = 0;
- wpa_s->global->p2p_per_sta_psk = 0;
- wpa_s->conf->num_sec_device_types = 0;
- wpa_s->p2p_disable_ip_addr_req = 0;
- os_free(wpa_s->global->p2p_go_avoid_freq.range);
- wpa_s->global->p2p_go_avoid_freq.range = NULL;
+ wpas_p2p_cancel(p2p_wpa_s);
+ p2p_ctrl_flush(p2p_wpa_s);
+ wpas_p2p_group_remove(p2p_wpa_s, "*");
+ wpas_p2p_service_flush(p2p_wpa_s);
+ p2p_wpa_s->global->p2p_disabled = 0;
+ p2p_wpa_s->global->p2p_per_sta_psk = 0;
+ p2p_wpa_s->conf->num_sec_device_types = 0;
+ p2p_wpa_s->p2p_disable_ip_addr_req = 0;
+ os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
+ p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
@@ -6145,8 +6172,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->sta_uapsd = 0;
wpa_drv_radio_disable(wpa_s, 0);
-
- wpa_bss_flush(wpa_s);
wpa_blacklist_clear(wpa_s);
wpa_s->extra_blacklist_count = 0;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
@@ -6176,11 +6201,22 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->ext_eapol_frame_io = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->extra_roc_dur = 0;
+ wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
+
+ wpa_bss_flush(wpa_s);
+ if (!dl_list_empty(&wpa_s->bss)) {
+ wpa_printf(MSG_DEBUG,
+ "BSS table not empty after flush: %u entries, current_bss=%p bssid="
+ MACSTR " pending_bssid=" MACSTR,
+ dl_list_len(&wpa_s->bss), wpa_s->current_bss,
+ MAC2STR(wpa_s->bssid),
+ MAC2STR(wpa_s->pending_bssid));
+ }
}
@@ -7873,8 +7909,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
reply_len = -1;
- } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
- if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+ } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
+ if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
@@ -8182,6 +8218,8 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
"P2P_PRESENCE_REQ ",
"P2P_EXT_LISTEN ",
"P2P_REMOVE_CLIENT ",
+ "WPS_NFC_TOKEN ",
+ "WPS_NFC_TAG_READ ",
"NFC_GET_HANDOVER_SEL ",
"NFC_GET_HANDOVER_REQ ",
"NFC_REPORT_HANDOVER ",
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 2c1c6a05..b1ac7666 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -74,7 +74,7 @@ static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
- socklen_t fromlen)
+ socklen_t fromlen, int global)
{
struct wpa_ctrl_dst *dst;
char addr_txt[200];
@@ -89,7 +89,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
printf_encode(addr_txt, sizeof(addr_txt),
(u8 *) from->sun_path,
fromlen - offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
+ global ? "global " : "", addr_txt);
return 0;
}
@@ -174,7 +175,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
- fromlen))
+ fromlen, 0))
reply_len = 1;
else {
new_attached = 1;
@@ -775,7 +776,8 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
if (os_strcmp(buf, "ATTACH") == 0) {
/* handle ATTACH signal of first monitor interface */
if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
- &from, fromlen)) {
+ &from, fromlen,
+ 0)) {
if (sendto(priv->sock, "OK\n", 3, 0,
(struct sockaddr *) &from, fromlen) <
0) {
@@ -830,7 +832,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
- fromlen))
+ fromlen, 1))
reply_len = 1;
else
reply_len = 2;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index b30cc389..30ef03a7 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -748,6 +748,8 @@ nomem:
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -771,6 +773,9 @@ void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
!wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
+ (altsubject && num_altsubject &&
+ !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
+ altsubject, num_altsubject)) ||
(cert_hash &&
!wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
cert_hash)) ||
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 5f32bbf6..d162d2b6 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -215,6 +215,8 @@ void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert);
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
@@ -484,6 +486,8 @@ wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth,
const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 9aff2c13..0b029207 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -254,6 +254,19 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
if (wpa_config_set(ssid, entry.key, value, 0) < 0)
goto error;
+ if (os_strcmp(entry.key, "bssid") != 0 &&
+ os_strcmp(entry.key, "priority") != 0)
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+ if (wpa_s->current_ssid == ssid ||
+ wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if anything in the
+ * current or previously used configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
(os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 8dc48d38..9debcf84 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -90,6 +90,10 @@ static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
+ return -EBUSY;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->driver->scan2)
return wpa_s->driver->scan2(wpa_s->drv_priv, params);
return -1;
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index aa9ab50c..9b7af305 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -480,6 +480,7 @@ static void eapol_test_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -509,6 +510,14 @@ static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
eapol_test_write_cert(e->server_cert_file,
subject, cert);
}
+
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", depth, altsubject[i]);
+ }
}
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index afda42a6..a89ab298 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1313,7 +1313,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_RANDOM_POOL */
if (own_request && wpa_s->scan_res_handler &&
- (wpa_s->own_scan_running || !wpa_s->external_scan_running)) {
+ (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -1334,7 +1334,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
}
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
- wpa_s->own_scan_running, wpa_s->external_scan_running);
+ wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
@@ -1347,7 +1347,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpas_notify_scan_done(wpa_s, 1);
- if (!wpa_s->own_scan_running && wpa_s->external_scan_running) {
+ if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
return 0;
@@ -3077,7 +3077,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
- wpa_s->external_scan_running = 1;
+ wpa_s->radio->external_scan_running = 1;
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
break;
@@ -3093,7 +3093,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
wpa_supplicant_event_scan_results(wpa_s, data);
wpa_s->own_scan_running = 0;
- wpa_s->external_scan_running = 0;
+ wpa_s->radio->external_scan_running = 0;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 9eb50646..eb18ed2b 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <sys/stat.h>
#include "common.h"
#include "eloop.h"
@@ -216,6 +217,30 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
}
+static void hs20_set_osu_access_permission(const char *osu_dir,
+ const char *fname)
+{
+ struct stat statbuf;
+
+ /* Get OSU directory information */
+ if (stat(osu_dir, &statbuf) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
+ osu_dir);
+ return;
+ }
+
+ if (chmod(fname, statbuf.st_mode) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot change the permissions for %s", fname);
+ return;
+ }
+
+ if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
+ fname);
+ }
+}
+
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *pos,
size_t slen)
@@ -278,6 +303,9 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
f = fopen(fname, "wb");
if (f == NULL)
return -1;
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
if (fwrite(pos, slen, 1, f) != 1) {
fclose(f);
unlink(fname);
@@ -327,11 +355,11 @@ static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *data, size_t slen)
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen)
{
const u8 *pos = data;
u8 subtype;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
int ret;
@@ -479,6 +507,9 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
hs20_free_osu_prov(wpa_s);
return;
}
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
for (i = 0; i < wpa_s->osu_prov_count; i++) {
struct osu_provider *osu = &wpa_s->osu_prov[i];
if (i > 0)
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 06739f5c..85b51201 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -17,7 +17,8 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *data, size_t slen);
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 116df052..3e919bd2 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -73,6 +73,8 @@ static int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b)
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
{
+ unsigned int tried;
+
if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s,
@@ -80,10 +82,13 @@ static void interworking_reconnect(struct wpa_supplicant *wpa_s)
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ tried = wpa_s->interworking_fast_assoc_tried;
+ wpa_s->interworking_fast_assoc_tried = 1;
- if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+ if (!tried && wpa_supplicant_fast_associate(wpa_s) >= 0)
return;
+ wpa_s->interworking_fast_assoc_tried = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -2556,7 +2561,12 @@ void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
wpa_s->fetch_anqp_in_progress = 1;
- interworking_next_anqp_fetch(wpa_s);
+
+ /*
+ * Start actual ANQP operation from eloop call to make sure the loop
+ * does not end up using excessive recursion.
+ */
+ eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL);
}
@@ -2739,8 +2749,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
switch (type) {
case HS20_ANQP_OUI_TYPE:
- hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
- slen);
+ hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
+ pos, slen);
break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
@@ -2775,6 +2785,7 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
u16 info_id;
u16 slen;
struct wpa_bss *bss = NULL, *tmp;
+ const char *anqp_result = "SUCCESS";
wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
" dialog_token=%u result=%d status_code=%u",
@@ -2782,7 +2793,8 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
if (result != GAS_QUERY_SUCCESS) {
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
- return;
+ anqp_result = "FAILURE";
+ goto out;
}
pos = wpabuf_head(adv_proto);
@@ -2792,7 +2804,8 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
"Protocol in response");
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
- return;
+ anqp_result = "INVALID_FRAME";
+ goto out;
}
/*
@@ -2818,7 +2831,8 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
if (left < 4) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
- break;
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
info_id = WPA_GET_LE16(pos);
pos += 2;
@@ -2828,14 +2842,19 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
if (left < slen) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
"for Info ID %u", info_id);
- break;
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
+out_parse_done:
hs20_notify_parse_done(wpa_s);
+out:
+ wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
+ MAC2STR(dst), anqp_result);
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 5fdf4e08..32506b67 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -166,6 +166,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
bss->conf = *conf->bss;
bss->conf->start_disabled = 1;
bss->conf->mesh = MESH_ENABLED;
+ bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
bss->iconf = conf;
ifmsh->conf = conf;
@@ -339,6 +340,7 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
}
+ params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index df1ce9e0..bf1836a5 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -690,13 +690,13 @@ void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s'%s%s",
- depth, subject,
- cert_hash ? " hash=" : "",
+ depth, subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "");
if (cert) {
@@ -714,11 +714,20 @@ void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
}
}
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", depth, altsubject[i]);
+ }
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
cert_hash, cert);
/* notify the new DBus API */
- wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+ wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 7feb5304..7fb1f58e 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -121,7 +121,8 @@ void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert);
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *dst, const u8 *bssid,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 59f95c35..4364a064 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -3158,14 +3158,14 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
}
#ifdef CONFIG_WPS_NFC
- if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
- dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+ if (dev_pw_id >= 0 && wpa_s->p2p_nfc_tag_enabled &&
+ dev_pw_id == wpa_s->p2p_oob_dev_pw_id) {
wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
- wpa_s->parent->p2p_wps_method = WPS_NFC;
- wpa_s->parent->pending_join_wps_method = WPS_NFC;
- os_memcpy(wpa_s->parent->pending_join_dev_addr,
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memcpy(wpa_s->pending_join_dev_addr,
go_dev_addr, ETH_ALEN);
- os_memcpy(wpa_s->parent->pending_join_iface_addr,
+ os_memcpy(wpa_s->pending_join_iface_addr,
bssid, ETH_ALEN);
goto accept_inv;
}
@@ -6177,6 +6177,12 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
pref_freq = 0;
}
+ /*
+ * Stop any find/listen operations before invitation and possibly
+ * connection establishment.
+ */
+ wpas_p2p_stop_find_oper(wpa_s);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
1, pref_freq, -1);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index cb2c8d63..08af9fba 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -168,17 +168,34 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
wpa_supplicant_notify_scanning(wpa_s, 1);
- if (wpa_s->clear_driver_scan_cache)
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
+ }
ret = wpa_drv_scan(wpa_s, params);
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
+ int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ;
+
+ if (wpa_s->disconnected)
+ retry = 0;
+
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
- wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d",
- ret);
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d%s",
+ ret, retry ? " retry=1" : "");
radio_work_done(work);
+
+ if (retry) {
+ /* Restore scan_req since we will try to scan again */
+ wpa_s->scan_req = wpa_s->last_scan_req;
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ }
return;
}
@@ -610,7 +627,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
- enum wpa_states prev_state;
if (wpa_s->pno || wpa_s->pno_sched_pending) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
@@ -678,7 +694,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
os_memset(&params, 0, sizeof(params));
- prev_state = wpa_s->wpa_state;
+ wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
if (wpa_s->wpa_state == WPA_DISCONNECTED ||
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
@@ -876,8 +892,11 @@ ssid_list_set:
extra_ie = wpa_supplicant_extra_ies(wpa_s);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
- wpa_s->manual_scan_only_new)
+ wpa_s->manual_scan_only_new) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to manual only_new=1 scan");
params.only_new_results = 1;
+ }
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
wpa_s->manual_scan_freqs) {
@@ -995,13 +1014,17 @@ scan:
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
- if (prev_state != wpa_s->wpa_state)
- wpa_supplicant_set_state(wpa_s, prev_state);
+ if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
/* Restore scan_req since we will try to scan again */
wpa_s->scan_req = wpa_s->last_scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
} else {
wpa_s->scan_for_connection = 0;
+#ifdef CONFIG_INTERWORKING
+ wpa_s->interworking_fast_assoc_tried = 0;
+#endif /* CONFIG_INTERWORKING */
}
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 80c280a1..d34668a5 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -449,6 +449,20 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+ size_t len;
+
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+ if (wpabuf_len(buf) <= len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
+ }
+ }
+
sme_auth_handle_rrm(wpa_s, bss);
#ifdef CONFIG_SAE
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index d2face01..79619f2d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1577,6 +1577,10 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
wpa_cli_close_connection();
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(argv[0]);
+ if (!ctrl_ifname) {
+ printf("Failed to allocate memory\n");
+ return 0;
+ }
if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
printf("Connected to interface '%s.\n", ctrl_ifname);
@@ -3743,7 +3747,8 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx)
if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
if (!warning_displayed) {
printf("Could not connect to wpa_supplicant: "
- "%s - re-trying\n", ctrl_ifname);
+ "%s - re-trying\n",
+ ctrl_ifname ? ctrl_ifname : "(nil)");
warning_displayed = 1;
}
eloop_register_timeout(1, 0, try_connection, NULL, NULL);
@@ -4004,7 +4009,8 @@ int main(int argc, char *argv[])
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
fprintf(stderr, "Failed to connect to non-global "
"ctrl_ifname: %s error: %s\n",
- ctrl_ifname, strerror(errno));
+ ctrl_ifname ? ctrl_ifname : "(nil)",
+ strerror(errno));
return -1;
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 9994a7a9..47243a3f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2029,6 +2029,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
}
}
+ if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+ size_t len;
+
+ len = sizeof(wpa_ie) - wpa_ie_len;
+ if (wpabuf_len(buf) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_ie_len += wpabuf_len(buf);
+ }
+ }
+
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -2184,7 +2196,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
params.vhtcaps = &vhtcaps;
params.vhtcaps_mask = &vhtcaps_mask;
- wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, &params);
+ wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_P2P
@@ -3599,7 +3611,7 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
radio_list);
- if (wpa_s && wpa_s->external_scan_running) {
+ if (wpa_s && wpa_s->radio->external_scan_running) {
wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
return;
}
@@ -5020,6 +5032,8 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ else
+ wpa_s->reattach = 0;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 7d189c72..23c22998 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -127,6 +127,17 @@ ap_scan=1
# Maximum number of mesh peering currently maintained by the STA.
#max_peer_links=99
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in mesh STA to clean up inactive stations.
+#mesh_max_inactivity=300
+
+# cert_in_cb - Whether to include a peer certificate dump in events
+# This controls whether peer certificates for authentication server and
+# its certificate chain are included in EAP peer certificate events. This is
+# enabled by default.
+#cert_in_cb=1
+
# EAP fast re-authentication
# By default, fast re-authentication is enabled for all EAP methods that
# support it. This variable can be used to disable fast re-authentication.
@@ -867,7 +878,8 @@ fast_reauth=1
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
# Note: Since this is a substring match, this cannot be used securily to
# do a suffix match against a possible domain name in the CN entry. For
-# such a use case, domain_suffix_match should be used instead.
+# such a use case, domain_suffix_match or domain_match should be used
+# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
# If this string is set, the server sertificate is only accepted if it
@@ -890,6 +902,16 @@ fast_reauth=1
#
# For example, domain_suffix_match=example.com would match
# test.example.com but would not match test-example.com.
+# domain_match: Constraint for server domain name
+# If set, this FQDN is used as a full match requirement for the
+# server certificate in SubjectAltName dNSName element(s). If a
+# matching dNSName is found, this constraint is met. If no dNSName
+# values are present, this constraint is matched against SubjectName CN
+# using same full match comparison. This behavior is similar to
+# domain_suffix_match, but has the requirement of a full match, i.e.,
+# no subdomains or wildcard matches are allowed. Case-insensitive
+# comparison is used, so "Example.com" matches "example.com", but would
+# not match "test.Example.com".
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index e396a5df..d1938fab 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -296,6 +296,7 @@ struct wpa_global {
struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
+ unsigned int external_scan_running:1;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
@@ -403,6 +404,11 @@ struct rrm_data {
u8 next_neighbor_rep_token;
};
+enum wpa_supplicant_test_failure {
+ WPAS_TEST_FAILURE_NONE,
+ WPAS_TEST_FAILURE_SCAN_TRIGGER,
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -580,6 +586,7 @@ struct wpa_supplicant {
*/
MANUAL_SCAN_REQ
} scan_req, last_scan_req;
+ enum wpa_states scan_prev_wpa_state;
struct os_reltime scan_trigger_time, scan_start_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
@@ -590,7 +597,6 @@ struct wpa_supplicant {
unsigned int manual_scan_only_new:1;
unsigned int own_scan_requested:1;
unsigned int own_scan_running:1;
- unsigned int external_scan_running:1;
unsigned int clear_driver_scan_cache:1;
unsigned int manual_scan_id;
int scan_interval; /* time in sec between scans to find suitable AP */
@@ -857,6 +863,7 @@ struct wpa_supplicant {
unsigned int network_select:1;
unsigned int auto_select:1;
unsigned int auto_network_select:1;
+ unsigned int interworking_fast_assoc_tried:1;
unsigned int fetch_all_anqp:1;
unsigned int fetch_osu_info:1;
unsigned int fetch_osu_waiting_scan:1;
@@ -939,6 +946,7 @@ struct wpa_supplicant {
#ifdef CONFIG_TESTING_OPTIONS
struct l2_packet_data *l2_test;
unsigned int extra_roc_dur;
+ enum wpa_supplicant_test_failure test_failure;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 209e2bce..83870433 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -860,12 +860,14 @@ static void wpa_supplicant_port_cb(void *ctx, int authorized)
static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
struct wpa_supplicant *wpa_s = ctx;
- wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+ wpas_notify_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -948,6 +950,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
+ ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;