diff options
Diffstat (limited to 'freebsd/contrib/wpa/wpa_supplicant')
39 files changed, 4539 insertions, 887 deletions
diff --git a/freebsd/contrib/wpa/wpa_supplicant/ap.h b/freebsd/contrib/wpa/wpa_supplicant/ap.h index 594168cf..5a59ddcc 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/ap.h +++ b/freebsd/contrib/wpa/wpa_supplicant/ap.h @@ -76,12 +76,16 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, const struct wpabuf *pw, const u8 *pubkey_hash); struct hostapd_config; -void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, - struct hostapd_config *conf); +int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct hostapd_config *conf); int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s); +int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, + size_t len); +void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s); + void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s, struct dfs_event *radar); void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s, diff --git a/freebsd/contrib/wpa/wpa_supplicant/autoscan.h b/freebsd/contrib/wpa/wpa_supplicant/autoscan.h index e2a76522..560684fc 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/autoscan.h +++ b/freebsd/contrib/wpa/wpa_supplicant/autoscan.h @@ -27,6 +27,16 @@ void autoscan_deinit(struct wpa_supplicant *wpa_s); int autoscan_notify_scan(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); +/* Available autoscan modules */ + +#ifdef CONFIG_AUTOSCAN_EXPONENTIAL +extern const struct autoscan_ops autoscan_exponential_ops; +#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */ + +#ifdef CONFIG_AUTOSCAN_PERIODIC +extern const struct autoscan_ops autoscan_periodic_ops; +#endif /* CONFIG_AUTOSCAN_PERIODIC */ + #else /* CONFIG_AUTOSCAN */ static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan) diff --git a/freebsd/contrib/wpa/wpa_supplicant/bgscan.h b/freebsd/contrib/wpa/wpa_supplicant/bgscan.h index 9131e4ec..3df1550a 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/bgscan.h +++ b/freebsd/contrib/wpa/wpa_supplicant/bgscan.h @@ -39,6 +39,15 @@ void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above, int current_signal, int current_noise, int current_txrate); +/* Available bgscan modules */ + +#ifdef CONFIG_BGSCAN_SIMPLE +extern const struct bgscan_ops bgscan_simple_ops; +#endif /* CONFIG_BGSCAN_SIMPLE */ +#ifdef CONFIG_BGSCAN_LEARN +extern const struct bgscan_ops bgscan_learn_ops; +#endif /* CONFIG_BGSCAN_LEARN */ + #else /* CONFIG_BGSCAN */ static inline int bgscan_init(struct wpa_supplicant *wpa_s, diff --git a/freebsd/contrib/wpa/wpa_supplicant/binder/binder.h b/freebsd/contrib/wpa/wpa_supplicant/binder/binder.h new file mode 100644 index 00000000..019e3275 --- /dev/null +++ b/freebsd/contrib/wpa/wpa_supplicant/binder/binder.h @@ -0,0 +1,46 @@ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_H +#define WPA_SUPPLICANT_BINDER_BINDER_H + +#ifdef _cplusplus +extern "C" { +#endif /* _cplusplus */ + +/** + * This is the binder RPC interface entry point to the wpa_supplicant core. + * This initializes the binder driver & BinderManager instance and then forwards + * all the notifcations from the supplicant core to the BinderManager. + */ +struct wpas_binder_priv; +struct wpa_global; + +struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global); +void wpas_binder_deinit(struct wpas_binder_priv *priv); + +#ifdef CONFIG_CTRL_IFACE_BINDER +int wpas_binder_register_interface(struct wpa_supplicant *wpa_s); +int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s); +#else /* CONFIG_CTRL_IFACE_BINDER */ +static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +#endif /* CONFIG_CTRL_IFACE_BINDER */ + +#ifdef _cplusplus +} +#endif /* _cplusplus */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/bss.c b/freebsd/contrib/wpa/wpa_supplicant/bss.c index ff40bef0..4f805b1b 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/bss.c +++ b/freebsd/contrib/wpa/wpa_supplicant/bss.c @@ -14,6 +14,7 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "drivers/driver.h" +#include "eap_peer/eap.h" #include "wpa_supplicant_i.h" #include "config.h" #include "notify.h" @@ -62,6 +63,9 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void) anqp = os_zalloc(sizeof(*anqp)); if (anqp == NULL) return NULL; +#ifdef CONFIG_INTERWORKING + dl_list_init(&anqp->anqp_elems); +#endif /* CONFIG_INTERWORKING */ anqp->users = 1; return anqp; } @@ -82,6 +86,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) #ifdef CONFIG_INTERWORKING + dl_list_init(&n->anqp_elems); ANQP_DUP(capability_list); ANQP_DUP(venue_name); ANQP_DUP(network_auth_type); @@ -143,6 +148,10 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss) */ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) { +#ifdef CONFIG_INTERWORKING + struct wpa_bss_anqp_elem *elem; +#endif /* CONFIG_INTERWORKING */ + if (anqp == NULL) return; @@ -161,6 +170,13 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) wpabuf_free(anqp->nai_realm); wpabuf_free(anqp->anqp_3gpp); wpabuf_free(anqp->domain_name); + + while ((elem = dl_list_first(&anqp->anqp_elems, + struct wpa_bss_anqp_elem, list))) { + dl_list_del(&elem->list); + wpabuf_free(elem->payload); + os_free(elem); + } #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 wpabuf_free(anqp->hs20_capability_list); @@ -200,8 +216,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, } -static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - const char *reason) +void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const char *reason) { if (wpa_s->last_scan_res) { unsigned int i; @@ -290,6 +306,47 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, } +static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ +#ifdef CONFIG_WPS + struct wpa_ssid *ssid; + struct wpabuf *wps_ie; + int pbc = 0, ret; + + wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + if (!wps_ie) + return 0; + + if (wps_is_selected_pbc_registrar(wps_ie)) { + pbc = 1; + } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) { + wpabuf_free(wps_ie); + return 0; + } + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) + continue; + if (ssid->ssid_len && + (ssid->ssid_len != bss->ssid_len || + os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0)) + continue; + + if (pbc) + ret = eap_is_wps_pbc_enrollee(&ssid->eap); + else + ret = eap_is_wps_pin_enrollee(&ssid->eap); + wpabuf_free(wps_ie); + return ret; + } + wpabuf_free(wps_ie); +#endif /* CONFIG_WPS */ + + return 0; +} + + static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_ssid *ssid; @@ -328,7 +385,8 @@ static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s) struct wpa_bss *bss; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (!wpa_bss_known(wpa_s, bss)) { + if (!wpa_bss_known(wpa_s, bss) && + !wpa_bss_is_wps_candidate(wpa_s, bss)) { wpa_bss_remove(wpa_s, bss, __func__); return 0; } @@ -786,7 +844,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, struct wpa_bss *bss, *n; os_get_reltime(&wpa_s->last_scan); - if (!new_scan) + if ((info && info->aborted) || !new_scan) return; /* do not expire entries without new scan */ dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { @@ -1006,20 +1064,7 @@ struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s, */ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) { - const u8 *end, *pos; - - pos = (const u8 *) (bss + 1); - end = pos + bss->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; + return get_ie((const u8 *) (bss + 1), bss->ie_len, ie); } @@ -1039,8 +1084,8 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1076,8 +1121,8 @@ const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss, pos += bss->ie_len; end = pos + bss->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1112,8 +1157,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, pos = (const u8 *) (bss + 1); end = pos + bss->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1157,8 +1202,8 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, pos += bss->ie_len; end = pos + bss->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) diff --git a/freebsd/contrib/wpa/wpa_supplicant/bss.h b/freebsd/contrib/wpa/wpa_supplicant/bss.h index b215380e..84e8fb07 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/bss.h +++ b/freebsd/contrib/wpa/wpa_supplicant/bss.h @@ -19,6 +19,12 @@ struct wpa_scan_res; #define WPA_BSS_ASSOCIATED BIT(5) #define WPA_BSS_ANQP_FETCH_TRIED BIT(6) +struct wpa_bss_anqp_elem { + struct dl_list list; + u16 infoid; + struct wpabuf *payload; +}; + /** * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss) */ @@ -34,6 +40,7 @@ struct wpa_bss_anqp { struct wpabuf *nai_realm; struct wpabuf *anqp_3gpp; struct wpabuf *domain_name; + struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */ #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 struct wpabuf *hs20_capability_list; @@ -106,6 +113,8 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s); void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, struct os_reltime *fetch_time); +void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const char *reason); void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, int new_scan); int wpa_bss_init(struct wpa_supplicant *wpa_s); @@ -141,6 +150,17 @@ static inline int bss_is_dmg(const struct wpa_bss *bss) return bss->freq > 45000; } +/** + * Test whether a BSS is a PBSS. + * This checks whether a BSS is a DMG-band PBSS. PBSS is used for P2P DMG + * network. + */ +static inline int bss_is_pbss(struct wpa_bss *bss) +{ + return bss_is_dmg(bss) && + (bss->caps & IEEE80211_CAP_DMG_MASK) == IEEE80211_CAP_DMG_PBSS; +} + static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level) { if (bss != NULL && new_level < 0) diff --git a/freebsd/contrib/wpa/wpa_supplicant/config.c b/freebsd/contrib/wpa/wpa_supplicant/config.c index 992ba83d..cf9da641 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/config.c +++ b/freebsd/contrib/wpa/wpa_supplicant/config.c @@ -34,7 +34,11 @@ struct parse_data { /* Configuration variable name */ char *name; - /* Parser function for this variable */ + /* Parser function for this variable. The parser functions return 0 or 1 + * to indicate success. Value 0 indicates that the parameter value may + * have changed while value 1 means that the value did not change. + * Error cases (failure to parse the string) are indicated by returning + * -1. */ int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value); @@ -61,7 +65,7 @@ static int wpa_config_parse_str(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { - size_t res_len, *dst_len; + size_t res_len, *dst_len, prev_len; char **dst, *tmp; if (os_strcmp(value, "NULL") == 0) { @@ -107,6 +111,21 @@ static int wpa_config_parse_str(const struct parse_data *data, set: dst = (char **) (((u8 *) ssid) + (long) data->param1); dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); + + if (data->param2) + prev_len = *dst_len; + else if (*dst) + prev_len = os_strlen(*dst); + else + prev_len = 0; + if ((*dst == NULL && tmp == NULL) || + (*dst && tmp && prev_len == res_len && + os_memcmp(*dst, tmp, res_len) == 0)) { + /* No change to the previously configured value */ + os_free(tmp); + return 1; + } + os_free(*dst); *dst = tmp; if (data->param2) @@ -192,6 +211,9 @@ static int wpa_config_parse_int(const struct parse_data *data, line, value); return -1; } + + if (*dst == val) + return 1; *dst = val; wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); @@ -458,9 +480,17 @@ static int wpa_config_parse_psk(const struct parse_data *data, } wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", (u8 *) value, len); + if (has_ctrl_char((u8 *) value, len)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid passphrase character", + line); + return -1; + } if (ssid->passphrase && os_strlen(ssid->passphrase) == len && - os_memcmp(ssid->passphrase, value, len) == 0) - return 0; + os_memcmp(ssid->passphrase, value, len) == 0) { + /* No change to the previously configured value */ + return 1; + } ssid->psk_set = 0; str_clear_free(ssid->passphrase); ssid->passphrase = dup_binstr(value, len); @@ -571,6 +601,8 @@ static int wpa_config_parse_proto(const struct parse_data *data, errors++; } + if (!errors && ssid->proto == val) + return 1; wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); ssid->proto = val; return errors ? -1 : 0; @@ -707,6 +739,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, errors++; } + if (!errors && ssid->key_mgmt == val) + return 1; wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); ssid->key_mgmt = val; return errors ? -1 : 0; @@ -901,6 +935,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, static int wpa_config_parse_cipher(int line, const char *value) { +#ifdef CONFIG_NO_WPA + return -1; +#else /* CONFIG_NO_WPA */ int val = wpa_parse_cipher(value); if (val < 0) { wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", @@ -913,12 +950,16 @@ static int wpa_config_parse_cipher(int line, const char *value) return -1; } return val; +#endif /* CONFIG_NO_WPA */ } #ifndef NO_CONFIG_WRITE static char * wpa_config_write_cipher(int cipher) { +#ifdef CONFIG_NO_WPA + return NULL; +#else /* CONFIG_NO_WPA */ char *buf = os_zalloc(50); if (buf == NULL) return NULL; @@ -929,6 +970,7 @@ static char * wpa_config_write_cipher(int cipher) } return buf; +#endif /* CONFIG_NO_WPA */ } #endif /* NO_CONFIG_WRITE */ @@ -947,6 +989,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data, return -1; } + if (ssid->pairwise_cipher == val) + return 1; wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); ssid->pairwise_cipher = val; return 0; @@ -983,6 +1027,8 @@ static int wpa_config_parse_group(const struct parse_data *data, return -1; } + if (ssid->group_cipher == val) + return 1; wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); ssid->group_cipher = val; return 0; @@ -1044,6 +1090,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data, errors++; } + if (!errors && ssid->auth_alg == val) + return 1; wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); ssid->auth_alg = val; return errors ? -1 : 0; @@ -1298,6 +1346,32 @@ static int wpa_config_parse_eap(const struct parse_data *data, methods[num_methods].method = EAP_TYPE_NONE; num_methods++; + if (!errors && ssid->eap.eap_methods) { + struct eap_method_type *prev_m; + size_t i, j, prev_methods, match = 0; + + prev_m = ssid->eap.eap_methods; + for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF || + prev_m[i].method != EAP_TYPE_NONE; i++) { + /* Count the methods */ + } + prev_methods = i + 1; + + for (i = 0; prev_methods == num_methods && i < prev_methods; + i++) { + for (j = 0; j < num_methods; j++) { + if (prev_m[i].vendor == methods[j].vendor && + prev_m[i].method == methods[j].method) { + match++; + break; + } + } + } + if (match == num_methods) { + os_free(methods); + return 1; + } + } wpa_hexdump(MSG_MSGDUMP, "eap methods", (u8 *) methods, num_methods * sizeof(*methods)); os_free(ssid->eap.eap_methods); @@ -1350,6 +1424,8 @@ static int wpa_config_parse_password(const struct parse_data *data, u8 *hash; if (os_strcmp(value, "NULL") == 0) { + if (!ssid->eap.password) + return 1; /* Already unset */ wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); bin_clear_free(ssid->eap.password, ssid->eap.password_len); ssid->eap.password = NULL; @@ -1413,6 +1489,12 @@ static int wpa_config_parse_password(const struct parse_data *data, wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); + if (ssid->eap.password && ssid->eap.password_len == 16 && + os_memcmp(ssid->eap.password, hash, 16) == 0 && + (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { + bin_clear_free(hash, 16); + return 1; + } bin_clear_free(ssid->eap.password, ssid->eap.password_len); ssid->eap.password = hash; ssid->eap.password_len = 16; @@ -1839,6 +1921,8 @@ static const struct parse_data ssid_fields[] = { { FUNC(auth_alg) }, { FUNC(scan_freq) }, { FUNC(freq_list) }, + { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT, + VHT_CHANWIDTH_80P80MHZ) }, #ifdef IEEE8021X_EAPOL { FUNC(eap) }, { STR_LENe(identity) }, @@ -1912,6 +1996,9 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(frequency, 0, 65000) }, { INT_RANGE(fixed_freq, 0, 1) }, +#ifdef CONFIG_ACS + { INT_RANGE(acs, 0, 1) }, +#endif /* CONFIG_ACS */ #ifdef CONFIG_MESH { FUNC(mesh_basic_rates) }, { INT(dot11MeshMaxRetries) }, @@ -1920,6 +2007,7 @@ static const struct parse_data ssid_fields[] = { { INT(dot11MeshHoldingTimeout) }, #endif /* CONFIG_MESH */ { INT(wpa_ptk_rekey) }, + { INT(group_rekey) }, { STR(bgscan) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, #ifdef CONFIG_P2P @@ -1969,6 +2057,8 @@ static const struct parse_data ssid_fields[] = { { INT(update_identifier) }, #endif /* CONFIG_HS20 */ { INT_RANGE(mac_addr, 0, 2) }, + { INT_RANGE(pbss, 0, 2) }, + { INT_RANGE(wps_disabled, 0, 1) }, }; #undef OFFSET @@ -2273,6 +2363,11 @@ void wpa_config_free(struct wpa_config *config) os_free(config->bgscan); os_free(config->wowlan_triggers); os_free(config->fst_group_id); + os_free(config->sched_scan_plans); +#ifdef CONFIG_MBO + os_free(config->non_pref_chan); +#endif /* CONFIG_MBO */ + os_free(config); } @@ -2455,7 +2550,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) * @var: Variable name, e.g., "ssid" * @value: Variable value * @line: Line number in configuration file or 0 if not used - * Returns: 0 on success, -1 on failure + * Returns: 0 on success with possible change in the value, 1 on success with + * no change to previously configured value, or -1 on failure * * This function can be used to set network configuration variables based on * both the configuration file and management interface input. The value @@ -2476,7 +2572,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, if (os_strcmp(var, field->name) != 0) continue; - if (field->parser(field, ssid, line, value)) { + ret = field->parser(field, ssid, line, value); + if (ret < 0) { if (line) { wpa_printf(MSG_ERROR, "Line %d: failed to " "parse %s '%s'.", line, var, value); @@ -2575,9 +2672,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) return props; err: - value = *props; - while (value) - os_free(value++); + for (i = 0; props[i]; i++) + os_free(props[i]); os_free(props); return NULL; #endif /* NO_CONFIG_WRITE */ @@ -2606,8 +2702,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var) for (i = 0; i < NUM_SSID_FIELDS; i++) { const struct parse_data *field = &ssid_fields[i]; - if (os_strcmp(var, field->name) == 0) - return field->writer(field, ssid); + if (os_strcmp(var, field->name) == 0) { + char *ret = field->writer(field, ssid); + + if (ret && has_newline(ret)) { + wpa_printf(MSG_ERROR, + "Found newline in value for %s; not returning it", + var); + os_free(ret); + ret = NULL; + } + + return ret; + } } return NULL; @@ -2792,6 +2899,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, if (os_strcmp(var, "password") == 0 && os_strncmp(value, "ext:", 4) == 0) { + if (has_newline(value)) + return -1; str_clear_free(cred->password); cred->password = os_strdup(value); cred->ext_password = 1; @@ -2842,9 +2951,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } val = wpa_config_parse_string(value, &len); - if (val == NULL) { + if (val == NULL || + (os_strcmp(var, "excluded_ssid") != 0 && + os_strcmp(var, "roaming_consortium") != 0 && + os_strcmp(var, "required_roaming_consortium") != 0 && + has_newline(val))) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " "value '%s'.", line, var, value); + os_free(val); return -1; } @@ -3542,6 +3656,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; config->cert_in_cb = DEFAULT_CERT_IN_CB; + config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION; + +#ifdef CONFIG_MBO + config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; +#endif /* CONFIG_MBO */ if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); @@ -3648,6 +3767,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data, return -1; } + if (has_newline(pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline", + line, data->name); + return -1; + } + tmp = os_strdup(pos); if (tmp == NULL) return -1; @@ -3686,22 +3811,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) { - size_t len; struct wpabuf **dst, *tmp; - len = os_strlen(pos); - if (len & 0x01) - return -1; - - tmp = wpabuf_alloc(len / 2); - if (tmp == NULL) + tmp = wpabuf_parse_bin(pos); + if (!tmp) return -1; - if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) { - wpabuf_free(tmp); - return -1; - } - dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); wpabuf_free(*dst); *dst = tmp; @@ -4248,6 +4363,16 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 }, { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 }, #endif /* CONFIG_FST */ + { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 }, + { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS }, +#ifdef CONFIG_MBO + { STR(non_pref_chan), 0 }, + { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE, + MBO_CELL_CAPA_NOT_SUPPORTED), 0 }, +#endif /*CONFIG_MBO */ + { INT(gas_address3), 0 }, + { INT_RANGE(ftm_responder, 0, 1), 0 }, + { INT_RANGE(ftm_initiator, 0, 1), 0 }, }; #undef FUNC @@ -4306,6 +4431,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config, } +int wpa_config_get_num_global_field_names(void) +{ + return NUM_GLOBAL_FIELDS; +} + + +const char * wpa_config_get_global_field_name(unsigned int i, int *no_var) +{ + if (i >= NUM_GLOBAL_FIELDS) + return NULL; + + if (no_var) + *no_var = !global_fields[i].param1; + return global_fields[i].name; +} + + int wpa_config_process_global(struct wpa_config *config, char *pos, int line) { size_t i; diff --git a/freebsd/contrib/wpa/wpa_supplicant/config.h b/freebsd/contrib/wpa/wpa_supplicant/config.h index 9de7e704..9d41fd17 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/config.h +++ b/freebsd/contrib/wpa/wpa_supplicant/config.h @@ -39,6 +39,8 @@ #define DEFAULT_KEY_MGMT_OFFLOAD 1 #define DEFAULT_CERT_IN_CB 1 #define DEFAULT_P2P_GO_CTWINDOW 0 +#define DEFAULT_WPA_RSC_RELAXATION 1 +#define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED #include "config_ssid.h" #include "wps/wps.h" @@ -334,6 +336,7 @@ struct wpa_cred { #define CFG_CHANGED_EXT_PW_BACKEND BIT(14) #define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15) #define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16) +#define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17) /** * struct wpa_config - wpa_supplicant configuration data @@ -764,12 +767,17 @@ struct wpa_config { * frequency list of the local device and the peer device. * * @P2P_GO_FREQ_MOVE_STAY: Prefer to stay on the current frequency. + * + * @P2P_GO_FREQ_MOVE_SCM_ECSA: Same as + * P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS but a transition is possible only + * if all the group members advertise eCSA support. */ enum { P2P_GO_FREQ_MOVE_SCM = 0, P2P_GO_FREQ_MOVE_SCM_PEER_SUPPORTS = 1, P2P_GO_FREQ_MOVE_STAY = 2, - P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_STAY, + P2P_GO_FREQ_MOVE_SCM_ECSA = 3, + P2P_GO_FREQ_MOVE_MAX = P2P_GO_FREQ_MOVE_SCM_ECSA, } p2p_go_freq_change_policy; #define DEFAULT_P2P_GO_FREQ_MOVE P2P_GO_FREQ_MOVE_STAY @@ -1034,7 +1042,8 @@ struct wpa_config { * * By default, PMF is disabled unless enabled by the per-network * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change - * this default behavior. + * this default behavior for RSN network (this is not applicable for + * non-RSN cases). */ enum mfp_options pmf; @@ -1250,6 +1259,78 @@ struct wpa_config { * interface. */ int fst_llt; + + /** + * wpa_rsc_relaxation - RSC relaxation on GTK installation + * + * Values: + * 0 - use the EAPOL-Key RSC value on GTK installation + * 1 - use the null RSC if a bogus RSC value is detected in message 3 + * of 4-Way Handshake or message 1 of Group Key Handshake. + */ + int wpa_rsc_relaxation; + + /** + * sched_scan_plans - Scan plans for scheduled scan + * + * Each scan plan specifies the interval between scans and the number of + * iterations. The last scan plan only specifies the scan interval and + * will be run infinitely. + * + * format: <interval:iterations> <interval2:iterations2> ... <interval> + */ + char *sched_scan_plans; + +#ifdef CONFIG_MBO + /** + * non_pref_chan - Non-preferred channels list, separated by spaces. + * + * format: op_class:chan:preference:reason<:detail> + * Detail is optional. + */ + char *non_pref_chan; + + /** + * mbo_cell_capa - Cellular capabilities for MBO + */ + enum mbo_cellular_capa mbo_cell_capa; +#endif /* CONFIG_MBO */ + + /** + * gas_address3 - GAS Address3 field behavior + * + * Values: + * 0 - P2P specification (Address3 = AP BSSID) + * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when + * sent to not-associated AP; if associated, AP BSSID) + */ + int gas_address3; + + /** + * ftm_responder - Publish FTM (fine timing measurement) + * responder functionality + * + * Values: + * 0 - do not publish FTM responder functionality (Default) + * 1 - publish FTM responder functionality in + * bit 70 of Extended Capabilities element + * Note, actual FTM responder operation is managed outside + * wpa_supplicant. + */ + int ftm_responder; + + /** + * ftm_initiator - Publish FTM (fine timing measurement) + * initiator functionality + * + * Values: + * 0 - do not publish FTM initiator functionality (Default) + * 1 - publish FTM initiator functionality in + * bit 71 of Extended Capabilities element + * Note, actual FTM initiator operation is managed outside + * wpa_supplicant. + */ + int ftm_initiator; }; @@ -1308,6 +1389,9 @@ void wpa_config_debug_dump_networks(struct wpa_config *config); /* Prototypes for common functions from config.c */ int wpa_config_process_global(struct wpa_config *config, char *pos, int line); +int wpa_config_get_num_global_field_names(void); + +const char * wpa_config_get_global_field_name(unsigned int i, int *no_var); /* Prototypes for backend specific functions from the selected config_*.c */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/config_file.c b/freebsd/contrib/wpa/wpa_supplicant/config_file.c index 8466fc39..09df6c14 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/config_file.c +++ b/freebsd/contrib/wpa/wpa_supplicant/config_file.c @@ -749,10 +749,16 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(no_auto_peer); INT(frequency); INT(fixed_freq); +#ifdef CONFIG_ACS + INT(acs); +#endif /* CONFIG_ACS */ write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1); INT(disabled); INT(peerkey); INT(mixed_cell); + INT(max_oper_chwidth); + INT(pbss); + INT(wps_disabled); #ifdef CONFIG_IEEE80211W write_int(f, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); @@ -781,6 +787,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT); #endif /* CONFIG_MESH */ INT(wpa_ptk_rekey); + INT(group_rekey); INT(ignore_broadcast_ssid); #ifdef CONFIG_HT_OVERRIDES INT_DEF(disable_ht, DEFAULT_DISABLE_HT); @@ -1138,6 +1145,22 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->p2p_go_freq_change_policy != DEFAULT_P2P_GO_FREQ_MOVE) fprintf(f, "p2p_go_freq_change_policy=%u\n", config->p2p_go_freq_change_policy); + if (WPA_GET_BE32(config->ip_addr_go)) + fprintf(f, "ip_addr_go=%u.%u.%u.%u\n", + config->ip_addr_go[0], config->ip_addr_go[1], + config->ip_addr_go[2], config->ip_addr_go[3]); + if (WPA_GET_BE32(config->ip_addr_mask)) + fprintf(f, "ip_addr_mask=%u.%u.%u.%u\n", + config->ip_addr_mask[0], config->ip_addr_mask[1], + config->ip_addr_mask[2], config->ip_addr_mask[3]); + if (WPA_GET_BE32(config->ip_addr_start)) + fprintf(f, "ip_addr_start=%u.%u.%u.%u\n", + config->ip_addr_start[0], config->ip_addr_start[1], + config->ip_addr_start[2], config->ip_addr_start[3]); + if (WPA_GET_BE32(config->ip_addr_end)) + fprintf(f, "ip_addr_end=%u.%u.%u.%u\n", + config->ip_addr_end[0], config->ip_addr_end[1], + config->ip_addr_end[2], config->ip_addr_end[3]); #endif /* CONFIG_P2P */ if (config->country[0] && config->country[1]) { fprintf(f, "country=%c%c\n", @@ -1301,6 +1324,28 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->wps_priority) fprintf(f, "wps_priority=%d\n", config->wps_priority); + + if (config->wpa_rsc_relaxation != DEFAULT_WPA_RSC_RELAXATION) + fprintf(f, "wpa_rsc_relaxation=%d\n", + config->wpa_rsc_relaxation); + + if (config->sched_scan_plans) + fprintf(f, "sched_scan_plans=%s\n", config->sched_scan_plans); + +#ifdef CONFIG_MBO + if (config->non_pref_chan) + fprintf(f, "non_pref_chan=%s\n", config->non_pref_chan); + if (config->mbo_cell_capa != DEFAULT_MBO_CELL_CAPA) + fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa); +#endif /* CONFIG_MBO */ + + if (config->gas_address3) + fprintf(f, "gas_address3=%d\n", config->gas_address3); + + if (config->ftm_responder) + fprintf(f, "ftm_responder=%d\n", config->ftm_responder); + if (config->ftm_initiator) + fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/config_ssid.h b/freebsd/contrib/wpa/wpa_supplicant/config_ssid.h index 7ef326cf..010b594a 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/config_ssid.h +++ b/freebsd/contrib/wpa/wpa_supplicant/config_ssid.h @@ -360,6 +360,19 @@ struct wpa_ssid { } mode; /** + * pbss - Whether to use PBSS. Relevant to DMG networks only. + * 0 = do not use PBSS + * 1 = use PBSS + * 2 = don't care (not allowed in AP mode) + * Used together with mode configuration. When mode is AP, it + * means to start a PCP instead of a regular AP. When mode is INFRA it + * means connect to a PCP instead of AP. In this mode you can also + * specify 2 (don't care) meaning connect to either AP or PCP. + * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network. + */ + int pbss; + + /** * disabled - Whether this network is currently disabled * * 0 = this network can be used (default). @@ -431,6 +444,18 @@ struct wpa_ssid { */ int fixed_freq; +#ifdef CONFIG_ACS + /** + * ACS - Automatic Channel Selection for AP mode + * + * If present, it will be handled together with frequency. + * frequency will be used to determine hardware mode only, when it is + * used for both hardware mode and channel when used alone. This will + * force the channel to be set to 0, thus enabling ACS. + */ + int acs; +#endif /* CONFIG_ACS */ + /** * mesh_basic_rates - BSS Basic rate set for mesh network * @@ -449,6 +474,10 @@ struct wpa_ssid { int vht; + u8 max_oper_chwidth; + + unsigned int vht_center_freq2; + /** * wpa_ptk_rekey - Maximum lifetime for PTK in seconds * @@ -458,6 +487,14 @@ struct wpa_ssid { int wpa_ptk_rekey; /** + * group_rekey - Group rekeying time in seconds + * + * This value, if non-zero, is used as the dot11RSNAConfigGroupRekeyTime + * parameter when operating in Authenticator role in IBSS. + */ + int group_rekey; + + /** * scan_freq - Array of frequencies to scan or %NULL for all * * This is an optional zero-terminated array of frequencies in @@ -719,6 +756,14 @@ struct wpa_ssid { * this MBSS will trigger a peering attempt. */ int no_auto_peer; + + /** + * wps_disabled - WPS disabled in AP mode + * + * 0 = WPS enabled and configured (default) + * 1 = WPS disabled + */ + int wps_disabled; }; #endif /* CONFIG_SSID_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface.c b/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface.c index d540fc8c..9699c784 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface.c +++ b/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface.c @@ -17,6 +17,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/uuid.h" +#include "utils/module_tests.h" #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -57,6 +58,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len); static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val); @@ -312,6 +314,33 @@ static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) } +static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *lci; + + if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) { + wpabuf_free(wpa_s->lci); + wpa_s->lci = NULL; + return 0; + } + + lci = wpabuf_parse_bin(cmd); + if (!lci) + return -1; + + if (os_get_reltime(&wpa_s->lci_time)) { + wpabuf_free(lci); + return -1; + } + + wpabuf_free(wpa_s->lci); + wpa_s->lci = lci; + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -373,6 +402,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wps_corrupt_pkhash = atoi(value); wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", wps_corrupt_pkhash); + } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) { + if (value[0] == '\0') { + wps_force_auth_types_in_use = 0; + } else { + wps_force_auth_types = strtol(value, NULL, 0); + wps_force_auth_types_in_use = 1; + } + } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) { + if (value[0] == '\0') { + wps_force_encr_types_in_use = 0; + } else { + wps_force_encr_types = strtol(value, NULL, 0); + wps_force_encr_types_in_use = 1; + } #endif /* CONFIG_WPS_TESTING */ } else if (os_strcasecmp(cmd, "ampdu") == 0) { if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) @@ -380,7 +423,6 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING } else if (os_strcasecmp(cmd, "tdls_testing") == 0) { - extern unsigned int tdls_testing; tdls_testing = strtol(value, NULL, 0); wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing); #endif /* CONFIG_TDLS_TESTING */ @@ -469,6 +511,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->extra_roc_dur = atoi(value); } else if (os_strcasecmp(cmd, "test_failure") == 0) { wpa_s->test_failure = atoi(value); + } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) { + wpa_s->p2p_go_csa_on_inv = !!atoi(value); + } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) { + wpa_s->ignore_auth_resp = !!atoi(value); + } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) { + wpa_s->ignore_assoc_disallow = !!atoi(value); + } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) { + wpa_s->reject_btm_req_reason = atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { @@ -476,6 +526,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_CONFIG_BLOBS */ } else if (os_strcasecmp(cmd, "setband") == 0) { ret = wpas_ctrl_set_band(wpa_s, value); +#ifdef CONFIG_MBO + } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) { + ret = wpas_mbo_update_non_pref_chan(wpa_s, value); + } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { + wpas_mbo_update_cell_capa(wpa_s, atoi(value)); +#endif /* CONFIG_MBO */ + } else if (os_strcasecmp(cmd, "lci") == 0) { + ret = wpas_ctrl_iface_set_lci(wpa_s, value); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -942,7 +1000,8 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, if (os_strcmp(cmd, "any") == 0) _bssid = NULL; else if (os_strcmp(cmd, "get") == 0) { - ret = wps_generate_pin(); + if (wps_generate_pin((unsigned int *) &ret) < 0) + return -1; goto done; } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", @@ -1835,6 +1894,10 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, "mode=P2P GO - group " "formation\n"); break; + case WPAS_MODE_MESH: + ret = os_snprintf(pos, end - pos, + "mode=mesh\n"); + break; default: ret = 0; break; @@ -2705,6 +2768,40 @@ static int wpa_supplicant_ctrl_iface_mesh_group_remove( return 0; } + +static int wpa_supplicant_ctrl_iface_mesh_peer_remove( + struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + + if (hwaddr_aton(cmd, addr) < 0) + return -1; + + return wpas_mesh_peer_remove(wpa_s, addr); +} + + +static int wpa_supplicant_ctrl_iface_mesh_peer_add( + struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + int duration; + char *pos; + + pos = os_strstr(cmd, " duration="); + if (pos) { + *pos = '\0'; + duration = atoi(pos + 10); + } else { + duration = -1; + } + + if (hwaddr_aton(cmd, addr)) + return -1; + + return wpas_mesh_peer_add(wpa_s, addr, duration); +} + #endif /* CONFIG_MESH */ @@ -2834,15 +2931,10 @@ static int wpa_supplicant_ctrl_iface_add_network( wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK"); - ssid = wpa_config_add_network(wpa_s->conf); + ssid = wpa_supplicant_add_network(wpa_s); if (ssid == NULL) return -1; - wpas_notify_network_added(wpa_s, ssid); - - ssid->disabled = 1; - wpa_config_set_network_defaults(ssid); - ret = os_snprintf(buf, buflen, "%d\n", ssid->id); if (os_snprintf_error(buflen, ret)) return -1; @@ -2855,7 +2947,7 @@ static int wpa_supplicant_ctrl_iface_remove_network( { int id; struct wpa_ssid *ssid; - int was_disabled; + int result; /* cmd: "<network id>" or "all" */ if (os_strcmp(cmd, "all") == 0) { @@ -2891,54 +2983,17 @@ static int wpa_supplicant_ctrl_iface_remove_network( id = atoi(cmd); wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id); - ssid = wpa_config_get_network(wpa_s->conf, id); - if (ssid) - wpas_notify_network_removed(wpa_s, ssid); - if (ssid == NULL) { + result = wpa_supplicant_remove_network(wpa_s, id); + if (result == -1) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " "id=%d", id); return -1; } - - if (wpa_s->last_ssid == ssid) - wpa_s->last_ssid = NULL; - - if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - /* - * Invalidate the EAP session cache if the current or - * previously used network is removed. - */ - eapol_sm_invalidate_cached_session(wpa_s->eapol); - } - - if (ssid == wpa_s->current_ssid) { - wpa_sm_set_config(wpa_s->wpa, NULL); - eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); - - if (wpa_s->wpa_state >= WPA_AUTHENTICATING) - wpa_s->own_disconnect_req = 1; - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - } - - was_disabled = ssid->disabled; - - if (wpa_config_remove_network(wpa_s->conf, id) < 0) { + if (result == -2) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the " "network id=%d", id); return -1; } - - if (!was_disabled && wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove " - "network from filters"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); - } - return 0; } @@ -2947,22 +3002,29 @@ static int wpa_supplicant_ctrl_iface_update_network( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, char *name, char *value) { - if (wpa_config_set(ssid, name, value, 0) < 0) { + int ret; + + ret = wpa_config_set(ssid, name, value, 0); + if (ret < 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network " "variable '%s'", name); return -1; } + if (ret == 1) + return 0; /* No change to the previously configured value */ if (os_strcmp(name, "bssid") != 0 && - os_strcmp(name, "priority") != 0) + os_strcmp(name, "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 (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(name, "psk") == 0 && @@ -3937,6 +3999,15 @@ static int wpa_supplicant_ctrl_iface_get_capability( } #endif /* CONFIG_FIPS */ +#ifdef CONFIG_ACS + if (os_strcmp(field, "acs") == 0) { + res = os_snprintf(buf, buflen, "ACS"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } +#endif /* CONFIG_ACS */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'", field); @@ -4197,9 +4268,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (mask & WPA_BSS_MASK_P2P_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); - if (ret < 0 || ret >= end - pos) + if (ret >= end - pos) return 0; - pos += ret; + if (ret > 0) + pos += ret; } #endif /* CONFIG_P2P */ @@ -4233,6 +4305,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_INTERWORKING if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { struct wpa_bss_anqp *anqp = bss->anqp; + struct wpa_bss_anqp_elem *elem; + pos = anqp_add_hex(pos, end, "anqp_capability_list", anqp->capability_list); pos = anqp_add_hex(pos, end, "anqp_venue_name", @@ -4262,6 +4336,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos = anqp_add_hex(pos, end, "hs20_osu_providers_list", anqp->hs20_osu_providers_list); #endif /* CONFIG_HS20 */ + + dl_list_for_each(elem, &anqp->anqp_elems, + struct wpa_bss_anqp_elem, list) { + char title[20]; + + os_snprintf(title, sizeof(title), "anqp[%u]", + elem->infoid); + pos = anqp_add_hex(pos, end, title, elem->payload); + } } #endif /* CONFIG_INTERWORKING */ @@ -4269,9 +4352,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (mask & WPA_BSS_MASK_MESH_SCAN) { ie = (const u8 *) (bss + 1); ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end); - if (ret < 0 || ret >= end - pos) + if (ret >= end - pos) return 0; - pos += ret; + if (ret > 0) + pos += ret; } #endif /* CONFIG_MESH */ @@ -4678,7 +4762,7 @@ static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt) return -1; } - if (isblank(*last)) { + if (isblank((unsigned char) *last)) { i++; break; } @@ -4850,6 +4934,30 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd) } +static int parse_freq(int chwidth, int freq2) +{ + if (freq2 < 0) + return -1; + if (freq2) + return VHT_CHANWIDTH_80P80MHZ; + + switch (chwidth) { + case 0: + case 20: + case 40: + return VHT_CHANWIDTH_USE_HT; + case 80: + return VHT_CHANWIDTH_80MHZ; + case 160: + return VHT_CHANWIDTH_160MHZ; + default: + wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", + chwidth); + return -1; + } +} + + static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -4866,7 +4974,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, int go_intent = -1; int freq = 0; int pd; - int ht40, vht; + int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; + u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL; + size_t group_ssid_len = 0; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -4879,7 +4989,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] * [persistent|persistent=<network id>] * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] - * [ht40] [vht] [auto] */ + * [ht40] [vht] [auto] [ssid=<hexdump>] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -4927,11 +5037,41 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, return -1; } + pos2 = os_strstr(pos, " freq2="); + if (pos2) + freq2 = atoi(pos2 + 7); + + pos2 = os_strstr(pos, " max_oper_chwidth="); + if (pos2) + chwidth = atoi(pos2 + 18); + + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + + pos2 = os_strstr(pos, " ssid="); + if (pos2) { + char *end; + + pos2 += 6; + end = os_strchr(pos2, ' '); + if (!end) + group_ssid_len = os_strlen(pos2) / 2; + else + group_ssid_len = (end - pos2) / 2; + if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN || + hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0) + return -1; + group_ssid = _group_ssid; + } + if (os_strncmp(pos, "pin", 3) == 0) { /* Request random PIN (to be displayed) and enable the PIN */ wps_method = WPS_PIN_DISPLAY; } else if (os_strncmp(pos, "pbc", 3) == 0) { wps_method = WPS_PBC; + } else if (os_strstr(pos, "p2ps") != NULL) { + wps_method = WPS_P2PS; } else { pin = pos; pos = os_strchr(pin, ' '); @@ -4940,8 +5080,6 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, *pos++ = '\0'; if (os_strncmp(pos, "display", 7) == 0) wps_method = WPS_PIN_DISPLAY; - else if (os_strncmp(pos, "p2ps", 4) == 0) - wps_method = WPS_P2PS; } if (!wps_pin_str_valid(pin)) { os_memcpy(buf, "FAIL-INVALID-PIN\n", 17); @@ -4951,8 +5089,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, - auth, go_intent, freq, persistent_id, pd, - ht40, vht); + auth, go_intent, freq, freq2, persistent_id, + pd, ht40, vht, max_oper_chwidth, + group_ssid, group_ssid_len); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; @@ -5507,7 +5646,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) struct wpa_ssid *ssid; u8 *_peer = NULL, peer[ETH_ALEN]; int freq = 0, pref_freq = 0; - int ht40, vht; + int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0; id = atoi(cmd); pos = os_strstr(cmd, " peer="); @@ -5545,8 +5684,20 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || vht; - return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht, - pref_freq); + pos = os_strstr(cmd, "freq2="); + if (pos) + freq2 = atoi(pos + 6); + + pos = os_strstr(cmd, " max_oper_chwidth="); + if (pos) + chwidth = atoi(pos + 18); + + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, + max_oper_chwidth, pref_freq); } @@ -5593,7 +5744,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, - int id, int freq, int ht40, int vht) + int id, int freq, int vht_center_freq2, + int ht40, int vht, int vht_chwidth) { struct wpa_ssid *ssid; @@ -5605,8 +5757,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return -1; } - return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht, - NULL, 0, 0); + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, + vht_center_freq2, 0, ht40, vht, + vht_chwidth, NULL, 0, 0); } @@ -5615,11 +5768,14 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) int freq = 0, persistent = 0, group_id = -1; int vht = wpa_s->conf->p2p_go_vht; int ht40 = wpa_s->conf->p2p_go_ht40 || vht; + int max_oper_chwidth, chwidth = 0, freq2 = 0; char *token, *context = NULL; while ((token = str_token(cmd, " ", &context))) { if (sscanf(token, "freq=%d", &freq) == 1 || - sscanf(token, "persistent=%d", &group_id) == 1) { + sscanf(token, "freq2=%d", &freq2) == 1 || + sscanf(token, "persistent=%d", &group_id) == 1 || + sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) { continue; } else if (os_strcmp(token, "ht40") == 0) { ht40 = 1; @@ -5636,11 +5792,40 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) } } + max_oper_chwidth = parse_freq(chwidth, freq2); + if (max_oper_chwidth < 0) + return -1; + if (group_id >= 0) return p2p_ctrl_group_add_persistent(wpa_s, group_id, - freq, ht40, vht); + freq, freq2, ht40, vht, + max_oper_chwidth); + + return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, + max_oper_chwidth); +} + + +static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd, + char *buf, size_t buflen) +{ + u8 dev_addr[ETH_ALEN]; + struct wpa_ssid *ssid; + int res; + const u8 *iaddr; + + ssid = wpa_s->current_ssid; + if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO || + hwaddr_aton(cmd, dev_addr)) + return -1; - return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht); + iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr); + if (!iaddr) + return -1; + res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr)); + if (os_snprintf_error(buflen, res)) + return -1; + return res; } @@ -5799,8 +5984,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) } if (os_strcmp(cmd, "listen_channel") == 0) { - return p2p_set_listen_channel(wpa_s->global->p2p, 81, - atoi(param), 1); + char *pos; + u8 channel, op_class; + + channel = atoi(param); + pos = os_strchr(param, ' '); + op_class = pos ? atoi(pos) : 81; + + return p2p_set_listen_channel(wpa_s->global->p2p, op_class, + channel, 1); } if (os_strcmp(cmd, "ssid_postfix") == 0) { @@ -6061,6 +6253,21 @@ static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd) return 0; } + +static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq = 0, period = 0, interval = 0, count = 0; + + if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4) + { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid P2P LO Start parameter: '%s'", cmd); + return -1; + } + + return wpas_p2p_lo_start(wpa_s, freq, period, interval, count); +} + #endif /* CONFIG_P2P */ @@ -6178,6 +6385,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) u16 id[MAX_ANQP_INFO_ID]; size_t num_id = 0; u32 subtypes = 0; + int get_cell_pref = 0; used = hwaddr_aton2(dst, dst_addr); if (used < 0) @@ -6195,6 +6403,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) #else /* CONFIG_HS20 */ return -1; #endif /* CONFIG_HS20 */ + } else if (os_strncmp(pos, "mbo:", 4) == 0) { +#ifdef CONFIG_MBO + int num = atoi(pos + 4); + if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF) + return -1; + get_cell_pref = 1; +#else /* CONFIG_MBO */ + return -1; +#endif /* CONFIG_MBO */ } else { id[num_id] = atoi(pos); if (id[num_id]) @@ -6209,7 +6426,8 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst) if (num_id == 0) return -1; - return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes); + return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes, + get_cell_pref); } @@ -6380,7 +6598,7 @@ static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst) if (subtypes == 0) return -1; - return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0); + return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0); } @@ -6403,7 +6621,7 @@ static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); @@ -6449,14 +6667,59 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s, ret = hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_NAI_HOME_REALM_QUERY), - buf, len); + buf, len, 0); os_free(buf); return ret; } -static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) +static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply, + int buflen) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *ctx = NULL, *icon, *poffset, *psize; + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + cmd += used; + + icon = str_token(cmd, " ", &ctx); + poffset = str_token(cmd, " ", &ctx); + psize = str_token(cmd, " ", &ctx); + if (!icon || !poffset || !psize) + return -1; + + wpa_s->fetch_osu_icon_in_progress = 0; + return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize), + reply, buflen); +} + + +static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 dst_addr[ETH_ALEN]; + int used; + char *icon; + + if (!cmd[0]) + return hs20_del_icon(wpa_s, NULL, NULL); + + used = hwaddr_aton2(cmd, dst_addr); + if (used < 0) + return -1; + + while (cmd[used] == ' ') + used++; + icon = cmd[used] ? &cmd[used] : NULL; + + return hs20_del_icon(wpa_s, dst_addr, icon); +} + + +static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem) { u8 dst_addr[ETH_ALEN]; int used; @@ -6472,7 +6735,7 @@ static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd) wpa_s->fetch_osu_icon_in_progress = 0; return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST), - (u8 *) icon, os_strlen(icon)); + (u8 *) icon, os_strlen(icon), inmem); } #endif /* CONFIG_HS20 */ @@ -6562,14 +6825,27 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd) static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd) { - int query_reason; + int query_reason, list = 0; query_reason = atoi(cmd); - wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d", - query_reason); + cmd = os_strchr(cmd, ' '); + if (cmd) { + cmd++; + if (os_strncmp(cmd, "list", 4) == 0) { + list = 1; + } else { + wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s", + cmd); + return -1; + } + } - return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason); + wpa_printf(MSG_DEBUG, + "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s", + query_reason, list ? " candidate list" : ""); + + return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list); } #endif /* CONFIG_WNM */ @@ -6634,6 +6910,28 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, } +static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + const char *pos; + int threshold = 0; + int hysteresis = 0; + + if (wpa_s->bgscan && wpa_s->bgscan_priv) { + wpa_printf(MSG_DEBUG, + "Reject SIGNAL_MONITOR command - bgscan is active"); + return -1; + } + pos = os_strstr(cmd, "THRESHOLD="); + if (pos) + threshold = atoi(pos + 10); + pos = os_strstr(cmd, "HYSTERESIS="); + if (pos) + hysteresis = atoi(pos + 11); + return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis); +} + + static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -6681,6 +6979,34 @@ static int wpas_ctrl_iface_get_pref_freq_list( } +static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + int ret, i; + char *pos, *end; + + ret = os_snprintf(buf, buflen, "%016llX:\n", + (long long unsigned) wpa_s->drv_flags); + if (os_snprintf_error(buflen, ret)) + return -1; + + pos = buf + ret; + end = buf + buflen; + + for (i = 0; i < 64; i++) { + if (wpa_s->drv_flags & (1LLU << i)) { + ret = os_snprintf(pos, end - pos, "%s\n", + driver_flag_to_string(1LLU << i)); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + } + + return pos - buf; +} + + static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { @@ -6738,13 +7064,13 @@ static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ vendor_id = strtoul(cmd, &pos, 16); - if (!isblank(*pos)) + if (!isblank((unsigned char) *pos)) return -EINVAL; subcmd = strtoul(pos, &pos, 10); if (*pos != '\0') { - if (!isblank(*pos++)) + if (!isblank((unsigned char) *pos++)) return -EINVAL; data_len = os_strlen(pos); } @@ -6792,10 +7118,20 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); + wpas_abort_ongoing_scan(wpa_s); + + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) { + /* + * Avoid possible auto connect re-connection on getting + * disconnected due to state flush. + */ + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + } + #ifdef CONFIG_P2P + wpas_p2p_group_remove(p2p_wpa_s, "*"); 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; @@ -6805,12 +7141,15 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL; p2p_wpa_s->global->p2p_go_avoid_freq.num = 0; p2p_wpa_s->global->pending_p2ps_group = 0; + p2p_wpa_s->global->pending_p2ps_group_freq = 0; #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS_TESTING wps_version_number = 0x20; wps_testing_dummy_cred = 0; wps_corrupt_pkhash = 0; + wps_force_auth_types_in_use = 0; + wps_force_encr_types_in_use = 0; #endif /* CONFIG_WPS_TESTING */ #ifdef CONFIG_WPS wpa_s->wps_fragment_size = 0; @@ -6822,7 +7161,6 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TDLS #ifdef CONFIG_TDLS_TESTING - extern unsigned int tdls_testing; tdls_testing = 0; #endif /* CONFIG_TDLS_TESTING */ wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL); @@ -6868,7 +7206,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->next_ssid = NULL; #ifdef CONFIG_INTERWORKING +#ifdef CONFIG_HS20 hs20_cancel_fetch_osu(wpa_s); + hs20_del_icon(wpa_s, NULL, NULL); +#endif /* CONFIG_HS20 */ #endif /* CONFIG_INTERWORKING */ wpa_s->ext_mgmt_frame_handling = 0; @@ -6876,6 +7217,11 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TESTING_OPTIONS wpa_s->extra_roc_dur = 0; wpa_s->test_failure = WPAS_TEST_FAILURE_NONE; + wpa_s->p2p_go_csa_on_inv = 0; + wpa_s->ignore_auth_resp = 0; + wpa_s->ignore_assoc_disallow = 0; + wpa_s->reject_btm_req_reason = 0; + wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); #endif /* CONFIG_TESTING_OPTIONS */ wpa_s->disconnected = 0; @@ -6894,6 +7240,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); wpa_s->wnmsleep_used = 0; + +#ifdef CONFIG_SME + wpa_s->sme.last_unprot_disconnect.sec = 0; +#endif /* CONFIG_SME */ } @@ -6950,6 +7300,13 @@ static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit) eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL); + /* + * work->type points to a buffer in ework, so need to replace + * that here with a fixed string to avoid use of freed memory + * in debug prints. + */ + work->type = "freed-ext-work"; + work->ctx = NULL; os_free(ework); return; } @@ -7399,6 +7756,76 @@ static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) } +static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *pos, *param; + size_t len; + u8 *buf; + int freq = 0, datarate = 0, ssi_signal = 0; + union wpa_event_data event; + + if (!wpa_s->ext_mgmt_frame_handling) + return -1; + + /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */ + + wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd); + + pos = cmd; + param = os_strstr(pos, "freq="); + if (param) { + param += 5; + freq = atoi(param); + } + + param = os_strstr(pos, " datarate="); + if (param) { + param += 10; + datarate = atoi(param); + } + + param = os_strstr(pos, " ssi_signal="); + if (param) { + param += 12; + ssi_signal = atoi(param); + } + + param = os_strstr(pos, " frame="); + if (param == NULL) + return -1; + param += 7; + + len = os_strlen(param); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(param, buf, len) < 0) { + os_free(buf); + return -1; + } + + os_memset(&event, 0, sizeof(event)); + event.rx_mgmt.freq = freq; + event.rx_mgmt.frame = buf; + event.rx_mgmt.frame_len = len; + event.rx_mgmt.ssi_signal = ssi_signal; + event.rx_mgmt.datarate = datarate; + wpa_s->ext_mgmt_frame_handling = 0; + wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event); + wpa_s->ext_mgmt_frame_handling = 1; + + os_free(buf); + + return 0; +} + + static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) { char *pos, *param; @@ -7498,7 +7925,8 @@ static u16 ipv4_hdr_checksum(const void *buf, size_t len) #define HWSIM_PACKETLEN 1500 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) -void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) +static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, + size_t len) { struct wpa_supplicant *wpa_s = ctx; const struct ether_header *eth; @@ -7532,6 +7960,8 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, char *cmd) { int enabled = atoi(cmd); + char *pos; + const char *ifname; if (!enabled) { if (wpa_s->l2_test) { @@ -7545,7 +7975,13 @@ static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s, if (wpa_s->l2_test) return 0; - wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, + pos = os_strstr(cmd, " ifname="); + if (pos) + ifname = pos + 8; + else + ifname = wpa_s->ifname; + + wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr, ETHERTYPE_IP, wpas_data_test_rx, wpa_s, 1); if (wpa_s->l2_test == NULL) @@ -7666,8 +8102,6 @@ done: static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_fail_func[256]; - extern unsigned int wpa_trace_fail_after; char *pos; wpa_trace_fail_after = atoi(cmd); @@ -7690,9 +8124,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_fail_func[256]; - extern unsigned int wpa_trace_fail_after; - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, wpa_trace_fail_func); #else /* WPA_TRACE_BFD */ @@ -7704,8 +8135,6 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; char *pos; wpa_trace_test_fail_after = atoi(cmd); @@ -7728,9 +8157,6 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { #ifdef WPA_TRACE_BFD - extern char wpa_trace_test_fail_func[256]; - extern unsigned int wpa_trace_test_fail_after; - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, wpa_trace_test_fail_func); #else /* WPA_TRACE_BFD */ @@ -7738,62 +8164,64 @@ static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, #endif /* WPA_TRACE_BFD */ } -#endif /* CONFIG_TESTING_OPTIONS */ - -static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s) +static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx) { - unsigned int i; - char buf[30]; + struct wpa_supplicant *wpa_s = eloop_ctx; + int i, count = (intptr_t) timeout_ctx; - wpa_printf(MSG_DEBUG, "Update vendor elements"); + wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages", + count); + for (i = 0; i < count; i++) { + wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d", + i + 1, count); + } +} - for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { - if (wpa_s->vendor_elem[i]) { - int res; - res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); - if (!os_snprintf_error(sizeof(buf), res)) { - wpa_hexdump_buf(MSG_DEBUG, buf, - wpa_s->vendor_elem[i]); - } - } - } +static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int count; -#ifdef CONFIG_P2P - if (wpa_s->parent == wpa_s && - wpa_s->global->p2p && - !wpa_s->global->p2p_disabled) - p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); -#endif /* CONFIG_P2P */ + count = atoi(cmd); + if (count <= 0) + return -1; + + return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s, + (void *) (intptr_t) count); } -static struct wpa_supplicant * -wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s, - enum wpa_vendor_elem_frame frame) +static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, + const char *cmd) { - switch (frame) { -#ifdef CONFIG_P2P - case VENDOR_ELEM_PROBE_REQ_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P: - case VENDOR_ELEM_PROBE_RESP_P2P_GO: - case VENDOR_ELEM_BEACON_P2P_GO: - case VENDOR_ELEM_P2P_PD_REQ: - case VENDOR_ELEM_P2P_PD_RESP: - case VENDOR_ELEM_P2P_GO_NEG_REQ: - case VENDOR_ELEM_P2P_GO_NEG_RESP: - case VENDOR_ELEM_P2P_GO_NEG_CONF: - case VENDOR_ELEM_P2P_INV_REQ: - case VENDOR_ELEM_P2P_INV_RESP: - case VENDOR_ELEM_P2P_ASSOC_REQ: - return wpa_s->parent; -#endif /* CONFIG_P2P */ - default: - return wpa_s; + struct wpabuf *buf; + size_t len; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + + if (len == 0) { + buf = NULL; + } else { + buf = wpabuf_alloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { + wpabuf_free(buf); + return -1; + } } + + wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); + return 0; } +#endif /* CONFIG_TESTING_OPTIONS */ + static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) { @@ -7806,7 +8234,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7837,7 +8265,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) if (wpa_s->vendor_elem[frame] == NULL) { wpa_s->vendor_elem[frame] = buf; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7848,7 +8276,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); wpabuf_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7861,7 +8289,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); if (wpa_s->vendor_elem[frame] == NULL) return 0; @@ -7879,12 +8307,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) size_t len; u8 *buf; struct ieee802_11_elems elems; - u8 *ie, *end; + int res; frame = atoi(pos); if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) return -1; - wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + wpa_s = wpas_vendor_elem(wpa_s, frame); pos = os_strchr(pos, ' '); if (pos == NULL) @@ -7894,7 +8322,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) if (*pos == '*') { wpabuf_free(wpa_s->vendor_elem[frame]); wpa_s->vendor_elem[frame] = NULL; - wpas_ctrl_vendor_elem_update(wpa_s); + wpas_vendor_elem_update(wpa_s); return 0; } @@ -7922,65 +8350,149 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) return -1; } - ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); - end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); - - for (; ie + 1 < end; ie += 2 + ie[1]) { - if (ie + len > end) - break; - if (os_memcmp(ie, buf, len) != 0) - continue; - - if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { - wpabuf_free(wpa_s->vendor_elem[frame]); - wpa_s->vendor_elem[frame] = NULL; - } else { - os_memmove(ie, ie + len, - end - (ie + len)); - wpa_s->vendor_elem[frame]->used -= len; - } - os_free(buf); - wpas_ctrl_vendor_elem_update(wpa_s); - return 0; - } - + res = wpas_vendor_elem_remove(wpa_s, frame, buf, len); os_free(buf); - - return -1; + return res; } static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) { struct wpa_supplicant *wpa_s = ctx; + size_t len; + const u8 *data; - if (neighbor_rep) { - wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED - "length=%u", - (unsigned int) wpabuf_len(neighbor_rep)); - wpabuf_free(neighbor_rep); - } else { + /* + * Neighbor Report element (IEEE P802.11-REVmc/D5.0) + * BSSID[6] + * BSSID Information[4] + * Operating Class[1] + * Channel Number[1] + * PHY Type[1] + * Optional Subelements[variable] + */ +#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1) + + if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) { wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED); + goto out; + } + + data = wpabuf_head_u8(neighbor_rep); + len = wpabuf_len(neighbor_rep); + + while (len >= 2 + NR_IE_MIN_LEN) { + const u8 *nr; + char lci[256 * 2 + 1]; + char civic[256 * 2 + 1]; + u8 nr_len = data[1]; + const u8 *pos = data, *end; + + if (pos[0] != WLAN_EID_NEIGHBOR_REPORT || + nr_len < NR_IE_MIN_LEN) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid Neighbor Report element: id=%u len=%u", + data[0], nr_len); + goto out; + } + + if (2U + nr_len > len) { + wpa_printf(MSG_DEBUG, + "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u", + data[0], len, nr_len); + goto out; + } + pos += 2; + end = pos + nr_len; + + nr = pos; + pos += NR_IE_MIN_LEN; + + lci[0] = '\0'; + civic[0] = '\0'; + while (end - pos > 2) { + u8 s_id, s_len; + + s_id = *pos++; + s_len = *pos++; + if (s_len > end - pos) + goto out; + if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) { + /* Measurement Token[1] */ + /* Measurement Report Mode[1] */ + /* Measurement Type[1] */ + /* Measurement Report[variable] */ + switch (pos[2]) { + case MEASURE_TYPE_LCI: + if (lci[0]) + break; + wpa_snprintf_hex(lci, sizeof(lci), + pos, s_len); + break; + case MEASURE_TYPE_LOCATION_CIVIC: + if (civic[0]) + break; + wpa_snprintf_hex(civic, sizeof(civic), + pos, s_len); + break; + } + } + + pos += s_len; + } + + wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED + "bssid=" MACSTR + " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s", + MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN), + nr[ETH_ALEN + 4], nr[ETH_ALEN + 5], + nr[ETH_ALEN + 6], + lci[0] ? " lci=" : "", lci, + civic[0] ? " civic=" : "", civic); + + data = end; + len -= 2 + nr_len; } + +out: + wpabuf_free(neighbor_rep); } -static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s, - char *cmd) +static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s, + char *cmd) { - struct wpa_ssid ssid; - struct wpa_ssid *ssid_p = NULL; - int ret = 0; + struct wpa_ssid_value ssid, *ssid_p = NULL; + int ret, lci = 0, civic = 0; + char *ssid_s; - if (os_strncmp(cmd, " ssid=", 6) == 0) { - ssid.ssid_len = os_strlen(cmd + 6); - if (ssid.ssid_len > SSID_MAX_LEN) + ssid_s = os_strstr(cmd, "ssid="); + if (ssid_s) { + if (ssid_parse(ssid_s + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: Send Neighbor Report: bad SSID"); return -1; - ssid.ssid = (u8 *) (cmd + 6); + } + ssid_p = &ssid; + + /* + * Move cmd after the SSID text that may include "lci" or + * "civic". + */ + cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' '); + if (cmd) + cmd++; + } - ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, + if (cmd && os_strstr(cmd, "lci")) + lci = 1; + + if (cmd && os_strstr(cmd, "civic")) + civic = 1; + + ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic, wpas_ctrl_neighbor_rep_cb, wpa_s); @@ -8065,10 +8577,7 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); + wpas_scan_restart_sched_scan(wpa_s); } return 0; } @@ -8094,12 +8603,8 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN, addr, mask); - if (wpa_s->sched_scanning && !wpa_s->pno) { - /* simulate timeout to restart the sched scan */ - wpa_s->sched_scan_timed_out = 1; - wpa_s->prev_sched_ssid = NULL; - wpa_supplicant_cancel_sched_scan(wpa_s); - } + if (wpa_s->sched_scanning && !wpa_s->pno) + wpas_scan_restart_sched_scan(wpa_s); } if (type & MAC_ADDR_RAND_PNO) { @@ -8115,6 +8620,29 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + size_t reply_len; + + reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen); +#ifdef CONFIG_AP + reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len], + buflen - reply_len); +#endif /* CONFIG_AP */ + return reply_len; +} + + +static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) +{ + wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); +#ifdef CONFIG_AP + wpas_ap_pmksa_cache_flush(wpa_s); +#endif /* CONFIG_AP */ +} + + static int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || @@ -8186,10 +8714,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); } else if (os_strcmp(buf, "PMKSA") == 0) { - reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply, - reply_size); + reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size); } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) { - wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); + wpas_ctrl_iface_pmksa_flush(wpa_s); } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; @@ -8357,6 +8884,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s, buf + 18)) reply_len = -1; + } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) { + if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14)) + reply_len = -1; #endif /* CONFIG_MESH */ #ifdef CONFIG_P2P } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { @@ -8391,6 +8924,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { if (p2p_ctrl_group_add(wpa_s, buf + 14)) reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) { + reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply, + reply_size); } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) reply_len = -1; @@ -8456,6 +8992,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) { if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0) reply_len = -1; + } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) { + if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) { + if (wpas_p2p_lo_stop(wpa_s)) + reply_len = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { @@ -8509,10 +9051,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0) reply_len = -1; } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) { - if (hs20_icon_request(wpa_s, buf + 18) < 0) + if (hs20_icon_request(wpa_s, buf + 18, 0) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) { + if (hs20_icon_request(wpa_s, buf + 14, 1) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) { + reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size); + } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) { + if (del_hs20_icon(wpa_s, buf + 14) < 0) reply_len = -1; } else if (os_strcmp(buf, "FETCH_OSU") == 0) { - if (hs20_fetch_osu(wpa_s) < 0) + if (hs20_fetch_osu(wpa_s, 0) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) { + if (hs20_fetch_osu(wpa_s, 1) < 0) reply_len = -1; } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) { hs20_cancel_fetch_osu(wpa_s); @@ -8551,16 +9104,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_list_networks( wpa_s, NULL, reply, reply_size); } else if (os_strcmp(buf, "DISCONNECT") == 0) { -#ifdef CONFIG_SME - wpa_s->sme.prev_bssid_set = 0; -#endif /* CONFIG_SME */ - wpa_s->reassociate = 0; - wpa_s->disconnected = 1; - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_cancel_scan(wpa_s); - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); + wpas_request_disconnection(wpa_s); } else if (os_strcmp(buf, "SCAN") == 0) { wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); } else if (os_strncmp(buf, "SCAN ", 5) == 0) { @@ -8568,6 +9112,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "ABORT_SCAN") == 0) { + if (wpas_abort_ongoing_scan(wpa_s) < 0) + reply_len = -1; } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) reply_len = -1; @@ -8626,9 +9173,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( wpa_s->global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - wpa_s->global, reply, reply_size); + wpa_s->global, buf + 10, reply, reply_size); } else if (os_strncmp(buf, "BSS ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); @@ -8709,6 +9256,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { reply_len = wpa_supplicant_signal_poll(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) { + if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14)) + reply_len = -1; } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) { reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply, reply_size); @@ -8717,6 +9267,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9)) reply_len = -1; #endif /* CONFIG_AUTOSCAN */ + } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { + reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply, + reply_size); #ifdef ANDROID } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, @@ -8747,6 +9300,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { wpas_ctrl_iface_mgmt_tx_done(wpa_s); + } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) { + if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) reply_len = -1; @@ -8772,6 +9328,12 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "GET_FAIL") == 0) { reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) { + if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { + if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) @@ -8783,7 +9345,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) reply_len = -1; } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) { - if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20)) + if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20)) reply_len = -1; } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { wpas_ctrl_iface_erp_flush(wpa_s); @@ -8816,10 +9378,11 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, struct wpa_supplicant *wpa_s; unsigned int create_iface = 0; u8 mac_addr[ETH_ALEN]; + enum wpa_driver_if_type type = WPA_IF_STATION; /* * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> - * TAB<bridge_ifname>[TAB<create>] + * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]] */ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); @@ -8887,9 +9450,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, if (!extra[0]) break; - if (os_strcmp(extra, "create") == 0) + if (os_strcmp(extra, "create") == 0) { create_iface = 1; - else { + if (!pos) + break; + + if (os_strcmp(pos, "sta") == 0) { + type = WPA_IF_STATION; + } else if (os_strcmp(pos, "ap") == 0) { + type = WPA_IF_AP_BSS; + } else { + wpa_printf(MSG_DEBUG, + "INTERFACE_ADD unsupported interface type: '%s'", + pos); + return -1; + } + } else { wpa_printf(MSG_DEBUG, "INTERFACE_ADD unsupported extra parameter: '%s'", extra); @@ -8902,7 +9478,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, iface.ifname); if (!global->ifaces) return -1; - if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname, + if (wpa_drv_if_add(global->ifaces, type, iface.ifname, NULL, NULL, NULL, mac_addr, NULL) < 0) { wpa_printf(MSG_ERROR, "CTRL_IFACE interface creation failed"); @@ -9011,18 +9587,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len) { int res; char *pos, *end; struct wpa_supplicant *wpa_s; + int show_ctrl = 0; + + if (input) + show_ctrl = !!os_strstr(input, "ctrl"); wpa_s = global->ifaces; pos = buf; end = buf + len; while (wpa_s) { - res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); + if (show_ctrl) + res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n", + wpa_s->ifname, + wpa_s->conf->ctrl_interface ? + wpa_s->conf->ctrl_interface : "N/A"); + else + res = os_snprintf(pos, end - pos, "%s\n", + wpa_s->ifname); + if (os_snprintf_error(end - pos, res)) { *pos = '\0'; break; @@ -9088,6 +9677,7 @@ static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global, "P2P_LISTEN ", "P2P_GROUP_REMOVE ", "P2P_GROUP_ADD ", + "P2P_GROUP_MEMBER ", "P2P_PROV_DISC ", "P2P_SERV_DISC_REQ ", "P2P_SERV_DISC_CANCEL_REQ ", @@ -9411,9 +10001,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - global, reply, reply_size); + global, buf + 10, reply, reply_size); #ifdef CONFIG_FST } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, @@ -9459,7 +10049,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, reply_size); #ifdef CONFIG_MODULE_TESTS } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { - int wpas_module_tests(void); if (wpas_module_tests() < 0) reply_len = -1; #endif /* CONFIG_MODULE_TESTS */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c b/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c index 259d2937..ff1814c9 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c +++ b/freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_unix.c @@ -17,7 +17,6 @@ #include <fcntl.h> #ifdef __linux__ #include <sys/ioctl.h> -#include <linux/sockios.h> #endif /* __linux__ */ #ifdef ANDROID #include <cutils/sockets.h> @@ -26,6 +25,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/list.h" +#include "common/ctrl_iface_common.h" #include "eapol_supp/eapol_supp_sm.h" #include "config.h" #include "wpa_supplicant_i.h" @@ -33,27 +33,13 @@ /* Per-interface ctrl_iface */ -/** - * struct wpa_ctrl_dst - Internal data structure of control interface monitors - * - * This structure is used to store information about registered control - * interface monitors into struct wpa_supplicant. This data is private to - * ctrl_iface_unix.c and should not be touched directly from other files. - */ -struct wpa_ctrl_dst { - struct dl_list list; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - - struct ctrl_iface_priv { struct wpa_supplicant *wpa_s; int sock; struct dl_list ctrl_dst; int android_control_socket; + struct dl_list msg_queue; + unsigned int throttle_count; }; @@ -62,6 +48,17 @@ struct ctrl_iface_global_priv { int sock; struct dl_list ctrl_dst; int android_control_socket; + struct dl_list msg_queue; + unsigned int throttle_count; +}; + +struct ctrl_iface_msg { + struct dl_list list; + struct wpa_supplicant *wpa_s; + int level; + enum wpa_msg_type type; + const char *txt; + size_t len; }; @@ -94,7 +91,7 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) sndbuf = -1; - if (ioctl(sock, SIOCOUTQ, &outq) < 0) + if (ioctl(sock, TIOCOUTQ, &outq) < 0) outq = -1; wpa_printf(level, @@ -105,81 +102,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, int global) { - struct wpa_ctrl_dst *dst; - char addr_txt[200]; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dl_list_add(ctrl_dst, &dst->list); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s", - global ? "global " : "", addr_txt); - return 0; + return ctrl_iface_attach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - 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 detached %s", - addr_txt); - dl_list_del(&dst->list); - os_free(dst); - return 0; - } - } - return -1; + return ctrl_iface_detach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, char *level) { - struct wpa_ctrl_dst *dst; - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - dst->debug_level = atoi(level); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", - dst->debug_level, addr_txt); - return 0; - } - } - - return -1; + return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level); } @@ -190,7 +135,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len = 0; @@ -336,33 +281,209 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) } +static int wpas_ctrl_iface_throttle(int sock) +{ +#ifdef __linux__ + socklen_t optlen; + int sndbuf, outq; + + optlen = sizeof(sndbuf); + sndbuf = 0; + if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 || + ioctl(sock, TIOCOUTQ, &outq) < 0 || + sndbuf <= 0 || outq < 0) + return 0; + return outq > sndbuf / 2; +#else /* __linux__ */ + return 0; +#endif /* __linux__ */ +} + + +static void wpas_ctrl_msg_send_pending_global(struct wpa_global *global) +{ + struct ctrl_iface_global_priv *gpriv; + struct ctrl_iface_msg *msg; + + gpriv = global->ctrl_iface; + while (gpriv && !dl_list_empty(&gpriv->msg_queue) && + !wpas_ctrl_iface_throttle(gpriv->sock)) { + msg = dl_list_first(&gpriv->msg_queue, struct ctrl_iface_msg, + list); + if (!msg) + break; + dl_list_del(&msg->list); + wpa_supplicant_ctrl_iface_send( + msg->wpa_s, + msg->type != WPA_MSG_PER_INTERFACE ? + NULL : msg->wpa_s->ifname, + gpriv->sock, &gpriv->ctrl_dst, msg->level, + msg->txt, msg->len, NULL, gpriv); + os_free(msg); + } +} + + +static void wpas_ctrl_msg_send_pending_iface(struct wpa_supplicant *wpa_s) +{ + struct ctrl_iface_priv *priv; + struct ctrl_iface_msg *msg; + + priv = wpa_s->ctrl_iface; + while (priv && !dl_list_empty(&priv->msg_queue) && + !wpas_ctrl_iface_throttle(priv->sock)) { + msg = dl_list_first(&priv->msg_queue, struct ctrl_iface_msg, + list); + if (!msg) + break; + dl_list_del(&msg->list); + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, + &priv->ctrl_dst, msg->level, + msg->txt, msg->len, priv, NULL); + os_free(msg); + } +} + + +static void wpas_ctrl_msg_queue_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct ctrl_iface_priv *priv; + struct ctrl_iface_global_priv *gpriv; + int sock = -1, gsock = -1; + + wpas_ctrl_msg_send_pending_global(wpa_s->global); + wpas_ctrl_msg_send_pending_iface(wpa_s); + + priv = wpa_s->ctrl_iface; + if (priv && !dl_list_empty(&priv->msg_queue)) + sock = priv->sock; + + gpriv = wpa_s->global->ctrl_iface; + if (gpriv && !dl_list_empty(&gpriv->msg_queue)) + gsock = gpriv->sock; + + if (sock > -1 || gsock > -1) { + /* Continue pending message transmission from a timeout */ + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle pending event message transmission for (sock %d gsock %d)", + sock, gsock); + eloop_register_timeout(0, 20000, wpas_ctrl_msg_queue_timeout, + wpa_s, NULL); + } +} + + +static void wpas_ctrl_msg_queue(struct dl_list *queue, + struct wpa_supplicant *wpa_s, int level, + enum wpa_msg_type type, + const char *txt, size_t len) +{ + struct ctrl_iface_msg *msg; + + msg = os_zalloc(sizeof(*msg) + len); + if (!msg) + return; + + msg->wpa_s = wpa_s; + msg->level = level; + msg->type = type; + os_memcpy(msg + 1, txt, len); + msg->txt = (const char *) (msg + 1); + msg->len = len; + dl_list_add_tail(queue, &msg->list); + eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL); + eloop_register_timeout(0, 0, wpas_ctrl_msg_queue_timeout, wpa_s, NULL); +} + + +static void wpas_ctrl_msg_queue_limit(unsigned int throttle_count, + struct dl_list *queue) +{ + struct ctrl_iface_msg *msg; + + if (throttle_count < 2000) + return; + + msg = dl_list_first(queue, struct ctrl_iface_msg, list); + if (msg) { + wpa_printf(MSG_DEBUG, "CTRL: Dropped oldest pending message"); + dl_list_del(&msg->list); + os_free(msg); + } +} + + static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, enum wpa_msg_type type, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; + struct ctrl_iface_priv *priv; + struct ctrl_iface_global_priv *gpriv; if (wpa_s == NULL) return; - if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { - struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; - if (!dl_list_empty(&priv->ctrl_dst)) { + gpriv = wpa_s->global->ctrl_iface; + + if (type != WPA_MSG_NO_GLOBAL && gpriv && + !dl_list_empty(&gpriv->ctrl_dst)) { + if (!dl_list_empty(&gpriv->msg_queue) || + wpas_ctrl_iface_throttle(gpriv->sock)) { + if (gpriv->throttle_count == 0) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle global event message for sock %d", + gpriv->sock); + } + gpriv->throttle_count++; + wpas_ctrl_msg_queue_limit(gpriv->throttle_count, + &gpriv->msg_queue); + wpas_ctrl_msg_queue(&gpriv->msg_queue, wpa_s, level, + type, txt, len); + } else { + if (gpriv->throttle_count) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle %u global event message(s) for sock %d", + gpriv->throttle_count, gpriv->sock); + } + gpriv->throttle_count = 0; wpa_supplicant_ctrl_iface_send( wpa_s, type != WPA_MSG_PER_INTERFACE ? NULL : wpa_s->ifname, - priv->sock, &priv->ctrl_dst, level, txt, len, - NULL, priv); + gpriv->sock, &gpriv->ctrl_dst, level, + txt, len, NULL, gpriv); } } - if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL) - return; - wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, - &wpa_s->ctrl_iface->ctrl_dst, - level, txt, len, wpa_s->ctrl_iface, - NULL); + priv = wpa_s->ctrl_iface; + + if (type != WPA_MSG_ONLY_GLOBAL && priv) { + if (!dl_list_empty(&priv->msg_queue) || + wpas_ctrl_iface_throttle(priv->sock)) { + if (priv->throttle_count == 0) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle event message for sock %d", + priv->sock); + } + priv->throttle_count++; + wpas_ctrl_msg_queue_limit(priv->throttle_count, + &priv->msg_queue); + wpas_ctrl_msg_queue(&priv->msg_queue, wpa_s, level, + type, txt, len); + } else { + if (priv->throttle_count) { + wpa_printf(MSG_MSGDUMP, + "CTRL: Had to throttle %u event message(s) for sock %d", + priv->throttle_count, priv->sock); + } + priv->throttle_count = 0; + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, priv->sock, + &priv->ctrl_dst, level, + txt, len, priv, NULL); + } + } } @@ -580,6 +701,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); + dl_list_init(&priv->msg_queue); priv->wpa_s = wpa_s; priv->sock = -1; @@ -673,6 +795,8 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { struct wpa_ctrl_dst *dst, *prev; + struct ctrl_iface_msg *msg, *prev_msg; + struct ctrl_iface_global_priv *gpriv; if (priv->sock > -1) { char *fname; @@ -726,8 +850,26 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) free_dst: dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, - list) + list) { + dl_list_del(&dst->list); os_free(dst); + } + dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, + struct ctrl_iface_msg, list) { + dl_list_del(&msg->list); + os_free(msg); + } + gpriv = priv->wpa_s->global->ctrl_iface; + if (gpriv) { + dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue, + struct ctrl_iface_msg, list) { + if (msg->wpa_s == priv->wpa_s) { + dl_list_del(&msg->list); + os_free(msg); + } + } + } + eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL); os_free(priv); } @@ -787,33 +929,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; - char addr_txt[200]; + char txt[200]; if (level < dst->debug_level) continue; - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { - wpa_printf(MSG_MSGDUMP, - "CTRL_IFACE monitor sent successfully to %s", - addr_txt); + sockaddr_print(MSG_MSGDUMP, + "CTRL_IFACE monitor sent successfully to", + &dst->addr, dst->addrlen); dst->errors = 0; continue; } _errno = errno; - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", - addr_txt, errno, strerror(errno)); + os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for", + _errno, strerror(_errno)); + sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { - wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", - addr_txt); + sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:", + &dst->addr, dst->addrlen); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } @@ -847,9 +987,12 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { char buf[256]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); + if (priv->sock == -1) + return; + for (;;) { wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " "attach", priv->wpa_s->ifname); @@ -907,7 +1050,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_global_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len; @@ -1157,6 +1300,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) if (priv == NULL) return NULL; dl_list_init(&priv->ctrl_dst); + dl_list_init(&priv->msg_queue); priv->global = global; priv->sock = -1; @@ -1206,6 +1350,7 @@ void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) { struct wpa_ctrl_dst *dst, *prev; + struct ctrl_iface_msg *msg, *prev_msg; if (priv->sock >= 0) { eloop_unregister_read_sock(priv->sock); @@ -1214,7 +1359,14 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) if (priv->global->params.ctrl_interface) unlink(priv->global->params.ctrl_interface); dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, - list) + list) { + dl_list_del(&dst->list); os_free(dst); + } + dl_list_for_each_safe(msg, prev_msg, &priv->msg_queue, + struct ctrl_iface_msg, list) { + dl_list_del(&msg->list); + os_free(msg); + } os_free(priv); } diff --git a/freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new.h index 6d240fff..d64fceef 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new.h +++ b/freebsd/contrib/wpa/wpa_supplicant/dbus/dbus_new.h @@ -29,6 +29,7 @@ enum wpas_dbus_prop { WPAS_DBUS_PROP_CURRENT_AUTH_MODE, WPAS_DBUS_PROP_BSSS, WPAS_DBUS_PROP_DISCONNECT_REASON, + WPAS_DBUS_PROP_ASSOC_STATUS_CODE, }; enum wpas_dbus_bss_prop { @@ -189,8 +190,7 @@ void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id, u8 go_intent); void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, - int client, int network_id); + int client, int persistent); void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, const char *reason); void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s, @@ -400,8 +400,7 @@ static inline void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s, static inline void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, - int client, int network_id) + int client, int persistent) { } diff --git a/freebsd/contrib/wpa/wpa_supplicant/driver_i.h b/freebsd/contrib/wpa/wpa_supplicant/driver_i.h index 73768c75..220b7ba3 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/driver_i.h +++ b/freebsd/contrib/wpa/wpa_supplicant/driver_i.h @@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - u32 interval) + struct wpa_driver_scan_params *params) { if (wpa_s->driver->sched_scan) - return wpa_s->driver->sched_scan(wpa_s->drv_priv, - params, interval); + return wpa_s->driver->sched_scan(wpa_s->drv_priv, params); return -1; } @@ -160,6 +158,15 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s, + const u8 *addr, int idx, u8 *seq) +{ + if (wpa_s->driver->get_seqnum) + return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv, + addr, idx, seq); + return -1; +} + static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s, const u8 *addr, int reason_code) { @@ -292,7 +299,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, if (wpa_s->driver->send_mlme) return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len, noack, - freq); + freq, NULL, 0); return -1; } @@ -401,7 +408,7 @@ static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s, if (wpa_s->driver->if_add) return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname, addr, bss_ctx, NULL, force_ifname, - if_addr, bridge, 0); + if_addr, bridge, 0, 0); return -1; } @@ -726,12 +733,11 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s, } static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s, - const u8 *cs, size_t cs_len) + u64 cs) { if (!wpa_s->driver->set_current_cipher_suite) return -1; - return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs, - cs_len); + return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs); } static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s, @@ -912,4 +918,62 @@ static inline int wpa_drv_set_prob_oper_freq(struct wpa_supplicant *wpa_s, return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq); } +static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->abort_scan) + return -1; + return wpa_s->driver->abort_scan(wpa_s->drv_priv); +} + +static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s, + u32 filters) +{ + if (!wpa_s->driver->configure_data_frame_filters) + return -1; + return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv, + filters); +} + +static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s, + enum wpa_driver_if_type type) +{ + if (!wpa_s->driver->get_ext_capab) + return -1; + return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type, + &wpa_s->extended_capa, + &wpa_s->extended_capa_mask, + &wpa_s->extended_capa_len); +} + +static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s, + unsigned int channel, + unsigned int period, + unsigned int interval, + unsigned int count, + const u8 *device_types, + size_t dev_types_len, + const u8 *ies, size_t ies_len) +{ + if (!wpa_s->driver->p2p_lo_start) + return -1; + return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period, + interval, count, device_types, + dev_types_len, ies, ies_len); +} + +static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->p2p_lo_stop) + return -1; + return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv); +} + +static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t len) +{ + if (!wpa_s->driver->set_default_scan_ies) + return -1; + return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); +} + #endif /* DRIVER_I_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/events.c b/freebsd/contrib/wpa/wpa_supplicant/events.c index 3cf22d4c..1ed27b58 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/events.c +++ b/freebsd/contrib/wpa/wpa_supplicant/events.c @@ -74,6 +74,7 @@ static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, } +#ifndef CONFIG_NO_SCAN_PROCESSING /** * wpas_reenabled_network_time - Time until first network is re-enabled * @wpa_s: Pointer to wpa_supplicant data @@ -109,6 +110,7 @@ static int wpas_reenabled_network_time(struct wpa_supplicant *wpa_s) return res; } +#endif /* CONFIG_NO_SCAN_PROCESSING */ void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx) @@ -281,6 +283,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_supplicant_ap_deinit(wpa_s); #endif /* CONFIG_AP */ +#ifdef CONFIG_HS20 + /* Clear possibly configured frame filters */ + wpa_drv_configure_frame_filters(wpa_s, 0); +#endif /* CONFIG_HS20 */ + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) return; @@ -567,11 +574,36 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, break; } #endif /* CONFIG_IEEE80211W */ + if ((ie.capabilities & WPA_CAPABILITY_MFPR) && + wpas_get_ssid_pmf(wpa_s, ssid) == + NO_MGMT_FRAME_PROTECTION) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - no mgmt frame protection enabled but AP requires it"); + break; + } +#ifdef CONFIG_MBO + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && + wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) && + wpas_get_ssid_pmf(wpa_s, ssid) != + NO_MGMT_FRAME_PROTECTION) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSN IE - no mgmt frame protection enabled on MBO AP"); + break; + } +#endif /* CONFIG_MBO */ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE"); return 1; } +#ifdef CONFIG_IEEE80211W + if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - MFP Required but network not MFP Capable"); + return 0; + } +#endif /* CONFIG_IEEE80211W */ + wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { proto_match++; @@ -809,10 +841,10 @@ static int addr_in_list(const u8 *addr, const u8 *list, size_t num) } -static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, - int i, struct wpa_bss *bss, - struct wpa_ssid *group, - int only_first_ssid) +struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, + int i, struct wpa_bss *bss, + struct wpa_ssid *group, + int only_first_ssid) { u8 wpa_ie_len, rsn_ie_len; int wpa; @@ -820,6 +852,9 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, const u8 *ie; struct wpa_ssid *ssid; int osen; +#ifdef CONFIG_MBO + const u8 *assoc_disallow; +#endif /* CONFIG_MBO */ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); wpa_ie_len = ie ? ie[1] : 0; @@ -981,8 +1016,16 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } - if (!bss_is_ess(bss)) { - wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network"); + if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) && + !bss_is_pbss(bss)) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - not ESS, PBSS, or MBSS"); + continue; + } + + if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - PBSS mismatch (ssid %d bss %d)", + ssid->pbss, bss_is_pbss(bss)); continue; } @@ -992,6 +1035,14 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } +#ifdef CONFIG_MESH + if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 && + ssid->frequency != bss->freq) { + wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not allowed (mesh)"); + continue; + } +#endif /* CONFIG_MESH */ + if (!rate_match(wpa_s, bss)) { wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do " "not match"); @@ -1051,6 +1102,29 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, (unsigned int) diff.usec); continue; } +#ifdef CONFIG_MBO +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_assoc_disallow) + goto skip_assoc_disallow; +#endif /* CONFIG_TESTING_OPTIONS */ + assoc_disallow = wpas_mbo_get_bss_attr( + bss, MBO_ATTR_ID_ASSOC_DISALLOW); + if (assoc_disallow && assoc_disallow[1] >= 1) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - MBO association disallowed (reason %u)", + assoc_disallow[2]); + continue; + } + + if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - MBO retry delay has not passed yet"); + continue; + } +#ifdef CONFIG_TESTING_OPTIONS + skip_assoc_disallow: +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_MBO */ /* Matching configuration found */ return ssid; @@ -1304,6 +1378,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_bss *current_bss = NULL; #ifndef CONFIG_NO_ROAMING int min_diff; + int to_5ghz; #endif /* CONFIG_NO_ROAMING */ if (wpa_s->reassociate) @@ -1359,7 +1434,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, return 1; } - if (current_bss->level < 0 && current_bss->level > selected->level) { + to_5ghz = selected->freq > 4000 && current_bss->freq < 4000; + + if (current_bss->level < 0 && + current_bss->level > selected->level + to_5ghz * 2) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); return 0; @@ -1378,6 +1456,13 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, else min_diff = 5; } + if (to_5ghz) { + /* Make it easier to move to 5 GHz band */ + if (min_diff > 2) + min_diff -= 2; + else + min_diff = 0; + } if (abs(current_bss->level - selected->level) < min_diff) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference " "in signal level"); @@ -1420,6 +1505,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return -1; if (!own_request) return -1; + if (data && data->scan_info.external_scan) + return -1; wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try " "scanning again"); wpa_supplicant_req_new_scan(wpa_s, 1, 0); @@ -1444,7 +1531,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->radio->external_scan_running)) { + !(data && data->scan_info.external_scan)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); @@ -1465,9 +1552,11 @@ 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->radio->external_scan_running); + wpa_s->own_scan_running, + data ? data->scan_info.external_scan : 0); if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && - wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { + wpa_s->manual_scan_use_id && wpa_s->own_scan_running && + own_request && !(data && data->scan_info.external_scan)) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); wpa_s->manual_scan_use_id = 0; @@ -1478,7 +1567,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->radio->external_scan_running) { + if (data && data->scan_info.external_scan) { 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; @@ -1507,9 +1596,13 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_wps_update_ap_info(wpa_s, scan_res); + if (wpa_s->wpa_state >= WPA_AUTHENTICATING && + wpa_s->wpa_state < WPA_COMPLETED) + goto scan_work_done; + wpa_scan_results_free(scan_res); - if (wpa_s->scan_work) { + if (own_request && wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); @@ -1519,7 +1612,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, scan_work_done: wpa_scan_results_free(scan_res); - if (wpa_s->scan_work) { + if (own_request && wpa_s->scan_work) { struct wpa_radio_work *work = wpa_s->scan_work; wpa_s->scan_work = NULL; radio_work_done(work); @@ -1550,6 +1643,14 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, selected = wpa_supplicant_pick_network(wpa_s, &ssid); +#ifdef CONFIG_MESH + if (wpa_s->ifmsh) { + wpa_msg(wpa_s, MSG_INFO, + "Avoiding join because we already joined a mesh group"); + return 0; + } +#endif /* CONFIG_MESH */ + if (selected) { int skip; skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid); @@ -1559,6 +1660,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; } + if (ssid != wpa_s->current_ssid && + wpa_s->wpa_state >= WPA_AUTHENTICATING) { + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); + } + if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed"); return -1; @@ -1571,13 +1679,6 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, */ return 1; } else { -#ifdef CONFIG_MESH - if (wpa_s->ifmsh) { - wpa_msg(wpa_s, MSG_INFO, - "Avoiding join because we already joined a mesh group"); - return 0; - } -#endif /* CONFIG_MESH */ wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found"); ssid = wpa_supplicant_pick_new_network(wpa_s); if (ssid) { @@ -1833,6 +1934,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_FST +static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s, + const u8 *ie, size_t ie_len) +{ + struct mb_ies_info mb_ies; + + if (!ie || !ie_len || !wpa_s->fst) + return -ENOENT; + + os_memset(&mb_ies, 0, sizeof(mb_ies)); + + while (ie_len >= 2 && mb_ies.nof_ies < MAX_NOF_MB_IES_SUPPORTED) { + size_t len; + + len = 2 + ie[1]; + if (len > ie_len) { + wpa_hexdump(MSG_DEBUG, "FST: Truncated IE found", + ie, ie_len); + break; + } + + if (ie[0] == WLAN_EID_MULTI_BAND) { + wpa_printf(MSG_DEBUG, "MB IE of %u bytes found", + (unsigned int) len); + mb_ies.ies[mb_ies.nof_ies].ie = ie + 2; + mb_ies.ies[mb_ies.nof_ies].ie_len = len - 2; + mb_ies.nof_ies++; + } + + ie_len -= len; + ie += len; + } + + if (mb_ies.nof_ies > 0) { + wpabuf_free(wpa_s->received_mb_ies); + wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies); + return 0; + } + + return -ENOENT; +} +#endif /* CONFIG_FST */ + + static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -1883,6 +2028,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, } if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || + (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 && + (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) || (p[0] == WLAN_EID_RSN && p[1] >= 2)) { if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) break; @@ -2015,19 +2162,6 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, if (wpa_found || rsn_found) wpa_s->ap_ies_from_associnfo = 1; -#ifdef CONFIG_FST - wpabuf_free(wpa_s->received_mb_ies); - wpa_s->received_mb_ies = NULL; - if (wpa_s->fst) { - struct mb_ies_info mb_ies; - - wpa_printf(MSG_DEBUG, "Looking for MB IE"); - if (!mb_ies_info_by_ies(&mb_ies, data->assoc_info.resp_ies, - data->assoc_info.resp_ies_len)) - wpa_s->received_mb_ies = mb_ies_by_info(&mb_ies); - } -#endif /* CONFIG_FST */ - if (wpa_s->assoc_freq && data->assoc_info.freq && wpa_s->assoc_freq != data->assoc_info.freq) { wpa_printf(MSG_DEBUG, "Operating frequency changed from " @@ -2066,11 +2200,50 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s) } +static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ +#ifdef CONFIG_FST + struct assoc_info *ai = data ? &data->assoc_info : NULL; + struct wpa_bss *bss = wpa_s->current_bss; + const u8 *ieprb, *iebcn; + + wpabuf_free(wpa_s->received_mb_ies); + wpa_s->received_mb_ies = NULL; + + if (ai && + !wpas_fst_update_mbie(wpa_s, ai->resp_ies, ai->resp_ies_len)) { + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from Association Response frame"); + return; + } + + if (ai && + !wpas_fst_update_mbie(wpa_s, ai->beacon_ies, ai->beacon_ies_len)) { + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from association event Beacon IEs"); + return; + } + + if (!bss) + return; + + ieprb = (const u8 *) (bss + 1); + iebcn = ieprb + bss->ie_len; + + if (!wpas_fst_update_mbie(wpa_s, ieprb, bss->ie_len)) + wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss IE"); + else if (!wpas_fst_update_mbie(wpa_s, iebcn, bss->beacon_ie_len)) + wpa_printf(MSG_DEBUG, "FST: MB IEs updated from bss beacon IE"); +#endif /* CONFIG_FST */ +} + + static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { u8 bssid[ETH_ALEN]; - int ft_completed; + int ft_completed, already_authorized; int new_bss = 0; #ifdef CONFIG_AP @@ -2126,6 +2299,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, "WPA/RSN IEs not updated"); } + wpas_fst_update_mb_assoc(wpa_s, data); + #ifdef CONFIG_SME os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); wpa_s->sme.prev_bssid_set = 1; @@ -2144,6 +2319,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (wpa_s->l2) l2_packet_notify_auth_start(wpa_s->l2); + already_authorized = data && data->assoc_info.authorized; + /* * Set portEnabled first to FALSE in order to get EAP state machine out * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE @@ -2152,11 +2329,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, * AUTHENTICATED without ever giving chance to EAP state machine to * reset the state. */ - if (!ft_completed) { + if (!ft_completed && !already_authorized) { eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); } - if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed) + if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed || + already_authorized) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); /* 802.1X::portControl = Auto */ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); @@ -2248,7 +2426,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->key_mgmt != WPA_KEY_MGMT_NONE && wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE && wpa_s->ibss_rsn == NULL) { - wpa_s->ibss_rsn = ibss_rsn_init(wpa_s); + wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid); if (!wpa_s->ibss_rsn) { wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN"); wpa_supplicant_deauthenticate( @@ -2342,6 +2520,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, struct wpa_bss *fast_reconnect = NULL; struct wpa_ssid *fast_reconnect_ssid = NULL; struct wpa_ssid *last_ssid; + struct wpa_bss *curr = NULL; authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); @@ -2357,6 +2536,19 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, return; } + if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING && + reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY && + locally_generated) + /* + * Remove the inactive AP (which is probably out of range) from + * the BSS list after marking disassociation. In particular + * mac80211-based drivers use the + * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in + * locally generated disconnection events for cases where the + * AP does not reply anymore. + */ + curr = wpa_s->current_bss; + if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) { wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); @@ -2367,7 +2559,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, if (!wpa_s->disconnected && (!wpa_s->auto_reconnect_disabled || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS || - wpas_wps_searching(wpa_s))) { + wpas_wps_searching(wpa_s) || + wpas_wps_reenable_networks_pending(wpa_s))) { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to " "reconnect (wps=%d/%d wpa_state=%d)", wpa_s->key_mgmt == WPA_KEY_MGMT_WPS, @@ -2417,6 +2610,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, last_ssid = wpa_s->current_ssid; wpa_supplicant_mark_disassoc(wpa_s); + if (curr) + wpa_bss_remove(wpa_s, curr, "Connection to AP lost"); + if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid); wpa_s->current_ssid = last_ssid; @@ -2427,7 +2623,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, !disallowed_bssid(wpa_s, fast_reconnect->bssid) && !disallowed_ssid(wpa_s, fast_reconnect->ssid, fast_reconnect->ssid_len) && - !wpas_temp_disabled(wpa_s, fast_reconnect_ssid)) { + !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) && + !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) { #ifndef CONFIG_NO_SCAN_PROCESSING wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS"); if (wpa_supplicant_connect(wpa_s, fast_reconnect, @@ -2625,6 +2822,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + if (wpa_s->matched) { + wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0); + break; + } +#endif /* CONFIG_MATCH_IFACE */ + #ifdef CONFIG_TERMINATE_ONLASTIF /* check if last interface */ if (!any_interfaces(wpa_s->global->ifaces)) @@ -3010,7 +3214,16 @@ static void wpa_supplicant_update_channel_list( { struct wpa_supplicant *ifs; - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", + /* + * To allow backwards compatibility with higher level layers that + * assumed the REGDOM_CHANGE event is sent over the initially added + * interface. Find the highest parent of this interface and use it to + * send the event. + */ + for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent) + ; + + wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s", reg_init_str(info->initiator), reg_type_str(info->type), info->alpha2[0] ? " alpha2=" : "", info->alpha2[0] ? info->alpha2 : ""); @@ -3025,14 +3238,16 @@ static void wpa_supplicant_update_channel_list( free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( ifs, &ifs->hw.num_modes, &ifs->hw.flags); - } - /* Restart sched_scan with updated channel list */ - if (wpa_s->sched_scanning) { - wpa_dbg(wpa_s, MSG_DEBUG, - "Channel list changed restart sched scan."); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); + /* Restart PNO/sched_scan with updated channel list */ + if (ifs->pno) { + wpas_stop_pno(ifs); + wpas_start_pno(ifs); + } else if (ifs->sched_scanning && !ifs->pno_sched_pending) { + wpa_dbg(ifs, MSG_DEBUG, + "Channel list changed - restart sched_scan"); + wpas_scan_restart_sched_scan(ifs); + } } wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER); @@ -3123,6 +3338,14 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ if (category == WLAN_ACTION_RADIO_MEASUREMENT && + payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) { + wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa, + payload + 1, + plen - 1); + return; + } + + if (category == WLAN_ACTION_RADIO_MEASUREMENT && payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) { wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1); return; @@ -3212,6 +3435,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && event != EVENT_INTERFACE_STATUS && + event != EVENT_SCAN_RESULTS && event != EVENT_SCHED_SCAN_STOPPED) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore event %s (%d) while interface is disabled", @@ -3240,18 +3464,43 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, switch (event) { case EVENT_AUTH: +#ifdef CONFIG_FST + if (!wpas_fst_update_mbie(wpa_s, data->auth.ies, + data->auth.ies_len)) + wpa_printf(MSG_DEBUG, + "FST: MB IEs updated from auth IE"); +#endif /* CONFIG_FST */ sme_event_auth(wpa_s, data); break; case EVENT_ASSOC: +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, + "EVENT_ASSOC - ignore_auth_resp active!"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpa_supplicant_event_assoc(wpa_s, data); if (data && data->assoc_info.authorized) wpa_supplicant_event_assoc_auth(wpa_s, data); + if (data) { + wpa_msg(wpa_s, MSG_INFO, + WPA_EVENT_SUBNET_STATUS_UPDATE "status=%u", + data->assoc_info.subnet_status); + } break; case EVENT_DISASSOC: wpas_event_disassoc(wpa_s, data ? &data->disassoc_info : NULL); break; case EVENT_DEAUTH: +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, + "EVENT_DEAUTH - ignore_auth_resp active!"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); break; @@ -3260,10 +3509,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #ifndef CONFIG_NO_SCAN_PROCESSING case EVENT_SCAN_STARTED: - os_get_reltime(&wpa_s->scan_start_time); - if (wpa_s->own_scan_requested) { + if (wpa_s->own_scan_requested || + (data && !data->scan_info.external_scan)) { struct os_reltime diff; + os_get_reltime(&wpa_s->scan_start_time); os_reltime_sub(&wpa_s->scan_start_time, &wpa_s->scan_trigger_time, &diff); wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan in %ld.%06ld seconds", @@ -3286,7 +3536,16 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } break; case EVENT_SCAN_RESULTS: - if (os_reltime_initialized(&wpa_s->scan_start_time)) { + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + wpa_s->scan_res_handler = NULL; + wpa_s->own_scan_running = 0; + wpa_s->radio->external_scan_running = 0; + wpa_s->last_scan_req = NORMAL_SCAN_REQ; + break; + } + + if (!(data && data->scan_info.external_scan) && + os_reltime_initialized(&wpa_s->scan_start_time)) { struct os_reltime now, diff; os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); @@ -3297,8 +3556,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } if (wpa_supplicant_event_scan_results(wpa_s, data)) break; /* interface may have been removed */ - wpa_s->own_scan_running = 0; - wpa_s->radio->external_scan_running = 0; + if (!(data && data->scan_info.external_scan)) + wpa_s->own_scan_running = 0; + if (data && data->scan_info.nl_scan_event) + wpa_s->radio->external_scan_running = 0; radio_work_check_next(wpa_s); break; #endif /* CONFIG_NO_SCAN_PROCESSING */ @@ -3339,13 +3600,17 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_ASSOC_REJECT: if (data->assoc_reject.bssid) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "bssid=" MACSTR " status_code=%u", + "bssid=" MACSTR " status_code=%u%s", MAC2STR(data->assoc_reject.bssid), - data->assoc_reject.status_code); + data->assoc_reject.status_code, + data->assoc_reject.timed_out ? " timeout" : ""); else wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT - "status_code=%u", - data->assoc_reject.status_code); + "status_code=%u%s", + data->assoc_reject.status_code, + data->assoc_reject.timed_out ? " timeout" : ""); + wpa_s->assoc_status_code = data->assoc_reject.status_code; + wpas_notify_assoc_status_code(wpa_s); if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_reject(wpa_s, data); else { @@ -3401,17 +3666,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ #ifdef CONFIG_OFFCHANNEL wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst=" - MACSTR, MAC2STR(wpa_s->parent->pending_action_dst)); + MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst)); /* * Catch TX status events for Action frames we sent via group - * interface in GO mode. + * interface in GO mode, or via standalone AP interface. + * Note, wpa_s->p2pdev will be the same as wpa_s->parent, + * except when the primary interface is used as a GO interface + * (for drivers which do not have group interface concurrency) */ if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_ACTION && - os_memcmp(wpa_s->parent->pending_action_dst, + os_memcmp(wpa_s->p2pdev->pending_action_dst, data->tx_status.dst, ETH_ALEN) == 0) { offchannel_send_action_tx_status( - wpa_s->parent, data->tx_status.dst, + wpa_s->p2pdev, data->tx_status.dst, data->tx_status.data, data->tx_status.data_len, data->tx_status.ack ? @@ -3454,20 +3722,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.wds); break; case EVENT_CH_SWITCH: - if (!data) - break; - if (!wpa_s->ap_iface) { - wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch " - "event in non-AP mode"); + if (!data || !wpa_s->current_ssid) break; + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH + "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d", + data->ch_switch.freq, + data->ch_switch.ht_enabled, + data->ch_switch.ch_offset, + channel_width_to_string(data->ch_switch.ch_width), + data->ch_switch.cf1, + data->ch_switch.cf2); + + wpa_s->assoc_freq = data->ch_switch.freq; + wpa_s->current_ssid->frequency = data->ch_switch.freq; + + if (wpa_s->current_ssid->mode == WPAS_MODE_AP || + wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO || + wpa_s->current_ssid->mode == + WPAS_MODE_P2P_GROUP_FORMATION) { + wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, + data->ch_switch.ht_enabled, + data->ch_switch.ch_offset, + data->ch_switch.ch_width, + data->ch_switch.cf1, + data->ch_switch.cf2); } - wpas_ap_ch_switch(wpa_s, data->ch_switch.freq, - data->ch_switch.ht_enabled, - data->ch_switch.ch_offset, - data->ch_switch.ch_width, - data->ch_switch.cf1, - data->ch_switch.cf2); + wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS); break; #ifdef NEED_AP_MLME case EVENT_DFS_RADAR_DETECTED: @@ -3524,12 +3806,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ #ifdef CONFIG_P2P if (stype == WLAN_FC_STYPE_PROBE_REQ && - data->rx_mgmt.frame_len > 24) { + data->rx_mgmt.frame_len > IEEE80211_HDRLEN) { const u8 *src = mgmt->sa; - const u8 *ie = mgmt->u.probe_req.variable; - size_t ie_len = data->rx_mgmt.frame_len - - (mgmt->u.probe_req.variable - - data->rx_mgmt.frame); + const u8 *ie; + size_t ie_len; + + ie = data->rx_mgmt.frame + IEEE80211_HDRLEN; + ie_len = data->rx_mgmt.frame_len - + IEEE80211_HDRLEN; wpas_p2p_probe_req_rx( wpa_s, src, mgmt->da, mgmt->bssid, ie, ie_len, @@ -3569,11 +3853,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } if (stype == WLAN_FC_STYPE_PROBE_REQ && - data->rx_mgmt.frame_len > 24) { - const u8 *ie = mgmt->u.probe_req.variable; - size_t ie_len = data->rx_mgmt.frame_len - - (mgmt->u.probe_req.variable - - data->rx_mgmt.frame); + data->rx_mgmt.frame_len > IEEE80211_HDRLEN) { + const u8 *ie; + size_t ie_len; + + ie = data->rx_mgmt.frame + IEEE80211_HDRLEN; + ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN; wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da, mgmt->bssid, ie, ie_len, @@ -3716,6 +4001,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1); } wpa_supplicant_mark_disassoc(wpa_s); + wpa_bss_flush(wpa_s); radio_remove_works(wpa_s, NULL, 0); wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); @@ -3774,15 +4060,28 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->driver_gtk_rekey.replay_ctr); break; case EVENT_SCHED_SCAN_STOPPED: - wpa_s->pno = 0; wpa_s->sched_scanning = 0; - resched = wpa_s->scanning; + resched = wpa_s->scanning && wpas_scan_scheduled(wpa_s); wpa_supplicant_notify_scanning(wpa_s, 0); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) break; /* + * If the driver stopped scanning without being requested to, + * request a new scan to continue scanning for networks. + */ + if (!wpa_s->sched_scan_stop_req && + wpa_s->wpa_state == WPA_SCANNING) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Restart scanning after unexpected sched_scan stop event"); + wpa_supplicant_req_scan(wpa_s, 1, 0); + break; + } + + wpa_s->sched_scan_stop_req = 0; + + /* * Start a new sched scan to continue searching for more SSIDs * either if timed out or PNO schedule scan is pending. */ @@ -3823,8 +4122,72 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->mesh_peer.ie_len); #endif /* CONFIG_MESH */ break; + case EVENT_SURVEY: +#ifdef CONFIG_AP + if (!wpa_s->ap_iface) + break; + hostapd_event_get_survey(wpa_s->ap_iface, + &data->survey_results); +#endif /* CONFIG_AP */ + break; + case EVENT_ACS_CHANNEL_SELECTED: +#ifdef CONFIG_ACS + if (!wpa_s->ap_iface) + break; + hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0], + &data->acs_selected_channels); +#endif /* CONFIG_ACS */ + break; + case EVENT_P2P_LO_STOP: +#ifdef CONFIG_P2P + wpa_s->p2p_lo_started = 0; + wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP + P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d", + data->p2p_lo_stop.reason_code); +#endif /* CONFIG_P2P */ + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; } } + + +void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, + union wpa_event_data *data) +{ + struct wpa_supplicant *wpa_s; + + if (event != EVENT_INTERFACE_STATUS) + return; + + wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname); + if (wpa_s && wpa_s->driver->get_ifindex) { + unsigned int ifindex; + + ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv); + if (ifindex != data->interface_status.ifindex) { + wpa_dbg(wpa_s, MSG_DEBUG, + "interface status ifindex %d mismatch (%d)", + ifindex, data->interface_status.ifindex); + return; + } + } +#ifdef CONFIG_MATCH_IFACE + else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) { + struct wpa_interface *wpa_i; + + wpa_i = wpa_supplicant_match_iface( + ctx, data->interface_status.ifname); + if (!wpa_i) + return; + wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL); + os_free(wpa_i); + if (wpa_s) + wpa_s->matched = 1; + } +#endif /* CONFIG_MATCH_IFACE */ + + if (wpa_s) + wpa_supplicant_event(wpa_s, event, data); +} diff --git a/freebsd/contrib/wpa/wpa_supplicant/gas_query.c b/freebsd/contrib/wpa/wpa_supplicant/gas_query.c index a93f8064..c099bc9a 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/gas_query.c +++ b/freebsd/contrib/wpa/wpa_supplicant/gas_query.c @@ -19,6 +19,7 @@ #include "common/wpa_ctrl.h" #include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" +#include "config.h" #include "driver_i.h" #include "offchannel.h" #include "gas_query.h" @@ -27,6 +28,9 @@ /** GAS query timeout in seconds */ #define GAS_QUERY_TIMEOUT_PERIOD 2 +/* GAS query wait-time / duration in ms */ +#define GAS_QUERY_WAIT_TIME_INITIAL 1000 +#define GAS_QUERY_WAIT_TIME_COMEBACK 150 /** * struct gas_query_pending - Pending GAS query @@ -39,6 +43,7 @@ struct gas_query_pending { u8 next_frag_id; unsigned int wait_comeback:1; unsigned int offchannel_tx_started:1; + unsigned int retry:1; int freq; u16 status_code; struct wpabuf *req; @@ -65,6 +70,10 @@ struct gas_query { static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx); static void gas_query_timeout(void *eloop_data, void *user_ctx); +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx); +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query); +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst); static int ms_from_time(struct os_reltime *last) @@ -110,8 +119,6 @@ static const char * gas_result_txt(enum gas_query_result result) return "PEER_ERROR"; case GAS_QUERY_INTERNAL_ERROR: return "INTERNAL_ERROR"; - case GAS_QUERY_CANCELLED: - return "CANCELLED"; case GAS_QUERY_DELETED_AT_DEINIT: return "DELETED_AT_DEINIT"; } @@ -153,6 +160,7 @@ static void gas_query_done(struct gas_query *gas, offchannel_send_action_done(gas->wpa_s); eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); eloop_cancel_timeout(gas_query_timeout, gas, query); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); dl_list_del(&query->list); query->cb(query->ctx, query->addr, query->dialog_token, result, query->adv_proto, query->resp, query->status_code); @@ -237,6 +245,13 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(gas_query_timeout, gas, query); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); + if (query->wait_comeback && !query->retry) { + eloop_cancel_timeout(gas_query_rx_comeback_timeout, + gas, query); + eloop_register_timeout( + 0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000, + gas_query_rx_comeback_timeout, gas, query); + } } if (result == OFFCHANNEL_SEND_ACTION_FAILED) { eloop_cancel_timeout(gas_query_timeout, gas, query); @@ -256,10 +271,13 @@ static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, - struct wpabuf *req) + struct wpabuf *req, unsigned int wait_time) { - unsigned int wait_time; int res, prot = pmf_in_use(gas->wpa_s, query->addr); + const u8 *bssid; + const u8 wildcard_bssid[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " "freq=%d prot=%d", MAC2STR(query->addr), @@ -269,12 +287,18 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, *categ = WLAN_ACTION_PROTECTED_DUAL; } os_get_reltime(&query->last_oper); - wait_time = 1000; if (gas->wpa_s->max_remain_on_chan && wait_time > gas->wpa_s->max_remain_on_chan) wait_time = gas->wpa_s->max_remain_on_chan; + if (!gas->wpa_s->conf->gas_address3 || + (gas->wpa_s->current_ssid && + gas->wpa_s->wpa_state >= WPA_ASSOCIATED && + os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0)) + bssid = query->addr; + else + bssid = wildcard_bssid; res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, - gas->wpa_s->own_addr, query->addr, + gas->wpa_s->own_addr, bssid, wpabuf_head(req), wpabuf_len(req), wait_time, gas_query_tx_status, 0); if (res == 0) @@ -287,6 +311,7 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, struct gas_query_pending *query) { struct wpabuf *req; + unsigned int wait_time; req = gas_build_comeback_req(query->dialog_token); if (req == NULL) { @@ -294,7 +319,10 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, return; } - if (gas_query_tx(gas, query, req) < 0) { + wait_time = (query->retry || !query->offchannel_tx_started) ? + GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK; + + if (gas_query_tx(gas, query, req, wait_time) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); @@ -304,6 +332,35 @@ static void gas_query_tx_comeback_req(struct gas_query *gas, } +static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx) +{ + struct gas_query *gas = eloop_data; + struct gas_query_pending *query = user_ctx; + int dialog_token; + + wpa_printf(MSG_DEBUG, + "GAS: No response to comeback request received (retry=%u)", + query->retry); + if (gas->current != query || query->retry) + return; + dialog_token = gas_query_new_dialog_token(gas, query->addr); + if (dialog_token < 0) + return; + wpa_printf(MSG_DEBUG, + "GAS: Retry GAS query due to comeback response timeout"); + query->retry = 1; + query->dialog_token = dialog_token; + *(wpabuf_mhead_u8(query->req) + 2) = dialog_token; + query->wait_comeback = 0; + query->next_frag_id = 0; + wpabuf_free(query->adv_proto); + query->adv_proto = NULL; + eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query); + eloop_cancel_timeout(gas_query_timeout, gas, query); + gas_query_tx_initial_req(gas, query); +} + + static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx) { struct gas_query *gas = eloop_data; @@ -321,6 +378,11 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas, { unsigned int secs, usecs; + if (comeback_delay > 1 && query->offchannel_tx_started) { + offchannel_send_action_done(gas->wpa_s); + query->offchannel_tx_started = 0; + } + secs = (comeback_delay * 1024) / 1000000; usecs = comeback_delay * 1024 - secs * 1000000; wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR @@ -373,6 +435,7 @@ static void gas_query_rx_comeback(struct gas_query *gas, "comeback_delay=%u)", MAC2STR(query->addr), query->dialog_token, frag_id, more_frags, comeback_delay); + eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || os_memcmp(adv_proto, wpabuf_head(query->adv_proto), @@ -449,8 +512,16 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, if (gas == NULL || len < 4) return -1; + pos = data; + action = *pos++; + dialog_token = *pos++; + + if (action != WLAN_PA_GAS_INITIAL_RESP && + action != WLAN_PA_GAS_COMEBACK_RESP) + return -1; /* Not a GAS response */ + prot = categ == WLAN_ACTION_PROTECTED_DUAL; - pmf = pmf_in_use(gas->wpa_s, bssid); + pmf = pmf_in_use(gas->wpa_s, sa); if (prot && !pmf) { wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); return 0; @@ -460,14 +531,6 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, return 0; } - pos = data; - action = *pos++; - dialog_token = *pos++; - - if (action != WLAN_PA_GAS_INITIAL_RESP && - action != WLAN_PA_GAS_COMEBACK_RESP) - return -1; /* Not a GAS response */ - query = gas_query_get_pending(gas, sa, dialog_token); if (query == NULL) { wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR @@ -622,11 +685,18 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) } gas->work = work; + gas_query_tx_initial_req(gas, query); +} - if (gas_query_tx(gas, query, query->req) < 0) { + +static void gas_query_tx_initial_req(struct gas_query *gas, + struct gas_query_pending *query) +{ + if (gas_query_tx(gas, query, query->req, + GAS_QUERY_WAIT_TIME_INITIAL) < 0) { wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to " MACSTR, MAC2STR(query->addr)); - gas_query_free(query, 1); + gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; } gas->current = query; @@ -635,7 +705,24 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit) query->dialog_token); eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout, gas, query); +} + + +static int gas_query_new_dialog_token(struct gas_query *gas, const u8 *dst) +{ + static int next_start = 0; + int dialog_token; + for (dialog_token = 0; dialog_token < 256; dialog_token++) { + if (gas_query_dialog_token_available( + gas, dst, (next_start + dialog_token) % 256)) + break; + } + if (dialog_token == 256) + return -1; /* Too many pending queries */ + dialog_token = (next_start + dialog_token) % 256; + next_start = (dialog_token + 1) % 256; + return dialog_token; } @@ -660,20 +747,13 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, { struct gas_query_pending *query; int dialog_token; - static int next_start = 0; if (wpabuf_len(req) < 3) return -1; - for (dialog_token = 0; dialog_token < 256; dialog_token++) { - if (gas_query_dialog_token_available( - gas, dst, (next_start + dialog_token) % 256)) - break; - } - if (dialog_token == 256) - return -1; /* Too many pending queries */ - dialog_token = (next_start + dialog_token) % 256; - next_start = (dialog_token + 1) % 256; + dialog_token = gas_query_new_dialog_token(gas, dst); + if (dialog_token < 0) + return -1; query = os_zalloc(sizeof(*query)); if (query == NULL) @@ -696,26 +776,10 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, query) < 0) { + query->req = NULL; /* caller will free this in error case */ gas_query_free(query, 1); return -1; } return dialog_token; } - - -/** - * gas_query_cancel - Cancel a pending GAS query - * @gas: GAS query data from gas_query_init() - * @dst: Destination MAC address for the query - * @dialog_token: Dialog token from gas_query_req() - */ -void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token) -{ - struct gas_query_pending *query; - - query = gas_query_get_pending(gas, dst, dialog_token); - if (query) - gas_query_done(gas, query, GAS_QUERY_CANCELLED); - -} diff --git a/freebsd/contrib/wpa/wpa_supplicant/gas_query.h b/freebsd/contrib/wpa/wpa_supplicant/gas_query.h index ad134908..ef82097e 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/gas_query.h +++ b/freebsd/contrib/wpa/wpa_supplicant/gas_query.h @@ -29,7 +29,6 @@ enum gas_query_result { GAS_QUERY_TIMEOUT, GAS_QUERY_PEER_ERROR, GAS_QUERY_INTERNAL_ERROR, - GAS_QUERY_CANCELLED, GAS_QUERY_DELETED_AT_DEINIT }; @@ -40,7 +39,6 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code), void *ctx); -void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token); #else /* CONFIG_GAS */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.c b/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.c index ab52320d..44be415a 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.c +++ b/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.c @@ -27,6 +27,7 @@ #include "gas_query.h" #include "interworking.h" #include "hs20_supplicant.h" +#include "base64.h" #define OSU_MAX_ITEMS 10 @@ -62,6 +63,46 @@ struct osu_provider { }; +void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s) +{ + struct wpa_bss *bss = wpa_s->current_bss; + u8 *bssid = wpa_s->bssid; + const u8 *ie; + const u8 *ext_capa; + u32 filter = 0; + + if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) { + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - BSS " MACSTR + " is not a Hotspot 2.0 network", MAC2STR(bssid)); + return; + } + + ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE); + + /* Check if DGAF disabled bit is zero (5th byte in the IE) */ + if (!ie || ie[1] < 5) + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - Can't extract DGAF bit"); + else if (!(ie[6] & HS20_DGAF_DISABLED)) + filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK; + + ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB); + if (!ext_capa || ext_capa[1] < 2) { + wpa_printf(MSG_DEBUG, + "Not configuring frame filtering - Can't extract Proxy ARP bit"); + return; + } + + /* Check if Proxy ARP is enabled (2nd byte in the IE) */ + if (ext_capa[3] & BIT(4)) + filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP | + WPA_DATA_FRAME_FILTER_FLAG_NA; + + wpa_drv_configure_frame_filters(wpa_s, filter); +} + + void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id) { u8 conf; @@ -166,8 +207,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, } -struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, - size_t payload_len) +static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, + size_t payload_len) { struct wpabuf *buf; @@ -182,13 +223,14 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len) + const u8 *payload, size_t payload_len, int inmem) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; + struct icon_entry *icon_entry; bss = wpa_bss_get_bssid(wpa_s, dst); if (!bss) { @@ -212,15 +254,127 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); - ret = -1; + return -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); + if (inmem) { + icon_entry = os_zalloc(sizeof(struct icon_entry)); + if (!icon_entry) + return -1; + os_memcpy(icon_entry->bssid, dst, ETH_ALEN); + icon_entry->file_name = os_malloc(payload_len + 1); + if (!icon_entry->file_name) { + os_free(icon_entry); + return -1; + } + os_memcpy(icon_entry->file_name, payload, payload_len); + icon_entry->file_name[payload_len] = '\0'; + icon_entry->dialog_token = res; + + dl_list_add(&wpa_s->icon_head, &icon_entry->list); + } + return ret; } +static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s, + const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon; + + dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { + if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, file_name) == 0 && icon->image) + return icon; + } + + return NULL; +} + + +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len) +{ + struct icon_entry *icon; + size_t out_size; + unsigned char *b64; + size_t b64_size; + int reply_size; + + wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)", + MAC2STR(bssid), file_name, (unsigned int) offset, + (unsigned int) size, (unsigned int) buf_len); + + icon = hs20_find_icon(wpa_s, bssid, file_name); + if (!icon || !icon->image || offset >= icon->image_len) + return -1; + if (size > icon->image_len - offset) + size = icon->image_len - offset; + out_size = buf_len - 3 /* max base64 padding */; + if (size * 4 > out_size * 3) + size = out_size * 3 / 4; + if (size == 0) + return -1; + + b64 = base64_encode(&icon->image[offset], size, &b64_size); + if (b64 && buf_len >= b64_size) { + os_memcpy(reply, b64, b64_size); + reply_size = b64_size; + } else { + reply_size = -1; + } + os_free(b64); + return reply_size; +} + + +static void hs20_free_icon_entry(struct icon_entry *icon) +{ + wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR + " dialog_token=%u file_name=%s image_len=%u", + MAC2STR(icon->bssid), icon->dialog_token, + icon->file_name ? icon->file_name : "N/A", + (unsigned int) icon->image_len); + os_free(icon->file_name); + os_free(icon->image); + os_free(icon); +} + + +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name) +{ + struct icon_entry *icon, *tmp; + int count = 0; + + if (!bssid) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons"); + else if (!file_name) + wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for " + MACSTR, MAC2STR(bssid)); + else + wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for " + MACSTR " file name %s", MAC2STR(bssid), file_name); + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) && + (!file_name || + os_strcmp(icon->file_name, file_name) == 0)) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + count++; + } + } + return count == 0 ? -1 : 0; +} + + static void hs20_set_osu_access_permission(const char *osu_dir, const char *fname) { @@ -245,16 +399,53 @@ static void hs20_set_osu_access_permission(const char *osu_dir, } } + +static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s, + struct icon_entry *new_icon) +{ + struct icon_entry *icon, *tmp; + + dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, + list) { + if (icon == new_icon) + continue; + if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 && + os_strcmp(icon->file_name, new_icon->file_name) == 0) { + dl_list_del(&icon->list); + hs20_free_icon_entry(icon); + } + } +} + + static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, - size_t slen) + size_t slen, u8 dialog_token) { char fname[256]; int png; FILE *f; u16 data_len; + struct icon_entry *icon; + + dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { + if (icon->dialog_token == dialog_token && !icon->image && + os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) { + icon->image = os_malloc(slen); + if (!icon->image) + return -1; + os_memcpy(icon->image, pos, slen); + icon->image_len = slen; + hs20_remove_duplicate_icons(wpa_s, icon); + wpa_msg(wpa_s, MSG_INFO, + RX_HS20_ICON MACSTR " %s %u", + MAC2STR(sa), icon->file_name, + (unsigned int) icon->image_len); + return 0; + } + } - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File", + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File", MAC2STR(sa)); if (slen < 4) { @@ -317,7 +508,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, } fclose(f); - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname); return 0; } @@ -360,7 +551,7 @@ 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, struct wpa_bss *bss, const u8 *sa, - const u8 *data, size_t slen) + const u8 *data, size_t slen, u8 dialog_token) { const u8 *pos = data; u8 subtype; @@ -381,7 +572,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " HS Capability List", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); if (anqp) { @@ -391,7 +582,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operator Friendly Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); if (anqp) { @@ -407,7 +598,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, "Metrics value from " MACSTR, MAC2STR(sa)); break; } - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), pos[9], pos[10], WPA_GET_LE16(pos + 11)); @@ -417,7 +608,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_CONNECTION_CAPABILITY: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Connection Capability", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); if (anqp) { @@ -427,7 +618,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATING_CLASS: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operating Class", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); if (anqp) { @@ -437,7 +628,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OSU_PROVIDERS_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " OSU Providers list", MAC2STR(sa)); wpa_s->num_prov_found++; if (anqp) { @@ -447,7 +638,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_ICON_BINARY_FILE: - ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen); + ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen, + dialog_token); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, @@ -513,7 +705,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) wpa_s->conf->osu_dir); f = fopen(fname, "w"); if (f == NULL) { + wpa_msg(wpa_s, MSG_INFO, + "Could not write OSU provider information"); hs20_free_osu_prov(wpa_s); + wpa_s->fetch_anqp_in_progress = 0; return; } @@ -581,7 +776,8 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s) if (hs20_anqp_send_req(wpa_s, osu->bssid, BIT(HS20_STYPE_ICON_REQUEST), (u8 *) icon->filename, - os_strlen(icon->filename)) < 0) { + os_strlen(icon->filename), + 0) < 0) { icon->failed = 1; continue; } @@ -619,7 +815,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, prov->osu_ssid_len = osu_ssid_len; /* OSU Friendly Name Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Friendly Name Length"); return; @@ -635,9 +831,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += len2; /* OSU Friendly Name Duples */ - while (pos2 + 4 <= pos && prov->friendly_name_count < OSU_MAX_ITEMS) { + while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; - if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) { + if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name"); break; } @@ -648,7 +844,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } /* OSU Server URI */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server URI length"); return; @@ -663,7 +859,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += uri_len; /* OSU Method list */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method " "list length"); return; @@ -683,7 +879,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } /* Icons Available Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " "Available Length"); return; @@ -703,7 +899,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct osu_icon *icon = &prov->icon[prov->icon_count]; u8 flen; - if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) { + if (2 + 2 + 3 + 1 + 1 > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata"); break; } @@ -715,46 +911,46 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, os_memcpy(icon->lang, pos2, 3); pos2 += 3; - flen = pos2[0]; - if (flen > pos - pos2 - 1) { + flen = *pos2++; + if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type"); break; } - os_memcpy(icon->icon_type, pos2 + 1, flen); - pos2 += 1 + flen; + os_memcpy(icon->icon_type, pos2, flen); + pos2 += flen; - if (pos2 + 1 > pos) { + if (pos - pos2 < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename length"); break; } - flen = pos2[0]; - if (flen > pos - pos2 - 1) { + flen = *pos2++; + if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename"); break; } - os_memcpy(icon->filename, pos2 + 1, flen); - pos2 += 1 + flen; + os_memcpy(icon->filename, pos2, flen); + pos2 += flen; prov->icon_count++; } /* OSU_NAI */ - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } - osu_nai_len = pos[0]; - if (osu_nai_len > end - pos - 1) { + osu_nai_len = *pos++; + if (osu_nai_len > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } - os_memcpy(prov->osu_nai, pos + 1, osu_nai_len); - pos += 1 + osu_nai_len; + os_memcpy(prov->osu_nai, pos, osu_nai_len); + pos += osu_nai_len; /* OSU Service Description Length */ - if (pos + 2 > end) { + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Service Description Length"); return; @@ -770,20 +966,20 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos += len2; /* OSU Service Description Duples */ - while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) { + while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; u8 descr_len; - descr_len = pos2[0]; - if (descr_len > pos - pos2 - 1 || descr_len < 3) { + descr_len = *pos2++; + if (descr_len > pos - pos2 || descr_len < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Service " "Description"); break; } f = &prov->serv_desc[prov->serv_desc_count++]; - os_memcpy(f->lang, pos2 + 1, 3); - os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3); - pos2 += 1 + descr_len; + os_memcpy(f->lang, pos2, 3); + os_memcpy(f->text, pos2 + 3, descr_len - 3); + pos2 += descr_len; } wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR, @@ -818,9 +1014,9 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) end = pos + wpabuf_len(prov_anqp); /* OSU SSID */ - if (pos + 1 > end) + if (end - pos < 1) continue; - if (pos + 1 + pos[0] > end) { + if (1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "OSU SSID"); continue; @@ -834,7 +1030,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) osu_ssid = pos; pos += osu_ssid_len; - if (pos + 1 > end) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "Number of OSU Providers"); continue; @@ -844,7 +1040,7 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) num_providers); /* OSU Providers */ - while (pos + 2 < end && num_providers > 0) { + while (end - pos > 2 && num_providers > 0) { num_providers--; len = WPA_GET_LE16(pos); pos += 2; @@ -884,7 +1080,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s, } -int hs20_fetch_osu(struct wpa_supplicant *wpa_s) +int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan) { if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - " @@ -915,7 +1111,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch"); wpa_s->num_osu_scans = 0; wpa_s->num_prov_found = 0; - hs20_start_osu_scan(wpa_s); + if (skip_scan) { + wpa_s->network_select = 0; + wpa_s->fetch_all_anqp = 1; + wpa_s->fetch_osu_info = 1; + wpa_s->fetch_osu_icon_in_progress = 0; + + interworking_start_fetch_anqp(wpa_s); + } else { + hs20_start_osu_scan(wpa_s); + } return 0; } @@ -1004,8 +1209,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, } +void hs20_init(struct wpa_supplicant *wpa_s) +{ + dl_list_init(&wpa_s->icon_head); +} + + void hs20_deinit(struct wpa_supplicant *wpa_s) { eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); hs20_free_osu_prov(wpa_s); + if (wpa_s->icon_head.next) + hs20_del_icon(wpa_s, NULL, NULL); } diff --git a/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.h b/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.h index 85b51201..0dd559fd 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.h +++ b/freebsd/contrib/wpa/wpa_supplicant/hs20_supplicant.h @@ -8,17 +8,16 @@ #ifndef HS20_SUPPLICANT_H #define HS20_SUPPLICANT_H +void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s); void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id); int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, - const u8 *payload, size_t payload_len); -struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload, - size_t payload_len); + const u8 *payload, size_t payload_len, int inmem); 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, struct wpa_bss *bss, const u8 *sa, - const u8 *data, size_t slen); + const u8 *data, size_t slen, u8 dialog_token); 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); @@ -32,10 +31,16 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code, void hs20_free_osu_prov(struct wpa_supplicant *wpa_s); void hs20_next_osu_icon(struct wpa_supplicant *wpa_s); void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s); -int hs20_fetch_osu(struct wpa_supplicant *wpa_s); +int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan); void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s); void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s); void hs20_start_osu_scan(struct wpa_supplicant *wpa_s); +void hs20_init(struct wpa_supplicant *wpa_s); void hs20_deinit(struct wpa_supplicant *wpa_s); +int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name, size_t offset, size_t size, + char *reply, size_t buf_len); +int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, + const char *file_name); #endif /* HS20_SUPPLICANT_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/ibss_rsn.h b/freebsd/contrib/wpa/wpa_supplicant/ibss_rsn.h index 67fae2d1..626c5435 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/ibss_rsn.h +++ b/freebsd/contrib/wpa/wpa_supplicant/ibss_rsn.h @@ -51,7 +51,8 @@ struct ibss_rsn { }; -struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s); +struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn); int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr); void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); diff --git a/freebsd/contrib/wpa/wpa_supplicant/interworking.c b/freebsd/contrib/wpa/wpa_supplicant/interworking.c index 21875e15..89f9a9be 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/interworking.c +++ b/freebsd/contrib/wpa/wpa_supplicant/interworking.c @@ -364,13 +364,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, u8 elen, auth_count, a; const u8 *e_end; - if (pos + 3 > end) { + if (end - pos < 3) { wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); return NULL; } elen = *pos++; - if (pos + elen > end || elen < 2) { + if (elen > end - pos || elen < 2) { wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); return NULL; } @@ -383,14 +383,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, for (a = 0; a < auth_count; a++) { u8 id, len; - if (pos + 2 > end || pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "No room for Authentication " - "Parameter subfield"); + if (end - pos < 2) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield header"); return NULL; } id = *pos++; len = *pos++; + if (len > end - pos) { + wpa_printf(MSG_DEBUG, + "No room for Authentication Parameter subfield"); + return NULL; + } switch (id) { case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: @@ -465,7 +470,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ pos += 2; - if (pos + len > end || len < 3) { + if (len > end - pos || len < 3) { wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " "(len=%u; left=%u)", len, (unsigned int) (end - pos)); @@ -475,7 +480,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, r->encoding = *pos++; realm_len = *pos++; - if (pos + realm_len > f_end) { + if (realm_len > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for NAI Realm " "(len=%u; left=%u)", realm_len, (unsigned int) (f_end - pos)); @@ -487,13 +492,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos, return NULL; pos += realm_len; - if (pos + 1 > f_end) { + if (f_end - pos < 1) { wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); return NULL; } r->eap_count = *pos++; wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); - if (pos + r->eap_count * 3 > f_end) { + if (r->eap_count * 3 > f_end - pos) { wpa_printf(MSG_DEBUG, "No room for EAP Methods"); return NULL; } @@ -748,7 +753,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) return 0; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); - if (pos + 2 > end) + if (end - pos < 2) return 0; if (*pos != 0) { wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); @@ -756,7 +761,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) } pos++; udhl = *pos++; - if (pos + udhl > end) { + if (udhl > end - pos) { wpa_printf(MSG_DEBUG, "Invalid UDHL"); return 0; } @@ -766,12 +771,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], imsi, mnc_len); - while (pos + 2 <= end) { + while (end - pos >= 2) { u8 iei, len; const u8 *l_end; iei = *pos++; len = *pos++ & 0x7f; - if (pos + len > end) + if (len > end - pos) break; l_end = pos + len; @@ -782,7 +787,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len) pos, len); num = *pos++; for (i = 0; i < num; i++) { - if (pos + 3 > l_end) + if (l_end - pos < 3) break; if (os_memcmp(pos, plmn, 3) == 0 || os_memcmp(pos, plmn2, 3) == 0) @@ -947,11 +952,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, if (!key_mgmt) key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ? "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP"; - if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0) - return -1; - if (wpa_config_set(ssid, "proto", "RSN", 0) < 0) - return -1; - if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) + if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 || + wpa_config_set(ssid, "proto", "RSN", 0) < 0 || + wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0) return -1; return 0; } @@ -1084,12 +1087,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, * OI #1, [OI #2], [OI #3] */ - if (pos + 2 > end) + if (end - pos < 2) return 0; pos++; /* skip Number of ANQP OIs */ lens = *pos++; - if (pos + (lens & 0x0f) + (lens >> 4) > end) + if ((lens & 0x0f) + (lens >> 4) > end - pos) return 0; if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) @@ -1123,7 +1126,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, /* Set of <OI Length, OI> duples */ while (pos < end) { len = *pos++; - if (pos + len > end) + if (len > end - pos) break; if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) return 1; @@ -1184,6 +1187,7 @@ static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss) static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; unsigned int dl_bandwidth, ul_bandwidth; const u8 *wan; @@ -1235,6 +1239,7 @@ static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s, if (cred->min_ul_bandwidth_roaming > ul_bandwidth) return 1; } +#endif /* CONFIG_HS20 */ return 0; } @@ -1262,9 +1267,11 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_HS20 + static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && pos[3] == 1 /* Open */) return 1; pos += 4; @@ -1277,7 +1284,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, u16 port) { - while (pos + 4 <= end) { + while (end - pos >= 4) { if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && pos[3] == 1 /* Open */) return 1; @@ -1287,10 +1294,13 @@ static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, return 0; } +#endif /* CONFIG_HS20 */ + static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, struct wpa_bss *bss) { +#ifdef CONFIG_HS20 int res; const u8 *capab, *end; unsigned int i, j; @@ -1327,6 +1337,7 @@ static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s, } } } +#endif /* CONFIG_HS20 */ return 0; } @@ -1440,7 +1451,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, os_free(anon); } - if (cred->username && cred->username[0] && + if (!ttls && cred->username && cred->username[0] && cred->realm && + !os_strchr(cred->username, '@')) { + char *id; + size_t buflen; + int res; + + buflen = os_strlen(cred->username) + 1 + + os_strlen(cred->realm) + 1; + + id = os_malloc(buflen); + if (!id) + return -1; + os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm); + res = wpa_config_set_quoted(ssid, "identity", id); + os_free(id); + if (res < 0) + return -1; + } else if (cred->username && cred->username[0] && wpa_config_set_quoted(ssid, "identity", cred->username) < 0) return -1; @@ -1562,9 +1590,8 @@ fail: } -static int interworking_connect_helper(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, int allow_excluded, - int only_add) +int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + int only_add) { struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_ssid *ssid; @@ -1572,7 +1599,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, struct nai_realm_eap *eap = NULL; u16 count, i; char buf[100]; - int excluded = 0, *excl = allow_excluded ? &excluded : NULL; + int excluded = 0, *excl = &excluded; const char *name; if (wpa_s->conf->cred == NULL || bss == NULL) @@ -1586,8 +1613,8 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, } wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR - " for connection (allow_excluded=%d)", - MAC2STR(bss->bssid), allow_excluded); + " for connection", + MAC2STR(bss->bssid)); if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) { /* @@ -1605,7 +1632,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d", cred_rc->priority, cred_rc->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1614,7 +1641,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d", cred->priority, cred->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1624,7 +1651,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest 3GPP matching credential priority %d sp_priority %d", cred_3gpp->priority, cred_3gpp->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1637,7 +1664,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)", cred_rc->priority, cred_rc->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1647,7 +1674,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)", cred->priority, cred->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } @@ -1657,7 +1684,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)", cred_3gpp->priority, cred_3gpp->sp_priority); - if (allow_excluded && excl && !(*excl)) + if (excl && !(*excl)) excl = NULL; } } @@ -1822,13 +1849,6 @@ fail: } -int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - int only_add) -{ - return interworking_connect_helper(wpa_s, bss, 1, only_add); -} - - #ifdef PCSC_FUNCS static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s) { @@ -2127,23 +2147,27 @@ int domain_name_list_contains(struct wpabuf *domain_names, pos = wpabuf_head(domain_names); end = pos + wpabuf_len(domain_names); - while (pos + 1 < end) { - if (pos + 1 + pos[0] > end) + while (end - pos > 1) { + u8 elen; + + elen = *pos++; + if (elen > end - pos) break; wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", - pos + 1, pos[0]); - if (pos[0] == len && - os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) + pos, elen); + if (elen == len && + os_strncasecmp(domain, (const char *) pos, len) == 0) return 1; - if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { - const char *ap = (const char *) (pos + 1); - int offset = pos[0] - len; + if (!exact_match && elen > len && pos[elen - len - 1] == '.') { + const char *ap = (const char *) pos; + int offset = elen - len; + if (os_strncasecmp(domain, ap + offset, len) == 0) return 1; } - pos += 1 + pos[0]; + pos += elen; } return 0; @@ -2566,11 +2590,13 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) return; } +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) { wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)"); hs20_next_osu_icon(wpa_s); return; } +#endif /* CONFIG_HS20 */ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (!(bss->caps & IEEE80211_CAP_ESS)) @@ -2604,6 +2630,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) } if (found == 0) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_info) { if (wpa_s->num_prov_found == 0 && wpa_s->fetch_osu_waiting_scan && @@ -2616,6 +2643,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) hs20_osu_icon_fetch(wpa_s); return; } +#endif /* CONFIG_HS20 */ wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed"); wpa_s->fetch_anqp_in_progress = 0; if (wpa_s->network_select) @@ -2666,10 +2694,11 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s) int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, - u16 info_ids[], size_t num_ids, u32 subtypes) + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref) { struct wpabuf *buf; - struct wpabuf *hs20_buf = NULL; + struct wpabuf *extra_buf = NULL; int ret = 0; int freq; struct wpa_bss *bss; @@ -2692,15 +2721,31 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, #ifdef CONFIG_HS20 if (subtypes != 0) { - hs20_buf = wpabuf_alloc(100); - if (hs20_buf == NULL) + extra_buf = wpabuf_alloc(100); + if (extra_buf == NULL) return -1; - hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf); + hs20_put_anqp_req(subtypes, NULL, 0, extra_buf); } #endif /* CONFIG_HS20 */ - buf = anqp_build_req(info_ids, num_ids, hs20_buf); - wpabuf_free(hs20_buf); +#ifdef CONFIG_MBO + if (get_cell_pref) { + struct wpabuf *mbo; + + mbo = mbo_build_anqp_buf(wpa_s, bss); + if (mbo) { + if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) { + wpabuf_free(extra_buf); + return -1; + } + wpabuf_put_buf(extra_buf, mbo); + wpabuf_free(mbo); + } + } +#endif /* CONFIG_MBO */ + + buf = anqp_build_req(info_ids, num_ids, extra_buf); + wpabuf_free(extra_buf); if (buf == NULL) return -1; @@ -2718,10 +2763,46 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, } +static void anqp_add_extra(struct wpa_supplicant *wpa_s, + struct wpa_bss_anqp *anqp, u16 info_id, + const u8 *data, size_t slen) +{ + struct wpa_bss_anqp_elem *tmp, *elem = NULL; + + if (!anqp) + return; + + dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem, + list) { + if (tmp->infoid == info_id) { + elem = tmp; + break; + } + } + + if (!elem) { + elem = os_zalloc(sizeof(*elem)); + if (!elem) + return; + elem->infoid = info_id; + dl_list_add(&anqp->anqp_elems, &elem->list); + } else { + wpabuf_free(elem->payload); + } + + elem->payload = wpabuf_alloc_copy(data, slen); + if (!elem->payload) { + dl_list_del(&elem->list); + os_free(elem); + } +} + + static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, u16 info_id, - const u8 *data, size_t slen) + const u8 *data, size_t slen, + u8 dialog_token) { const u8 *pos = data; struct wpa_bss_anqp *anqp = NULL; @@ -2734,7 +2815,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (info_id) { case ANQP_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " ANQP Capability list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list", pos, slen); @@ -2744,7 +2825,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_VENUE_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (anqp) { @@ -2753,7 +2834,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NETWORK_AUTH_TYPE: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Network Authentication Type information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " @@ -2764,7 +2845,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_ROAMING_CONSORTIUM: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Roaming Consortium list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); @@ -2774,7 +2855,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " IP Address Type Availability information", MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", @@ -2786,7 +2867,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NAI_REALM: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " NAI Realm list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (anqp) { @@ -2795,7 +2876,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_3GPP_CELLULAR_NETWORK: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " 3GPP Cellular Network information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); @@ -2805,7 +2886,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_DOMAIN_NAME: - wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Domain Name list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (anqp) { @@ -2831,7 +2912,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, bss, sa, - pos, slen); + pos, slen, + dialog_token); break; default: wpa_msg(wpa_s, MSG_DEBUG, @@ -2851,6 +2933,7 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, default: wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Unsupported ANQP Info ID %u", info_id); + anqp_add_extra(wpa_s, anqp, info_id, data, slen); break; } } @@ -2873,8 +2956,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, " dialog_token=%u result=%d status_code=%u", MAC2STR(dst), dialog_token, result, status_code); if (result != GAS_QUERY_SUCCESS) { +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "FAILURE"; goto out; } @@ -2884,8 +2969,10 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Unexpected Advertisement Protocol in response"); +#ifdef CONFIG_HS20 if (wpa_s->fetch_osu_icon_in_progress) hs20_icon_fetch_failed(wpa_s); +#endif /* CONFIG_HS20 */ anqp_result = "INVALID_FRAME"; goto out; } @@ -2929,12 +3016,14 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, goto out_parse_done; } interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos, - slen); + slen, dialog_token); pos += slen; } out_parse_done: +#ifdef CONFIG_HS20 hs20_notify_parse_done(wpa_s); +#endif /* CONFIG_HS20 */ out: wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s", MAC2STR(dst), anqp_result); diff --git a/freebsd/contrib/wpa/wpa_supplicant/interworking.h b/freebsd/contrib/wpa/wpa_supplicant/interworking.h index 3743dc00..3d222926 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/interworking.h +++ b/freebsd/contrib/wpa/wpa_supplicant/interworking.h @@ -12,7 +12,8 @@ enum gas_query_result; int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, - u16 info_ids[], size_t num_ids, u32 subtypes); + u16 info_ids[], size_t num_ids, u32 subtypes, + int get_cell_pref); void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, diff --git a/freebsd/contrib/wpa/wpa_supplicant/main.c b/freebsd/contrib/wpa/wpa_supplicant/main.c index e1c13df3..75f07e36 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/main.c +++ b/freebsd/contrib/wpa/wpa_supplicant/main.c @@ -75,41 +75,44 @@ static void usage(void) " -B = run daemon in the background\n" " -c = Configuration file\n" " -C = ctrl_interface parameter (only used if -c is not)\n" - " -i = interface name\n" - " -I = additional configuration file\n" " -d = increase debugging verbosity (-dd even more)\n" " -D = driver name (can be multiple drivers: nl80211,wext)\n" - " -e = entropy file\n"); + " -e = entropy file\n" #ifdef CONFIG_DEBUG_FILE - printf(" -f = log output to debug file instead of stdout\n"); + " -f = log output to debug file instead of stdout\n" #endif /* CONFIG_DEBUG_FILE */ - printf(" -g = global ctrl_interface\n" + " -g = global ctrl_interface\n" " -G = global ctrl_interface group\n" - " -K = include keys (passwords, etc.) in debug output\n"); -#ifdef CONFIG_DEBUG_SYSLOG - printf(" -s = log output to syslog instead of stdout\n"); -#endif /* CONFIG_DEBUG_SYSLOG */ -#ifdef CONFIG_DEBUG_LINUX_TRACING - printf(" -T = record to Linux tracing in addition to logging\n"); - printf(" (records all messages regardless of debug verbosity)\n"); -#endif /* CONFIG_DEBUG_LINUX_TRACING */ - printf(" -t = include timestamp in debug messages\n" " -h = show this help text\n" + " -i = interface name\n" + " -I = additional configuration file\n" + " -K = include keys (passwords, etc.) in debug output\n" " -L = show license (BSD)\n" +#ifdef CONFIG_P2P + " -m = Configuration file for the P2P Device interface\n" +#endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + " -M = start describing new matching interface\n" +#endif /* CONFIG_MATCH_IFACE */ + " -N = start describing new interface\n" " -o = override driver parameter for new interfaces\n" " -O = override ctrl_interface parameter for new interfaces\n" " -p = driver parameters\n" " -P = PID file\n" - " -q = decrease debugging verbosity (-qq even less)\n"); + " -q = decrease debugging verbosity (-qq even less)\n" +#ifdef CONFIG_DEBUG_SYSLOG + " -s = log output to syslog instead of stdout\n" +#endif /* CONFIG_DEBUG_SYSLOG */ + " -t = include timestamp in debug messages\n" +#ifdef CONFIG_DEBUG_LINUX_TRACING + " -T = record to Linux tracing in addition to logging\n" + " (records all messages regardless of debug verbosity)\n" +#endif /* CONFIG_DEBUG_LINUX_TRACING */ #ifdef CONFIG_DBUS - printf(" -u = enable DBus control interface\n"); + " -u = enable DBus control interface\n" #endif /* CONFIG_DBUS */ - printf(" -v = show version\n" - " -W = wait for a control interface monitor before starting\n" -#ifdef CONFIG_P2P - " -m = Configuration file for the P2P Device interface\n" -#endif /* CONFIG_P2P */ - " -N = start describing new interface\n"); + " -v = show version\n" + " -W = wait for a control interface monitor before starting\n"); printf("example:\n" " wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n", @@ -182,6 +185,28 @@ int rtems_bsd_command_wpa_supplicant(int argc, char **argv) } #endif /* __rtems__ */ +#ifdef CONFIG_MATCH_IFACE +static int wpa_supplicant_init_match(struct wpa_global *global) +{ + /* + * The assumption is that the first driver is the primary driver and + * will handle the arrival / departure of interfaces. + */ + if (wpa_drivers[0]->global_init && !global->drv_priv[0]) { + global->drv_priv[0] = wpa_drivers[0]->global_init(global); + if (!global->drv_priv[0]) { + wpa_printf(MSG_ERROR, + "Failed to initialize driver '%s'", + wpa_drivers[0]->name); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_MATCH_IFACE */ + + int main(int argc, char *argv[]) { int c, i; @@ -214,7 +239,7 @@ int main(int argc, char *argv[]) for (;;) { c = getopt(argc, argv, - "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW"); + "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW"); if (c < 0) break; switch (c) { @@ -320,6 +345,20 @@ int main(int argc, char *argv[]) case 'W': params.wait_for_monitor++; break; +#ifdef CONFIG_MATCH_IFACE + case 'M': + params.match_iface_count++; + iface = os_realloc_array(params.match_ifaces, + params.match_iface_count, + sizeof(struct wpa_interface)); + if (!iface) + goto out; + params.match_ifaces = iface; + iface = ¶ms.match_ifaces[params.match_iface_count - + 1]; + os_memset(iface, 0, sizeof(*iface)); + break; +#endif /* CONFIG_MATCH_IFACE */ case 'N': iface_count++; iface = os_realloc_array(ifaces, iface_count, @@ -366,6 +405,9 @@ int main(int argc, char *argv[]) ifaces[i].ctrl_interface == NULL) || ifaces[i].ifname == NULL) { if (iface_count == 1 && (params.ctrl_interface || +#ifdef CONFIG_MATCH_IFACE + params.match_iface_count || +#endif /* CONFIG_MATCH_IFACE */ params.dbus_ctrl_interface)) break; usage(); @@ -379,6 +421,11 @@ int main(int argc, char *argv[]) } } +#ifdef CONFIG_MATCH_IFACE + if (exitcode == 0) + exitcode = wpa_supplicant_init_match(global); +#endif /* CONFIG_MATCH_IFACE */ + if (exitcode == 0) exitcode = wpa_supplicant_run(global); @@ -389,6 +436,9 @@ int main(int argc, char *argv[]) out: wpa_supplicant_fd_workaround(0); os_free(ifaces); +#ifdef CONFIG_MATCH_IFACE + os_free(params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ os_free(params.pid_file); os_program_deinit(); diff --git a/freebsd/contrib/wpa/wpa_supplicant/mesh.h b/freebsd/contrib/wpa/wpa_supplicant/mesh.h index 3cb7f1b1..7317083c 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/mesh.h +++ b/freebsd/contrib/wpa/wpa_supplicant/mesh.h @@ -18,6 +18,9 @@ int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname, size_t len); +int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr); +int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration); #ifdef CONFIG_MESH diff --git a/freebsd/contrib/wpa/wpa_supplicant/mesh_mpm.h b/freebsd/contrib/wpa/wpa_supplicant/mesh_mpm.h index 7ebaef0c..5fc1e618 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/mesh_mpm.h +++ b/freebsd/contrib/wpa/wpa_supplicant/mesh_mpm.h @@ -14,10 +14,13 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, struct ieee802_11_elems *elems); void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh); void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr); -void mesh_mpm_free_sta(struct sta_info *sta); +void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta); void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta, enum mesh_plink_state state); +int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr); +int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr, + int duration); #ifdef CONFIG_MESH diff --git a/freebsd/contrib/wpa/wpa_supplicant/mesh_rsn.h b/freebsd/contrib/wpa/wpa_supplicant/mesh_rsn.h index b1471b2d..8775cedc 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/mesh_rsn.h +++ b/freebsd/contrib/wpa/wpa_supplicant/mesh_rsn.h @@ -12,7 +12,15 @@ struct mesh_rsn { struct wpa_supplicant *wpa_s; struct wpa_authenticator *auth; - u8 mgtk[16]; + unsigned int pairwise_cipher; + unsigned int group_cipher; + u8 mgtk[WPA_TK_MAX_LEN]; + size_t mgtk_len; + u8 mgtk_key_id; + unsigned int mgmt_group_cipher; + u8 igtk_key_id; + u8 igtk[WPA_TK_MAX_LEN]; + size_t igtk_len; #ifdef CONFIG_SAE struct wpabuf *sae_token; int sae_group_index; @@ -30,6 +38,7 @@ int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta, const u8 *cat, struct wpabuf *buf); int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, struct ieee802_11_elems *elems, const u8 *cat, + const u8 *chosen_pmk, const u8 *start, size_t elems_len); void mesh_auth_timer(void *eloop_ctx, void *user_data); diff --git a/freebsd/contrib/wpa/wpa_supplicant/notify.c b/freebsd/contrib/wpa/wpa_supplicant/notify.c index 1b41f147..020a9a7b 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/notify.c +++ b/freebsd/contrib/wpa/wpa_supplicant/notify.c @@ -15,6 +15,7 @@ #include "config.h" #include "wpa_supplicant_i.h" #include "wps_supplicant.h" +#include "binder/binder.h" #include "dbus/dbus_common.h" #include "dbus/dbus_old.h" #include "dbus/dbus_new.h" @@ -36,6 +37,12 @@ int wpas_notify_supplicant_initialized(struct wpa_global *global) } #endif /* CONFIG_DBUS */ +#ifdef CONFIG_BINDER + global->binder = wpas_binder_init(global); + if (!global->binder) + return -1; +#endif /* CONFIG_BINDER */ + return 0; } @@ -46,6 +53,11 @@ void wpas_notify_supplicant_deinitialized(struct wpa_global *global) if (global->dbus) wpas_dbus_deinit(global->dbus); #endif /* CONFIG_DBUS */ + +#ifdef CONFIG_BINDER + if (global->binder) + wpas_binder_deinit(global->binder); +#endif /* CONFIG_BINDER */ } @@ -130,6 +142,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) } +void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE); +} + + void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) @@ -649,13 +670,13 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, int network_id, + struct wpa_ssid *ssid, int persistent, int client) { /* Notify a group has been started */ wpas_dbus_register_p2p_group(wpa_s, ssid); - wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id); + wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent); } diff --git a/freebsd/contrib/wpa/wpa_supplicant/notify.h b/freebsd/contrib/wpa/wpa_supplicant/notify.h index d9f0f5a9..8cce0f30 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/notify.h +++ b/freebsd/contrib/wpa/wpa_supplicant/notify.h @@ -23,6 +23,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state); void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s); +void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s); void wpas_notify_network_changed(struct wpa_supplicant *wpa_s); void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s); void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s); @@ -112,7 +113,7 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, u16 config_methods, unsigned int generated_pin); void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, int network_id, + struct wpa_ssid *ssid, int persistent, int client); void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s, const char *reason); diff --git a/freebsd/contrib/wpa/wpa_supplicant/offchannel.c b/freebsd/contrib/wpa/wpa_supplicant/offchannel.c index 54b8772b..a269fdaf 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/offchannel.c +++ b/freebsd/contrib/wpa/wpa_supplicant/offchannel.c @@ -25,8 +25,29 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src) { struct wpa_supplicant *iface; - if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) + if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) { +#ifdef CONFIG_P2P + if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent && + wpa_s->parent->ap_iface && + os_memcmp(wpa_s->parent->own_addr, + wpa_s->own_addr, ETH_ALEN) == 0 && + wpabuf_len(wpa_s->pending_action_tx) >= 2 && + *wpabuf_head_u8(wpa_s->pending_action_tx) != + WLAN_ACTION_PUBLIC) { + /* + * When P2P Device interface has same MAC address as + * the GO interface, make sure non-Public Action frames + * are sent through the GO interface. The P2P Device + * interface can only send Public Action frames. + */ + wpa_printf(MSG_DEBUG, + "P2P: Use GO interface %s instead of interface %s for Action TX", + wpa_s->parent->ifname, wpa_s->ifname); + return wpa_s->parent; + } +#endif /* CONFIG_P2P */ return wpa_s; + } /* * Try to find a group interface that matches with the source address. @@ -120,8 +141,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx) } wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to " - MACSTR " using interface %s", - MAC2STR(wpa_s->pending_action_dst), iface->ifname); + MACSTR " using interface %s (pending_action_tx=%p)", + MAC2STR(wpa_s->pending_action_dst), iface->ifname, + wpa_s->pending_action_tx); res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0, wpa_s->pending_action_dst, wpa_s->pending_action_src, @@ -185,8 +207,12 @@ void offchannel_send_action_tx_status( return; } - wpa_printf(MSG_DEBUG, "Off-channel: Delete matching pending action frame"); - + wpa_printf(MSG_DEBUG, + "Off-channel: Delete matching pending action frame (dst=" + MACSTR " pending_action_tx=%p)", MAC2STR(dst), + wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; @@ -252,8 +278,11 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, if (wpa_s->pending_action_tx) { wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action " - "frame TX to " MACSTR, - MAC2STR(wpa_s->pending_action_dst)); + "frame TX to " MACSTR " (pending_action_tx=%p)", + MAC2STR(wpa_s->pending_action_dst), + wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); } wpa_s->pending_action_tx_done = 0; @@ -270,6 +299,12 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN); wpa_s->pending_action_freq = freq; wpa_s->pending_action_no_cck = no_cck; + wpa_printf(MSG_DEBUG, + "Off-channel: Stored pending action frame (dst=" MACSTR + " pending_action_tx=%p)", + MAC2STR(dst), wpa_s->pending_action_tx); + wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame", + wpa_s->pending_action_tx); if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) { struct wpa_supplicant *iface; @@ -430,6 +465,9 @@ const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s) */ void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s) { + wpa_printf(MSG_DEBUG, + "Off-channel: Clear pending Action frame TX (pending_action_tx=%p", + wpa_s->pending_action_tx); wpabuf_free(wpa_s->pending_action_tx); wpa_s->pending_action_tx = NULL; } diff --git a/freebsd/contrib/wpa/wpa_supplicant/p2p_supplicant.h b/freebsd/contrib/wpa/wpa_supplicant/p2p_supplicant.h index 56e68349..63910d1c 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/p2p_supplicant.h +++ b/freebsd/contrib/wpa/wpa_supplicant/p2p_supplicant.h @@ -34,17 +34,22 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s, const u8 *peer_dev_addr); int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, const char *pin, enum p2p_wps_method wps_method, - int persistent_group, int auto_join, int join, - int auth, int go_intent, int freq, int persistent_id, - int pd, int ht40, int vht); + int persistent_group, int auto_join, int join, int auth, + int go_intent, int freq, unsigned int vht_center_freq2, + int persistent_id, int pd, int ht40, int vht, + unsigned int vht_chwidth, const u8 *group_ssid, + size_t group_ssid_len); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, - int freq, int ht40, int vht); + int freq, int vht_center_freq2, int ht40, int vht, + int max_oper_chwidth); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, - int force_freq, int neg_freq, int ht40, - int vht, const struct p2p_channels *channels, + int force_freq, int neg_freq, + int vht_center_freq2, int ht40, + int vht, int max_oper_chwidth, + const struct p2p_channels *channels, int connection_timeout, int force_scan); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -111,7 +116,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, - int ht40, int vht, int pref_freq); + int vht_center_freq2, int ht40, int vht, + int max_oper_chwidth, int pref_freq); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr); int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, @@ -140,6 +146,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); +int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s, + struct hostapd_hw_modes *mode, u8 channel); unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s); void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *p2p_dev_addr, @@ -199,6 +207,10 @@ int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s); void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s, struct wps_event_fail *fail); int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname); +int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq, + unsigned int period, unsigned int interval, + unsigned int count); +int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/scan.c b/freebsd/contrib/wpa/wpa_supplicant/scan.c index 9f9f4148..4fd269a8 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/scan.c +++ b/freebsd/contrib/wpa/wpa_supplicant/scan.c @@ -38,8 +38,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) if (wpa_s->current_ssid == NULL) { wpa_s->current_ssid = ssid; - if (wpa_s->current_ssid != NULL) - wpas_notify_network_changed(wpa_s); + wpas_notify_network_changed(wpa_s); } wpa_supplicant_initiate_eapol(wpa_s); wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured " @@ -62,10 +61,7 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, wps = 1; *req_type = wpas_wps_get_req_type(ssid); - if (!ssid->eap.phase1) - continue; - - if (os_strstr(ssid->eap.phase1, "pbc=1")) + if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1")) return 2; } @@ -168,6 +164,8 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) if (wpas_update_random_addr_disassoc(wpa_s) < 0) { wpa_msg(wpa_s, MSG_INFO, "Failed to assign random MAC address for a scan"); + wpa_scan_free_params(params); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); radio_work_done(work); return; } @@ -231,12 +229,11 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, } ctx = wpa_scan_clone_params(params); - if (ctx == NULL) - return -1; - - if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) + if (!ctx || + radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) { wpa_scan_free_params(ctx); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); return -1; } @@ -268,14 +265,14 @@ wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx) } -int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - int interval) +static int +wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params) { int ret; wpa_supplicant_notify_scanning(wpa_s, 1); - ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000); + ret = wpa_drv_sched_scan(wpa_s, params); if (ret) wpa_supplicant_notify_scanning(wpa_s, 0); else @@ -285,7 +282,7 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, } -int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) +static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) { int ret; @@ -431,6 +428,39 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *default_ies = NULL; + u8 ext_capab[18]; + int ext_capab_len; + enum wpa_driver_if_type type = WPA_IF_STATION; + +#ifdef CONFIG_P2P + if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) + type = WPA_IF_P2P_CLIENT; +#endif /* CONFIG_P2P */ + + wpa_drv_get_ext_capa(wpa_s, type); + + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, + sizeof(ext_capab)); + if (ext_capab_len > 0 && + wpabuf_resize(&default_ies, ext_capab_len) == 0) + wpabuf_put_data(default_ies, ext_capab, ext_capab_len); + +#ifdef CONFIG_MBO + /* Send cellular capabilities for potential MBO STAs */ + if (wpabuf_resize(&default_ies, 9) == 0) + wpas_mbo_scan_ie(wpa_s, default_ies); +#endif /* CONFIG_MBO */ + + if (default_ies) + wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies), + wpabuf_len(default_ies)); + wpabuf_free(default_ies); +} + + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; @@ -441,6 +471,13 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); + else +#endif /* CONFIG_P2P */ + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, sizeof(ext_capab)); if (ext_capab_len > 0 && @@ -493,6 +530,19 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) wpabuf_put_buf(extra_ie, wpa_s->fst_ies); #endif /* CONFIG_FST */ +#ifdef CONFIG_MBO + /* Send cellular capabilities for potential MBO STAs */ + if (wpabuf_resize(&extra_ie, 9) == 0) + wpas_mbo_scan_ie(wpa_s, extra_ie); +#endif /* CONFIG_MBO */ + + if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) { + struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]; + + if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0) + wpabuf_put_buf(extra_ie, buf); + } + return extra_ie; } @@ -524,21 +574,6 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) #endif /* CONFIG_P2P */ -static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, - enum hostapd_hw_mode mode) -{ - u16 i; - - for (i = 0; i < num_modes; i++) { - if (modes[i].mode == mode) - return &modes[i]; - } - - return NULL; -} - - static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode band, struct wpa_driver_scan_params *params) @@ -588,6 +623,12 @@ static void wpa_set_scan_ssids(struct wpa_supplicant *wpa_s, unsigned int i; struct wpa_ssid *ssid; + /* + * For devices with max_ssids greater than 1, leave the last slot empty + * for adding the wildcard scan entry. + */ + max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids; + for (i = 0; i < wpa_s->scan_id_count; i++) { unsigned int j; @@ -842,12 +883,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) * slot for the zero-terminator. */ params.freqs = os_malloc(sizeof(int) * 2); - if (params.freqs == NULL) { - wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed"); - return; + if (params.freqs) { + params.freqs[0] = wpa_s->assoc_freq; + params.freqs[1] = 0; } - params.freqs[0] = wpa_s->assoc_freq; - params.freqs[1] = 0; /* * Reset the reattach flag so that we fall back to full scan if @@ -1018,6 +1057,27 @@ ssid_list_set: } } + if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) { + struct wpa_bss *bss; + + params.bssid = wpa_s->next_scan_bssid; + bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); + if (bss && bss->ssid_len && params.num_ssids == 1 && + params.ssids[0].ssid_len == 0) { + params.ssids[0].ssid = bss->ssid; + params.ssids[0].ssid_len = bss->ssid_len; + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR + " and SSID %s", + MAC2STR(params.bssid), + wpa_ssid_txt(bss->ssid, bss->ssid_len)); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, + "Scan a previously specified BSSID " MACSTR, + MAC2STR(params.bssid)); + } + } + scan_params = ¶ms; scan: @@ -1078,6 +1138,8 @@ scan: #ifdef CONFIG_INTERWORKING wpa_s->interworking_fast_assoc_tried = 0; #endif /* CONFIG_INTERWORKING */ + if (params.bssid) + os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } } @@ -1184,6 +1246,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) unsigned int max_sched_scan_ssids; int wildcard = 0; int need_ssids; + struct sched_scan_plan scan_plan; if (!wpa_s->sched_scan_supported) return -1; @@ -1195,6 +1258,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload) return -1; + wpa_s->sched_scan_stop_req = 0; + if (wpa_s->sched_scanning) { wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning"); return 0; @@ -1273,11 +1338,6 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) if (!ssid || !wpa_s->prev_sched_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); - if (wpa_s->conf->sched_scan_interval) - wpa_s->sched_scan_interval = - wpa_s->conf->sched_scan_interval; - if (wpa_s->sched_scan_interval == 0) - wpa_s->sched_scan_interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; wpa_s->first_sched_scan = 1; ssid = wpa_s->conf->ssid; @@ -1362,14 +1422,51 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s) scan_params = ¶ms; scan: - if (ssid || !wpa_s->first_sched_scan) { + wpa_s->sched_scan_timed_out = 0; + + /* + * We cannot support multiple scan plans if the scan request includes + * too many SSID's, so in this case use only the last scan plan and make + * it run infinitely. It will be stopped by the timeout. + */ + if (wpa_s->sched_scan_plans_num == 1 || + (wpa_s->sched_scan_plans_num && !ssid && wpa_s->first_sched_scan)) { + params.sched_scan_plans = wpa_s->sched_scan_plans; + params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; + } else if (wpa_s->sched_scan_plans_num > 1) { wpa_dbg(wpa_s, MSG_DEBUG, - "Starting sched scan: interval %d timeout %d", - wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout); + "Too many SSIDs. Default to using single scheduled_scan plan"); + params.sched_scan_plans = + &wpa_s->sched_scan_plans[wpa_s->sched_scan_plans_num - + 1]; + params.sched_scan_plans_num = 1; } else { + if (wpa_s->conf->sched_scan_interval) + scan_plan.interval = wpa_s->conf->sched_scan_interval; + else + scan_plan.interval = 10; + + if (scan_plan.interval > wpa_s->max_sched_scan_plan_interval) { + wpa_printf(MSG_WARNING, + "Scan interval too long(%u), use the maximum allowed(%u)", + scan_plan.interval, + wpa_s->max_sched_scan_plan_interval); + scan_plan.interval = + wpa_s->max_sched_scan_plan_interval; + } + + scan_plan.iterations = 0; + params.sched_scan_plans = &scan_plan; + params.sched_scan_plans_num = 1; + } + + if (ssid || !wpa_s->first_sched_scan) { wpa_dbg(wpa_s, MSG_DEBUG, - "Starting sched scan: interval %d (no timeout)", - wpa_s->sched_scan_interval); + "Starting sched scan: interval %u timeout %d", + params.sched_scan_plans[0].interval, + wpa_s->sched_scan_timeout); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Starting sched scan (no timeout)"); } wpa_setband_scan_freqs(wpa_s, scan_params); @@ -1383,8 +1480,7 @@ scan: } } - ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params, - wpa_s->sched_scan_interval); + ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params); wpabuf_free(extra_ie); os_free(params.filter_ssids); if (ret) { @@ -1402,9 +1498,12 @@ scan: wpa_s, NULL); wpa_s->first_sched_scan = 0; wpa_s->sched_scan_timeout /= 2; - wpa_s->sched_scan_interval *= 2; - if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) { - wpa_s->sched_scan_interval = 10; + params.sched_scan_plans[0].interval *= 2; + if ((unsigned int) wpa_s->sched_scan_timeout < + params.sched_scan_plans[0].interval || + params.sched_scan_plans[0].interval > + wpa_s->max_sched_scan_plan_interval) { + params.sched_scan_plans[0].interval = 10; wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2; } } @@ -1459,6 +1558,9 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) if (!wpa_s->sched_scanning) return; + if (wpa_s->sched_scanning) + wpa_s->sched_scan_stop_req = 1; + wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan"); eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL); wpa_supplicant_stop_sched_scan(wpa_s); @@ -1518,20 +1620,7 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) */ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) { - const u8 *end, *pos; - - pos = (const u8 *) (res + 1); - end = pos + res->ie_len; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; + return get_ie((const u8 *) (res + 1), res->ie_len, ie); } @@ -1552,8 +1641,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, pos = (const u8 *) (res + 1); end = pos + res->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1589,8 +1678,8 @@ const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, pos += res->ie_len; end = pos + res->beacon_ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1625,8 +1714,8 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, pos = (const u8 *) (res + 1); end = pos + res->ie_len; - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) + while (end - pos > 1) { + if (2 + pos[1] > end - pos) break; if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && vendor_type == WPA_GET_BE32(&pos[2])) @@ -1834,8 +1923,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, } -static void filter_scan_res(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *res) +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res) { size_t i, j; @@ -1862,13 +1951,13 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s, /* * Noise floor values to use when we have signal strength - * measurements, but no noise floor measurments. These values were + * measurements, but no noise floor measurements. These values were * measured in an office environment with many APs. */ #define DEFAULT_NOISE_FLOOR_2GHZ (-89) #define DEFAULT_NOISE_FLOOR_5GHZ (-92) -static void scan_snr(struct wpa_scan_res *res) +void scan_snr(struct wpa_scan_res *res) { if (res->flags & WPA_SCAN_NOISE_INVALID) { res->noise = IS_5GHZ(res->freq) ? @@ -1952,8 +2041,8 @@ static unsigned int max_vht80_rate(int snr) } -static void scan_est_throughput(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *res) +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) { enum local_hw_capab capab = wpa_s->hw_capab; int rate; /* max legacy rate in 500 kb/s units */ @@ -2150,6 +2239,9 @@ void scan_only_handler(struct wpa_supplicant *wpa_s, wpa_s->scan_work = NULL; radio_work_done(work); } + + if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); } @@ -2216,6 +2308,19 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->only_new_results = src->only_new_results; params->low_priority = src->low_priority; + if (src->sched_scan_plans_num > 0) { + params->sched_scan_plans = + os_malloc(sizeof(*src->sched_scan_plans) * + src->sched_scan_plans_num); + if (!params->sched_scan_plans) + goto failed; + + os_memcpy(params->sched_scan_plans, src->sched_scan_plans, + sizeof(*src->sched_scan_plans) * + src->sched_scan_plans_num); + params->sched_scan_plans_num = src->sched_scan_plans_num; + } + if (src->mac_addr_rand) { params->mac_addr_rand = src->mac_addr_rand; @@ -2233,6 +2338,17 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->mac_addr_mask = mac_addr + ETH_ALEN; } } + + if (src->bssid) { + u8 *bssid; + + bssid = os_malloc(ETH_ALEN); + if (!bssid) + goto failed; + os_memcpy(bssid, src->bssid, ETH_ALEN); + params->bssid = bssid; + } + return params; failed: @@ -2253,6 +2369,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) os_free((u8 *) params->extra_ies); os_free(params->freqs); os_free(params->filter_ssids); + os_free(params->sched_scan_plans); /* * Note: params->mac_addr_mask points to same memory allocation and @@ -2260,20 +2377,31 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) */ os_free((u8 *) params->mac_addr); + os_free((u8 *) params->bssid); + os_free(params); } int wpas_start_pno(struct wpa_supplicant *wpa_s) { - int ret, interval, prio; + int ret, prio; size_t i, num_ssid, num_match_ssid; struct wpa_ssid *ssid; struct wpa_driver_scan_params params; + struct sched_scan_plan scan_plan; + unsigned int max_sched_scan_ssids; if (!wpa_s->sched_scan_supported) return -1; + if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS) + max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS; + else + max_sched_scan_ssids = wpa_s->max_sched_scan_ssids; + if (max_sched_scan_ssids < 1) + return -1; + if (wpa_s->pno || wpa_s->pno_sched_pending) return 0; @@ -2294,6 +2422,13 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) } } + if (wpa_s->sched_scan_stop_req) { + wpa_printf(MSG_DEBUG, + "Schedule PNO after previous sched scan has stopped"); + wpa_s->pno_sched_pending = 1; + return 0; + } + os_memset(¶ms, 0, sizeof(params)); num_ssid = num_match_ssid = 0; @@ -2317,10 +2452,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) num_ssid++; } - if (num_ssid > WPAS_MAX_SCAN_SSIDS) { + if (num_ssid > max_sched_scan_ssids) { wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from " - "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid); - num_ssid = WPAS_MAX_SCAN_SSIDS; + "%u", max_sched_scan_ssids, (unsigned int) num_ssid); + num_ssid = max_sched_scan_ssids; } if (num_match_ssid > wpa_s->max_match_sets) { @@ -2363,8 +2498,20 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) if (wpa_s->conf->filter_rssi) params.filter_rssi = wpa_s->conf->filter_rssi; - interval = wpa_s->conf->sched_scan_interval ? - wpa_s->conf->sched_scan_interval : 10; + if (wpa_s->sched_scan_plans_num) { + params.sched_scan_plans = wpa_s->sched_scan_plans; + params.sched_scan_plans_num = wpa_s->sched_scan_plans_num; + } else { + /* Set one scan plan that will run infinitely */ + if (wpa_s->conf->sched_scan_interval) + scan_plan.interval = wpa_s->conf->sched_scan_interval; + else + scan_plan.interval = 10; + + scan_plan.iterations = 0; + params.sched_scan_plans = &scan_plan; + params.sched_scan_plans_num = 1; + } if (params.freqs == NULL && wpa_s->manual_sched_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Limit sched scan to specified channels"); @@ -2379,7 +2526,7 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) } } - ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, interval); + ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms); os_free(params.filter_ssids); if (ret == 0) wpa_s->pno = 1; @@ -2397,6 +2544,7 @@ int wpas_stop_pno(struct wpa_supplicant *wpa_s) return 0; ret = wpa_supplicant_stop_sched_scan(wpa_s); + wpa_s->sched_scan_stop_req = 1; wpa_s->pno = 0; wpa_s->pno_sched_pending = 0; @@ -2464,3 +2612,160 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, wpa_s->mac_addr_rand_enable |= type; return 0; } + + +int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s) +{ + int scan_work = !!wpa_s->scan_work; + +#ifdef CONFIG_P2P + scan_work |= !!wpa_s->p2p_scan_work; +#endif /* CONFIG_P2P */ + + if (scan_work && wpa_s->own_scan_running) { + wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan"); + return wpa_drv_abort_scan(wpa_s); + } + + return 0; +} + + +int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd) +{ + struct sched_scan_plan *scan_plans = NULL; + const char *token, *context = NULL; + unsigned int num = 0; + + if (!cmd) + return -1; + + if (!cmd[0]) { + wpa_printf(MSG_DEBUG, "Clear sched scan plans"); + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = NULL; + wpa_s->sched_scan_plans_num = 0; + return 0; + } + + while ((token = cstr_token(cmd, " ", &context))) { + int ret; + struct sched_scan_plan *scan_plan, *n; + + n = os_realloc_array(scan_plans, num + 1, sizeof(*scan_plans)); + if (!n) + goto fail; + + scan_plans = n; + scan_plan = &scan_plans[num]; + num++; + + ret = sscanf(token, "%u:%u", &scan_plan->interval, + &scan_plan->iterations); + if (ret <= 0 || ret > 2 || !scan_plan->interval) { + wpa_printf(MSG_ERROR, + "Invalid sched scan plan input: %s", token); + goto fail; + } + + if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) { + wpa_printf(MSG_WARNING, + "scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)", + num, scan_plan->interval, + wpa_s->max_sched_scan_plan_interval); + scan_plan->interval = + wpa_s->max_sched_scan_plan_interval; + } + + if (ret == 1) { + scan_plan->iterations = 0; + break; + } + + if (!scan_plan->iterations) { + wpa_printf(MSG_ERROR, + "scan plan %u: Number of iterations cannot be zero", + num); + goto fail; + } + + if (scan_plan->iterations > + wpa_s->max_sched_scan_plan_iterations) { + wpa_printf(MSG_WARNING, + "scan plan %u: Too many iterations(%u), use the maximum allowed(%u)", + num, scan_plan->iterations, + wpa_s->max_sched_scan_plan_iterations); + scan_plan->iterations = + wpa_s->max_sched_scan_plan_iterations; + } + + wpa_printf(MSG_DEBUG, + "scan plan %u: interval=%u iterations=%u", + num, scan_plan->interval, scan_plan->iterations); + } + + if (!scan_plans) { + wpa_printf(MSG_ERROR, "Invalid scan plans entry"); + goto fail; + } + + if (cstr_token(cmd, " ", &context) || scan_plans[num - 1].iterations) { + wpa_printf(MSG_ERROR, + "All scan plans but the last must specify a number of iterations"); + goto fail; + } + + wpa_printf(MSG_DEBUG, "scan plan %u (last plan): interval=%u", + num, scan_plans[num - 1].interval); + + if (num > wpa_s->max_sched_scan_plans) { + wpa_printf(MSG_WARNING, + "Too many scheduled scan plans (only %u supported)", + wpa_s->max_sched_scan_plans); + wpa_printf(MSG_WARNING, + "Use only the first %u scan plans, and the last one (in infinite loop)", + wpa_s->max_sched_scan_plans - 1); + os_memcpy(&scan_plans[wpa_s->max_sched_scan_plans - 1], + &scan_plans[num - 1], sizeof(*scan_plans)); + num = wpa_s->max_sched_scan_plans; + } + + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = scan_plans; + wpa_s->sched_scan_plans_num = num; + + return 0; + +fail: + os_free(scan_plans); + wpa_printf(MSG_ERROR, "invalid scan plans list"); + return -1; +} + + +/** + * wpas_scan_reset_sched_scan - Reset sched_scan state + * @wpa_s: Pointer to wpa_supplicant data + * + * This function is used to cancel a running scheduled scan and to reset an + * internal scan state to continue with a regular scan on the following + * wpa_supplicant_req_scan() calls. + */ +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s) +{ + wpa_s->normal_scans = 0; + if (wpa_s->sched_scanning) { + wpa_s->sched_scan_timed_out = 0; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); + } +} + + +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s) +{ + /* simulate timeout to restart the sched scan */ + wpa_s->sched_scan_timed_out = 1; + wpa_s->prev_sched_ssid = NULL; + wpa_supplicant_cancel_sched_scan(wpa_s); +} diff --git a/freebsd/contrib/wpa/wpa_supplicant/scan.h b/freebsd/contrib/wpa/wpa_supplicant/scan.h index 7650f5a2..2aa0a8be 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/scan.h +++ b/freebsd/contrib/wpa/wpa_supplicant/scan.h @@ -39,20 +39,25 @@ void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec); void scan_only_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); int wpas_scan_scheduled(struct wpa_supplicant *wpa_s); -int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params, - int interval); -int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s); struct wpa_driver_scan_params * wpa_scan_clone_params(const struct wpa_driver_scan_params *src); void wpa_scan_free_params(struct wpa_driver_scan_params *params); int wpas_start_pno(struct wpa_supplicant *wpa_s); int wpas_stop_pno(struct wpa_supplicant *wpa_s); +void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s); +void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s); void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s, unsigned int type); int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, unsigned int type, const u8 *addr, const u8 *mask); +int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s); +void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res); +void scan_snr(struct wpa_scan_res *res); +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res); +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); #endif /* SCAN_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/wmm_ac.h b/freebsd/contrib/wpa/wpa_supplicant/wmm_ac.h index 5171b168..0d15ad01 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wmm_ac.h +++ b/freebsd/contrib/wpa/wpa_supplicant/wmm_ac.h @@ -88,7 +88,7 @@ enum ts_dir_idx { */ struct wmm_ac_addts_request { /* - * dialog token - Used to link the recived ADDTS response with this + * dialog token - Used to link the received ADDTS response with this * saved ADDTS request when ADDTS response is being handled */ u8 dialog_token; diff --git a/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.h b/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.h index 8de43480..81d81535 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.h +++ b/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.h @@ -56,7 +56,7 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len); int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, - u8 query_reason); + u8 query_reason, int cand_list); void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); diff --git a/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant.c index d65398e2..7346ae0b 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant.c +++ b/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant.c @@ -2,7 +2,7 @@ /* * WPA Supplicant - * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -13,6 +13,10 @@ */ #include "includes.h" +#ifdef CONFIG_MATCH_IFACE +#include <net/if.h> +#include <fnmatch.h> +#endif /* CONFIG_MATCH_IFACE */ #include "common.h" #include "crypto/random.h" @@ -60,7 +64,7 @@ const char *const wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors"; const char *const wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -190,7 +194,9 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; const u8 *bssid = wpa_s->bssid; - if (is_zero_ether_addr(bssid)) + if (!is_zero_ether_addr(wpa_s->pending_bssid) && + (wpa_s->wpa_state == WPA_AUTHENTICATING || + wpa_s->wpa_state == WPA_ASSOCIATING)) bssid = wpa_s->pending_bssid; wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.", MAC2STR(bssid)); @@ -399,6 +405,18 @@ void free_hw_features(struct wpa_supplicant *wpa_s) } +static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) +{ + struct wpa_bss_tmp_disallowed *bss, *prev; + + dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + dl_list_del(&bss->list); + os_free(bss); + } +} + + static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { int i; @@ -538,6 +556,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->last_scan_res = NULL; #ifdef CONFIG_HS20 + if (wpa_s->drv_priv) + wpa_drv_configure_frame_filters(wpa_s, 0); hs20_deinit(wpa_s); #endif /* CONFIG_HS20 */ @@ -547,6 +567,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) } wmm_ac_notify_disassoc(wpa_s); + + wpa_s->sched_scan_plans_num = 0; + os_free(wpa_s->sched_scan_plans); + wpa_s->sched_scan_plans = NULL; + +#ifdef CONFIG_MBO + wpa_s->non_pref_chan_num = 0; + os_free(wpa_s->non_pref_chan); + wpa_s->non_pref_chan = NULL; +#endif /* CONFIG_MBO */ + + free_bss_tmp_disallowed(wpa_s); + + wpabuf_free(wpa_s->lci); + wpa_s->lci = NULL; } @@ -965,6 +1000,11 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx) wpa_supplicant_terminate_proc(global); } } + + if (wpa_debug_reopen_file() < 0) { + /* Ignore errors since we cannot really do much to fix this */ + wpa_printf(MSG_DEBUG, "Could not reopen debug log file"); + } } @@ -1152,6 +1192,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, return -1; } +#ifdef CONFIG_NO_WPA + wpa_s->group_cipher = WPA_CIPHER_NONE; + wpa_s->pairwise_cipher = WPA_CIPHER_NONE; +#else /* CONFIG_NO_WPA */ sel = ie.group_cipher & ssid->group_cipher; wpa_s->group_cipher = wpa_pick_group_cipher(sel); if (wpa_s->group_cipher < 0) { @@ -1171,6 +1215,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s", wpa_cipher_txt(wpa_s->pairwise_cipher)); +#endif /* CONFIG_NO_WPA */ sel = ie.key_mgmt & ssid->key_mgmt; #ifdef CONFIG_SAE @@ -1281,7 +1326,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, int psk_set = 0; if (ssid->psk_set) { - wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, + NULL); psk_set = 1; } #ifndef CONFIG_NO_PBKDF2 @@ -1292,7 +1338,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, 4096, psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } @@ -1330,7 +1376,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " "external passphrase)", psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, + NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else @@ -1343,7 +1390,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, ext_password_free(pw); return -1; } - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, + NULL); psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else { @@ -1406,9 +1454,20 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) if (wpa_s->conf->hs20) *pos |= 0x40; /* Bit 46 - WNM-Notification */ #endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + *pos |= 0x40; /* Bit 46 - WNM-Notification */ +#endif /* CONFIG_MBO */ break; case 6: /* Bits 48-55 */ break; + case 7: /* Bits 56-63 */ + break; + case 8: /* Bits 64-71 */ + if (wpa_s->conf->ftm_responder) + *pos |= 0x40; /* Bit 70 - FTM responder */ + if (wpa_s->conf->ftm_initiator) + *pos |= 0x80; /* Bit 71 - FTM initiator */ + break; } } @@ -1418,6 +1477,9 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) u8 *pos = buf; u8 len = 6, i; + if (len < 9 && + (wpa_s->conf->ftm_initiator || wpa_s->conf->ftm_responder)) + len = 9; if (len < wpa_s->extended_capa_len) len = wpa_s->extended_capa_len; if (buflen < (size_t) len + 2) { @@ -1588,6 +1650,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_connect_work *cwork; int rand_style; + wpa_s->own_disconnect_req = 0; + + /* + * If we are starting a new connection, any previously pending EAPOL + * RX cannot be valid anymore. + */ + wpabuf_free(wpa_s->pending_eapol_rx); + wpa_s->pending_eapol_rx = NULL; + if (ssid->mac_addr == -1) rand_style = wpa_s->conf->mac_addr; else @@ -1595,9 +1666,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wmm_ac_clear_saved_tspecs(wpa_s); wpa_s->reassoc_same_bss = 0; + wpa_s->reassoc_same_ess = 0; if (wpa_s->last_ssid == ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS"); + wpa_s->reassoc_same_ess = 1; if (wpa_s->current_bss && wpa_s->current_bss == bss) { wmm_ac_save_tspecs(wpa_s); wpa_s->reassoc_same_bss = 1; @@ -1663,10 +1736,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } wpa_s->current_bss = bss; - wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED - "ssid=\"%s\" id=%d", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len), - ssid->id); + wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d", + wpa_ssid_txt(ssid->ssid, ssid->ssid_len), + ssid->id); #else /* CONFIG_MESH */ wpa_msg(wpa_s, MSG_ERROR, "mesh mode support not included in the build"); @@ -1696,6 +1768,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, return; } + wpas_abort_ongoing_scan(wpa_s); + cwork = os_zalloc(sizeof(*cwork)); if (cwork == NULL) return; @@ -1717,6 +1791,36 @@ static int bss_is_ibss(struct wpa_bss *bss) } +static int drv_supports_vht(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid) +{ + enum hostapd_hw_mode hw_mode; + struct hostapd_hw_modes *mode = NULL; + u8 channel; + int i; + +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht) + return 0; +#endif /* CONFIG_HT_OVERRIDES */ + + hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel); + if (hw_mode == NUM_HOSTAPD_MODES) + return 0; + for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].mode == hw_mode) { + mode = &wpa_s->hw.modes[i]; + break; + } + } + + if (!mode) + return 0; + + return mode->vht_capab != 0; +} + + void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, struct hostapd_freq_params *freq) @@ -1729,8 +1833,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; u8 channel; int i, chan_idx, ht40 = -1, res, obss_scan = 1; - unsigned int j; + unsigned int j, k; struct hostapd_freq_params vht_freq; + int chwidth, seg0, seg1; + u32 vht_caps = 0; freq->freq = ssid->frequency; @@ -1782,6 +1888,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (!mode) return; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht) { + freq->ht_enabled = 0; + return; + } +#endif /* CONFIG_HT_OVERRIDES */ + freq->ht_enabled = ht_supported(mode); if (!freq->ht_enabled) return; @@ -1803,6 +1916,11 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) return; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht40) + return; +#endif /* CONFIG_HT_OVERRIDES */ + /* Check/setup HT40+/HT40- */ for (j = 0; j < ARRAY_SIZE(ht40plus); j++) { if (ht40plus[j] == channel) { @@ -1827,22 +1945,16 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, freq->channel = pri_chan->chan; - switch (ht40) { - case -1: + if (ht40 == -1) { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS)) return; - freq->sec_channel_offset = -1; - break; - case 1: + } else { if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS)) return; - freq->sec_channel_offset = 1; - break; - default: - break; } + freq->sec_channel_offset = ht40; - if (freq->sec_channel_offset && obss_scan) { + if (obss_scan) { struct wpa_scan_results *scan_res; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); @@ -1880,12 +1992,12 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, "IBSS/mesh: setup freq channel %d, sec_channel_offset %d", freq->channel, freq->sec_channel_offset); - /* Not sure if mesh is ready for VHT */ - if (ssid->mode != WPAS_MODE_IBSS) + if (!drv_supports_vht(wpa_s, ssid)) return; /* For IBSS check VHT_IBSS flag */ - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) + if (ssid->mode == WPAS_MODE_IBSS && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) return; vht_freq = *freq; @@ -1916,12 +2028,55 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, return; } + chwidth = VHT_CHANWIDTH_80MHZ; + seg0 = vht80[j] + 6; + seg1 = 0; + + if (ssid->max_oper_chwidth == VHT_CHANWIDTH_80P80MHZ) { + /* setup center_freq2, bandwidth */ + for (k = 0; k < ARRAY_SIZE(vht80); k++) { + /* Only accept 80 MHz segments separated by a gap */ + if (j == k || abs(vht80[j] - vht80[k]) == 16) + continue; + for (i = vht80[k]; i < vht80[k] + 16; i += 4) { + struct hostapd_channel_data *chan; + + chan = hw_get_channel_chan(mode, i, NULL); + if (!chan) + continue; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + /* Found a suitable second segment for 80+80 */ + chwidth = VHT_CHANWIDTH_80P80MHZ; + vht_caps |= + VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + seg1 = vht80[k] + 6; + } + + if (chwidth == VHT_CHANWIDTH_80P80MHZ) + break; + } + } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) { + if (freq->freq == 5180) { + chwidth = VHT_CHANWIDTH_160MHZ; + vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + seg0 = 50; + } else if (freq->freq == 5520) { + chwidth = VHT_CHANWIDTH_160MHZ; + vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + seg0 = 114; + } + } + if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, freq->channel, freq->ht_enabled, vht_freq.vht_enabled, freq->sec_channel_offset, - VHT_CHANWIDTH_80MHZ, - vht80[j] + 6, 0, 0) != 0) + chwidth, seg0, seg1, vht_caps) != 0) return; *freq = vht_freq; @@ -1946,6 +2101,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) int wep_keys_set = 0; int assoc_failed = 0; struct wpa_ssid *old_ssid; + u8 prev_bssid[ETH_ALEN]; #ifdef CONFIG_HT_OVERRIDES struct ieee80211_ht_capabilities htcaps; struct ieee80211_ht_capabilities htcaps_mask; @@ -1954,6 +2110,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) struct ieee80211_vht_capabilities vhtcaps; struct ieee80211_vht_capabilities vhtcaps_mask; #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_MBO + const u8 *mbo = NULL; +#endif /* CONFIG_MBO */ if (deinit) { if (work->started) { @@ -1976,6 +2135,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) return; } + os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN); os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; wpa_s->eap_expected_failure = 0; @@ -2017,7 +2177,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } else { wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + if (bss) + os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); + else + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); } if (!wpa_s->pno) wpa_supplicant_cancel_sched_scan(wpa_s); @@ -2138,25 +2301,21 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info)); #endif /* CONFIG_P2P */ -#ifdef CONFIG_HS20 - if (is_hs20_network(wpa_s, ssid, bss)) { - struct wpabuf *hs20; - hs20 = wpabuf_alloc(20); - if (hs20) { - int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid); - size_t len; - - wpas_hs20_add_indication(hs20, pps_mo_id); - len = sizeof(wpa_ie) - wpa_ie_len; - if (wpabuf_len(hs20) <= len) { - os_memcpy(wpa_ie + wpa_ie_len, - wpabuf_head(hs20), wpabuf_len(hs20)); - wpa_ie_len += wpabuf_len(hs20); - } - wpabuf_free(hs20); +#ifdef CONFIG_MBO + if (bss) { + mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (mbo) { + int len; + + len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq, + wpa_ie + wpa_ie_len, + sizeof(wpa_ie) - + wpa_ie_len); + if (len > 0) + wpa_ie_len += len; } } -#endif /* CONFIG_HS20 */ +#endif /* CONFIG_MBO */ /* * Workaround: Add Extended Capabilities element only if the AP @@ -2166,6 +2325,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) * element in all cases, it is justifiable to skip it to avoid * interoperability issues. */ + if (ssid->p2p_group) + wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); + else + wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); + if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) { u8 ext_capab[18]; int ext_capab_len; @@ -2182,6 +2346,29 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } } +#ifdef CONFIG_HS20 + if (is_hs20_network(wpa_s, ssid, bss)) { + struct wpabuf *hs20; + + hs20 = wpabuf_alloc(20); + if (hs20) { + int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid); + size_t len; + + wpas_hs20_add_indication(hs20, pps_mo_id); + len = sizeof(wpa_ie) - wpa_ie_len; + if (wpabuf_len(hs20) <= len) { + os_memcpy(wpa_ie + wpa_ie_len, + wpabuf_head(hs20), wpabuf_len(hs20)); + wpa_ie_len += wpabuf_len(hs20); + } + wpabuf_free(hs20); + + hs20_configure_frame_filters(wpa_s); + } + } +#endif /* CONFIG_HS20 */ + if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) { struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]; size_t len; @@ -2206,6 +2393,17 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif /* CONFIG_FST */ +#ifdef CONFIG_MBO + if (mbo) { + int len; + + len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len, + sizeof(wpa_ie) - wpa_ie_len); + if (len >= 0) + wpa_ie_len += len; + } +#endif /* CONFIG_MBO */ + wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); use_crypt = 1; cipher_pairwise = wpa_s->pairwise_cipher; @@ -2258,9 +2456,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } params.bssid_hint = bss->bssid; params.freq_hint = bss->freq; + params.pbss = bss_is_pbss(bss); } else { params.ssid = ssid->ssid; params.ssid_len = ssid->ssid_len; + params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0; } if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set && @@ -2344,8 +2544,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.p2p = ssid->p2p_group; - if (wpa_s->parent->set_sta_uapsd) - params.uapsd = wpa_s->parent->sta_uapsd; + if (wpa_s->p2pdev->set_sta_uapsd) + params.uapsd = wpa_s->p2pdev->sta_uapsd; else params.uapsd = -1; @@ -2386,6 +2586,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif /* CONFIG_P2P */ + if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) && + wpa_s->current_ssid) + params.prev_bssid = prev_bssid; + ret = wpa_drv_associate(wpa_s, ¶ms); if (ret < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " @@ -2453,8 +2657,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; - if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) + + if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) { wpa_s->current_bss = bss; +#ifdef CONFIG_HS20 + hs20_configure_frame_filters(wpa_s); +#endif /* CONFIG_HS20 */ + } + wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) @@ -2499,12 +2709,12 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state)); - if (!is_zero_ether_addr(wpa_s->bssid)) - addr = wpa_s->bssid; - else if (!is_zero_ether_addr(wpa_s->pending_bssid) && - (wpa_s->wpa_state == WPA_AUTHENTICATING || - wpa_s->wpa_state == WPA_ASSOCIATING)) + if (!is_zero_ether_addr(wpa_s->pending_bssid) && + (wpa_s->wpa_state == WPA_AUTHENTICATING || + wpa_s->wpa_state == WPA_ASSOCIATING)) addr = wpa_s->pending_bssid; + else if (!is_zero_ether_addr(wpa_s->bssid)) + addr = wpa_s->bssid; else if (wpa_s->wpa_state == WPA_ASSOCIATING) { /* * When using driver-based BSS selection, we may not know the @@ -2522,8 +2732,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MESH if (wpa_s->ifmsh) { - wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", - wpa_s->ifname); + wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s", + wpa_s->ifname); wpa_supplicant_leave_mesh(wpa_s); } #endif /* CONFIG_MESH */ @@ -2561,6 +2771,95 @@ static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, /** + * wpa_supplicant_add_network - Add a new network + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: The new network configuration or %NULL if operation failed + * + * This function performs the following operations: + * 1. Adds a new network. + * 2. Send network addition notification. + * 3. Marks the network disabled. + * 4. Set network default parameters. + */ +struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s) +{ + struct wpa_ssid *ssid; + + ssid = wpa_config_add_network(wpa_s->conf); + if (!ssid) + return NULL; + wpas_notify_network_added(wpa_s, ssid); + ssid->disabled = 1; + wpa_config_set_network_defaults(ssid); + + return ssid; +} + + +/** + * wpa_supplicant_remove_network - Remove a configured network based on id + * @wpa_s: wpa_supplicant structure for a network interface + * @id: Unique network id to search for + * Returns: 0 on success, or -1 if the network was not found, -2 if the network + * could not be removed + * + * This function performs the following operations: + * 1. Removes the network. + * 2. Send network removal notification. + * 3. Update internal state machines. + * 4. Stop any running sched scans. + */ +int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) +{ + struct wpa_ssid *ssid; + int was_disabled; + + ssid = wpa_config_get_network(wpa_s->conf, id); + if (!ssid) + return -1; + wpas_notify_network_removed(wpa_s, ssid); + + if (wpa_s->last_ssid == ssid) + wpa_s->last_ssid = NULL; + + if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) { +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + /* + * Invalidate the EAP session cache if the current or + * previously used network is removed. + */ + eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if (ssid == wpa_s->current_ssid) { + wpa_sm_set_config(wpa_s->wpa, NULL); + eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); + + if (wpa_s->wpa_state >= WPA_AUTHENTICATING) + wpa_s->own_disconnect_req = 1; + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } + + was_disabled = ssid->disabled; + + if (wpa_config_remove_network(wpa_s->conf, id) < 0) + return -2; + + if (!was_disabled && wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, + "Stop ongoing sched_scan to remove network from filters"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } + + return 0; +} + + +/** * wpa_supplicant_enable_network - Mark a configured network as enabled * @wpa_s: wpa_supplicant structure for a network interface * @ssid: wpa_ssid structure for a configured network or %NULL @@ -2690,7 +2989,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpas_notify_network_enabled_changed(wpa_s, other_ssid); } - if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) { + if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid && + wpa_s->wpa_state >= WPA_AUTHENTICATING) { /* We are already associated with the selected network */ wpa_printf(MSG_DEBUG, "Already associated with the " "selected network - do nothing"); @@ -2719,6 +3019,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, if (wpa_s->connect_without_scan || wpa_supplicant_fast_associate(wpa_s) != 1) { wpa_s->scan_req = NORMAL_SCAN_REQ; + wpas_scan_reset_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0); } @@ -2996,7 +3297,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i) struct wpa_global *global = wpa_s->global; if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) { - global->drv_priv[i] = wpa_drivers[i]->global_init(); + global->drv_priv[i] = wpa_drivers[i]->global_init(global); if (global->drv_priv[i] == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize driver " "'%s'", wpa_drivers[i]->name); @@ -3079,6 +3380,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ignore_auth_resp) { + wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!"); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + #ifdef CONFIG_PEERKEY if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid && wpa_s->current_ssid->peerkey && @@ -3363,8 +3671,11 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->scan_interval = 5; wpa_s->new_connection = 1; wpa_s->parent = parent ? parent : wpa_s; + wpa_s->p2pdev = wpa_s->parent; wpa_s->sched_scanning = 0; + dl_list_init(&wpa_s->bss_tmp_disallowed); + return wpa_s; } @@ -3616,8 +3927,8 @@ void wpa_supplicant_apply_vht_overrides( if (!vhtcaps || !vhtcaps_mask) return; - vhtcaps->vht_capabilities_info = ssid->vht_capa; - vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask; + vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa); + vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask); #ifdef CONFIG_HT_OVERRIDES /* if max ampdu is <= 3, we have to make the HT cap the same */ @@ -3639,15 +3950,17 @@ void wpa_supplicant_apply_vht_overrides( #define OVERRIDE_MCS(i) \ if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.tx_map |= \ - 3 << 2 * (i - 1); \ + host_to_le16(3 << 2 * (i - 1)); \ vhtcaps->vht_supported_mcs_set.tx_map |= \ - ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \ + host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \ + 2 * (i - 1)); \ } \ if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \ vhtcaps_mask->vht_supported_mcs_set.rx_map |= \ - 3 << 2 * (i - 1); \ + host_to_le16(3 << 2 * (i - 1)); \ vhtcaps->vht_supported_mcs_set.rx_map |= \ - ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \ + host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \ + 2 * (i - 1)); \ } OVERRIDE_MCS(1); @@ -3819,8 +4132,9 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr, } -const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx, - Boolean mb_only) +static const u8 * wpas_fst_get_peer_first(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) { struct wpa_supplicant *wpa_s = ctx; @@ -3832,8 +4146,9 @@ const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx, } -const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx, - Boolean mb_only) +static const u8 * wpas_fst_get_peer_next(void *ctx, + struct fst_get_peer_ctx **get_ctx, + Boolean mb_only) { return NULL; } @@ -3872,6 +4187,55 @@ static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s, } +enum wpa_radio_work_band wpas_freq_to_band(int freq) +{ + if (freq < 3000) + return BAND_2_4_GHZ; + if (freq > 50000) + return BAND_60_GHZ; + return BAND_5_GHZ; +} + + +unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs) +{ + int i; + unsigned int band = 0; + + if (freqs) { + /* freqs are specified for the radio work */ + for (i = 0; freqs[i]; i++) + band |= wpas_freq_to_band(freqs[i]); + } else { + /* + * freqs are not specified, implies all + * the supported freqs by HW + */ + for (i = 0; i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].num_channels != 0) { + if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211B || + wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211G) + band |= BAND_2_4_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211A) + band |= BAND_5_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211AD) + band |= BAND_60_GHZ; + else if (wpa_s->hw.modes[i].mode == + HOSTAPD_MODE_IEEE80211ANY) + band = BAND_2_4_GHZ | BAND_5_GHZ | + BAND_60_GHZ; + } + } + } + + return band; +} + + static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s, const char *rn) { @@ -3924,11 +4288,103 @@ static void radio_work_free(struct wpa_radio_work *work) } #endif /* CONFIG_P2P */ + if (work->started) { + work->wpa_s->radio->num_active_works--; + wpa_dbg(work->wpa_s, MSG_DEBUG, + "radio_work_free('%s'@%p: num_active_works --> %u", + work->type, work, + work->wpa_s->radio->num_active_works); + } + dl_list_del(&work->list); os_free(work); } +static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio) +{ + struct wpa_radio_work *active_work = NULL; + struct wpa_radio_work *tmp; + + /* Get the active work to know the type and band. */ + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) { + if (tmp->started) { + active_work = tmp; + break; + } + } + + if (!active_work) { + /* No active work, start one */ + radio->num_active_works = 0; + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, + list) { + if (os_strcmp(tmp->type, "scan") == 0 && + radio->external_scan_running && + (((struct wpa_driver_scan_params *) + tmp->ctx)->only_new_results || + tmp->wpa_s->clear_driver_scan_cache)) + continue; + return tmp; + } + return NULL; + } + + if (os_strcmp(active_work->type, "sme-connect") == 0 || + os_strcmp(active_work->type, "connect") == 0) { + /* + * If the active work is either connect or sme-connect, + * do not parallelize them with other radio works. + */ + wpa_dbg(active_work->wpa_s, MSG_DEBUG, + "Do not parallelize radio work with %s", + active_work->type); + return NULL; + } + + dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) { + if (tmp->started) + continue; + + /* + * If connect or sme-connect are enqueued, parallelize only + * those operations ahead of them in the queue. + */ + if (os_strcmp(tmp->type, "connect") == 0 || + os_strcmp(tmp->type, "sme-connect") == 0) + break; + + /* + * Check that the radio works are distinct and + * on different bands. + */ + if (os_strcmp(active_work->type, tmp->type) != 0 && + (active_work->bands != tmp->bands)) { + /* + * If a scan has to be scheduled through nl80211 scan + * interface and if an external scan is already running, + * do not schedule the scan since it is likely to get + * rejected by kernel. + */ + if (os_strcmp(tmp->type, "scan") == 0 && + radio->external_scan_running && + (((struct wpa_driver_scan_params *) + tmp->ctx)->only_new_results || + tmp->wpa_s->clear_driver_scan_cache)) + continue; + + wpa_dbg(active_work->wpa_s, MSG_DEBUG, + "active_work:%s new_work:%s", + active_work->type, tmp->type); + return tmp; + } + } + + /* Did not find a radio work to schedule in parallel. */ + return NULL; +} + + static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) { struct wpa_radio *radio = eloop_ctx; @@ -3937,26 +4393,48 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s; work = dl_list_first(&radio->work, struct wpa_radio_work, list); - if (work == NULL) + if (work == NULL) { + radio->num_active_works = 0; return; - - if (work->started) - return; /* already started and still in progress */ + } wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant, radio_list); - if (wpa_s && wpa_s->radio->external_scan_running) { - wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); - return; + + if (!(wpa_s && + wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) { + if (work->started) + return; /* already started and still in progress */ + + if (wpa_s && wpa_s->radio->external_scan_running) { + wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes"); + return; + } + } else { + work = NULL; + if (radio->num_active_works < MAX_ACTIVE_WORKS) { + /* get the work to schedule next */ + work = radio_work_get_next_work(radio); + } + if (!work) + return; } + wpa_s = work->wpa_s; os_get_reltime(&now); os_reltime_sub(&now, &work->time, &diff); - wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting radio work '%s'@%p after %ld.%06ld second wait", + wpa_dbg(wpa_s, MSG_DEBUG, + "Starting radio work '%s'@%p after %ld.%06ld second wait", work->type, work, diff.sec, diff.usec); work->started = 1; work->time = now; + radio->num_active_works++; + work->cb(work, 0); + + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) && + radio->num_active_works < MAX_ACTIVE_WORKS) + radio_work_check_next(wpa_s); } @@ -4064,6 +4542,7 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, void (*cb)(struct wpa_radio_work *work, int deinit), void *ctx) { + struct wpa_radio *radio = wpa_s->radio; struct wpa_radio_work *work; int was_empty; @@ -4078,6 +4557,16 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, work->cb = cb; work->ctx = ctx; + if (freq) + work->bands = wpas_freq_to_band(freq); + else if (os_strcmp(type, "scan") == 0 || + os_strcmp(type, "p2p-scan") == 0) + work->bands = wpas_get_bands(wpa_s, + ((struct wpa_driver_scan_params *) + ctx)->freqs); + else + work->bands = wpas_get_bands(wpa_s, NULL); + was_empty = dl_list_empty(&wpa_s->radio->work); if (next) dl_list_add(&wpa_s->radio->work, &work->list); @@ -4086,6 +4575,12 @@ int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, if (was_empty) { wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately"); radio_work_check_next(wpa_s); + } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) + && radio->num_active_works < MAX_ACTIVE_WORKS) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Try to schedule a radio work (num_active_works=%u)", + radio->num_active_works); + radio_work_check_next(wpa_s); } return 0; @@ -4341,6 +4836,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; + wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans; + wpa_s->max_sched_scan_plan_interval = + capa.max_sched_scan_plan_interval; + wpa_s->max_sched_scan_plan_iterations = + capa.max_sched_scan_plan_iterations; wpa_s->sched_scan_supported = capa.sched_scan_supported; wpa_s->max_match_sets = capa.max_match_sets; wpa_s->max_remain_on_chan = capa.max_remain_on_chan; @@ -4480,6 +4980,17 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpas_rrm_reset(wpa_s); + wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); + +#ifdef CONFIG_HS20 + hs20_init(wpa_s); +#endif /* CONFIG_HS20 */ +#ifdef CONFIG_MBO + wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan); +#endif /* CONFIG_MBO */ + + wpa_supplicant_set_default_scan_ies(wpa_s); + return 0; } @@ -4495,6 +5006,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, iface = global->ifaces; while (iface) { + if (iface->p2pdev == wpa_s) + iface->p2pdev = iface->parent; if (iface == wpa_s || iface->parent != wpa_s) { iface = iface->next; continue; @@ -4565,6 +5078,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_MATCH_IFACE + +/** + * wpa_supplicant_match_iface - Match an interface description to a name + * @global: Pointer to global data from wpa_supplicant_init() + * @ifname: Name of the interface to match + * Returns: Pointer to the created interface description or %NULL on failure + */ +struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global, + const char *ifname) +{ + int i; + struct wpa_interface *iface, *miface; + + for (i = 0; i < global->params.match_iface_count; i++) { + miface = &global->params.match_ifaces[i]; + if (!miface->ifname || + fnmatch(miface->ifname, ifname, 0) == 0) { + iface = os_zalloc(sizeof(*iface)); + if (!iface) + return NULL; + *iface = *miface; + iface->ifname = ifname; + return iface; + } + } + + return NULL; +} + + +/** + * wpa_supplicant_match_existing - Match existing interfaces + * @global: Pointer to global data from wpa_supplicant_init() + * Returns: 0 on success, -1 on failure + */ +static int wpa_supplicant_match_existing(struct wpa_global *global) +{ + struct if_nameindex *ifi, *ifp; + struct wpa_supplicant *wpa_s; + struct wpa_interface *iface; + + ifp = if_nameindex(); + if (!ifp) { + wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno)); + return -1; + } + + for (ifi = ifp; ifi->if_name; ifi++) { + wpa_s = wpa_supplicant_get_iface(global, ifi->if_name); + if (wpa_s) + continue; + iface = wpa_supplicant_match_iface(global, ifi->if_name); + if (iface) { + wpa_s = wpa_supplicant_add_iface(global, iface, NULL); + os_free(iface); + if (wpa_s) + wpa_s->matched = 1; + } + } + + if_freenameindex(ifp); + return 0; +} + +#endif /* CONFIG_MATCH_IFACE */ + + /** * wpa_supplicant_add_iface - Add a new network interface * @global: Pointer to global data from wpa_supplicant_init() @@ -4866,6 +5447,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) if (params->override_ctrl_interface) global->params.override_ctrl_interface = os_strdup(params->override_ctrl_interface); +#ifdef CONFIG_MATCH_IFACE + global->params.match_iface_count = params->match_iface_count; + if (params->match_iface_count) { + global->params.match_ifaces = + os_calloc(params->match_iface_count, + sizeof(struct wpa_interface)); + os_memcpy(global->params.match_ifaces, + params->match_ifaces, + params->match_iface_count * + sizeof(struct wpa_interface)); + } +#endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_P2P if (params->conf_p2p_dev) global->params.conf_p2p_dev = @@ -4941,12 +5534,18 @@ int wpa_supplicant_run(struct wpa_global *global) struct wpa_supplicant *wpa_s; if (global->params.daemonize && - wpa_supplicant_daemon(global->params.pid_file)) + (wpa_supplicant_daemon(global->params.pid_file) || + eloop_sock_requeue())) + return -1; + +#ifdef CONFIG_MATCH_IFACE + if (wpa_supplicant_match_existing(global)) return -1; +#endif if (global->params.wait_for_monitor) { for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) - if (wpa_s->ctrl_iface) + if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt) wpa_supplicant_ctrl_iface_wait( wpa_s->ctrl_iface); } @@ -5012,6 +5611,9 @@ void wpa_supplicant_deinit(struct wpa_global *global) os_free(global->params.ctrl_interface_group); os_free(global->params.override_driver); os_free(global->params.override_ctrl_interface); +#ifdef CONFIG_MATCH_IFACE + os_free(global->params.match_ifaces); +#endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_P2P os_free(global->params.conf_p2p_dev); #endif /* CONFIG_P2P */ @@ -5044,6 +5646,9 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s) if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND) wpas_init_ext_pw(wpa_s); + if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS) + wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); + #ifdef CONFIG_WPS wpas_wps_update_config(wpa_s); #endif /* CONFIG_WPS */ @@ -5283,6 +5888,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning) wpa_supplicant_req_scan(wpa_s, 0, 0); break; + case WPA_CTRL_REQ_EXT_CERT_CHECK: + if (eap->pending_ext_cert_check != PENDING_CHECK) + return -1; + if (os_strcmp(value, "good") == 0) + eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD; + else if (os_strcmp(value, "bad") == 0) + eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD; + else + return -1; + break; default: wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field); return -1; @@ -5352,6 +5967,19 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) return NO_MGMT_FRAME_PROTECTION; } + if (ssid && + (ssid->key_mgmt & + ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS | + WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) { + /* + * Do not use the default PMF value for non-RSN networks + * since PMF is available only with RSN and pmf=2 + * configuration would otherwise prevent connections to + * all open networks. + */ + return NO_MGMT_FRAME_PROTECTION; + } + return wpa_s->conf->pmf; } @@ -5510,6 +6138,27 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s) } +/** + * wpas_request_disconnection - Request disconnection + * @wpa_s: Pointer to the network interface + * + * This function is used to request disconnection from the currently connected + * network. This will stop any ongoing scans and initiate deauthentication. + */ +void wpas_request_disconnection(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_SME + wpa_s->sme.prev_bssid_set = 0; +#endif /* CONFIG_SME */ + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_cancel_scan(wpa_s); + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); + eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); +} + + void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, struct wpa_used_freq_data *freqs_data, unsigned int len) @@ -5692,11 +6341,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, #define ECANCELED -1 #endif +/* Measurement Request element + Location Subject + Maximum Age subelement */ +#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4) +/* Measurement Request element + Location Civic Request */ +#define MEASURE_REQUEST_CIVIC_LEN (3 + 5) + + /** * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP * @wpa_s: Pointer to wpa_supplicant * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE * is sent in the request. + * @lci: if set, neighbor request will include LCI request + * @civic: if set, neighbor request will include civic location request * @cb: Callback function to be called once the requested report arrives, or * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds. * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's @@ -5710,7 +6367,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, * Request must contain a callback function. */ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx) @@ -5751,7 +6409,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, } /* 3 = action category + action code + dialog token */ - buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0)); + buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) + + (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) + + (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0)); if (buf == NULL) { wpa_printf(MSG_DEBUG, "RRM: Failed to allocate Neighbor Report Request"); @@ -5771,6 +6431,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len); } + if (lci) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 1); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */ + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + + /* Optional Subelements */ + /* + * IEEE P802.11-REVmc/D5.0 Figure 9-170 + * The Maximum Age subelement is required, otherwise the AP can + * send only data that was determined after receiving the + * request. Setting it here to unlimited age. + */ + wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); + wpabuf_put_u8(buf, 2); + wpabuf_put_le16(buf, 0xffff); + } + + if (civic) { + /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN); + + /* + * Measurement token; nonzero number that is unique among the + * Measurement Request elements in a particular frame. + */ + wpabuf_put_u8(buf, 2); /* Measurement Token */ + + /* + * Parallel, Enable, Request, and Report bits are 0, Duration is + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + /* Measurement Type */ + wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC); + + /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14: + * Location Civic request */ + /* Location Subject */ + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */ + /* Location Service Interval Units: Seconds */ + wpabuf_put_u8(buf, 0); + /* Location Service Interval: 0 - Only one report is requested + */ + wpabuf_put_le16(buf, 0); + /* No optional subelements */ + } + wpa_s->rrm.next_neighbor_rep_token++; if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, @@ -5793,6 +6519,147 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, } +static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s, + const u8 *request, size_t len, + struct wpabuf *report) +{ + u8 token, type, subject; + u16 max_age = 0; + struct os_reltime t, diff; + unsigned long diff_l; + u8 *ptoken; + const u8 *subelem; + + if (!wpa_s->lci || len < 3 + 4) + return report; + + token = *request++; + /* Measurement request mode isn't used */ + request++; + type = *request++; + subject = *request++; + + wpa_printf(MSG_DEBUG, + "Measurement request token %u type %u location subject %u", + token, type, subject); + + if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) { + wpa_printf(MSG_INFO, + "Not building LCI report - bad type or location subject"); + return report; + } + + /* Subelements are formatted exactly like elements */ + subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE); + if (subelem && subelem[1] == 2) + max_age = WPA_GET_LE16(subelem + 2); + + if (os_get_reltime(&t)) + return report; + + os_reltime_sub(&t, &wpa_s->lci_time, &diff); + /* LCI age is calculated in 10th of a second units. */ + diff_l = diff.sec * 10 + diff.usec / 100000; + + if (max_age != 0xffff && max_age < diff_l) + return report; + + if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci))) + return report; + + wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT); + wpabuf_put_u8(report, wpabuf_len(wpa_s->lci)); + /* We'll override user's measurement token */ + ptoken = wpabuf_put(report, 0); + wpabuf_put_buf(report, wpa_s->lci); + *ptoken = token; + + return report; +} + + +void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *frame, size_t len) +{ + struct wpabuf *buf, *report; + u8 token; + const u8 *ie, *end; + + if (wpa_s->wpa_state != WPA_COMPLETED) { + wpa_printf(MSG_INFO, + "RRM: Ignoring radio measurement request: Not associated"); + return; + } + + if (!wpa_s->rrm.rrm_used) { + wpa_printf(MSG_INFO, + "RRM: Ignoring radio measurement request: Not RRM network"); + return; + } + + if (len < 3) { + wpa_printf(MSG_INFO, + "RRM: Ignoring too short radio measurement request"); + return; + } + + end = frame + len; + + token = *frame++; + + /* Ignore number of repetitions because it's not used in LCI request */ + frame += 2; + + report = NULL; + while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) && + ie[1] >= 3) { + u8 msmt_type; + + msmt_type = ie[4]; + wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type); + + switch (msmt_type) { + case MEASURE_TYPE_LCI: + report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1], + report); + break; + default: + wpa_printf(MSG_INFO, + "RRM: Unsupported radio measurement request %d", + msmt_type); + break; + } + + frame = ie + ie[1] + 2; + } + + if (!report) + return; + + buf = wpabuf_alloc(3 + wpabuf_len(report)); + if (!buf) { + wpabuf_free(report); + return; + } + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT); + wpabuf_put_u8(buf, token); + + wpabuf_put_buf(buf, report); + wpabuf_free(report); + + if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(buf), wpabuf_len(buf), 0)) { + wpa_printf(MSG_ERROR, + "RRM: Radio measurement report failed: Sending Action frame failed"); + } + wpabuf_free(buf); +} + + void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *frame, size_t len, @@ -5870,3 +6737,175 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, } wpabuf_free(buf); } + + +struct wpa_supplicant * +wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame) +{ + switch (frame) { +#ifdef CONFIG_P2P + case VENDOR_ELEM_PROBE_REQ_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P_GO: + case VENDOR_ELEM_BEACON_P2P_GO: + case VENDOR_ELEM_P2P_PD_REQ: + case VENDOR_ELEM_P2P_PD_RESP: + case VENDOR_ELEM_P2P_GO_NEG_REQ: + case VENDOR_ELEM_P2P_GO_NEG_RESP: + case VENDOR_ELEM_P2P_GO_NEG_CONF: + case VENDOR_ELEM_P2P_INV_REQ: + case VENDOR_ELEM_P2P_INV_RESP: + case VENDOR_ELEM_P2P_ASSOC_REQ: + case VENDOR_ELEM_P2P_ASSOC_RESP: + return wpa_s->p2pdev; +#endif /* CONFIG_P2P */ + default: + return wpa_s; + } +} + + +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + char buf[30]; + + wpa_printf(MSG_DEBUG, "Update vendor elements"); + + for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { + if (wpa_s->vendor_elem[i]) { + int res; + + res = os_snprintf(buf, sizeof(buf), "frame[%u]", i); + if (!os_snprintf_error(sizeof(buf), res)) { + wpa_hexdump_buf(MSG_DEBUG, buf, + wpa_s->vendor_elem[i]); + } + } + } + +#ifdef CONFIG_P2P + if (wpa_s->parent == wpa_s && + wpa_s->global->p2p && + !wpa_s->global->p2p_disabled) + p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); +#endif /* CONFIG_P2P */ +} + + +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len) +{ + u8 *ie, *end; + + ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); + end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); + + for (; ie + 1 < end; ie += 2 + ie[1]) { + if (ie + len > end) + break; + if (os_memcmp(ie, elem, len) != 0) + continue; + + if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { + wpabuf_free(wpa_s->vendor_elem[frame]); + wpa_s->vendor_elem[frame] = NULL; + } else { + os_memmove(ie, ie + len, end - (ie + len)); + wpa_s->vendor_elem[frame]->used -= len; + } + wpas_vendor_elem_update(wpa_s); + return 0; + } + + return -1; +} + + +struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, + u16 num_modes, enum hostapd_hw_mode mode) +{ + u16 i; + + for (i = 0; i < num_modes; i++) { + if (modes[i].mode == mode) + return &modes[i]; + } + + return NULL; +} + + +static struct +wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + struct wpa_bss_tmp_disallowed *bss; + + dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0) + return bss; + } + + return NULL; +} + + +void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, + unsigned int sec) +{ + struct wpa_bss_tmp_disallowed *bss; + struct os_reltime until; + + os_get_reltime(&until); + until.sec += sec; + + bss = wpas_get_disallowed_bss(wpa_s, bssid); + if (bss) { + bss->disallowed_until = until; + return; + } + + bss = os_malloc(sizeof(*bss)); + if (!bss) { + wpa_printf(MSG_DEBUG, + "Failed to allocate memory for temp disallow BSS"); + return; + } + + bss->disallowed_until = until; + os_memcpy(bss->bssid, bssid, ETH_ALEN); + dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); +} + + +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid) +{ + struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev; + struct os_reltime now, age; + + os_get_reltime(&now); + + dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed, + struct wpa_bss_tmp_disallowed, list) { + if (!os_reltime_before(&now, &tmp->disallowed_until)) { + /* This BSS is not disallowed anymore */ + dl_list_del(&tmp->list); + os_free(tmp); + continue; + } + if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) { + bss = tmp; + break; + } + } + if (!bss) + return 0; + + os_reltime_sub(&bss->disallowed_until, &now, &age); + wpa_printf(MSG_DEBUG, + "BSS " MACSTR " disabled for %ld.%0ld seconds", + MAC2STR(bss->bssid), age.sec, age.usec); + return 1; +} diff --git a/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h index 318768bc..ef9273d0 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h +++ b/freebsd/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h @@ -44,6 +44,7 @@ struct wpa_driver_associate_params; struct ctrl_iface_priv; struct ctrl_iface_global_priv; struct wpas_dbus_priv; +struct wpas_binder_priv; /** * struct wpa_interface - Parameters for wpa_supplicant_add_iface() @@ -228,6 +229,17 @@ struct wpa_params { char *conf_p2p_dev; #endif /* CONFIG_P2P */ +#ifdef CONFIG_MATCH_IFACE + /** + * match_ifaces - Interface descriptions to match + */ + struct wpa_interface *match_ifaces; + + /** + * match_iface_count - Number of defined matching interfaces + */ + int match_iface_count; +#endif /* CONFIG_MATCH_IFACE */ }; struct p2p_srv_bonjour { @@ -253,6 +265,7 @@ struct wpa_global { struct wpa_params params; struct ctrl_iface_global_priv *ctrl_iface; struct wpas_dbus_priv *dbus; + struct wpas_binder_priv *binder; void **drv_priv; size_t drv_count; struct os_time suspend_time; @@ -278,6 +291,7 @@ struct wpa_global { unsigned int p2p_24ghz_social_channels:1; unsigned int pending_p2ps_group:1; unsigned int pending_group_iface_for_p2ps:1; + unsigned int pending_p2ps_group_freq; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; @@ -300,10 +314,14 @@ struct wpa_radio { char name[16]; /* from driver_ops get_radio_name() or empty if not * available */ unsigned int external_scan_running:1; + unsigned int num_active_works; struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */ struct dl_list work; /* struct wpa_radio_work::list entries */ }; +#define MAX_ACTIVE_WORKS 2 + + /** * struct wpa_radio_work - Radio work item */ @@ -316,6 +334,7 @@ struct wpa_radio_work { void *ctx; unsigned int started:1; struct os_reltime time; + unsigned int bands; }; int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq, @@ -347,6 +366,9 @@ struct wpa_external_work { unsigned int timeout; }; +enum wpa_radio_work_band wpas_freq_to_band(int freq); +unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs); + /** * offchannel_send_action_result - Result of offchannel send Action frame */ @@ -371,11 +393,6 @@ struct wps_ap_info { u8 uuid[WPS_UUID_LEN]; }; -struct wpa_ssid_value { - u8 ssid[SSID_MAX_LEN]; - size_t ssid_len; -}; - #define WPA_FREQ_USED_BY_INFRA_STATION BIT(0) #define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1) @@ -414,6 +431,21 @@ enum wpa_supplicant_test_failure { WPAS_TEST_FAILURE_SCAN_TRIGGER, }; +struct icon_entry { + struct dl_list list; + u8 bssid[ETH_ALEN]; + u8 dialog_token; + char *file_name; + u8 *image; + size_t image_len; +}; + +struct wpa_bss_tmp_disallowed { + struct dl_list list; + u8 bssid[ETH_ALEN]; + struct os_reltime disallowed_until; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -427,12 +459,16 @@ struct wpa_supplicant { struct wpa_radio *radio; /* shared radio context */ struct dl_list radio_list; /* list head: struct wpa_radio::ifaces */ struct wpa_supplicant *parent; + struct wpa_supplicant *p2pdev; struct wpa_supplicant *next; struct l2_packet_data *l2; struct l2_packet_data *l2_br; unsigned char own_addr[ETH_ALEN]; unsigned char perm_addr[ETH_ALEN]; char ifname[100]; +#ifdef CONFIG_MATCH_IFACE + int matched; +#endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_CTRL_IFACE_DBUS char *dbus_path; #endif /* CONFIG_CTRL_IFACE_DBUS */ @@ -443,6 +479,9 @@ struct wpa_supplicant { char *preq_notify_peer; #endif /* CONFIG_AP */ #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ +#ifdef CONFIG_CTRL_IFACE_BINDER + const void *binder_object_key; +#endif /* CONFIG_CTRL_IFACE_BINDER */ char bridge_ifname[16]; char *confname; @@ -455,7 +494,8 @@ struct wpa_supplicant { u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this * field contains the target BSSID. */ int reassociate; /* reassociation requested */ - int reassoc_same_bss; /* reassociating to the same bss */ + unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */ + unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */ int disconnected; /* all connections disabled; i.e., do no reassociate * before this has been cleared */ struct wpa_ssid *current_ssid; @@ -500,9 +540,10 @@ struct wpa_supplicant { struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */ int sched_scan_timeout; - int sched_scan_interval; int first_sched_scan; int sched_scan_timed_out; + struct sched_scan_plan *sched_scan_plans; + size_t sched_scan_plans_num; void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); @@ -533,6 +574,7 @@ struct wpa_supplicant { struct wpa_radio_work *scan_work; int scanning; int sched_scanning; + unsigned int sched_scan_stop_req:1; int new_connection; int eapol_received; /* number of EAPOL packets received after the @@ -613,6 +655,7 @@ struct wpa_supplicant { #define MAX_SCAN_ID 16 int scan_id[MAX_SCAN_ID]; unsigned int scan_id_count; + u8 next_scan_bssid[ETH_ALEN]; struct wpa_ssid_value *ssids_from_scan_req; unsigned int num_ssids_from_scan_req; @@ -634,6 +677,9 @@ struct wpa_supplicant { int max_scan_ssids; int max_sched_scan_ssids; + unsigned int max_sched_scan_plans; + unsigned int max_sched_scan_plan_interval; + unsigned int max_sched_scan_plan_iterations; int sched_scan_supported; unsigned int max_match_sets; unsigned int max_remain_on_chan; @@ -723,7 +769,7 @@ struct wpa_supplicant { int mesh_if_idx; unsigned int mesh_if_created:1; unsigned int mesh_ht_enabled:1; - int mesh_auth_block_duration; /* sec */ + unsigned int mesh_vht_enabled:1; #endif /* CONFIG_MESH */ unsigned int off_channel_freq; @@ -845,6 +891,10 @@ struct wpa_supplicant { int *p2p_group_common_freqs; unsigned int p2p_group_common_freqs_num; u8 p2ps_join_addr[ETH_ALEN]; + + unsigned int p2p_go_max_oper_chwidth; + unsigned int p2p_go_vht_center_freq2; + int p2p_lo_started; #endif /* CONFIG_P2P */ struct wpa_ssid *bgscan_ssid; @@ -886,6 +936,7 @@ struct wpa_supplicant { unsigned int fetch_osu_icon_in_progress:1; struct wpa_bss *interworking_gas_bss; unsigned int osu_icon_id; + struct dl_list icon_head; /* struct icon_entry */ struct osu_provider *osu_prov; size_t osu_prov_count; struct os_reltime osu_icon_fetch_start; @@ -915,6 +966,9 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; + /* WLAN_STATUS_* status codes from (Re)Association Response frame. */ + u16 assoc_status_code; + struct ext_password_data *ext_pw; struct wpabuf *last_gas_resp, *prev_gas_resp; @@ -970,6 +1024,10 @@ struct wpa_supplicant { struct l2_packet_data *l2_test; unsigned int extra_roc_dur; enum wpa_supplicant_test_failure test_failure; + unsigned int reject_btm_req_reason; + unsigned int p2p_go_csa_on_inv:1; + unsigned int ignore_auth_resp:1; + unsigned int ignore_assoc_disallow:1; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -986,6 +1044,31 @@ struct wpa_supplicant { const struct wpabuf *fst_ies; struct wpabuf *received_mb_ies; #endif /* CONFIG_FST */ + +#ifdef CONFIG_MBO + /* Multiband operation non-preferred channel */ + struct wpa_mbo_non_pref_channel { + enum mbo_non_pref_chan_reason reason; + u8 oper_class; + u8 chan; + u8 preference; + } *non_pref_chan; + size_t non_pref_chan_num; + u8 mbo_wnm_token; +#endif /* CONFIG_MBO */ + + /* + * This should be under CONFIG_MBO, but it is left out to allow using + * the bss_temp_disallowed list for other purposes as well. + */ + struct dl_list bss_tmp_disallowed; + + /* + * Content of a measurement report element with type 8 (LCI), + * own location. + */ + struct wpabuf *lci; + struct os_reltime lci_time; }; @@ -1027,6 +1110,8 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int reason_code); +struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s); +int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id); void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, @@ -1051,6 +1136,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s); void wpa_show_license(void); +struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global, + const char *ifname); struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, struct wpa_interface *iface, struct wpa_supplicant *parent); @@ -1080,6 +1167,7 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); +void wpas_request_disconnection(struct wpa_supplicant *wpa_s); int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen); int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style); int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s); @@ -1089,15 +1177,37 @@ void wpas_rrm_reset(struct wpa_supplicant *wpa_s); void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, const u8 *report, size_t report_len); int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, + const struct wpa_ssid_value *ssid, + int lci, int civic, void (*cb)(void *ctx, struct wpabuf *neighbor_rep), void *cb_ctx); +void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s, + const u8 *src, + const u8 *frame, size_t len); void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *frame, size_t len, int rssi); + +/* MBO functions */ +int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len); +const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr); +int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, + const char *non_pref_chan); +void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie); +int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos, + size_t len); +void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie, + size_t len); +size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos, + size_t len, + enum mbo_transition_reject_reason reason); +void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa); +struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); + /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response * @wpa_s: Pointer to wpa_supplicant data @@ -1159,6 +1269,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx); +void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s); +struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s, + enum wpa_vendor_elem_frame frame); +int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, + const u8 *elem, size_t len); + #ifdef CONFIG_FST struct fst_wpa_obj; @@ -1168,4 +1284,18 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s, #endif /* CONFIG_FST */ +int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd); + +struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, + u16 num_modes, enum hostapd_hw_mode mode); + +void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, + unsigned int sec); +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid); + +struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, + int i, struct wpa_bss *bss, + struct wpa_ssid *group, + int only_first_ssid); + #endif /* WPA_SUPPLICANT_I_H */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c b/freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c index 7ce05ddb..158cbb07 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c +++ b/freebsd/contrib/wpa/wpa_supplicant/wpas_glue.c @@ -741,6 +741,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field) return WPA_CTRL_REQ_SIM; else if (os_strcmp(field, "PSK_PASSPHRASE") == 0) return WPA_CTRL_REQ_PSK_PASSPHRASE; + else if (os_strcmp(field, "EXT_CERT_CHECK") == 0) + return WPA_CTRL_REQ_EXT_CERT_CHECK; return WPA_CTRL_REQ_UNKNOWN; } @@ -784,6 +786,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, *txt = "PSK or passphrase"; ret = "PSK_PASSPHRASE"; break; + case WPA_CTRL_REQ_EXT_CERT_CHECK: + *txt = "External server certificate validation"; + ret = "EXT_CERT_CHECK"; + break; default: break; } @@ -839,6 +845,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx, if (ssid == NULL) return; + if (field == WPA_CTRL_REQ_EXT_CERT_CHECK) + ssid->eap.pending_ext_cert_check = PENDING_CHECK; wpas_notify_network_request(wpa_s, ssid, field, default_txt); field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt, @@ -1015,7 +1023,6 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr); } -#endif /* CONFIG_NO_WPA */ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, @@ -1030,6 +1037,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, else return 0; } +#endif /* CONFIG_NO_WPA */ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) @@ -1126,6 +1134,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, } } #endif /* CONFIG_P2P */ + conf.wpa_rsc_relaxation = wpa_s->conf->wpa_rsc_relaxation; } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } diff --git a/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.c b/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.c index b3c061b3..39440b36 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.c +++ b/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.c @@ -585,8 +585,8 @@ static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s, m2d->dev_password_id, m2d->config_error); wpas_notify_wps_event_m2d(wpa_s, m2d); #ifdef CONFIG_P2P - if (wpa_s->parent && wpa_s->parent != wpa_s) { - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_M2D + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) { + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_M2D "dev_password_id=%d config_error=%d", m2d->dev_password_id, m2d->config_error); } @@ -619,8 +619,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, wps_ei_str(fail->error_indication)); - if (wpa_s->parent && wpa_s->parent != wpa_s) - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", fail->msg, fail->config_error, fail->error_indication, @@ -629,8 +629,8 @@ static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); - if (wpa_s->parent && wpa_s->parent != wpa_s) - wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL + if (wpa_s->p2pdev && wpa_s->p2pdev != wpa_s) + wpa_msg(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_FAIL "msg=%d config_error=%d", fail->msg, fail->config_error); } @@ -685,6 +685,13 @@ static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx) } +int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s) +{ + return eloop_is_timeout_registered(wpas_wps_reenable_networks_cb, + wpa_s, NULL); +} + + static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS); @@ -1137,6 +1144,13 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; ssid->temporary = 1; ssid->p2p_group = p2p_group; + /* + * When starting a regular WPS process (not P2P group formation) + * the registrar/final station can be either AP or PCP + * so use a "don't care" value for the pbss flag. + */ + if (!p2p_group) + ssid->pbss = 2; #ifdef CONFIG_P2P if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) { ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1); @@ -1144,6 +1158,10 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); + if (wpa_s->go_params->freq > 56160) { + /* P2P in 60 GHz uses PBSS */ + ssid->pbss = 1; + } wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } @@ -1188,6 +1206,13 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, } ssid->temporary = 1; ssid->p2p_group = p2p_group; + /* + * When starting a regular WPS process (not P2P group formation) + * the registrar/final station can be either AP or PCP + * so use a "don't care" value for the pbss flag. + */ + if (!p2p_group) + ssid->pbss = 2; if (ssid_val) { ssid->ssid = os_malloc(ssid_len); if (ssid->ssid) { @@ -1211,6 +1236,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, ssid->ssid_len = wpa_s->go_params->ssid_len; os_memcpy(ssid->ssid, wpa_s->go_params->ssid, ssid->ssid_len); + if (wpa_s->go_params->freq > 56160) { + /* P2P in 60 GHz uses PBSS */ + ssid->pbss = 1; + } wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP " "SSID", ssid->ssid, ssid->ssid_len); } @@ -1223,7 +1252,10 @@ static int wpas_wps_start_dev_pw(struct wpa_supplicant *wpa_s, os_snprintf(val, sizeof(val), "\"dev_pw_id=%u%s\"", dev_pw_id, hash); } else { - rpin = wps_generate_pin(); + if (wps_generate_pin(&rpin) < 0) { + wpa_printf(MSG_DEBUG, "WPS: Could not generate PIN"); + return -1; + } os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u%s\"", rpin, dev_pw_id, hash); } diff --git a/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.h b/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.h index 3c25ca86..c8fe47e3 100644 --- a/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.h +++ b/freebsd/contrib/wpa/wpa_supplicant/wps_supplicant.h @@ -85,6 +85,7 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s); #else /* CONFIG_WPS */ @@ -147,6 +148,12 @@ static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, { } +static inline int +wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s) +{ + return 0; +} + #endif /* CONFIG_WPS */ #endif /* WPS_SUPPLICANT_H */ |