P2P: Handle frequency conflict in single channel concurrency case

Based on priority, remove the connection with least priority whenever
a frequency conflict is detected.

Signed-hostap: Jithu Jance <jithu@broadcom.com>
This commit is contained in:
Jithu Jance 2013-11-26 18:40:16 +05:30 committed by Jouni Malinen
parent b125c48fce
commit 8567866d75
4 changed files with 93 additions and 1 deletions

View file

@ -66,6 +66,12 @@ extern "C" {
/** 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 */

View file

@ -93,7 +93,8 @@ enum p2p_group_removal_reason {
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
};
@ -113,6 +114,7 @@ static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
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);
@ -427,6 +429,9 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
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;
@ -437,6 +442,8 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
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,
@ -3574,6 +3581,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
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 */
@ -6547,6 +6555,63 @@ static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx)
}
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;

View file

@ -29,6 +29,8 @@ void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
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);

View file

@ -1647,6 +1647,25 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
#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, &params);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "