]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Handle frequency conflict in single channel concurrency case
authorJithu Jance <jithu@broadcom.com>
Tue, 26 Nov 2013 13:10:16 +0000 (18:40 +0530)
committerJouni Malinen <j@w1.fi>
Sun, 8 Dec 2013 02:55:58 +0000 (18:55 -0800)
Based on priority, remove the connection with least priority whenever
a frequency conflict is detected.

Signed-hostap: Jithu Jance <jithu@broadcom.com>

src/common/wpa_ctrl.h
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant.c

index b43531018906360876d563e9b711305bd736a9ec..88bfb4d965f07dbbdefe04f977d66e4d53d3430e 100644 (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 */
index 6f5b81670327c1ec65b9295b9a3ab6b64f619cae..f02f05019fe1420725f0fa96be162f3bd091af6d 100644 (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;
index 785062d988de874de39cfbf0b118dd01036924a9..9630eb5b8053c4167aa7c6a8549e6b4a4f710275 100644 (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);
index f43ef1453f9252e1d398656026506d729342c1f5..e8bca8a8a1f4c4bb045f203b0f72082d3c28b476 100644 (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 "