diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2015-01-21 13:19:05 -0800 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2015-01-21 13:26:50 -0800 |
commit | 2f74e36e84064ffa32f82f3decf36b653c7e4fad (patch) | |
tree | 184eb654d7eeb89fbca4b8735baf64c07c1c721d | |
parent | ff787d557db719adea0fdf2679667500c65cf74d (diff) | |
download | android_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>
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(¶ms, 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, ¶ms); + wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms); #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; |