Cumulative patch from commit 075131e32e6967977da4bbfa8a7f63dbfbf86008i
075131e Android: Do not compile wpa_supplicant if not chosen
f7154ce DFS: Use channel switch when radar is detected
6c6c58d hostapd: Make hostapd_set_freq_params() public
b72f949 DFS: Allow skipping radar channels
8d1fdde nl80211/hostapd: Extend channel switch notify handling
10e694a AP: Use monotonic clock for SA query timeout
af53896 Use monotonic clock for RADIUS cache timeouts
fe52c21 Use monotonic clock for last_sae_token_key_update
100298e AP: Use monotonic time for AP list
e5c9e40 OS utils: Add os_reltime_expired()
b3493fa AP: Use monotonic time for STA connected time
ed0ebee OS utils: Provide os_reltime_age()
8567866 P2P: Handle frequency conflict in single channel concurrency case
b125c48 P2P: Add wfd_dev_info= field for device found event
e706d2d bsd: Fix compilation error for NetBSD
f757950 eap_proxy: Extend Android.mk to support additional libraries
Change-Id: I6d4f0f559f420680903d12966c7a6a87da97d61a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0dc0600..09b5f68 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -464,11 +464,11 @@
}
-static int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
- int freq, int channel, int ht_enabled,
- int vht_enabled, int sec_channel_offset,
- int vht_oper_chwidth, int center_segment0,
- int center_segment1, u32 vht_caps)
+int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps)
{
int tmp;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 1eab939..b5f6a02 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -14,6 +14,7 @@
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
+struct hostapd_freq_params;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -105,6 +106,11 @@
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
+int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps);
#include "drivers/driver.h"
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 9f02151..0dab39f 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -172,7 +172,6 @@
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
- struct os_time now;
int new_ap = 0;
int set_beacon = 0;
@@ -210,8 +209,7 @@
else
ap->ht_support = 0;
- os_get_time(&now);
- ap->last_beacon = now.sec;
+ os_get_reltime(&ap->last_beacon);
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -252,7 +250,7 @@
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
struct ap_info *ap;
int set_beacon = 0;
@@ -261,12 +259,12 @@
if (!iface->ap_list)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
- if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
- now.sec)
+ if (!os_reltime_expired(&now, &ap->last_beacon,
+ iface->conf->ap_table_expiration_time))
break;
ap_free_ap(iface, ap);
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index d0529a1..93dc0ed 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -26,7 +26,7 @@
int ht_support;
- os_time_t last_beacon;
+ struct os_reltime last_beacon;
};
struct ieee802_11_elems;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ac33068..4125fd5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -24,14 +24,13 @@
static int hostapd_get_sta_conn_time(struct sta_info *sta,
char *buf, size_t buflen)
{
- struct os_time now, age;
+ struct os_reltime age;
int len = 0, ret;
if (!sta->connected_time.sec)
return 0;
- os_get_time(&now);
- os_time_sub(&now, &sta->connected_time, &age);
+ os_reltime_age(&sta->connected_time, &age);
ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
(unsigned int) age.sec);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0a909f4..caf4092 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -44,8 +44,17 @@
}
-static int dfs_channel_available(struct hostapd_channel_data *chan)
+static int dfs_channel_available(struct hostapd_channel_data *chan,
+ int skip_radar)
{
+ /*
+ * When radar detection happens, CSA is performed. However, there's no
+ * time for CAC, so radar channels must be skipped when finding a new
+ * channel for CSA.
+ */
+ if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
+ return 0;
+
if (chan->flag & HOSTAPD_CHAN_DISABLED)
return 0;
if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
@@ -96,7 +105,8 @@
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
- int first_chan_idx, int num_chans)
+ int first_chan_idx, int num_chans,
+ int skip_radar)
{
struct hostapd_channel_data *first_chan, *chan;
int i;
@@ -112,7 +122,7 @@
if (first_chan->freq + i * 20 != chan->freq)
return 0;
- if (!dfs_channel_available(chan))
+ if (!dfs_channel_available(chan, skip_radar))
return 0;
}
@@ -129,7 +139,7 @@
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
- int idx)
+ int idx, int skip_radar)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
@@ -149,7 +159,7 @@
continue;
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans))
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
continue;
if (ret_chan && idx == channel_idx) {
@@ -322,7 +332,8 @@
dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel,
u8 *vht_oper_centr_freq_seg0_idx,
- u8 *vht_oper_centr_freq_seg1_idx)
+ u8 *vht_oper_centr_freq_seg1_idx,
+ int skip_radar)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
@@ -340,13 +351,13 @@
return NULL;
/* Get the count first */
- num_available_chandefs = dfs_find_channel(iface, NULL, 0);
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
if (num_available_chandefs == 0)
return NULL;
os_get_random((u8 *) &_rand, sizeof(_rand));
chan_idx = _rand % num_available_chandefs;
- dfs_find_channel(iface, &chan, chan_idx);
+ dfs_find_channel(iface, &chan, chan_idx, skip_radar);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@@ -518,6 +529,7 @@
{
struct hostapd_channel_data *channel;
int res, n_chans, start_chan_idx;
+ int skip_radar = 0;
iface->cac_started = 0;
@@ -555,7 +567,8 @@
int sec;
u8 cf1, cf2;
- channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2);
+ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+ skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
return -1;
@@ -614,25 +627,111 @@
}
-static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
- int err = 1;
int secondary_channel;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+ int skip_radar = 0;
+ int err = 1;
- wpa_printf(MSG_DEBUG, "%s called", __func__);
+ /* Radar detected during active CAC */
+ iface->cac_started = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx);
- if (channel) {
- wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
- channel->chan);
- wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
- "freq=%d chan=%d sec_chan=%d", channel->freq,
- channel->chan, secondary_channel);
+ &vht_oper_centr_freq_seg1_idx,
+ skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+ channel->chan);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", channel->freq,
+ channel->chan, secondary_channel);
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ iface->conf->vht_oper_centr_freq_seg0_idx =
+ vht_oper_centr_freq_seg0_idx;
+ iface->conf->vht_oper_centr_freq_seg1_idx =
+ vht_oper_centr_freq_seg1_idx;
+ err = 0;
+
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+}
+
+
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *channel;
+ int secondary_channel;
+ u8 vht_oper_centr_freq_seg0_idx;
+ u8 vht_oper_centr_freq_seg1_idx;
+ int skip_radar = 1;
+ struct csa_settings csa_settings;
+ struct hostapd_data *hapd = iface->bss[0];
+ int err = 1;
+
+ wpa_printf(MSG_DEBUG, "%s called (CAC active: %s)", __func__,
+ iface->cac_started ? "yes" : "no");
+
+ /* Check if active CAC */
+ if (iface->cac_started)
+ return hostapd_dfs_start_channel_switch_cac(iface);
+
+
+ /* Perform channel switch/CSA */
+ channel = dfs_get_valid_channel(iface, &secondary_channel,
+ &vht_oper_centr_freq_seg0_idx,
+ &vht_oper_centr_freq_seg1_idx,
+ skip_radar);
+
+ if (!channel) {
+ /* FIXME: Wait for channel(s) to become available */
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+ channel->chan);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", channel->freq,
+ channel->chan, secondary_channel);
+
+ /* Setup CSA request */
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = 5;
+ csa_settings.block_tx = 1;
+ err = hostapd_set_freq_params(&csa_settings.freq_params,
+ iface->conf->hw_mode,
+ channel->freq,
+ channel->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ vht_oper_centr_freq_seg0_idx,
+ vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ err = hostapd_switch_channel(hapd, &csa_settings);
+ if (err) {
+ wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
+ err);
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
@@ -640,29 +739,16 @@
vht_oper_centr_freq_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx =
vht_oper_centr_freq_seg1_idx;
- err = 0;
- } else {
- wpa_printf(MSG_ERROR, "No valid channel available");
- }
- if (iface->cac_started) {
- wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
- iface->cac_started = 0;
- /* FIXME: Wait for channel(s) to become available if no channel
- * has been found */
- hostapd_setup_interface_complete(iface, err);
- return err;
- }
-
- if (err) {
- /* FIXME: Wait for channel(s) to become available */
hostapd_disable_iface(iface);
- return err;
+ hostapd_enable_iface(iface);
+ return 0;
}
- wpa_printf(MSG_DEBUG, "DFS radar detected");
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
+ /* Channel configuration will be updated once CSA completes and
+ * ch_switch_notify event is received */
+
+ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
return 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 1b69ba8..b066bff 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -381,14 +381,15 @@
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
- int channel;
+ int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
- "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+ "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
+ freq, ht, offset, width, cf1, cf2);
hapd->iface->freq = freq;
@@ -400,9 +401,43 @@
return;
}
+ switch (width) {
+ case CHAN_WIDTH_80:
+ chwidth = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ chwidth = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ default:
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ switch (hapd->iface->current_mode->mode) {
+ case HOSTAPD_MODE_IEEE80211A:
+ if (cf1 > 5000)
+ seg0_idx = (cf1 - 5000) / 5;
+ if (cf2 > 5000)
+ seg1_idx = (cf2 - 5000) / 5;
+ break;
+ default:
+ seg0_idx = hostapd_hw_get_channel(hapd, cf1);
+ seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+ break;
+ }
+
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
hapd->iconf->secondary_channel = offset;
+ hapd->iconf->vht_oper_chwidth = chwidth;
+ 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) {
hostapd_cleanup_cs_params(hapd);
@@ -976,7 +1011,10 @@
break;
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 492861e..6fe2956 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1967,7 +1967,7 @@
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
- os_get_time(&sta->connected_time);
+ os_get_reltime(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index c25917d..84468de 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -241,7 +241,7 @@
#ifdef CONFIG_SAE
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
- os_time_t last_sae_token_key_update;
+ struct os_reltime last_sae_token_key_update;
#endif /* CONFIG_SAE */
};
@@ -414,7 +414,7 @@
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d553caa..e55f843 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -411,17 +411,17 @@
{
struct wpabuf *buf;
u8 *token;
- struct os_time t;
+ struct os_reltime now;
- os_get_time(&t);
- if (hapd->last_sae_token_key_update == 0 ||
- t.sec > hapd->last_sae_token_key_update + 60) {
+ os_get_reltime(&now);
+ if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
+ os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
if (random_get_bytes(hapd->sae_token_key,
sizeof(hapd->sae_token_key)) < 0)
return NULL;
wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
hapd->sae_token_key, sizeof(hapd->sae_token_key));
- hapd->last_sae_token_key_update = t.sec;
+ hapd->last_sae_token_key_update = now;
}
buf = wpabuf_alloc(SHA256_MAC_LEN);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index c311e55..56c3ce0 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -29,7 +29,7 @@
struct hostapd_cached_radius_acl {
- os_time_t timestamp;
+ struct os_reltime timestamp;
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
@@ -43,7 +43,7 @@
struct hostapd_acl_query_data {
- os_time_t timestamp;
+ struct os_reltime timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@@ -104,15 +104,16 @@
char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
for (entry = hapd->acl_cache; entry; entry = entry->next) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
continue;
- if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+ if (os_reltime_expired(&now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
@@ -265,7 +266,6 @@
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
- struct os_time t;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
@@ -305,8 +305,7 @@
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
- os_get_time(&t);
- query->timestamp = t.sec;
+ os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -338,7 +337,8 @@
#ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
+ struct os_reltime *now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
@@ -346,7 +346,8 @@
entry = hapd->acl_cache;
while (entry) {
- if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+ if (os_reltime_expired(now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@@ -367,7 +368,7 @@
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
- os_time_t now)
+ struct os_reltime *now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
@@ -375,7 +376,8 @@
entry = hapd->acl_queries;
while (entry) {
- if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+ if (os_reltime_expired(now, &entry->timestamp,
+ RADIUS_ACL_TIMEOUT)) {
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
@@ -403,11 +405,11 @@
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
- hostapd_acl_expire_cache(hapd, now.sec);
- hostapd_acl_expire_queries(hapd, now.sec);
+ os_get_reltime(&now);
+ hostapd_acl_expire_cache(hapd, &now);
+ hostapd_acl_expire_queries(hapd, &now);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
@@ -480,7 +482,6 @@
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- struct os_time t;
query = hapd->acl_queries;
prev = NULL;
@@ -515,8 +516,7 @@
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
- os_get_time(&t);
- cache->timestamp = t.sec;
+ os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 76688b5..eadaa4d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -24,13 +24,13 @@
{
u8 *pos = eid;
u32 timeout, tu;
- struct os_time now, passed;
+ struct os_reltime now, passed;
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
- os_get_time(&now);
- os_time_sub(&now, &sta->sa_query_start, &passed);
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout > tu)
timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 7874332..4465d12 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -102,7 +102,7 @@
}
if (authorized) {
- os_get_time(&sta->connected_time);
+ os_get_reltime(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 474597e..d1d8657 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -825,9 +825,9 @@
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
- struct os_time now, passed;
- os_get_time(&now);
- os_time_sub(&now, &sta->sa_query_start, &passed);
+ struct os_reltime now, passed;
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
hostapd_logger(hapd, sta->addr,
@@ -864,7 +864,7 @@
return;
if (sta->sa_query_count == 0) {
/* Starting a new SA Query procedure */
- os_get_time(&sta->sa_query_start);
+ os_get_reltime(&sta->sa_query_start);
}
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index dc74219..ea3fe40 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -113,7 +113,7 @@
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending SA Query
* transaction identifiers */
- struct os_time sa_query_start;
+ struct os_reltime sa_query_start;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_INTERWORKING
@@ -126,7 +126,7 @@
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
- struct os_time connected_time;
+ struct os_reltime connected_time;
#ifdef CONFIG_SAE
struct sae_data *sae;
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index b435310..88bfb4d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -66,6 +66,12 @@
/** RSN IBSS 4-way handshakes completed with specified peer */
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
+/** Notification of frequency conflict due to a concurrent operation.
+ *
+ * The indicated network is disabled and needs to be re-enabled before it can
+ * be used again.
+ */
+#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 3502eb8..a3602ed 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4028,11 +4028,17 @@
* @freq: Frequency of new channel in MHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
+ * @ch_width: Channel width
+ * @cf1: Center frequency 1
+ * @cf2: Center frequency 2
*/
struct ch_switch {
int freq;
int ht_enabled;
int ch_offset;
+ enum chan_width ch_width;
+ int cf1;
+ int cf2;
} ch_switch;
/**
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 45d6b19..fb6402d 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -85,8 +85,10 @@
return IEEE80211_M_HOSTAP;
if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
return IEEE80211_M_MONITOR;
+#ifdef IEEE80211_M_MBSS
if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
return IEEE80211_M_MBSS;
+#endif /* IEEE80211_M_MBSS */
}
return IEEE80211_M_STA;
}
@@ -324,7 +326,9 @@
size_t seq_len, const u8 *key, size_t key_len)
{
struct ieee80211req_key wk;
+#ifdef IEEE80211_KEY_NOREPLAY
struct bsd_driver_data *drv = priv;
+#endif /* IEEE80211_KEY_NOREPLAY */
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -380,12 +384,14 @@
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
#ifndef HOSTAPD
+#ifdef IEEE80211_KEY_NOREPLAY
/*
* Ignore replay failures in IBSS and AHDEMO mode.
*/
if (drv->opmode == IEEE80211_M_IBSS ||
drv->opmode == IEEE80211_M_AHDEMO)
wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
+#endif /* IEEE80211_KEY_NOREPLAY */
#endif /* HOSTAPD */
wk.ik_keylen = key_len;
if (seq) {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 64ab29a..42dddf0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -504,6 +504,27 @@
}
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ return CHAN_WIDTH_20_NOHT;
+ case NL80211_CHAN_WIDTH_20:
+ return CHAN_WIDTH_20;
+ case NL80211_CHAN_WIDTH_40:
+ return CHAN_WIDTH_40;
+ case NL80211_CHAN_WIDTH_80:
+ return CHAN_WIDTH_80;
+ case NL80211_CHAN_WIDTH_80P80:
+ return CHAN_WIDTH_80P80;
+ case NL80211_CHAN_WIDTH_160:
+ return CHAN_WIDTH_160;
+ }
+ return CHAN_WIDTH_UNKNOWN;
+}
+
+
static int is_ap_interface(enum nl80211_iftype nlmode)
{
return (nlmode == NL80211_IFTYPE_AP ||
@@ -1484,36 +1505,60 @@
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *freq, struct nlattr *type)
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
{
+ struct i802_bss *bss;
union wpa_event_data data;
int ht_enabled = 1;
int chan_offset = 0;
+ int ifidx;
wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
- if (!freq || !type)
+ if (!freq)
return;
- switch (nla_get_u32(type)) {
- case NL80211_CHAN_NO_HT:
- ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- chan_offset = -1;
- break;
+ ifidx = nla_get_u32(ifindex);
+ for (bss = drv->first_bss; bss; bss = bss->next)
+ if (bss->ifindex == ifidx)
+ break;
+
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
}
+ if (type) {
+ switch (nla_get_u32(type)) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+ }
+
+ os_memset(&data, 0, sizeof(data));
data.ch_switch.freq = nla_get_u32(freq);
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
- drv->first_bss->freq = data.ch_switch.freq;
+ bss->freq = data.ch_switch.freq;
wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
}
@@ -2534,8 +2579,6 @@
}
-static enum chan_width convert2width(int width);
-
static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -2702,8 +2745,13 @@
tb[NL80211_ATTR_RESP_IE]);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
- mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
- tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
break;
case NL80211_CMD_DISCONNECT:
mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -10020,27 +10068,6 @@
}
-/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
-{
- switch (width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- return CHAN_WIDTH_20_NOHT;
- case NL80211_CHAN_WIDTH_20:
- return CHAN_WIDTH_20;
- case NL80211_CHAN_WIDTH_40:
- return CHAN_WIDTH_40;
- case NL80211_CHAN_WIDTH_80:
- return CHAN_WIDTH_80;
- case NL80211_CHAN_WIDTH_80P80:
- return CHAN_WIDTH_80P80;
- case NL80211_CHAN_WIDTH_160:
- return CHAN_WIDTH_160;
- }
- return CHAN_WIDTH_UNKNOWN;
-}
-
-
static int get_channel_width(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -11288,9 +11315,11 @@
struct nlattr *beacon_csa;
int ret = -ENOBUFS;
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d)",
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
settings->cs_count, settings->block_tx,
- settings->freq_params.freq);
+ settings->freq_params.freq, settings->freq_params.bandwidth,
+ settings->freq_params.center_freq1,
+ settings->freq_params.center_freq2);
if (!drv->channel_switch_supported) {
wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
diff --git a/src/utils/os.h b/src/utils/os.h
index 77dc6e3..2e2350a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -86,6 +86,34 @@
}
+static inline void os_reltime_age(struct os_reltime *start,
+ struct os_reltime *age)
+{
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, start, age);
+}
+
+
+static inline int os_reltime_expired(struct os_reltime *now,
+ struct os_reltime *ts,
+ os_time_t timeout_secs)
+{
+ struct os_reltime age;
+
+ os_reltime_sub(now, ts, &age);
+ return (age.sec > timeout_secs) ||
+ (age.sec == timeout_secs && age.usec > 0);
+}
+
+
+static inline int os_reltime_initialized(struct os_reltime *t)
+{
+ return t->sec != 0 || t->usec != 0;
+}
+
+
/**
* os_mktime - Convert broken-down time into seconds since 1970-01-01
* @year: Four digit year
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 373a344..a030a0b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -504,7 +504,7 @@
ifdef CONFIG_EAP_PROXY
L_CFLAGS += -DCONFIG_EAP_PROXY
OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
-include eap_proxy_$(CONFIG_EAP_PROXY).mk
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
CONFIG_IEEE8021X_EAPOL=y
endif
@@ -1559,6 +1559,10 @@
LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
endif
LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifdef CONFIG_EAP_PROXY
+LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY)
+LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
+endif
ifeq ($(CONFIG_TLS), openssl)
LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
endif
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index cbe67a4..394ab30 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1085,13 +1085,13 @@
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset)
+ int offset, int width, int cf1, int cf2)
{
if (!wpa_s->ap_iface)
return;
wpa_s->assoc_freq = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+ hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
}
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 33a3d0f..c382898 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -54,7 +54,7 @@
struct csa_settings *settings);
int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
- int offset);
+ int offset, int width, int cf1, int cf2);
struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef);
#ifdef CONFIG_AP
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4d9eea8..c03dcc2 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2895,7 +2895,10 @@
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
data->ch_switch.ht_enabled,
- data->ch_switch.ch_offset);
+ data->ch_switch.ch_offset,
+ data->ch_switch.ch_width,
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
break;
#endif /* CONFIG_AP */
#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 21d99f1..e6a88e6 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -33,6 +33,7 @@
#include "offchannel.h"
#include "wps_supplicant.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
/*
@@ -92,7 +93,8 @@
P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
P2P_GROUP_REMOVAL_UNAVAILABLE,
P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
- P2P_GROUP_REMOVAL_PSK_FAILURE
+ P2P_GROUP_REMOVAL_PSK_FAILURE,
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
};
@@ -112,6 +114,7 @@
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
@@ -426,6 +429,9 @@
case P2P_GROUP_REMOVAL_PSK_FAILURE:
reason = " reason=PSK_FAILURE";
break;
+ case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
+ reason = " reason=FREQ_CONFLICT";
+ break;
default:
reason = "";
break;
@@ -436,6 +442,8 @@
wpa_s->ifname, gtype, reason);
}
+ if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout");
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
@@ -1442,16 +1450,13 @@
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
-#define WFD_DEV_INFO_SIZE 9
- char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
- os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
+ char *wfd_dev_info_hex = NULL;
+
#ifdef CONFIG_WIFI_DISPLAY
- if (info->wfd_subelems) {
- wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
- wpabuf_head(info->wfd_subelems),
- WFD_DEV_INFO_SIZE);
- }
+ wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+ WFD_SUBELEM_DEVICE_INFO);
#endif /* CONFIG_WIFI_DISPLAY */
+
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
@@ -1461,9 +1466,12 @@
sizeof(devtype)),
info->device_name, info->config_methods,
info->dev_capab, info->group_capab,
- wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
+ wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+ wfd_dev_info_hex ? wfd_dev_info_hex : "");
#endif /* CONFIG_NO_STDOUT_DEBUG */
+ os_free(wfd_dev_info_hex);
+
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
}
@@ -3579,6 +3587,7 @@
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
wpas_p2p_remove_pending_group_interface(wpa_s);
+ eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
@@ -6562,6 +6571,63 @@
}
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_supplicant *iface;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if (!iface->current_ssid ||
+ iface->current_ssid->frequency == freq ||
+ (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ !iface->current_ssid->p2p_group))
+ continue;
+
+ /* Remove the connection with least priority */
+ if (!wpas_is_p2p_prioritized(iface)) {
+ /* STA connection has priority over existing
+ * P2P connection, so remove the interface. */
+ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+ eloop_register_timeout(0, 0,
+ wpas_p2p_group_freq_conflict,
+ iface, NULL);
+ /* If connection in progress is P2P connection, do not
+ * proceed for the connection. */
+ if (wpa_s == iface)
+ return -1;
+ else
+ return 0;
+ } else {
+ /* P2P connection has priority, disable the STA network
+ */
+ wpa_supplicant_disable_network(wpa_s->global->ifaces,
+ ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+ WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+ ETH_ALEN);
+ /* If P2P connection is in progress, continue
+ * connecting...*/
+ if (wpa_s == iface)
+ return 0;
+ else
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 785062d..9630eb5 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -29,6 +29,8 @@
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
+ int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int ht40, int vht);
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index 92ca536..578199e 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -16,6 +16,9 @@
#include "wifi_display.h"
+#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
+
+
int wifi_display_init(struct wpa_global *global)
{
global->wifi_display = 1;
@@ -249,3 +252,41 @@
1,
wpabuf_len(global->wfd_subelem[subelem]) - 1);
}
+
+
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
+{
+ char *subelem = NULL;
+ const u8 *buf;
+ size_t buflen;
+ size_t i = 0;
+ u16 elen;
+
+ if (!wfd_subelems)
+ return NULL;
+
+ buf = wpabuf_head_u8(wfd_subelems);
+ if (!buf)
+ return NULL;
+
+ buflen = wpabuf_len(wfd_subelems);
+
+ while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
+ elen = WPA_GET_BE16(buf + i + 1);
+
+ if (buf[i] == id) {
+ subelem = os_zalloc(2 * elen + 1);
+ if (!subelem)
+ return NULL;
+ wpa_snprintf_hex(subelem, 2 * elen + 1,
+ buf + i +
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN,
+ elen);
+ break;
+ }
+
+ i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
+ }
+
+ return subelem;
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
index b75d4f2..7554817 100644
--- a/wpa_supplicant/wifi_display.h
+++ b/wpa_supplicant/wifi_display.h
@@ -16,5 +16,6 @@
int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
char *buf, size_t buflen);
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
#endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f43ef14..e8bca8a 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1647,6 +1647,25 @@
wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_P2P
+ /*
+ * If multi-channel concurrency is not supported, check for any
+ * frequency conflict. In case of any frequency conflict, remove the
+ * least prioritized connection.
+ */
+ if (wpa_s->num_multichan_concurrent < 2) {
+ int freq = wpa_drv_shared_freq(wpa_s);
+ if (freq > 0 && freq != params.freq) {
+ wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)",
+ freq, params.freq);
+ if (wpas_p2p_handle_frequency_conflicts(wpa_s,
+ params.freq,
+ ssid) < 0)
+ return;
+ }
+ }
+#endif /* CONFIG_P2P */
+
ret = wpa_drv_associate(wpa_s, ¶ms);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "