diff --git a/contrib/wpa/hostapd/Android.mk b/contrib/wpa/hostapd/Android.mk index dd8aa2450d7e..bf26e41c6b23 100644 --- a/contrib/wpa/hostapd/Android.mk +++ b/contrib/wpa/hostapd/Android.mk @@ -567,6 +567,9 @@ NEED_ASN1=y ifdef CONFIG_DPP2 L_CFLAGS += -DCONFIG_DPP2 endif +ifdef CONFIG_DPP3 +L_CFLAGS += -DCONFIG_DPP3 +endif endif ifdef CONFIG_PASN diff --git a/contrib/wpa/hostapd/Makefile b/contrib/wpa/hostapd/Makefile index ac085fd10520..e37c13b27a6e 100644 --- a/contrib/wpa/hostapd/Makefile +++ b/contrib/wpa/hostapd/Makefile @@ -593,6 +593,9 @@ NEED_ASN1=y ifdef CONFIG_DPP2 CFLAGS += -DCONFIG_DPP2 endif +ifdef CONFIG_DPP3 +CFLAGS += -DCONFIG_DPP3 +endif endif ifdef CONFIG_PASN diff --git a/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c index daf3f37ad99e..b14728d1b507 100644 --- a/contrib/wpa/hostapd/config_file.c +++ b/contrib/wpa/hostapd/config_file.c @@ -3193,6 +3193,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->acs_freq_list_present = 1; } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) { conf->acs_exclude_6ghz_non_psc = atoi(pos); + } else if (os_strcmp(buf, "min_tx_power") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 255) { + wpa_printf(MSG_ERROR, + "Line %d: invalid min_tx_power %d (expected 0..255)", + line, val); + return 1; + } + conf->min_tx_power = val; } else if (os_strcmp(buf, "beacon_int") == 0) { int val = atoi(pos); /* MIB defines range as 1..65535, but very small values diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c index 6c99a3105f49..86adf18e5fe3 100644 --- a/contrib/wpa/hostapd/ctrl_iface.c +++ b/contrib/wpa/hostapd/ctrl_iface.c @@ -1504,7 +1504,7 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) return -1; val = atoi(value); - if (val < 0 || val > 1) + if (val < 0 || val > MBO_ASSOC_DISALLOW_REASON_LOW_RSSI) return -1; hapd->mbo_assoc_disallow = val; @@ -3463,7 +3463,9 @@ static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd, if (os_strcmp(field, "dpp") == 0) { int res; -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 + res = os_snprintf(buf, buflen, "DPP=3"); +#elif defined(CONFIG_DPP2) res = os_snprintf(buf, buflen, "DPP=2"); #else /* CONFIG_DPP2 */ res = os_snprintf(buf, buflen, "DPP=1"); @@ -4492,7 +4494,9 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) #ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_DPP dpp_test = DPP_TEST_DISABLED; -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 + dpp_version_override = 3; +#elif defined(CONFIG_DPP2) dpp_version_override = 2; #else /* CONFIG_DPP2 */ dpp_version_override = 1; diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig index 666447e4ab40..6b50b6c59b46 100644 --- a/contrib/wpa/hostapd/defconfig +++ b/contrib/wpa/hostapd/defconfig @@ -402,3 +402,11 @@ CONFIG_IPV6=y # production use. # This requires CONFIG_IEEE80211W=y to be enabled, too. #CONFIG_PASN=y + +# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect) +CONFIG_DPP=y +# DPP version 2 support +CONFIG_DPP2=y +# DPP version 3 support (experimental and still changing; do not enable for +# production use) +#CONFIG_DPP3=y diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf index 67d4cefb920b..3c2019f73048 100644 --- a/contrib/wpa/hostapd/hostapd.conf +++ b/contrib/wpa/hostapd/hostapd.conf @@ -225,6 +225,10 @@ channel=1 # Default behavior is to include all PSC and non-PSC channels. #acs_exclude_6ghz_non_psc=1 +# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection. +# (default 0, i.e., not constraint) +#min_tx_power=20 + # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c index 46429f265433..0030edc2a90f 100644 --- a/contrib/wpa/src/ap/acs.c +++ b/contrib/wpa/src/ap/acs.c @@ -546,6 +546,9 @@ static void acs_survey_mode_interference_factor( if (!is_in_freqlist(iface, chan)) continue; + if (chan->max_tx_power < iface->conf->min_tx_power) + continue; + wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", chan->chan, chan->freq); @@ -673,6 +676,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, if (!is_in_freqlist(iface, chan)) continue; + if (chan->max_tx_power < iface->conf->min_tx_power) + continue; + if (!chan_bw_allowed(chan, bw, 1, 1)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: BW %u is not supported", @@ -1047,6 +1053,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, if (!is_in_freqlist(iface, chan)) continue; + if (chan->max_tx_power < iface->conf->min_tx_power) + continue; + *freq++ = chan->freq; } diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h index b8f791e56307..49cd3168a2fa 100644 --- a/contrib/wpa/src/ap/ap_config.h +++ b/contrib/wpa/src/ap/ap_config.h @@ -51,6 +51,7 @@ struct mesh_conf { int dot11MeshRetryTimeout; /* msec */ int dot11MeshConfirmTimeout; /* msec */ int dot11MeshHoldingTimeout; /* msec */ + int mesh_fwding; }; #define MAX_STA_COUNT 2007 @@ -696,6 +697,7 @@ struct hostapd_bss_config { #define MESH_ENABLED BIT(0) int mesh; + int mesh_fwding; u8 radio_measurements[RRM_CAPABILITIES_IE_LEN]; @@ -953,6 +955,7 @@ struct hostapd_config { struct wpa_freq_range_list acs_freq_list; u8 acs_freq_list_present; int acs_exclude_dfs; + u8 min_tx_power; enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ int acs_exclude_6ghz_non_psc; enum { diff --git a/contrib/wpa/src/ap/ap_drv_ops.c b/contrib/wpa/src/ap/ap_drv_ops.c index d1642d7dff15..e917736664bd 100644 --- a/contrib/wpa/src/ap/ap_drv_ops.c +++ b/contrib/wpa/src/ap/ap_drv_ops.c @@ -888,7 +888,8 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, continue; if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && !(hapd->iface->conf->acs_exclude_dfs && - (chan->flag & HOSTAPD_CHAN_RADAR))) + (chan->flag & HOSTAPD_CHAN_RADAR)) && + !(chan->max_tx_power < hapd->iface->conf->min_tx_power)) int_array_add_unique(freq_list, chan->freq); } } diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c index 22782f54e480..8cd1c417043e 100644 --- a/contrib/wpa/src/ap/beacon.c +++ b/contrib/wpa/src/ap/beacon.c @@ -570,9 +570,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_txpower_envelope(hapd, pos); #endif /* CONFIG_IEEE80211AX */ - if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) || - (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)) - pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); + pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP); pos = hostapd_eid_fils_indic(hapd, pos, 0); @@ -1594,9 +1592,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_txpower_envelope(hapd, tailpos); #endif /* CONFIG_IEEE80211AX */ - if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) || - (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)) - tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); + tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON); tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); diff --git a/contrib/wpa/src/ap/dfs.c b/contrib/wpa/src/ap/dfs.c index 03c99b175215..5c99ecfd017e 100644 --- a/contrib/wpa/src/ap/dfs.c +++ b/contrib/wpa/src/ap/dfs.c @@ -246,6 +246,9 @@ static int dfs_find_channel(struct hostapd_iface *iface, continue; } + if (chan->max_tx_power < iface->conf->min_tx_power) + continue; + if (ret_chan && idx == channel_idx) { wpa_printf(MSG_DEBUG, "Selected channel %d (%d)", chan->freq, chan->chan); diff --git a/contrib/wpa/src/ap/dpp_hostapd.c b/contrib/wpa/src/ap/dpp_hostapd.c index 41769f475544..13e1fc5bdd96 100644 --- a/contrib/wpa/src/ap/dpp_hostapd.c +++ b/contrib/wpa/src/ap/dpp_hostapd.c @@ -1554,17 +1554,38 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd, #ifdef CONFIG_TESTING_OPTIONS skip_connector: + if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); + goto skip_proto_ver; + } #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_DPP2 if (DPP_VERSION > 1) { + u8 ver = DPP_VERSION; +#ifdef CONFIG_DPP3 + int conn_ver; + + conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector); + if (conn_ver > 0 && ver != conn_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Use Connector version %d instead of current protocol version %d", + conn_ver, ver); + ver = conn_ver; + } +#endif /* CONFIG_DPP3 */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, DPP_VERSION); + wpabuf_put_u8(msg, ver); } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_TESTING_OPTIONS +skip_proto_ver: +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR " status=%d", MAC2STR(src), status); wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR @@ -1648,6 +1669,28 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, return; } +#ifdef CONFIG_DPP3 + if (intro.peer_version && intro.peer_version >= 2) { + const u8 *version; + u16 version_len; + u8 attr_version = 1; + + version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, + &version_len); + if (version && version_len >= 1) + attr_version = version[0]; + if (attr_version != intro.peer_version) { + wpa_printf(MSG_INFO, + "DPP: Protocol version mismatch (Connector: %d Attribute: %d", + intro.peer_version, attr_version); + hostapd_dpp_send_peer_disc_resp(hapd, src, freq, + trans_id[0], + DPP_STATUS_NO_MATCH); + return; + } + } +#endif /* CONFIG_DPP3 */ + if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire) expire = hapd->conf->dpp_netaccesskey_expiry; if (expire) @@ -1670,7 +1713,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, static void hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, const u8 *buf, size_t len, - unsigned int freq) + unsigned int freq, bool v2) { struct wpabuf *msg; @@ -1698,7 +1741,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, hapd->own_addr, src, hapd->dpp_pkex_identifier, hapd->dpp_pkex_code, - buf, len); + buf, len, v2); if (!hapd->dpp_pkex) { wpa_printf(MSG_DEBUG, "DPP: Failed to process the request - ignore it"); @@ -1910,8 +1953,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, case DPP_PA_PEER_DISCOVERY_REQ: hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq); break; +#ifdef CONFIG_DPP3 case DPP_PA_PKEX_EXCHANGE_REQ: - hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq); + /* This is for PKEXv2, but for now, process only with + * CONFIG_DPP3 to avoid issues with a capability that has not + * been tested with other implementations. */ + hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq, + true); + break; +#endif /* CONFIG_DPP3 */ + case DPP_PA_PKEX_V1_EXCHANGE_REQ: + hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq, + false); break; case DPP_PA_PKEX_EXCHANGE_RESP: hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq); @@ -2118,15 +2171,16 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) if (!hapd->dpp_pkex_code) return -1; - if (os_strstr(cmd, " init=1")) { + if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) { struct wpabuf *msg; + bool v2 = os_strstr(cmd, " init=2") != NULL; wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); dpp_pkex_free(hapd->dpp_pkex); hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi, hapd->own_addr, hapd->dpp_pkex_identifier, - hapd->dpp_pkex_code); + hapd->dpp_pkex_code, v2); if (!hapd->dpp_pkex) return -1; @@ -2134,7 +2188,8 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) /* TODO: Which channel to use? */ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", MAC2STR(broadcast), 2437, - DPP_PA_PKEX_EXCHANGE_REQ); + v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); hostapd_drv_send_action(hapd, 2437, 0, broadcast, wpabuf_head(msg), wpabuf_len(msg)); } diff --git a/contrib/wpa/src/ap/drv_callbacks.c b/contrib/wpa/src/ap/drv_callbacks.c index ec5abf166b23..a50e6f2afa77 100644 --- a/contrib/wpa/src/ap/drv_callbacks.c +++ b/contrib/wpa/src/ap/drv_callbacks.c @@ -957,6 +957,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->ch_switch_vht_config = 0; hapd->iconf->ch_switch_he_config = 0; + if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 || + width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160) + hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; + else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT) + hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; + hapd->iconf->secondary_channel = offset; hostapd_set_oper_chwidth(hapd->iconf, chwidth); hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx); diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c index 913a8e29e16d..4b88641a2dde 100644 --- a/contrib/wpa/src/ap/hostapd.c +++ b/contrib/wpa/src/ap/hostapd.c @@ -3461,6 +3461,20 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, NULL)) return -1; + switch (params->bandwidth) { + case 0: + case 20: + conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; + break; + case 40: + case 80: + case 160: + conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; + break; + default: + return -1; + } + switch (params->bandwidth) { case 0: case 20: @@ -3482,6 +3496,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, conf->channel = channel; conf->ieee80211n = params->ht_enabled; + conf->ieee80211ac = params->vht_enabled; conf->secondary_channel = params->sec_channel_offset; ieee80211_freq_to_chan(params->center_freq1, &seg0); diff --git a/contrib/wpa/src/common/dpp.c b/contrib/wpa/src/common/dpp.c index 1fd074f05627..ac6eae4c893e 100644 --- a/contrib/wpa/src/common/dpp.c +++ b/contrib/wpa/src/common/dpp.c @@ -28,7 +28,9 @@ static const char * dpp_netrole_str(enum dpp_netrole netrole); #ifdef CONFIG_TESTING_OPTIONS -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 +int dpp_version_override = 3; +#elif defined(CONFIG_DPP2) int dpp_version_override = 2; #else int dpp_version_override = 1; @@ -306,6 +308,8 @@ int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version) bi->version = 1; else if (*version == '2') bi->version = 2; + else if (*version == '3') + bi->version = 3; else wpa_printf(MSG_DEBUG, "DPP: Unknown URI version"); @@ -628,7 +632,8 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) macstr, bi->info ? "I:" : "", bi->info ? bi->info : "", bi->info ? ";" : "", - DPP_VERSION == 2 ? "V:2;" : "", + DPP_VERSION == 3 ? "V:3;" : + (DPP_VERSION == 2 ? "V:2;" : ""), bi->pk); return 0; } @@ -1499,6 +1504,10 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, json_value_sep(dppcon); json_add_string(dppcon, "expiry", expiry); } +#ifdef CONFIG_DPP3 + json_value_sep(dppcon); + json_add_int(dppcon, "version", auth->peer_version); +#endif /* CONFIG_DPP3 */ json_end_object(dppcon); wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", (const char *) wpabuf_head(dppcon)); @@ -3694,6 +3703,14 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, } } +#ifdef CONFIG_DPP3 + token = json_get_member(root, "version"); + if (token && token->type == JSON_NUMBER) { + wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number); + intro->peer_version = token->number; + } +#endif /* CONFIG_DPP3 */ + netkey = json_get_member(root, "netAccessKey"); if (!netkey || netkey->type != JSON_OBJECT) { wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); @@ -3751,6 +3768,26 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, } +#ifdef CONFIG_DPP3 +int dpp_get_connector_version(const char *connector) +{ + struct json_token *root, *token; + int ver = -1; + + root = dpp_parse_own_connector(connector); + if (!root) + return -1; + + token = json_get_member(root, "version"); + if (token && token->type == JSON_NUMBER) + ver = token->number; + + json_free(root); + return ver; +} +#endif /* CONFIG_DPP3 */ + + unsigned int dpp_next_id(struct dpp_global *dpp) { struct dpp_bootstrap_info *bi; diff --git a/contrib/wpa/src/common/dpp.h b/contrib/wpa/src/common/dpp.h index a47c685f64b9..8d62a0e2ac3b 100644 --- a/contrib/wpa/src/common/dpp.h +++ b/contrib/wpa/src/common/dpp.h @@ -25,7 +25,9 @@ struct dpp_reconfig_id; #define DPP_VERSION (dpp_version_override) extern int dpp_version_override; #else /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 +#define DPP_VERSION 3 +#elif defined(CONFIG_DPP2) #define DPP_VERSION 2 #else #define DPP_VERSION 1 @@ -41,7 +43,7 @@ enum dpp_public_action_frame_type { DPP_PA_AUTHENTICATION_CONF = 2, DPP_PA_PEER_DISCOVERY_REQ = 5, DPP_PA_PEER_DISCOVERY_RESP = 6, - DPP_PA_PKEX_EXCHANGE_REQ = 7, + DPP_PA_PKEX_V1_EXCHANGE_REQ = 7, DPP_PA_PKEX_EXCHANGE_RESP = 8, DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9, DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10, @@ -52,6 +54,7 @@ enum dpp_public_action_frame_type { DPP_PA_RECONFIG_AUTH_REQ = 15, DPP_PA_RECONFIG_AUTH_RESP = 16, DPP_PA_RECONFIG_AUTH_CONF = 17, + DPP_PA_PKEX_EXCHANGE_REQ = 18, }; enum dpp_attribute_id { @@ -173,6 +176,7 @@ struct dpp_pkex { unsigned int initiator:1; unsigned int exchange_done:1; unsigned int failed:1; + unsigned int v2:1; struct dpp_bootstrap_info *own_bi; u8 own_mac[ETH_ALEN]; u8 peer_mac[ETH_ALEN]; @@ -190,6 +194,7 @@ struct dpp_pkex { unsigned int exch_req_wait_time; unsigned int exch_req_tries; unsigned int freq; + u8 peer_version; }; enum dpp_akm { @@ -372,6 +377,7 @@ struct dpp_introduction { u8 pmkid[PMKID_LEN]; u8 pmk[PMK_LEN_MAX]; size_t pmk_len; + int peer_version; }; struct dpp_relay_config { @@ -491,6 +497,8 @@ enum dpp_test_behavior { DPP_TEST_STOP_AT_AUTH_CONF = 89, DPP_TEST_STOP_AT_CONF_REQ = 90, DPP_TEST_REJECT_CONFIG = 91, + DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ = 92, + DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93, }; extern enum dpp_test_behavior dpp_test; @@ -593,17 +601,18 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, const u8 *csign_key, size_t csign_key_len, const u8 *peer_connector, size_t peer_connector_len, os_time_t *expiry); +int dpp_get_connector_version(const char *connector); struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, - const char *identifier, - const char *code); + const char *identifier, const char *code, + bool v2); struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, const u8 *peer_mac, const char *identifier, const char *code, - const u8 *buf, size_t len); + const u8 *buf, size_t len, bool v2); struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, const u8 *peer_mac, const u8 *buf, size_t len); diff --git a/contrib/wpa/src/common/dpp_crypto.c b/contrib/wpa/src/common/dpp_crypto.c index da59730eb7b7..300416fb12ec 100644 --- a/contrib/wpa/src/common/dpp_crypto.c +++ b/contrib/wpa/src/common/dpp_crypto.c @@ -1447,12 +1447,15 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, struct crypto_bignum *hash_bn = NULL; struct crypto_ec *ec = NULL; - /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ + /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ - wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init)); - addr[num_elem] = mac_init; - len[num_elem] = ETH_ALEN; - num_elem++; + if (mac_init) { + wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, + MAC2STR(mac_init)); + addr[num_elem] = mac_init; + len[num_elem] = ETH_ALEN; + num_elem++; + } if (identifier) { wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", identifier); @@ -1467,7 +1470,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) goto fail; wpa_hexdump_key(MSG_DEBUG, - "DPP: H(MAC-Initiator | [identifier |] code)", + "DPP: H([MAC-Initiator |] [identifier |] code)", hash, curve->hash_len); Pi_key = dpp_pkex_get_role_elem(curve, 1); if (!Pi_key) @@ -1519,12 +1522,15 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, struct crypto_bignum *hash_bn = NULL; struct crypto_ec *ec = NULL; - /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ + /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ - wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp)); - addr[num_elem] = mac_resp; - len[num_elem] = ETH_ALEN; - num_elem++; + if (mac_resp) { + wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, + MAC2STR(mac_resp)); + addr[num_elem] = mac_resp; + len[num_elem] = ETH_ALEN; + num_elem++; + } if (identifier) { wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", identifier); @@ -1539,7 +1545,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) goto fail; wpa_hexdump_key(MSG_DEBUG, - "DPP: H(MAC-Responder | [identifier |] code)", + "DPP: H([MAC-Responder |] [identifier |] code)", hash, curve->hash_len); Pr_key = dpp_pkex_get_role_elem(curve, 0); if (!Pr_key) @@ -1578,6 +1584,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, + u8 ver_init, u8 ver_resp, const u8 *Mx, size_t Mx_len, const u8 *Nx, size_t Nx_len, const char *code, @@ -1589,7 +1596,10 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, u8 *info, *pos; size_t info_len; - /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) + /* + * v1: info = MAC-Initiator | MAC-Responder + * v2: info = Protocol Version-Initiator | Protocol Version-Responder + * z = HKDF(<>, info | M.x | N.x | code, K.x) */ /* HKDF-Extract(<>, IKM=K.x) */ @@ -1598,15 +1608,24 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, return -1; wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", prk, hash_len); - info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code); + if (mac_init && mac_resp) + info_len = 2 * ETH_ALEN; + else + info_len = 2; + info_len += Mx_len + Nx_len + os_strlen(code); info = os_malloc(info_len); if (!info) return -1; pos = info; - os_memcpy(pos, mac_init, ETH_ALEN); - pos += ETH_ALEN; - os_memcpy(pos, mac_resp, ETH_ALEN); - pos += ETH_ALEN; + if (mac_init && mac_resp) { + os_memcpy(pos, mac_init, ETH_ALEN); + pos += ETH_ALEN; + os_memcpy(pos, mac_resp, ETH_ALEN); + pos += ETH_ALEN; + } else { + *pos++ = ver_init; + *pos++ = ver_resp; + } os_memcpy(pos, Mx, Mx_len); pos += Mx_len; os_memcpy(pos, Nx, Nx_len); diff --git a/contrib/wpa/src/common/dpp_i.h b/contrib/wpa/src/common/dpp_i.h index 087878a508cb..c00b1ee41240 100644 --- a/contrib/wpa/src/common/dpp_i.h +++ b/contrib/wpa/src/common/dpp_i.h @@ -118,6 +118,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, const char *code, const char *identifier, struct crypto_ec **ret_ec); int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, + u8 ver_init, u8 ver_resp, const u8 *Mx, size_t Mx_len, const u8 *Nx, size_t Nx_len, const char *code, diff --git a/contrib/wpa/src/common/dpp_pkex.c b/contrib/wpa/src/common/dpp_pkex.c index 06532b5457bd..38349fa3f540 100644 --- a/contrib/wpa/src/common/dpp_pkex.c +++ b/contrib/wpa/src/common/dpp_pkex.c @@ -26,7 +26,8 @@ size_t dpp_pkex_ephemeral_key_override_len = 0; #endif /* CONFIG_TESTING_OPTIONS */ -static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex) +static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex, + bool v2) { struct crypto_ec *ec = NULL; const struct crypto_ec_point *X; @@ -36,10 +37,11 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex) size_t attr_len; const struct dpp_curve_params *curve = pkex->own_bi->curve; - wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request"); + wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request", + v2 ? "" : "Version 1 "); - /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ - Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code, + /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ + Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code, pkex->identifier, &ec); if (!Qi) goto fail; @@ -76,13 +78,27 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex) /* Initiator -> Responder: group, [identifier,] M */ attr_len = 4 + 2; +#ifdef CONFIG_DPP2 + if (v2) + attr_len += 4 + 1; +#endif /* CONFIG_DPP2 */ if (pkex->identifier) attr_len += 4 + os_strlen(pkex->identifier); attr_len += 4 + 2 * curve->prime_len; - msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len); + msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len); if (!msg) goto fail; +#ifdef CONFIG_DPP2 + if (v2) { + /* Protocol Version */ + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, DPP_VERSION); + } +#endif /* CONFIG_DPP2 */ + #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) { wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group"); @@ -154,8 +170,8 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt) struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, - const char *identifier, - const char *code) + const char *identifier, const char *code, + bool v2) { struct dpp_pkex *pkex; @@ -172,6 +188,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, return NULL; pkex->msg_ctx = msg_ctx; pkex->initiator = 1; + pkex->v2 = v2; pkex->own_bi = bi; os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); if (identifier) { @@ -182,7 +199,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, pkex->code = os_strdup(code); if (!pkex->code) goto fail; - pkex->exchange_req = dpp_pkex_build_exchange_req(pkex); + pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2); if (!pkex->exchange_req) goto fail; return pkex; @@ -201,8 +218,13 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex, size_t attr_len; const struct dpp_curve_params *curve = pkex->own_bi->curve; - /* Initiator -> Responder: DPP Status, [identifier,] N */ + /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,] + * N */ attr_len = 4 + 1; +#ifdef CONFIG_DPP2 + if (pkex->v2) + attr_len += 4 + 1; +#endif /* CONFIG_DPP2 */ if (pkex->identifier) attr_len += 4 + os_strlen(pkex->identifier); attr_len += 4 + 2 * curve->prime_len; @@ -229,6 +251,15 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex, skip_status: #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_DPP2 + if (pkex->v2) { + /* Protocol Version */ + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, DPP_VERSION); + } +#endif /* CONFIG_DPP2 */ + /* Code Identifier attribute */ if (pkex->identifier) { wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); @@ -310,7 +341,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, const u8 *peer_mac, const char *identifier, const char *code, - const u8 *buf, size_t len) + const u8 *buf, size_t len, bool v2) { const u8 *attr_group, *attr_id, *attr_key; u16 attr_group_len, attr_id_len, attr_key_len; @@ -325,6 +356,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, u8 Kx[DPP_MAX_SHARED_SECRET_LEN]; size_t Kx_len; int res; + u8 peer_version = 0; if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) { wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL @@ -332,6 +364,24 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, return NULL; } +#ifdef CONFIG_DPP2 + if (v2) { + const u8 *version; + u16 version_len; + + version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, + &version_len); + if (!version || version_len < 1 || version[0] == 0) { + wpa_msg(msg_ctx, MSG_INFO, + "Missing or invalid Protocol Version attribute"); + return NULL; + } + peer_version = version[0]; + wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", + peer_version); + } +#endif /* CONFIG_DPP2 */ + #ifdef CONFIG_TESTING_OPTIONS if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, @@ -366,6 +416,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, pkex = os_zalloc(sizeof(*pkex)); if (!pkex) goto fail; + pkex->v2 = v2; + pkex->peer_version = peer_version; pkex->own_bi = bi; pkex->failed = 1; pkex->exchange_resp = dpp_pkex_build_exchange_resp( @@ -385,8 +437,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, return NULL; } - /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ - Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, &ec); + /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ + Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier, + &ec); if (!Qi) goto fail; @@ -411,6 +464,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, pkex = os_zalloc(sizeof(*pkex)); if (!pkex) goto fail; + pkex->v2 = v2; + pkex->peer_version = peer_version; pkex->t = bi->pkex_t; pkex->msg_ctx = msg_ctx; pkex->own_bi = bi; @@ -438,8 +493,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, if (!pkex->x) goto fail; - /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ - Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, NULL); + /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ + Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier, + NULL); if (!Qr) goto fail; @@ -487,9 +543,10 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", Kx, Kx_len); - /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) - */ - res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac, + /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ + res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac, + pkex->v2 ? NULL : pkex->own_mac, + pkex->peer_version, DPP_VERSION, pkex->Mx, curve->prime_len, pkex->Nx, curve->prime_len, pkex->code, Kx, Kx_len, pkex->z, curve->hash_len); @@ -645,6 +702,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; const u8 *addr[4]; size_t len[4]; + size_t num_elem; u8 u[DPP_MAX_HASH_LEN]; int res; @@ -666,6 +724,24 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, } #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_DPP2 + if (pkex->v2) { + const u8 *version; + u16 version_len; + + version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION, + &version_len); + if (!version || version_len < 1 || version[0] == 0) { + dpp_pkex_fail(pkex, + "Missing or invalid Protocol Version attribute"); + return NULL; + } + pkex->peer_version = version[0]; + wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", + pkex->peer_version); + } +#endif /* CONFIG_DPP2 */ + os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, @@ -710,9 +786,9 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, return NULL; } - /* Qr = H(MAC-Responder | [identifier |] code) * Pr */ - Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code, - pkex->identifier, &ec); + /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ + Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac, + pkex->code, pkex->identifier, &ec); if (!Qr) goto fail; @@ -751,21 +827,29 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", Jx, Jx_len); - /* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x) */ + /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */ A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); if (!A_pub || !Y_pub || !X_pub) goto fail; - addr[0] = pkex->own_mac; - len[0] = ETH_ALEN; - addr[1] = wpabuf_head(A_pub); - len[1] = wpabuf_len(A_pub) / 2; - addr[2] = wpabuf_head(Y_pub); - len[2] = wpabuf_len(Y_pub) / 2; - addr[3] = wpabuf_head(X_pub); - len[3] = wpabuf_len(X_pub) / 2; - if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) + num_elem = 0; + if (!pkex->v2) { + addr[num_elem] = pkex->own_mac; + len[num_elem] = ETH_ALEN; + num_elem++; + } + addr[num_elem] = wpabuf_head(A_pub); + len[num_elem] = wpabuf_len(A_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(Y_pub); + len[num_elem] = wpabuf_len(Y_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(X_pub); + len[num_elem] = wpabuf_len(X_pub) / 2; + num_elem++; + if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) + < 0) goto fail; wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len); @@ -776,9 +860,10 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", Kx, Kx_len); - /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) - */ - res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac, + /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ + res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac, + pkex->v2 ? NULL : pkex->peer_mac, + DPP_VERSION, pkex->peer_version, pkex->Mx, curve->prime_len, attr_key /* N.x */, attr_key_len / 2, pkex->code, Kx, Kx_len, @@ -933,6 +1018,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, u16 wrapped_data_len, b_key_len, peer_u_len = 0; const u8 *addr[4]; size_t len[4]; + size_t num_elem; u8 octet; u8 *unwrapped = NULL; size_t unwrapped_len = 0; @@ -1015,21 +1101,29 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", Jx, Jx_len); - /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */ + /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */ A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); if (!A_pub || !Y_pub || !X_pub) goto fail; - addr[0] = pkex->peer_mac; - len[0] = ETH_ALEN; - addr[1] = wpabuf_head(A_pub); - len[1] = wpabuf_len(A_pub) / 2; - addr[2] = wpabuf_head(Y_pub); - len[2] = wpabuf_len(Y_pub) / 2; - addr[3] = wpabuf_head(X_pub); - len[3] = wpabuf_len(X_pub) / 2; - if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) + num_elem = 0; + if (!pkex->v2) { + addr[num_elem] = pkex->peer_mac; + len[num_elem] = ETH_ALEN; + num_elem++; + } + addr[num_elem] = wpabuf_head(A_pub); + len[num_elem] = wpabuf_len(A_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(Y_pub); + len[num_elem] = wpabuf_len(Y_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(X_pub); + len[num_elem] = wpabuf_len(X_pub) / 2; + num_elem++; + if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) + < 0) goto fail; peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, @@ -1052,19 +1146,27 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", Lx, Lx_len); - /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */ + /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */ B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); if (!B_pub) goto fail; - addr[0] = pkex->own_mac; - len[0] = ETH_ALEN; - addr[1] = wpabuf_head(B_pub); - len[1] = wpabuf_len(B_pub) / 2; - addr[2] = wpabuf_head(X_pub); - len[2] = wpabuf_len(X_pub) / 2; - addr[3] = wpabuf_head(Y_pub); - len[3] = wpabuf_len(Y_pub) / 2; - if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) + num_elem = 0; + if (!pkex->v2) { + addr[num_elem] = pkex->own_mac; + len[num_elem] = ETH_ALEN; + num_elem++; + } + addr[num_elem] = wpabuf_head(B_pub); + len[num_elem] = wpabuf_len(B_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(X_pub); + len[num_elem] = wpabuf_len(X_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(Y_pub); + len[num_elem] = wpabuf_len(Y_pub) / 2; + num_elem++; + if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) + < 0) goto fail; wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len); @@ -1094,6 +1196,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, u16 wrapped_data_len, b_key_len, peer_v_len = 0; const u8 *addr[4]; size_t len[4]; + size_t num_elem; u8 octet; u8 *unwrapped = NULL; size_t unwrapped_len = 0; @@ -1177,21 +1280,29 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", Lx, Lx_len); - /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */ + /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */ B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); if (!B_pub || !X_pub || !Y_pub) goto fail; - addr[0] = pkex->peer_mac; - len[0] = ETH_ALEN; - addr[1] = wpabuf_head(B_pub); - len[1] = wpabuf_len(B_pub) / 2; - addr[2] = wpabuf_head(X_pub); - len[2] = wpabuf_len(X_pub) / 2; - addr[3] = wpabuf_head(Y_pub); - len[3] = wpabuf_len(Y_pub) / 2; - if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) + num_elem = 0; + if (!pkex->v2) { + addr[num_elem] = pkex->peer_mac; + len[num_elem] = ETH_ALEN; + num_elem++; + } + addr[num_elem] = wpabuf_head(B_pub); + len[num_elem] = wpabuf_len(B_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(X_pub); + len[num_elem] = wpabuf_len(X_pub) / 2; + num_elem++; + addr[num_elem] = wpabuf_head(Y_pub); + len[num_elem] = wpabuf_len(Y_pub) / 2; + num_elem++; + if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) + < 0) goto fail; peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG, diff --git a/contrib/wpa/src/common/hw_features_common.c b/contrib/wpa/src/common/hw_features_common.c index e7ac3b2aac6b..f168d4e9290f 100644 --- a/contrib/wpa/src/common/hw_features_common.c +++ b/contrib/wpa/src/common/hw_features_common.c @@ -293,87 +293,12 @@ static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, } -/* - * Returns: - * 0: no impact - * 1: overlapping BSS - * 2: overlapping BSS with 40 MHz intolerant advertisement - */ -int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq) -{ - int affected_start, affected_end; - struct ieee802_11_elems elems; - int pri_chan, sec_chan; - int pri = bss->freq; - int sec = pri; - - if (pri_freq == sec_freq) - return 1; - - affected_start = (pri_freq + sec_freq) / 2 - 25; - affected_end = (pri_freq + sec_freq) / 2 + 25; - - /* Check for overlapping 20 MHz BSS */ - if (check_20mhz_bss(bss, pri_freq, affected_start, affected_end)) { - wpa_printf(MSG_DEBUG, "Overlapping 20 MHz BSS is found"); - return 1; - } - - get_pri_sec_chan(bss, &pri_chan, &sec_chan); - - if (sec_chan) { - if (sec_chan < pri_chan) - sec = pri - 20; - else - sec = pri + 20; - } - - if ((pri < affected_start || pri > affected_end) && - (sec < affected_start || sec > affected_end)) - return 0; /* not within affected channel range */ - - wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR - " freq=%d pri=%d sec=%d", - MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); - - if (sec_chan) { - if (pri_freq != pri || sec_freq != sec) { - wpa_printf(MSG_DEBUG, - "40 MHz pri/sec mismatch with BSS " - MACSTR - " <%d,%d> (chan=%d%c) vs. <%d,%d>", - MAC2STR(bss->bssid), - pri, sec, pri_chan, - sec > pri ? '+' : '-', - pri_freq, sec_freq); - return 1; - } - } - - ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); - if (elems.ht_capabilities) { - struct ieee80211_ht_capabilities *ht_cap = - (struct ieee80211_ht_capabilities *) - elems.ht_capabilities; - - if (le_to_host16(ht_cap->ht_capabilities_info) & - HT_CAP_INFO_40MHZ_INTOLERANT) { - wpa_printf(MSG_DEBUG, - "40 MHz Intolerant is set on channel %d in BSS " - MACSTR, pri, MAC2STR(bss->bssid)); - return 2; - } - } - - return 0; -} - - int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan) { int pri_freq, sec_freq; + int affected_start, affected_end; size_t i; if (!mode || !scan_res || !pri_chan || !sec_chan || @@ -383,12 +308,70 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, pri_freq = hw_get_freq(mode, pri_chan); sec_freq = hw_get_freq(mode, sec_chan); + affected_start = (pri_freq + sec_freq) / 2 - 25; + affected_end = (pri_freq + sec_freq) / 2 + 25; wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", - (pri_freq + sec_freq) / 2 - 25, - (pri_freq + sec_freq) / 2 + 25); + affected_start, affected_end); for (i = 0; i < scan_res->num; i++) { - if (check_bss_coex_40mhz(scan_res->res[i], pri_freq, sec_freq)) + struct wpa_scan_res *bss = scan_res->res[i]; + int pri = bss->freq; + int sec = pri; + struct ieee802_11_elems elems; + + /* Check for overlapping 20 MHz BSS */ + if (check_20mhz_bss(bss, pri_freq, affected_start, + affected_end)) { + wpa_printf(MSG_DEBUG, + "Overlapping 20 MHz BSS is found"); return 0; + } + + get_pri_sec_chan(bss, &pri_chan, &sec_chan); + + if (sec_chan) { + if (sec_chan < pri_chan) + sec = pri - 20; + else + sec = pri + 20; + } + + if ((pri < affected_start || pri > affected_end) && + (sec < affected_start || sec > affected_end)) + continue; /* not within affected channel range */ + + wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR + " freq=%d pri=%d sec=%d", + MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); + + if (sec_chan) { + if (pri_freq != pri || sec_freq != sec) { + wpa_printf(MSG_DEBUG, + "40 MHz pri/sec mismatch with BSS " + MACSTR + " <%d,%d> (chan=%d%c) vs. <%d,%d>", + MAC2STR(bss->bssid), + pri, sec, pri_chan, + sec > pri ? '+' : '-', + pri_freq, sec_freq); + return 0; + } + } + + ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, + 0); + if (elems.ht_capabilities) { + struct ieee80211_ht_capabilities *ht_cap = + (struct ieee80211_ht_capabilities *) + elems.ht_capabilities; + + if (le_to_host16(ht_cap->ht_capabilities_info) & + HT_CAP_INFO_40MHZ_INTOLERANT) { + wpa_printf(MSG_DEBUG, + "40 MHz Intolerant is set on channel %d in BSS " + MACSTR, pri, MAC2STR(bss->bssid)); + return 0; + } + } } return 1; diff --git a/contrib/wpa/src/common/hw_features_common.h b/contrib/wpa/src/common/hw_features_common.h index ddde36b99263..0e92aa0f2bc5 100644 --- a/contrib/wpa/src/common/hw_features_common.h +++ b/contrib/wpa/src/common/hw_features_common.h @@ -32,7 +32,6 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan); int check_40mhz_5g(struct wpa_scan_results *scan_res, struct hostapd_channel_data *pri_chan, struct hostapd_channel_data *sec_chan); -int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq); int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan); diff --git a/contrib/wpa/src/common/qca-vendor.h b/contrib/wpa/src/common/qca-vendor.h index 4dac10ef9724..d9eab0212e73 100644 --- a/contrib/wpa/src/common/qca-vendor.h +++ b/contrib/wpa/src/common/qca-vendor.h @@ -622,7 +622,14 @@ enum qca_radiotap_vendor_ids { * This new command is alternative to existing command * QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event * is using stream of bytes instead of structured data using vendor - * attributes. + * attributes. User space sends unsafe frequency ranges to the driver using + * a nested attribute %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE. On + * reception of this command, the driver shall check if an interface is + * operating on an unsafe frequency and the driver shall try to move to a + * safe channel when needed. If the driver is not able to find a safe + * channel the interface can keep operating on an unsafe channel with the + * TX power limit derived based on internal configurations like + * regulatory/SAR rules. * * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to * add the STA node details in driver/firmware. Attributes for this event @@ -10316,20 +10323,48 @@ enum qca_wlan_vendor_attr_oem_data_params { * * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE: Required * Nested attribute containing multiple ranges with following attributes: - * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and - * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END. + * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START, + * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END, and + * QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM. * * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START: Required (u32) * Starting center frequency in MHz. * * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END: Required (u32) * Ending center frequency in MHz. + * + * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM: + * s32 attribute, optional. It is a per frequency range attribute. + * The maximum TX power limit from user space is to be applied on an + * unrestricted interface for corresponding frequency range. It is also + * possible that the actual TX power may be even lower than this cap due to + * other considerations such as regulatory compliance, SAR, etc. In absence of + * this attribute the driver shall follow current behavior which means + * interface (SAP/P2P) function can keep operating on an unsafe channel with TX + * power derived by the driver based on regulatory/SAR during interface up. + * + * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK: + * u32 attribute, optional. Indicates all the interface types which are + * restricted for all frequency ranges provided in + * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START and + * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END. + * This attribute encapsulates bitmasks of interface types defined in + * enum nl80211_iftype. If an interface is marked as restricted the driver must + * move to a safe channel and if no safe channel is available the driver shall + * terminate that interface functionality. In absence of this attribute, + * interface (SAP/P2P) can still continue operating on an unsafe channel with + * TX power limit derived from either + * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM or based on + * regulatory/SAE limits if %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM + * is not provided. */ enum qca_wlan_vendor_attr_avoid_frequency_ext { QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE = 1, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START = 2, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3, + QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM = 4, + QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK = 5, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX = diff --git a/contrib/wpa/src/drivers/driver.h b/contrib/wpa/src/drivers/driver.h index 2020184c5f94..d3312a34d8f8 100644 --- a/contrib/wpa/src/drivers/driver.h +++ b/contrib/wpa/src/drivers/driver.h @@ -1590,6 +1590,7 @@ struct wpa_driver_mesh_bss_params { #define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004 #define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008 #define WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD 0x00000010 +#define WPA_DRIVER_MESH_CONF_FLAG_FORWARDING 0x00000020 /* * TODO: Other mesh configuration parameters would go here. * See NL80211_MESHCONF_* for all the mesh config parameters. @@ -1599,6 +1600,7 @@ struct wpa_driver_mesh_bss_params { int peer_link_timeout; int max_peer_links; int rssi_threshold; + int forwarding; u16 ht_opmode; }; diff --git a/contrib/wpa/src/drivers/driver_nl80211.c b/contrib/wpa/src/drivers/driver_nl80211.c index 9a9a146f7ea1..aec179ac38cf 100644 --- a/contrib/wpa/src/drivers/driver_nl80211.c +++ b/contrib/wpa/src/drivers/driver_nl80211.c @@ -10475,6 +10475,9 @@ static int nl80211_put_mesh_config(struct nl_msg *msg, if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) && nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, params->auto_plinks)) || + ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_FORWARDING) && + nla_put_u8(msg, NL80211_MESHCONF_FORWARDING, + params->forwarding)) || ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) && nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, params->max_peer_links)) || diff --git a/contrib/wpa/tests/hwsim/test_dpp3.py b/contrib/wpa/tests/hwsim/test_dpp3.py new file mode 100644 index 000000000000..e50f199f385f --- /dev/null +++ b/contrib/wpa/tests/hwsim/test_dpp3.py @@ -0,0 +1,49 @@ +# Test cases for Device Provisioning Protocol (DPP) version 3 +# Copyright (c) 2021, Qualcomm Innovation Center, Inc. +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +from test_dpp import check_dpp_capab, run_dpp_auto_connect + +def test_dpp_network_intro_version(dev, apdev): + """DPP Network Introduction and protocol version""" + check_dpp_capab(dev[0], min_ver=3) + + try: + id, hapd = run_dpp_auto_connect(dev, apdev, 1, stop_after_prov=True) + dev[0].select_network(id, freq=2412) + dev[0].wait_connected() + finally: + dev[0].set("dpp_config_processing", "0", allow_fail=True) + +def test_dpp_network_intro_version_change(dev, apdev): + """DPP Network Introduction and protocol version change""" + check_dpp_capab(dev[0], min_ver=3) + + try: + dev[0].set("dpp_version_override", "2") + id, hapd = run_dpp_auto_connect(dev, apdev, 1, stop_after_prov=True) + dev[0].set("dpp_version_override", "3") + dev[0].select_network(id, freq=2412) + dev[0].wait_connected() + finally: + dev[0].set("dpp_config_processing", "0", allow_fail=True) + +def test_dpp_network_intro_version_missing_req(dev, apdev): + """DPP Network Introduction and protocol version missing from request""" + check_dpp_capab(dev[0], min_ver=3) + + try: + dev[0].set("dpp_version_override", "2") + id, hapd = run_dpp_auto_connect(dev, apdev, 1, stop_after_prov=True) + dev[0].set("dpp_version_override", "3") + dev[0].set("dpp_test", "92") + dev[0].select_network(id, freq=2412) + ev = dev[0].wait_event(["DPP-INTRO"], timeout=10) + if ev is None: + raise Exception("DPP network introduction result not seen on STA") + if "status=8" not in ev: + raise Exception("Unexpected network introduction result on STA: " + ev) + finally: + dev[0].set("dpp_config_processing", "0", allow_fail=True) diff --git a/contrib/wpa/wpa_supplicant/Android.mk b/contrib/wpa/wpa_supplicant/Android.mk index 0aacafd4ab96..7e597f396a07 100644 --- a/contrib/wpa/wpa_supplicant/Android.mk +++ b/contrib/wpa/wpa_supplicant/Android.mk @@ -279,6 +279,9 @@ NEED_ASN1=y ifdef CONFIG_DPP2 L_CFLAGS += -DCONFIG_DPP2 endif +ifdef CONFIG_DPP3 +L_CFLAGS += -DCONFIG_DPP3 +endif endif ifdef CONFIG_OWE diff --git a/contrib/wpa/wpa_supplicant/Makefile b/contrib/wpa/wpa_supplicant/Makefile index ce1c8b2e3366..cb66defac7c8 100644 --- a/contrib/wpa/wpa_supplicant/Makefile +++ b/contrib/wpa/wpa_supplicant/Makefile @@ -294,6 +294,9 @@ NEED_ASN1=y ifdef CONFIG_DPP2 CFLAGS += -DCONFIG_DPP2 endif +ifdef CONFIG_DPP3 +CFLAGS += -DCONFIG_DPP3 +endif endif ifdef CONFIG_OWE diff --git a/contrib/wpa/wpa_supplicant/README-HS20 b/contrib/wpa/wpa_supplicant/README-HS20 index 484e4cbf4724..b076621db527 100644 --- a/contrib/wpa/wpa_supplicant/README-HS20 +++ b/contrib/wpa/wpa_supplicant/README-HS20 @@ -286,6 +286,12 @@ Credentials can be pre-configured for automatic network selection: # # sim_num: Identifier for which SIM to use in multi-SIM devices # +# engine: Whether to use an engine for private key operations (0/1) +# engine_id: String identifying the engine to use +# ca_cert_id: The CA certificate identifier when using an engine +# cert_id: The certificate identifier when using an engine +# key_id: The private key identifier when using an engine +# # for example: # #cred={ diff --git a/contrib/wpa/wpa_supplicant/config.c b/contrib/wpa/wpa_supplicant/config.c index c5177d915524..bf062b0792b7 100644 --- a/contrib/wpa/wpa_supplicant/config.c +++ b/contrib/wpa/wpa_supplicant/config.c @@ -2527,6 +2527,7 @@ static const struct parse_data ssid_fields[] = { #ifdef CONFIG_MESH { INT_RANGE(mode, 0, 5) }, { INT_RANGE(no_auto_peer, 0, 1) }, + { INT_RANGE(mesh_fwding, 0, 1) }, { INT_RANGE(mesh_rssi_threshold, -255, 1) }, #else /* CONFIG_MESH */ { INT_RANGE(mode, 0, 4) }, @@ -2855,6 +2856,10 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->client_cert); os_free(cred->private_key); str_clear_free(cred->private_key_passwd); + os_free(cred->engine_id); + os_free(cred->ca_cert_id); + os_free(cred->cert_id); + os_free(cred->key_id); os_free(cred->imsi); str_clear_free(cred->milenage); for (i = 0; i < cred->num_domain; i++) @@ -3107,6 +3112,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT; ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT; ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT; + ssid->mesh_fwding = DEFAULT_MESH_FWDING; ssid->mesh_rssi_threshold = DEFAULT_MESH_RSSI_THRESHOLD; #endif /* CONFIG_MESH */ #ifdef CONFIG_HT_OVERRIDES @@ -3618,6 +3624,11 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "engine") == 0) { + cred->engine = atoi(value); + return 0; + } + val = wpa_config_parse_string(value, &len); if (val == NULL || (os_strcmp(var, "excluded_ssid") != 0 && @@ -3673,6 +3684,30 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "engine_id") == 0) { + os_free(cred->engine_id); + cred->engine_id = val; + return 0; + } + + if (os_strcmp(var, "ca_cert_id") == 0) { + os_free(cred->ca_cert_id); + cred->ca_cert_id = val; + return 0; + } + + if (os_strcmp(var, "cert_id") == 0) { + os_free(cred->cert_id); + cred->cert_id = val; + return 0; + } + + if (os_strcmp(var, "key_id") == 0) { + os_free(cred->key_id); + cred->key_id = val; + return 0; + } + if (os_strcmp(var, "imsi") == 0) { os_free(cred->imsi); cred->imsi = val; @@ -4349,6 +4384,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->user_mpm = DEFAULT_USER_MPM; config->max_peer_links = DEFAULT_MAX_PEER_LINKS; config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY; + config->mesh_fwding = DEFAULT_MESH_FWDING; config->dot11RSNASAERetransPeriod = DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD; config->fast_reauth = DEFAULT_FAST_REAUTH; @@ -5062,6 +5098,7 @@ static const struct global_parse_data global_fields[] = { { INT(user_mpm), 0 }, { INT_RANGE(max_peer_links, 0, 255), 0 }, { INT(mesh_max_inactivity), 0 }, + { INT_RANGE(mesh_fwding, 0, 1), 0 }, { INT(dot11RSNASAERetransPeriod), 0 }, #endif /* CONFIG_MESH */ { INT(disable_scan_offload), 0 }, diff --git a/contrib/wpa/wpa_supplicant/config.h b/contrib/wpa/wpa_supplicant/config.h index 0320d9eebb57..d22ef05fb8ba 100644 --- a/contrib/wpa/wpa_supplicant/config.h +++ b/contrib/wpa/wpa_supplicant/config.h @@ -18,6 +18,7 @@ #define DEFAULT_USER_MPM 1 #define DEFAULT_MAX_PEER_LINKS 99 #define DEFAULT_MESH_MAX_INACTIVITY 300 +#define DEFAULT_MESH_FWDING 1 /* * The default dot11RSNASAERetransPeriod is defined as 40 ms in the standard, * but use 1000 ms in practice to avoid issues on low power CPUs. @@ -179,6 +180,31 @@ struct wpa_cred { */ char *milenage; + /** + * engine - Use an engine for private key operations + */ + int engine; + + /** + * engine_id - String identifying the engine to use + */ + char *engine_id; + + /** + * ca_cert_id - The CA certificate identifier when using an engine + */ + char *ca_cert_id; + + /** + * cert_id - The certificate identifier when using an engine + */ + char *cert_id; + + /** + * key_id - The private key identifier when using an engine + */ + char *key_id; + /** * domain_suffix_match - Constraint for server domain name * @@ -1388,6 +1414,14 @@ struct wpa_config { */ int mesh_max_inactivity; + /** + * mesh_fwding - Mesh network layer-2 forwarding (dot11MeshForwarding) + * + * This controls whether to enable layer-2 forwarding. + * By default: 1: enabled + */ + int mesh_fwding; + /** * dot11RSNASAERetransPeriod - Timeout to retransmit SAE Auth frame * diff --git a/contrib/wpa/wpa_supplicant/config_file.c b/contrib/wpa/wpa_supplicant/config_file.c index 54fb72d8c1f7..6db5010db3a7 100644 --- a/contrib/wpa/wpa_supplicant/config_file.c +++ b/contrib/wpa/wpa_supplicant/config_file.c @@ -769,6 +769,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) #endif /* IEEE8021X_EAPOL */ INT(mode); INT(no_auto_peer); + INT(mesh_fwding); INT(frequency); INT(enable_edmg); INT(edmg_channel); @@ -1026,6 +1027,17 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) if (cred->sim_num != DEFAULT_USER_SELECTED_SIM) fprintf(f, "\tsim_num=%d\n", cred->sim_num); + + if (cred->engine) + fprintf(f, "\tengine=%d\n", cred->engine); + if (cred->engine_id) + fprintf(f, "\tengine_id=\"%s\"\n", cred->engine_id); + if (cred->key_id) + fprintf(f, "\tkey_id=\"%s\"\n", cred->key_id); + if (cred->cert_id) + fprintf(f, "\tcert_id=\"%s\"\n", cred->cert_id); + if (cred->ca_cert_id) + fprintf(f, "\tca_cert_id=\"%s\"\n", cred->ca_cert_id); } @@ -1462,6 +1474,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "mesh_max_inactivity=%d\n", config->mesh_max_inactivity); + if (config->mesh_fwding != DEFAULT_MESH_FWDING) + fprintf(f, "mesh_fwding=%d\n", config->mesh_fwding); + if (config->dot11RSNASAERetransPeriod != DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD) fprintf(f, "dot11RSNASAERetransPeriod=%d\n", diff --git a/contrib/wpa/wpa_supplicant/config_ssid.h b/contrib/wpa/wpa_supplicant/config_ssid.h index 339eead1c333..724534dd0123 100644 --- a/contrib/wpa/wpa_supplicant/config_ssid.h +++ b/contrib/wpa/wpa_supplicant/config_ssid.h @@ -549,6 +549,11 @@ struct wpa_ssid { int dot11MeshConfirmTimeout; /* msec */ int dot11MeshHoldingTimeout; /* msec */ + /** + * Mesh network layer-2 forwarding (dot11MeshForwarding) + */ + int mesh_fwding; + int ht; int ht40; diff --git a/contrib/wpa/wpa_supplicant/ctrl_iface.c b/contrib/wpa/wpa_supplicant/ctrl_iface.c index 9dc17f5eef85..bcd67fca3e12 100644 --- a/contrib/wpa/wpa_supplicant/ctrl_iface.c +++ b/contrib/wpa/wpa_supplicant/ctrl_iface.c @@ -3793,47 +3793,6 @@ static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, } -static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s, - struct wpa_cred *cred) -{ - struct wpa_ssid *ssid; - char str[20]; - int id; - - if (cred == NULL) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); - return -1; - } - - id = cred->id; - if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); - return -1; - } - - wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); - - /* Remove any network entry created based on the removed credential */ - ssid = wpa_s->conf->ssid; - while (ssid) { - if (ssid->parent_cred == cred) { - int res; - - wpa_printf(MSG_DEBUG, "Remove network id %d since it " - "used the removed credential", ssid->id); - res = os_snprintf(str, sizeof(str), "%d", ssid->id); - if (os_snprintf_error(sizeof(str), res)) - str[sizeof(str) - 1] = '\0'; - ssid = ssid->next; - wpa_supplicant_ctrl_iface_remove_network(wpa_s, str); - } else - ssid = ssid->next; - } - - return 0; -} - - static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, char *cmd) { @@ -3844,13 +3803,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, * "provisioning_sp= */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); - cred = wpa_s->conf->cred; - while (cred) { - prev = cred; - cred = cred->next; - wpas_ctrl_remove_cred(wpa_s, prev); - } - return 0; + return wpas_remove_all_creds(wpa_s); } if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) { @@ -3866,7 +3819,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, if (os_strcmp(prev->domain[i], cmd + 8) != 0) continue; - wpas_ctrl_remove_cred(wpa_s, prev); + wpas_remove_cred(wpa_s, prev); break; } } @@ -3883,7 +3836,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, cred = cred->next; if (prev->provisioning_sp && os_strcmp(prev->provisioning_sp, cmd + 16) == 0) - wpas_ctrl_remove_cred(wpa_s, prev); + wpas_remove_cred(wpa_s, prev); } return 0; } @@ -3892,7 +3845,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); cred = wpa_config_get_cred(wpa_s->conf, id); - return wpas_ctrl_remove_cred(wpa_s, cred); + return wpas_remove_cred(wpa_s, cred); } @@ -4826,7 +4779,9 @@ static int wpa_supplicant_ctrl_iface_get_capability( #ifdef CONFIG_DPP if (os_strcmp(field, "dpp") == 0) { -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 + res = os_snprintf(buf, buflen, "DPP=3"); +#elif defined(CONFIG_DPP2) res = os_snprintf(buf, buflen, "DPP=2"); #else /* CONFIG_DPP2 */ res = os_snprintf(buf, buflen, "DPP=1"); @@ -8477,7 +8432,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) dpp_pkex_ephemeral_key_override_len = 0; dpp_protocol_key_override_len = 0; dpp_nonce_override_len = 0; -#ifdef CONFIG_DPP2 +#ifdef CONFIG_DPP3 + dpp_version_override = 3; +#elif defined(CONFIG_DPP2) dpp_version_override = 2; #else /* CONFIG_DPP2 */ dpp_version_override = 1; diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c index 2c01943f754e..9279ae4d5847 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.c @@ -937,6 +937,95 @@ void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, #endif /* CONFIG_MESH */ +#ifdef CONFIG_INTERWORKING + +void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_cred *cred, + const char *type, + int excluded, + int bh, + int bss_load, + int conn_capab) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + char bss_path[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path; + char cred_path[WPAS_DBUS_OBJECT_PATH_MAX], *cred_obj_path; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "InterworkingAPAdded"); + if (!msg) + return; + + os_snprintf(bss_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", + wpa_s->dbus_new_path, bss->id); + bss_obj_path = bss_path; + + os_snprintf(cred_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%u", + wpa_s->dbus_new_path, cred->id); + cred_obj_path = cred_path; + + dbus_message_iter_init_append(msg, &iter); + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &bss_obj_path) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &cred_obj_path) || + !wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_string(&dict_iter, "type", type) || + !wpa_dbus_dict_append_int32(&dict_iter, "excluded", excluded) || + !wpa_dbus_dict_append_int32(&dict_iter, "priority", + cred->priority) || + !wpa_dbus_dict_append_int32(&dict_iter, "sp_priority", + cred->sp_priority) || + !wpa_dbus_dict_append_int32(&dict_iter, "below_min_backhaul", bh) || + !wpa_dbus_dict_append_int32(&dict_iter, "over_max_bss_load", + bss_load) || + !wpa_dbus_dict_append_int32(&dict_iter, "conn_capab_missing", + conn_capab) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "InterworkingSelectDone"); + if (!msg) + return; + + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + +#endif /* CONFIG_INTERWORKING */ + + void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *altsubject[], @@ -3570,6 +3659,35 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, +#ifdef CONFIG_INTERWORKING + { "AddCred", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_add_cred, + { + { "args", "a{sv}", ARG_IN }, + { "path", "o", ARG_OUT }, + END_ARGS + } + }, + { "RemoveCred", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_remove_cred, + { + { "path", "o", ARG_IN }, + END_ARGS + } + }, + { "RemoveAllCreds", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_remove_all_creds, + { + END_ARGS + } + }, + { "InterworkingSelect", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_interworking_select, + { + END_ARGS + } + }, +#endif /* CONFIG_INTERWORKING */ { NULL, NULL, NULL, { END_ARGS } } }; @@ -4137,6 +4255,21 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { } }, #endif /* CONFIG_MESH */ +#ifdef CONFIG_INTERWORKING + { "InterworkingAPAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "bss", "o", ARG_OUT }, + { "cred", "o", ARG_OUT }, + { "properties", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "InterworkingSelectDone", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + END_ARGS + } + }, +#endif /* CONFIG_INTERWORKING */ { NULL, NULL, { END_ARGS } } }; diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h index 42db3892ed77..26bdcb548de8 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new.h +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new.h @@ -16,6 +16,8 @@ struct wpa_global; struct wpa_supplicant; struct wpa_ssid; +struct wpa_cred; +struct wpa_bss; struct wps_event_m2d; struct wps_event_fail; struct wps_credential; @@ -96,6 +98,9 @@ enum wpas_dbus_sta_prop { #define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers" #define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer" +#define WPAS_DBUS_NEW_CREDENTIALS_PART "Credentials" +#define WPAS_DBUS_NEW_IFACE_CREDENTIAL WPAS_DBUS_NEW_INTERFACE ".Credential" + /* Top-level Errors */ #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \ WPAS_DBUS_NEW_INTERFACE ".UnknownError" @@ -264,6 +269,13 @@ void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s, const u8 *peer_addr); void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int reason); +void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_cred *cred, + const char *type, int excluded, + int bh, int bss_load, + int conn_capab); +void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -616,6 +628,21 @@ void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, { } +static inline +void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_cred *cred, + const char *type, int excluded, + int bh, int bss_load, + int conn_capab) +{ +} + +static inline +void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c index db9f30c9aabf..545e9f64295a 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.c @@ -26,6 +26,7 @@ #include "../scan.h" #include "../autoscan.h" #include "../ap.h" +#include "../interworking.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" @@ -148,6 +149,9 @@ static const char * const dont_quote[] = { #ifdef CONFIG_P2P "go_p2p_dev_addr", "p2p_client_list", "psk_list", #endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + "roaming_consortium", "required_roaming_consortium", +#endif /* CONFIG_INTERWORKING */ NULL }; @@ -328,6 +332,110 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, } +/** + * set_cred_properties - Set the properties of a configured credential + * @wpa_s: wpa_supplicant structure for a network interface + * @cred: wpa_cred structure for a configured credential + * @iter: DBus message iterator containing dictionary of network + * properties to set. + * @error: On failure, an error describing the failure + * Returns: TRUE if the request succeeds, FALSE if it failed + */ +static dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s, + struct wpa_cred *cred, + DBusMessageIter *iter, + DBusError *error) +{ + struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; + DBusMessageIter iter_dict; + char *value = NULL; + + if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) + return FALSE; + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + size_t size = 50; + int ret; + + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + goto error; + + value = NULL; + if (entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + if (entry.array_len <= 0) + goto error; + + size = entry.array_len * 2 + 1; + value = os_zalloc(size); + if (!value) + goto error; + + ret = wpa_snprintf_hex(value, size, + (u8 *) entry.bytearray_value, + entry.array_len); + if (ret <= 0) + goto error; + } else if (entry.type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry.key)) { + size = os_strlen(entry.str_value); + + size += 3; + value = os_zalloc(size); + if (!value) + goto error; + + ret = os_snprintf(value, size, "\"%s\"", + entry.str_value); + if (os_snprintf_error(size, ret)) + goto error; + } else { + value = os_strdup(entry.str_value); + if (!value) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (!value) + goto error; + + ret = os_snprintf(value, size, "%u", + entry.uint32_value); + if (os_snprintf_error(size, ret)) + goto error; + } else if (entry.type == DBUS_TYPE_INT32) { + value = os_zalloc(size); + if (!value) + goto error; + + ret = os_snprintf(value, size, "%d", + entry.int32_value); + if (os_snprintf_error(size, ret)) + goto error; + } else { + goto error; + } + + ret = wpa_config_set_cred(cred, entry.key, value, 0); + if (ret < 0) + goto error; + + os_free(value); + value = NULL; + wpa_dbus_dict_entry_clear(&entry); + } + + return TRUE; + +error: + os_free(value); + wpa_dbus_dict_entry_clear(&entry); + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; +} + + /** * wpas_dbus_simple_property_getter - Get basic type property * @iter: Message iter to use when appending arguments @@ -1515,6 +1623,185 @@ DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message, } +/** + * wpas_dbus_new_iface_add_cred - Add a new credential + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A dbus message containing the object path of the new credential + * + * Handler function for "AddCred" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + DBusMessageIter iter; + struct wpa_cred *cred = NULL; + char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; + DBusError error; + + dbus_message_iter_init(message, &iter); + + if (wpa_s->dbus_new_path) + cred = wpa_config_add_cred(wpa_s->conf); + if (!cred) { + wpa_printf(MSG_ERROR, "%s[dbus]: can't add new credential.", + __func__); + reply = wpas_dbus_error_unknown_error( + message, + "wpa_supplicant could not add a credential on this interface."); + goto err; + } + + dbus_error_init(&error); + if (!set_cred_properties(wpa_s, cred, &iter, &error)) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: control interface couldn't set credential properties", + __func__); + reply = wpas_dbus_reply_new_from_error(message, &error, + DBUS_ERROR_INVALID_ARGS, + "Failed to add credential"); + dbus_error_free(&error); + goto err; + } + + /* Construct the object path for this network. */ + os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d", + wpa_s->dbus_new_path, cred->id); + + reply = dbus_message_new_method_return(message); + if (!reply) { + reply = wpas_dbus_error_no_memory(message); + goto err; + } + if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + reply = wpas_dbus_error_no_memory(message); + goto err; + } + + return reply; + +err: + if (cred) + wpa_config_remove_cred(wpa_s->conf, cred->id); + return reply; +} + + +/** + * wpas_dbus_handler_remove_cred - Remove a configured credential + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL on success or dbus error on failure + * + * Handler function for "RemoveCred" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + const char *op; + char *iface, *cred_id; + int id; + struct wpa_cred *cred; + + dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, + DBUS_TYPE_INVALID); + + /* Extract the network ID and ensure the network is actually a child of + * this interface */ + iface = wpas_dbus_new_decompose_object_path( + op, WPAS_DBUS_NEW_CREDENTIALS_PART, &cred_id); + if (!iface || !cred_id || !wpa_s->dbus_new_path || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + errno = 0; + id = strtoul(cred_id, NULL, 10); + if (errno != 0) { + reply = wpas_dbus_error_invalid_args(message, op); + goto out; + } + + cred = wpa_config_get_cred(wpa_s->conf, id); + if (!cred) { + wpa_printf(MSG_ERROR, "%s[dbus]: could not find credential %s", + __func__, op); + reply = wpas_dbus_error_invalid_args( + message, "could not find credential"); + goto out; + } + + if (wpas_remove_cred(wpa_s, cred) < 0) { + wpa_printf(MSG_ERROR, + "%s[dbus]: error occurred when removing cred %d", + __func__, id); + reply = wpas_dbus_error_unknown_error( + message, + "error removing the specified credential on its interface."); + goto out; + } + +out: + os_free(iface); + return reply; +} + + +/** + * wpas_dbus_handler_remove_all_creds - Remove all the configured credentials + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "RemoveAllCreds" method call of a network interface. + */ +DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int res; + DBusMessage *reply = NULL; + + res = wpas_remove_all_creds(wpa_s); + if (res < 0) { + wpa_printf(MSG_ERROR, + "%s[dbus]: failed to remove all credentials", + __func__); + reply = wpas_dbus_error_unknown_error( + message, "failed to remove all credentials"); + } + + return reply; +} + + +DBusMessage * +wpas_dbus_handler_interworking_select(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int result; + DBusMessage *reply = NULL; + + /* Automatic selection is disabled and no constraint on channels */ + result = interworking_select(wpa_s, 0, NULL); + if (result < 0) { + wpa_printf(MSG_ERROR, + "%s[dbus]: failed to start Interworking selection", + __func__); + reply = wpas_dbus_error_scan_error( + message, + "error starting Interworking selection."); + } + + return reply; +} + + /** * wpas_dbus_handler_signal_poll - Request immediate signal properties * @message: Pointer to incoming dbus message diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h index c36383f05668..a421083f7fe2 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers.h @@ -144,6 +144,19 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * +wpas_dbus_handler_interworking_select(DBusMessage *message, + struct wpa_supplicant *wpa_s); + DECLARE_ACCESSOR(wpas_dbus_getter_capabilities); DECLARE_ACCESSOR(wpas_dbus_getter_state); DECLARE_ACCESSOR(wpas_dbus_getter_scanning); diff --git a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 565ced0fd7e2..de79178f4655 100644 --- a/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/contrib/wpa/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -744,6 +744,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, unsigned int group_id = 0; int persistent = 0; struct wpa_ssid *ssid; + const char *group_ifname; if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) return reply; @@ -777,6 +778,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, !p2p_peer_known(wpa_s->global->p2p, peer_addr)) goto err; + /* Capture the interface name for the group first */ + group_ifname = wpa_s->ifname; wpa_s = wpa_s->global->p2p_init_wpa_s; if (persistent) { @@ -821,7 +824,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, /* * No group ID means propose to a peer to join my active group */ - if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, + if (wpas_p2p_invite_group(wpa_s, group_ifname, peer_addr, NULL, false)) { reply = wpas_dbus_error_unknown_error( message, "Failed to join to an active group"); diff --git a/contrib/wpa/wpa_supplicant/defconfig b/contrib/wpa/wpa_supplicant/defconfig index 708a82385170..a4719dbb543d 100644 --- a/contrib/wpa/wpa_supplicant/defconfig +++ b/contrib/wpa/wpa_supplicant/defconfig @@ -603,8 +603,13 @@ CONFIG_BGSCAN_SIMPLE=y # Experimental implementation of draft-harkins-owe-07.txt #CONFIG_OWE=y -# Device Provisioning Protocol (DPP) +# Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect) CONFIG_DPP=y +# DPP version 2 support +CONFIG_DPP2=y +# DPP version 3 support (experimental and still changing; do not enable for +# production use) +#CONFIG_DPP3=y # Wired equivalent privacy (WEP) # WEP is an obsolete cryptographic data confidentiality algorithm that is not diff --git a/contrib/wpa/wpa_supplicant/dpp_supplicant.c b/contrib/wpa/wpa_supplicant/dpp_supplicant.c index 40ef8aeb510f..584654a6cb2c 100644 --- a/contrib/wpa/wpa_supplicant/dpp_supplicant.c +++ b/contrib/wpa/wpa_supplicant/dpp_supplicant.c @@ -1021,6 +1021,7 @@ void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s) wpa_drv_dpp_listen(wpa_s, false); wpa_s->dpp_listen_freq = 0; wpas_dpp_listen_work_done(wpa_s); + radio_remove_works(wpa_s, "dpp-listen", 0); } @@ -2462,6 +2463,16 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, &version_len); if (version && version_len >= 1) peer_version = version[0]; +#ifdef CONFIG_DPP3 + if (intro.peer_version && intro.peer_version >= 2 && + peer_version != intro.peer_version) { + wpa_printf(MSG_INFO, + "DPP: Protocol version mismatch (Connector: %d Attribute: %d", + intro.peer_version, peer_version); + wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH); + goto fail; + } +#endif /* CONFIG_DPP3 */ entry->dpp_pfs = peer_version >= 2; #endif /* CONFIG_DPP2 */ if (expiry) { @@ -2568,7 +2579,9 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", pkex->exch_req_tries); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", - MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ); + MAC2STR(broadcast), pkex->freq, + pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); offchannel_send_action(wpa_s, pkex->freq, broadcast, wpa_s->own_addr, broadcast, wpabuf_head(pkex->exchange_req), @@ -2627,7 +2640,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, static void wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, - const u8 *buf, size_t len, unsigned int freq) + const u8 *buf, size_t len, unsigned int freq, + bool v2) { struct wpabuf *msg; unsigned int wait_time; @@ -2655,7 +2669,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_s->own_addr, src, wpa_s->dpp_pkex_identifier, wpa_s->dpp_pkex_code, - buf, len); + buf, len, v2); if (!wpa_s->dpp_pkex) { wpa_printf(MSG_DEBUG, "DPP: Failed to process the request - ignore it"); @@ -2878,8 +2892,17 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, case DPP_PA_PEER_DISCOVERY_RESP: wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len); break; +#ifdef CONFIG_DPP3 case DPP_PA_PKEX_EXCHANGE_REQ: - wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq); + /* This is for PKEXv2, but for now, process only with + * CONFIG_DPP3 to avoid issues with a capability that has not + * been tested with other implementations. */ + wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, true); + break; +#endif /* CONFIG_DPP3 */ + case DPP_PA_PKEX_V1_EXCHANGE_REQ: + wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, + false); break; case DPP_PA_PKEX_EXCHANGE_RESP: wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq); @@ -3192,17 +3215,38 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, #ifdef CONFIG_TESTING_OPTIONS skip_connector: + if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); + goto skip_proto_ver; + } #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_DPP2 if (DPP_VERSION > 1) { + u8 ver = DPP_VERSION; +#ifdef CONFIG_DPP3 + int conn_ver; + + conn_ver = dpp_get_connector_version(ssid->dpp_connector); + if (conn_ver > 0 && ver != conn_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Use Connector version %d instead of current protocol version %d", + conn_ver, ver); + ver = conn_ver; + } +#endif /* CONFIG_DPP3 */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, DPP_VERSION); + wpabuf_put_u8(msg, ver); } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_TESTING_OPTIONS +skip_proto_ver: +#endif /* CONFIG_TESTING_OPTIONS */ + /* TODO: Timeout on AP response */ wait_time = wpa_s->max_remain_on_chan; if (wait_time > 2000) @@ -3270,15 +3314,16 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) if (!wpa_s->dpp_pkex_code) return -1; - if (os_strstr(cmd, " init=1")) { + if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) { struct dpp_pkex *pkex; struct wpabuf *msg; + bool v2 = os_strstr(cmd, " init=2") != NULL; wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); dpp_pkex_free(wpa_s->dpp_pkex); wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr, wpa_s->dpp_pkex_identifier, - wpa_s->dpp_pkex_code); + wpa_s->dpp_pkex_code, v2); pkex = wpa_s->dpp_pkex; if (!pkex) return -1; @@ -3291,7 +3336,8 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", MAC2STR(broadcast), pkex->freq, - DPP_PA_PKEX_EXCHANGE_REQ); + v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); offchannel_send_action(wpa_s, pkex->freq, broadcast, wpa_s->own_addr, broadcast, wpabuf_head(msg), wpabuf_len(msg), diff --git a/contrib/wpa/wpa_supplicant/events.c b/contrib/wpa/wpa_supplicant/events.c index 5f5c50ba9754..f55e1846e205 100644 --- a/contrib/wpa/wpa_supplicant/events.c +++ b/contrib/wpa/wpa_supplicant/events.c @@ -2177,7 +2177,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (wnm_scan_process(wpa_s, 1) > 0) goto scan_work_done; - if (sme_proc_obss_scan(wpa_s, scan_res) > 0) + if (sme_proc_obss_scan(wpa_s) > 0) goto scan_work_done; if (own_request && data && diff --git a/contrib/wpa/wpa_supplicant/interworking.c b/contrib/wpa/wpa_supplicant/interworking.c index 1c82d2117ab0..71a5c16510d4 100644 --- a/contrib/wpa/wpa_supplicant/interworking.c +++ b/contrib/wpa/wpa_supplicant/interworking.c @@ -702,12 +702,14 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s, ((cred->password == NULL || cred->password[0] == '\0') && (cred->private_key == NULL || - cred->private_key[0] == '\0'))) { + cred->private_key[0] == '\0') && + (!cred->key_id || cred->key_id[0] == '\0'))) { wpa_msg(wpa_s, MSG_DEBUG, - "nai-realm-find-eap: incomplete cred info: username: %s password: %s private_key: %s", + "nai-realm-find-eap: incomplete cred info: username: %s password: %s private_key: %s key_id: %s", cred->username ? cred->username : "NULL", cred->password ? cred->password : "NULL", - cred->private_key ? cred->private_key : "NULL"); + cred->private_key ? cred->private_key : "NULL", + cred->key_id ? cred->key_id : "NULL"); return NULL; } @@ -716,7 +718,8 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s, if (cred->password && cred->password[0] && nai_realm_cred_username(wpa_s, eap)) return eap; - if (cred->private_key && cred->private_key[0] && + if (((cred->private_key && cred->private_key[0]) || + (cred->key_id && cred->key_id[0])) && nai_realm_cred_cert(wpa_s, eap)) return eap; } @@ -1539,6 +1542,24 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, cred->private_key_passwd) < 0) return -1; + if (cred->ca_cert_id && cred->ca_cert_id[0] && + wpa_config_set_quoted(ssid, "ca_cert_id", cred->ca_cert_id) < 0) + return -1; + + if (cred->cert_id && cred->cert_id[0] && + wpa_config_set_quoted(ssid, "cert_id", cred->cert_id) < 0) + return -1; + + if (cred->key_id && cred->key_id[0] && + wpa_config_set_quoted(ssid, "key_id", cred->key_id) < 0) + return -1; + + if (cred->engine_id && cred->engine_id[0] && + wpa_config_set_quoted(ssid, "engine_id", cred->engine_id) < 0) + return -1; + + ssid->eap.cert.engine = cred->engine; + if (cred->phase1) { os_free(ssid->eap.phase1); ssid->eap.phase1 = os_strdup(cred->phase1); @@ -2481,13 +2502,9 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) bh = cred_below_min_backhaul(wpa_s, cred, bss); bss_load = cred_over_max_bss_load(wpa_s, cred, bss); conn_capab = cred_conn_capab_missing(wpa_s, cred, bss); - wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d", - excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP, - MAC2STR(bss->bssid), type, - bh ? " below_min_backhaul=1" : "", - bss_load ? " over_max_bss_load=1" : "", - conn_capab ? " conn_capab_missing=1" : "", - cred->id, cred->priority, cred->sp_priority); + wpas_notify_interworking_ap_added(wpa_s, bss, cred, excluded, + type, bh, bss_load, + conn_capab); if (excluded) continue; if (wpa_s->auto_select || @@ -2578,6 +2595,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); } + wpas_notify_interworking_select_done(wpa_s); + if (selected) { wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR, MAC2STR(selected->bssid)); diff --git a/contrib/wpa/wpa_supplicant/mesh.c b/contrib/wpa/wpa_supplicant/mesh.c index 7938b8b4903e..d6b8a1ad9e36 100644 --- a/contrib/wpa/wpa_supplicant/mesh.c +++ b/contrib/wpa/wpa_supplicant/mesh.c @@ -140,6 +140,7 @@ static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s, conf->mesh_cc_id = 0; conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET; conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0; + conf->mesh_fwding = ssid->mesh_fwding; conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries; conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout; conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout; @@ -472,6 +473,7 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s, bss->conf->start_disabled = 1; bss->conf->mesh = MESH_ENABLED; bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity; + bss->conf->mesh_fwding = wpa_s->conf->mesh_fwding; if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes, wpa_s->hw.num_modes) && wpa_s->conf->country[0]) { @@ -686,6 +688,10 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, } params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity; + /* Always explicitely set forwarding to on or off for now */ + params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_FORWARDING; + params->conf.forwarding = ssid->mesh_fwding; + os_free(wpa_s->mesh_params); wpa_s->mesh_params = params; if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) { diff --git a/contrib/wpa/wpa_supplicant/mesh_mpm.c b/contrib/wpa/wpa_supplicant/mesh_mpm.c index 38f0d641a03b..2eb9a7ef6182 100644 --- a/contrib/wpa/wpa_supplicant/mesh_mpm.c +++ b/contrib/wpa/wpa_supplicant/mesh_mpm.c @@ -306,9 +306,10 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1; /* TODO: Add Connected to Mesh Gate/AS subfields */ wpabuf_put_u8(buf, info); - /* always forwarding & accepting plinks for now */ + /* Set forwarding based on configuration and always accept + * plinks for now */ wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER | - MESH_CAP_FORWARDING); + (conf->mesh_fwding ? MESH_CAP_FORWARDING : 0)); } else { /* Peer closing frame */ /* IE: Mesh ID */ wpabuf_put_u8(buf, WLAN_EID_MESH_ID); diff --git a/contrib/wpa/wpa_supplicant/notify.c b/contrib/wpa/wpa_supplicant/notify.c index fe5e072c24c2..821c916c153f 100644 --- a/contrib/wpa/wpa_supplicant/notify.c +++ b/contrib/wpa/wpa_supplicant/notify.c @@ -19,6 +19,7 @@ #include "rsn_supp/wpa.h" #include "fst/fst.h" #include "crypto/tls.h" +#include "bss.h" #include "driver_i.h" #include "scan.h" #include "p2p_supplicant.h" @@ -943,3 +944,32 @@ void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_MESH */ + + +#ifdef CONFIG_INTERWORKING + +void wpas_notify_interworking_ap_added(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_cred *cred, int excluded, + const char *type, int bh, int bss_load, + int conn_capab) +{ + wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d", + excluded ? INTERWORKING_EXCLUDED : INTERWORKING_AP, + MAC2STR(bss->bssid), type, + bh ? " below_min_backhaul=1" : "", + bss_load ? " over_max_bss_load=1" : "", + conn_capab ? " conn_capab_missing=1" : "", + cred->id, cred->priority, cred->sp_priority); + + wpas_dbus_signal_interworking_ap_added(wpa_s, bss, cred, type, excluded, + bh, bss_load, conn_capab); +} + + +void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_interworking_select_done(wpa_s); +} + +#endif /* CONFIG_INTERWORKING */ diff --git a/contrib/wpa/wpa_supplicant/notify.h b/contrib/wpa/wpa_supplicant/notify.h index e843aa124b39..c46e7986e3b3 100644 --- a/contrib/wpa/wpa_supplicant/notify.h +++ b/contrib/wpa/wpa_supplicant/notify.h @@ -15,6 +15,7 @@ struct wps_credential; struct wps_event_m2d; struct wps_event_fail; struct tls_cert_data; +struct wpa_cred; int wpas_notify_supplicant_initialized(struct wpa_global *global); void wpas_notify_supplicant_deinitialized(struct wpa_global *global); @@ -156,5 +157,11 @@ void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s, const u8 *peer_addr); void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, const u8 *peer_addr, u16 reason_code); +void wpas_notify_interworking_ap_added(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_cred *cred, int excluded, + const char *type, int bh, int bss_load, + int conn_capab); +void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s); #endif /* NOTIFY_H */ diff --git a/contrib/wpa/wpa_supplicant/sme.c b/contrib/wpa/wpa_supplicant/sme.c index f2c42ff354e7..1dc7001a7305 100644 --- a/contrib/wpa/wpa_supplicant/sme.c +++ b/contrib/wpa/wpa_supplicant/sme.c @@ -13,7 +13,6 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/ocv.h" -#include "common/hw_features_common.h" #include "eapol_supp/eapol_supp_sm.h" #include "common/wpa_common.h" #include "common/sae.h" @@ -138,6 +137,12 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, } bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (!bss) { + wpa_printf(MSG_DEBUG, + "SAE: BSS not available, update scan result to get BSS"); + wpa_supplicant_update_scan_results(wpa_s); + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + } if (bss) { const u8 *rsnxe; @@ -2380,14 +2385,13 @@ static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s, } -int sme_proc_obss_scan(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res) +int sme_proc_obss_scan(struct wpa_supplicant *wpa_s) { + struct wpa_bss *bss; const u8 *ie; + u16 ht_cap; u8 chan_list[P2P_MAX_CHANNELS], channel; u8 num_channels = 0, num_intol = 0, i; - size_t j; - int pri_freq, sec_freq; if (!wpa_s->sme.sched_obss_scan) return 0; @@ -2415,36 +2419,22 @@ int sme_proc_obss_scan(struct wpa_supplicant *wpa_s, os_memset(chan_list, 0, sizeof(chan_list)); - pri_freq = wpa_s->assoc_freq; - - switch (wpa_s->sme.ht_sec_chan) { - case HT_SEC_CHAN_ABOVE: - sec_freq = pri_freq + 20; - break; - case HT_SEC_CHAN_BELOW: - sec_freq = pri_freq - 20; - break; - case HT_SEC_CHAN_UNKNOWN: - default: - wpa_msg(wpa_s, MSG_WARNING, - "Undefined secondary channel: drop OBSS scan results"); - return 1; - } - - for (j = 0; j < scan_res->num; j++) { - struct wpa_scan_res *bss = scan_res->res[j]; - enum hostapd_hw_mode mode; - int res; - + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { /* Skip other band bss */ + enum hostapd_hw_mode mode; mode = ieee80211_freq_to_chan(bss->freq, &channel); if (mode != HOSTAPD_MODE_IEEE80211G && mode != HOSTAPD_MODE_IEEE80211B) continue; - res = check_bss_coex_40mhz(bss, pri_freq, sec_freq); - if (res) { - if (res == 2) + ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP); + ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0; + wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR + " freq=%u chan=%u ht_cap=0x%x", + MAC2STR(bss->bssid), bss->freq, channel, ht_cap); + + if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) { + if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT) num_intol++; /* Check whether the channel is already considered */ @@ -2583,6 +2573,12 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) ssid == NULL || ssid->mode != WPAS_MODE_INFRA) return; +#ifdef CONFIG_HT_OVERRIDES + /* No need for OBSS scan if HT40 is explicitly disabled */ + if (ssid->disable_ht40) + return; +#endif /* CONFIG_HT_OVERRIDES */ + if (!wpa_s->hw.modes) return; diff --git a/contrib/wpa/wpa_supplicant/sme.h b/contrib/wpa/wpa_supplicant/sme.h index ecbc16dacd9d..c797d2e9e796 100644 --- a/contrib/wpa/wpa_supplicant/sme.h +++ b/contrib/wpa/wpa_supplicant/sme.h @@ -37,8 +37,7 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s, void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s); void sme_deinit(struct wpa_supplicant *wpa_s); -int sme_proc_obss_scan(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res); +int sme_proc_obss_scan(struct wpa_supplicant *wpa_s); void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable); void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, union wpa_event_data *data); @@ -113,8 +112,7 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s) { } -static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res) +static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s) { return 0; } diff --git a/contrib/wpa/wpa_supplicant/wpa_cli.c b/contrib/wpa/wpa_supplicant/wpa_cli.c index 075d587be2f1..5bbc4535e364 100644 --- a/contrib/wpa/wpa_supplicant/wpa_cli.c +++ b/contrib/wpa/wpa_supplicant/wpa_cli.c @@ -1591,6 +1591,7 @@ static const char * const cred_fields[] = { "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming", "max_bss_load", "req_conn_capab", "ocsp", "sim_num", "realm", "username", "password", "ca_cert", "client_cert", "private_key", "private_key_passwd", "imsi", + "ca_cert_id", "cert_id", "key_id", "engine_id", "engine", "milenage", "domain_suffix_match", "domain", "phase1", "phase2", "roaming_consortium", "required_roaming_consortium", "excluded_ssid", "roaming_partner", "provisioning_sp" diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.c b/contrib/wpa/wpa_supplicant/wpa_supplicant.c index 71bf95f951a1..53b44035f16e 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant.c +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.c @@ -4512,6 +4512,82 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, } +/** + * wpas_remove_cred - Remove the specified credential and all the network + * entries created based on the removed credential + * @wpa_s: wpa_supplicant structure for a network interface + * @cred: The credential to remove + * Returns: 0 on success, -1 on failure + */ +int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred) +{ + struct wpa_ssid *ssid, *next; + int id; + + if (!cred) { + wpa_printf(MSG_DEBUG, "Could not find cred"); + return -1; + } + + id = cred->id; + if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { + wpa_printf(MSG_DEBUG, "Could not find cred %d", id); + return -1; + } + + wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); + + /* Remove any network entry created based on the removed credential */ + ssid = wpa_s->conf->ssid; + while (ssid) { + next = ssid->next; + + if (ssid->parent_cred == cred) { + wpa_printf(MSG_DEBUG, + "Remove network id %d since it used the removed credential", + ssid->id); + if (wpa_supplicant_remove_network(wpa_s, ssid->id) == + -1) { + wpa_printf(MSG_DEBUG, + "Could not find network id=%d", + ssid->id); + } + } + + ssid = next; + } + + return 0; +} + + +/** + * wpas_remove_cred - Remove all the Interworking credentials + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: 0 on success, -1 on failure + */ +int wpas_remove_all_creds(struct wpa_supplicant *wpa_s) +{ + int res, ret = 0; + struct wpa_cred *cred, *prev; + + cred = wpa_s->conf->cred; + while (cred) { + prev = cred; + cred = cred->next; + res = wpas_remove_cred(wpa_s, prev); + if (res < 0) { + wpa_printf(MSG_DEBUG, + "Removal of all credentials failed - failed to remove credential id=%d", + prev->id); + ret = -1; + } + } + + return ret; +} + + /** * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path * @wpa_s: wpa_supplicant structure for a network interface diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf index fa257f3dec1b..6619d6ba7fb1 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant.conf +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant.conf @@ -150,6 +150,9 @@ ap_scan=1 # This timeout value is used in mesh STA to clean up inactive stations. #mesh_max_inactivity=300 +# Enable 802.11s layer-2 routing and forwarding (dot11MeshForwarding) +#mesh_fwding=1 + # cert_in_cb - Whether to include a peer certificate dump in events # This controls whether peer certificates for authentication server and # its certificate chain are included in EAP peer certificate events. This is diff --git a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h index cbc955159bbe..5fa765fda25c 100644 --- a/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h +++ b/contrib/wpa/wpa_supplicant/wpa_supplicant_i.h @@ -38,6 +38,7 @@ struct wpa_bss; struct wpa_scan_results; struct hostapd_hw_modes; struct wpa_driver_associate_params; +struct wpa_cred; /* * Forward declarations of private structures used within the ctrl_iface @@ -1578,6 +1579,8 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred); +int wpas_remove_all_creds(struct wpa_supplicant *wpa_s); int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s, const char *pkcs11_engine_path, const char *pkcs11_module_path);