Cumulative patch from commit 6e9023ea499ea9a89b0e858c85e32b455d57264c
6e9023e DFS: Allow wpa_supplicant AP mode to use non-offloaded DFS
02e42ab nl80211: Add vendor event parsing for DFS offload events
bd0f68c DFS: wpa_supplicant event processing
d7f1aa8 DFS offload: P2P changes for autonomous GO
1e2aaff DFS offload: Indicate AP-CSA-FINISHED for DFS offloaded case
c13578c DFS offload: Add main DFS handler for offloaded case
5de81d7 DFS offload: Skip user space processing for CAC operations
192ad3d Interworking: Clear SCANNING state if no match found
95d7b86 P2P: Consider 5 GHz channels also for auto GO
a51c40a P2P: Fix regression in start-GO/AP through a "fake" scan
dd5c155 eap_proxy: Callback to notify any updates from eap_proxy
9a05d98 atheros: Add a new flag for OSEN support
9feadba Remove unnecessary NULL check to make function more consistent
1772d34 P2P: Fix interface deinit for failed group interface initialization
3f9ebc4 P2P: Allow AP/GO interface to be started while P2P-in-progress
b4a9292 RADIUS client: Fix server failover on return-to-primary on error case
9836cb5 Add option to force a specific RADIUS client address to be used
1a7ed38 RADIUS client: Fix a copy-paste error in accounting server failover
de7c06e P2P: Continue find in GO-Neg-Resp-fail status corner cases
c280590 Do not add blacklist entries based on normal disconnect request cases
bdf0518 P2P: Direct P2P_CONNECT command to proper interface
44b9ea5 P2P: Do not allow scan or normal association on cfg80211 P2P Device
9542f21 Clean up p2p_find command parsing and execution
fa9f381 P2P: Allow a specific channel to be specified in P2P_FIND
eb78a8d P2P: Restore P2P_SCAN_SPECIFIC
d988ff7 hostapd: Disable VHT caps for STAs when no valid VHT MCS found
70fd828 RADIUS client: Fix previous failover change
c3dabf5 Fix merge issue with IBSS VHT support
8b2b718 Fix minor issue in HT40 max rate determination
347c55e RADIUS client: Re-try connection if socket is closed on retransmit
94b39e5 RADIUS client: Fix server connection recovery after initial failure
bbee36e Allow RADIUS server address to be replaced
efb4008 TLS: Remove placeholders for SIGN_ALG_DSA support
Change-Id: I8e5d0dfd5fddb6de2f8d8211b708c3bb6674098b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 9edbe63..53143f7 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2189,6 +2189,14 @@
os_free(bss->nas_identifier);
bss->nas_identifier = os_strdup(pos);
#ifndef CONFIG_NO_RADIUS
+ } else if (os_strcmp(buf, "radius_client_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->radius->force_client_addr = 1;
} else if (os_strcmp(buf, "auth_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
&bss->radius->auth_servers,
@@ -2200,6 +2208,15 @@
return 1;
}
} else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->auth_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->auth_server &&
os_strcmp(buf, "auth_server_port") == 0) {
bss->radius->auth_server->port = atoi(pos);
} else if (bss->radius->auth_server &&
@@ -2225,6 +2242,15 @@
return 1;
}
} else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->acct_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (bss->radius->acct_server &&
os_strcmp(buf, "acct_server_port") == 0) {
bss->radius->acct_server->port = atoi(pos);
} else if (bss->radius->acct_server &&
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index dd05c2f..9e81e9e 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -885,6 +885,12 @@
# 48 octets long.
#nas_identifier=ap.example.com
+# RADIUS client forced local IP address for the access point
+# Normally the local IP address is determined automatically based on configured
+# IP addresses, but this field can be used to force a specific address to be
+# used, e.g., when the device has multiple IP addresses.
+#radius_client_addr=127.0.0.1
+
# RADIUS authentication server
#auth_server_addr=127.0.0.1
#auth_server_port=1812
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index fc8d7ad..da6fd46 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1,7 +1,7 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -748,11 +748,19 @@
if (success) {
/* Complete iface/ap configuration */
- set_dfs_state(iface, freq, ht_enabled, chan_offset,
- chan_width, cf1, cf2,
- HOSTAPD_CHAN_DFS_AVAILABLE);
- iface->cac_started = 0;
- hostapd_setup_interface_complete(iface, 0);
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ /* Complete AP configuration for the first bring up. */
+ if (iface->state != HAPD_IFACE_ENABLED)
+ hostapd_setup_interface_complete(iface, 0);
+ else
+ iface->cac_started = 0;
+ } else {
+ set_dfs_state(iface, freq, ht_enabled, chan_offset,
+ chan_width, cf1, cf2,
+ HOSTAPD_CHAN_DFS_AVAILABLE);
+ iface->cac_started = 0;
+ hostapd_setup_interface_complete(iface, 0);
+ }
}
return 0;
@@ -934,13 +942,17 @@
{
int res;
- if (!iface->conf->ieee80211h)
- return 0;
-
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
+ if (!iface->conf->ieee80211h)
+ return 0;
+
/* mark radar frequency as invalid */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
@@ -964,6 +976,11 @@
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
/* TODO add correct implementation here */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
@@ -995,3 +1012,53 @@
res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
return res;
}
+
+
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+ "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
+ "seg1=%d cac_time=%ds",
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ iface->cac_started = 1;
+ return 0;
+}
+
+
+/*
+ * Main DFS handler for offloaded case.
+ * 2 - continue channel/AP setup for non-DFS channel
+ * 1 - continue channel/AP setup for DFS channel
+ * 0 - channel/AP setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+
+ /*
+ * If DFS has already been started, then we are being called from a
+ * callback to continue AP/channel setup. Reset the CAC start flag and
+ * return.
+ */
+ if (iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+ iface->cac_started = 0;
+ return 1;
+ }
+
+ if (ieee80211_is_dfs(iface->freq)) {
+ wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
+ __func__, iface->freq);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
+ __func__, iface->freq);
+ return 2;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index a619c55..be8c0e6 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -22,5 +22,9 @@
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2);
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
#endif /* DFS_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index c39989c..a0adc67 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -439,7 +439,7 @@
int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
- int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
+ int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
@@ -497,13 +497,18 @@
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
+ is_dfs = ieee80211_is_dfs(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);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
+ } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
}
#endif /* NEED_AP_MLME */
}
@@ -1032,6 +1037,16 @@
radar->cf1, radar->cf2);
}
+
+static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
+ hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
#endif /* NEED_AP_MLME */
@@ -1207,6 +1222,11 @@
hostapd_channel_list_updated(
hapd->iface, data->channel_list_changed.initiator);
break;
+ case EVENT_DFS_CAC_STARTED:
+ if (!data)
+ break;
+ hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
+ break;
#endif /* NEED_AP_MLME */
case EVENT_INTERFACE_ENABLED:
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index e641b12..f6019ac 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1377,6 +1377,7 @@
size_t j;
u8 *prev_addr;
int delay_apply_cfg = 0;
+ int res_dfs_offload = 0;
if (err)
goto fail;
@@ -1403,6 +1404,23 @@
goto fail;
return res;
}
+ } else {
+ /* If DFS is offloaded to the driver */
+ res_dfs_offload = hostapd_handle_dfs_offload(iface);
+ if (res_dfs_offload <= 0) {
+ if (res_dfs_offload < 0)
+ goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Proceed with AP/channel setup");
+ /*
+ * If this is a DFS channel, move to completing
+ * AP setup.
+ */
+ if (res_dfs_offload == 1)
+ goto dfs_offload;
+ /* Otherwise fall through. */
+ }
}
#endif /* NEED_AP_MLME */
@@ -1497,6 +1515,19 @@
goto fail;
}
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ !res_dfs_offload) {
+ /*
+ * If freq is DFS, and DFS is offloaded to the driver, then wait
+ * for CAC to complete.
+ */
+ wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
+ return res_dfs_offload;
+ }
+
+#ifdef NEED_AP_MLME
+dfs_offload:
+#endif /* NEED_AP_MLME */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 159693f..171538a 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -90,13 +90,55 @@
}
+static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
+ const u8 *sta_vht_capab)
+{
+ const struct ieee80211_vht_capabilities *vht_cap;
+ struct ieee80211_vht_capabilities ap_vht_cap;
+ u16 sta_rx_mcs_set, ap_tx_mcs_set;
+ int i;
+
+ if (!mode)
+ return 1;
+
+ /*
+ * Disable VHT caps for STAs for which there is not even a single
+ * allowed MCS in any supported number of streams, i.e., STA is
+ * advertising 3 (not supported) as VHT MCS rates for all supported
+ * stream cases.
+ */
+ os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
+ sizeof(ap_vht_cap.vht_supported_mcs_set));
+ vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
+
+ /* AP Tx MCS map vs. STA Rx MCS map */
+ sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
+ ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
+
+ for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
+ if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching VHT MCS found between AP TX and STA RX");
+ return 0;
+}
+
+
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
- hapd->conf->disable_11ac) {
+ hapd->conf->disable_11ac ||
+ !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
sta->vht_capabilities = NULL;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index ed8d466..aca0b73 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -826,6 +826,13 @@
}
+int ieee80211_is_dfs(int freq)
+{
+ /* TODO: this could be more accurate to better cover all domains */
+ return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+}
+
+
static int is_11b(u8 rate)
{
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 05fe32b..7f0b296 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -108,6 +108,7 @@
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+int ieee80211_is_dfs(int freq);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 350d505..f464421 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1810,7 +1810,7 @@
wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
params->assocresp_ies);
-#if defined(CONFIG_HS20) && defined(IEEE80211_PARAM_OSEN)
+#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN))
if (params->osen) {
struct wpa_bss_params bss_params;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 2dce242..2a2ef6f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4301,7 +4301,8 @@
return -1;
}
- if (nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) {
+ if (params->freq.freq &&
+ nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) {
if (old_mode != nlmode)
wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 6a7b509..b59d139 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1531,6 +1531,92 @@
}
+static void qca_nl80211_dfs_offload_radar_event(
+ struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
+{
+ union wpa_event_data data;
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: DFS offload radar vendor event received");
+
+ if (nla_parse(tb, NL80211_ATTR_MAX,
+ (struct nlattr *) msg, length, NULL))
+ return;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ]) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Error parsing WIPHY_FREQ in FS offload radar vendor event");
+ return;
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
+ data.dfs_event.freq);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, "
+ "offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
+
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unknown DFS offload radar event %d received",
+ subcmd);
+ break;
+ }
+}
+
+
static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
u32 subcmd, u8 *data, size_t len)
{
@@ -1547,6 +1633,13 @@
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
qca_nl80211_acs_select_ch(drv, data, len);
break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED:
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED:
+ qca_nl80211_dfs_offload_radar_event(drv, subcmd, data, len);
+ break;
default:
wpa_printf(MSG_DEBUG,
"nl80211: Ignore unsupported QCA vendor event %u",
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 8c4a42f..702463b 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -246,6 +246,14 @@
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+#ifdef CONFIG_EAP_PROXY
+ /**
+ * eap_proxy_cb - Callback signifying any updates from eap_proxy
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ */
+ void (*eap_proxy_cb)(void *ctx);
+#endif /* CONFIG_EAP_PROXY */
+
/**
* set_anon_id - Set or add anonymous identity
* @ctx: eapol_ctx from eap_peer_sm_init() call
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f615051..9cc234a 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1977,6 +1977,17 @@
}
+#ifdef CONFIG_EAP_PROXY
+static void eapol_sm_eap_proxy_cb(void *ctx)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_proxy_cb)
+ sm->ctx->eap_proxy_cb(sm->ctx->ctx);
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct eapol_sm *sm = ctx;
@@ -2000,6 +2011,9 @@
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
eapol_sm_notify_status,
+#ifdef CONFIG_EAP_PROXY
+ eapol_sm_eap_proxy_cb,
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_set_anon_id
};
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 03341a3..1309ff7 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -271,6 +271,14 @@
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+#ifdef CONFIG_EAP_PROXY
+ /**
+ * eap_proxy_cb - Callback signifying any updates from eap_proxy
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ */
+ void (*eap_proxy_cb)(void *ctx);
+#endif /* CONFIG_EAP_PROXY */
+
/**
* set_anon_id - Set or add anonymous identity
* @ctx: eapol_ctx from eap_peer_sm_init() call
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index d62874e..6adb3dc 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1147,7 +1147,7 @@
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_count, const char **seek)
+ u8 seek_count, const char **seek, int freq)
{
int res;
@@ -1230,6 +1230,19 @@
p2p, NULL);
switch (type) {
case P2P_FIND_START_WITH_FULL:
+ if (freq > 0) {
+ /*
+ * Start with the specified channel and then move to
+ * social channels only scans.
+ */
+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
+ P2P_SCAN_SPECIFIC, freq,
+ p2p->num_req_dev_types,
+ p2p->req_dev_types, dev_id,
+ DEV_PW_DEFAULT);
+ break;
+ }
+ /* fall through */
case P2P_FIND_PROGRESSIVE:
res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
p2p->num_req_dev_types,
@@ -3508,13 +3521,19 @@
p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
- } else if (success) {
+ return;
+ }
+
+ if (success) {
struct p2p_device *dev;
dev = p2p_get_device(p2p, addr);
if (dev &&
dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
}
+
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
+ p2p_continue_find(p2p);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index b1c89d7..2402db6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -245,6 +245,7 @@
enum p2p_scan_type {
P2P_SCAN_SOCIAL,
P2P_SCAN_FULL,
+ P2P_SCAN_SPECIFIC,
P2P_SCAN_SOCIAL_PLUS_ONE
};
@@ -545,7 +546,8 @@
* operation to be completed. Type type argument specifies which type
* of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
* social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
- * indicates that all channels are to be scanned.
+ * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC
+ * request a scan of a single channel specified by freq.
* @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels
* plus one extra channel specified by freq.
*
@@ -1129,13 +1131,17 @@
* @search_delay: Extra delay in milliseconds between search iterations
* @seek_count: Number of ASP Service Strings in the seek_string array
* @seek_string: ASP Service Strings to query for in Probe Requests
+ * @freq: Requested first scan frequency (in MHz) to modify type ==
+ * P2P_FIND_START_WITH_FULL behavior. 0 = Use normal full scan.
+ * If p2p_find is already in progress, this parameter is ignored and full
+ * scan will be executed.
* Returns: 0 on success, -1 on failure
*/
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_count, const char **seek_string);
+ u8 seek_count, const char **seek_string, int freq);
/**
* p2p_notify_scan_trigger_status - Indicate scan trigger status
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 34f5685..693f61e 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1,6 +1,6 @@
/*
* RADIUS client
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -236,6 +236,8 @@
int sock, int sock6, int auth);
static int radius_client_init_acct(struct radius_client_data *radius);
static int radius_client_init_auth(struct radius_client_data *radius);
+static void radius_client_auth_failover(struct radius_client_data *radius);
+static void radius_client_acct_failover(struct radius_client_data *radius);
static void radius_client_msg_free(struct radius_msg_list *req)
@@ -304,7 +306,7 @@
{
#ifndef CONFIG_NATIVE_WINDOWS
int _errno = errno;
- wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
+ wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
_errno == EBADF || _errno == ENETUNREACH) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -333,9 +335,18 @@
struct hostapd_radius_servers *conf = radius->conf;
int s;
struct wpabuf *buf;
+ size_t prev_num_msgs;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+ if (radius->acct_sock < 0)
+ radius_client_init_acct(radius);
+ if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
+ prev_num_msgs = radius->num_msgs;
+ radius_client_acct_failover(radius);
+ if (prev_num_msgs != radius->num_msgs)
+ return 0;
+ }
s = radius->acct_sock;
if (entry->attempts == 0)
conf->acct_server->requests++;
@@ -344,6 +355,14 @@
conf->acct_server->retransmissions++;
}
} else {
+ if (radius->auth_sock < 0)
+ radius_client_init_auth(radius);
+ if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
+ prev_num_msgs = radius->num_msgs;
+ radius_client_auth_failover(radius);
+ if (prev_num_msgs != radius->num_msgs)
+ return 0;
+ }
s = radius->auth_sock;
if (entry->attempts == 0)
conf->auth_server->requests++;
@@ -352,6 +371,11 @@
conf->auth_server->retransmissions++;
}
}
+ if (s < 0) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: No valid socket for retransmission");
+ return 1;
+ }
/* retransmit; remove entry if too many attempts */
entry->attempts++;
@@ -388,7 +412,6 @@
os_time_t first;
struct radius_msg_list *entry, *prev, *tmp;
int auth_failover = 0, acct_failover = 0;
- char abuf[50];
size_t prev_num_msgs;
int s;
@@ -453,54 +476,70 @@
(long int) (first - now.sec));
}
- if (auth_failover && conf->num_auth_servers > 1) {
- struct hostapd_radius_server *next, *old;
- old = conf->auth_server;
- hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_NOTICE,
- "No response from Authentication server "
- "%s:%d - failover",
- hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
- old->port);
+ if (auth_failover && conf->num_auth_servers > 1)
+ radius_client_auth_failover(radius);
- for (entry = radius->msgs; entry; entry = entry->next) {
- if (entry->msg_type == RADIUS_AUTH)
- old->timeouts++;
- }
+ if (acct_failover && conf->num_acct_servers > 1)
+ radius_client_acct_failover(radius);
+}
- next = old + 1;
- if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
- next = conf->auth_servers;
- conf->auth_server = next;
- radius_change_server(radius, next, old,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+
+static void radius_client_auth_failover(struct radius_client_data *radius)
+{
+ struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_server *next, *old;
+ struct radius_msg_list *entry;
+ char abuf[50];
+
+ old = conf->auth_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_NOTICE,
+ "No response from Authentication server %s:%d - failover",
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_AUTH)
+ old->timeouts++;
}
- if (acct_failover && conf->num_acct_servers > 1) {
- struct hostapd_radius_server *next, *old;
- old = conf->acct_server;
- hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_NOTICE,
- "No response from Accounting server "
- "%s:%d - failover",
- hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
- old->port);
+ next = old + 1;
+ if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
+ next = conf->auth_servers;
+ conf->auth_server = next;
+ radius_change_server(radius, next, old,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
+}
- for (entry = radius->msgs; entry; entry = entry->next) {
- if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- old->timeouts++;
- }
- next = old + 1;
- if (next > &conf->acct_servers[conf->num_acct_servers - 1])
- next = conf->acct_servers;
- conf->acct_server = next;
- radius_change_server(radius, next, old,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+static void radius_client_acct_failover(struct radius_client_data *radius)
+{
+ struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_server *next, *old;
+ struct radius_msg_list *entry;
+ char abuf[50];
+
+ old = conf->acct_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_NOTICE,
+ "No response from Accounting server %s:%d - failover",
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ old->timeouts++;
}
+
+ next = old + 1;
+ if (next > &conf->acct_servers[conf->num_acct_servers - 1])
+ next = conf->acct_servers;
+ conf->acct_server = next;
+ radius_change_server(radius, next, old,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
}
@@ -658,6 +697,9 @@
}
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
+ if (conf->acct_server && radius->acct_sock < 0)
+ radius_client_init_acct(radius);
+
if (conf->acct_server == NULL || radius->acct_sock < 0 ||
conf->acct_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
@@ -673,6 +715,9 @@
s = radius->acct_sock;
conf->acct_server->requests++;
} else {
+ if (conf->auth_server && radius->auth_sock < 0)
+ radius_client_init_auth(radius);
+
if (conf->auth_server == NULL || radius->auth_sock < 0 ||
conf->auth_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
@@ -1131,18 +1176,28 @@
conf->auth_server != conf->auth_servers) {
oserv = conf->auth_server;
conf->auth_server = conf->auth_servers;
- radius_change_server(radius, conf->auth_server, oserv,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+ if (radius_change_server(radius, conf->auth_server, oserv,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1) < 0) {
+ conf->auth_server = oserv;
+ radius_change_server(radius, oserv, conf->auth_server,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
+ }
}
if (radius->acct_sock >= 0 && conf->acct_servers &&
conf->acct_server != conf->acct_servers) {
oserv = conf->acct_server;
conf->acct_server = conf->acct_servers;
- radius_change_server(radius, conf->acct_server, oserv,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+ if (radius_change_server(radius, conf->acct_server, oserv,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0) < 0) {
+ conf->acct_server = oserv;
+ radius_change_server(radius, oserv, conf->acct_server,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
+ }
}
if (conf->retry_primary_interval)
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 839eb90..d192f44 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -432,7 +432,6 @@
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
size_t rlen, hlen, clen;
u8 hash[100], *hpos;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
pos = *msgpos;
@@ -505,21 +504,17 @@
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -532,8 +527,7 @@
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index ced28cf..dabc12a 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -366,23 +366,20 @@
{
u8 *hpos;
size_t hlen;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
struct crypto_hash *ctx;
hpos = hash;
- if (alg == SIGN_ALG_RSA) {
- ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
- if (ctx == NULL)
- return -1;
- crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
- crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
- crypto_hash_update(ctx, server_params, server_params_len);
- hlen = MD5_MAC_LEN;
- if (crypto_hash_finish(ctx, hash, &hlen) < 0)
- return -1;
- hpos += hlen;
- }
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ if (ctx == NULL)
+ return -1;
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
+ crypto_hash_update(ctx, server_params, server_params_len);
+ hlen = MD5_MAC_LEN;
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
+ return -1;
+ hpos += hlen;
ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
if (ctx == NULL)
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 310966c..0f237ba 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -775,7 +775,6 @@
u8 type;
size_t hlen;
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
u8 alert;
if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
@@ -883,21 +882,17 @@
} else {
#endif /* CONFIG_TLSV12 */
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify.md5_cert == NULL ||
- crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
- {
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify.md5_cert = NULL;
- crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
- conn->verify.sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
conn->verify.md5_cert = NULL;
hlen = SHA1_MAC_LEN;
@@ -910,8 +905,7 @@
}
conn->verify.sha1_cert = NULL;
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
+ hlen += MD5_MAC_LEN;
#ifdef CONFIG_TLSV12
}
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index 9a9ec40..4b97dad 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -1,6 +1,6 @@
/*
* utils module tests
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/bitfield.h"
#include "utils/ext_password.h"
#include "utils/trace.h"
+#include "utils/base64.h"
struct printf_test_data {
@@ -84,6 +85,15 @@
}
}
+ if (printf_decode(bin, 3, "abcde") != 2)
+ errors++;
+
+ if (printf_decode(bin, 3, "\\xa") != 1 || bin[0] != 10)
+ errors++;
+
+ if (printf_decode(bin, 3, "\\a") != 1 || bin[0] != 'a')
+ errors++;
+
if (errors) {
wpa_printf(MSG_ERROR, "%d printf test(s) failed", errors);
return -1;
@@ -167,6 +177,17 @@
bitfield_free(bf);
+ bf = bitfield_alloc(8);
+ if (bf == NULL)
+ return -1;
+ if (bitfield_get_first_zero(bf) != 0)
+ errors++;
+ for (i = 0; i < 8; i++)
+ bitfield_set(bf, i);
+ if (bitfield_get_first_zero(bf) != -1)
+ errors++;
+ bitfield_free(bf);
+
if (errors) {
wpa_printf(MSG_ERROR, "%d bitfield test(s) failed", errors);
return -1;
@@ -249,6 +270,140 @@
}
+static int base64_tests(void)
+{
+ int errors = 0;
+ unsigned char *res;
+ size_t res_len;
+
+ wpa_printf(MSG_INFO, "base64 tests");
+
+ res = base64_encode((const unsigned char *) "", ~0, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_encode((const unsigned char *) "=", 1, &res_len);
+ if (!res || res_len != 5 || res[0] != 'P' || res[1] != 'Q' ||
+ res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ errors++;
+ os_free(res);
+
+ res = base64_encode((const unsigned char *) "=", 1, NULL);
+ if (!res || res[0] != 'P' || res[1] != 'Q' ||
+ res[2] != '=' || res[3] != '=' || res[4] != '\n')
+ errors++;
+ os_free(res);
+
+ res = base64_decode((const unsigned char *) "", 0, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "a", 1, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "====", 4, &res_len);
+ if (res) {
+ errors++;
+ os_free(res);
+ }
+
+ res = base64_decode((const unsigned char *) "PQ==", 4, &res_len);
+ if (!res || res_len != 1 || res[0] != '=')
+ errors++;
+ os_free(res);
+
+ res = base64_decode((const unsigned char *) "P.Q-=!=*", 8, &res_len);
+ if (!res || res_len != 1 || res[0] != '=')
+ errors++;
+ os_free(res);
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d base64 test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int common_tests(void)
+{
+ char buf[3];
+ u8 addr[ETH_ALEN] = { 1, 2, 3, 4, 5, 6 };
+ u8 bin[3];
+ int errors = 0;
+ struct wpa_freq_range_list ranges;
+
+ wpa_printf(MSG_INFO, "common tests");
+
+ if (hwaddr_mask_txt(buf, 3, addr, addr) != -1)
+ errors++;
+
+ if (wpa_scnprintf(buf, 0, "hello") != 0 ||
+ wpa_scnprintf(buf, 3, "hello") != 2)
+ errors++;
+
+ if (wpa_snprintf_hex(buf, 0, addr, ETH_ALEN) != 0 ||
+ wpa_snprintf_hex(buf, 3, addr, ETH_ALEN) != 2)
+ errors++;
+
+ if (merge_byte_arrays(bin, 3, addr, ETH_ALEN, NULL, 0) != 3 ||
+ merge_byte_arrays(bin, 3, NULL, 0, addr, ETH_ALEN) != 3)
+ errors++;
+
+ if (dup_binstr(NULL, 0) != NULL)
+ errors++;
+
+ if (freq_range_list_includes(NULL, 0) != 0)
+ errors++;
+
+ os_memset(&ranges, 0, sizeof(ranges));
+ if (freq_range_list_parse(&ranges, "") != 0 ||
+ freq_range_list_includes(&ranges, 0) != 0 ||
+ freq_range_list_str(&ranges) != NULL)
+ errors++;
+
+ if (utf8_unescape(NULL, 0, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("a", 1, NULL, 0) != 0 ||
+ utf8_unescape("a\\", 2, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("abcde", 5, buf, sizeof(buf)) != 0 ||
+ utf8_unescape("abc", 3, buf, 3) != 3)
+ errors++;
+
+ if (utf8_unescape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+ errors++;
+
+ if (utf8_unescape("\\b", 2, buf, sizeof(buf)) != 1 || buf[0] != 'b')
+ errors++;
+
+ if (utf8_escape(NULL, 0, buf, sizeof(buf)) != 0 ||
+ utf8_escape("a", 1, NULL, 0) != 0 ||
+ utf8_escape("abcde", 5, buf, sizeof(buf)) != 0 ||
+ utf8_escape("a\\bcde", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("ab\\cde", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("abc\\de", 6, buf, sizeof(buf)) != 0 ||
+ utf8_escape("abc", 3, buf, 3) != 3)
+ errors++;
+
+ if (utf8_escape("a", 0, buf, sizeof(buf)) != 1 || buf[0] != 'a')
+ errors++;
+
+ if (errors) {
+ wpa_printf(MSG_ERROR, "%d common test(s) failed", errors);
+ return -1;
+ }
+
+ return 0;
+}
+
+
int utils_module_tests(void)
{
int ret = 0;
@@ -259,6 +414,8 @@
ext_password_tests() < 0 ||
trace_tests() < 0 ||
bitfield_tests() < 0 ||
+ base64_tests() < 0 ||
+ common_tests() < 0 ||
int_array_tests() < 0)
ret = -1;
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index a1d96fb..6a5b032 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -73,7 +73,7 @@
p2p_find [timeout in seconds] [type=<social|progressive>] \
[dev_id=<addr>] [dev_type=<device type>] \
- [delay=<search delay in ms>] [seek=<service name>]
+ [delay=<search delay in ms>] [seek=<service name>] [freq=<MHz>]
The default behavior is to run a single full scan in the beginning and
then scan only social channels. type=social will scan only social
@@ -81,7 +81,9 @@
like the default behavior, but it will scan through all the channels
progressively one channel at the time in the Search state rounds. This
will help in finding new groups or groups missed during the initial
-full scan.
+full scan. When the type parameter is not included (i.e., full scan), the
+optional freq parameter can be used to override the first scan to use only
+the specified channel after which only social channels are scanned.
The optional dev_id option can be used to specify a single P2P peer to
search for. The optional delay parameter can be used to request an extra
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f2c60e7..ea5b2b4 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -26,6 +26,7 @@
#include "ap/ieee802_1x.h"
#include "ap/wps_hostapd.h"
#include "ap/ctrl_iface_ap.h"
+#include "ap/dfs.h"
#include "wps/wps.h"
#include "common/ieee802_11_defs.h"
#include "config_ssid.h"
@@ -165,6 +166,13 @@
wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+ if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
+ conf->ieee80211h = 1;
+ conf->ieee80211d = 1;
+ conf->country[0] = wpa_s->conf->country[0];
+ conf->country[1] = wpa_s->conf->country[1];
+ }
+
#ifdef CONFIG_P2P
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
(ssid->mode == WPAS_MODE_P2P_GO ||
@@ -566,6 +574,9 @@
else
params.uapsd = -1;
+ if (ieee80211_is_dfs(params.freq.freq))
+ params.freq.freq = 0; /* set channel after CAC */
+
if (wpa_drv_associate(wpa_s, ¶ms) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
@@ -1260,3 +1271,66 @@
hapd = wpa_s->ap_iface->bss[0];
return hostapd_ctrl_iface_stop_ap(hapd);
}
+
+
+#ifdef NEED_AP_MLME
+void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return;
+ wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
+ hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return;
+ wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq);
+ hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return;
+ wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
+ hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return;
+ wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
+ hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width, radar->cf1, radar->cf2);
+}
+
+
+void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar)
+{
+ if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ return;
+ wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
+ hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq,
+ radar->ht_enabled, radar->chan_offset,
+ radar->chan_width, radar->cf1, radar->cf2);
+}
+#endif /* NEED_AP_MLME */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 6a11834..3f4151d 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -82,4 +82,15 @@
int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
+void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+void wpas_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
+ struct dfs_event *radar);
+
#endif /* AP_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index ec198b2..b4aefb6 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -209,6 +209,7 @@
wpa_s->sme.prev_bssid_set = 0;
#endif /* CONFIG_SME */
wpa_s->reassociate = 1;
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -2835,6 +2836,7 @@
#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
@@ -2881,6 +2883,7 @@
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
@@ -4508,8 +4511,9 @@
u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
unsigned int search_delay;
- const char *seek[P2P_MAX_QUERY_HASH + 1];
+ const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
u8 seek_count = 0;
+ int freq = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_INFO,
@@ -4550,27 +4554,28 @@
char *term;
term = os_strchr(pos + 1, ' ');
- seek[seek_count++] = pos + 6;
+ _seek[seek_count++] = pos + 6;
+ seek = _seek;
pos = os_strstr(pos + 6, " seek=");
if (term)
*term = '\0';
}
-
- if (!seek_count)
- return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
- _dev_type, _dev_id,
- search_delay, 0, NULL);
-
if (seek_count > P2P_MAX_QUERY_HASH) {
seek[0] = NULL;
- return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
- _dev_type, _dev_id,
- search_delay, 1, seek);
+ seek_count = 1;
+ }
+
+ pos = os_strstr(cmd, "freq=");
+ if (pos) {
+ pos += 5;
+ freq = atoi(pos);
+ if (freq <= 0)
+ return -1;
}
return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
- _dev_id, search_delay, seek_count, seek);
+ _dev_id, search_delay, seek_count, seek, freq);
}
@@ -4739,6 +4744,14 @@
int pd;
int ht40, vht;
+ if (!wpa_s->global->p2p_init_wpa_s)
+ return -1;
+ if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
+ wpa_s->global->p2p_init_wpa_s->ifname);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ }
+
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
@@ -6618,6 +6631,7 @@
wpa_supplicant_stop_countermeasures(wpa_s, NULL);
wpa_s->no_keep_alive = 0;
+ wpa_s->own_disconnect_req = 0;
os_free(wpa_s->disallow_aps_bssid);
wpa_s->disallow_aps_bssid = NULL;
@@ -8534,7 +8548,7 @@
if (wpa_supplicant_get_iface(global, iface.ifname))
return -1;
- return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+ return wpa_supplicant_add_iface(global, &iface, NULL) ? 0 : -1;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index e7c2dd8..f2e62ca 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -599,7 +599,7 @@
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- wpa_s = wpa_supplicant_add_iface(global, &iface);
+ wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
if (wpa_s) {
const char *path = wpa_s->dbus_new_path;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 24822bf..0eff763 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -131,7 +131,7 @@
wpa_s = wpa_s->p2p_dev;
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0, 0, NULL);
+ NULL, 0, 0, NULL, 0);
os_free(req_dev_types);
return reply;
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 955ea78..773ee8b 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -165,7 +165,7 @@
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- wpa_s = wpa_supplicant_add_iface(global, &iface);
+ wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
if (wpa_s) {
const char *path = wpa_s->dbus_path;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 1c46d35..94be68f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1421,6 +1421,9 @@
struct wpa_bss *selected;
struct wpa_ssid *ssid = NULL;
+ if (wpa_s->p2p_mgmt)
+ return 0; /* no normal connection on p2p_mgmt interface */
+
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
if (selected) {
@@ -2672,6 +2675,9 @@
}
#endif /* CONFIG_AP */
+ if (!locally_generated)
+ wpa_s->own_disconnect_req = 0;
+
wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
if (((reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
@@ -3301,6 +3307,29 @@
data->ch_switch.cf1,
data->ch_switch.cf2);
break;
+#ifdef NEED_AP_MLME
+ case EVENT_DFS_RADAR_DETECTED:
+ if (data)
+ wpas_event_dfs_radar_detected(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_STARTED:
+ if (data)
+ wpas_event_dfs_cac_started(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_FINISHED:
+ if (data)
+ wpas_event_dfs_cac_finished(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_CAC_ABORTED:
+ if (data)
+ wpas_event_dfs_cac_aborted(wpa_s, &data->dfs_event);
+ break;
+ case EVENT_DFS_NOP_FINISHED:
+ if (data)
+ wpas_event_dfs_cac_nop_finished(wpa_s,
+ &data->dfs_event);
+ break;
+#endif /* NEED_AP_MLME */
#endif /* CONFIG_AP */
case EVENT_RX_MGMT: {
u16 fc, stype;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 90b2991..4a39665 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -77,6 +77,7 @@
if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
@@ -915,6 +916,7 @@
if (ssid == wpa_s->current_ssid) {
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
@@ -2489,6 +2491,8 @@
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
"with matching credentials found");
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
}
if (selected) {
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 13e9769..2282747 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -322,7 +322,7 @@
exitcode = -1;
break;
}
- wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
+ wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
if (wpa_s == NULL) {
exitcode = -1;
break;
diff --git a/wpa_supplicant/main_none.c b/wpa_supplicant/main_none.c
index 010c30a..4d3caf2 100644
--- a/wpa_supplicant/main_none.c
+++ b/wpa_supplicant/main_none.c
@@ -28,7 +28,7 @@
memset(&iface, 0, sizeof(iface));
/* TODO: set interface parameters */
- if (wpa_supplicant_add_iface(global, &iface) == NULL)
+ if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL)
exitcode = -1;
if (exitcode == 0)
diff --git a/wpa_supplicant/main_winmain.c b/wpa_supplicant/main_winmain.c
index 93a68f1..e1dded0 100644
--- a/wpa_supplicant/main_winmain.c
+++ b/wpa_supplicant/main_winmain.c
@@ -61,7 +61,7 @@
exitcode = -1;
break;
}
- if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+ if (wpa_supplicant_add_iface(global, &ifaces[i], NULL) == NULL)
exitcode = -1;
}
diff --git a/wpa_supplicant/main_winsvc.c b/wpa_supplicant/main_winsvc.c
index 0b7d5ce..9950aa9 100644
--- a/wpa_supplicant/main_winsvc.c
+++ b/wpa_supplicant/main_winsvc.c
@@ -119,7 +119,7 @@
RegCloseKey(hk);
- if (wpa_supplicant_add_iface(global, &iface) == NULL) {
+ if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL) {
if (skip_on_error)
wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
"initialization failure", iface.ifname);
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 32506b6..cf3676c 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -527,7 +527,7 @@
iface.driver_param = wpa_s->conf->driver_param;
iface.ctrl_interface = wpa_s->conf->ctrl_interface;
- mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
if (!mesh_wpa_s) {
wpa_printf(MSG_ERROR,
"mesh: Failed to create new wpa_supplicant interface");
@@ -535,6 +535,5 @@
return -1;
}
mesh_wpa_s->mesh_if_created = 1;
- mesh_wpa_s->parent = wpa_s;
return 0;
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5e6646e..b200ca0 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -22,6 +22,7 @@
#include "ap/ap_drv_ops.h"
#include "ap/wps_hostapd.h"
#include "ap/p2p_hostapd.h"
+#include "ap/dfs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
@@ -377,6 +378,13 @@
break;
case P2P_SCAN_FULL:
break;
+ case P2P_SCAN_SPECIFIC:
+ params->freqs = os_calloc(2, sizeof(int));
+ if (params->freqs == NULL)
+ goto fail;
+ params->freqs[0] = freq;
+ params->freqs[1] = 0;
+ break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
params->freqs = os_calloc(ARRAY_SIZE(social_channels_freq) + 2,
sizeof(int));
@@ -1983,14 +1991,13 @@
else
iface.ctrl_interface = wpa_s->conf->ctrl_interface;
iface.driver_param = wpa_s->conf->driver_param;
- group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ group_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
if (group_wpa_s == NULL) {
wpa_printf(MSG_ERROR, "P2P: Failed to create new "
"wpa_supplicant interface");
return NULL;
}
wpa_s->pending_interface_name[0] = '\0';
- group_wpa_s->parent = wpa_s;
group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
P2P_GROUP_INTERFACE_CLIENT;
wpa_s->global->p2p_group_formation = group_wpa_s;
@@ -4662,12 +4669,11 @@
}
iface.conf_p2p_dev = NULL;
- p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
if (!p2pdev_wpa_s) {
wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
return -1;
}
- p2pdev_wpa_s->parent = wpa_s;
wpa_s->p2p_dev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0';
@@ -5922,11 +5928,22 @@
else
ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
if (!ret) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel "
- "(%u MHz) is not supported for P2P uses",
- freq);
- res = -3;
- goto exit_free;
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded
+ * to the driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to the driver",
+ freq);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: The forced channel (%u MHz) is not supported for P2P uses",
+ freq);
+ res = -3;
+ goto exit_free;
+ }
}
for (i = 0; i < num; i++) {
@@ -6297,6 +6314,17 @@
}
if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(freq)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded to the
+ * driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: "
+ "%s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded",
+ __func__, freq);
+ return freq;
+ }
wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
"(%u MHz) is not supported for P2P uses",
freq);
@@ -6334,6 +6362,24 @@
goto out;
}
+ /* try all channels in operating class 115 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 5180 + i * 20;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
+ /* try all channels in operating class 124 */
+ for (i = 0; i < 4; i++) {
+ params->freq = 5745 + i * 20;
+ if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
+ freq_included(channels, params->freq) &&
+ p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ goto out;
+ }
+
/* try social channel class 180 channel 2 */
params->freq = 58320 + 1 * 2160;
if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
@@ -6350,7 +6396,7 @@
goto out;
}
- wpa_printf(MSG_DEBUG, "P2P: No 2.4 and 60 GHz channel allowed");
+ wpa_printf(MSG_DEBUG, "P2P: No 2.4, 5, or 60 GHz channel allowed");
return -1;
out:
wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference known)",
@@ -6560,10 +6606,21 @@
return -1;
if (params.freq &&
!p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
- "(%u MHz) is not supported for P2P uses",
- params.freq);
- return -1;
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ ieee80211_is_dfs(params.freq)) {
+ /*
+ * If freq is a DFS channel and DFS is offloaded to the
+ * driver, allow P2P GO to use it.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s: The forced channel for GO (%u MHz) is DFS, and DFS is offloaded to driver",
+ __func__, params.freq);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "P2P: The selected channel for GO (%u MHz) is not supported for P2P uses",
+ params.freq);
+ return -1;
+ }
}
p2p_go_params(wpa_s->global->p2p, ¶ms);
params.persistent_group = persistent_group;
@@ -6985,7 +7042,7 @@
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_cnt, const char **seek_string)
+ u8 seek_cnt, const char **seek_string, int freq)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -6998,7 +7055,7 @@
return p2p_find(wpa_s->global->p2p, timeout, type,
num_req_dev_types, req_dev_types, dev_id,
- search_delay, seek_cnt, seek_string);
+ search_delay, seek_cnt, seek_string, freq);
}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 1cf1573..b786178 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -59,7 +59,7 @@
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
const u8 *dev_id, unsigned int search_delay,
- u8 seek_cnt, const char **seek_string);
+ u8 seek_cnt, const char **seek_string, int freq);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 30a6657..805891a 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -96,6 +96,10 @@
{
struct wpa_ssid *ssid = wpa_s->conf->ssid;
int count = 0, disabled = 0;
+
+ if (wpa_s->p2p_mgmt)
+ return 0; /* no normal network profiles on p2p_mgmt interface */
+
while (ssid) {
if (!wpas_network_disabled(wpa_s, ssid))
count++;
@@ -627,6 +631,7 @@
struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
+ int connect_without_scan = 0;
if (wpa_s->pno || wpa_s->pno_sched_pending) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
@@ -674,8 +679,20 @@
return;
}
+ ssid = NULL;
+ if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
+ wpa_s->connect_without_scan) {
+ connect_without_scan = 1;
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->connect_without_scan)
+ break;
+ }
+ }
+
p2p_in_prog = wpas_p2p_in_progress(wpa_s);
- if (p2p_in_prog && p2p_in_prog != 2) {
+ if (p2p_in_prog && p2p_in_prog != 2 &&
+ (!ssid ||
+ (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
wpa_supplicant_req_scan(wpa_s, 5, 0);
return;
@@ -692,6 +709,16 @@
wpa_s->last_scan_req = wpa_s->scan_req;
wpa_s->scan_req = NORMAL_SCAN_REQ;
+ if (connect_without_scan) {
+ wpa_s->connect_without_scan = NULL;
+ if (ssid) {
+ wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+ "without scan step");
+ wpa_supplicant_associate(wpa_s, NULL, ssid);
+ return;
+ }
+ }
+
os_memset(¶ms, 0, sizeof(params));
wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
@@ -707,21 +734,6 @@
goto scan;
}
- if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
- wpa_s->connect_without_scan) {
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
- if (ssid == wpa_s->connect_without_scan)
- break;
- }
- wpa_s->connect_without_scan = NULL;
- if (ssid) {
- wpa_printf(MSG_DEBUG, "Start a pre-selected network "
- "without scan step");
- wpa_supplicant_associate(wpa_s, NULL, ssid);
- return;
- }
- }
-
#ifdef CONFIG_P2P
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
wpa_s->go_params && !wpa_s->conf->passive_scan) {
@@ -1066,8 +1078,17 @@
*/
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
- int res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
- NULL);
+ int res;
+
+ if (wpa_s->p2p_mgmt) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
+ sec, usec);
+ return;
+ }
+
+ res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
+ NULL);
if (res == 1) {
wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
sec, usec);
@@ -1861,7 +1882,7 @@
return 81000; /* HT40 MCS4 */
if (snr < 22)
return 108000; /* HT40 MCS5 */
- if (snr < 22)
+ if (snr < 24)
return 121500; /* HT40 MCS6 */
return 135000; /* HT40 MCS7 */
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 05b785e..19fb890 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -870,6 +870,7 @@
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
@@ -1865,7 +1866,7 @@
vht_freq.vht_enabled,
freq->sec_channel_offset,
VHT_CHANWIDTH_80MHZ,
- vht80[i] + 6, 0, 0) != 0)
+ vht80[j] + 6, 0, 0) != 0)
return;
*freq = vht_freq;
@@ -2585,6 +2586,7 @@
int disconnected = 0;
if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
disconnected = 1;
@@ -3228,7 +3230,8 @@
}
-static struct wpa_supplicant * wpa_supplicant_alloc(void)
+static struct wpa_supplicant *
+wpa_supplicant_alloc(struct wpa_supplicant *parent)
{
struct wpa_supplicant *wpa_s;
@@ -3238,7 +3241,7 @@
wpa_s->scan_req = INITIAL_SCAN_REQ;
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
- wpa_s->parent = wpa_s;
+ wpa_s->parent = parent ? parent : wpa_s;
wpa_s->sched_scanning = 0;
return wpa_s;
@@ -4292,6 +4295,7 @@
* wpa_supplicant_add_iface - Add a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
* @iface: Interface configuration options
+ * @parent: Parent interface or %NULL to assign new interface as parent
* Returns: Pointer to the created interface or %NULL on failure
*
* This function is used to add new network interfaces for %wpa_supplicant.
@@ -4301,7 +4305,8 @@
* e.g., when a hotplug network adapter is inserted.
*/
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
- struct wpa_interface *iface)
+ struct wpa_interface *iface,
+ struct wpa_supplicant *parent)
{
struct wpa_supplicant *wpa_s;
struct wpa_interface t_iface;
@@ -4310,7 +4315,7 @@
if (global == NULL || iface == NULL)
return NULL;
- wpa_s = wpa_supplicant_alloc();
+ wpa_s = wpa_supplicant_alloc(parent);
if (wpa_s == NULL)
return NULL;
@@ -4792,11 +4797,17 @@
*/
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+ /*
+ * There is no point in blacklisting the AP if this event is
+ * generated based on local request to disconnect.
+ */
+ if (wpa_s->own_disconnect_req) {
+ wpa_s->own_disconnect_req = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore connection failure due to local request to disconnect");
+ return;
+ }
if (wpa_s->disconnected) {
- /*
- * There is no point in blacklisting the AP if this event is
- * generated based on local request to disconnect.
- */
wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
"indication since interface has been put into "
"disconnected state");
@@ -4966,13 +4977,16 @@
int i;
unsigned int drv_enc;
+ if (wpa_s->p2p_mgmt)
+ return 1; /* no normal network profiles on p2p_mgmt interface */
+
if (ssid == NULL)
return 1;
if (ssid->disabled)
return 1;
- if (wpa_s && wpa_s->drv_capa_known)
+ if (wpa_s->drv_capa_known)
drv_enc = wpa_s->drv_enc;
else
drv_enc = (unsigned int) -1;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7949a01..26ff216 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -915,6 +915,7 @@
unsigned int ext_eapol_frame_io:1;
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
+ unsigned int own_disconnect_req:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
@@ -1034,7 +1035,8 @@
void wpa_show_license(void);
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
- struct wpa_interface *iface);
+ struct wpa_interface *iface,
+ struct wpa_supplicant *parent);
int wpa_supplicant_remove_iface(struct wpa_global *global,
struct wpa_supplicant *wpa_s,
int terminate);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 99e7351..1bb82ba 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -842,6 +842,25 @@
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#ifdef CONFIG_EAP_PROXY
+static void wpa_supplicant_eap_proxy_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ size_t len;
+
+ wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
+ wpa_s->imsi, &len);
+ if (wpa_s->mnc_len > 0) {
+ wpa_s->imsi[len] = '\0';
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+ } else {
+ wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ }
+}
+#endif /* CONFIG_EAP_PROXY */
+
+
static void wpa_supplicant_port_cb(void *ctx, int authorized)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -947,6 +966,9 @@
ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
ctx->wps = wpa_s->wps;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
+#ifdef CONFIG_EAP_PROXY
+ ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+#endif /* CONFIG_EAP_PROXY */
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index b1266c6..eabe986 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -113,6 +113,7 @@
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
if (disabled) {
@@ -160,6 +161,7 @@
wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting "
"for external credential processing");
wpas_clear_wps(wpa_s);
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
return 1;
@@ -913,6 +915,7 @@
while (ssid) {
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
if (ssid == wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
@@ -1022,9 +1025,11 @@
{
struct wpa_ssid *ssid;
- if (wpa_s->current_ssid)
+ if (wpa_s->current_ssid) {
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
/* Mark all other networks disabled and trigger reassociation */
ssid = wpa_s->conf->ssid;
@@ -1234,6 +1239,7 @@
} else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
"deauthenticate");
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);