Patchwork [RFC] P2P: Handling single channel concurrency

login
register
mail settings
Submitter Jithu Jance
Date Jan. 16, 2012, 7:11 p.m.
Message ID <6C370B347C3FE8438C9692873287D2E1195AE35D95@SJEXCHCCR01.corp.ad.broadcom.com>
Download mbox | patch
Permalink /patch/136351/
State Superseded
Headers show

Comments

Jithu Jance - Jan. 16, 2012, 7:11 p.m.
>> If this is what you meant, then
>> i guess probably we might have to define a new event which will notify the
>> application of the frequency conflict with enough data [the network id of
>> the bss in conflict so that the application can enable the network blob
>> after removing the P2P group]. Please correct me if my understanding is
>> wrong.

> This is the part I did not think about, i.e., I was more or less
> thinking of just making the command that requested connection fail.
> Though, that doesn't really work in many cases, so this type of event
> may indeed be the way to go.


I made some changes to the previously sent patch and is attached below. Kindly review the same.

A new config param "prioritize" has been added to provide the default user preference setting. If it is not used, then event is
indicated to application/above framework to take appropriate action. I also added a new event to indicate that a STATION
connection is in conflict with a P2P connection. If prioritize=<iface> is set for STA interface, then it will disconnect P2P and then
proceed with STA connection. If it is not set, then it will indicate user application of the frequency conflict.

In scenarios where a STA connection already exists and a P2P join is attempted on a different channel, I am failing the P2P connection when frequency
conflict is detected. I have appended a reason code to GROUP-FORMATION-FAILURE to indicate that this is a case of frequency conflict. I know that
changing an external event is dangerous. But was doubtful on whether to add another specific event to handle this case. so i just appended a reason code to
the existing event. Please advise whether it is better to add another event or handle it in some other way.



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

---
 src/common/wpa_ctrl.h             |    2 +
 src/drivers/driver.h              |   11 +++++++++
 wpa_supplicant/config.c           |    2 +
 wpa_supplicant/config.h           |    9 +++++++
 wpa_supplicant/config_file.c      |    2 +
 wpa_supplicant/config_winreg.c    |    5 ++++
 wpa_supplicant/driver_i.h         |    7 ++++++
 wpa_supplicant/p2p_supplicant.c   |   43 +++++++++++++++++++++++++++++++++++++
 wpa_supplicant/p2p_supplicant.h   |    2 +
 wpa_supplicant/wpa_supplicant.c   |   32 +++++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant_i.h |    1 +
 11 files changed, 116 insertions(+), 0 deletions(-)

--
1.7.4.1



- Jithu Jance

Patch

diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 6cd9de5..f31aef9 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -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 "
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d72c83b..4272ff0 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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);
 };


diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0fd1f3e..f9a642a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -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 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index f9e5043..80c255b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -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;
 };


diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index f3a7291..1329203 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -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];
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 5fb2580..b275c1d 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -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];
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index d61b3fd..1e40792 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -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 */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 8ef3553..3d21d18 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -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;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 605741d..1582a41 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -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);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 68b80b9..2d63291 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -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, &params);
        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;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3e3b23d..053f2cc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -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);