summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Lippers-Hollmann <s.l-h@gmx.de>2014-10-14 12:39:25 +0000
committerAndrew Shadura <andrewsh@debian.org>2016-07-20 23:23:37 +0200
commit6e1f9c092d6958a8a1c01629f43941647dc7fc20 (patch)
treecf3c0e907680dcc04786ee490c8b6227abfc5c02 /src
parent7ea3403faef12dfe4f6ee746c3e21306b4dc4460 (diff)
Imported Upstream version 2.3
Diffstat (limited to 'src')
-rw-r--r--src/ap/ap_config.c10
-rw-r--r--src/ap/beacon.c26
-rw-r--r--src/ap/ctrl_iface_ap.c7
-rw-r--r--src/ap/dfs.c98
-rw-r--r--src/ap/drv_callbacks.c29
-rw-r--r--src/ap/eap_user_db.c10
-rw-r--r--src/ap/gas_serv.c13
-rw-r--r--src/ap/hostapd.c212
-rw-r--r--src/ap/hostapd.h19
-rw-r--r--src/ap/ieee802_11.c5
-rw-r--r--src/ap/ieee802_11_ht.c6
-rw-r--r--src/ap/ieee802_11_vht.c14
-rw-r--r--src/ap/ieee802_1x.c106
-rw-r--r--src/ap/pmksa_cache_auth.c65
-rw-r--r--src/ap/sta_info.c2
-rw-r--r--src/ap/sta_info.h3
-rw-r--r--src/ap/wnm_ap.c5
-rw-r--r--src/ap/wpa_auth.c9
-rw-r--r--src/ap/wpa_auth_ft.c62
-rw-r--r--src/common/ieee802_11_common.c57
-rw-r--r--src/common/ieee802_11_common.h1
-rw-r--r--src/common/ieee802_11_defs.h1
-rw-r--r--src/common/qca-vendor.h24
-rw-r--r--src/common/sae.c2
-rw-r--r--src/common/version.h2
-rw-r--r--src/common/wpa_common.c24
-rw-r--r--src/common/wpa_common.h1
-rw-r--r--src/common/wpa_ctrl.h26
-rw-r--r--src/crypto/aes-ccm.c2
-rw-r--r--src/crypto/aes-gcm.c2
-rw-r--r--src/crypto/aes-unwrap.c19
-rw-r--r--src/crypto/aes-wrap.c20
-rw-r--r--src/crypto/aes_wrap.h8
-rw-r--r--src/crypto/crypto_openssl.c39
-rw-r--r--src/crypto/milenage.c4
-rw-r--r--src/crypto/tls_openssl.c34
-rw-r--r--src/drivers/driver.h89
-rw-r--r--src/drivers/driver_atheros.c41
-rw-r--r--src/drivers/driver_common.c21
-rw-r--r--src/drivers/driver_nl80211.c502
-rw-r--r--src/drivers/driver_test.c2
-rw-r--r--src/drivers/driver_wext.c41
-rw-r--r--src/drivers/drivers.mak7
-rw-r--r--src/drivers/drivers.mk4
-rw-r--r--src/drivers/nl80211_copy.h150
-rw-r--r--src/eap_common/eap_eke_common.c2
-rw-r--r--src/eap_common/eap_fast_common.c2
-rw-r--r--src/eap_common/eap_fast_common.h2
-rw-r--r--src/eap_common/eap_gpsk_common.c19
-rw-r--r--src/eap_common/eap_ikev2_common.c12
-rw-r--r--src/eap_common/eap_ikev2_common.h7
-rw-r--r--src/eap_common/eap_pwd_common.c14
-rw-r--r--src/eap_common/eap_sim_common.c13
-rw-r--r--src/eap_common/eap_sim_common.h3
-rw-r--r--src/eap_common/ikev2_common.c71
-rw-r--r--src/eap_common/ikev2_common.h4
-rw-r--r--src/eap_peer/eap.c21
-rw-r--r--src/eap_peer/eap_aka.c52
-rw-r--r--src/eap_peer/eap_config.h4
-rw-r--r--src/eap_peer/eap_eke.c12
-rw-r--r--src/eap_peer/eap_fast.c16
-rw-r--r--src/eap_peer/eap_gpsk.c27
-rw-r--r--src/eap_peer/eap_i.h1
-rw-r--r--src/eap_peer/eap_ikev2.c15
-rw-r--r--src/eap_peer/eap_leap.c5
-rw-r--r--src/eap_peer/eap_mschapv2.c41
-rw-r--r--src/eap_peer/eap_pax.c6
-rw-r--r--src/eap_peer/eap_peap.c18
-rw-r--r--src/eap_peer/eap_psk.c4
-rw-r--r--src/eap_peer/eap_pwd.c64
-rw-r--r--src/eap_peer/eap_sake.c4
-rw-r--r--src/eap_peer/eap_sim.c39
-rw-r--r--src/eap_peer/eap_tls.c16
-rw-r--r--src/eap_peer/eap_tnc.c3
-rw-r--r--src/eap_peer/eap_ttls.c26
-rw-r--r--src/eap_peer/ikev2.c60
-rw-r--r--src/eap_peer/mschapv2.c4
-rw-r--r--src/eap_peer/tncc.c4
-rw-r--r--src/eap_server/eap_server.c12
-rw-r--r--src/eap_server/eap_server_aka.c14
-rw-r--r--src/eap_server/eap_server_eke.c6
-rw-r--r--src/eap_server/eap_server_fast.c27
-rw-r--r--src/eap_server/eap_server_gpsk.c6
-rw-r--r--src/eap_server/eap_server_gtc.c2
-rw-r--r--src/eap_server/eap_server_ikev2.c2
-rw-r--r--src/eap_server/eap_server_md5.c2
-rw-r--r--src/eap_server/eap_server_mschapv2.c4
-rw-r--r--src/eap_server/eap_server_pax.c17
-rw-r--r--src/eap_server/eap_server_peap.c4
-rw-r--r--src/eap_server/eap_server_psk.c4
-rw-r--r--src/eap_server/eap_server_pwd.c78
-rw-r--r--src/eap_server/eap_server_sake.c6
-rw-r--r--src/eap_server/eap_server_sim.c12
-rw-r--r--src/eap_server/eap_server_tnc.c3
-rw-r--r--src/eap_server/eap_server_ttls.c22
-rw-r--r--src/eap_server/ikev2.c2
-rw-r--r--src/eapol_supp/eapol_supp_sm.c23
-rw-r--r--src/eapol_supp/eapol_supp_sm.h5
-rw-r--r--src/p2p/p2p.c184
-rw-r--r--src/p2p/p2p.h72
-rw-r--r--src/p2p/p2p_dev_disc.c6
-rw-r--r--src/p2p/p2p_go_neg.c23
-rw-r--r--src/p2p/p2p_group.c48
-rw-r--r--src/p2p/p2p_i.h6
-rw-r--r--src/p2p/p2p_invitation.c7
-rw-r--r--src/p2p/p2p_pd.c13
-rw-r--r--src/p2p/p2p_sd.c16
-rw-r--r--src/p2p/p2p_utils.c35
-rw-r--r--src/pae/ieee802_1x_kay.c9
-rw-r--r--src/radius/radius.c21
-rw-r--r--src/radius/radius.h6
-rw-r--r--src/radius/radius_client.c22
-rw-r--r--src/radius/radius_server.c12
-rw-r--r--src/rsn_supp/peerkey.c56
-rw-r--r--src/rsn_supp/peerkey.h6
-rw-r--r--src/rsn_supp/pmksa_cache.c8
-rw-r--r--src/rsn_supp/tdls.c319
-rw-r--r--src/rsn_supp/wpa.c186
-rw-r--r--src/rsn_supp/wpa.h6
-rw-r--r--src/rsn_supp/wpa_ft.c21
-rw-r--r--src/rsn_supp/wpa_i.h14
-rw-r--r--src/rsn_supp/wpa_ie.c2
-rw-r--r--src/tls/pkcs1.c2
-rw-r--r--src/tls/tlsv1_client_read.c2
-rw-r--r--src/tls/tlsv1_common.c3
-rw-r--r--src/tls/tlsv1_record.c2
-rw-r--r--src/tls/tlsv1_server_read.c2
-rw-r--r--src/tls/x509v3.c2
-rw-r--r--src/utils/browser-android.c6
-rw-r--r--src/utils/browser-system.c2
-rw-r--r--src/utils/browser-wpadebug.c13
-rw-r--r--src/utils/common.c43
-rw-r--r--src/utils/common.h7
-rw-r--r--src/utils/ext_password_test.c2
-rw-r--r--src/utils/http_curl.c12
-rw-r--r--src/utils/os.h26
-rw-r--r--src/utils/os_internal.c14
-rw-r--r--src/utils/os_none.c5
-rw-r--r--src/utils/os_unix.c71
-rw-r--r--src/utils/os_win32.c20
-rw-r--r--src/utils/pcsc_funcs.c6
-rw-r--r--src/utils/wpa_debug.c28
-rw-r--r--src/utils/wpa_debug.h16
-rw-r--r--src/wps/httpread.c4
-rw-r--r--src/wps/wps.c13
-rw-r--r--src/wps/wps_attr_process.c4
-rw-r--r--src/wps/wps_enrollee.c22
-rw-r--r--src/wps/wps_er.c15
-rw-r--r--src/wps/wps_registrar.c28
-rw-r--r--src/wps/wps_upnp.c7
150 files changed, 2943 insertions, 1198 deletions
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 7535b1b..d7d5c3b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -379,7 +379,7 @@ void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
hostapd_config_free_radius_attr(user->accept_attr);
os_free(user->identity);
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
os_free(user);
}
@@ -388,7 +388,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- os_free(keys->key[i]);
+ bin_clear_free(keys->key[i], keys->len[i]);
keys->key[i] = NULL;
}
}
@@ -406,10 +406,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
while (psk) {
prev = psk;
psk = psk->next;
- os_free(prev);
+ bin_clear_free(prev, sizeof(*prev));
}
- os_free(conf->ssid.wpa_passphrase);
+ str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
hostapd_config_free_wep(&conf->ssid.wep);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -759,7 +759,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
- "allowed, disabling HT capabilites");
+ "allowed, disabling HT capabilities");
}
if (full_config && conf->ieee80211n &&
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2a4acf2..4cae0d9 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -113,6 +113,10 @@ static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid)
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return eid;
+ /* Let host drivers add this IE if DFS support is offloaded */
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return eid;
+
/*
* There is no DFS support and power constraint was not directly
* requested by config option.
@@ -220,7 +224,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
continue; /* can use same entry */
}
- if (start) {
+ if (start && prev) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
@@ -265,18 +269,18 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
u8 chan;
- if (!hapd->iface->cs_freq_params.freq)
+ if (!hapd->cs_freq_params.freq)
return eid;
- if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) ==
+ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
NUM_HOSTAPD_MODES)
return eid;
*eid++ = WLAN_EID_CHANNEL_SWITCH;
*eid++ = 3;
- *eid++ = hapd->iface->cs_block_tx;
+ *eid++ = hapd->cs_block_tx;
*eid++ = chan;
- *eid++ = hapd->iface->cs_count;
+ *eid++ = hapd->cs_count;
return eid;
}
@@ -286,12 +290,12 @@ static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
{
u8 sec_ch;
- if (!hapd->iface->cs_freq_params.sec_channel_offset)
+ if (!hapd->cs_freq_params.sec_channel_offset)
return eid;
- if (hapd->iface->cs_freq_params.sec_channel_offset == -1)
+ if (hapd->cs_freq_params.sec_channel_offset == -1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->iface->cs_freq_params.sec_channel_offset == 1)
+ else if (hapd->cs_freq_params.sec_channel_offset == 1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
else
return eid;
@@ -409,7 +413,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_roaming_consortium(hapd, pos);
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
- &hapd->iface->cs_c_off_proberesp);
+ &hapd->cs_c_off_proberesp);
#ifdef CONFIG_IEEE80211AC
pos = hostapd_eid_vht_capabilities(hapd, pos);
pos = hostapd_eid_vht_operation(hapd, pos);
@@ -824,7 +828,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
- &hapd->iface->cs_c_off_beacon);
+ &hapd->cs_c_off_beacon);
#ifdef CONFIG_IEEE80211AC
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
@@ -957,7 +961,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
- if (hapd->iface->csa_in_progress) {
+ if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
return -1;
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ccbbab5..39edbd7 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -230,11 +230,12 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
if (mgmt == NULL)
return -1;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
- " with minor reason code %u (stype=%u)",
- MAC2STR(addr), minor_reason_code, stype);
+ " with minor reason code %u (stype=%u (%s))",
+ MAC2STR(addr), minor_reason_code, stype,
+ fc2str(mgmt->frame_control));
- mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index c30f6d6..a6ec20b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -18,10 +18,12 @@
#include "dfs.h"
-static int dfs_get_used_n_chans(struct hostapd_iface *iface)
+static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
{
int n_chans = 1;
+ *seg1 = 0;
+
if (iface->conf->ieee80211n && iface->conf->secondary_channel)
n_chans = 2;
@@ -35,6 +37,10 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface)
case VHT_CHANWIDTH_160MHZ:
n_chans = 8;
break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ n_chans = 4;
+ *seg1 = 4;
+ break;
default:
break;
}
@@ -170,10 +176,10 @@ static int dfs_find_channel(struct hostapd_iface *iface,
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
- int i, channel_idx = 0, n_chans;
+ int i, channel_idx = 0, n_chans, n_chans1;
mode = iface->current_mode;
- n_chans = dfs_get_used_n_chans(iface);
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
for (i = 0; i < mode->num_channels; i++) {
@@ -246,12 +252,15 @@ static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
/* Return start channel idx we will use for mode->channels[idx] */
-static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
+static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
int channel_no = iface->conf->channel;
int res = -1, i;
+ int chan_seg1 = -1;
+
+ *seg1_start = -1;
/* HT40- */
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
@@ -270,9 +279,15 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
channel_no =
iface->conf->vht_oper_centr_freq_seg0_idx - 14;
break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ channel_no =
+ iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+ chan_seg1 =
+ iface->conf->vht_oper_centr_freq_seg1_idx - 6;
+ break;
default:
wpa_printf(MSG_INFO,
- "DFS only VHT20/40/80/160 is supported now");
+ "DFS only VHT20/40/80/160/80+80 is supported now");
channel_no = -1;
break;
}
@@ -288,6 +303,23 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
}
}
+ if (res != -1 && chan_seg1 > -1) {
+ int found = 0;
+
+ /* Get idx for seg1 */
+ mode = iface->current_mode;
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->chan == chan_seg1) {
+ *seg1_start = i;
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ res = -1;
+ }
+
if (res == -1) {
wpa_printf(MSG_DEBUG,
"DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
@@ -511,17 +543,17 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
int chan_width, int cf1, int cf2)
{
- int start_chan_idx;
+ int start_chan_idx, start_chan_idx1;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
- int n_chans, i, j, frequency = freq, radar_n_chans = 1;
+ int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
u8 radar_chan;
int res = 0;
/* Our configuration */
mode = iface->current_mode;
- start_chan_idx = dfs_get_start_chan_idx(iface);
- n_chans = dfs_get_used_n_chans(iface);
+ start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
/* Check we are on DFS channel(s) */
if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
@@ -604,19 +636,20 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
int hostapd_handle_dfs(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
- int res, n_chans, start_chan_idx;
+ int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
iface->cac_started = 0;
do {
/* Get start (first) channel for current configuration */
- start_chan_idx = dfs_get_start_chan_idx(iface);
+ start_chan_idx = dfs_get_start_chan_idx(iface,
+ &start_chan_idx1);
if (start_chan_idx == -1)
return -1;
/* Get number of used channels, depend on width */
- n_chans = dfs_get_used_n_chans(iface);
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
/* Setup CAC time */
iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
@@ -756,6 +789,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
}
+static int hostapd_csa_in_progress(struct hostapd_iface *iface)
+{
+ unsigned int i;
+ for (i = 0; i < iface->num_bss; i++)
+ if (iface->bss[i]->csa_in_progress)
+ return 1;
+ return 0;
+}
+
+
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -764,15 +807,15 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
u8 vht_oper_centr_freq_seg1_idx;
int skip_radar = 1;
struct csa_settings csa_settings;
- struct hostapd_data *hapd = iface->bss[0];
+ unsigned int i;
int err = 1;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
- iface->csa_in_progress ? "yes" : "no");
+ hostapd_csa_in_progress(iface) ? "yes" : "no");
/* Check if CSA in progress */
- if (iface->csa_in_progress)
+ if (hostapd_csa_in_progress(iface))
return 0;
/* Check if active CAC */
@@ -843,7 +886,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
return err;
}
- err = hostapd_switch_channel(hapd, &csa_settings);
+ for (i = 0; i < iface->num_bss; i++) {
+ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+ if (err)
+ break;
+ }
+
if (err) {
wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
err);
@@ -882,9 +930,8 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
/* mark radar frequency as invalid */
- res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
- chan_width, cf1, cf2,
- HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -914,20 +961,25 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int hostapd_is_dfs_required(struct hostapd_iface *iface)
{
- int n_chans, start_chan_idx;
+ int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
if (!iface->conf->ieee80211h || !iface->current_mode ||
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
/* Get start (first) channel for current configuration */
- start_chan_idx = dfs_get_start_chan_idx(iface);
+ start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
if (start_chan_idx == -1)
return -1;
/* Get number of used channels, depend on width */
- n_chans = dfs_get_used_n_chans(iface);
+ n_chans = dfs_get_used_n_chans(iface, &n_chans1);
/* Check if any of configured channels require DFS */
- return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+ res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
+ if (res)
+ return res;
+ if (start_chan_idx1 >= 0 && n_chans1 > 0)
+ res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
+ return res;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index fb095ef..3bde720 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -340,6 +340,9 @@ skip_wpa_check:
sta->auth_alg, req_ies, req_ies_len);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+
+ if (sta->auth_alg == WLAN_AUTH_FT)
+ ap_sta_set_authorized(hapd, sta, 1);
#else /* CONFIG_IEEE80211R */
/* Keep compiler silent about unused variables */
if (status) {
@@ -350,6 +353,8 @@ skip_wpa_check:
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
+ hostapd_set_sta_flags(hapd, sta);
+
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
@@ -489,9 +494,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
- if (hapd->iface->csa_in_progress &&
- freq == hapd->iface->cs_freq_params.freq) {
+ if (hapd->csa_in_progress &&
+ freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
+ ieee802_11_set_beacon(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
freq);
@@ -884,6 +890,20 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
#ifdef NEED_AP_MLME
+static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
+ hapd->conf->iface);
+
+ if (hapd->csa_in_progress) {
+ wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
+ hapd->conf->iface);
+ hostapd_switch_channel_fallback(hapd->iface,
+ &hapd->cs_freq_params);
+ }
+}
+
+
static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
struct dfs_event *radar)
{
@@ -1029,6 +1049,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->eapol_rx.data_len);
break;
case EVENT_ASSOC:
+ if (!data)
+ return;
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len,
@@ -1071,6 +1093,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
hostapd_event_get_survey(hapd, &data->survey_results);
break;
#ifdef NEED_AP_MLME
+ case EVENT_INTERFACE_UNAVAILABLE:
+ hostapd_event_iface_unavailable(hapd);
+ break;
case EVENT_DFS_RADAR_DETECTED:
if (!data)
break;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 371a73f..559d77f 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -83,7 +83,7 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "password") == 0 && argv[i]) {
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[i]);
user->password = (u8 *) os_strdup(argv[i]);
user->next = (void *) 1;
@@ -118,7 +118,7 @@ static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
if (len <= user->identity_len &&
os_memcmp(argv[id], user->identity, len) == 0 &&
(user->password == NULL || len > user->password_len)) {
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password_len = os_strlen(argv[id]);
user->password = (u8 *) os_strdup(argv[id]);
user->next = (void *) 1;
@@ -158,8 +158,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
return NULL;
}
- os_free(hapd->tmp_eap_user.identity);
- os_free(hapd->tmp_eap_user.password);
+ bin_clear_free(hapd->tmp_eap_user.identity,
+ hapd->tmp_eap_user.identity_len);
+ bin_clear_free(hapd->tmp_eap_user.password,
+ hapd->tmp_eap_user.password_len);
os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
hapd->tmp_eap_user.phase2 = phase2;
hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index b406880..ad07107 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -414,7 +414,7 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
gas_anqp_set_element_len(buf, realm_data_len);
}
gas_anqp_set_element_len(buf, len);
- } else if (nai_home_realm && hapd->conf->nai_realm_data) {
+ } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
home_realm_len);
}
@@ -686,7 +686,6 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
- struct gas_dialog_info *di,
const u8 *home_realm, size_t home_realm_len,
const u8 *icon_name, size_t icon_name_len)
{
@@ -962,7 +961,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
{
struct wpabuf *buf, *tx_buf;
- buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len,
qi->icon_name, qi->icon_name_len);
@@ -1214,13 +1213,11 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
{
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
- size_t hdr_len;
const u8 *sa, *data;
int prot;
mgmt = (const struct ieee80211_mgmt *) buf;
- hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
- if (hdr_len > len)
+ if (len < IEEE80211_HDRLEN + 2)
return;
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
@@ -1232,8 +1229,8 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
- len -= hdr_len;
- data = &mgmt->u.action.u.public_action.action;
+ len -= IEEE80211_HDRLEN + 1;
+ data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ed73301..3142391 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -311,8 +311,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_SQLITE
- os_free(hapd->tmp_eap_user.identity);
- os_free(hapd->tmp_eap_user.password);
+ bin_clear_free(hapd->tmp_eap_user.identity,
+ hapd->tmp_eap_user.identity_len);
+ bin_clear_free(hapd->tmp_eap_user.password,
+ hapd->tmp_eap_user.password_len);
#endif /* CONFIG_SQLITE */
}
@@ -691,10 +693,10 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
u8 if_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
- __func__, hapd, hapd->conf->iface, first);
+ __func__, hapd, conf->iface, first);
#ifdef EAP_SERVER_TNC
- if (hapd->conf->tnc && tncs_global_init() < 0) {
+ if (conf->tnc && tncs_global_init() < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
return -1;
}
@@ -702,37 +704,37 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (hapd->started) {
wpa_printf(MSG_ERROR, "%s: Interface %s was already started",
- __func__, hapd->conf->iface);
+ __func__, conf->iface);
return -1;
}
hapd->started = 1;
if (!first || first == -1) {
- if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+ if (hostapd_mac_comp_empty(conf->bssid) == 0) {
/* Allocate the next available BSSID. */
do {
inc_byte_array(hapd->own_addr, ETH_ALEN);
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
} else {
/* Allocate the configured BSSID. */
- os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+ os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
if (hostapd_mac_comp(hapd->own_addr,
hapd->iface->bss[0]->own_addr) ==
0) {
wpa_printf(MSG_ERROR, "BSS '%s' may not have "
"BSSID set to the MAC address of "
- "the radio", hapd->conf->iface);
+ "the radio", conf->iface);
return -1;
}
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- hapd->conf->iface, hapd->own_addr, hapd,
+ conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
- hapd->conf->bridge[0] ? hapd->conf->bridge :
- NULL, first == -1)) {
+ conf->bridge[0] ? conf->bridge : NULL,
+ first == -1)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
hapd->interface_added = 0;
@@ -747,7 +749,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
- if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+ if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
/*
@@ -781,9 +783,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
- hapd->conf->iface, MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
+ conf->iface, MAC2STR(hapd->own_addr),
+ wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
}
if (hostapd_setup_wpa_psk(conf)) {
@@ -808,17 +809,17 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->radius_das_port) {
+ if (conf->radius_das_port) {
struct radius_das_conf das_conf;
os_memset(&das_conf, 0, sizeof(das_conf));
- das_conf.port = hapd->conf->radius_das_port;
- das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+ das_conf.port = conf->radius_das_port;
+ das_conf.shared_secret = conf->radius_das_shared_secret;
das_conf.shared_secret_len =
- hapd->conf->radius_das_shared_secret_len;
- das_conf.client_addr = &hapd->conf->radius_das_client_addr;
- das_conf.time_window = hapd->conf->radius_das_time_window;
+ conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &conf->radius_das_client_addr;
+ das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
- hapd->conf->radius_das_require_event_timestamp;
+ conf->radius_das_require_event_timestamp;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
hapd->radius_das = radius_das_init(&das_conf);
@@ -845,7 +846,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if ((hapd->conf->wpa || hapd->conf->osen) && hostapd_setup_wpa(hapd))
+ if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
@@ -853,8 +854,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->ieee802_11f &&
- (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+ if (conf->ieee802_11f &&
+ (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
"failed.");
return -1;
@@ -879,7 +880,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+ if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
return -1;
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
@@ -946,35 +947,24 @@ static void hostapd_set_acl(struct hostapd_data *hapd)
if (hapd->iface->drv_max_acl_mac_addrs == 0)
return;
- if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
- return;
if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
- if (conf->bss[0]->num_accept_mac) {
- accept_acl = 1;
- err = hostapd_set_acl_list(hapd,
- conf->bss[0]->accept_mac,
- conf->bss[0]->num_accept_mac,
- accept_acl);
- if (err) {
- wpa_printf(MSG_DEBUG, "Failed to set accept acl");
- return;
- }
- } else {
- wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ accept_acl = 1;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
+ conf->bss[0]->num_accept_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+ return;
}
} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
- if (conf->bss[0]->num_deny_mac) {
- accept_acl = 0;
- err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
- conf->bss[0]->num_deny_mac,
- accept_acl);
- if (err) {
- wpa_printf(MSG_DEBUG, "Failed to set deny acl");
- return;
- }
- } else {
- wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ accept_acl = 0;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+ conf->bss[0]->num_deny_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+ return;
}
}
}
@@ -1191,12 +1181,15 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
iface->conf->channel, iface->freq);
#ifdef NEED_AP_MLME
- /* Check DFS */
- res = hostapd_handle_dfs(iface);
- if (res <= 0) {
- if (res < 0)
- goto fail;
- return res;
+ /* Handle DFS only if it is not offloaded to the driver */
+ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
+ /* Check DFS */
+ res = hostapd_handle_dfs(iface);
+ if (res <= 0) {
+ if (res < 0)
+ goto fail;
+ return res;
+ }
}
#endif /* NEED_AP_MLME */
@@ -2186,13 +2179,12 @@ static void free_beacon_data(struct beacon_data *beacon)
}
-static int hostapd_build_beacon_data(struct hostapd_iface *iface,
+static int hostapd_build_beacon_data(struct hostapd_data *hapd,
struct beacon_data *beacon)
{
struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
struct wpa_driver_ap_params params;
int ret;
- struct hostapd_data *hapd = iface->bss[0];
os_memset(beacon, 0, sizeof(*beacon));
ret = ieee802_11_build_ap_params(hapd, &params);
@@ -2292,13 +2284,13 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (!params->channel) {
/* check if the new channel is supported by hw */
- channel = hostapd_hw_get_channel(hapd, params->freq);
- if (!channel)
- return -1;
- } else {
- channel = params->channel;
+ params->channel = hostapd_hw_get_channel(hapd, params->freq);
}
+ channel = params->channel;
+ if (!channel)
+ return -1;
+
/* if a pointer to old_params is provided we save previous state */
if (old_params) {
old_params->channel = conf->channel;
@@ -2316,14 +2308,15 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
}
-static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
+static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
struct csa_settings *settings)
{
+ struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
os_memset(&old_freq, 0, sizeof(old_freq));
- if (!iface || !iface->freq || iface->csa_in_progress)
+ if (!iface || !iface->freq || hapd->csa_in_progress)
return -1;
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
@@ -2332,7 +2325,7 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
if (ret)
return ret;
- ret = hostapd_build_beacon_data(iface, &settings->beacon_after);
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
/* change back the configuration */
hostapd_change_config_freq(iface->bss[0], iface->conf,
@@ -2342,18 +2335,18 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
return ret;
/* set channel switch parameters for csa ie */
- iface->cs_freq_params = settings->freq_params;
- iface->cs_count = settings->cs_count;
- iface->cs_block_tx = settings->block_tx;
+ hapd->cs_freq_params = settings->freq_params;
+ hapd->cs_count = settings->cs_count;
+ hapd->cs_block_tx = settings->block_tx;
- ret = hostapd_build_beacon_data(iface, &settings->beacon_csa);
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
if (ret) {
free_beacon_data(&settings->beacon_after);
return ret;
}
- settings->counter_offset_beacon = iface->cs_c_off_beacon;
- settings->counter_offset_presp = iface->cs_c_off_proberesp;
+ settings->counter_offset_beacon = hapd->cs_c_off_beacon;
+ settings->counter_offset_presp = hapd->cs_c_off_proberesp;
return 0;
}
@@ -2361,13 +2354,12 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface,
void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
{
- os_memset(&hapd->iface->cs_freq_params, 0,
- sizeof(hapd->iface->cs_freq_params));
- hapd->iface->cs_count = 0;
- hapd->iface->cs_block_tx = 0;
- hapd->iface->cs_c_off_beacon = 0;
- hapd->iface->cs_c_off_proberesp = 0;
- hapd->iface->csa_in_progress = 0;
+ os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params));
+ hapd->cs_count = 0;
+ hapd->cs_block_tx = 0;
+ hapd->cs_c_off_beacon = 0;
+ hapd->cs_c_off_proberesp = 0;
+ hapd->csa_in_progress = 0;
}
@@ -2375,7 +2367,7 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings)
{
int ret;
- ret = hostapd_fill_csa_settings(hapd->iface, settings);
+ ret = hostapd_fill_csa_settings(hapd, settings);
if (ret)
return ret;
@@ -2389,8 +2381,64 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
return ret;
}
- hapd->iface->csa_in_progress = 1;
+ hapd->csa_in_progress = 1;
return 0;
}
+
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ const struct hostapd_freq_params *freq_params)
+{
+ int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
+
+ if (freq_params->center_freq1)
+ vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ if (freq_params->center_freq2)
+ vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+
+ switch (freq_params->bandwidth) {
+ case 0:
+ case 20:
+ case 40:
+ vht_bw = VHT_CHANWIDTH_USE_HT;
+ break;
+ case 80:
+ if (freq_params->center_freq2)
+ vht_bw = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht_bw = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 160:
+ vht_bw = VHT_CHANWIDTH_160MHZ;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
+ freq_params->bandwidth);
+ break;
+ }
+
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+ iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
+ iface->conf->vht_oper_chwidth = vht_bw;
+ iface->conf->ieee80211n = freq_params->ht_enabled;
+ iface->conf->ieee80211ac = freq_params->vht_enabled;
+
+ /*
+ * cs_params must not be cleared earlier because the freq_params
+ * argument may actually point to one of these.
+ */
+ for (i = 0; i < iface->num_bss; i++)
+ hostapd_cleanup_cs_params(iface->bss[i]);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+}
+
#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bd85c54..3c8727b 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -210,6 +210,14 @@ struct hostapd_data {
size_t psk_len);
void *new_psk_cb_ctx;
+ /* channel switch parameters */
+ struct hostapd_freq_params cs_freq_params;
+ u8 cs_count;
+ int cs_block_tx;
+ unsigned int cs_c_off_beacon;
+ unsigned int cs_c_off_proberesp;
+ int csa_in_progress;
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -343,14 +351,6 @@ struct hostapd_iface {
/* lowest observed noise floor in dBm */
s8 lowest_nf;
- /* channel switch parameters */
- struct hostapd_freq_params cs_freq_params;
- u8 cs_count;
- int cs_block_tx;
- unsigned int cs_c_off_beacon;
- unsigned int cs_c_off_proberesp;
- int csa_in_progress;
-
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
@@ -397,6 +397,9 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
+void
+hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ca8db8f..de1ee5e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -236,7 +236,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
/* Transaction 3 */
if (!iswep || !sta->challenge || !challenge ||
- os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
+ os_memcmp_const(sta->challenge, challenge,
+ WLAN_AUTH_CHALLENGE_LEN)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"shared key authentication - invalid "
@@ -402,7 +403,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
return -1;
if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
addr, ETH_ALEN, mac) < 0 ||
- os_memcmp(token, mac, SHA256_MAC_LEN) != 0)
+ os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0)
return -1;
return 0;
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index c0a7cd4..fe87883 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -211,8 +211,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
struct ieee80211_2040_intol_chan_report *ic_report;
int is_ht_allowed = 1;
int i;
- const u8 *data = (const u8 *) &mgmt->u.action.u.public_action.action;
- size_t hdr_len;
+ const u8 *data = ((const u8 *) mgmt) + 1;
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
@@ -221,8 +220,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
return;
- hdr_len = data - (u8 *) mgmt;
- if (hdr_len > len)
+ if (len < IEEE80211_HDRLEN + 1)
return;
data++;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 221d9c2..437cf50 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -112,25 +112,11 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper_notif)
{
- u8 channel_width;
-
if (!vht_oper_notif) {
sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
return WLAN_STATUS_SUCCESS;
}
- channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK;
-
- if (channel_width != VHT_CHANWIDTH_USE_HT &&
- channel_width != VHT_CHANWIDTH_80MHZ &&
- channel_width != VHT_CHANWIDTH_160MHZ &&
- channel_width != VHT_CHANWIDTH_80P80MHZ &&
- ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >>
- VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) {
- sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
-
sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
sta->vht_opmode = *vht_oper_notif;
return WLAN_STATUS_SUCCESS;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 035415f..2d09b67 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -306,6 +306,67 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
}
+static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ u32 suite;
+ int ver, val;
+
+ ver = wpa_auth_sta_wpa_version(sta->wpa_sm);
+ val = wpa_auth_get_pairwise(sta->wpa_sm);
+ suite = wpa_cipher_to_suite(ver, val);
+ if (val != -1 &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher");
+ return -1;
+ }
+
+ suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ?
+ WPA_PROTO_RSN : WPA_PROTO_WPA,
+ hapd->conf->wpa_group);
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_GROUP_CIPHER) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher");
+ return -1;
+ }
+
+ val = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+ suite = wpa_akm_to_suite(val);
+ if (val != -1 &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_AKM_SUITE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
+ suite)) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite");
+ return -1;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ hapd->conf->group_mgmt_cipher);
+ if (!hostapd_config_get_radius_attr(
+ req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) &&
+ !radius_msg_add_attr_int32(
+ msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) {
+ wpa_printf(MSG_ERROR,
+ "Could not add WLAN-Group-Mgmt-Cipher");
+ return -1;
+ }
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ return 0;
+}
+
+
static int add_common_radius_sta_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
@@ -357,6 +418,25 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
}
+#ifdef CONFIG_IEEE80211R
+ if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
+ sta->wpa_sm &&
+ (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
+ sta->auth_alg == WLAN_AUTH_FT) &&
+ !hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_MOBILITY_DOMAIN_ID) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID,
+ WPA_GET_BE16(
+ hapd->conf->mobility_domain))) {
+ wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211R */
+
+ if (hapd->conf->wpa && sta->wpa_sm &&
+ add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
+ return -1;
+
return 0;
}
@@ -420,6 +500,22 @@ int add_common_radius_attr(struct hostapd_data *hapd,
return -1;
}
+#ifdef CONFIG_INTERWORKING
+ if (hapd->conf->interworking &&
+ !is_zero_ether_addr(hapd->conf->hessid)) {
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(hapd->conf->hessid));
+ buf[sizeof(buf) - 1] = '\0';
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_WLAN_HESSID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID");
+ return -1;
+ }
+ }
+#endif /* CONFIG_INTERWORKING */
+
if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
return -1;
@@ -1526,6 +1622,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
break;
+ sta->session_timeout_set = !!session_timeout_set;
+ sta->session_timeout = session_timeout;
+
/* RFC 3580, Ch. 3.17 */
if (session_timeout_set && termination_action ==
RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
@@ -2300,6 +2399,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
size_t len;
/* TODO: get PMKLifetime from WPA parameters */
static const int dot11RSNAConfigPMKLifetime = 43200;
+ unsigned int session_timeout;
#ifdef CONFIG_HS20
if (remediation && !sta->remediation) {
@@ -2334,9 +2434,13 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
#endif /* CONFIG_HS20 */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
+ if (sta->session_timeout_set)
+ session_timeout = sta->session_timeout;
+ else
+ session_timeout = dot11RSNAConfigPMKLifetime;
if (success && key && len >= PMK_LEN && !sta->remediation &&
!sta->hs20_deauth_requested &&
- wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+ wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 4720b59..9de4cff 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -37,14 +37,12 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
- if (entry == NULL)
- return;
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
- os_free(entry);
+ bin_clear_free(entry, sizeof(*entry));
}
@@ -52,38 +50,42 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
+ unsigned int hash;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
- pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+
+ /* unlink from hash list */
+ hash = PMKID_HASH(entry->pmkid);
+ pos = pmksa->pmkid[hash];
prev = NULL;
while (pos) {
if (pos == entry) {
- if (prev != NULL) {
- prev->hnext = pos->hnext;
- } else {
- pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
- pos->hnext;
- }
+ if (prev != NULL)
+ prev->hnext = entry->hnext;
+ else
+ pmksa->pmkid[hash] = entry->hnext;
break;
}
prev = pos;
pos = pos->hnext;
}
+ /* unlink from entry list */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL)
- prev->next = pos->next;
+ prev->next = entry->next;
else
- pmksa->pmksa = pos->next;
+ pmksa->pmksa = entry->next;
break;
}
prev = pos;
pos = pos->next;
}
+
_pmksa_cache_free_entry(entry);
}
@@ -188,6 +190,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
+ int hash;
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
@@ -205,8 +208,10 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
entry->next = prev->next;
prev->next = entry;
}
- entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
- pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
+
+ hash = PMKID_HASH(entry->pmkid);
+ entry->hnext = pmksa->pmkid[hash];
+ pmksa->pmkid[hash] = entry;
pmksa->pmksa_count++;
if (prev == NULL)
@@ -342,6 +347,8 @@ void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+ pmksa->pmksa_count = 0;
+ pmksa->pmksa = NULL;
for (i = 0; i < PMKID_HASH_SIZE; i++)
pmksa->pmkid[i] = NULL;
os_free(pmksa);
@@ -361,18 +368,22 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *entry;
- if (pmkid)
- entry = pmksa->pmkid[PMKID_HASH(pmkid)];
- else
- entry = pmksa->pmksa;
- while (entry) {
- if ((spa == NULL ||
- os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
- (pmkid == NULL ||
- os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
- return entry;
- entry = pmkid ? entry->hnext : entry->next;
+ if (pmkid) {
+ for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry;
+ entry = entry->hnext) {
+ if ((spa == NULL ||
+ os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
+ os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ }
+ } else {
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (spa == NULL ||
+ os_memcmp(entry->spa, spa, ETH_ALEN) == 0)
+ return entry;
+ }
}
+
return NULL;
}
@@ -394,15 +405,13 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *entry;
u8 new_pmkid[PMKID_LEN];
- entry = pmksa->pmksa;
- while (entry) {
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
wpa_key_mgmt_sha256(entry->akmp));
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
- entry = entry->next;
}
return NULL;
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 60f0768..efd2a72 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -956,12 +956,12 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
dev_addr = addr;
} else
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
-#endif /* CONFIG_P2P */
if (dev_addr)
os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
+#endif /* CONFIG_P2P */
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
if (authorized) {
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 03db98f..faf32d8 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -60,6 +60,7 @@ struct sta_info {
unsigned int qos_map_enabled:1;
unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
+ unsigned int session_timeout_set:1;
u16 auth_alg;
@@ -135,6 +136,8 @@ struct sta_info {
#ifdef CONFIG_SAE
struct sae_data *sae;
#endif /* CONFIG_SAE */
+
+ u32 session_timeout; /* valid only if session_timeout_set == 1 */
};
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 8e5bdcb..cf25dbb 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -376,10 +376,9 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
if (len < IEEE80211_HDRLEN + 2)
return -1;
- payload = &mgmt->u.action.category;
- payload++;
+ payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
action = *payload++;
- plen = (((const u8 *) mgmt) + len) - payload;
+ plen = len - IEEE80211_HDRLEN - 2;
switch (action) {
case WNM_BSS_TRANS_MGMT_QUERY:
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index a9cd6f6..1a16b5c 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1390,7 +1390,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
+ if (aes_wrap(sm->PTK.kek, 16,
+ (key_data_len - 8) / 8, buf,
(u8 *) (key + 1))) {
os_free(hdr);
os_free(buf);
@@ -1490,7 +1491,7 @@ static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
os_memset(key->key_mic, 0, 16);
if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
data, data_len, key->key_mic) ||
- os_memcmp(mic, key->key_mic, 16) != 0)
+ os_memcmp_const(mic, key->key_mic, 16) != 0)
ret = -1;
os_memcpy(key->key_mic, mic, 16);
return ret;
@@ -1877,8 +1878,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
* Verify that PMKR1Name from EAPOL-Key message 2/4 matches
* with the value we derived.
*/
- if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
- WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKR1Name mismatch in FT 4-way "
"handshake");
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a80bbb7..781f15f 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -235,8 +235,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
r0 = cache->pmk_r0;
while (r0) {
if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
- os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
- == 0) {
+ os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
+ WPA_PMK_NAME_LEN) == 0) {
os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
if (pairwise)
*pairwise = r0->pairwise;
@@ -285,8 +285,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
r1 = cache->pmk_r1;
while (r1) {
if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
- os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
- == 0) {
+ os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
+ WPA_PMK_NAME_LEN) == 0) {
os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
if (pairwise)
*pairwise = r1->pairwise;
@@ -310,7 +310,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
r0kh = sm->wpa_auth->conf.r0kh_list;
while (r0kh) {
if (r0kh->id_len == sm->r0kh_id_len &&
- os_memcmp(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) == 0)
+ os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) ==
+ 0)
break;
r0kh = r0kh->next;
}
@@ -343,7 +344,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
os_memset(f.pad, 0, sizeof(f.pad));
- if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+ if (aes_wrap(r0kh->key, sizeof(r0kh->key),
+ (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
f.nonce, frame.nonce) < 0)
return -1;
@@ -458,7 +460,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
- if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
+ if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) {
os_free(subelem);
return NULL;
}
@@ -490,7 +492,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+ if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
os_free(subelem);
return NULL;
@@ -1013,8 +1015,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_PMKID;
}
- if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
- {
+ if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)
+ != 0) {
wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
"with the PMKR1Name derived from auth request");
return WLAN_STATUS_INVALID_PMKID;
@@ -1060,7 +1062,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -1075,8 +1078,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
- FT_R1KH_ID_LEN) != 0) {
+ if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
@@ -1087,7 +1090,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@@ -1113,7 +1117,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
@@ -1333,7 +1337,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
frame = (struct ft_r0kh_r1kh_pull_frame *) data;
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
- if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+ if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
+ (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
frame->nonce, f.nonce) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"request from " MACSTR, MAC2STR(src_addr));
@@ -1373,7 +1378,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
r.pairwise = host_to_le16(pairwise);
os_memset(r.pad, 0, sizeof(r.pad));
- if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+ if (aes_wrap(r1kh->key, sizeof(r1kh->key),
+ (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
r.nonce, resp.nonce) < 0) {
os_memset(pmk_r0, 0, PMK_LEN);
return -1;
@@ -1461,15 +1467,16 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
frame = (struct ft_r0kh_r1kh_resp_frame *) data;
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
- if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+ if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
+ (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
frame->nonce, f.nonce) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"response from " MACSTR, MAC2STR(src_addr));
return -1;
}
- if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
- != 0) {
+ if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
"matching R1KH-ID");
return -1;
@@ -1527,7 +1534,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
frame = (struct ft_r0kh_r1kh_push_frame *) data;
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
- if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+ if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
+ (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
frame->timestamp, f.timestamp) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
MACSTR, MAC2STR(src_addr));
@@ -1544,8 +1552,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
return -1;
}
- if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
- != 0) {
+ if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder,
+ FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
"R1KH-ID (received " MACSTR " own " MACSTR ")",
MAC2STR(f.r1kh_id),
@@ -1686,6 +1694,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
+ if (end > pos) {
+ wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
+ pos, end - pos);
+ }
+
return 0;
}
@@ -1719,7 +1732,8 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
WPA_PUT_LE32(f.timestamp, now.sec);
f.pairwise = host_to_le16(pairwise);
os_memset(f.pad, 0, sizeof(f.pad));
- if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+ if (aes_wrap(r1kh->key, sizeof(r1kh->key),
+ (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
f.timestamp, frame.timestamp) < 0)
return;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index faa6a39..173a400 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -546,3 +546,60 @@ int supp_rates_11b_only(struct ieee802_11_elems *elems)
return num_11b > 0 && num_others == 0;
}
+
+
+const char * fc2str(u16 fc)
+{
+ u16 stype = WLAN_FC_GET_STYPE(fc);
+#define C2S(x) case x: return #x;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case WLAN_FC_TYPE_MGMT:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_ASSOC_REQ)
+ C2S(WLAN_FC_STYPE_ASSOC_RESP)
+ C2S(WLAN_FC_STYPE_REASSOC_REQ)
+ C2S(WLAN_FC_STYPE_REASSOC_RESP)
+ C2S(WLAN_FC_STYPE_PROBE_REQ)
+ C2S(WLAN_FC_STYPE_PROBE_RESP)
+ C2S(WLAN_FC_STYPE_BEACON)
+ C2S(WLAN_FC_STYPE_ATIM)
+ C2S(WLAN_FC_STYPE_DISASSOC)
+ C2S(WLAN_FC_STYPE_AUTH)
+ C2S(WLAN_FC_STYPE_DEAUTH)
+ C2S(WLAN_FC_STYPE_ACTION)
+ }
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_PSPOLL)
+ C2S(WLAN_FC_STYPE_RTS)
+ C2S(WLAN_FC_STYPE_CTS)
+ C2S(WLAN_FC_STYPE_ACK)
+ C2S(WLAN_FC_STYPE_CFEND)
+ C2S(WLAN_FC_STYPE_CFENDACK)
+ }
+ break;
+ case WLAN_FC_TYPE_DATA:
+ switch (stype) {
+ C2S(WLAN_FC_STYPE_DATA)
+ C2S(WLAN_FC_STYPE_DATA_CFACK)
+ C2S(WLAN_FC_STYPE_DATA_CFPOLL)
+ C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_NULLFUNC)
+ C2S(WLAN_FC_STYPE_CFACK)
+ C2S(WLAN_FC_STYPE_CFPOLL)
+ C2S(WLAN_FC_STYPE_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_QOS_DATA)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
+ C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
+ C2S(WLAN_FC_STYPE_QOS_NULL)
+ C2S(WLAN_FC_STYPE_QOS_CFPOLL)
+ C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
+ }
+ break;
+ }
+ return "WLAN_FC_TYPE_UNKNOWN";
+#undef C2S
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9b8bbd1..cf83057 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -98,4 +98,5 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
+const char * fc2str(u16 fc);
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b8e9254..6de71e9 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -809,6 +809,7 @@ struct ieee80211_vht_operation {
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WMM_IE_VENDOR_TYPE 0x0050f202
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index a56b188..ad3bdfd 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -32,6 +32,13 @@ enum qca_radiotap_vendor_ids {
*
* @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event
*
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAMING: Set roaming policy for drivers that use
+ * internal BSS-selection. This command uses
+ * @QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY to specify the new roaming policy
+ * for the current connection (i.e., changes policy set by the nl80211
+ * Connect command). @QCA_WLAN_VENDOR_ATTR_MAC_ADDR may optionally be
+ * included to indicate which BSS to use in case roaming is disabled.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
* ranges to avoid to reduce issues due to interference or internal
* co-existence information in the driver. The event data structure is
@@ -47,12 +54,13 @@ enum qca_radiotap_vendor_ids {
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
QCA_NL80211_VENDOR_SUBCMD_TEST = 1,
- /* subcmds 2..9 not yet allocated */
+ /* subcmds 2..8 not yet allocated */
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9,
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
- /* 14..19 - reserved for QCA */
+ /* 14..49 - reserved for QCA */
};
@@ -64,9 +72,21 @@ enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_NAN = 2,
/* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+ QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined
+ * by enum qca_roaming_policy. */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
+ QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
};
+
+enum qca_roaming_policy {
+ QCA_ROAMING_NOT_ALLOWED,
+ QCA_ROAMING_ALLOWED_WITHIN_ESS,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index c1b488e..b67623f 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -1051,7 +1051,7 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
sae->tmp->own_commit_element_ffc,
verifier);
- if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
data + 2, SHA256_MAC_LEN);
diff --git a/src/common/version.h b/src/common/version.h
index 340afc7..726289d 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.2" VERSION_STR_POSTFIX
+#define VERSION_STR "2.3" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index adb22c7..7aeb706 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1002,6 +1002,30 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
}
+u32 wpa_akm_to_suite(int akm)
+{
+ if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
+ return WLAN_AKM_SUITE_FT_8021X;
+ if (akm & WPA_KEY_MGMT_FT_PSK)
+ return WLAN_AKM_SUITE_FT_PSK;
+ if (akm & WPA_KEY_MGMT_IEEE8021X)
+ return WLAN_AKM_SUITE_8021X;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
+ return WLAN_AKM_SUITE_8021X_SHA256;
+ if (akm & WPA_KEY_MGMT_IEEE8021X)
+ return WLAN_AKM_SUITE_8021X;
+ if (akm & WPA_KEY_MGMT_PSK_SHA256)
+ return WLAN_AKM_SUITE_PSK_SHA256;
+ if (akm & WPA_KEY_MGMT_PSK)
+ return WLAN_AKM_SUITE_PSK;
+ if (akm & WPA_KEY_MGMT_CCKM)
+ return WLAN_AKM_SUITE_CCKM;
+ if (akm & WPA_KEY_MGMT_OSEN)
+ return WLAN_AKM_SUITE_OSEN;
+ return 0;
+}
+
+
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len)
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index c0b2caa..0ef5a9d 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -377,6 +377,7 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+u32 wpa_akm_to_suite(int akm);
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 534bc99..4812f8d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -239,6 +239,25 @@ extern "C" {
#define WPA_BSS_MASK_DELIM BIT(17)
+/* VENDOR_ELEM_* frame id values */
+enum wpa_vendor_elem_frame {
+ VENDOR_ELEM_PROBE_REQ_P2P = 0,
+ VENDOR_ELEM_PROBE_RESP_P2P = 1,
+ VENDOR_ELEM_PROBE_RESP_P2P_GO = 2,
+ VENDOR_ELEM_BEACON_P2P_GO = 3,
+ VENDOR_ELEM_P2P_PD_REQ = 4,
+ VENDOR_ELEM_P2P_PD_RESP = 5,
+ VENDOR_ELEM_P2P_GO_NEG_REQ = 6,
+ VENDOR_ELEM_P2P_GO_NEG_RESP = 7,
+ VENDOR_ELEM_P2P_GO_NEG_CONF = 8,
+ VENDOR_ELEM_P2P_INV_REQ = 9,
+ VENDOR_ELEM_P2P_INV_RESP = 10,
+ VENDOR_ELEM_P2P_ASSOC_REQ = 11,
+ VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+ NUM_VENDOR_ELEM_FRAMES
+};
+
+
/* wpa_supplicant/hostapd control interface access */
/**
@@ -326,9 +345,10 @@ int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
- * This function will receive a pending control interface message. This
- * function will block if no messages are available. The received response will
- * be written to reply and reply_len is set to the actual length of the reply.
+ * This function will receive a pending control interface message. The received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply.
+
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
diff --git a/src/crypto/aes-ccm.c b/src/crypto/aes-ccm.c
index d14670d..cf22778 100644
--- a/src/crypto/aes-ccm.c
+++ b/src/crypto/aes-ccm.c
@@ -203,7 +203,7 @@ int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
aes_encrypt_deinit(aes);
- if (os_memcmp(x, t, M) != 0) {
+ if (os_memcmp_const(x, t, M) != 0) {
wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch");
return -1;
}
diff --git a/src/crypto/aes-gcm.c b/src/crypto/aes-gcm.c
index 3d91c71..84294d2 100644
--- a/src/crypto/aes-gcm.c
+++ b/src/crypto/aes-gcm.c
@@ -310,7 +310,7 @@ int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
aes_encrypt_deinit(aes);
- if (os_memcmp(tag, T, 16) != 0) {
+ if (os_memcmp_const(tag, T, 16) != 0) {
wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch");
return -1;
}
diff --git a/src/crypto/aes-unwrap.c b/src/crypto/aes-unwrap.c
index 9dd5160..ec793d9 100644
--- a/src/crypto/aes-unwrap.c
+++ b/src/crypto/aes-unwrap.c
@@ -1,5 +1,5 @@
/*
- * AES key unwrap (128-bit KEK, RFC3394)
+ * AES key unwrap (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,26 +14,29 @@
#include "aes_wrap.h"
/**
- * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (RFC3394)
* @kek: Key encryption key (KEK)
+ * @kek_len: Length of KEK in octets
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
* @plain: Plaintext key, n * 64 bits
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
-int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
{
- u8 a[8], *r, b[16];
+ u8 a[8], *r, b[AES_BLOCK_SIZE];
int i, j;
void *ctx;
+ unsigned int t;
/* 1) Initialize variables. */
os_memcpy(a, cipher, 8);
r = plain;
os_memcpy(r, cipher + 8, 8 * n);
- ctx = aes_decrypt_init(kek, 16);
+ ctx = aes_decrypt_init(kek, kek_len);
if (ctx == NULL)
return -1;
@@ -48,7 +51,11 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
os_memcpy(b, a, 8);
- b[7] ^= n * j + i;
+ t = n * j + i;
+ b[7] ^= t;
+ b[6] ^= t >> 8;
+ b[5] ^= t >> 16;
+ b[4] ^= t >> 24;
os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
diff --git a/src/crypto/aes-wrap.c b/src/crypto/aes-wrap.c
index 89d6f94..7ed34e8 100644
--- a/src/crypto/aes-wrap.c
+++ b/src/crypto/aes-wrap.c
@@ -1,5 +1,5 @@
/*
- * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * AES Key Wrap Algorithm (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,19 +14,21 @@
#include "aes_wrap.h"
/**
- * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: 16-octet Key encryption key (KEK)
+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @kek_len: Length of KEK in octets
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @plain: Plaintext key to be wrapped, n * 64 bits
* @cipher: Wrapped key, (n + 1) * 64 bits
* Returns: 0 on success, -1 on failure
*/
-int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
- u8 *a, *r, b[16];
+ u8 *a, *r, b[AES_BLOCK_SIZE];
int i, j;
void *ctx;
+ unsigned int t;
a = cipher;
r = cipher + 8;
@@ -35,7 +37,7 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
os_memset(a, 0xa6, 8);
os_memcpy(r, plain, 8 * n);
- ctx = aes_encrypt_init(kek, 16);
+ ctx = aes_encrypt_init(kek, kek_len);
if (ctx == NULL)
return -1;
@@ -53,7 +55,11 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
os_memcpy(a, b, 8);
- a[7] ^= n * j + i;
+ t = n * j + i;
+ a[7] ^= t;
+ a[6] ^= t >> 8;
+ a[5] ^= t >> 16;
+ a[4] ^= t >> 24;
os_memcpy(r, b + 8, 8);
r += 8;
}
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 0433c04..6b3727c 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -1,7 +1,7 @@
/*
* AES-based functions
*
- * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - AES Key Wrap Algorithm (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
@@ -18,8 +18,10 @@
#ifndef AES_WRAP_H
#define AES_WRAP_H
-int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
-int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int __must_check aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain,
+ u8 *cipher);
+int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
+ const u8 *cipher, u8 *plain);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 817ee2d..b4c59d1 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -40,7 +40,7 @@
static BIGNUM * get_group5_prime(void)
{
-#if OPENSSL_VERSION_NUMBER < 0x00908000
+#if OPENSSL_VERSION_NUMBER < 0x00908000 || defined(OPENSSL_IS_BORINGSSL)
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -130,7 +130,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
pkey[i] = next | 1;
- DES_set_key(&pkey, &ks);
+ DES_set_key((DES_cblock *) &pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
@@ -199,8 +199,10 @@ static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
switch (keylen) {
case 16:
return EVP_aes_128_ecb();
+#ifndef OPENSSL_IS_BORINGSSL
case 24:
return EVP_aes_192_ecb();
+#endif /* OPENSSL_IS_BORINGSSL */
case 32:
return EVP_aes_256_ecb();
}
@@ -340,10 +342,10 @@ int crypto_mod_exp(const u8 *base, size_t base_len,
ret = 0;
error:
- BN_free(bn_base);
- BN_free(bn_exp);
- BN_free(bn_modulus);
- BN_free(bn_result);
+ BN_clear_free(bn_base);
+ BN_clear_free(bn_exp);
+ BN_clear_free(bn_modulus);
+ BN_clear_free(bn_result);
BN_CTX_free(ctx);
return ret;
}
@@ -378,9 +380,11 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
case 16:
cipher = EVP_aes_128_cbc();
break;
+#ifndef OPENSSL_IS_BORINGSSL
case 24:
cipher = EVP_aes_192_cbc();
break;
+#endif /* OPENSSL_IS_BORINGSSL */
case 32:
cipher = EVP_aes_256_cbc();
break;
@@ -571,12 +575,12 @@ struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
if (keylen < 0)
goto err;
wpabuf_put(res, keylen);
- BN_free(pub_key);
+ BN_clear_free(pub_key);
return res;
err:
- BN_free(pub_key);
+ BN_clear_free(pub_key);
wpabuf_free(res);
return NULL;
}
@@ -1066,7 +1070,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
{
if (e == NULL)
return;
- BN_free(e->order);
+ BN_clear_free(e->order);
+ BN_clear_free(e->prime);
EC_GROUP_free(e->group);
BN_CTX_free(e->bnctx);
os_free(e);
@@ -1138,8 +1143,8 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
ret = 0;
}
- BN_free(x_bn);
- BN_free(y_bn);
+ BN_clear_free(x_bn);
+ BN_clear_free(y_bn);
return ret;
}
@@ -1155,20 +1160,20 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
y = BN_bin2bn(val + len, len, NULL);
elem = EC_POINT_new(e->group);
if (x == NULL || y == NULL || elem == NULL) {
- BN_free(x);
- BN_free(y);
- EC_POINT_free(elem);
+ BN_clear_free(x);
+ BN_clear_free(y);
+ EC_POINT_clear_free(elem);
return NULL;
}
if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
e->bnctx)) {
- EC_POINT_free(elem);
+ EC_POINT_clear_free(elem);
elem = NULL;
}
- BN_free(x);
- BN_free(y);
+ BN_clear_free(x);
+ BN_clear_free(y);
return (struct crypto_ec_point *) elem;
}
diff --git a/src/crypto/milenage.c b/src/crypto/milenage.c
index a7f9c6a..6edea57 100644
--- a/src/crypto/milenage.c
+++ b/src/crypto/milenage.c
@@ -217,7 +217,7 @@ int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
for (i = 0; i < 6; i++)
sqn[i] = auts[i] ^ ak[i];
if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
- memcmp(mac_s, auts + 6, 8) != 0)
+ os_memcmp_const(mac_s, auts + 6, 8) != 0)
return -1;
return 0;
}
@@ -312,7 +312,7 @@ int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
- if (os_memcmp(mac_a, autn + 8, 8) != 0) {
+ if (os_memcmp_const(mac_a, autn + 8, 8) != 0) {
wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
autn + 8, 8);
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index d2d6600..e153422 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -38,14 +38,26 @@
#define OPENSSL_SUPPORTS_CTX_APP_DATA
#endif
-#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
-#ifdef SSL_OP_NO_TICKET
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
+ * deprecated. However, OpenSSL 0.9.8 doesn't include
+ * ERR_remove_thread_state. */
+#define ERR_remove_thread_state(tid) ERR_remove_state(0)
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
/*
* Session ticket override patch was merged into OpenSSL 0.9.9 tree on
* 2008-11-15. This version uses a bit different API compared to the old patch.
*/
#define CONFIG_OPENSSL_TICKET_OVERRIDE
#endif
+
+#if defined(OPENSSL_IS_BORINGSSL)
+/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
+typedef size_t stack_index_t;
+#else
+typedef int stack_index_t;
#endif
#ifdef SSL_set_tlsext_status_type
@@ -853,7 +865,7 @@ void tls_deinit(void *ssl_ctx)
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
+ ERR_remove_thread_state(NULL);
ERR_free_strings();
EVP_cleanup();
os_free(tls_global->ocsp_stapling_response);
@@ -1102,7 +1114,8 @@ static int tls_match_altsubject_component(X509 *cert, int type,
{
GENERAL_NAME *gen;
void *ext;
- int i, found = 0;
+ int found = 0;
+ stack_index_t i;
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
@@ -1204,6 +1217,7 @@ static int tls_match_suffix(X509 *cert, const char *match)
GENERAL_NAME *gen;
void *ext;
int i;
+ stack_index_t j;
int dns_name = 0;
X509_NAME *name;
@@ -1211,8 +1225,8 @@ static int tls_match_suffix(X509 *cert, const char *match)
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
- gen = sk_GENERAL_NAME_value(ext, i);
+ for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
+ gen = sk_GENERAL_NAME_value(ext, j);
if (gen->type != GEN_DNS)
continue;
dns_name++;
@@ -1639,7 +1653,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
BIO *bio = BIO_from_keystore(&ca_cert[11]);
STACK_OF(X509_INFO) *stack = NULL;
- int i;
+ stack_index_t i;
if (bio) {
stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
@@ -3386,9 +3400,15 @@ unsigned int tls_capabilities(void *tls_ctx)
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
+#ifdef OPENSSL_IS_BORINGSSL
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ const SSL_CIPHER **cipher, void *arg)
+#else /* OPENSSL_IS_BORINGSSL */
static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
STACK_OF(SSL_CIPHER) *peer_ciphers,
SSL_CIPHER **cipher, void *arg)
+#endif /* OPENSSL_IS_BORINGSSL */
{
struct tls_connection *conn = arg;
int ret;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6e47b86..6af7294 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -351,7 +351,7 @@ struct wpa_driver_scan_params {
* Mbps from the support rates element(s) in the Probe Request frames
* and not to transmit the frames at any of those rates.
*/
- u8 p2p_probe;
+ unsigned int p2p_probe:1;
/**
* only_new_results - Request driver to report only new results
@@ -360,7 +360,15 @@ struct wpa_driver_scan_params {
* been detected after this scan request has been started, i.e., to
* flush old cached BSS entries.
*/
- int only_new_results;
+ unsigned int only_new_results:1;
+
+ /**
+ * low_priority - Requests driver to use a lower scan priority
+ *
+ * This is used to request the driver to use a lower scan priority
+ * if it supports such a thing.
+ */
+ unsigned int low_priority:1;
/*
* NOTE: Whenever adding new parameters here, please make sure
@@ -403,6 +411,25 @@ enum wps_mode {
*/
};
+struct hostapd_freq_params {
+ int mode;
+ int freq;
+ int channel;
+ /* for HT */
+ int ht_enabled;
+ int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+ * secondary channel below primary, 1 = HT40
+ * enabled, secondary channel above primary */
+
+ /* for VHT */
+ int vht_enabled;
+
+ /* valid for both HT and VHT, center_freq2 is non-zero
+ * only for bandwidth 80 and an 80+80 channel */
+ int center_freq1, center_freq2;
+ int bandwidth;
+};
+
/**
* struct wpa_driver_associate_params - Association parameters
* Data for struct wpa_driver_ops::associate().
@@ -435,11 +462,9 @@ struct wpa_driver_associate_params {
size_t ssid_len;
/**
- * freq - Frequency of the channel the selected AP is using
- * Frequency that the selected AP is using (in MHz as
- * reported in the scan results)
+ * freq - channel parameters
*/
- int freq;
+ struct hostapd_freq_params freq;
/**
* freq_hint - Frequency of the channel the proposed AP is using
@@ -1083,25 +1108,6 @@ struct hostapd_sta_add_params {
size_t supp_oper_classes_len;
};
-struct hostapd_freq_params {
- int mode;
- int freq;
- int channel;
- /* for HT */
- int ht_enabled;
- int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
- * secondary channel below primary, 1 = HT40
- * enabled, secondary channel above primary */
-
- /* for VHT */
- int vht_enabled;
-
- /* valid for both HT and VHT, center_freq2 is non-zero
- * only for bandwidth 80 and an 80+80 channel */
- int center_freq1, center_freq2;
- int bandwidth;
-};
-
struct mac_address {
u8 addr[ETH_ALEN];
};
@@ -2495,6 +2501,7 @@ struct wpa_driver_ops {
* @dialog_token: Dialog Token to use in the message (if needed)
* @status_code: Status Code or Reason Code to use (if needed)
* @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield)
+ * @initiator: Is the current end the TDLS link initiator
* @buf: TDLS IEs to add to the message
* @len: Length of buf in octets
* Returns: 0 on success, negative (<0) on failure
@@ -2504,7 +2511,7 @@ struct wpa_driver_ops {
*/
int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code, u32 peer_capab,
- const u8 *buf, size_t len);
+ int initiator, const u8 *buf, size_t len);
/**
* tdls_oper - Ask the driver to perform high-level TDLS operations
@@ -2796,6 +2803,30 @@ struct wpa_driver_ops {
*/
int (*status)(void *priv, char *buf, size_t buflen);
+ /**
+ * roaming - Set roaming policy for driver-based BSS selection
+ * @priv: Private driver interface data
+ * @allowed: Whether roaming within ESS is allowed
+ * @bssid: Forced BSSID if roaming is disabled or %NULL if not set
+ * Returns: Length of written status information or -1 on failure
+ *
+ * This optional callback can be used to update roaming policy from the
+ * associate() command (bssid being set there indicates that the driver
+ * should not roam before getting this roaming() call to allow roaming.
+ * If the driver does not indicate WPA_DRIVER_FLAGS_BSS_SELECTION
+ * capability, roaming policy is handled within wpa_supplicant and there
+ * is no need to implement or react to this callback.
+ */
+ int (*roaming)(void *priv, int allowed, const u8 *bssid);
+
+ /**
+ * set_mac_addr - Set MAC address
+ * @priv: Private driver interface data
+ * @addr: MAC address to use or %NULL for setting back to permanent
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*set_mac_addr)(void *priv, const u8 *addr);
+
#ifdef CONFIG_MACSEC
int (*macsec_init)(void *priv, struct macsec_init_params *params);
@@ -3308,7 +3339,8 @@ enum wpa_event_type {
* the driver does not support radar detection and another virtual
* interfaces caused the operating channel to change. Other similar
* resource conflicts could also trigger this for station mode
- * interfaces.
+ * interfaces. This event can be propagated when channel switching
+ * fails.
*/
EVENT_INTERFACE_UNAVAILABLE,
@@ -4163,6 +4195,9 @@ void wpa_scan_results_free(struct wpa_scan_results *res);
/* Convert wpa_event_type to a string for logging */
const char * event_to_string(enum wpa_event_type event);
+/* Convert chan_width to a string for logging and control interfaces */
+const char * channel_width_to_string(enum chan_width width);
+
/* NULL terminated array of linked in driver wrappers */
extern struct wpa_driver_ops *wpa_drivers[];
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index c146cdc..b569a0a 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -260,6 +260,17 @@ atheros_configure_wpa(struct atheros_driver_data *drv,
case WPA_CIPHER_CCMP:
v = IEEE80211_CIPHER_AES_CCM;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_CIPHER_CCMP_256:
+ v = IEEE80211_CIPHER_AES_CCM_256;
+ break;
+ case WPA_CIPHER_GCMP:
+ v = IEEE80211_CIPHER_AES_GCM;
+ break;
+ case WPA_CIPHER_GCMP_256:
+ v = IEEE80211_CIPHER_AES_GCM_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
case WPA_CIPHER_TKIP:
v = IEEE80211_CIPHER_TKIP;
break;
@@ -294,6 +305,14 @@ atheros_configure_wpa(struct atheros_driver_data *drv,
v = 0;
if (params->wpa_pairwise & WPA_CIPHER_CCMP)
v |= 1<<IEEE80211_CIPHER_AES_CCM;
+#ifdef ATH_GCM_SUPPORT
+ if (params->wpa_pairwise & WPA_CIPHER_CCMP_256)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM_256;
+ if (params->wpa_pairwise & WPA_CIPHER_GCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_GCM;
+ if (params->wpa_pairwise & WPA_CIPHER_GCMP_256)
+ v |= 1<<IEEE80211_CIPHER_AES_GCM_256;
+#endif /* ATH_GCM_SUPPORT */
if (params->wpa_pairwise & WPA_CIPHER_TKIP)
v |= 1<<IEEE80211_CIPHER_TKIP;
if (params->wpa_pairwise & WPA_CIPHER_NONE)
@@ -471,10 +490,32 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
case WPA_ALG_CCMP:
cipher = IEEE80211_CIPHER_AES_CCM;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_ALG_CCMP_256:
+ cipher = IEEE80211_CIPHER_AES_CCM_256;
+ break;
+ case WPA_ALG_GCMP:
+ cipher = IEEE80211_CIPHER_AES_GCM;
+ break;
+ case WPA_ALG_GCMP_256:
+ cipher = IEEE80211_CIPHER_AES_GCM_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
#ifdef CONFIG_IEEE80211W
case WPA_ALG_IGTK:
cipher = IEEE80211_CIPHER_AES_CMAC;
break;
+#ifdef ATH_GCM_SUPPORT
+ case WPA_ALG_BIP_CMAC_256:
+ cipher = IEEE80211_CIPHER_AES_CMAC_256;
+ break;
+ case WPA_ALG_BIP_GMAC_128:
+ cipher = IEEE80211_CIPHER_AES_GMAC;
+ break;
+ case WPA_ALG_BIP_GMAC_256:
+ cipher = IEEE80211_CIPHER_AES_GMAC_256;
+ break;
+#endif /* ATH_GCM_SUPPORT */
#endif /* CONFIG_IEEE80211W */
default:
printf("%s: unknown/unsupported algorithm %d\n",
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 3058cd5..77e6905 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -84,3 +84,24 @@ const char * event_to_string(enum wpa_event_type event)
return "UNKNOWN";
#undef E2S
}
+
+
+const char * channel_width_to_string(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ return "20 MHz (no HT)";
+ case CHAN_WIDTH_20:
+ return "20 MHz";
+ case CHAN_WIDTH_40:
+ return "40 MHz";
+ case CHAN_WIDTH_80:
+ return "80 MHz";
+ case CHAN_WIDTH_80P80:
+ return "80+80 MHz";
+ case CHAN_WIDTH_160:
+ return "160 MHz";
+ default:
+ return "unknown";
+ }
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 7568653..d030474 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -19,6 +19,9 @@
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
+#ifdef CONFIG_LIBNL3_ROUTE
+#include <netlink/route/neighbour.h>
+#endif /* CONFIG_LIBNL3_ROUTE */
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
@@ -232,6 +235,7 @@ struct i802_bss {
unsigned int in_deinit:1;
unsigned int wdev_id_set:1;
unsigned int added_if:1;
+ unsigned int static_ap:1;
u8 addr[ETH_ALEN];
@@ -252,6 +256,7 @@ struct wpa_driver_nl80211_data {
struct dl_list list;
struct dl_list wiphy_list;
char phyname[32];
+ u8 perm_addr[ETH_ALEN];
void *ctx;
int ifindex;
int if_removed;
@@ -306,7 +311,11 @@ struct wpa_driver_nl80211_data {
unsigned int start_iface_up:1;
unsigned int test_use_roc_tx:1;
unsigned int ignore_deauth_event:1;
+ unsigned int roaming_vendor_cmd_avail:1;
unsigned int dfs_vendor_cmd_avail:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int force_connect_cmd:1;
+ unsigned int addr_changed:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@@ -322,6 +331,8 @@ struct wpa_driver_nl80211_data {
int eapol_sock; /* socket for EAPOL frames */
+ struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
int default_if_indices[16];
int *if_indices;
int num_if_indices;
@@ -347,6 +358,9 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
void *timeout_ctx);
static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
enum nl80211_iftype nlmode);
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
+ struct hostapd_freq_params *freq);
+
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const u8 *set_addr, int first);
@@ -413,6 +427,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
static int wpa_driver_nl80211_authenticate_retry(
struct wpa_driver_nl80211_data *drv);
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
static int i802_set_iface_flags(struct i802_bss *bss, int up);
@@ -574,6 +589,20 @@ static int is_p2p_net_interface(enum nl80211_iftype nlmode)
}
+static struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex)
+{
+ struct i802_bss *bss;
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (bss->ifindex == ifindex)
+ return bss;
+ }
+
+ return NULL;
+}
+
+
static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
{
if (drv->associated)
@@ -1238,8 +1267,9 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
}
extra[sizeof(extra) - 1] = '\0';
- wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)",
- ifi->ifi_index, ifname, extra, ifi->ifi_flags,
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
@@ -1291,6 +1321,28 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
"event since interface %s is marked "
"removed", drv->first_bss->ifname);
} else {
+ struct i802_bss *bss;
+ u8 addr[ETH_ALEN];
+
+ /* Re-read MAC address as it may have changed */
+ bss = get_bss_ifindex(drv, ifi->ifi_index);
+ if (bss &&
+ linux_get_ifhwaddr(drv->global->ioctl_sock,
+ bss->ifname, addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: %s: failed to re-read MAC address",
+ bss->ifname);
+ } else if (bss &&
+ os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Own MAC address on ifindex %d (%s) changed from "
+ MACSTR " to " MACSTR,
+ ifi->ifi_index, bss->ifname,
+ MAC2STR(bss->addr),
+ MAC2STR(addr));
+ os_memcpy(bss->addr, addr, ETH_ALEN);
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Interface up");
drv->if_disabled = 0;
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
@@ -1335,6 +1387,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
struct rtattr *attr;
u32 brid = 0;
char ifname[IFNAMSIZ + 1];
+ char extra[100], *pos, *end;
drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
if (!drv) {
@@ -1343,6 +1396,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
return;
}
+ extra[0] = '\0';
+ pos = extra;
+ end = pos + sizeof(extra);
ifname[0] = '\0';
attrlen = len;
@@ -1357,12 +1413,30 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
break;
case IFLA_MASTER:
brid = nla_get_u32((struct nlattr *) attr);
+ pos += os_snprintf(pos, end - pos, " master=%u", brid);
+ break;
+ case IFLA_OPERSTATE:
+ pos += os_snprintf(pos, end - pos, " operstate=%u",
+ nla_get_u32((struct nlattr *) attr));
+ break;
+ case IFLA_LINKMODE:
+ pos += os_snprintf(pos, end - pos, " linkmode=%u",
+ nla_get_u32((struct nlattr *) attr));
break;
}
attr = RTA_NEXT(attr, attrlen);
}
+ extra[sizeof(extra) - 1] = '\0';
- if (ifname[0])
+ wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ ifi->ifi_index, ifname, extra, ifi->ifi_family,
+ ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
wpa_driver_nl80211_event_dellink(drv, ifname);
if (ifi->ifi_family == AF_BRIDGE && brid) {
@@ -1382,6 +1456,17 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.auth)) {
@@ -1448,6 +1533,17 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
union wpa_event_data event;
u16 status;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Associate event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
@@ -1629,10 +1725,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
return;
ifidx = nla_get_u32(ifindex);
- for (bss = drv->first_bss; bss; bss = bss->next)
- if (bss->ifindex == ifidx)
- break;
-
+ bss = get_bss_ifindex(drv, ifidx);
if (bss == NULL) {
wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
ifidx);
@@ -1676,7 +1769,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
bss->freq = data.ch_switch.freq;
- wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
}
@@ -1735,8 +1828,10 @@ static void mlme_event_mgmt(struct i802_bss *bss,
rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
}
wpa_printf(MSG_DEBUG,
- "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u",
- rx_freq, ssi_signal, stype, (unsigned int) len);
+ "nl80211: RX frame sa=" MACSTR
+ " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
+ MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
+ (unsigned int) len);
event.rx_mgmt.frame = frame;
event.rx_mgmt.frame_len = len;
event.rx_mgmt.ssi_signal = ssi_signal;
@@ -3411,6 +3506,7 @@ struct wiphy_info_data {
unsigned int p2p_concurrent:1;
unsigned int channel_switch_supported:1;
unsigned int set_qos_map_supported:1;
+ unsigned int have_low_prio_scan:1;
};
@@ -3689,6 +3785,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+
+ if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
+ info->have_low_prio_scan = 1;
}
@@ -3835,9 +3934,14 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
continue;
}
vinfo = nla_data(nl);
- if (vinfo->subcmd ==
- QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
drv->dfs_vendor_cmd_avail = 1;
+ break;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
vinfo->vendor_id, vinfo->subcmd);
@@ -3981,6 +4085,7 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
drv->data_tx_status = info.data_tx_status;
if (info.set_qos_map_supported)
drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
+ drv->have_low_prio_scan = info.have_low_prio_scan;
/*
* If poll command and tx status are supported, mac80211 is new enough
@@ -4384,8 +4489,8 @@ static int nl80211_register_frame(struct i802_bss *bss,
buf[0] = '\0';
wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
- wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s",
- type, nl_handle, buf);
+ wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
+ type, fc2str(type), nl_handle, buf);
nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
@@ -4538,7 +4643,7 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
#ifdef CONFIG_HS20
/* WNM-Notification */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
- return -1;
+ ret = -1;
#endif /* CONFIG_HS20 */
nl80211_mgmt_handle_register_eloop(bss);
@@ -4752,6 +4857,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
drv->global->if_add_wdevid_set = 0;
+ if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
+ bss->static_ap = 1;
+
if (wpa_driver_nl80211_capa(drv))
return -1;
@@ -4767,7 +4875,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
drv->start_mode_ap = 1;
- if (drv->hostapd)
+ if (drv->hostapd || bss->static_ap)
nlmode = NL80211_IFTYPE_AP;
else if (bss->if_dynamic)
nlmode = nl80211_get_ifmode(bss);
@@ -4807,6 +4915,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
bss->addr))
return -1;
+ os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
if (send_rfkill_event) {
eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
@@ -4862,6 +4971,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"interface %s from bridge %s: %s",
bss->ifname, bss->brname, strerror(errno));
+ if (drv->rtnl_sk)
+ nl80211_handle_destroy(drv->rtnl_sk);
}
if (bss->added_bridge) {
if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
@@ -4895,6 +5006,16 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
+
+ if (drv->addr_changed) {
+ linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+ drv->perm_addr) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore permanent MAC address");
+ }
+ }
+
if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
if (!drv->hostapd || !drv->start_mode_ap)
wpa_driver_nl80211_set_mode(bss,
@@ -4949,6 +5070,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
{
struct nl_msg *msg;
size_t i;
+ u32 scan_flags = 0;
msg = nlmsg_alloc();
if (!msg)
@@ -5007,10 +5129,18 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
if (params->only_new_results) {
wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
- NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS,
- NL80211_SCAN_FLAG_FLUSH);
+ scan_flags |= NL80211_SCAN_FLAG_FLUSH;
}
+ if (params->low_priority && drv->have_low_prio_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+ scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+ }
+
+ if (scan_flags)
+ NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags);
+
return msg;
fail:
@@ -7070,8 +7200,10 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
mgmt = (struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
- wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
- noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
+ wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
+ " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d",
+ MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
+ fc, fc2str(fc), drv->nlmode);
if ((is_sta_interface(drv->nlmode) ||
drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
@@ -7660,6 +7792,43 @@ static int wpa_driver_nl80211_sta_add(void *priv,
}
+static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_addr;
+ int err;
+
+ rn = rtnl_neigh_alloc();
+ if (!rn)
+ return;
+
+ rtnl_neigh_set_family(rn, AF_BRIDGE);
+ rtnl_neigh_set_ifindex(rn, bss->ifindex);
+ nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
+ if (!nl_addr) {
+ rtnl_neigh_put(rn);
+ return;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_addr);
+
+ err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
+ MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
+ bss->ifindex, nl_geterror(err));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
+ MACSTR, MAC2STR(addr));
+ }
+
+ nl_addr_put(nl_addr);
+ rtnl_neigh_put(rn);
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -7680,6 +7849,10 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
" --> %d (%s)",
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
+
+ if (drv->rtnl_sk)
+ rtnl_neigh_delete_fdb_entry(bss, addr);
+
if (ret == -ENOENT)
return 0;
return ret;
@@ -8454,6 +8627,11 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
struct nlattr *flags;
struct nl80211_sta_flag_update upd;
+ wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
+ " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
+ bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
+ !!(total_flags & WPA_STA_AUTHORIZED));
+
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
@@ -8504,9 +8682,6 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
enum nl80211_iftype nlmode, old_mode;
- struct hostapd_freq_params freq = {
- .freq = params->freq,
- };
if (params->p2p) {
wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
@@ -8521,7 +8696,7 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
return -1;
}
- if (nl80211_set_channel(drv->first_bss, &freq, 0)) {
+ if (nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
if (old_mode != nlmode)
wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
@@ -8575,8 +8750,7 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
- if (wpa_driver_nl80211_set_mode(drv->first_bss,
- NL80211_IFTYPE_ADHOC)) {
+ if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"IBSS mode");
return -1;
@@ -8600,8 +8774,16 @@ retry:
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
drv->ssid_len = params->ssid_len;
- wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
+ wpa_printf(MSG_DEBUG, " * ht_enabled=%d", params->freq.ht_enabled);
+ wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
+ params->freq.sec_channel_offset);
+ wpa_printf(MSG_DEBUG, " * vht_enabled=%d", params->freq.vht_enabled);
+ wpa_printf(MSG_DEBUG, " * center_freq1=%d", params->freq.center_freq1);
+ wpa_printf(MSG_DEBUG, " * center_freq2=%d", params->freq.center_freq2);
+ wpa_printf(MSG_DEBUG, " * bandwidth=%d", params->freq.bandwidth);
+ if (nl80211_put_freq_params(msg, &params->freq) < 0)
+ goto nla_put_failure;
if (params->beacon_int > 0) {
wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int);
@@ -8679,10 +8861,10 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
params->bssid_hint);
}
- if (params->freq) {
- wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
- drv->assoc_freq = params->freq;
+ if (params->freq.freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq);
+ drv->assoc_freq = params->freq.freq;
} else
drv->assoc_freq = 0;
@@ -9016,26 +9198,29 @@ nla_put_failure:
}
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode)
+static int wpa_driver_nl80211_set_mode_impl(
+ struct i802_bss *bss,
+ enum nl80211_iftype nlmode,
+ struct hostapd_freq_params *desired_freq_params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
int i;
int was_ap = is_ap_interface(drv->nlmode);
int res;
+ int mode_switch_res;
- res = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (res && nlmode == nl80211_get_ifmode(bss))
- res = 0;
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
+ mode_switch_res = 0;
- if (res == 0) {
+ if (mode_switch_res == 0) {
drv->nlmode = nlmode;
ret = 0;
goto done;
}
- if (res == -ENODEV)
+ if (mode_switch_res == -ENODEV)
return -1;
if (nlmode == drv->nlmode) {
@@ -9055,21 +9240,35 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
res = i802_set_iface_flags(bss, 0);
if (res == -EACCES || res == -ENODEV)
break;
- if (res == 0) {
- /* Try to set the mode again while the interface is
- * down */
- ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
- if (ret == -EACCES)
- break;
- res = i802_set_iface_flags(bss, 1);
- if (res && !ret)
- ret = -1;
- else if (ret != -EBUSY)
- break;
- } else
+ if (res != 0) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
"interface down");
- os_sleep(0, 100000);
+ os_sleep(0, 100000);
+ continue;
+ }
+
+ /*
+ * Setting the mode will fail for some drivers if the phy is
+ * on a frequency that the mode is disallowed in.
+ */
+ if (desired_freq_params) {
+ res = i802_set_freq(bss, desired_freq_params);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set frequency on interface");
+ }
+ }
+
+ /* Try to set the mode again while the interface is down */
+ mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+ if (mode_switch_res == -EBUSY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Delaying mode set while interface going down");
+ os_sleep(0, 100000);
+ continue;
+ }
+ ret = mode_switch_res;
+ break;
}
if (!ret) {
@@ -9079,6 +9278,14 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
drv->ignore_if_down_event = 1;
}
+ /* Bring the interface back up */
+ res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to set interface up after switching mode");
+ ret = -1;
+ }
+
done:
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
@@ -9141,6 +9348,21 @@ static int dfs_info_handler(struct nl_msg *msg, void *arg)
}
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
+{
+ return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
+}
+
+
+static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
+ struct hostapd_freq_params *freq)
+{
+ return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
+ freq);
+}
+
+
static int wpa_driver_nl80211_get_capa(void *priv,
struct wpa_driver_capa *capa)
{
@@ -9917,6 +10139,22 @@ static void *i802_init(struct hostapd_data *hapd,
i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
goto failed;
+#ifdef CONFIG_LIBNL3_ROUTE
+ if (bss->added_if_into_bridge) {
+ drv->rtnl_sk = nl_socket_alloc();
+ if (drv->rtnl_sk == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
+ goto failed;
+ }
+
+ if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
+ strerror(errno));
+ goto failed;
+ }
+ }
+#endif /* CONFIG_LIBNL3_ROUTE */
+
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
if (drv->eapol_sock < 0) {
wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
@@ -9933,6 +10171,7 @@ static void *i802_init(struct hostapd_data *hapd,
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
params->own_addr))
goto failed;
+ os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
memcpy(bss->addr, params->own_addr, ETH_ALEN);
@@ -10177,7 +10416,15 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
if (drv->global)
drv->global->if_add_ifindex = ifidx;
- if (ifidx > 0)
+ /*
+ * Some virtual interfaces need to process EAPOL packets and events on
+ * the parent interface. This is used mainly with hostapd.
+ */
+ if (ifidx > 0 &&
+ (drv->hostapd ||
+ nlmode == NL80211_IFTYPE_AP_VLAN ||
+ nlmode == NL80211_IFTYPE_WDS ||
+ nlmode == NL80211_IFTYPE_MONITOR))
add_ifidx(drv, ifidx);
return 0;
@@ -10495,7 +10742,8 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
if (!report) {
if (bss->nl_preq && drv->device_ap_sme &&
- is_ap_interface(drv->nlmode)) {
+ is_ap_interface(drv->nlmode) && !bss->in_deinit &&
+ !bss->static_ap) {
/*
* Do not disable Probe Request reporting that was
* enabled in nl80211_setup_ap().
@@ -10883,6 +11131,7 @@ static int nl80211_set_param(void *priv, const char *param)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
+ drv->force_connect_cmd = 1;
}
if (os_strstr(param, "no_offchannel_tx=1")) {
@@ -11374,60 +11623,18 @@ static int nl80211_start_radar_detection(void *priv,
nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
- if (freq->vht_enabled) {
- switch (freq->bandwidth) {
- case 20:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_20);
- break;
- case 40:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_40);
- break;
- case 80:
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80P80);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80);
- break;
- case 160:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_160);
- break;
- default:
- return -1;
- }
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
- freq->center_freq2);
- } else if (freq->ht_enabled) {
- switch (freq->sec_channel_offset) {
- case -1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40MINUS);
- break;
- case 1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40PLUS);
- break;
- default:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT20);
- break;
- }
- }
+ if (nl80211_put_freq_params(msg, freq) < 0)
+ goto nla_put_failure;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
"%d (%s)", ret, strerror(-ret));
nla_put_failure:
+ nlmsg_free(msg);
return -1;
}
@@ -11435,7 +11642,8 @@ nla_put_failure:
static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code,
- u32 peer_capab, const u8 *buf, size_t len)
+ u32 peer_capab, int initiator, const u8 *buf,
+ size_t len)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -11466,6 +11674,8 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
*/
NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
}
+ if (initiator)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_INITIATOR);
NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
return send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -11878,6 +12088,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
res = os_snprintf(pos, end - pos,
"phyname=%s\n"
+ "perm_addr=" MACSTR "\n"
"drv_ifindex=%d\n"
"operstate=%d\n"
"scan_state=%s\n"
@@ -11894,6 +12105,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"eapol_tx_sock=%d\n"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
+ MAC2STR(drv->perm_addr),
drv->ifindex,
drv->operstate,
scan_state_str(drv->scan_state),
@@ -12047,7 +12259,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
ret = nl80211_put_freq_params(msg, &settings->freq_params);
if (ret)
@@ -12276,6 +12488,90 @@ nla_put_failure:
}
+static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
+
+ if (!drv->roaming_vendor_cmd_avail) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
+ return -1;
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
+ NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING);
+
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!params)
+ goto nla_put_failure;
+ NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+ allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+ QCA_ROAMING_NOT_ALLOWED);
+ if (bssid)
+ NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid);
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_set_mac_addr(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int new_addr = addr != NULL;
+
+ if (!addr)
+ addr = drv->perm_addr;
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
+ return -1;
+
+ if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: failed to set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 1) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after failed set_mac_addr");
+ }
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
+ bss->ifname, MAC2STR(addr));
+ drv->addr_changed = new_addr;
+ os_memcpy(bss->addr, addr, ETH_ALEN);
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not restore interface UP after set_mac_addr");
+ }
+
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -12367,4 +12663,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
+ .roaming = nl80211_roaming,
+ .set_mac_addr = nl80211_set_mac_addr,
};
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 3608b52..66edfa7 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1478,7 +1478,7 @@ static int wpa_driver_test_associate(
struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
- __func__, priv, params->freq, params->pairwise_suite,
+ __func__, priv, params->freq.freq, params->pairwise_suite,
params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index e5734bd..1b3a757 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -2027,7 +2027,11 @@ int wpa_driver_wext_associate(void *priv,
* Stop cfg80211 from trying to associate before we are done
* with all parameters.
*/
- wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)");
+ /* continue anyway */
+ }
}
if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
@@ -2115,7 +2119,8 @@ int wpa_driver_wext_associate(void *priv,
if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
ret = -1;
#endif /* CONFIG_IEEE80211W */
- if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
+ if (params->freq.freq &&
+ wpa_driver_wext_set_freq(drv, params->freq.freq) < 0)
ret = -1;
if (!drv->cfg80211 &&
wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
@@ -2316,6 +2321,37 @@ static const char * wext_get_radio_name(void *priv)
}
+static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_statistics stats;
+ struct iwreq iwr;
+
+ os_memset(si, 0, sizeof(*si));
+ si->current_signal = -9999;
+ si->current_noise = 9999;
+ si->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) &stats;
+ iwr.u.data.length = sizeof(stats);
+ iwr.u.data.flags = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ si->current_signal = stats.qual.level -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ si->current_noise = stats.qual.noise -
+ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0);
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
@@ -2335,4 +2371,5 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
+ .signal_poll = wpa_driver_wext_signal_poll,
};
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 7e175f4..cdb913e 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -36,6 +36,10 @@ ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -105,6 +109,9 @@ DRV_AP_OBJS += ../src/drivers/driver_atheros.o
CONFIG_L2_PACKET=linux
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
+ifdef ATH_GCM_SUPPORT
+CFLAGS += -DATH_GCM_SUPPORT
+endif
endif
##### PURE CLIENT DRIVERS
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index db8561a..9fa70d9 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -31,6 +31,10 @@ ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 406010d..4b28dc0 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -503,6 +503,9 @@
* TX status event pertaining to the TX request.
* %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
* management frames at CCK rate or not in 2GHz band.
+ * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA
+ * counters which will be updated to the current value. This attribute
+ * is used during CSA period.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
* time if it is known that it is no longer necessary.
@@ -719,6 +722,22 @@
* QoS mapping is relevant for IP packets, it is only valid during an
* association. This is cleared on disassociation and AP restart.
*
+ * @NL80211_CMD_ADD_TX_TS: Ask the kernel to add a traffic stream for the given
+ * %NL80211_ATTR_TSID and %NL80211_ATTR_MAC with %NL80211_ATTR_USER_PRIO
+ * and %NL80211_ATTR_ADMITTED_TIME parameters.
+ * Note that the action frame handshake with the AP shall be handled by
+ * userspace via the normal management RX/TX framework, this only sets
+ * up the TX TS in the driver/device.
+ * If the admitted time attribute is not added then the request just checks
+ * if a subsequent setup could be successful, the intent is to use this to
+ * avoid setting up a session with the AP when local restrictions would
+ * make that impossible. However, the subsequent "real" setup may still
+ * fail even if the check was successful.
+ * @NL80211_CMD_DEL_TX_TS: Remove an existing TS with the %NL80211_ATTR_TSID
+ * and %NL80211_ATTR_MAC parameters. It isn't necessary to call this
+ * before removing a station entry entirely, or before disassociating
+ * or similar, cleanup will happen in the driver/device in this case.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -890,6 +909,9 @@ enum nl80211_commands {
NL80211_CMD_SET_QOS_MAP,
+ NL80211_CMD_ADD_TX_TS,
+ NL80211_CMD_DEL_TX_TS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1525,10 +1547,10 @@ enum nl80211_commands {
* operation).
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch.
- * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
- * field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
- * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
- * field in the probe response (%NL80211_ATTR_PROBE_RESP).
+ * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel
+ * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel
+ * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).
*
* @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
* As specified in the &enum nl80211_rxmgmt_flags.
@@ -1576,6 +1598,11 @@ enum nl80211_commands {
* advertise values that cannot always be met. In such cases, an attempt
* to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
*
+ * @NL80211_ATTR_CSA_C_OFFSETS_TX: An array of csa counter offsets (u16) which
+ * should be updated when the frame is transmitted.
+ * @NL80211_ATTR_MAX_CSA_COUNTERS: U8 attribute used to advertise the maximum
+ * supported number of csa counters.
+ *
* @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
* As specified in the &enum nl80211_tdls_peer_capability.
*
@@ -1583,6 +1610,34 @@ enum nl80211_commands {
* creation then the new interface will be owned by the netlink socket
* that created it and will be destroyed when the socket is closed
*
+ * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
+ * the TDLS link initiator.
+ *
+ * @NL80211_ATTR_USE_RRM: flag for indicating whether the current connection
+ * shall support Radio Resource Measurements (11k). This attribute can be
+ * used with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests.
+ * User space applications are expected to use this flag only if the
+ * underlying device supports these minimal RRM features:
+ * %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
+ * %NL80211_FEATURE_QUIET,
+ * If this flag is used, driver must add the Power Capabilities IE to the
+ * association request. In addition, it must also set the RRM capability
+ * flag in the association request's Capability Info field.
+ *
+ * @NL80211_ATTR_WIPHY_DYN_ACK: flag attribute used to enable ACK timeout
+ * estimation algorithm (dynack). In order to activate dynack
+ * %NL80211_FEATURE_ACKTO_ESTIMATION feature flag must be set by lower
+ * drivers to indicate dynack capability. Dynack is automatically disabled
+ * setting valid value for coverage class.
+ *
+ * @NL80211_ATTR_TSID: a TSID value (u8 attribute)
+ * @NL80211_ATTR_USER_PRIO: user priority value (u8 attribute)
+ * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds
+ * (per second) (u16 attribute)
+ *
+ * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
+ * &enum nl80211_smps_mode.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1920,6 +1975,21 @@ enum nl80211_attrs {
NL80211_ATTR_IFACE_SOCKET_OWNER,
+ NL80211_ATTR_CSA_C_OFFSETS_TX,
+ NL80211_ATTR_MAX_CSA_COUNTERS,
+
+ NL80211_ATTR_TDLS_INITIATOR,
+
+ NL80211_ATTR_USE_RRM,
+
+ NL80211_ATTR_WIPHY_DYN_ACK,
+
+ NL80211_ATTR_TSID,
+ NL80211_ATTR_USER_PRIO,
+ NL80211_ATTR_ADMITTED_TIME,
+
+ NL80211_ATTR_SMPS_MODE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2188,6 +2258,8 @@ enum nl80211_sta_bss_param {
* Contains a nested array of signal strength attributes (u8, dBm)
* @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
* Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
+ * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
+ * 802.11 header (u32, kbps)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2219,6 +2291,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_BYTES64,
NL80211_STA_INFO_CHAIN_SIGNAL,
NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
+ NL80211_STA_INFO_EXPECTED_THROUGHPUT,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3036,14 +3109,20 @@ enum nl80211_bss_scan_width {
* @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
* @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
* @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * (if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ * from a probe response, otherwise it may be from the same beacon
+ * that the NL80211_BSS_BEACON_TSF will be from)
* @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
* @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
* @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
* raw information elements from the probe response/beacon (bin);
- * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ * different then the IEs here are from a Probe Response frame; otherwise
+ * they are from a Beacon frame.
* However, if the driver does not indicate the source of the IEs, these
* IEs may be from either frame subtype.
+ * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ * data here is known to be from a probe response, without any heuristics.
* @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
* in mBm (100 * dBm) (s32)
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -3055,6 +3134,10 @@ enum nl80211_bss_scan_width {
* yet been received
* @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
* (u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ * (not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ * @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3072,6 +3155,8 @@ enum nl80211_bss {
NL80211_BSS_SEEN_MS_AGO,
NL80211_BSS_BEACON_IES,
NL80211_BSS_CHAN_WIDTH,
+ NL80211_BSS_BEACON_TSF,
+ NL80211_BSS_PRESP_DATA,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -3688,6 +3773,8 @@ enum nl80211_iface_limit_attrs {
* different channels may be used within this group.
* @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
* of supported channel widths for radar detection.
+ * @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
+ * of supported regulatory regions for radar detection.
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -3721,6 +3808,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_STA_AP_BI_MATCH,
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+ NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
/* keep last */
NUM_NL80211_IFACE_COMB,
@@ -3894,6 +3982,8 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
* to work properly to suppport receiving regulatory hints from
* cellular base stations.
+ * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only
+ * here to reserve the value for API/ABI compatibility)
* @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
* equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
* mode
@@ -3932,13 +4022,33 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
* channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
* lifetime of a BSS.
+ * @NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES: This device adds a DS Parameter
+ * Set IE to probe requests.
+ * @NL80211_FEATURE_WFA_TPC_IE_IN_PROBES: This device adds a WFA TPC Report IE
+ * to probe requests.
+ * @NL80211_FEATURE_QUIET: This device, in client mode, supports Quiet Period
+ * requests sent to it by an AP.
+ * @NL80211_FEATURE_TX_POWER_INSERTION: This device is capable of inserting the
+ * current tx power value into the TPC Report IE in the spectrum
+ * management TPC Report action frame, and in the Radio Measurement Link
+ * Measurement Report action frame.
+ * @NL80211_FEATURE_ACKTO_ESTIMATION: This driver supports dynamic ACK timeout
+ * estimation (dynack). %NL80211_ATTR_WIPHY_DYN_ACK flag attribute is used
+ * to enable dynack.
+ * @NL80211_FEATURE_STATIC_SMPS: Device supports static spatial
+ * multiplexing powersave, ie. can turn off all but one chain
+ * even on HT connections that should be using more chains.
+ * @NL80211_FEATURE_DYNAMIC_SMPS: Device supports dynamic spatial
+ * multiplexing powersave, ie. can turn off all but one chain
+ * and then wake the rest up as required after, for example,
+ * rts/cts handshake.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
- /* bit 4 is reserved - don't use */
+ NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
NL80211_FEATURE_SAE = 1 << 5,
NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6,
NL80211_FEATURE_SCAN_FLUSH = 1 << 7,
@@ -3953,6 +4063,13 @@ enum nl80211_feature_flags {
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18,
+ NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES = 1 << 19,
+ NL80211_FEATURE_WFA_TPC_IE_IN_PROBES = 1 << 20,
+ NL80211_FEATURE_QUIET = 1 << 21,
+ NL80211_FEATURE_TX_POWER_INSERTION = 1 << 22,
+ NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23,
+ NL80211_FEATURE_STATIC_SMPS = 1 << 24,
+ NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25,
};
/**
@@ -4027,6 +4144,25 @@ enum nl80211_acl_policy {
};
/**
+ * enum nl80211_smps_mode - SMPS mode
+ *
+ * Requested SMPS mode (for AP mode)
+ *
+ * @NL80211_SMPS_OFF: SMPS off (use all antennas).
+ * @NL80211_SMPS_STATIC: static SMPS (use a single antenna)
+ * @NL80211_SMPS_DYNAMIC: dynamic smps (start with a single antenna and
+ * turn on other antennas after CTS/RTS).
+ */
+enum nl80211_smps_mode {
+ NL80211_SMPS_OFF,
+ NL80211_SMPS_STATIC,
+ NL80211_SMPS_DYNAMIC,
+
+ __NL80211_SMPS_AFTER_LAST,
+ NL80211_SMPS_MAX = __NL80211_SMPS_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_radar_event - type of radar event for DFS operation
*
* Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
index a62ac8e..4dfdb3f 100644
--- a/src/eap_common/eap_eke_common.c
+++ b/src/eap_common/eap_eke_common.c
@@ -692,7 +692,7 @@ int eap_eke_decrypt_prot(struct eap_eke_session *sess,
if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
prot_len - block_size - icv_len, icv) < 0)
return -1;
- if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) {
+ if (os_memcmp_const(icv, prot + prot_len - icv_len, icv_len) != 0) {
wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data");
return -1;
}
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 04b987d..fceb1b0 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -174,7 +174,7 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len)
+ int tlv_type, u8 *pos, size_t len)
{
switch (tlv_type) {
case EAP_TLV_EAP_PAYLOAD_TLV:
diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h
index 8955617..d59a845 100644
--- a/src/eap_common/eap_fast_common.h
+++ b/src/eap_common/eap_fast_common.h
@@ -102,6 +102,6 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
- int tlv_type, u8 *pos, int len);
+ int tlv_type, u8 *pos, size_t len);
#endif /* EAP_FAST_H */
diff --git a/src/eap_common/eap_gpsk_common.c b/src/eap_common/eap_gpsk_common.c
index 7a33215..8c7ae27 100644
--- a/src/eap_common/eap_gpsk_common.c
+++ b/src/eap_common/eap_gpsk_common.c
@@ -284,7 +284,6 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
u8 *pk, size_t *pk_len)
{
u8 *seed, *pos;
- size_t seed_len;
int ret;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
@@ -296,8 +295,7 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
/* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */
- seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
- seed = os_malloc(seed_len);
+ seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len);
if (seed == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
"for key derivation");
@@ -313,17 +311,18 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
pos += EAP_GPSK_RAND_LEN;
os_memcpy(pos, id_server, id_server_len);
pos += id_server_len;
- wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed);
switch (specifier) {
case EAP_GPSK_CIPHER_AES:
- ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+ ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, pos - seed,
msk, emsk, sk, sk_len,
pk, pk_len);
break;
#ifdef EAP_GPSK_SHA256
case EAP_GPSK_CIPHER_SHA256:
- ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+ ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed,
+ pos - seed,
msk, emsk, sk, sk_len);
break;
#endif /* EAP_GPSK_SHA256 */
@@ -423,7 +422,6 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
{
u8 *seed, *pos;
u8 kdf_out[16];
- size_t seed_len;
int ret;
wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
@@ -441,8 +439,7 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
* Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
* CSuite_Sel || inputString)
*/
- seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
- seed = os_malloc(seed_len);
+ seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len);
if (seed == NULL) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
"for Session-Id derivation");
@@ -458,11 +455,11 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
pos += EAP_GPSK_RAND_LEN;
os_memcpy(pos, id_server, id_server_len);
pos += id_server_len;
- wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed);
ret = eap_gpsk_derive_mid_helper(specifier,
kdf_out, sizeof(kdf_out),
- psk, seed, seed_len,
+ psk, seed, pos - seed,
method_type);
sid[0] = method_type;
diff --git a/src/eap_common/eap_ikev2_common.c b/src/eap_common/eap_ikev2_common.c
index 6095fd8..585c79c 100644
--- a/src/eap_common/eap_ikev2_common.c
+++ b/src/eap_common/eap_ikev2_common.c
@@ -52,22 +52,12 @@ struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code)
{
struct wpabuf *msg;
-#ifdef CCNS_PL
- msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id);
- if (msg == NULL) {
- wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
- "for fragment ack");
- return NULL;
- }
- wpabuf_put_u8(msg, 0); /* Flags */
-#else /* CCNS_PL */
msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id);
if (msg == NULL) {
wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory "
"for fragment ack");
return NULL;
}
-#endif /* CCNS_PL */
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack");
@@ -110,7 +100,7 @@ int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
return -1;
}
- if (os_memcmp(icv, end - icv_len, icv_len) != 0) {
+ if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) {
wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV");
wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV",
icv, icv_len);
diff --git a/src/eap_common/eap_ikev2_common.h b/src/eap_common/eap_ikev2_common.h
index 329ccc4..e7502d7 100644
--- a/src/eap_common/eap_ikev2_common.h
+++ b/src/eap_common/eap_ikev2_common.h
@@ -9,16 +9,9 @@
#ifndef EAP_IKEV2_COMMON_H
#define EAP_IKEV2_COMMON_H
-#ifdef CCNS_PL
-/* incorrect bit order */
-#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
-#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
-#define IKEV2_FLAGS_ICV_INCLUDED 0x04
-#else /* CCNS_PL */
#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
#define IKEV2_FLAGS_ICV_INCLUDED 0x20
-#endif /* CCNS_PL */
#define IKEV2_FRAGMENT_SIZE 1400
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 96c9efd..631c363 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -106,9 +106,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
case 21:
nid = NID_secp521r1;
break;
+#ifndef OPENSSL_IS_BORINGSSL
case 25:
nid = NID_X9_62_prime192v1;
break;
+#endif /* OPENSSL_IS_BORINGSSL */
case 26:
nid = NID_secp224r1;
break;
@@ -263,18 +265,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num,
fail:
EC_GROUP_free(grp->group);
grp->group = NULL;
- EC_POINT_free(grp->pwe);
+ EC_POINT_clear_free(grp->pwe);
grp->pwe = NULL;
- BN_free(grp->order);
+ BN_clear_free(grp->order);
grp->order = NULL;
- BN_free(grp->prime);
+ BN_clear_free(grp->prime);
grp->prime = NULL;
ret = 1;
}
/* cleanliness and order.... */
- BN_free(cofactor);
- BN_free(x_candidate);
- BN_free(rnd);
+ BN_clear_free(cofactor);
+ BN_clear_free(x_candidate);
+ BN_clear_free(rnd);
os_free(prfbuf);
return ret;
diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c
index e1773bf..2adc3b3 100644
--- a/src/eap_common/eap_sim_common.c
+++ b/src/eap_common/eap_sim_common.c
@@ -198,7 +198,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
hmac, EAP_SIM_MAC_LEN);
os_free(tmp);
- return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -393,7 +393,7 @@ int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
hmac, EAP_SIM_MAC_LEN);
os_free(tmp);
- return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -893,7 +893,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
"AT_KDF attributes - ignore this");
- continue;
+ break;
}
attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
attr->kdf_count++;
@@ -972,7 +972,6 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
struct eap_sim_msg {
struct wpabuf *buf;
size_t mac, iv, encr; /* index from buf */
- int type;
};
@@ -986,7 +985,6 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
if (msg == NULL)
return NULL;
- msg->type = type;
msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
if (msg->buf == NULL) {
os_free(msg);
@@ -1006,7 +1004,8 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
}
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
+ const u8 *k_aut,
const u8 *extra, size_t extra_len)
{
struct eap_hdr *eap;
@@ -1019,7 +1018,7 @@ struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
eap->length = host_to_be16(wpabuf_len(msg->buf));
#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
- if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
+ if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) {
eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
wpabuf_len(msg->buf),
(u8 *) wpabuf_mhead(msg->buf) +
diff --git a/src/eap_common/eap_sim_common.h b/src/eap_common/eap_sim_common.h
index 6021bd2..daeb0e2 100644
--- a/src/eap_common/eap_sim_common.h
+++ b/src/eap_common/eap_sim_common.h
@@ -211,7 +211,8 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
struct eap_sim_msg;
struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
-struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
+ const u8 *k_aut,
const u8 *extra, size_t extra_len);
void eap_sim_msg_free(struct eap_sim_msg *msg);
u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index f061866..3d4fb6f 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -173,46 +173,12 @@ const struct ikev2_encr_alg * ikev2_get_encr(int id)
}
-#ifdef CCNS_PL
-/* from des.c */
-struct des3_key_s {
- u32 ek[3][32];
- u32 dk[3][32];
-};
-
-void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
-void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
-void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
-#endif /* CCNS_PL */
-
-
int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
const u8 *plain, u8 *crypt, size_t len)
{
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
- u8 *pos;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- blocks = len / 8;
- pos = crypt;
- for (i = 0; i < blocks; i++) {
- des3_encrypt(pos, &des3key, pos);
- pos += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -237,9 +203,6 @@ int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -251,31 +214,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
struct crypto_cipher *cipher;
int encr_alg;
-#ifdef CCNS_PL
- if (alg == ENCR_3DES) {
- struct des3_key_s des3key;
- size_t i, blocks;
-
- /* ECB mode is used incorrectly for 3DES!? */
- if (key_len != 24) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length");
- return -1;
- }
- des3_key_setup(key, &des3key);
-
- if (len % 8) {
- wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted "
- "length");
- return -1;
- }
- blocks = len / 8;
- for (i = 0; i < blocks; i++) {
- des3_decrypt(crypt, &des3key, plain);
- plain += 8;
- crypt += 8;
- }
- } else {
-#endif /* CCNS_PL */
switch (alg) {
case ENCR_3DES:
encr_alg = CRYPTO_CIPHER_ALG_3DES;
@@ -300,9 +238,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv,
return -1;
}
crypto_cipher_deinit(cipher);
-#ifdef CCNS_PL
- }
-#endif /* CCNS_PL */
return 0;
}
@@ -542,7 +477,7 @@ u8 * ikev2_decrypt_payload(int encr_id, int integ_id,
"hash");
return NULL;
}
- if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) {
+ if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum "
"Data");
return NULL;
@@ -706,10 +641,6 @@ int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf,
keys->SK_integ_len = integ->key_len;
keys->SK_encr_len = encr->key_len;
keys->SK_prf_len = prf->key_len;
-#ifdef CCNS_PL
- /* Uses encryption key length for SK_d; should be PRF length */
- keys->SK_d_len = keys->SK_encr_len;
-#endif /* CCNS_PL */
keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len +
2 * keys->SK_encr_len + 2 * keys->SK_prf_len;
diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h
index 45c970b..8a7982a 100644
--- a/src/eap_common/ikev2_common.h
+++ b/src/eap_common/ikev2_common.h
@@ -70,11 +70,7 @@ struct ikev2_transform {
/* Current IKEv2 version from RFC 4306 */
#define IKEV2_MjVer 2
#define IKEV2_MnVer 0
-#ifdef CCNS_PL
-#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4))
-#else /* CCNS_PL */
#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer))
-#endif /* CCNS_PL */
/* IKEv2 Exchange Types */
enum {
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 47cbbee..9880d3b 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -92,6 +92,15 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
}
+static void eap_sm_free_key(struct eap_sm *sm)
+{
+ if (sm->eapKeyData) {
+ bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen);
+ sm->eapKeyData = NULL;
+ }
+}
+
+
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
{
ext_password_free(sm->ext_pw_buf);
@@ -144,11 +153,13 @@ SM_STATE(EAP, INITIALIZE)
SM_ENTRY(EAP, INITIALIZE);
if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
- !sm->prev_failure) {
+ !sm->prev_failure &&
+ sm->last_config == eap_get_config(sm)) {
wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
"fast reauthentication");
sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
} else {
+ sm->last_config = eap_get_config(sm);
eap_deinit_prev_method(sm, "INITIALIZE");
}
sm->selectedMethod = EAP_TYPE_NONE;
@@ -159,8 +170,7 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
- os_free(sm->eapKeyData);
- sm->eapKeyData = NULL;
+ eap_sm_free_key(sm);
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
sm->eapKeyAvailable = FALSE;
@@ -404,7 +414,7 @@ SM_STATE(EAP, METHOD)
if (sm->m->isKeyAvailable && sm->m->getKey &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
- os_free(sm->eapKeyData);
+ eap_sm_free_key(sm);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
os_free(sm->eapSessionId);
@@ -1488,8 +1498,7 @@ void eap_sm_abort(struct eap_sm *sm)
sm->lastRespData = NULL;
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
- os_free(sm->eapKeyData);
- sm->eapKeyData = NULL;
+ eap_sm_free_key(sm);
os_free(sm->eapSessionId);
sm->eapSessionId = NULL;
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index fee1b7b..0662ae7 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -42,7 +42,7 @@ struct eap_aka_data {
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+ CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
struct wpabuf *id_msgs;
@@ -64,8 +64,6 @@ static const char * eap_aka_state_txt(int state)
return "CONTINUE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
- case RESULT_FAILURE:
- return "RESULT_FAILURE";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -128,6 +126,21 @@ static void * eap_aka_prime_init(struct eap_sm *sm)
#endif /* EAP_AKA_PRIME */
+static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth)
+{
+ if (!reauth) {
+ os_memset(data->mk, 0, EAP_SIM_MK_LEN);
+ os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN);
+ os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
+ os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN);
+ }
+ os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
+ os_memset(data->autn, 0, EAP_AKA_AUTN_LEN);
+ os_memset(data->auts, 0, EAP_AKA_AUTS_LEN);
+}
+
+
static void eap_aka_deinit(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
@@ -137,6 +150,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
os_free(data->last_eap_identity);
wpabuf_free(data->id_msgs);
os_free(data->network_name);
+ eap_aka_clear_keys(data, 0);
os_free(data);
}
}
@@ -153,7 +167,7 @@ static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data)
pos += os_snprintf(pos, end - pos, ":");
pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN);
pos += os_snprintf(pos, end - pos, ":");
- pos += wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN);
eap_sm_request_sim(sm, req);
return 1;
@@ -296,7 +310,7 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
{
u8 autn[EAP_AKA_AUTN_LEN];
os_memset(autn, '1', EAP_AKA_AUTN_LEN);
- if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
+ if (os_memcmp_const(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
"with expected value");
return -1;
@@ -511,7 +525,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
#endif /* EAP_AKA_PRIME */
sha1_vector(1, &addr, &len, hash);
- if (os_memcmp(hash, checkcode, hash_len) != 0) {
+ if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
return -1;
}
@@ -534,7 +548,7 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id,
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -551,7 +565,7 @@ static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data,
"(id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -570,7 +584,7 @@ static struct wpabuf * eap_aka_synchronization_failure(
wpa_printf(MSG_DEBUG, " AT_AUTS");
eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
EAP_AKA_AUTS_LEN);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -614,7 +628,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
identity, identity_len);
}
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -636,7 +650,8 @@ static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, (u8 *) "",
+ 0);
}
@@ -678,7 +693,7 @@ static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -712,7 +727,7 @@ static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, data->eap_method, k_aut, (u8 *) "", 0);
}
@@ -792,7 +807,7 @@ static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
EAP_AKA_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_KDF");
eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
@@ -1025,7 +1040,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_aka_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -1241,7 +1256,7 @@ static struct wpabuf * eap_aka_process_reauthentication(
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_aka_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -1347,9 +1362,7 @@ done:
*/
ret->methodState = data->use_result_ind ?
METHOD_DONE : METHOD_MAY_CONT;
- } else if (data->state == RESULT_FAILURE)
- ret->methodState = METHOD_CONT;
- else if (data->state == RESULT_SUCCESS)
+ } else if (data->state == RESULT_SUCCESS)
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
@@ -1376,6 +1389,7 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
data->id_msgs = NULL;
data->use_result_ind = 0;
data->kdf_negotiation = 0;
+ eap_aka_clear_keys(data, 1);
}
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index daa1d32..2591e11 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -157,7 +157,7 @@ struct eap_peer_config {
*
* If left out, this will be asked through control interface.
*/
- u8 *private_key_passwd;
+ char *private_key_passwd;
/**
* dh_file - File path to DH/DSA parameters file (in PEM format)
@@ -289,7 +289,7 @@ struct eap_peer_config {
* This field is like private_key_passwd, but used for phase 2 (inside
* EAP-TTLS/PEAP/FAST tunnel) authentication.
*/
- u8 *private_key2_passwd;
+ char *private_key2_passwd;
/**
* dh_file2 - File path to DH/DSA parameters file (in PEM format)
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
index 864ea1d..9fec66c 100644
--- a/src/eap_peer/eap_eke.c
+++ b/src/eap_peer/eap_eke.c
@@ -138,7 +138,7 @@ static void eap_eke_deinit(struct eap_sm *sm, void *priv)
os_free(data->serverid);
os_free(data->peerid);
wpabuf_free(data->msgs);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -451,7 +451,7 @@ static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
/* DHComponent_P = Encr(key, y_p) */
rpos = wpabuf_put(resp, data->sess.dhcomp_len);
if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
- wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
os_memset(key, 0, sizeof(key));
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -523,7 +523,7 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
end = payload + payload_len;
if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
- wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_PROTO_ERROR);
}
@@ -543,7 +543,7 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
nonces, 2 * data->sess.nonce_len);
if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
- wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
+ wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_AUTHENTICATION_FAIL);
}
@@ -566,8 +566,8 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
}
wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len);
- if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len,
- data->sess.prf_len) != 0) {
+ if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len,
+ data->sess.prf_len) != 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match");
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_AUTHENTICATION_FAIL);
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index cc1f264..0739187 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -250,6 +250,8 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
pac = pac->next;
eap_fast_free_pac(prev);
}
+ os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
@@ -767,7 +769,7 @@ static struct wpabuf * eap_fast_process_crypto_binding(
"MAC calculation", (u8 *) _bind, bind_len);
hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
_bind->compound_mac);
- res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
+ res = os_memcmp_const(cmac, _bind->compound_mac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
cmac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
@@ -1080,7 +1082,8 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
struct eap_fast_tlv_parse *tlv,
struct wpabuf **resp)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1094,13 +1097,14 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
@@ -1634,6 +1638,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
os_free(data);
return NULL;
}
+ os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
data->session_id = NULL;
if (data->phase2_priv && data->phase2_method &&
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 5b023c7..c54bf11 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -134,8 +134,11 @@ static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
struct eap_gpsk_data *data = priv;
os_free(data->id_server);
os_free(data->id_peer);
- os_free(data->psk);
- os_free(data);
+ if (data->psk) {
+ os_memset(data->psk, 0, data->psk_len);
+ os_free(data->psk);
+ }
+ bin_clear_free(data, sizeof(*data));
}
@@ -236,6 +239,8 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
size_t *list_len,
const u8 *pos, const u8 *end)
{
+ size_t len;
+
if (pos == NULL)
return NULL;
@@ -243,23 +248,25 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
return NULL;
}
- *list_len = WPA_GET_BE16(pos);
+ len = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < (int) *list_len) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
return NULL;
}
- if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) {
+ if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu",
- (unsigned long) *list_len);
+ (unsigned long) len);
return NULL;
}
- *list = pos;
- pos += *list_len;
- if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0)
+ if (eap_gpsk_select_csuite(sm, data, pos, len) < 0)
return NULL;
+ *list = pos;
+ *list_len = len;
+ pos += len;
+
return pos;
}
@@ -561,7 +568,7 @@ static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
return NULL;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 8288ba5..fde809c 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -345,6 +345,7 @@ struct eap_sm {
struct wps_context *wps;
int prev_failure;
+ struct eap_peer_config *last_config;
struct ext_password_data *ext_pw;
struct wpabuf *ext_pw_buf;
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index 45945fe..c12b519 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -113,7 +113,7 @@ static void eap_ikev2_deinit(struct eap_sm *sm, void *priv)
wpabuf_free(data->in_buf);
wpabuf_free(data->out_buf);
ikev2_responder_deinit(&data->ikev2);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -154,12 +154,6 @@ static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data,
send_len -= 4;
}
}
-#ifdef CCNS_PL
- /* Some issues figuring out the length of the message if Message Length
- * field not included?! */
- if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED))
- flags |= IKEV2_FLAGS_LENGTH_INCLUDED;
-#endif /* CCNS_PL */
plen = 1 + send_len;
if (flags & IKEV2_FLAGS_LENGTH_INCLUDED)
@@ -381,12 +375,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv,
"Message Length %u", flags, message_length);
if (data->state == WAIT_FRAG_ACK) {
-#ifdef CCNS_PL
- if (len > 1) /* Empty Flags field included in ACK */
-#else /* CCNS_PL */
- if (len != 0)
-#endif /* CCNS_PL */
- {
+ if (len != 0) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload "
"in WAIT_FRAG_ACK state");
ret->ignore = TRUE;
diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c
index df34013..e0f8bcf 100644
--- a/src/eap_peer/eap_leap.c
+++ b/src/eap_peer/eap_leap.c
@@ -244,7 +244,7 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
ret->methodState = METHOD_DONE;
ret->allowNotifications = FALSE;
- if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
+ if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
"response - authentication failed");
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
@@ -383,6 +383,9 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
*len = LEAP_KEY_LEN;
+ os_memset(pw_hash, 0, sizeof(pw_hash));
+ os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash));
+
return key;
}
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index f9aa742..430c501 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -140,7 +140,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
os_free(data->peer_challenge);
os_free(data->auth_challenge);
wpabuf_free(data->prev_challenge);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -303,18 +303,23 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm,
WPA_EVENT_PASSWORD_CHANGED
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
- os_free(config->password);
+ bin_clear_free(config->password, config->password_len);
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
/* TODO: update external storage */
} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
config->password = os_malloc(16);
config->password_len = 16;
- if (config->password) {
- nt_password_hash(config->new_password,
- config->new_password_len,
- config->password);
+ if (config->password &&
+ nt_password_hash(config->new_password,
+ config->new_password_len,
+ config->password)) {
+ bin_clear_free(config->password,
+ config->password_len);
+ config->password = NULL;
+ config->password_len = 0;
}
- os_free(config->new_password);
+ bin_clear_free(config->new_password,
+ config->new_password_len);
} else {
config->password = config->new_password;
config->password_len = config->new_password_len;
@@ -549,15 +554,17 @@ static struct wpabuf * eap_mschapv2_change_password(
/* Encrypted-Hash */
if (pwhash) {
u8 new_password_hash[16];
- nt_password_hash(new_password, new_password_len,
- new_password_hash);
+ if (nt_password_hash(new_password, new_password_len,
+ new_password_hash))
+ goto fail;
nt_password_hash_encrypted_with_block(password,
new_password_hash,
cp->encr_hash);
} else {
- old_nt_password_hash_encrypted_with_new_nt_password_hash(
- new_password, new_password_len,
- password, password_len, cp->encr_hash);
+ if (old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ new_password, new_password_len,
+ password, password_len, cp->encr_hash))
+ goto fail;
}
/* Peer-Challenge */
@@ -594,9 +601,13 @@ static struct wpabuf * eap_mschapv2_change_password(
/* Likewise, generate master_key here since we have the needed data
* available. */
- nt_password_hash(new_password, new_password_len, password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
- get_master_key(password_hash_hash, cp->nt_response, data->master_key);
+ if (nt_password_hash(new_password, new_password_len, password_hash) ||
+ hash_nt_password_hash(password_hash, password_hash_hash) ||
+ get_master_key(password_hash_hash, cp->nt_response,
+ data->master_key)) {
+ data->auth_response_valid = 0;
+ goto fail;
+ }
data->master_key_valid = 1;
/* Flags */
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 7f87052..1c111c2 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -86,7 +86,7 @@ static void eap_pax_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
os_free(data->cid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -278,7 +278,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data,
eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, NULL, 0, mac);
- if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
+ if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
@@ -415,7 +415,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv,
wpabuf_head(reqData), mlen, NULL, 0, NULL, 0,
icvbuf);
}
- if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
+ if (os_memcmp_const(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 8634f75..472e861 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -170,6 +170,15 @@ static void * eap_peap_init(struct eap_sm *sm)
}
+static void eap_peap_free_key(struct eap_peap_data *data)
+{
+ if (data->key_data) {
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_peap_deinit(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
@@ -179,7 +188,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
data->phase2_method->deinit(sm, data->phase2_priv);
os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_peap_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
@@ -423,7 +432,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
buf, sizeof(buf));
hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
- if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
"cryptobinding TLV");
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
@@ -1005,7 +1014,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
char *label;
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
- os_free(data->key_data);
+ eap_peap_free_key(data);
/* draft-josefsson-ppext-eap-tls-eap-05.txt
* specifies that PEAPv1 would use "client PEAP
* encryption" as the label. However, most existing
@@ -1115,8 +1124,7 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_peap_free_key(data);
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c
index cd0e3f9..f012663 100644
--- a/src/eap_peer/eap_psk.c
+++ b/src/eap_peer/eap_psk.c
@@ -76,7 +76,7 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv)
struct eap_psk_data *data = priv;
os_free(data->id_s);
os_free(data->id_p);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -237,7 +237,7 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data,
return NULL;
}
os_free(buf);
- if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
"message");
ret->methodState = METHOD_DONE;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 2aa7ba5..1c915ed 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -123,7 +123,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
if ((data->password = os_malloc(password_len)) == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
BN_CTX_free(data->bnctx);
- os_free(data->id_peer);
+ bin_clear_free(data->id_peer, data->id_peer_len);
os_free(data);
return NULL;
}
@@ -148,26 +148,26 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_free(data->private_value);
- BN_free(data->server_scalar);
- BN_free(data->my_scalar);
- BN_free(data->k);
+ BN_clear_free(data->private_value);
+ BN_clear_free(data->server_scalar);
+ BN_clear_free(data->my_scalar);
+ BN_clear_free(data->k);
BN_CTX_free(data->bnctx);
- EC_POINT_free(data->my_element);
- EC_POINT_free(data->server_element);
- os_free(data->id_peer);
- os_free(data->id_server);
- os_free(data->password);
+ EC_POINT_clear_free(data->my_element);
+ EC_POINT_clear_free(data->server_element);
+ bin_clear_free(data->id_peer, data->id_peer_len);
+ bin_clear_free(data->id_server, data->id_server_len);
+ bin_clear_free(data->password, data->password_len);
if (data->grp) {
EC_GROUP_free(data->grp->group);
- EC_POINT_free(data->grp->pwe);
- BN_free(data->grp->order);
- BN_free(data->grp->prime);
+ EC_POINT_clear_free(data->grp->pwe);
+ BN_clear_free(data->grp->order);
+ BN_clear_free(data->grp->prime);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
wpabuf_free(data->outbuf);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -317,11 +317,15 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
goto fin;
}
- BN_rand_range(data->private_value, data->grp->order);
- BN_rand_range(mask, data->grp->order);
- BN_add(data->my_scalar, data->private_value, mask);
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx);
+ if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
+ BN_rand_range(mask, data->grp->order) != 1 ||
+ BN_add(data->my_scalar, data->private_value, mask) != 1 ||
+ BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+ data->bnctx) != 1) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd (peer): unable to get randomness");
+ goto fin;
+ }
if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
data->grp->pwe, mask, data->bnctx)) {
@@ -336,7 +340,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
goto fin;
}
- BN_free(mask);
+ BN_clear_free(mask);
if (((x = BN_new()) == NULL) ||
((y = BN_new()) == NULL)) {
@@ -471,11 +475,11 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
fin:
os_free(scalar);
os_free(element);
- BN_free(x);
- BN_free(y);
- BN_free(cofactor);
- EC_POINT_free(K);
- EC_POINT_free(point);
+ BN_clear_free(x);
+ BN_clear_free(y);
+ BN_clear_free(cofactor);
+ EC_POINT_clear_free(K);
+ EC_POINT_clear_free(point);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
else
@@ -589,7 +593,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
goto fin;
}
@@ -680,9 +684,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -782,6 +786,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
tot_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose "
"total length = %d", tot_len);
+ if (tot_len > 15000)
+ return NULL;
data->inbuf = wpabuf_alloc(tot_len);
if (data->inbuf == NULL) {
wpa_printf(MSG_INFO, "Out of memory to buffer "
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index 431519c..7d14907 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -108,7 +108,7 @@ static void eap_sake_deinit(struct eap_sm *sm, void *priv)
struct eap_sake_data *data = priv;
os_free(data->serverid);
os_free(data->peerid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -315,7 +315,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm,
data->peerid, data->peerid_len, 0,
wpabuf_head(reqData), wpabuf_len(reqData),
attr.mic_s, mic_s);
- if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
+ if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
eap_sake_state(data, FAILURE);
ret->methodState = METHOD_DONE;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index fc9df96..bd06df7 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -43,7 +43,7 @@ struct eap_sim_data {
u8 *last_eap_identity;
size_t last_eap_identity_len;
enum {
- CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
+ CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
};
@@ -57,8 +57,6 @@ static const char * eap_sim_state_txt(int state)
return "CONTINUE";
case RESULT_SUCCESS:
return "RESULT_SUCCESS";
- case RESULT_FAILURE:
- return "RESULT_FAILURE";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -132,6 +130,20 @@ static void * eap_sim_init(struct eap_sm *sm)
}
+static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth)
+{
+ if (!reauth) {
+ os_memset(data->mk, 0, EAP_SIM_MK_LEN);
+ os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN);
+ os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN);
+ }
+ os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN);
+ os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN);
+ os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN);
+ os_memset(data->emsk, 0, EAP_EMSK_LEN);
+}
+
+
static void eap_sim_deinit(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
@@ -140,6 +152,7 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv)
os_free(data->pseudonym);
os_free(data->reauth_id);
os_free(data->last_eap_identity);
+ eap_sim_clear_keys(data, 0);
os_free(data);
}
}
@@ -451,7 +464,7 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -504,7 +517,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
identity, identity_len);
}
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -522,7 +535,8 @@ static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
+ (u8 *) data->sres,
data->num_chal * EAP_SIM_SRES_LEN);
}
@@ -564,7 +578,7 @@ static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -598,7 +612,7 @@ static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0);
}
@@ -788,7 +802,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_sim_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -989,7 +1003,7 @@ static struct wpabuf * eap_sim_process_reauthentication(
if (data->result_ind && attr->result_ind)
data->use_result_ind = 1;
- if (data->state != FAILURE && data->state != RESULT_FAILURE) {
+ if (data->state != FAILURE) {
eap_sim_state(data, data->use_result_ind ?
RESULT_SUCCESS : SUCCESS);
}
@@ -1088,9 +1102,7 @@ done:
DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
ret->methodState = data->use_result_ind ?
METHOD_DONE : METHOD_MAY_CONT;
- } else if (data->state == RESULT_FAILURE)
- ret->methodState = METHOD_CONT;
- else if (data->state == RESULT_SUCCESS)
+ } else if (data->state == RESULT_SUCCESS)
ret->methodState = METHOD_CONT;
if (ret->methodState == METHOD_DONE) {
@@ -1113,6 +1125,7 @@ static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
struct eap_sim_data *data = priv;
eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
data->use_result_ind = 0;
+ eap_sim_clear_keys(data, 1);
}
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index bb9f3f2..5aa3fd5 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -125,13 +125,22 @@ static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
#endif /* CONFIG_HS20 */
+static void eap_tls_free_key(struct eap_tls_data *data)
+{
+ if (data->key_data) {
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
if (data == NULL)
return;
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_tls_free_key(data);
os_free(data->session_id);
os_free(data);
}
@@ -181,7 +190,7 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
- os_free(data->key_data);
+ eap_tls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"client EAP encryption",
EAP_TLS_KEY_LEN +
@@ -267,8 +276,7 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_tls_free_key(data);
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index bc13647..25b9f12 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -243,7 +243,8 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE32(pos);
pos += 4;
- if (message_length < (u32) (end - pos)) {
+ if (message_length < (u32) (end - pos) ||
+ message_length > 75000) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 5091bf0..771da58 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -133,6 +133,15 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
}
+static void eap_ttls_free_key(struct eap_ttls_data *data)
+{
+ if (data->key_data) {
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ data->key_data = NULL;
+ }
+}
+
+
static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
@@ -141,7 +150,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
eap_ttls_phase2_eap_deinit(sm, data);
os_free(data->phase2_eap_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- os_free(data->key_data);
+ eap_ttls_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
@@ -213,7 +222,7 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
- os_free(data->key_data);
+ eap_ttls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"ttls keying material",
EAP_TLS_KEY_LEN);
@@ -492,16 +501,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
wpabuf_put(msg, pos - buf);
*resp = msg;
- if (sm->workaround) {
- /* At least FreeRADIUS seems to be terminating
- * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
- * packet. */
- wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
- "allow success without tunneled response");
- ret->methodState = METHOD_MAY_CONT;
- ret->decision = DECISION_COND_SUCC;
- }
-
return 0;
#else /* EAP_MSCHAPv2 */
wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
@@ -1540,8 +1539,7 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
- os_free(data->key_data);
- data->key_data = NULL;
+ eap_ttls_free_key(data);
os_free(data->session_id);
data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 1ccc352..8186afb 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -72,27 +72,10 @@ static int ikev2_derive_keys(struct ikev2_responder_data *data)
os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN);
pos += IKEV2_SPI_LEN;
os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN);
-#ifdef CCNS_PL
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- {
- int i;
- u8 *tmp = pos - IKEV2_SPI_LEN;
- /* Incorrect byte re-ordering on little endian hosts.. */
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i];
- for (i = 0; i < IKEV2_SPI_LEN; i++)
- *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i];
- }
-#endif
-#endif /* CCNS_PL */
/* SKEYSEED = prf(Ni | Nr, g^ir) */
/* Use zero-padding per RFC 4306, Sect. 2.14 */
pad_len = data->dh->prime_len - wpabuf_len(shared);
-#ifdef CCNS_PL
- /* Shared secret is not zero-padded correctly */
- pad_len = 0;
-#endif /* CCNS_PL */
pad = os_zalloc(pad_len ? pad_len : 1);
if (pad == NULL) {
wpabuf_free(shared);
@@ -179,21 +162,12 @@ static int ikev2_parse_transform(struct ikev2_proposal_data *prop,
"Transform Attr for AES");
break;
}
-#ifdef CCNS_PL
- if (WPA_GET_BE16(pos) != 0x001d /* ?? */) {
- wpa_printf(MSG_DEBUG, "IKEV2: Not a "
- "Key Size attribute for "
- "AES");
- break;
- }
-#else /* CCNS_PL */
if (WPA_GET_BE16(pos) != 0x800e) {
wpa_printf(MSG_DEBUG, "IKEV2: Not a "
"Key Size attribute for "
"AES");
break;
}
-#endif /* CCNS_PL */
if (WPA_GET_BE16(pos + 2) != 128) {
wpa_printf(MSG_DEBUG, "IKEV2: "
"Unsupported AES key size "
@@ -456,14 +430,6 @@ static int ikev2_process_ni(struct ikev2_responder_data *data,
return -1;
}
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces */
- while (ni_len > 1 && *ni == 0) {
- ni_len--;
- ni++;
- }
-#endif /* CCNS_PL */
-
data->i_nonce_len = ni_len;
os_memcpy(data->i_nonce, ni, ni_len);
wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni",
@@ -599,7 +565,7 @@ static int ikev2_process_auth_secret(struct ikev2_responder_data *data,
return -1;
if (auth_len != prf->hash_len ||
- os_memcmp(auth, auth_data, auth_len) != 0) {
+ os_memcmp_const(auth, auth_data, auth_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
auth, auth_len);
@@ -887,16 +853,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data,
phdr->flags = 0;
p = wpabuf_put(msg, sizeof(*p));
-#ifdef CCNS_PL
- /* Seems to require that the Proposal # is 1 even though RFC 4306
- * Sect 3.3.1 has following requirement "When a proposal is accepted,
- * all of the proposal numbers in the SA payload MUST be the same and
- * MUST match the number on the proposal sent that was accepted.".
- */
- p->proposal_num = 1;
-#else /* CCNS_PL */
p->proposal_num = data->proposal.proposal_num;
-#endif /* CCNS_PL */
p->protocol_id = IKEV2_PROTOCOL_IKE;
p->num_transforms = 4;
@@ -906,11 +863,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data,
WPA_PUT_BE16(t->transform_id, data->proposal.encr);
if (data->proposal.encr == ENCR_AES_CBC) {
/* Transform Attribute: Key Len = 128 bits */
-#ifdef CCNS_PL
- wpabuf_put_be16(msg, 0x001d); /* ?? */
-#else /* CCNS_PL */
wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */
-#endif /* CCNS_PL */
wpabuf_put_be16(msg, 128); /* 128-bit key */
}
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t;
@@ -1082,11 +1035,7 @@ static int ikev2_build_notification(struct ikev2_responder_data *data,
phdr = wpabuf_put(msg, sizeof(*phdr));
phdr->next_payload = next_payload;
phdr->flags = 0;
-#ifdef CCNS_PL
- wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */
-#else /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */
-#endif /* CCNS_PL */
wpabuf_put_u8(msg, 0); /* SPI Size */
wpabuf_put_be16(msg, data->error_type);
@@ -1130,13 +1079,6 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data)
data->r_nonce_len = IKEV2_NONCE_MIN_LEN;
if (random_get_bytes(data->r_nonce, data->r_nonce_len))
return NULL;
-#ifdef CCNS_PL
- /* Zeros are removed incorrectly from the beginning of the nonces in
- * key derivation; as a workaround, make sure Nr does not start with
- * zero.. */
- if (data->r_nonce[0] == 0)
- data->r_nonce[0] = 1;
-#endif /* CCNS_PL */
wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len);
msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500);
diff --git a/src/eap_peer/mschapv2.c b/src/eap_peer/mschapv2.c
index 37e6735..9bc7370 100644
--- a/src/eap_peer/mschapv2.c
+++ b/src/eap_peer/mschapv2.c
@@ -117,8 +117,8 @@ int mschapv2_verify_auth_response(const u8 *auth_response,
buf[0] != 'S' || buf[1] != '=' ||
hexstr2bin((char *) (buf + 2), recv_response,
MSCHAPV2_AUTH_RESPONSE_LEN) ||
- os_memcmp(auth_response, recv_response,
- MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
+ os_memcmp_const(auth_response, recv_response,
+ MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
return -1;
return 0;
}
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index 5b1a2d4..7ca956e 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -1092,8 +1092,10 @@ static int tncc_read_config(struct tncc_data *tncc)
int error = 0;
imc = tncc_parse_imc(pos + 4, line_end, &error);
- if (error)
+ if (error) {
+ os_free(config);
return -1;
+ }
if (imc) {
if (last == NULL)
tncc->imc = imc;
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 65d00dd..c1bb6b8 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -168,7 +168,7 @@ SM_STATE(EAP, INITIALIZE)
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
sm->eap_if.eapTimeout = FALSE;
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
sm->eap_if.eapKeyAvailable = FALSE;
@@ -346,7 +346,7 @@ SM_STATE(EAP, METHOD_RESPONSE)
sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
if (sm->m->isDone(sm, sm->eap_method_priv)) {
eap_sm_Policy_update(sm, NULL, 0);
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
if (sm->m->getKey) {
sm->eap_if.eapKeyData = sm->m->getKey(
sm, sm->eap_method_priv,
@@ -632,7 +632,7 @@ SM_STATE(EAP, SUCCESS2)
if (sm->eap_if.aaaEapKeyAvailable) {
EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
} else {
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
}
@@ -1260,7 +1260,7 @@ static void eap_user_free(struct eap_user *user)
{
if (user == NULL)
return;
- os_free(user->password);
+ bin_clear_free(user->password, user->password_len);
user->password = NULL;
os_free(user);
}
@@ -1352,7 +1352,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
if (sm->m && sm->eap_method_priv)
sm->m->reset(sm, sm->eap_method_priv);
wpabuf_free(sm->eap_if.eapReqData);
- os_free(sm->eap_if.eapKeyData);
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
@@ -1361,7 +1361,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
os_free(sm->eap_fast_a_id_info);
wpabuf_free(sm->eap_if.aaaEapReqData);
wpabuf_free(sm->eap_if.aaaEapRespData);
- os_free(sm->eap_if.aaaEapKeyData);
+ bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
eap_user_free(sm->user);
wpabuf_free(sm->assoc_wps_ie);
wpabuf_free(sm->assoc_p2p_ie);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 46fc458..09b976e 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -241,7 +241,7 @@ static void eap_aka_reset(struct eap_sm *sm, void *priv)
os_free(data->next_reauth_id);
wpabuf_free(data->id_msgs);
os_free(data->network_name);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -336,7 +336,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data,
else
sha1_vector(1, &addr, &len, hash);
- if (os_memcmp(hash, checkcode, hash_len) != 0) {
+ if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
return -1;
}
@@ -377,7 +377,7 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
- buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
+ buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
if (eap_aka_add_id_msg(data, buf) < 0) {
wpabuf_free(buf);
return NULL;
@@ -534,7 +534,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -581,7 +581,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -620,7 +620,7 @@ static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
}
@@ -963,7 +963,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm,
*/
if (attr->res == NULL || attr->res_len < data->res_len ||
attr->res_len_bits != data->res_len * 8 ||
- os_memcmp(attr->res, data->res, data->res_len) != 0) {
+ os_memcmp_const(attr->res, data->res, data->res_len) != 0) {
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
"include valid AT_RES (attr len=%lu, res len=%lu "
"bits, expected %lu bits)",
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index b19a321..966f511 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -104,7 +104,7 @@ static void eap_eke_reset(struct eap_sm *sm, void *priv)
eap_eke_session_clean(&data->sess);
os_free(data->peerid);
wpabuf_free(data->msgs);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -635,8 +635,8 @@ static void eap_eke_process_confirm(struct eap_sm *sm,
return;
}
wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len);
- if (os_memcmp(auth_p, payload + data->sess.pnonce_len,
- data->sess.prf_len) != 0) {
+ if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len,
+ data->sess.prf_len) != 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match");
eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
return;
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index fcb80dc..2692bce 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -161,8 +161,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
return 0;
}
- if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
- pac_opaque, buf) < 0) {
+ if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
"PAC-Opaque");
os_free(buf);
@@ -187,7 +187,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
switch (*pos) {
case PAC_OPAQUE_TYPE_PAD:
pos = end;
- break;
+ goto done;
case PAC_OPAQUE_TYPE_KEY:
if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
@@ -218,6 +218,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
pos += 2 + pos[1];
}
+done:
if (pac_key == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
@@ -511,7 +512,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv)
os_free(data->key_block_p);
wpabuf_free(data->pending_phase2_resp);
os_free(data->identity);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -730,8 +731,8 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
os_free(pac_buf);
return NULL;
}
- if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
- pac_opaque) < 0) {
+ if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
+ pac_len / 8, pac_buf, pac_opaque) < 0) {
os_free(pac_buf);
os_free(pac_opaque);
return NULL;
@@ -1123,7 +1124,8 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm,
static int eap_fast_parse_tlvs(struct wpabuf *data,
struct eap_fast_tlv_parse *tlv)
{
- int mandatory, tlv_type, len, res;
+ int mandatory, tlv_type, res;
+ size_t len;
u8 *pos, *end;
os_memset(tlv, 0, sizeof(*tlv));
@@ -1136,13 +1138,14 @@ static int eap_fast_parse_tlvs(struct wpabuf *data,
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > (size_t) (end - pos)) {
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return -1;
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
- "TLV type %d length %d%s",
- tlv_type, len, mandatory ? " (mandatory)" : "");
+ "TLV type %d length %u%s",
+ tlv_type, (unsigned int) len,
+ mandatory ? " (mandatory)" : "");
res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
if (res == -2)
@@ -1196,7 +1199,7 @@ static int eap_fast_validate_crypto_binding(
return -1;
}
- if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+ if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
(data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
"Crypto-Binding");
@@ -1210,7 +1213,7 @@ static int eap_fast_validate_crypto_binding(
(u8 *) b, bind_len);
hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
b->compound_mac);
- if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+ if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) {
wpa_hexdump(MSG_MSGDUMP,
"EAP-FAST: Calculated Compound MAC",
b->compound_mac, sizeof(cmac));
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index 66f4271..cb369e4 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -95,7 +95,7 @@ static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
{
struct eap_gpsk_data *data = priv;
os_free(data->id_peer);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -433,7 +433,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
@@ -502,7 +502,7 @@ static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
eap_gpsk_state(data, FAILURE);
return;
}
- if (os_memcmp(mic, pos, miclen) != 0) {
+ if (os_memcmp_const(mic, pos, miclen) != 0) {
wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
diff --git a/src/eap_server/eap_server_gtc.c b/src/eap_server/eap_server_gtc.c
index f423106..98ac3c6 100644
--- a/src/eap_server/eap_server_gtc.c
+++ b/src/eap_server/eap_server_gtc.c
@@ -175,7 +175,7 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv,
}
if (rlen != sm->user->password_len ||
- os_memcmp(pos, sm->user->password, rlen) != 0) {
+ os_memcmp_const(pos, sm->user->password, rlen) != 0) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
data->state = FAILURE;
} else {
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 3e32cc9..65b2ef6 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -127,7 +127,7 @@ static void eap_ikev2_reset(struct eap_sm *sm, void *priv)
wpabuf_free(data->in_buf);
wpabuf_free(data->out_buf);
ikev2_initiator_deinit(&data->ikev2);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c
index 5a5e290..71e8d59 100644
--- a/src/eap_server/eap_server_md5.c
+++ b/src/eap_server/eap_server_md5.c
@@ -126,7 +126,7 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
return;
}
- if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
+ if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) {
wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
data->state = SUCCESS;
} else {
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 0eb7908..f7a753d 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -91,7 +91,7 @@ static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
return;
os_free(data->peer_challenge);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -393,7 +393,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
return;
}
- if (os_memcmp(nt_response, expected, 24) == 0) {
+ if (os_memcmp_const(nt_response, expected, 24) == 0) {
const u8 *pw_hash;
u8 pw_hash_buf[16], pw_hash_hash[16];
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index 35a42ad..d9d4375 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -64,7 +64,7 @@ static void eap_pax_reset(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
os_free(data->cid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -268,7 +268,7 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv,
wpabuf_mhead(respData),
wpabuf_len(respData) - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, icvbuf);
- if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
+ if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
@@ -287,7 +287,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
struct eap_pax_hdr *resp;
u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN];
const u8 *pos;
- size_t len, left;
+ size_t len, left, cid_len;
int i;
if (data->state != PAX_STD_1)
@@ -320,7 +320,12 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
return;
}
- data->cid_len = WPA_GET_BE16(pos);
+ cid_len = WPA_GET_BE16(pos);
+ if (cid_len > 1500) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Too long CID");
+ return;
+ }
+ data->cid_len = cid_len;
os_free(data->cid);
data->cid = os_malloc(data->cid_len);
if (data->cid == NULL) {
@@ -395,7 +400,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
data->rand.r.x, EAP_PAX_RAND_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, mac);
- if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in "
"PAX_STD-2");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)",
@@ -417,7 +422,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
wpabuf_head(respData),
wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0,
icvbuf);
- if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
+ if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV",
icvbuf, EAP_PAX_ICV_LEN);
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index defcb3c..594e02d 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -172,7 +172,7 @@ static void eap_peap_reset(struct eap_sm *sm, void *priv)
wpabuf_free(data->pending_phase2_resp);
os_free(data->phase2_key);
wpabuf_free(data->soh_response);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -593,7 +593,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
buf[60] = EAP_TYPE_PEAP;
hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
- if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
"cryptobinding TLV");
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index 46bedd9..db394e9 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -47,7 +47,7 @@ static void eap_psk_reset(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
os_free(data->id_p);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -314,7 +314,7 @@ static void eap_psk_process_2(struct eap_sm *sm,
}
os_free(buf);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN);
- if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
+ if (os_memcmp_const(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P");
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P",
mac, EAP_PSK_MAC_LEN);
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index ec53481..7e1278d 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -106,7 +106,7 @@ static void * eap_pwd_init(struct eap_sm *sm)
if (data->password == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
"fail");
- os_free(data->id_server);
+ bin_clear_free(data->id_server, data->id_server_len);
os_free(data);
return NULL;
}
@@ -116,8 +116,8 @@ static void * eap_pwd_init(struct eap_sm *sm)
data->bnctx = BN_CTX_new();
if (data->bnctx == NULL) {
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
- os_free(data->password);
- os_free(data->id_server);
+ bin_clear_free(data->password, data->password_len);
+ bin_clear_free(data->id_server, data->id_server_len);
os_free(data);
return NULL;
}
@@ -135,26 +135,26 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv)
{
struct eap_pwd_data *data = priv;
- BN_free(data->private_value);
- BN_free(data->peer_scalar);
- BN_free(data->my_scalar);
- BN_free(data->k);
+ BN_clear_free(data->private_value);
+ BN_clear_free(data->peer_scalar);
+ BN_clear_free(data->my_scalar);
+ BN_clear_free(data->k);
BN_CTX_free(data->bnctx);
- EC_POINT_free(data->my_element);
- EC_POINT_free(data->peer_element);
- os_free(data->id_peer);
- os_free(data->id_server);
- os_free(data->password);
+ EC_POINT_clear_free(data->my_element);
+ EC_POINT_clear_free(data->peer_element);
+ bin_clear_free(data->id_peer, data->id_peer_len);
+ bin_clear_free(data->id_server, data->id_server_len);
+ bin_clear_free(data->password, data->password_len);
if (data->grp) {
EC_GROUP_free(data->grp->group);
- EC_POINT_free(data->grp->pwe);
- BN_free(data->grp->order);
- BN_free(data->grp->prime);
+ EC_POINT_clear_free(data->grp->pwe);
+ BN_clear_free(data->grp->order);
+ BN_clear_free(data->grp->prime);
os_free(data->grp);
}
wpabuf_free(data->inbuf);
wpabuf_free(data->outbuf);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -210,11 +210,15 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
goto fin;
}
- BN_rand_range(data->private_value, data->grp->order);
- BN_rand_range(mask, data->grp->order);
- BN_add(data->my_scalar, data->private_value, mask);
- BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
- data->bnctx);
+ if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
+ BN_rand_range(mask, data->grp->order) != 1 ||
+ BN_add(data->my_scalar, data->private_value, mask) != 1 ||
+ BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+ data->bnctx) != 1) {
+ wpa_printf(MSG_INFO,
+ "EAP-pwd (server): unable to get randomness");
+ goto fin;
+ }
if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
data->grp->pwe, mask, data->bnctx)) {
@@ -230,7 +234,7 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
"fail");
goto fin;
}
- BN_free(mask);
+ BN_clear_free(mask);
if (((x = BN_new()) == NULL) ||
((y = BN_new()) == NULL)) {
@@ -282,8 +286,8 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm,
fin:
os_free(scalar);
os_free(element);
- BN_free(x);
- BN_free(y);
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -406,9 +410,9 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm,
wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
if (data->outbuf == NULL)
eap_pwd_state(data, FAILURE);
}
@@ -724,11 +728,11 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
res = 1;
fin:
- EC_POINT_free(K);
- EC_POINT_free(point);
- BN_free(cofactor);
- BN_free(x);
- BN_free(y);
+ EC_POINT_clear_free(K);
+ EC_POINT_clear_free(point);
+ BN_clear_free(cofactor);
+ BN_clear_free(x);
+ BN_clear_free(y);
if (res)
eap_pwd_state(data, PWD_Confirm_Req);
@@ -835,7 +839,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_h_final(hash, conf);
ptr = (u8 *) payload;
- if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+ if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
"verify");
goto fin;
@@ -851,9 +855,9 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
eap_pwd_state(data, SUCCESS);
fin:
- os_free(cruft);
- BN_free(x);
- BN_free(y);
+ bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+ BN_clear_free(x);
+ BN_clear_free(y);
}
@@ -900,6 +904,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv,
tot_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total "
"length = %d", tot_len);
+ if (tot_len > 15000)
+ return;
data->inbuf = wpabuf_alloc(tot_len);
if (data->inbuf == NULL) {
wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to "
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 68dd76b..1937621 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -83,7 +83,7 @@ static void eap_sake_reset(struct eap_sm *sm, void *priv)
{
struct eap_sake_data *data = priv;
os_free(data->peerid);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -351,7 +351,7 @@ static void eap_sake_process_challenge(struct eap_sm *sm,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p);
- if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
return;
@@ -388,7 +388,7 @@ static void eap_sake_process_confirm(struct eap_sm *sm,
data->peerid, data->peerid_len, 1,
wpabuf_head(respData), wpabuf_len(respData),
attr.mic_p, mic_p);
- if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
eap_sake_state(data, FAILURE);
} else
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index b531241..23ee2b6 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -94,7 +94,7 @@ static void eap_sim_reset(struct eap_sm *sm, void *priv)
struct eap_sim_data *data = priv;
os_free(data->next_pseudonym);
os_free(data->next_reauth_id);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -140,7 +140,7 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
ver[1] = EAP_SIM_VERSION;
eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
ver, sizeof(ver));
- return eap_sim_msg_finish(msg, NULL, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
}
@@ -240,8 +240,8 @@ static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt,
- EAP_SIM_NONCE_MT_LEN);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
}
@@ -278,7 +278,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
}
@@ -317,7 +317,7 @@ static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
}
- return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
+ return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
}
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index 67a3dfa..21bd26f 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -480,7 +480,8 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv,
message_length = WPA_GET_BE32(pos);
pos += 4;
- if (message_length < (u32) (end - pos)) {
+ if (message_length < (u32) (end - pos) ||
+ message_length > 75000) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
"Length (%d; %ld remaining in this msg)",
message_length, (long) (end - pos));
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index d09a769..31e3871 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -336,7 +336,7 @@ static void eap_ttls_reset(struct eap_sm *sm, void *priv)
data->phase2_method->reset(sm, data->phase2_priv);
eap_server_tls_ssl_deinit(sm, &data->ssl);
wpabuf_free(data->pending_phase2_eap_resp);
- os_free(data);
+ bin_clear_free(data, sizeof(*data));
}
@@ -509,8 +509,8 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
}
if (sm->user->password_len != user_password_len ||
- os_memcmp(sm->user->password, user_password, user_password_len) !=
- 0) {
+ os_memcmp_const(sm->user->password, user_password,
+ user_password_len) != 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password");
eap_ttls_state(data, FAILURE);
return;
@@ -558,7 +558,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN)
+ != 0 ||
password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch");
os_free(chal);
@@ -571,7 +572,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
chap_md5(password[0], sm->user->password, sm->user->password_len,
challenge, challenge_len, hash);
- if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
+ if (os_memcmp_const(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) ==
+ 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
eap_ttls_state(data, SUCCESS);
} else {
@@ -616,7 +618,8 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN)
+ != 0 ||
response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch");
os_free(chal);
@@ -631,7 +634,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
nt_challenge_response(challenge, sm->user->password,
sm->user->password_len, nt_response);
- if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
+ if (os_memcmp_const(nt_response, response + 2 + 24, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
eap_ttls_state(data, SUCCESS);
} else {
@@ -703,7 +706,8 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
return;
}
- if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 ||
+ if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN)
+ != 0 ||
response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch");
os_free(chal);
@@ -736,7 +740,7 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
}
rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
- if (os_memcmp(nt_response, rx_resp, 24) == 0) {
+ if (os_memcmp_const(nt_response, rx_resp, 24) == 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
"NT-Response");
data->mschapv2_resp_ok = 1;
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 512ba30..632598f 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -633,7 +633,7 @@ static int ikev2_process_auth_secret(struct ikev2_initiator_data *data,
return -1;
if (auth_len != prf->hash_len ||
- os_memcmp(auth, auth_data, auth_len) != 0) {
+ os_memcmp_const(auth, auth_data, auth_len) != 0) {
wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data");
wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data",
auth, auth_len);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 1004b1a..70258be 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -255,12 +255,14 @@ SM_STATE(SUPP_PAE, CONNECTING)
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
-#ifdef CONFIG_WPS
- /* Reduce latency on starting WPS negotiation. */
- sm->startWhen = 1;
-#else /* CONFIG_WPS */
- sm->startWhen = 3;
-#endif /* CONFIG_WPS */
+ if (sm->conf.wps) {
+ /* Reduce latency on starting WPS negotiation. */
+ wpa_printf(MSG_DEBUG,
+ "EAPOL: Using shorter startWhen for WPS");
+ sm->startWhen = 1;
+ } else {
+ sm->startWhen = 2;
+ }
}
eapol_enable_timer_tick(sm);
sm->eapolEap = FALSE;
@@ -719,8 +721,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
hmac_md5(keydata.sign_key, sign_key_len,
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
key->key_signature);
- if (os_memcmp(orig_key_sign, key->key_signature,
- IEEE8021X_KEY_SIGN_LEN) != 0) {
+ if (os_memcmp_const(orig_key_sign, key->key_signature,
+ IEEE8021X_KEY_SIGN_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
"EAPOL-Key packet");
os_memcpy(key->key_signature, orig_key_sign,
@@ -1242,7 +1244,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
return 0;
}
#ifdef CONFIG_WPS
- if (sm->conf.workaround &&
+ if (sm->conf.wps && sm->conf.workaround &&
plen < len - sizeof(*hdr) &&
hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
@@ -1491,6 +1493,7 @@ void eapol_sm_notify_config(struct eapol_sm *sm,
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+ sm->conf.wps = conf->wps;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
/* Using EAP Proxy, so skip EAP state machine update */
@@ -1523,7 +1526,7 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
size_t eap_len;
#ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
+ if (sm && sm->use_eap_proxy) {
/* Get key from EAP proxy */
if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index d76c8c2..5b37314 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -58,6 +58,11 @@ struct eapol_config {
* external_sim - Use external processing for SIM/USIM operations
*/
int external_sim;
+
+ /**
+ * wps - Whether this connection is used for WPS
+ */
+ int wps;
};
struct eapol_sm;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1875ca4..9985e4f 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -12,6 +12,7 @@
#include "eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -183,6 +184,14 @@ void p2p_set_state(struct p2p_data *p2p, int new_state)
p2p_dbg(p2p, "State %s -> %s",
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
p2p->state = new_state;
+
+ if (new_state == P2P_IDLE && p2p->pending_channel) {
+ p2p_dbg(p2p, "Apply change in listen channel");
+ p2p->cfg->reg_class = p2p->pending_reg_class;
+ p2p->cfg->channel = p2p->pending_channel;
+ p2p->pending_reg_class = 0;
+ p2p->pending_channel = 0;
+ }
}
@@ -250,7 +259,8 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
return;
}
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
p2p->min_disc_int) * 100;
if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
@@ -600,6 +610,46 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
}
+static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
+ size_t ies_len)
+{
+ const u8 *pos, *end;
+ u8 id, len;
+
+ wpabuf_free(dev->info.vendor_elems);
+ dev->info.vendor_elems = NULL;
+
+ end = ies + ies_len;
+
+ for (pos = ies; pos + 1 < end; pos += len) {
+ id = *pos++;
+ len = *pos++;
+
+ if (pos + len > end)
+ break;
+
+ if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
+ continue;
+
+ if (len >= 4) {
+ u32 type = WPA_GET_BE32(pos);
+
+ if (type == WPA_IE_VENDOR_TYPE ||
+ type == WMM_IE_VENDOR_TYPE ||
+ type == WPS_IE_VENDOR_TYPE ||
+ type == P2P_IE_VENDOR_TYPE ||
+ type == WFD_IE_VENDOR_TYPE)
+ continue;
+ }
+
+ /* Unknown vendor element - make raw IE data available */
+ if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
+ break;
+ wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ }
+}
+
+
/**
* p2p_add_device - Add peer entries based on scan results or P2P frames
* @p2p: P2P module context from p2p_init()
@@ -748,6 +798,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
p2p_parse_free(&msg);
+ p2p_update_peer_vendor_elems(dev, ies, ies_len);
+
if (dev->flags & P2P_DEV_REPORTED)
return 0;
@@ -817,6 +869,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
}
wpabuf_free(dev->info.wfd_subelems);
+ wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
os_free(dev);
@@ -1234,8 +1287,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
} else if (p2p_channel_random_social(&p2p->cfg->channels,
&p2p->op_reg_class,
&p2p->op_channel) == 0) {
- p2p_dbg(p2p, "Select random available social channel %d from 2.4 GHz band as operating channel preference",
- p2p->op_channel);
+ p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
+ p2p->op_reg_class, p2p->op_channel);
} else {
/* Select any random available channel from the first available
* operating class */
@@ -1553,7 +1606,7 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len)
int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
{
p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
- p2p_random(params->passphrase, 8);
+ p2p_random(params->passphrase, p2p->cfg->passphrase_len);
return 0;
}
@@ -1587,7 +1640,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
p2p->op_channel);
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
- p2p_random(res.passphrase, 8);
+ p2p_random(res.passphrase, p2p->cfg->passphrase_len);
} else {
res.freq = peer->oper_freq;
if (p2p->ssid_len) {
@@ -1772,8 +1825,17 @@ static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->go_neg_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->go_neg_peer->status = P2P_SC_SUCCESS;
+ /*
+ * Set new timeout to make sure a previously set one does not expire
+ * too quickly while waiting for the GO Negotiation to complete.
+ */
+ p2p_set_timeout(p2p, 0, 500000);
p2p_connect_send(p2p, p2p->go_neg_peer);
}
@@ -1783,6 +1845,10 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx)
struct p2p_data *p2p = eloop_ctx;
if (p2p->invite_peer == NULL)
return;
+ if (p2p->pending_listen_freq) {
+ p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start");
+ p2p->pending_listen_freq = 0;
+ }
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
p2p->invite_dev_pw_id);
@@ -1949,6 +2015,9 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
extra = wpabuf_len(p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -1969,6 +2038,10 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
+ wpabuf_put_buf(buf,
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
+
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
p2p_buf_add_capability(buf, p2p->dev_capab &
@@ -2244,6 +2317,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
extra = wpabuf_len(p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
@@ -2259,6 +2335,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
+ wpabuf_put_buf(tmp,
+ p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
+
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2380,7 +2460,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
- if (cfg->max_peers < 1)
+ if (cfg->max_peers < 1 ||
+ cfg->passphrase_len < 8 || cfg->passphrase_len > 63)
return NULL;
p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
@@ -2413,7 +2494,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->max_disc_int = 3;
p2p->max_disc_tu = -1;
- os_get_random(&p2p->next_tie_breaker, 1);
+ if (os_get_random(&p2p->next_tie_breaker, 1) < 0)
+ p2p->next_tie_breaker = 0;
p2p->next_tie_breaker &= 0x01;
if (cfg->sd_request)
p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
@@ -2706,6 +2788,19 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
return;
}
+ if (p2p->sd_query->for_all_peers) {
+ /* Update the pending broadcast SD query count for this device
+ */
+ p2p->sd_peer->sd_pending_bcast_queries--;
+
+ /*
+ * If there are no pending broadcast queries for this device,
+ * mark it as done (-1).
+ */
+ if (p2p->sd_peer->sd_pending_bcast_queries == 0)
+ p2p->sd_peer->sd_pending_bcast_queries = -1;
+ }
+
/* Wait for response from the peer */
p2p_set_state(p2p, P2P_SD_DURING_FIND);
p2p_set_timeout(p2p, 0, 200000);
@@ -2845,6 +2940,10 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ wpabuf_put_buf(ies,
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
+
len = p2p_buf_add_ie_hdr(ies);
p2p_buf_add_capability(ies, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
@@ -2871,6 +2970,10 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
len += wpabuf_len(p2p->wfd_ie_probe_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p && p2p->vendor_elem &&
+ p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
+ len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
+
return len;
}
@@ -2928,7 +3031,8 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
* make it less likely to hit cases where we could end up in
* sync with peer not listening.
*/
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
timeout += r % 100000;
}
p2p_set_timeout(p2p, 0, timeout);
@@ -3991,20 +4095,50 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
}
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel)
+{
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+}
+
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced)
{
if (p2p_channel_to_freq(reg_class, channel) < 0)
return -1;
p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
reg_class, channel);
- p2p->cfg->reg_class = reg_class;
- p2p->cfg->channel = channel;
+
+ /*
+ * Listen channel was set in configuration or set by control interface;
+ * cannot override it.
+ */
+ if (p2p->cfg->channel_forced && forced == 0)
+ return -1;
+
+ if (p2p->state == P2P_IDLE) {
+ p2p->cfg->reg_class = reg_class;
+ p2p->cfg->channel = channel;
+ p2p->cfg->channel_forced = forced;
+ } else {
+ p2p_dbg(p2p, "Defer setting listen channel");
+ p2p->pending_reg_class = reg_class;
+ p2p->pending_channel = channel;
+ p2p->pending_channel_forced = forced;
+ }
return 0;
}
+u8 p2p_get_listen_channel(struct p2p_data *p2p)
+{
+ return p2p->cfg->channel;
+}
+
+
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
{
p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
@@ -4462,6 +4596,19 @@ void p2p_err(struct p2p_data *p2p, const char *fmt, ...)
}
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data)
+{
+ struct p2p_device *dev, *n;
+
+ dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
+ peer_callback(&dev->info, user_data);
+ }
+}
+
+
#ifdef CONFIG_WPS_NFC
static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
@@ -4688,3 +4835,18 @@ void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
}
#endif /* CONFIG_WPS_NFC */
+
+
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len)
+{
+ if (len < 8 || len > 63)
+ return -1;
+ p2p->cfg->passphrase_len = len;
+ return 0;
+}
+
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem)
+{
+ p2p->vendor_elem = vendor_elem;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fa8031d..076a2ac 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -230,6 +230,14 @@ struct p2p_peer_info {
* wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
*/
struct wpabuf *wfd_subelems;
+
+ /**
+ * vendor_elems - Unrecognized vendor elements
+ *
+ * This buffer includes any other vendor element than P2P, WPS, and WFD
+ * IE(s) from the frame that was used to discover the peer.
+ */
+ struct wpabuf *vendor_elems;
};
enum p2p_prov_disc_status {
@@ -267,6 +275,12 @@ struct p2p_config {
u8 channel;
/**
+ * channel_forced - the listen channel was forced by configuration
+ * or by control interface and cannot be overridden
+ */
+ u8 channel_forced;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -389,6 +403,14 @@ struct p2p_config {
unsigned int max_listen;
/**
+ * passphrase_len - Passphrase length (8..63)
+ *
+ * This parameter controls the length of the random passphrase that is
+ * generated at the GO.
+ */
+ unsigned int passphrase_len;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1669,7 +1691,24 @@ void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
*/
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
+/**
+ * p2p_config_get_random_social - Return a random social channel
+ * @p2p: P2P config
+ * @op_class: Selected operating class
+ * @op_channel: Selected social channel
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used before p2p_init is called. A random social channel
+ * from supports bands 2.4 GHz (channels 1,6,11) and 60 GHz (channel 2) is
+ * returned on success.
+ */
+int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
+ u8 *op_channel);
+
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced);
+
+u8 p2p_get_listen_channel(struct p2p_data *p2p);
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
@@ -1771,7 +1810,7 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group);
* @group: P2P group context from p2p_group_init()
* @next: iteration pointer, must be a pointer to a void * that is set to %NULL
* on the first call and not modified later
- * Returns: A P2P Interface Address for each call and %NULL for no more members
+ * Returns: A P2P Device Address for each call and %NULL for no more members
*/
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
@@ -1793,6 +1832,26 @@ const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
/**
+ * p2p_group_get_config - Get the group configuration
+ * @group: P2P group context from p2p_group_init()
+ * Returns: The group configuration pointer
+ */
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group);
+
+/**
+ * p2p_loop_on_all_groups - Run the given callback on all groups
+ * @p2p: P2P module context from p2p_init()
+ * @group_callback: The callback function pointer
+ * @user_data: Some user data pointer which can be %NULL
+ *
+ * The group_callback function can stop the iteration by returning 0.
+ */
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data);
+
+/**
* p2p_get_peer_found - Get P2P peer info structure of a found peer
* @p2p: P2P module context from p2p_init()
* @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1951,4 +2010,13 @@ void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
int go_intent,
const u8 *own_interface_addr);
+int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len);
+
+void p2p_loop_on_known_peers(struct p2p_data *p2p,
+ void (*peer_callback)(struct p2p_peer_info *peer,
+ void *user_data),
+ void *user_data);
+
+void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index 76d01cf..86bae1a 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -68,6 +68,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
{
struct p2p_device *go;
struct wpabuf *req;
+ unsigned int wait_time;
go = p2p_get_device(p2p, dev->member_in_go_dev);
if (go == NULL || dev->oper_freq <= 0) {
@@ -88,9 +89,12 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
ETH_ALEN);
p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
+ wait_time = 1000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
p2p->cfg->dev_addr, go->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(req);
/* TODO: how to recover from failure? */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f24fe23..21fae3f 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -142,6 +143,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -191,6 +195,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+
return buf;
}
@@ -268,6 +275,9 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -336,6 +346,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
return buf;
}
@@ -844,6 +856,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
extra = wpabuf_len(p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -888,6 +903,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
return buf;
}
@@ -940,7 +958,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
os_get_reltime(&dev->go_neg_wait_started);
- p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
+ if (p2p->state == P2P_CONNECT_LISTEN)
+ p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
+ else
+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
p2p_set_timeout(p2p, 0, 0);
} else {
p2p_dbg(p2p, "Stop GO Negotiation attempt");
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 395ca08..da8588a 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -214,6 +215,10 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
extra = wpabuf_len(group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
@@ -223,6 +228,11 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
+ wpabuf_put_buf(ie,
+ group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -448,6 +458,13 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
ie = p2p_group_encaps_probe_resp(p2p_subelems);
wpabuf_free(p2p_subelems);
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) {
+ struct wpabuf *extra;
+ extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]);
+ ie = wpabuf_concat(extra, ie);
+ }
+
#ifdef CONFIG_WIFI_DISPLAY
if (group->wfd_ie) {
struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
@@ -634,6 +651,10 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
extra = wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
/*
* (Re)Association Response - P2P IE
* Status attribute (shall be present when association request is
@@ -649,6 +670,11 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
wpabuf_put_buf(resp, group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->p2p->vendor_elem &&
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP])
+ wpabuf_put_buf(resp,
+ group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]);
+
rlen = p2p_buf_add_ie_hdr(resp);
if (status != P2P_SC_SUCCESS)
p2p_buf_add_status(resp, status);
@@ -973,7 +999,7 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next)
if (!iter)
return NULL;
- return iter->addr;
+ return iter->dev_addr;
}
@@ -1013,3 +1039,23 @@ int p2p_group_get_freq(struct p2p_group *group)
{
return group->cfg->freq;
}
+
+
+const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group)
+{
+ return group->cfg;
+}
+
+
+void p2p_loop_on_all_groups(struct p2p_data *p2p,
+ int (*group_callback)(struct p2p_group *group,
+ void *user_data),
+ void *user_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < p2p->num_groups; i++) {
+ if (!group_callback(p2p->groups[i], user_data))
+ break;
+ }
+}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 65ff9ef..3b60582 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -480,6 +480,10 @@ struct p2p_data {
unsigned int search_delay;
int in_search_delay;
+ u8 pending_reg_class;
+ u8 pending_channel;
+ u8 pending_channel_forced;
+
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
struct wpabuf *wfd_ie_probe_req;
@@ -495,6 +499,8 @@ struct p2p_data {
#endif /* CONFIG_WIFI_DISPLAY */
u16 authorized_oob_dev_pw_id;
+
+ struct wpabuf **vendor_elem;
};
/**
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index a36898e..ef01a66 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -45,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -86,6 +90,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
+
if (dev_pw_id >= 0) {
/* WSC IE in Invitation Request for NFC static handover */
p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 68d79d2..e101367 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -53,6 +54,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -77,6 +81,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
+
return buf;
}
@@ -111,6 +118,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
buf = wpabuf_alloc(100 + extra);
if (buf == NULL)
return NULL;
@@ -125,6 +135,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
+
return buf;
}
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 9df834c..13119c2 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -266,6 +266,7 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
int ret = 0;
struct p2p_sd_query *query;
int freq;
+ unsigned int wait_time;
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
if (freq <= 0) {
@@ -290,23 +291,16 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
p2p->sd_query = query;
p2p->pending_action_state = P2P_PENDING_SD;
+ wait_time = 5000;
+ if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
+ wait_time = p2p->cfg->max_listen;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
+ wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
ret = -1;
}
- /* Update the pending broadcast SD query count for this device */
- dev->sd_pending_bcast_queries--;
-
- /*
- * If there are no pending broadcast queries for this device, mark it as
- * done (-1).
- */
- if (dev->sd_pending_bcast_queries == 0)
- dev->sd_pending_bcast_queries = -1;
-
wpabuf_free(req);
return ret;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index ac19064..23acce7 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -149,6 +149,15 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
return 0;
}
+ if (freq >= 58320 && freq <= 64800) {
+ if ((freq - 58320) % 2160)
+ return -1;
+
+ *op_class = 180; /* 60 GHz, channels 1..4 */
+ *channel = (freq - 56160) / 2160;
+ return 0;
+ }
+
return -1;
}
@@ -388,17 +397,19 @@ unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
const struct p2p_channels *channels)
{
unsigned int i;
- int freq;
+ int freq = 0;
+ const struct p2p_channels *tmpc = channels ?
+ channels : &p2p->cfg->channels;
+
+ if (tmpc == NULL)
+ return 0;
for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
p2p->cfg->pref_chan[i].chan);
- if (freq <= 0)
- continue;
- if (!channels || p2p_channels_includes_freq(channels, freq))
+ if (p2p_channels_includes_freq(tmpc, freq))
return freq;
}
-
return 0;
}
@@ -439,7 +450,8 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title,
static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels)
{
unsigned int r;
- os_get_random((u8 *) &r, sizeof(r));
+ if (os_get_random((u8 *) &r, sizeof(r)) < 0)
+ r = 0;
r %= num_channels;
return channels[r];
}
@@ -479,7 +491,7 @@ int p2p_channel_select(struct p2p_channels *chans, const int *classes,
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
u8 *op_channel)
{
- u8 chan[3];
+ u8 chan[4];
unsigned int num_channels = 0;
/* Try to find available social channels from 2.4 GHz */
@@ -490,11 +502,18 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
if (p2p_channels_includes(chans, 81, 11))
chan[num_channels++] = 11;
+ /* Try to find available social channels from 60 GHz */
+ if (p2p_channels_includes(chans, 180, 2))
+ chan[num_channels++] = 2;
+
if (num_channels == 0)
return -1;
- *op_class = 81;
*op_channel = p2p_channel_pick_random(chan, num_channels);
+ if (*op_channel == 2)
+ *op_class = 180;
+ else
+ *op_class = 81;
return 0;
}
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index fb8a8ca..b1cf32d 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1451,7 +1451,7 @@ ieee802_1x_mka_encode_dist_sak_body(
os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
sak_pos = CS_ID_LEN;
}
- if (aes_wrap(participant->kek.key,
+ if (aes_wrap(participant->kek.key, 16,
cipher_suite_tbl[cs_index].sak_len / 8,
sak->key, body->sak + sak_pos)) {
wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
@@ -1611,7 +1611,7 @@ ieee802_1x_mka_decode_dist_sak_body(
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- if (aes_unwrap(participant->kek.key, sak_len >> 3, wrap_sak,
+ if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak,
unwrap_sak)) {
wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
os_free(unwrap_sak);
@@ -2942,8 +2942,9 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
mka_msg_len);
if (msg_icv) {
- if (os_memcmp(msg_icv, icv,
- mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
+ if (os_memcmp_const(msg_icv, icv,
+ mka_alg_tbl[kay->mka_algindex].icv_len) !=
+ 0) {
wpa_printf(MSG_ERROR,
"KaY: Computed ICV is not equal to Received ICV");
return -1;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index e34d08b..f3b645d 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -233,6 +233,17 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
+ RADIUS_ATTR_HEXDUMP },
};
#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
@@ -508,7 +519,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+ return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
}
@@ -535,7 +546,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+ if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
return 1;
for (i = 0; i < msg->attr_used; i++) {
@@ -568,7 +579,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
os_memcpy(msg->hdr->authenticator, orig_authenticator,
sizeof(orig_authenticator));
- return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+ return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0;
}
@@ -801,7 +812,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
sizeof(orig_authenticator));
}
- if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+ if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
return 1;
}
@@ -838,7 +849,7 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 34307f2..62faae1 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -92,6 +92,12 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
RADIUS_ATTR_ERROR_CAUSE = 101,
RADIUS_ATTR_EAP_KEY_NAME = 102,
+ RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
+ RADIUS_ATTR_WLAN_HESSID = 181,
+ RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
+ RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
+ RADIUS_ATTR_WLAN_AKM_SUITE = 188,
+ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189,
};
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 10056a6..e2766e2 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1080,19 +1080,23 @@ radius_change_server(struct radius_client_data *radius,
switch (nserv->addr.af) {
case AF_INET:
claddrlen = sizeof(claddr);
- getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntoa(claddr.sin_addr),
+ ntohs(claddr.sin_port));
+ }
break;
#ifdef CONFIG_IPV6
case AF_INET6: {
claddrlen = sizeof(claddr6);
- getsockname(sel_sock, (struct sockaddr *) &claddr6,
- &claddrlen);
- wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
- inet_ntop(AF_INET6, &claddr6.sin6_addr,
- abuf, sizeof(abuf)),
- ntohs(claddr6.sin6_port));
+ if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
+ &claddrlen) == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntop(AF_INET6, &claddr6.sin6_addr,
+ abuf, sizeof(abuf)),
+ ntohs(claddr6.sin6_port));
+ }
break;
}
#endif /* CONFIG_IPV6 */
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index c35ba55..00394b4 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -623,7 +623,7 @@ radius_server_get_new_session(struct radius_server_data *data,
os_memset(&tmp, 0, sizeof(tmp));
res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp);
- os_free(tmp.password);
+ bin_clear_free(tmp.password, tmp.password_len);
if (res != 0) {
RADIUS_DEBUG("User-Name not found from user database");
@@ -852,7 +852,7 @@ radius_server_macacl(struct radius_server_data *data,
os_strlen(sess->username), 0, &tmp);
if (res || !tmp.macacl || tmp.password == NULL) {
RADIUS_DEBUG("No MAC ACL user entry");
- os_free(tmp.password);
+ bin_clear_free(tmp.password, tmp.password_len);
code = RADIUS_CODE_ACCESS_REJECT;
} else {
u8 buf[128];
@@ -861,10 +861,10 @@ radius_server_macacl(struct radius_server_data *data,
(u8 *) client->shared_secret,
client->shared_secret_len,
buf, sizeof(buf));
- os_free(tmp.password);
+ bin_clear_free(tmp.password, tmp.password_len);
if (res < 0 || pw_len != (size_t) res ||
- os_memcmp(pw, buf, res) != 0) {
+ os_memcmp_const(pw, buf, res) != 0) {
RADIUS_DEBUG("Incorrect User-Password");
code = RADIUS_CODE_ACCESS_REJECT;
}
@@ -1926,7 +1926,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf,
if (inet_ntop(AF_INET6, &cli->addr6, abuf,
sizeof(abuf)) == NULL)
abuf[0] = '\0';
- if (inet_ntop(AF_INET6, &cli->mask6, abuf,
+ if (inet_ntop(AF_INET6, &cli->mask6, mbuf,
sizeof(mbuf)) == NULL)
mbuf[0] = '\0';
}
@@ -2048,8 +2048,6 @@ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
sess = s;
break;
}
- if (sess)
- break;
}
if (sess)
break;
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 88550e4..aab8b7e 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -653,11 +653,11 @@ static int wpa_supplicant_process_smk_error(
static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
- const u8 *kde;
- size_t len, kde_buf_len;
+ size_t kde_buf_len;
struct wpa_ptk *stk;
u8 buf[8], *kde_buf, *pos;
be32 lifetime;
@@ -668,14 +668,13 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
/* RSN: msg 1/4 should contain SMKID for the selected SMK */
- kde = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
- if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
+ ie.pmkid == NULL) {
wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
return;
}
- if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
ie.pmkid, PMKID_LEN);
return;
@@ -760,11 +759,10 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len;
wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
@@ -773,16 +771,14 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
* from the peer. It may also include Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
kde.pmkid == NULL || kde.rsn_ie == NULL) {
wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
return;
}
- if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
kde.pmkid, PMKID_LEN);
return;
@@ -809,11 +805,11 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len, key_len;
+ size_t key_len;
const u8 *_key;
u8 key_buf[32], rsc[6];
@@ -824,10 +820,8 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
* Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
"STK 3/4");
return;
@@ -935,7 +929,7 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
} else {
@@ -951,7 +945,7 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -1117,21 +1111,25 @@ void peerkey_deinit(struct wpa_sm *sm)
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver)
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len)
{
if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
(WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
/* 3/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_ACK) {
/* 1/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_SECURE) {
/* 4/4 STK 4-Way Handshake */
wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
} else {
/* 2/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
}
}
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index f420691..4c17eae 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -41,7 +41,8 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_eapol_key *key, u16 ver,
const u8 *buf, size_t len);
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver);
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len);
void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
struct wpa_eapol_key *key, size_t extra_len,
u16 key_info, u16 ver);
@@ -60,7 +61,8 @@ peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
static inline void
peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver)
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len)
{
}
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 0960815..885291a 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -35,7 +35,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
- os_free(entry);
+ bin_clear_free(entry, sizeof(*entry));
}
@@ -152,9 +152,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
while (pos) {
if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
if (pos->pmk_len == pmk_len &&
- os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
- os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
- 0) {
+ os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+ os_memcmp_const(pos->pmkid, entry->pmkid,
+ PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
"PMKSA entry");
os_free(entry);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 3b14656..8cb19a2 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -218,26 +218,29 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capab,
- const u8 *buf, size_t len)
+ int initiator, const u8 *buf, size_t len)
{
return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
- status_code, peer_capab, buf, len);
+ status_code, peer_capab, initiator, buf,
+ len);
}
static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
u8 dialog_token, u16 status_code, u32 peer_capab,
- const u8 *msg, size_t msg_len)
+ int initiator, const u8 *msg, size_t msg_len)
{
struct wpa_tdls_peer *peer;
wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u "
- "dialog_token=%u status_code=%u peer_capab=%u msg_len=%u",
+ "dialog_token=%u status_code=%u peer_capab=%u initiator=%d "
+ "msg_len=%u",
MAC2STR(dest), action_code, dialog_token, status_code,
- peer_capab, (unsigned int) msg_len);
+ peer_capab, initiator, (unsigned int) msg_len);
if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
- status_code, peer_capab, msg, msg_len)) {
+ status_code, peer_capab, initiator, msg,
+ msg_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to send message "
"(action_code=%u)", action_code);
return -1;
@@ -333,6 +336,7 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
peer->sm_tmr.dialog_token,
peer->sm_tmr.status_code,
peer->sm_tmr.peer_capab,
+ peer->initiator,
peer->sm_tmr.buf,
peer->sm_tmr.buf_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to retry "
@@ -564,7 +568,7 @@ static int wpa_supplicant_verify_tdls_mic(u8 trans_seq,
wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid,
peer->rsnie_p, timeoutie, (u8 *) ftie,
mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - "
"dropping packet");
wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC",
@@ -591,7 +595,7 @@ static int wpa_supplicant_verify_tdls_mic_teardown(
if (peer->tpk_set) {
wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode,
dtoken, lnkid, (u8 *) ftie, mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - "
"dropping packet");
return -1;
@@ -631,7 +635,33 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
}
-static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ struct wpa_tdls_peer *cur, *prev;
+
+ cur = sm->tdls;
+ prev = NULL;
+ while (cur && cur != peer) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur != peer) {
+ wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR
+ " to remove it from the list",
+ MAC2STR(peer->addr));
+ return;
+ }
+
+ if (prev)
+ prev->next = peer->next;
+ else
+ sm->tdls = peer->next;
+}
+
+
+static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
MAC2STR(peer->addr));
@@ -663,6 +693,14 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
}
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+ wpa_tdls_peer_clear(sm, peer);
+ wpa_tdls_peer_remove_from_list(sm, peer);
+ os_free(peer);
+}
+
+
static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
struct wpa_tdls_lnkid *lnkid)
{
@@ -759,7 +797,7 @@ skip_ies:
/* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
- reason_code, 0, rbuf, pos - rbuf);
+ reason_code, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
return 0;
@@ -802,7 +840,7 @@ static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
}
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
@@ -811,8 +849,25 @@ void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
break;
}
- if (peer)
+ if (!peer || !peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " not connected - cannot teardown unreachable link",
+ MAC2STR(addr));
+ return;
+ }
+
+ if (wpa_tdls_is_external_setup(sm)) {
+ /*
+ * Disable the link, send a teardown packet through the
+ * AP, and then reset link data.
+ */
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+ wpa_tdls_send_teardown(sm, addr,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
+ wpa_tdls_peer_free(sm, peer);
+ } else {
wpa_tdls_disable_peer_link(sm, peer);
+ }
}
@@ -917,17 +972,19 @@ skip_ftie:
* appropriate status code mentioning reason for error/failure.
* @dst - MAC addr of Peer station
* @tdls_action - TDLS frame type for which error code is sent
+ * @initiator - was this end the initiator of the connection
* @status - status code mentioning reason
*/
static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
- u8 tdls_action, u8 dialog_token, u16 status)
+ u8 tdls_action, u8 dialog_token, int initiator,
+ u16 status)
{
wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR
" (action=%u status=%u)",
MAC2STR(dst), tdls_action, status);
return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
- 0, NULL, 0);
+ 0, initiator, NULL, 0);
}
@@ -1133,7 +1190,7 @@ skip_ies:
MAC2STR(peer->addr));
status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
- 1, 0, 0, rbuf, pos - rbuf);
+ 1, 0, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
return status;
@@ -1223,7 +1280,8 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
skip_ies:
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
- dtoken, 0, 0, rbuf, pos - rbuf);
+ dtoken, 0, 0, peer->initiator, rbuf,
+ pos - rbuf);
os_free(rbuf);
return status;
@@ -1320,7 +1378,8 @@ skip_ies:
peer_capab |= TDLS_PEER_WMM;
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
- dtoken, 0, peer_capab, rbuf, pos - rbuf);
+ dtoken, 0, peer_capab, peer->initiator,
+ rbuf, pos - rbuf);
os_free(rbuf);
return status;
@@ -1331,11 +1390,85 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
struct wpa_tdls_peer *peer,
u8 dialog_token)
{
+ size_t buf_len = 0;
+ struct wpa_tdls_timeoutie timeoutie;
+ u16 rsn_capab;
+ u8 *rbuf, *pos, *count_pos;
+ u16 count;
+ struct rsn_ie_hdr *hdr;
+ int status;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
"(peer " MACSTR ")", MAC2STR(peer->addr));
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_rsn_ies;
+
+ /* Filling RSN IE */
+ hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+ count_pos = pos;
+ pos += 2;
+ count = 0;
+
+ /*
+ * AES-CCMP is the default encryption preferred for TDLS, so
+ * RSN IE is filled only with CCMP cipher suite.
+ * Note: TKIP is not used to encrypt TDLS link.
+ *
+ * Regardless of the cipher used on the AP connection, select CCMP
+ * here.
+ */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ WPA_PUT_LE16(count_pos, count);
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+ pos += RSN_SELECTOR_LEN;
+
+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+ WPA_PUT_LE16(pos, rsn_capab);
+ pos += 2;
+ hdr->len = (pos - (u8 *) hdr) - 2;
+ peer->rsnie_i_len = pos - peer->rsnie_i;
+
+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response",
+ (u8 *) hdr, hdr->len + 2);
+skip_rsn_ies:
+ buf_len = 0;
+ if (wpa_tdls_get_privacy(sm)) {
+ /* Peer RSN IE, Lifetime */
+ buf_len += peer->rsnie_i_len +
+ sizeof(struct wpa_tdls_timeoutie);
+ }
+ rbuf = os_zalloc(buf_len + 1);
+ if (rbuf == NULL) {
+ wpa_tdls_peer_free(sm, peer);
+ return -1;
+ }
+ pos = rbuf;
+
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_ies;
+ /* Initiator RSN IE */
+ pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+ /* Lifetime */
+ peer->lifetime = TPK_LIFETIME;
+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+ sizeof(timeoutie), peer->lifetime);
+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+skip_ies:
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+ dialog_token, 0, 0, 0, rbuf, pos - rbuf);
+ os_free(rbuf);
- return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
- dialog_token, 0, 0, NULL, 0);
+ return status;
}
@@ -1361,10 +1494,17 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+ /*
+ * Some APs will tack on a weird IE to the end of a TDLS
+ * discovery request packet. This needn't fail the response,
+ * since the required IE are verified separately.
+ */
if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
len - (sizeof(struct wpa_tdls_frame) + 1),
- &kde) < 0)
- return -1;
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround");
+ }
if (!kde.lnkid) {
wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
@@ -1396,7 +1536,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
MACSTR, MAC2STR(addr));
return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
- 1, 0, 0, NULL, 0);
+ 1, 0, 0, 1, NULL, 0);
}
@@ -1573,6 +1713,23 @@ static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde,
}
+static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+ int add)
+{
+ return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid,
+ peer->capability,
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities,
+ peer->vht_capabilities,
+ peer->qos_info, peer->wmm_capable,
+ peer->ext_capab, peer->ext_capab_len,
+ peer->supp_channels,
+ peer->supp_channels_len,
+ peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1620,16 +1777,16 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
"direct link is enabled - tear down the "
"old link first");
- wpa_tdls_disable_peer_link(sm, peer);
- }
-
- /*
- * An entry is already present, so check if we already sent a
- * TDLS Setup Request. If so, compare MAC addresses and let the
- * STA with the lower MAC address continue as the initiator.
- * The other negotiation is terminated.
- */
- if (peer->initiator) {
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ } else if (peer->initiator) {
+ /*
+ * An entry is already present, so check if we already
+ * sent a TDLS Setup Request. If so, compare MAC
+ * addresses and let the STA with the lower MAC address
+ * continue as the initiator. The other negotiation is
+ * terminated.
+ */
if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
wpa_printf(MSG_DEBUG, "TDLS: Discard request "
"from peer with higher address "
@@ -1641,7 +1798,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
MACSTR " (terminate previously "
"initiated negotiation",
MAC2STR(src_addr));
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
}
}
}
@@ -1666,7 +1825,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
- status = WLAN_STATUS_NOT_IN_SAME_BSS;
+ status = WLAN_STATUS_REQUEST_DECLINED;
goto error;
}
@@ -1707,6 +1866,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
"TDLS setup - send own request");
peer->initiator = 1;
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
wpa_tdls_send_tpk_m1(sm, peer);
}
@@ -1831,7 +1992,6 @@ skip_rsn:
if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->ctx, MSG_WARNING,
"TDLS: Failed to get random data for responder nonce");
- wpa_tdls_peer_free(sm, peer);
goto error;
}
}
@@ -1886,22 +2046,33 @@ skip_rsn:
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
skip_rsn_check:
- /* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
- NULL, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT)
+ goto skip_add_peer;
+#endif /* CONFIG_TDLS_TESTING */
+
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 1) < 0)
+ goto error;
+
+#ifdef CONFIG_TDLS_TESTING
+skip_add_peer:
+#endif /* CONFIG_TDLS_TESTING */
peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
goto error;
}
return 0;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
status);
+ if (peer)
+ wpa_tdls_peer_free(sm, peer);
return -1;
}
@@ -1930,20 +2101,6 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates, capabilities, and qos_info to the TDLS peer */
- if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
- peer->capability,
- peer->supp_rates, peer->supp_rates_len,
- peer->ht_capabilities,
- peer->vht_capabilities,
- peer->qos_info, peer->ext_capab,
- peer->ext_capab_len,
- peer->supp_channels,
- peer->supp_channels_len,
- peer->supp_oper_classes,
- peer->supp_oper_classes_len) < 0)
- return -1;
-
if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
"driver");
@@ -2098,6 +2255,13 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
kde.rsn_ie, kde.rsn_ie_len);
+ if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+ wpa_printf(MSG_INFO,
+ "TDLS: Too long Responder RSN IE in TPK M2");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto error;
+ }
+
/*
* FIX: bitwise comparison of RSN IE is not the correct way of
* validation this. It can be different, but certain fields must
@@ -2190,12 +2354,14 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
skip_rsn:
peer->dtoken = dtoken;
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
- if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_peer_link(sm, peer);
- return -1;
- }
+ if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
+ goto error;
if (!peer->tpk_success) {
/*
@@ -2214,7 +2380,7 @@ skip_rsn:
return ret;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1,
status);
wpa_tdls_disable_peer_link(sm, peer);
return -1;
@@ -2263,9 +2429,16 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
pos += 2 /* status code */ + 1 /* dialog token */;
ielen = len - (pos - buf); /* start of IE in buf */
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs piggy-back broken IEs to the end
+ * of a TDLS Confirm packet, which will fail the link if we don't ignore
+ * this error.
+ */
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
- goto error;
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround");
}
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
@@ -2350,6 +2523,10 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
}
skip_rsn:
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
if (!peer->tpk_success) {
/*
* Enable Link only when tpk_success is 0, signifying that this
@@ -2359,14 +2536,12 @@ skip_rsn:
ret = wpa_tdls_enable_link(sm, peer);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
- wpa_tdls_do_teardown(
- sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ goto error;
}
}
return ret;
error:
- wpa_tdls_disable_peer_link(sm, peer);
+ wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
return -1;
}
@@ -2429,8 +2604,11 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
- NULL, 0, NULL, 0, NULL, 0);
+ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
+ }
peer->tpk_in_progress = 1;
@@ -2580,13 +2758,14 @@ int wpa_tdls_init(struct wpa_sm *sm)
void wpa_tdls_teardown_peers(struct wpa_sm *sm)
{
- struct wpa_tdls_peer *peer;
+ struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
while (peer) {
+ tmp = peer->next;
wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
MAC2STR(peer->addr));
if (sm->tdls_external_setup)
@@ -2595,7 +2774,7 @@ void wpa_tdls_teardown_peers(struct wpa_sm *sm)
else
wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
- peer = peer->next;
+ peer = tmp;
}
}
@@ -2605,7 +2784,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm)
struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
- sm->tdls = NULL;
while (peer) {
int res;
@@ -2614,7 +2792,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm)
wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
MAC2STR(peer->addr), res);
wpa_tdls_peer_free(sm, peer);
- os_free(peer);
peer = tmp;
}
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index ba2a8c8..b17fc88 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -162,7 +162,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (pmkid && sm->cur_pmksa &&
- os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -379,7 +379,8 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
struct wpa_ptk *ptk;
@@ -401,10 +402,9 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
- const u8 *_buf = (const u8 *) (key + 1);
- size_t len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
- if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
+ key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
@@ -906,7 +906,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
return -1;
}
- if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+ {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"FT: PMKR1Name mismatch in "
"FT 4-way handshake message 3/4");
@@ -1068,10 +1069,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
- u16 key_info, keylen, len;
- const u8 *pos;
+ u16 key_info, keylen;
struct wpa_eapol_ie_parse ie;
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
@@ -1080,10 +1081,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
key_info = WPA_GET_BE16(key->key_info);
- pos = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1238,21 +1237,14 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- size_t keydatalen, int key_info,
- size_t extra_len, u16 ver,
- struct wpa_gtk_data *gd)
+ const u8 *key_data,
+ size_t key_data_len, u16 key_info,
+ u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
gd->gtk_len = WPA_GET_BE16(key->key_length);
- maxkeylen = keydatalen;
- if (keydatalen > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "WPA: Truncated EAPOL-Key packet: "
- "key_data_length=%lu > extra_len=%lu",
- (unsigned long) keydatalen, (unsigned long) extra_len);
- return -1;
- }
+ maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1272,16 +1264,16 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
WPA_KEY_INFO_KEY_INDEX_SHIFT;
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
u8 ek[32];
- if (keydatalen > sizeof(gd->gtk)) {
+ if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: RC4 key data too long (%lu)",
- (unsigned long) keydatalen);
+ (unsigned long) key_data_len);
return -1;
}
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, 16);
- os_memcpy(gd->gtk, key + 1, keydatalen);
- if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+ os_memcpy(gd->gtk, key_data, key_data_len);
+ if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
@@ -1289,22 +1281,22 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
}
os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- if (keydatalen % 8) {
+ if (maxkeylen % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported AES-WRAP len %lu",
- (unsigned long) keydatalen);
+ (unsigned long) maxkeylen);
return -1;
}
if (maxkeylen > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES-WRAP key data "
"too long (keydatalen=%lu maxkeylen=%lu)",
- (unsigned long) keydatalen,
+ (unsigned long) key_data_len,
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
- (const u8 *) (key + 1), gd->gtk)) {
+ if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data,
+ gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1360,9 +1352,10 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ const u8 *key_data,
+ size_t key_data_len, u16 ver)
{
- u16 key_info, keydatalen;
+ u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
@@ -1373,17 +1366,15 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
key_info = WPA_GET_BE16(key->key_info);
- keydatalen = WPA_GET_BE16(key->key_data_length);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
- ret = wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
+ ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data,
+ key_data_len, key_info,
&gd);
} else {
- ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
- key_info, extra_len,
- ver, &gd);
+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data,
+ key_data_len,
+ key_info, ver, &gd);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1429,7 +1420,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1446,7 +1437,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1471,12 +1462,11 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver)
+ struct wpa_eapol_key *key, u16 ver,
+ u8 *key_data, size_t *key_data_len)
{
- u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
if (!sm->ptk_set) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
@@ -1490,7 +1480,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+ if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
@@ -1501,37 +1491,37 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
sm->key_mgmt == WPA_KEY_MGMT_OSEN) {
u8 *buf;
- if (keydatalen % 8) {
+ if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Unsupported AES-WRAP len %d",
- keydatalen);
+ "WPA: Unsupported AES-WRAP len %u",
+ (unsigned int) *key_data_len);
return -1;
}
- keydatalen -= 8; /* AES-WRAP adds 8 bytes */
- buf = os_malloc(keydatalen);
+ *key_data_len -= 8; /* AES-WRAP adds 8 bytes */
+ buf = os_malloc(*key_data_len);
if (buf == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
- (u8 *) (key + 1), buf)) {
+ if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8,
+ key_data, buf)) {
os_free(buf);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
- os_memcpy(key + 1, buf, keydatalen);
+ os_memcpy(key_data, buf, *key_data_len);
os_free(buf);
- WPA_PUT_BE16(key->key_data_length, keydatalen);
+ WPA_PUT_BE16(key->key_data_length, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
return 0;
}
@@ -1605,13 +1595,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
- size_t plen, data_len, extra_len;
- struct ieee802_1x_hdr *hdr;
+ size_t plen, data_len, key_data_len;
+ const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
u16 key_info, ver;
- u8 *tmp;
+ u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
+ u8 *key_data;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
@@ -1626,13 +1617,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
return 0;
}
- tmp = os_malloc(len);
- if (tmp == NULL)
- return -1;
- os_memcpy(tmp, buf, len);
-
- hdr = (struct ieee802_1x_hdr *) tmp;
- key = (struct wpa_eapol_key *) (hdr + 1);
+ hdr = (const struct ieee802_1x_hdr *) buf;
plen = be_to_host16(hdr->length);
data_len = plen + sizeof(*hdr);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1649,6 +1634,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
@@ -1657,6 +1643,22 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ if (data_len < len) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+ (unsigned long) len - data_len);
+ }
+
+ /*
+ * Make a copy of the frame since we need to modify the buffer during
+ * MAC validation and Key Data decryption.
+ */
+ tmp = os_malloc(data_len);
+ if (tmp == NULL)
+ goto out;
+ os_memcpy(tmp, buf, data_len);
+ key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
+ key_data = (u8 *) (key + 1);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1668,13 +1670,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
wpa_eapol_key_dump(sm, key);
- eapol_sm_notify_lower_layer_success(sm->eapol, 0);
- wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
- if (data_len < len) {
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: ignoring %lu bytes after the IEEE 802.1X data",
- (unsigned long) len - data_len);
+ key_data_len = WPA_GET_BE16(key->key_data_length);
+ if (key_data_len > plen - sizeof(struct wpa_eapol_key)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+ "frame - key_data overflow (%u > %u)",
+ (unsigned int) key_data_len,
+ (unsigned int) (plen - sizeof(struct wpa_eapol_key)));
+ goto out;
}
+
+ eapol_sm_notify_lower_layer_success(sm->eapol, 0);
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
@@ -1814,22 +1819,11 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
#endif /* CONFIG_PEERKEY */
- extra_len = data_len - sizeof(*hdr) - sizeof(*key);
-
- if (WPA_GET_BE16(key->key_data_length) > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
- "frame - key_data overflow (%d > %lu)",
- WPA_GET_BE16(key->key_data_length),
- (unsigned long) extra_len);
- goto out;
- }
- extra_len = WPA_GET_BE16(key->key_data_length);
-
if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+ if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ &key_data_len))
goto out;
- extra_len = WPA_GET_BE16(key->key_data_length);
}
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
@@ -1841,24 +1835,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if (peerkey) {
/* PeerKey 4-Way Handshake */
- peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+ peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, key, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+ key_data_len);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
- ver);
+ ver, key_data,
+ key_data_len);
}
} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
/* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
ver);
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
- extra_len, ver);
+ key_data, key_data_len,
+ ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic bit - "
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e98967c..63032b0 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -55,14 +55,14 @@ struct wpa_sm_ctx {
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capab,
- const u8 *buf, size_t len);
+ int initiator, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u8 qosinfo, const u8 *ext_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len,
const u8 *supp_oper_classes,
@@ -385,7 +385,7 @@ int wpa_tdls_init(struct wpa_sm *sm);
void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index c8d8cfc..3b3c9d0 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -442,7 +442,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -458,7 +459,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
"RSNIE");
return -1;
@@ -564,7 +566,7 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) {
+ if (aes_unwrap(sm->ptk.kek, 16, gtk_len / 8, gtk_elem + 11, gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -643,7 +645,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
return -1;
}
- if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
+ if (aes_unwrap(sm->ptk.kek, 16, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk))
+ {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -727,7 +730,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -742,14 +746,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
+ if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocResp");
return -1;
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@@ -775,7 +780,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index e20e9da..839b545 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -268,12 +268,14 @@ static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capab,
- const u8 *buf, size_t len)
+ int initiator, const u8 *buf,
+ size_t len)
{
if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code,
- peer_capab, buf, len);
+ peer_capab, initiator, buf,
+ len);
return -1;
}
@@ -291,16 +293,16 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len,
- const u8 *supp_channels, size_t supp_channels_len,
- const u8 *supp_oper_classes,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
+ size_t ext_capab_len, const u8 *supp_channels,
+ size_t supp_channels_len, const u8 *supp_oper_classes,
size_t supp_oper_classes_len)
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
aid, capability, supp_rates,
supp_rates_len, ht_capab,
- vht_capab, qosinfo,
+ vht_capab, qosinfo, wmm,
ext_capab, ext_capab_len,
supp_channels,
supp_channels_len,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 2329033..93e8cf6 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -549,7 +549,7 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
ie->ht_capabilities_len = pos[1];
} else if (*pos == WLAN_EID_VHT_AID) {
if (pos[1] >= 2)
- ie->aid = WPA_GET_LE16(pos + 2);
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
} else if (*pos == WLAN_EID_VHT_CAP) {
ie->vht_capabilities = pos + 2;
ie->vht_capabilities_len = pos[1];
diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c
index 381b7a0..141ac50 100644
--- a/src/tls/pkcs1.c
+++ b/src/tls/pkcs1.c
@@ -298,7 +298,7 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk,
hdr.payload, hdr.length);
if (hdr.length != hash_len ||
- os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash");
os_free(decrypted);
return -1;
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index f78921d..4f08e0f 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -962,7 +962,7 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_DECRYPT_ERROR);
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 8a4645b..ced28cf 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -481,7 +481,8 @@ int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
}
#endif /* CONFIG_TLSV12 */
- if (buflen != data_len || os_memcmp(decrypted, data, data_len) != 0) {
+ if (buflen != data_len ||
+ os_memcmp_const(decrypted, data, data_len) != 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
os_free(buf);
*alert = TLS_ALERT_DECRYPT_ERROR;
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index 3bec3be..0c6897a 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -456,7 +456,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
if (hlen != rl->hash_size ||
- os_memcmp(hash, out_data + plen, hlen) != 0 ||
+ os_memcmp_const(hash, out_data + plen, hlen) != 0 ||
force_mac_error) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
"received message (force_mac_error=%d)",
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index c34545e..728e137 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1135,7 +1135,7 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
verify_data, TLS_VERIFY_DATA_LEN);
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
tlsv1_server_log(conn, "Mismatch in verify_data");
return -1;
}
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 751a268..e1e4df8 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -1776,7 +1776,7 @@ skip_digest_oid:
}
if (hdr.length != hash_len ||
- os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+ os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
"with calculated tbsCertificate hash");
os_free(data);
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index a066392..d5ff5b5 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -75,7 +75,7 @@ int hs20_web_browser(const char *url)
os_memset(&data, 0, sizeof(data));
ret = os_snprintf(cmd, sizeof(cmd),
- "am start -a android.intent.action.VIEW -d '%s' "
+ "start -a android.intent.action.VIEW -d %s "
"-n com.android.browser/.BrowserActivity", url);
if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
wpa_printf(MSG_ERROR, "Too long URL");
@@ -94,7 +94,7 @@ int hs20_web_browser(const char *url)
return -1;
}
- if (system(cmd) != 0) {
+ if (os_exec("/system/bin/am", cmd, 1) != 0) {
wpa_printf(MSG_INFO, "Failed to launch Android browser");
eloop_cancel_timeout(browser_timeout, NULL, NULL);
http_server_deinit(http);
@@ -109,7 +109,7 @@ int hs20_web_browser(const char *url)
eloop_destroy();
wpa_printf(MSG_INFO, "Closing Android browser");
- if (system("input keyevent 3") != 0) {
+ if (os_exec("/system/bin/input", "keyevent 3", 1) != 0) {
wpa_printf(MSG_INFO, "Failed to inject keyevent");
}
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index 2884d34..a080e2c 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -92,7 +92,7 @@ int hs20_web_browser(const char *url)
return -1;
}
- if (system(cmd) != 0) {
+ if (os_exec("/usr/bin/x-www-browser", url, 0) != 0) {
wpa_printf(MSG_INFO, "Failed to launch browser");
eloop_cancel_timeout(browser_timeout, NULL, NULL);
http_server_deinit(http);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index eeb8f65..ce3054b 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -76,7 +76,7 @@ int hs20_web_browser(const char *url)
os_memset(&data, 0, sizeof(data));
ret = os_snprintf(cmd, sizeof(cmd),
- "am start -a android.action.MAIN "
+ "start -a android.action.MAIN "
"-c android.intent.category.LAUNCHER "
"-n w1.fi.wpadebug/.WpaWebViewActivity "
"-e w1.fi.wpadebug.URL '%s'", url);
@@ -97,7 +97,7 @@ int hs20_web_browser(const char *url)
return -1;
}
- if (system(cmd) != 0) {
+ if (os_exec("/system/bin/am", cmd, 1) != 0) {
wpa_printf(MSG_INFO, "Failed to launch wpadebug browser");
eloop_cancel_timeout(browser_timeout, NULL, NULL);
http_server_deinit(http);
@@ -112,10 +112,11 @@ int hs20_web_browser(const char *url)
eloop_destroy();
wpa_printf(MSG_INFO, "Closing Android browser");
- if (system("am start -a android.action.MAIN "
- "-c android.intent.category.LAUNCHER "
- "-n w1.fi.wpadebug/.WpaWebViewActivity "
- "-e w1.fi.wpadebug.URL FINISH") != 0) {
+ if (os_exec("/system/bin/am",
+ "start -a android.action.MAIN "
+ "-c android.intent.category.LAUNCHER "
+ "-n w1.fi.wpadebug/.WpaWebViewActivity "
+ "-e w1.fi.wpadebug.URL FINISH", 1) != 0) {
wpa_printf(MSG_INFO, "Failed to close wpadebug browser");
}
diff --git a/src/utils/common.c b/src/utils/common.c
index 7dc4797..9902004 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -362,7 +362,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
*txt++ = '\\';
*txt++ = '\\';
break;
- case '\e':
+ case '\033':
*txt++ = '\\';
*txt++ = 'e';
break;
@@ -427,7 +427,7 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
pos++;
break;
case 'e':
- buf[len++] = '\e';
+ buf[len++] = '\033';
pos++;
break;
case 'x':
@@ -827,3 +827,42 @@ void int_array_add_unique(int **res, int a)
*res = n;
}
+
+
+void str_clear_free(char *str)
+{
+ if (str) {
+ size_t len = os_strlen(str);
+ os_memset(str, 0, len);
+ os_free(str);
+ }
+}
+
+
+void bin_clear_free(void *bin, size_t len)
+{
+ if (bin) {
+ os_memset(bin, 0, len);
+ os_free(bin);
+ }
+}
+
+
+int random_mac_addr(u8 *addr)
+{
+ if (os_get_random(addr, ETH_ALEN) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
+
+
+int random_mac_addr_keep_oui(u8 *addr)
+{
+ if (os_get_random(addr + 3, 3) < 0)
+ return -1;
+ addr[0] &= 0xfe; /* unicast */
+ addr[0] |= 0x02; /* locally administered */
+ return 0;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index a85cc15..14d9ad1 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -535,6 +535,13 @@ void int_array_add_unique(int **res, int a);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+void str_clear_free(char *str);
+void bin_clear_free(void *bin, size_t len);
+
+int random_mac_addr(u8 *addr);
+int random_mac_addr_keep_oui(u8 *addr);
+
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
* networking socket uses that do not really result in a real problem and
diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c
index 3801bb8..b3a4552 100644
--- a/src/utils/ext_password_test.c
+++ b/src/utils/ext_password_test.c
@@ -36,7 +36,7 @@ static void ext_password_test_deinit(void *ctx)
{
struct ext_password_test_data *data = ctx;
- os_free(data->params);
+ str_clear_free(data->params);
os_free(data);
}
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index 07d9af0..0c18269 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -1099,7 +1099,6 @@ static int ocsp_resp_cb(SSL *s, void *arg)
certs = NULL;
}
if (ctx->peer_issuer_issuer) {
- X509 *cert;
cert = X509_dup(ctx->peer_issuer_issuer);
if (cert && !sk_X509_push(certs, cert)) {
tls_show_errors(
@@ -1178,9 +1177,10 @@ static int ocsp_resp_cb(SSL *s, void *arg)
if (status == V_OCSP_CERTSTATUS_GOOD)
return 1;
- if (status == V_OCSP_CERTSTATUS_REVOKED)
+ if (status == V_OCSP_CERTSTATUS_REVOKED) {
ctx->last_err = "Server certificate has been revoked";
return 0;
+ }
if (ctx->ocsp == MANDATORY_OCSP) {
wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
ctx->last_err = "OCSP status unknown";
@@ -1368,8 +1368,8 @@ int soap_reinit_client(struct http_ctx *ctx)
client_cert, client_key);
os_free(address);
os_free(ca_fname);
- os_free(username);
- os_free(password);
+ str_clear_free(username);
+ str_clear_free(password);
os_free(client_cert);
os_free(client_key);
return ret;
@@ -1487,8 +1487,8 @@ void http_deinit_ctx(struct http_ctx *ctx)
os_free(ctx->svc_address);
os_free(ctx->svc_ca_fname);
- os_free(ctx->svc_username);
- os_free(ctx->svc_password);
+ str_clear_free(ctx->svc_username);
+ str_clear_free(ctx->svc_password);
os_free(ctx->svc_client_cert);
os_free(ctx->svc_client_key);
diff --git a/src/utils/os.h b/src/utils/os.h
index f019e26..b9247d8 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -584,6 +584,32 @@ static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size,
*/
size_t os_strlcpy(char *dest, const char *src, size_t siz);
+/**
+ * os_memcmp_const - Constant time memory comparison
+ * @a: First buffer to compare
+ * @b: Second buffer to compare
+ * @len: Number of octets to compare
+ * Returns: 0 if buffers are equal, non-zero if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time could provide external observer information
+ * about the location of the difference in the memory buffers. The return value
+ * does not behave like os_memcmp(), i.e., os_memcmp_const() cannot be used to
+ * sort items into a defined order. Unlike os_memcmp(), execution time of
+ * os_memcmp_const() does not depend on the contents of the compared memory
+ * buffers, but only on the total compared length.
+ */
+int os_memcmp_const(const void *a, const void *b, size_t len);
+
+/**
+ * os_exec - Execute an external program
+ * @program: Path to the program
+ * @arg: Command line argument string
+ * @wait_completion: Whether to wait until the program execution completes
+ * Returns: 0 on success, -1 on error
+ */
+int os_exec(const char *program, const char *arg, int wait_completion);
+
#ifdef OS_REJECT_C_LIB_FUNCTIONS
#define malloc OS_DO_NOT_USE_malloc
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 2cb0d12..90b6688 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -463,6 +463,20 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz)
}
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
char * os_strstr(const char *haystack, const char *needle)
{
size_t len = os_strlen(needle);
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index 228c472..2649111 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -218,6 +218,11 @@ size_t os_strlcpy(char *dest, const char *src, size_t size)
}
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ return 0;
+}
+
char * os_strstr(const char *haystack, const char *needle)
{
return NULL;
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 008ec6b..523a4d0 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -9,10 +9,11 @@
#include "includes.h"
#include <time.h>
+#include <sys/wait.h>
#ifdef ANDROID
#include <sys/capability.h>
-#include <linux/prctl.h>
+#include <sys/prctl.h>
#include <private/android_filesystem_config.h>
#endif /* ANDROID */
@@ -450,6 +451,20 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz)
}
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
#ifdef WPA_TRACE
void * os_malloc(size_t size)
@@ -540,3 +555,57 @@ char * os_strdup(const char *s)
}
#endif /* WPA_TRACE */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ pid_t pid;
+ int pid_status;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ const int MAX_ARG = 30;
+ char *_program, *_arg, *pos;
+ char *argv[MAX_ARG + 1];
+ int i;
+
+ _program = os_strdup(program);
+ _arg = os_strdup(arg);
+
+ argv[0] = _program;
+
+ i = 1;
+ pos = _arg;
+ while (i < MAX_ARG && pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[i++] = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = '\0';
+ }
+ argv[i] = NULL;
+
+ execv(program, argv);
+ perror("execv");
+ os_free(_program);
+ os_free(_arg);
+ exit(0);
+ return -1;
+ }
+
+ if (wait_completion) {
+ /* wait for the child process to complete in the parent */
+ waitpid(pid, &pid_status, 0);
+ }
+
+ return 0;
+}
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 1cfa7a5..57ee132 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -244,3 +244,23 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz)
return s - src - 1;
}
+
+
+int os_memcmp_const(const void *a, const void *b, size_t len)
+{
+ const u8 *aa = a;
+ const u8 *bb = b;
+ size_t i;
+ u8 res;
+
+ for (res = 0, i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return res;
+}
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ return -1;
+}
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index ec06556..d955dc4 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -1406,6 +1406,12 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
pos += IK_LEN;
wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
+ if (end > pos) {
+ wpa_hexdump(MSG_DEBUG,
+ "SCARD: Ignore extra data in end",
+ pos, end - pos);
+ }
+
return 0;
}
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 647f6b4..68cbace 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -685,6 +685,34 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
}
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int buflen;
+ int len;
+
+ if (!wpa_msg_cb)
+ return;
+
+ va_start(ap, fmt);
+ buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "wpa_msg_global_ctrl: Failed to allocate message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_msg_cb(ctx, level, 1, buf, len);
+ os_free(buf);
+}
+
+
void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 50e8ae9..391f197 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -160,6 +160,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
#define wpa_msg(args...) do { } while (0)
#define wpa_msg_ctrl(args...) do { } while (0)
#define wpa_msg_global(args...) do { } while (0)
+#define wpa_msg_global_ctrl(args...) do { } while (0)
#define wpa_msg_no_global(args...) do { } while (0)
#define wpa_msg_register_cb(f) do { } while (0)
#define wpa_msg_register_ifname_cb(f) do { } while (0)
@@ -212,6 +213,21 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
/**
+ * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg_global(), but it sends the output only to the
+ * attached global ctrl_iface monitors. In other words, it can be used for
+ * frequent events that do not need to be sent to syslog.
+ */
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
* wpa_msg_no_global - Conditional printf for ctrl_iface monitors
* @ctx: Pointer to context data; this is the ctx variable registered
* with struct wpa_driver_ops::init()
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index 6d2d11c..2f08f37 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -413,8 +413,8 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
*/
if (httpread_debug >= 10)
wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
- h->got_body = 1;
- goto got_file;
+ h->got_body = 1;
+ goto got_file;
}
rbp = readbuf;
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 648cfd1..b0f6887 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -89,7 +89,7 @@ struct wps_data * wps_init(const struct wps_config *cfg)
if (cfg->pbc) {
/* Use special PIN '00000000' for PBC */
data->dev_pw_id = DEV_PW_PUSHBUTTON;
- os_free(data->dev_password);
+ bin_clear_free(data->dev_password, data->dev_password_len);
data->dev_password = (u8 *) os_strdup("00000000");
if (data->dev_password == NULL) {
os_free(data);
@@ -122,7 +122,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
data->new_ap_settings =
os_malloc(sizeof(*data->new_ap_settings));
if (data->new_ap_settings == NULL) {
- os_free(data->dev_password);
+ bin_clear_free(data->dev_password,
+ data->dev_password_len);
os_free(data);
return NULL;
}
@@ -173,11 +174,11 @@ void wps_deinit(struct wps_data *data)
wpabuf_free(data->dh_pubkey_e);
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
- os_free(data->dev_password);
- os_free(data->alt_dev_password);
- os_free(data->new_psk);
+ bin_clear_free(data->dev_password, data->dev_password_len);
+ bin_clear_free(data->alt_dev_password, data->alt_dev_password_len);
+ bin_clear_free(data->new_psk, data->new_psk_len);
wps_device_data_free(&data->peer_dev);
- os_free(data->new_ap_settings);
+ bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings));
dh5_free(data->dh_ctx);
os_free(data);
}
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index 5266620..eadb22f 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -41,7 +41,7 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -71,7 +71,7 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
}
hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index d072582..9f5a90c 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -175,6 +175,12 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps)
}
wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps->wps->ap && random_pool_ready() != 1) {
+ wpa_printf(MSG_INFO,
+ "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used");
+ return NULL;
+ }
+
msg = wpabuf_alloc(1000);
if (msg == NULL)
return NULL;
@@ -268,8 +274,12 @@ static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
char hex[65];
u8 psk[32];
/* Generate a random per-device PSK */
- if (random_get_bytes(psk, sizeof(psk)) < 0)
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(psk, sizeof(psk)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
psk, sizeof(psk));
wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
@@ -525,8 +535,8 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
if (wps->peer_pubkey_hash_set) {
u8 hash[WPS_HASH_LEN];
sha256_vector(1, &pk, &pk_len, hash);
- if (os_memcmp(hash, wps->peer_pubkey_hash,
- WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ if (os_memcmp_const(hash, wps->peer_pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
pk, pk_len);
@@ -605,7 +615,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
@@ -645,7 +655,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
@@ -892,7 +902,7 @@ static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
- os_free(wps->dev_password);
+ bin_clear_free(wps->dev_password, wps->dev_password_len);
wps->dev_pw_id = wps->alt_dev_pw_id;
wps->dev_password = wps->alt_dev_password;
wps->dev_password_len = wps->alt_dev_password_len;
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 8b2675e..078ff72 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -579,12 +579,15 @@ static void wps_er_parse_device_description(struct wps_er_ap *ap,
wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
ap->udn = xml_get_first_item(data, "UDN");
- wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
- pos = os_strstr(ap->udn, "uuid:");
- if (pos) {
- pos += 5;
- if (uuid_str2bin(pos, ap->uuid) < 0)
- wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
+ if (ap->udn) {
+ wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
+ pos = os_strstr(ap->udn, "uuid:");
+ if (pos) {
+ pos += 5;
+ if (uuid_str2bin(pos, ap->uuid) < 0)
+ wpa_printf(MSG_DEBUG,
+ "WPS ER: Invalid UUID in UDN");
+ }
}
ap->upc = xml_get_first_item(data, "UPC");
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b917e6b..b90cc25 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -42,7 +42,7 @@ struct wps_nfc_pw_token {
static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
{
dl_list_del(&token->list);
- os_free(token);
+ bin_clear_free(token, sizeof(*token));
}
@@ -91,7 +91,7 @@ struct wps_uuid_pin {
static void wps_free_pin(struct wps_uuid_pin *pin)
{
- os_free(pin->pin);
+ bin_clear_free(pin->pin, pin->pin_len);
os_free(pin);
}
@@ -826,7 +826,7 @@ static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
{
if (dev_pw && pin->pin &&
(dev_pw_len != pin->pin_len ||
- os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0))
+ os_memcmp_const(dev_pw, pin->pin, dev_pw_len) != 0))
continue; /* different PIN */
if (pin->wildcard_uuid) {
wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
@@ -1343,7 +1343,7 @@ static int wps_get_dev_password(struct wps_data *wps)
const u8 *pin;
size_t pin_len = 0;
- os_free(wps->dev_password);
+ bin_clear_free(wps->dev_password, wps->dev_password_len);
wps->dev_password = NULL;
if (wps->pbc) {
@@ -1640,8 +1640,12 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
!wps->wps->registrar->disable_auto_conf) {
u8 r[16];
/* Generate a random passphrase */
- if (random_get_bytes(r, sizeof(r)) < 0)
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(r, sizeof(r)) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
return -1;
+ }
os_free(wps->new_psk);
wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
if (wps->new_psk == NULL)
@@ -1674,7 +1678,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
wps->new_psk = os_malloc(wps->new_psk_len);
if (wps->new_psk == NULL)
return -1;
- if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ if (random_pool_ready() != 1 ||
+ random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
+ wpa_printf(MSG_INFO,
+ "WPS: Could not generate random PSK");
os_free(wps->new_psk);
wps->new_psk = NULL;
return -1;
@@ -2211,7 +2218,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
@@ -2251,7 +2258,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
len[3] = wpabuf_len(wps->dh_pubkey_r);
hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
- if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+ if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
"not match with the pre-committed value");
wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
@@ -2591,8 +2598,9 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
addr[0] = attr->public_key;
sha256_vector(1, addr, &attr->public_key_len, hash);
- if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash,
- WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ if (os_memcmp_const(hash,
+ wps->nfc_pw_token->pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
wpa_printf(MSG_ERROR, "WPS: Public Key hash "
"mismatch");
wps->state = SEND_M2D;
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 6fb3d4c..ae94a9f 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -227,6 +227,8 @@ void format_date(struct wpabuf *buf)
t = time(NULL);
date = gmtime(&t);
+ if (date == NULL)
+ return;
wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
&weekday_str[date->tm_wday * 4], date->tm_mday,
&month_str[date->tm_mon * 4], date->tm_year + 1900,
@@ -594,7 +596,10 @@ static struct wpabuf * build_fake_wsc_ack(void)
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
wpabuf_put_be16(msg, WPS_NONCE_LEN);
wpabuf_put(msg, WPS_NONCE_LEN);
- wps_build_wfa_ext(msg, 0, NULL, 0);
+ if (wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
return msg;
}