From 8567866d75fcbe031c308194d8868d9c68bd6bf2 Mon Sep 17 00:00:00 2001 From: Jithu Jance Date: Tue, 26 Nov 2013 18:40:16 +0530 Subject: [PATCH] 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 --- src/common/wpa_ctrl.h | 6 +++ wpa_supplicant/p2p_supplicant.c | 67 ++++++++++++++++++++++++++++++++- wpa_supplicant/p2p_supplicant.h | 2 + wpa_supplicant/wpa_supplicant.c | 19 ++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index b43531018..88bfb4d96 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -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 */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 6f5b81670..f02f05019 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 785062d98..9630eb5b8 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -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); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index f43ef1453..e8bca8a8a 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1647,6 +1647,25 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, 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 "