aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/dbus.doxygen34
-rw-r--r--hostapd/Android.mk3
-rw-r--r--hostapd/Makefile3
-rw-r--r--hostapd/config_file.c10
-rw-r--r--hostapd/ctrl_iface.c10
-rw-r--r--hostapd/defconfig8
-rw-r--r--hostapd/hostapd.conf4
-rw-r--r--src/ap/acs.c9
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/ap_drv_ops.c3
-rw-r--r--src/ap/beacon.c8
-rw-r--r--src/ap/dfs.c3
-rw-r--r--src/ap/dpp_hostapd.c69
-rw-r--r--src/ap/drv_callbacks.c6
-rw-r--r--src/ap/hostapd.c15
-rw-r--r--src/common/dpp.c41
-rw-r--r--src/common/dpp.h19
-rw-r--r--src/common/dpp_crypto.c55
-rw-r--r--src/common/dpp_i.h1
-rw-r--r--src/common/dpp_pkex.c237
-rw-r--r--src/common/hw_features_common.c141
-rw-r--r--src/common/hw_features_common.h1
-rw-r--r--src/common/qca-vendor.h41
-rw-r--r--src/drivers/driver.h2
-rw-r--r--src/drivers/driver_nl80211.c3
-rw-r--r--tests/hwsim/hostapd.py7
-rw-r--r--tests/hwsim/remotehost.py5
-rw-r--r--tests/hwsim/test_ap_hs20.py4
-rw-r--r--tests/hwsim/test_dbus.py111
-rw-r--r--tests/hwsim/test_dpp.py54
-rw-r--r--tests/hwsim/test_dpp3.py49
-rw-r--r--tests/hwsim/test_mbo.py4
-rw-r--r--tests/hwsim/wpasupplicant.py7
-rw-r--r--wlantest/Makefile1
-rw-r--r--wlantest/wlantest.c85
-rw-r--r--wlantest/wlantest_cli.c109
-rw-r--r--wpa_supplicant/Android.mk3
-rw-r--r--wpa_supplicant/Makefile3
-rw-r--r--wpa_supplicant/README-HS206
-rw-r--r--wpa_supplicant/config.c37
-rw-r--r--wpa_supplicant/config.h34
-rw-r--r--wpa_supplicant/config_file.c15
-rw-r--r--wpa_supplicant/config_ssid.h5
-rw-r--r--wpa_supplicant/ctrl_iface.c63
-rw-r--r--wpa_supplicant/dbus/dbus_new.c133
-rw-r--r--wpa_supplicant/dbus/dbus_new.h27
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c287
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h13
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c5
-rw-r--r--wpa_supplicant/defconfig7
-rw-r--r--wpa_supplicant/dpp_supplicant.c62
-rw-r--r--wpa_supplicant/events.c2
-rw-r--r--wpa_supplicant/interworking.c41
-rw-r--r--wpa_supplicant/mesh.c6
-rw-r--r--wpa_supplicant/mesh_mpm.c5
-rw-r--r--wpa_supplicant/notify.c30
-rw-r--r--wpa_supplicant/notify.h7
-rw-r--r--wpa_supplicant/sme.c54
-rw-r--r--wpa_supplicant/sme.h6
-rw-r--r--wpa_supplicant/wpa_cli.c1
-rw-r--r--wpa_supplicant/wpa_supplicant.c76
-rw-r--r--wpa_supplicant/wpa_supplicant.conf3
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h3
63 files changed, 1699 insertions, 400 deletions
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 8231aac41805..f6ab82000108 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -553,6 +553,32 @@ fi.w1.wpa_supplicant1.CreateInterface.
<p>Abort ongoing scan operation.</p>
</li>
<li>
+ <h3>AddCred ( a{sv} : args ) --> o : path</h3>
+ <p>Add an Interworking/Hotspot 2.0 credential.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>A dictionary with credential configuration. Dictionary entries are equivalent to entries in the "cred" block in wpa_supplicant configuration file.</dd>
+ </dl>
+ <h4>Returns</h4>
+ <dl>
+ <dt>o : path</dt>
+ <dd>A D-Bus path to an object representing the added credential</dd>
+ </dl>
+ </li>
+ <li>
+ <h3>RemoveCred ( o : path ) --> nothing</h3>
+ <p>Remove the specified Interworking/Hotspot 2.0 credential.</p>
+ </li>
+ <li>
+ <h3>RemoveAllCreds ( ) --> nothing</h3>
+ <p>Remove all configured Interworking/Hotspot 2.0 credentials.</p>
+ </li>
+ <li>
+ <h3>InterworkingSelect ( ) --> nothing</h3>
+ <p>Perform Interworking (Hotspot 2.0) network selection.</p>
+ </li>
+ <li>
<h3>EAPLogoff ( ) --> nothing</h3>
<p>IEEE 802.1X EAPOL state machine logoff.</p>
</li>
@@ -1261,6 +1287,14 @@ fi.w1.wpa_supplicant1.CreateInterface.
<dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "addr", "dst", "bssid", "ies", "signal".</dd>
</dl>
</li>
+
+ <li>
+ <h3>InterworkingAPAdded ( o : bss, o : cred, a{sv} : args )</h3>
+ </li>
+
+ <li>
+ <h3>InterworkingSelectDone ( )</h3>
+ </li>
</ul>
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index dd8aa2450d7e..bf26e41c6b23 100644
--- a/hostapd/Android.mk
+++ b/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/hostapd/Makefile b/hostapd/Makefile
index ac085fd10520..e37c13b27a6e 100644
--- a/hostapd/Makefile
+++ b/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/hostapd/config_file.c b/hostapd/config_file.c
index daf3f37ad99e..b14728d1b507 100644
--- a/hostapd/config_file.c
+++ b/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/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 6c99a3105f49..86adf18e5fe3 100644
--- a/hostapd/ctrl_iface.c
+++ b/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/hostapd/defconfig b/hostapd/defconfig
index 666447e4ab40..6b50b6c59b46 100644
--- a/hostapd/defconfig
+++ b/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/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 67d4cefb920b..3c2019f73048 100644
--- a/hostapd/hostapd.conf
+++ b/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/src/ap/acs.c b/src/ap/acs.c
index 46429f265433..0030edc2a90f 100644
--- a/src/ap/acs.c
+++ b/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/src/ap/ap_config.h b/src/ap/ap_config.h
index b8f791e56307..49cd3168a2fa 100644
--- a/src/ap/ap_config.h
+++ b/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/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index d1642d7dff15..e917736664bd 100644
--- a/src/ap/ap_drv_ops.c
+++ b/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/src/ap/beacon.c b/src/ap/beacon.c
index 22782f54e480..8cd1c417043e 100644
--- a/src/ap/beacon.c
+++ b/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/src/ap/dfs.c b/src/ap/dfs.c
index 03c99b175215..5c99ecfd017e 100644
--- a/src/ap/dfs.c
+++ b/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/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 41769f475544..13e1fc5bdd96 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1554,17 +1554,38 @@ skip_status:
#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/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index ec5abf166b23..a50e6f2afa77 100644
--- a/src/ap/drv_callbacks.c
+++ b/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/src/ap/hostapd.c b/src/ap/hostapd.c
index 913a8e29e16d..4b88641a2dde 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3464,6 +3464,20 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
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:
case 40:
hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
break;
@@ -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/src/common/dpp.c b/src/common/dpp.c
index 1fd074f05627..ac6eae4c893e 100644
--- a/src/common/dpp.c
+++ b/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 @@ skip_groups:
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 @@ fail:
}
+#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/src/common/dpp.h b/src/common/dpp.h
index a47c685f64b9..8d62a0e2ac3b 100644
--- a/src/common/dpp.h
+++ b/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/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index da59730eb7b7..300416fb12ec 100644
--- a/src/common/dpp_crypto.c
+++ b/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 @@ fail:
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/src/common/dpp_i.h b/src/common/dpp_i.h
index 087878a508cb..c00b1ee41240 100644
--- a/src/common/dpp_i.h
+++ b/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/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
index 06532b5457bd..38349fa3f540 100644
--- a/src/common/dpp_pkex.c
+++ b/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/src/common/hw_features_common.c b/src/common/hw_features_common.c
index e7ac3b2aac6b..f168d4e9290f 100644
--- a/src/common/hw_features_common.c
+++ b/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/src/common/hw_features_common.h b/src/common/hw_features_common.h
index ddde36b99263..0e92aa0f2bc5 100644
--- a/src/common/hw_features_common.h
+++ b/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/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 4dac10ef9724..d9eab0212e73 100644
--- a/src/common/qca-vendor.h
+++ b/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/src/drivers/driver.h b/src/drivers/driver.h
index 2020184c5f94..d3312a34d8f8 100644
--- a/src/drivers/driver.h
+++ b/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/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9a9a146f7ea1..aec179ac38cf 100644
--- a/src/drivers/driver_nl80211.c
+++ b/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/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py
index 5ea68444c1b9..f9becfcef4a6 100644
--- a/tests/hwsim/hostapd.py
+++ b/tests/hwsim/hostapd.py
@@ -508,7 +508,7 @@ class Hostapd:
raise Exception("Failed to initiate DPP Authentication")
def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None,
- extra=None, use_id=None):
+ extra=None, use_id=None, v2=False):
if use_id is None:
id1 = self.dpp_bootstrap_gen(type="pkex", key=key, curve=curve)
else:
@@ -516,7 +516,10 @@ class Hostapd:
cmd = "own=%d " % id1
if identifier:
cmd += "identifier=%s " % identifier
- cmd += "init=1 "
+ if v2:
+ cmd += "init=2 "
+ else:
+ cmd += "init=1 "
if role:
cmd += "role=%s " % role
if extra:
diff --git a/tests/hwsim/remotehost.py b/tests/hwsim/remotehost.py
index 0799b951f2e7..9d7c657a1e93 100644
--- a/tests/hwsim/remotehost.py
+++ b/tests/hwsim/remotehost.py
@@ -24,7 +24,7 @@ def execute_thread(command, reply):
err = tempfile.TemporaryFile()
try:
status = 0
- buf = subprocess.check_output(command, stderr=err).decode()
+ buf = subprocess.check_output(command, stderr=err, bufsize=0).decode()
except subprocess.CalledProcessError as e:
status = e.returncode
err.seek(0)
@@ -181,7 +181,8 @@ class Host():
_cmd = self.name + " proc_run: " + ' '.join(cmd)
logger.debug(_cmd)
err = tempfile.TemporaryFile()
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=err)
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=err,
+ bufsize=0)
proc.reaper_file = filename
return proc
diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py
index 9c4ba9597513..e3cb8a4c7bc2 100644
--- a/tests/hwsim/test_ap_hs20.py
+++ b/tests/hwsim/test_ap_hs20.py
@@ -4180,12 +4180,12 @@ def test_ap_hs20_multi_network_and_cred_removal(dev, apdev):
interworking_connect(dev[0], bssid, "PEAP")
dev[0].add_network()
if len(dev[0].list_networks()) != 5:
- raise Exception("Unexpected number of networks prior to remove_crec")
+ raise Exception("Unexpected number of networks prior to remove_cred")
dev[0].dump_monitor()
dev[0].remove_cred(id)
if len(dev[0].list_networks()) != 3:
- raise Exception("Unexpected number of networks after to remove_crec")
+ raise Exception("Unexpected number of networks after to remove_cred")
dev[0].wait_disconnected(timeout=10)
def test_ap_hs20_interworking_add_network(dev, apdev):
diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py
index 1143802c6131..28fb05014736 100644
--- a/tests/hwsim/test_dbus.py
+++ b/tests/hwsim/test_dbus.py
@@ -6091,3 +6091,114 @@ def test_dbus_roam(dev, apdev):
with TestDbusConnect(bus) as t:
if not t.success():
raise Exception("Expected signals not seen")
+
+def test_dbus_creds(dev, apdev):
+ "D-Bus interworking credentials"
+ (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+ iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+ args = {'domain': 'server.w1.fi',
+ 'realm': 'server.w1.fi',
+ 'roaming_consortium': '50a9bf',
+ 'required_roaming_consortium': '23bf50',
+ 'eap': 'TTLS',
+ 'phase2': 'auth=MSCHAPV2',
+ 'username': 'user',
+ 'password': 'password',
+ 'domain_suffix_match': 'server.w1.fi',
+ 'ca_cert': 'auth_serv/ca.pem'}
+
+ path = iface.AddCred(dbus.Dictionary(args, signature='sv'))
+ for k, v in args.items():
+ if k == 'password':
+ continue
+ prop = dev[0].get_cred(0, k)
+ if prop != v:
+ raise Exception('Credential add failed: %s does not match %s' % (prop, v))
+
+ iface.RemoveCred(path)
+ if not "FAIL" in dev[0].get_cred(0, 'domain'):
+ raise Exception("Credential remove failed")
+
+ # Removal of multiple credentials
+ cred1 = {'domain': 'server1.w1.fi','realm': 'server1.w1.fi','eap': 'TTLS'}
+ iface.AddCred(dbus.Dictionary(cred1, signature='sv'))
+ if "FAIL" in dev[0].get_cred(0, 'domain'):
+ raise Exception("Failed to add credential")
+
+ cred2 = {'domain': 'server2.w1.fi','realm': 'server2.w1.fi','eap': 'TTLS'}
+ iface.AddCred(dbus.Dictionary(cred2, signature='sv'))
+ if "FAIL" in dev[0].get_cred(1, 'domain'):
+ raise Exception("Failed to add credential")
+
+ iface.RemoveAllCreds()
+ if not "FAIL" in dev[0].get_cred(0, 'domain'):
+ raise Exception("Credential remove failed")
+ if not "FAIL" in dev[0].get_cred(1, 'domain'):
+ raise Exception("Credential remove failed")
+
+def test_dbus_interworking(dev, apdev):
+ "D-Bus interworking selection"
+ (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+ iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+ params = {"ssid": "test-interworking", "wpa": "2",
+ "wpa_key_mgmt": "WPA-EAP", "rsn_pairwise": "CCMP",
+ "ieee8021x": "1", "eapol_version": "2",
+ "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
+ "ca_cert": "auth_serv/ca.pem",
+ "server_cert": "auth_serv/server.pem",
+ "private_key": "auth_serv/server.key",
+ "interworking": "1",
+ "domain_name": "server.w1.fi",
+ "nai_realm": "0,server.w1.fi,21[2:4][5:7]",
+ "roaming_consortium": "2233445566",
+ "hs20": "1", "anqp_domain_id": "1234"}
+
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ class TestDbusInterworking(TestDbus):
+ def __init__(self, bus):
+ TestDbus.__init__(self, bus)
+ self.interworking_ap_seen = False
+ self.interworking_select_done = False
+
+ def __enter__(self):
+ gobject.timeout_add(1, self.run_select)
+ gobject.timeout_add(15000, self.timeout)
+ self.add_signal(self.interworkingAPAdded, WPAS_DBUS_IFACE,
+ "InterworkingAPAdded")
+ self.add_signal(self.interworkingSelectDone, WPAS_DBUS_IFACE,
+ "InterworkingSelectDone")
+ self.loop.run()
+ return self
+
+ def interworkingAPAdded(self, bss, cred, properties):
+ logger.debug("interworkingAPAdded: bss=%s cred=%s %s" % (bss, cred, str(properties)))
+ if self.cred == cred:
+ self.interworking_ap_seen = True
+
+ def interworkingSelectDone(self):
+ logger.debug("interworkingSelectDone")
+ self.interworking_select_done = True
+ self.loop.quit()
+
+ def run_select(self, *args):
+ args = {"domain": "server.w1.fi",
+ "realm": "server.w1.fi",
+ "eap": "TTLS",
+ "phase2": "auth=MSCHAPV2",
+ "username": "user",
+ "password": "password",
+ "domain_suffix_match": "server.w1.fi",
+ "ca_cert": "auth_serv/ca.pem"}
+ self.cred = iface.AddCred(dbus.Dictionary(args, signature='sv'))
+ iface.InterworkingSelect()
+ return False
+
+ def success(self):
+ return self.interworking_ap_seen and self.interworking_select_done
+
+ with TestDbusInterworking(bus) as t:
+ if not t.success():
+ raise Exception("Expected signals not seen")
diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py
index 4ed2652ef5df..339d7297f7d7 100644
--- a/tests/hwsim/test_dpp.py
+++ b/tests/hwsim/test_dpp.py
@@ -126,8 +126,12 @@ def test_dpp_uri_version(dev, apdev):
uri = dev[0].request("DPP_BOOTSTRAP_GET_URI %d" % id1)
info = dev[0].request("DPP_BOOTSTRAP_INFO %d" % id1)
logger.info("Parsed URI info:\n" + info)
- if "version=2" not in info.splitlines():
- raise Exception("Unexpected version information (v2)")
+ capa = dev[0].request("GET_CAPABILITY dpp")
+ ver = 1
+ if capa.startswith("DPP="):
+ ver = int(capa[4:])
+ if "version=%d" % ver not in info.splitlines():
+ raise Exception("Unexpected version information (with indication)")
dev[0].set("dpp_version_override", "1")
id0 = dev[0].dpp_bootstrap_gen()
@@ -1877,7 +1881,7 @@ def test_dpp_auto_connect_2_conf_ver1(dev, apdev):
dev[0].set("dpp_config_processing", "0", allow_fail=True)
def run_dpp_auto_connect(dev, apdev, processing, ap_version=0, sta_version=0,
- sta1_version=0):
+ sta1_version=0, stop_after_prov=False):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
@@ -1916,6 +1920,8 @@ def run_dpp_auto_connect(dev, apdev, processing, ap_version=0, sta_version=0,
if ev is None:
raise Exception("DPP network profile not generated")
id = ev.split(' ')[1]
+ if stop_after_prov:
+ return id, hapd
if processing == 1:
dev[0].select_network(id, freq=2412)
@@ -2262,6 +2268,10 @@ def test_dpp_pkex(dev, apdev):
"""DPP and PKEX"""
run_dpp_pkex(dev, apdev)
+def test_dpp_pkex_v2(dev, apdev):
+ """DPP and PKEXv2"""
+ run_dpp_pkex(dev, apdev, v2=True)
+
def test_dpp_pkex_p256(dev, apdev):
"""DPP and PKEX (P-256)"""
run_dpp_pkex(dev, apdev, "P-256")
@@ -2315,13 +2325,14 @@ def test_dpp_pkex_identifier_mismatch3(dev, apdev):
def run_dpp_pkex(dev, apdev, curve=None, init_extra=None, check_config=False,
identifier_i="test", identifier_r="test",
- expect_no_resp=False):
- check_dpp_capab(dev[0], curve and "brainpool" in curve)
- check_dpp_capab(dev[1], curve and "brainpool" in curve)
+ expect_no_resp=False, v2=False):
+ min_ver = 3 if v2 else 1
+ check_dpp_capab(dev[0], curve and "brainpool" in curve, min_ver=min_ver)
+ check_dpp_capab(dev[1], curve and "brainpool" in curve, min_ver=min_ver)
dev[0].dpp_pkex_resp(2437, identifier=identifier_r, code="secret",
curve=curve)
dev[1].dpp_pkex_init(identifier=identifier_i, code="secret", curve=curve,
- extra=init_extra)
+ extra=init_extra, v2=v2)
if expect_no_resp:
ev = dev[0].wait_event(["DPP-RX"], timeout=10)
@@ -2545,6 +2556,19 @@ def test_dpp_pkex_hostapd_responder(dev, apdev):
wait_auth_success(hapd, dev[0], configurator=dev[0], enrollee=hapd,
stop_initiator=True)
+def test_dpp_pkex_v2_hostapd_responder(dev, apdev):
+ """DPP PKEXv2 with hostapd as responder"""
+ check_dpp_capab(dev[0], min_ver=3)
+ hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured",
+ "channel": "6"})
+ check_dpp_capab(hapd, min_ver=3)
+ hapd.dpp_pkex_resp(2437, identifier="test", code="secret")
+ conf_id = dev[0].dpp_configurator_add()
+ dev[0].dpp_pkex_init(identifier="test", code="secret",
+ extra="conf=ap-dpp configurator=%d" % conf_id, v2=True)
+ wait_auth_success(hapd, dev[0], configurator=dev[0], enrollee=hapd,
+ stop_initiator=True)
+
def test_dpp_pkex_hostapd_initiator(dev, apdev):
"""DPP PKEX with hostapd as initiator"""
check_dpp_capab(dev[0])
@@ -2560,6 +2584,22 @@ def test_dpp_pkex_hostapd_initiator(dev, apdev):
wait_auth_success(hapd, dev[0], configurator=dev[0], enrollee=hapd,
stop_initiator=True)
+def test_dpp_pkex_v2_hostapd_initiator(dev, apdev):
+ """DPP PKEXv2 with hostapd as initiator"""
+ check_dpp_capab(dev[0], min_ver=3)
+ hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured",
+ "channel": "6"})
+ check_dpp_capab(hapd, min_ver=3)
+ conf_id = dev[0].dpp_configurator_add()
+ dev[0].set("dpp_configurator_params",
+ " conf=ap-dpp configurator=%d" % conf_id)
+ dev[0].dpp_pkex_resp(2437, identifier="test", code="secret",
+ listen_role="configurator")
+ hapd.dpp_pkex_init(identifier="test", code="secret", role="enrollee",
+ v2=True)
+ wait_auth_success(hapd, dev[0], configurator=dev[0], enrollee=hapd,
+ stop_initiator=True)
+
def test_dpp_pkex_hostapd_errors(dev, apdev):
"""DPP PKEX errors with hostapd"""
hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured",
diff --git a/tests/hwsim/test_dpp3.py b/tests/hwsim/test_dpp3.py
new file mode 100644
index 000000000000..e50f199f385f
--- /dev/null
+++ b/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/tests/hwsim/test_mbo.py b/tests/hwsim/test_mbo.py
index 36efd6a0e0ce..d4426ac4be50 100644
--- a/tests/hwsim/test_mbo.py
+++ b/tests/hwsim/test_mbo.py
@@ -203,8 +203,8 @@ def test_mbo_assoc_disallow(dev, apdev, params):
hapd2 = hostapd.add_ap(apdev[1], {"ssid": "MBO", "mbo": "1"})
logger.debug("Set mbo_assoc_disallow with invalid value")
- if "FAIL" not in hapd1.request("SET mbo_assoc_disallow 2"):
- raise Exception("Set mbo_assoc_disallow for AP1 succeeded unexpectedly with value 2")
+ if "FAIL" not in hapd1.request("SET mbo_assoc_disallow 6"):
+ raise Exception("Set mbo_assoc_disallow for AP1 succeeded unexpectedly with value 6")
logger.debug("Disallow associations to AP1 and allow association to AP2")
if "OK" not in hapd1.request("SET mbo_assoc_disallow 1"):
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index fdece92f66d4..160aa3e2df88 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -1577,7 +1577,7 @@ class WpaSupplicant:
return int(peer)
def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None,
- extra=None, use_id=None, allow_fail=False):
+ extra=None, use_id=None, allow_fail=False, v2=False):
if use_id is None:
id1 = self.dpp_bootstrap_gen(type="pkex", key=key, curve=curve)
else:
@@ -1585,7 +1585,10 @@ class WpaSupplicant:
cmd = "own=%d " % id1
if identifier:
cmd += "identifier=%s " % identifier
- cmd += "init=1 "
+ if v2:
+ cmd += "init=2 "
+ else:
+ cmd += "init=1 "
if role:
cmd += "role=%s " % role
if extra:
diff --git a/wlantest/Makefile b/wlantest/Makefile
index 0045020d4130..1eba3cec9fd5 100644
--- a/wlantest/Makefile
+++ b/wlantest/Makefile
@@ -64,6 +64,7 @@ TOBJS += gcmp.o
OBJS_cli = wlantest_cli.o
+OBJS_cli += ../src/common/cli.o
_OBJS_VAR := OBJS
include ../src/objs.mk
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
index ac20b068eb8a..fd6dc2024655 100644
--- a/wlantest/wlantest.c
+++ b/wlantest/wlantest.c
@@ -27,7 +27,7 @@ static void usage(void)
"[-P<RADIUS shared secret>]\n"
" [-n<write pcapng file>]\n"
" [-w<write pcap file>] [-f<MSK/PMK file>]\n"
- " [-L<log file>] [-T<PTK file>]\n");
+ " [-L<log file>] [-T<PTK file>] [-W<WEP key>]\n");
}
@@ -77,6 +77,13 @@ static void ptk_deinit(struct wlantest_ptk *ptk)
}
+static void wep_deinit(struct wlantest_wep *wep)
+{
+ dl_list_del(&wep->list);
+ os_free(wep);
+}
+
+
static void wlantest_deinit(struct wlantest *wt)
{
struct wlantest_passphrase *p, *pn;
@@ -104,7 +111,7 @@ static void wlantest_deinit(struct wlantest *wt)
dl_list_for_each_safe(ptk, npt, &wt->ptk, struct wlantest_ptk, list)
ptk_deinit(ptk);
dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list)
- os_free(wep);
+ wep_deinit(wep);
write_pcap_deinit(wt);
write_pcapng_deinit(wt);
clear_notes(wt);
@@ -364,7 +371,7 @@ int wlantest_relog(struct wlantest *wt)
int main(int argc, char *argv[])
{
- int c;
+ int c, ret = 0;
const char *read_file = NULL;
const char *read_wired_file = NULL;
const char *ifname = NULL;
@@ -372,6 +379,7 @@ int main(int argc, char *argv[])
const char *logfile = NULL;
struct wlantest wt;
int ctrl_iface = 0;
+ bool eloop_init_done = false;
wpa_debug_level = MSG_INFO;
wpa_debug_show_keys = 1;
@@ -397,15 +405,18 @@ int main(int argc, char *argv[])
wt.ethernet = 1;
break;
case 'f':
- if (add_pmk_file(&wt, optarg) < 0)
- return -1;
+ if (add_pmk_file(&wt, optarg) < 0) {
+ ret = -1;
+ goto deinit;
+ }
break;
case 'F':
wt.assume_fcs = 1;
break;
case 'h':
usage();
- return 0;
+ ret = 0;
+ goto deinit;
case 'i':
ifname = optarg;
break;
@@ -440,54 +451,54 @@ int main(int argc, char *argv[])
wpa_debug_timestamp = 1;
break;
case 'T':
- if (add_ptk_file(&wt, optarg) < 0)
- return -1;
+ if (add_ptk_file(&wt, optarg) < 0) {
+ ret = -1;
+ goto deinit;
+ }
break;
case 'w':
wt.write_file = optarg;
break;
case 'W':
- if (add_wep(&wt, optarg) < 0)
- return -1;
+ if (add_wep(&wt, optarg) < 0) {
+ ret = -1;
+ goto deinit;
+ }
break;
default:
usage();
- return -1;
+ ret = -1;
+ goto deinit;
}
}
if (ifname == NULL && ifname_wired == NULL &&
read_file == NULL && read_wired_file == NULL) {
usage();
- return 0;
+ ret = 0;
+ goto deinit;
}
- if (eloop_init())
- return -1;
+ if (eloop_init()) {
+ ret = -1;
+ goto deinit;
+ }
+ eloop_init_done = true;
if (logfile)
wpa_debug_open_file(logfile);
- if (wt.write_file && write_pcap_init(&wt, wt.write_file) < 0)
- return -1;
-
- if (wt.pcapng_file && write_pcapng_init(&wt, wt.pcapng_file) < 0)
- return -1;
-
- if (read_wired_file && read_wired_cap_file(&wt, read_wired_file) < 0)
- return -1;
-
- if (read_file && read_cap_file(&wt, read_file) < 0)
- return -1;
-
- if (ifname && monitor_init(&wt, ifname) < 0)
- return -1;
-
- if (ifname_wired && monitor_init_wired(&wt, ifname_wired) < 0)
- return -1;
-
- if (ctrl_iface && ctrl_init(&wt) < 0)
- return -1;
+ if ((wt.write_file && write_pcap_init(&wt, wt.write_file) < 0) ||
+ (wt.pcapng_file && write_pcapng_init(&wt, wt.pcapng_file) < 0) ||
+ (read_wired_file &&
+ read_wired_cap_file(&wt, read_wired_file) < 0) ||
+ (read_file && read_cap_file(&wt, read_file) < 0) ||
+ (ifname && monitor_init(&wt, ifname) < 0) ||
+ (ifname_wired && monitor_init_wired(&wt, ifname_wired) < 0) ||
+ (ctrl_iface && ctrl_init(&wt) < 0)) {
+ ret = -1;
+ goto deinit;
+ }
eloop_register_signal_terminate(wlantest_terminate, &wt);
@@ -497,11 +508,13 @@ int main(int argc, char *argv[])
"fcs_error=%u",
wt.rx_mgmt, wt.rx_ctrl, wt.rx_data, wt.fcs_error);
+deinit:
wlantest_deinit(&wt);
wpa_debug_close_file();
- eloop_destroy();
+ if (eloop_init_done)
+ eloop_destroy();
os_program_deinit();
- return 0;
+ return ret;
}
diff --git a/wlantest/wlantest_cli.c b/wlantest/wlantest_cli.c
index ad5a48deaaf8..0a1384ed9e2a 100644
--- a/wlantest/wlantest_cli.c
+++ b/wlantest/wlantest_cli.c
@@ -12,25 +12,11 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/edit.h"
+#include "common/cli.h"
#include "wlantest_ctrl.h"
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
- int arg = 0, i;
-
- for (i = 0; i <= pos; i++) {
- if (str[i] != ' ') {
- arg++;
- while (i <= pos && str[i] != ' ')
- i++;
- }
- }
-
- if (arg > 0)
- arg--;
- return arg;
-}
+static void print_help(FILE *stream, const char *cmd);
+static char ** wlantest_cli_cmd_list(void);
static int get_prev_arg_pos(const char *str, int pos)
@@ -1566,6 +1552,28 @@ static char ** complete_get_tid(int s, const char *str, int pos)
}
+static int wlantest_cli_cmd_help(int s, int argc, char *argv[])
+{
+ print_help(stdout, argc > 0 ? argv[0] : NULL);
+ return 0;
+}
+
+
+static char ** wlantest_cli_complete_help(int s, const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = wlantest_cli_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
struct wlantest_cli_cmd {
const char *cmd;
int (*handler)(int s, int argc, char *argv[]);
@@ -1623,10 +1631,45 @@ static const struct wlantest_cli_cmd wlantest_cli_commands[] = {
{ "get_rx_tid", cmd_get_rx_tid,
"<BSSID> <STA> <TID> = get STA RX TID counter value",
complete_get_tid },
+ { "help", wlantest_cli_cmd_help,
+ "= show this usage help", wlantest_cli_complete_help },
{ NULL, NULL, NULL, NULL }
};
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct wlantest_cli_cmd *cmd,
+ const char *pad)
+{
+ char c;
+ size_t n;
+
+ if (!cmd->usage)
+ return;
+ fprintf(stream, "%s%s ", pad, cmd->cmd);
+ for (n = 0; (c = cmd->usage[n]); n++) {
+ fprintf(stream, "%c", c);
+ if (c == '\n')
+ fprintf(stream, "%s", pad);
+ }
+ fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+ int n;
+
+ fprintf(stream, "commands:\n");
+ for (n = 0; wlantest_cli_commands[n].cmd; n++) {
+ if (!cmd || str_starts(wlantest_cli_commands[n].cmd, cmd))
+ print_cmd_help(stream, &wlantest_cli_commands[n], " ");
+ }
+}
+
+
static int ctrl_command(int s, int argc, char *argv[])
{
const struct wlantest_cli_cmd *cmd, *match = NULL;
@@ -1672,38 +1715,6 @@ struct wlantest_cli {
};
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
-}
-
-
static void wlantest_cli_edit_cmd_cb(void *ctx, char *cmd)
{
struct wlantest_cli *cli = ctx;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0aacafd4ab96..7e597f396a07 100644
--- a/wpa_supplicant/Android.mk
+++ b/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/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index ce1c8b2e3366..cb66defac7c8 100644
--- a/wpa_supplicant/Makefile
+++ b/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/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 484e4cbf4724..b076621db527 100644
--- a/wpa_supplicant/README-HS20
+++ b/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/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c5177d915524..bf062b0792b7 100644
--- a/wpa_supplicant/config.c
+++ b/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/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 0320d9eebb57..d22ef05fb8ba 100644
--- a/wpa_supplicant/config.h
+++ b/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.
@@ -180,6 +181,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
*
* If set, this FQDN is used as a suffix match requirement for the AAA
@@ -1389,6 +1415,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
*
* This timeout value is used in mesh STA to retransmit
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 54fb72d8c1f7..6db5010db3a7 100644
--- a/wpa_supplicant/config_file.c
+++ b/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/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 339eead1c333..724534dd0123 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/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/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 9dc17f5eef85..bcd67fca3e12 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/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=<FQDN> */
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/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 2c01943f754e..9279ae4d5847 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/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/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 42db3892ed77..26bdcb548de8 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/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/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index db9f30c9aabf..545e9f64295a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/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
};
@@ -329,6 +333,110 @@ error:
/**
+ * 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
* @type: DBus type of property (must be basic type)
@@ -1516,6 +1624,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
* @wpa_s: wpa_supplicant structure for a network interface
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index c36383f05668..a421083f7fe2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/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/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 565ced0fd7e2..de79178f4655 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/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/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 708a82385170..a4719dbb543d 100644
--- a/wpa_supplicant/defconfig
+++ b/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/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 40ef8aeb510f..584654a6cb2c 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/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 @@ skip_trans_id:
#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/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 5f5c50ba9754..f55e1846e205 100644
--- a/wpa_supplicant/events.c
+++ b/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/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 1c82d2117ab0..71a5c16510d4 100644
--- a/wpa_supplicant/interworking.c
+++ b/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/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7938b8b4903e..d6b8a1ad9e36 100644
--- a/wpa_supplicant/mesh.c
+++ b/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, &params->freq)) {
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 38f0d641a03b..2eb9a7ef6182 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/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/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index fe5e072c24c2..821c916c153f 100644
--- a/wpa_supplicant/notify.c
+++ b/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/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index e843aa124b39..c46e7986e3b3 100644
--- a/wpa_supplicant/notify.h
+++ b/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/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index f2c42ff354e7..1dc7001a7305 100644
--- a/wpa_supplicant/sme.c
+++ b/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/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index ecbc16dacd9d..c797d2e9e796 100644
--- a/wpa_supplicant/sme.h
+++ b/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/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b72983e9c3f7..17b14c824ddb 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/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/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index b80f1d4f0b38..1785f88ab73d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4513,6 +4513,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
* @pkcs11_engine_path: PKCS #11 engine path or NULL
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index fa257f3dec1b..6619d6ba7fb1 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/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/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index cbc955159bbe..5fa765fda25c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/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);