@@ -62,6 +62,8 @@ extern "C" {
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+/** Notify the Userspace about the freq conflict */
+#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
@@ -2483,6 +2483,17 @@ struct wpa_driver_ops {
*/
void (*poll_client)(void *priv, const u8 *own_addr,
const u8 *addr, int qos);
+ /**
+ * switch_channel - Announce channel switch and migrate the GO to a
+ * given frequency.
+ * @priv: Private driver interface data
+ * @freq: frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to move the GO to the legacy STA channel to avoid
+ * frequency conflict in single channel concurrency.
+ */
+ int (*switch_channel)(void *priv, unsigned int freq);
};
@@ -1820,6 +1820,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->home_ca_cert);
os_free(config->home_imsi);
os_free(config->home_milenage);
+ os_free(config->prioritize);
os_free(config);
}
@@ -2569,6 +2570,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
#endif /* CONFIG_P2P */
+ { STR_RANGE(prioritize, 0, 32), CFG_CHANGED_PRIORITY },
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
{ INT(bss_expiration_age), 0 },
@@ -47,6 +47,7 @@
#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
+#define CFG_CHANGED_PRIORITY BIT(13)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -484,6 +485,14 @@ struct wpa_config {
* <Ki>:<OPc>:<SQN> format
*/
char *home_milenage;
+
+ /**
+ * prioritize - Prioritize an Interface
+ * Interface name of the interface that needs to be proritized; Useful
+ * for resolving conflicts in connection. up to 16 octets encoded in
+ * UTF-8
+ */
+ char *prioritize;
};
@@ -642,6 +642,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
config->dot11RSNAConfigSATimeout);
if (config->update_config)
fprintf(f, "update_config=%d\n", config->update_config);
+ if (config->prioritize)
+ fprintf(f, "prioritize=%s\n", config->prioritize);
#ifdef CONFIG_WPS
if (!is_nil_uuid(config->uuid)) {
char buf[40];
@@ -236,6 +236,8 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
config->ctrl_interface = wpa_config_read_reg_string(
hk, TEXT("ctrl_interface"));
+ config->prioritize = wpa_config_read_reg_string(
+ hk, TEXT("prioritize"));
#ifdef CONFIG_WPS
if (wpa_config_read_global_uuid(config, hk))
errors++;
@@ -576,6 +578,9 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
wpa_config_write_reg_dword(hk, TEXT("update_config"),
config->update_config,
0);
+ wpa_config_write_reg_dword(hk, TEXT("prioritize"),
+ config->prioritize,
+ 0);
#ifdef CONFIG_WPS
if (!is_nil_uuid(config->uuid)) {
char buf[40];
@@ -663,4 +663,11 @@ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
}
+static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (!wpa_s->driver->switch_channel)
+ return -1;
+ return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+}
#endif /* DRIVER_I_H */
@@ -67,6 +67,40 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
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);
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+{
+ struct wpa_supplicant *iface = NULL;
+
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ if((iface->p2p_group_interface) && (iface->current_ssid) &&
+ (iface->current_ssid->frequency != freq)) {
+
+ if (iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) {
+ /* Try to see whether we can move the GO. If it
+ * is not possible, remove the GO interface
+ */
+ if(wpa_drv_switch_channel(iface, freq) == 0) {
+ wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
+ iface->current_ssid->frequency = freq;
+ continue;
+ }
+ }
+
+ /* If GO cannot be moved or if the conflicting interface is a
+ * P2P Client, remove the interface depending up on the connection
+ * priority */
+ if(wpas_is_interface_prioritized(wpa_s)) {
+ /* Newly requested connection has priority over existing
+ * P2P connection. So remove the interface */
+ wpas_p2p_disconnect(iface);
+ } else if(!wpa_s->conf->prioritize) {
+ /* No priority set. Notify the application to take action */
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
@@ -2525,6 +2559,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss;
int freq;
u8 iface_addr[ETH_ALEN];
+ int shared_freq = 0;
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
@@ -2560,6 +2595,14 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
+
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+ ((shared_freq = wpa_drv_shared_freq(wpa_s)) > 0) && (shared_freq != freq)) {
+ wpa_msg(wpa_s->parent, MSG_INFO,
+ P2P_EVENT_GROUP_FORMATION_FAILURE "reason=FREQ_CONFLICT");
+ return;
+ }
+
bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
freq = bss->freq;
@@ -31,6 +31,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);
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);
@@ -1121,6 +1121,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_driver_capa capa;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
+ int freq = 0;
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1415,6 +1416,25 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
else
params.uapsd = -1;
+ /* If multichannel concurrency is not supported, check for any frequency
+ * conflict and take appropriate action.
+ */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+ ((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
+ wpa_printf(MSG_ERROR, "Shared interface with conflicting frequency found (%d != %d)"
+ , freq, params.freq);
+ if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq) < 0) {
+ /* Handling conflicts failed. Disable the current connect req and
+ * notify the userspace to take appropriate action */
+ wpa_printf(MSG_ERROR, "prioritize param not set."
+ "Notifying user space to handle the case");
+ wpa_supplicant_disable_network(wpa_s, ssid);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+ " ssid:%s bssid:"MACSTR, ssid->ssid, MAC2STR(wpa_s->pending_bssid));
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ }
+ }
+
ret = wpa_drv_associate(wpa_s, ¶ms);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -2912,3 +2932,15 @@ int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
return wpa_s->conf->ap_scan == 2 ||
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
}
+
+int wpas_is_interface_prioritized(struct wpa_supplicant *wpa_s)
+{
+ if(wpa_s->conf->prioritize &&
+ !os_strncmp(wpa_s->conf->prioritize, wpa_s->ifname, sizeof(wpa_s->ifname))) {
+ /* The given interface is prioritized */
+ wpa_printf(MSG_DEBUG, "Given interface (%s) is prioritized", wpa_s->ifname);
+ return 1;
+ } else
+ wpa_printf(MSG_DEBUG, "Interface (%s) is not prioritized" , wpa_s->ifname);
+ return 0;
+}
@@ -593,6 +593,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+int wpas_is_interface_prioritized(struct wpa_supplicant *wpa_s);
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);