wpa: Import wpa_supplicant/hostapd commit b26f5c0fe

This is the December/January update to vendor/wpa committed upstream
2021-12-13.
This commit is contained in:
Cy Schubert 2022-01-05 22:05:32 -08:00
parent 56f32b0e4c
commit 7b54fad807
63 changed files with 1699 additions and 400 deletions

View File

@ -552,6 +552,32 @@ fi.w1.wpa_supplicant1.CreateInterface.
<h3>AbortScan ( ) --> nothing</h3>
<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>
@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -1554,17 +1554,38 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
#ifdef CONFIG_TESTING_OPTIONS
skip_connector:
if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP) {
wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
goto skip_proto_ver;
}
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
if (DPP_VERSION > 1) {
u8 ver = DPP_VERSION;
#ifdef CONFIG_DPP3
int conn_ver;
conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector);
if (conn_ver > 0 && ver != conn_ver) {
wpa_printf(MSG_DEBUG,
"DPP: Use Connector version %d instead of current protocol version %d",
conn_ver, ver);
ver = conn_ver;
}
#endif /* CONFIG_DPP3 */
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, DPP_VERSION);
wpabuf_put_u8(msg, ver);
}
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
skip_proto_ver:
#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
" status=%d", MAC2STR(src), status);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
@ -1648,6 +1669,28 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
return;
}
#ifdef CONFIG_DPP3
if (intro.peer_version && intro.peer_version >= 2) {
const u8 *version;
u16 version_len;
u8 attr_version = 1;
version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
&version_len);
if (version && version_len >= 1)
attr_version = version[0];
if (attr_version != intro.peer_version) {
wpa_printf(MSG_INFO,
"DPP: Protocol version mismatch (Connector: %d Attribute: %d",
intro.peer_version, attr_version);
hostapd_dpp_send_peer_disc_resp(hapd, src, freq,
trans_id[0],
DPP_STATUS_NO_MATCH);
return;
}
}
#endif /* CONFIG_DPP3 */
if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
expire = hapd->conf->dpp_netaccesskey_expiry;
if (expire)
@ -1670,7 +1713,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
static void
hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
const u8 *buf, size_t len,
unsigned int freq)
unsigned int freq, bool v2)
{
struct wpabuf *msg;
@ -1698,7 +1741,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
hapd->own_addr, src,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code,
buf, len);
buf, len, v2);
if (!hapd->dpp_pkex) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to process the request - ignore it");
@ -1910,8 +1953,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
case DPP_PA_PEER_DISCOVERY_REQ:
hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
break;
#ifdef CONFIG_DPP3
case DPP_PA_PKEX_EXCHANGE_REQ:
hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
/* This is for PKEXv2, but for now, process only with
* CONFIG_DPP3 to avoid issues with a capability that has not
* been tested with other implementations. */
hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
true);
break;
#endif /* CONFIG_DPP3 */
case DPP_PA_PKEX_V1_EXCHANGE_REQ:
hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
false);
break;
case DPP_PA_PKEX_EXCHANGE_RESP:
hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
@ -2118,15 +2171,16 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
if (!hapd->dpp_pkex_code)
return -1;
if (os_strstr(cmd, " init=1")) {
if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
struct wpabuf *msg;
bool v2 = os_strstr(cmd, " init=2") != NULL;
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
dpp_pkex_free(hapd->dpp_pkex);
hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
hapd->own_addr,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code);
hapd->dpp_pkex_code, v2);
if (!hapd->dpp_pkex)
return -1;
@ -2134,7 +2188,8 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
/* TODO: Which channel to use? */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d", MAC2STR(broadcast), 2437,
DPP_PA_PKEX_EXCHANGE_REQ);
v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
hostapd_drv_send_action(hapd, 2437, 0, broadcast,
wpabuf_head(msg), wpabuf_len(msg));
}

View File

@ -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);

View File

@ -3461,6 +3461,20 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
NULL))
return -1;
switch (params->bandwidth) {
case 0:
case 20:
conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
break;
case 40:
case 80:
case 160:
conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
break;
default:
return -1;
}
switch (params->bandwidth) {
case 0:
case 20:
@ -3482,6 +3496,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
conf->channel = channel;
conf->ieee80211n = params->ht_enabled;
conf->ieee80211ac = params->vht_enabled;
conf->secondary_channel = params->sec_channel_offset;
ieee80211_freq_to_chan(params->center_freq1,
&seg0);

View File

@ -28,7 +28,9 @@
static const char * dpp_netrole_str(enum dpp_netrole netrole);
#ifdef CONFIG_TESTING_OPTIONS
#ifdef CONFIG_DPP2
#ifdef CONFIG_DPP3
int dpp_version_override = 3;
#elif defined(CONFIG_DPP2)
int dpp_version_override = 2;
#else
int dpp_version_override = 1;
@ -306,6 +308,8 @@ int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
bi->version = 1;
else if (*version == '2')
bi->version = 2;
else if (*version == '3')
bi->version = 3;
else
wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
@ -628,7 +632,8 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi)
macstr,
bi->info ? "I:" : "", bi->info ? bi->info : "",
bi->info ? ";" : "",
DPP_VERSION == 2 ? "V:2;" : "",
DPP_VERSION == 3 ? "V:3;" :
(DPP_VERSION == 2 ? "V:2;" : ""),
bi->pk);
return 0;
}
@ -1499,6 +1504,10 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
json_value_sep(dppcon);
json_add_string(dppcon, "expiry", expiry);
}
#ifdef CONFIG_DPP3
json_value_sep(dppcon);
json_add_int(dppcon, "version", auth->peer_version);
#endif /* CONFIG_DPP3 */
json_end_object(dppcon);
wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
(const char *) wpabuf_head(dppcon));
@ -3694,6 +3703,14 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
}
}
#ifdef CONFIG_DPP3
token = json_get_member(root, "version");
if (token && token->type == JSON_NUMBER) {
wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
intro->peer_version = token->number;
}
#endif /* CONFIG_DPP3 */
netkey = json_get_member(root, "netAccessKey");
if (!netkey || netkey->type != JSON_OBJECT) {
wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
@ -3751,6 +3768,26 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
}
#ifdef CONFIG_DPP3
int dpp_get_connector_version(const char *connector)
{
struct json_token *root, *token;
int ver = -1;
root = dpp_parse_own_connector(connector);
if (!root)
return -1;
token = json_get_member(root, "version");
if (token && token->type == JSON_NUMBER)
ver = token->number;
json_free(root);
return ver;
}
#endif /* CONFIG_DPP3 */
unsigned int dpp_next_id(struct dpp_global *dpp)
{
struct dpp_bootstrap_info *bi;

View File

@ -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);

View File

@ -1447,12 +1447,15 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
struct crypto_bignum *hash_bn = NULL;
struct crypto_ec *ec = NULL;
/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
addr[num_elem] = mac_init;
len[num_elem] = ETH_ALEN;
num_elem++;
if (mac_init) {
wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR,
MAC2STR(mac_init));
addr[num_elem] = mac_init;
len[num_elem] = ETH_ALEN;
num_elem++;
}
if (identifier) {
wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
identifier);
@ -1467,7 +1470,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
"DPP: H(MAC-Initiator | [identifier |] code)",
"DPP: H([MAC-Initiator |] [identifier |] code)",
hash, curve->hash_len);
Pi_key = dpp_pkex_get_role_elem(curve, 1);
if (!Pi_key)
@ -1519,12 +1522,15 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
struct crypto_bignum *hash_bn = NULL;
struct crypto_ec *ec = NULL;
/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
addr[num_elem] = mac_resp;
len[num_elem] = ETH_ALEN;
num_elem++;
if (mac_resp) {
wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR,
MAC2STR(mac_resp));
addr[num_elem] = mac_resp;
len[num_elem] = ETH_ALEN;
num_elem++;
}
if (identifier) {
wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
identifier);
@ -1539,7 +1545,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG,
"DPP: H(MAC-Responder | [identifier |] code)",
"DPP: H([MAC-Responder |] [identifier |] code)",
hash, curve->hash_len);
Pr_key = dpp_pkex_get_role_elem(curve, 0);
if (!Pr_key)
@ -1578,6 +1584,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
u8 ver_init, u8 ver_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
const char *code,
@ -1589,7 +1596,10 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
u8 *info, *pos;
size_t info_len;
/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
/*
* v1: info = MAC-Initiator | MAC-Responder
* v2: info = Protocol Version-Initiator | Protocol Version-Responder
* z = HKDF(<>, info | M.x | N.x | code, K.x)
*/
/* HKDF-Extract(<>, IKM=K.x) */
@ -1598,15 +1608,24 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
return -1;
wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
prk, hash_len);
info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
if (mac_init && mac_resp)
info_len = 2 * ETH_ALEN;
else
info_len = 2;
info_len += Mx_len + Nx_len + os_strlen(code);
info = os_malloc(info_len);
if (!info)
return -1;
pos = info;
os_memcpy(pos, mac_init, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, mac_resp, ETH_ALEN);
pos += ETH_ALEN;
if (mac_init && mac_resp) {
os_memcpy(pos, mac_init, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, mac_resp, ETH_ALEN);
pos += ETH_ALEN;
} else {
*pos++ = ver_init;
*pos++ = ver_resp;
}
os_memcpy(pos, Mx, Mx_len);
pos += Mx_len;
os_memcpy(pos, Nx, Nx_len);

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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 =

View File

@ -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;
};

View File

@ -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)) ||

View File

@ -508,7 +508,7 @@ def dpp_auth_init(self, peer=None, uri=None, conf=None, configurator=None,
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 @@ def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None,
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:

View File

@ -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 @@ def proc_run(self, command):
_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

View File

@ -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):

View File

@ -6091,3 +6091,114 @@ def success(self):
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")

View File

@ -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",

49
tests/hwsim/test_dpp3.py Normal file
View File

@ -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)

View File

@ -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"):

View File

@ -1577,7 +1577,7 @@ def dpp_auth_init(self, peer=None, uri=None, conf=None, configurator=None,
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 @@ def dpp_pkex_init(self, identifier, code, role=None, key=None, curve=None,
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:

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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={

View File

@ -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 },

View File

@ -18,6 +18,7 @@
#define DEFAULT_USER_MPM 1
#define DEFAULT_MAX_PEER_LINKS 99
#define DEFAULT_MESH_MAX_INACTIVITY 300
#define DEFAULT_MESH_FWDING 1
/*
* The default dot11RSNASAERetransPeriod is defined as 40 ms in the standard,
* but use 1000 ms in practice to avoid issues on low power CPUs.
@ -179,6 +180,31 @@ struct wpa_cred {
*/
char *milenage;
/**
* engine - Use an engine for private key operations
*/
int engine;
/**
* engine_id - String identifying the engine to use
*/
char *engine_id;
/**
* ca_cert_id - The CA certificate identifier when using an engine
*/
char *ca_cert_id;
/**
* cert_id - The certificate identifier when using an engine
*/
char *cert_id;
/**
* key_id - The private key identifier when using an engine
*/
char *key_id;
/**
* domain_suffix_match - Constraint for server domain name
*
@ -1388,6 +1414,14 @@ struct wpa_config {
*/
int mesh_max_inactivity;
/**
* mesh_fwding - Mesh network layer-2 forwarding (dot11MeshForwarding)
*
* This controls whether to enable layer-2 forwarding.
* By default: 1: enabled
*/
int mesh_fwding;
/**
* dot11RSNASAERetransPeriod - Timeout to retransmit SAE Auth frame
*

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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 } }
};

View File

@ -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 */

View File

@ -26,6 +26,7 @@
#include "../scan.h"
#include "../autoscan.h"
#include "../ap.h"
#include "../interworking.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
@ -148,6 +149,9 @@ static const char * const dont_quote[] = {
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
#ifdef CONFIG_INTERWORKING
"roaming_consortium", "required_roaming_consortium",
#endif /* CONFIG_INTERWORKING */
NULL
};
@ -328,6 +332,110 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
}
/**
* set_cred_properties - Set the properties of a configured credential
* @wpa_s: wpa_supplicant structure for a network interface
* @cred: wpa_cred structure for a configured credential
* @iter: DBus message iterator containing dictionary of network
* properties to set.
* @error: On failure, an error describing the failure
* Returns: TRUE if the request succeeds, FALSE if it failed
*/
static dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s,
struct wpa_cred *cred,
DBusMessageIter *iter,
DBusError *error)
{
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
DBusMessageIter iter_dict;
char *value = NULL;
if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
return FALSE;
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
size_t size = 50;
int ret;
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
value = NULL;
if (entry.type == DBUS_TYPE_ARRAY &&
entry.array_type == DBUS_TYPE_BYTE) {
if (entry.array_len <= 0)
goto error;
size = entry.array_len * 2 + 1;
value = os_zalloc(size);
if (!value)
goto error;
ret = wpa_snprintf_hex(value, size,
(u8 *) entry.bytearray_value,
entry.array_len);
if (ret <= 0)
goto error;
} else if (entry.type == DBUS_TYPE_STRING) {
if (should_quote_opt(entry.key)) {
size = os_strlen(entry.str_value);
size += 3;
value = os_zalloc(size);
if (!value)
goto error;
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
if (!value)
goto error;
}
} else if (entry.type == DBUS_TYPE_UINT32) {
value = os_zalloc(size);
if (!value)
goto error;
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
if (!value)
goto error;
ret = os_snprintf(value, size, "%d",
entry.int32_value);
if (os_snprintf_error(size, ret))
goto error;
} else {
goto error;
}
ret = wpa_config_set_cred(cred, entry.key, value, 0);
if (ret < 0)
goto error;
os_free(value);
value = NULL;
wpa_dbus_dict_entry_clear(&entry);
}
return TRUE;
error:
os_free(value);
wpa_dbus_dict_entry_clear(&entry);
dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
"invalid message format");
return FALSE;
}
/**
* wpas_dbus_simple_property_getter - Get basic type property
* @iter: Message iter to use when appending arguments
@ -1515,6 +1623,185 @@ DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
}
/**
* wpas_dbus_new_iface_add_cred - Add a new credential
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: A dbus message containing the object path of the new credential
*
* Handler function for "AddCred" method call of a network interface.
*/
DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
DBusMessageIter iter;
struct wpa_cred *cred = NULL;
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
DBusError error;
dbus_message_iter_init(message, &iter);
if (wpa_s->dbus_new_path)
cred = wpa_config_add_cred(wpa_s->conf);
if (!cred) {
wpa_printf(MSG_ERROR, "%s[dbus]: can't add new credential.",
__func__);
reply = wpas_dbus_error_unknown_error(
message,
"wpa_supplicant could not add a credential on this interface.");
goto err;
}
dbus_error_init(&error);
if (!set_cred_properties(wpa_s, cred, &iter, &error)) {
wpa_printf(MSG_DEBUG,
"%s[dbus]: control interface couldn't set credential properties",
__func__);
reply = wpas_dbus_reply_new_from_error(message, &error,
DBUS_ERROR_INVALID_ARGS,
"Failed to add credential");
dbus_error_free(&error);
goto err;
}
/* Construct the object path for this network. */
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d",
wpa_s->dbus_new_path, cred->id);
reply = dbus_message_new_method_return(message);
if (!reply) {
reply = wpas_dbus_error_no_memory(message);
goto err;
}
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
reply = wpas_dbus_error_no_memory(message);
goto err;
}
return reply;
err:
if (cred)
wpa_config_remove_cred(wpa_s->conf, cred->id);
return reply;
}
/**
* wpas_dbus_handler_remove_cred - Remove a configured credential
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: NULL on success or dbus error on failure
*
* Handler function for "RemoveCred" method call of a network interface.
*/
DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
DBusMessage *reply = NULL;
const char *op;
char *iface, *cred_id;
int id;
struct wpa_cred *cred;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
/* Extract the network ID and ensure the network is actually a child of
* this interface */
iface = wpas_dbus_new_decompose_object_path(
op, WPAS_DBUS_NEW_CREDENTIALS_PART, &cred_id);
if (!iface || !cred_id || !wpa_s->dbus_new_path ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
errno = 0;
id = strtoul(cred_id, NULL, 10);
if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
cred = wpa_config_get_cred(wpa_s->conf, id);
if (!cred) {
wpa_printf(MSG_ERROR, "%s[dbus]: could not find credential %s",
__func__, op);
reply = wpas_dbus_error_invalid_args(
message, "could not find credential");
goto out;
}
if (wpas_remove_cred(wpa_s, cred) < 0) {
wpa_printf(MSG_ERROR,
"%s[dbus]: error occurred when removing cred %d",
__func__, id);
reply = wpas_dbus_error_unknown_error(
message,
"error removing the specified credential on its interface.");
goto out;
}
out:
os_free(iface);
return reply;
}
/**
* wpas_dbus_handler_remove_all_creds - Remove all the configured credentials
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: NULL indicating success or DBus error message on failure
*
* Handler function for "RemoveAllCreds" method call of a network interface.
*/
DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
int res;
DBusMessage *reply = NULL;
res = wpas_remove_all_creds(wpa_s);
if (res < 0) {
wpa_printf(MSG_ERROR,
"%s[dbus]: failed to remove all credentials",
__func__);
reply = wpas_dbus_error_unknown_error(
message, "failed to remove all credentials");
}
return reply;
}
DBusMessage *
wpas_dbus_handler_interworking_select(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
int result;
DBusMessage *reply = NULL;
/* Automatic selection is disabled and no constraint on channels */
result = interworking_select(wpa_s, 0, NULL);
if (result < 0) {
wpa_printf(MSG_ERROR,
"%s[dbus]: failed to start Interworking selection",
__func__);
reply = wpas_dbus_error_scan_error(
message,
"error starting Interworking selection.");
}
return reply;
}
/**
* wpas_dbus_handler_signal_poll - Request immediate signal properties
* @message: Pointer to incoming dbus message

View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -1021,6 +1021,7 @@ void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s)
wpa_drv_dpp_listen(wpa_s, false);
wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
radio_remove_works(wpa_s, "dpp-listen", 0);
}
@ -2462,6 +2463,16 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
&version_len);
if (version && version_len >= 1)
peer_version = version[0];
#ifdef CONFIG_DPP3
if (intro.peer_version && intro.peer_version >= 2 &&
peer_version != intro.peer_version) {
wpa_printf(MSG_INFO,
"DPP: Protocol version mismatch (Connector: %d Attribute: %d",
intro.peer_version, peer_version);
wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
goto fail;
}
#endif /* CONFIG_DPP3 */
entry->dpp_pfs = peer_version >= 2;
#endif /* CONFIG_DPP2 */
if (expiry) {
@ -2568,7 +2579,9 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
pkex->exch_req_tries);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
MAC2STR(broadcast), pkex->freq,
pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
offchannel_send_action(wpa_s, pkex->freq, broadcast,
wpa_s->own_addr, broadcast,
wpabuf_head(pkex->exchange_req),
@ -2627,7 +2640,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
static void
wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len, unsigned int freq)
const u8 *buf, size_t len, unsigned int freq,
bool v2)
{
struct wpabuf *msg;
unsigned int wait_time;
@ -2655,7 +2669,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_s->own_addr, src,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code,
buf, len);
buf, len, v2);
if (!wpa_s->dpp_pkex) {
wpa_printf(MSG_DEBUG,
"DPP: Failed to process the request - ignore it");
@ -2878,8 +2892,17 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
case DPP_PA_PEER_DISCOVERY_RESP:
wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
break;
#ifdef CONFIG_DPP3
case DPP_PA_PKEX_EXCHANGE_REQ:
wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq);
/* This is for PKEXv2, but for now, process only with
* CONFIG_DPP3 to avoid issues with a capability that has not
* been tested with other implementations. */
wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, true);
break;
#endif /* CONFIG_DPP3 */
case DPP_PA_PKEX_V1_EXCHANGE_REQ:
wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq,
false);
break;
case DPP_PA_PKEX_EXCHANGE_RESP:
wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
@ -3192,17 +3215,38 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
#ifdef CONFIG_TESTING_OPTIONS
skip_connector:
if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ) {
wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
goto skip_proto_ver;
}
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
if (DPP_VERSION > 1) {
u8 ver = DPP_VERSION;
#ifdef CONFIG_DPP3
int conn_ver;
conn_ver = dpp_get_connector_version(ssid->dpp_connector);
if (conn_ver > 0 && ver != conn_ver) {
wpa_printf(MSG_DEBUG,
"DPP: Use Connector version %d instead of current protocol version %d",
conn_ver, ver);
ver = conn_ver;
}
#endif /* CONFIG_DPP3 */
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, DPP_VERSION);
wpabuf_put_u8(msg, ver);
}
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
skip_proto_ver:
#endif /* CONFIG_TESTING_OPTIONS */
/* TODO: Timeout on AP response */
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
@ -3270,15 +3314,16 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
if (!wpa_s->dpp_pkex_code)
return -1;
if (os_strstr(cmd, " init=1")) {
if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
struct dpp_pkex *pkex;
struct wpabuf *msg;
bool v2 = os_strstr(cmd, " init=2") != NULL;
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
dpp_pkex_free(wpa_s->dpp_pkex);
wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code);
wpa_s->dpp_pkex_code, v2);
pkex = wpa_s->dpp_pkex;
if (!pkex)
return -1;
@ -3291,7 +3336,8 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d",
MAC2STR(broadcast), pkex->freq,
DPP_PA_PKEX_EXCHANGE_REQ);
v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
offchannel_send_action(wpa_s, pkex->freq, broadcast,
wpa_s->own_addr, broadcast,
wpabuf_head(msg), wpabuf_len(msg),

View File

@ -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 &&

View File

@ -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));

View File

@ -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)) {

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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"

View File

@ -4512,6 +4512,82 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
}
/**
* wpas_remove_cred - Remove the specified credential and all the network
* entries created based on the removed credential
* @wpa_s: wpa_supplicant structure for a network interface
* @cred: The credential to remove
* Returns: 0 on success, -1 on failure
*/
int wpas_remove_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred)
{
struct wpa_ssid *ssid, *next;
int id;
if (!cred) {
wpa_printf(MSG_DEBUG, "Could not find cred");
return -1;
}
id = cred->id;
if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
wpa_printf(MSG_DEBUG, "Could not find cred %d", id);
return -1;
}
wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
/* Remove any network entry created based on the removed credential */
ssid = wpa_s->conf->ssid;
while (ssid) {
next = ssid->next;
if (ssid->parent_cred == cred) {
wpa_printf(MSG_DEBUG,
"Remove network id %d since it used the removed credential",
ssid->id);
if (wpa_supplicant_remove_network(wpa_s, ssid->id) ==
-1) {
wpa_printf(MSG_DEBUG,
"Could not find network id=%d",
ssid->id);
}
}
ssid = next;
}
return 0;
}
/**
* wpas_remove_cred - Remove all the Interworking credentials
* @wpa_s: wpa_supplicant structure for a network interface
* Returns: 0 on success, -1 on failure
*/
int wpas_remove_all_creds(struct wpa_supplicant *wpa_s)
{
int res, ret = 0;
struct wpa_cred *cred, *prev;
cred = wpa_s->conf->cred;
while (cred) {
prev = cred;
cred = cred->next;
res = wpas_remove_cred(wpa_s, prev);
if (res < 0) {
wpa_printf(MSG_DEBUG,
"Removal of all credentials failed - failed to remove credential id=%d",
prev->id);
ret = -1;
}
}
return ret;
}
/**
* wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
* @wpa_s: wpa_supplicant structure for a network interface

View File

@ -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

View File

@ -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);