P2P: Add support for automatic channel selection at GO
authorAnil Gathala Sudha <Anil.Sudha@Atheros.com>
Wed, 10 Nov 2010 11:33:47 +0000 (13:33 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 10 Nov 2010 11:33:47 +0000 (13:33 +0200)
The driver wrapper may now indicate the preferred channel (e.g., based
on scan results) on both 2.4 GHz and 5 GHz bands (and an overall best
frequency). When setting up a GO, this preference information is used
to select the operating channel if configuration does not include
hardcoded channel. Similarly, this information can be used during
GO Negotiation to indicate preference for a specific channel based
on current channel conditions.

p2p_group_add command can now use special values (freq=2 and freq=5)
to indicate that the GO is to be started on the specified band.

src/drivers/driver.h
src/p2p/p2p.c
src/p2p/p2p.h
src/p2p/p2p_i.h
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index da2daaf..5bf0f52 100644 (file)
@@ -2229,7 +2229,16 @@ enum wpa_event_type {
         * resource conflicts could also trigger this for station mode
         * interfaces.
         */
-       EVENT_INTERFACE_UNAVAILABLE
+       EVENT_INTERFACE_UNAVAILABLE,
+
+       /**
+        * EVENT_BEST_CHANNEL
+        *
+        * Driver generates this event whenever it detects a better channel
+        * (e.g., based on RSSI or channel use). This information can be used
+        * to improve channel selection for a new AP/P2P group.
+        */
+       EVENT_BEST_CHANNEL
 };
 
 
@@ -2649,6 +2658,20 @@ union wpa_event_data {
                int current_noise;
                int current_txrate;
        } signal_change;
+
+       /**
+        * struct best_channel - Data for EVENT_BEST_CHANNEL events
+        * @freq_24: Best 2.4 GHz band channel frequency in MHz
+        * @freq_5: Best 5 GHz band channel frequency in MHz
+        * @freq_overall: Best channel frequency in MHz
+        *
+        * 0 can be used to indicate no preference in either band.
+        */
+       struct best_channel {
+               int freq_24;
+               int freq_5;
+               int freq_overall;
+       } best_chan;
 };
 
 /**
index 1f0d7c1..02fa35f 100644 (file)
@@ -853,14 +853,52 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
                p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
                p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
        } else {
-               p2p->op_reg_class = p2p->cfg->op_reg_class;
-               p2p->op_channel = p2p->cfg->op_channel;
+               u8 op_reg_class, op_channel;
+
+               if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
+                   p2p_supported_freq(p2p, p2p->best_freq_overall) &&
+                   p2p_freq_to_channel(p2p->cfg->country,
+                                       p2p->best_freq_overall,
+                                       &op_reg_class, &op_channel) == 0) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Select best overall channel as "
+                               "operating channel preference");
+                       p2p->op_reg_class = op_reg_class;
+                       p2p->op_channel = op_channel;
+               } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
+                          p2p_supported_freq(p2p, p2p->best_freq_5) &&
+                          p2p_freq_to_channel(p2p->cfg->country,
+                                              p2p->best_freq_5,
+                                              &op_reg_class, &op_channel) ==
+                          0) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Select best 5 GHz channel as "
+                               "operating channel preference");
+                       p2p->op_reg_class = op_reg_class;
+                       p2p->op_channel = op_channel;
+               } else if (!p2p->cfg->cfg_op_channel &&
+                          p2p->best_freq_24 > 0 &&
+                          p2p_supported_freq(p2p, p2p->best_freq_24) &&
+                          p2p_freq_to_channel(p2p->cfg->country,
+                                              p2p->best_freq_24,
+                                              &op_reg_class, &op_channel) ==
+                          0) {
+                       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+                               "P2P: Select best 2.4 GHz channel as "
+                               "operating channel preference");
+                       p2p->op_reg_class = op_reg_class;
+                       p2p->op_channel = op_channel;
+               } else {
+                       p2p->op_reg_class = p2p->cfg->op_reg_class;
+                       p2p->op_channel = p2p->cfg->op_channel;
+               }
+
                os_memcpy(&p2p->channels, &p2p->cfg->channels,
                          sizeof(struct p2p_channels));
        }
        wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
                "P2P: Own preference for operation channel: "
-               "Regulatory Class %u Channel %u%s",
+               "Operating Class %u Channel %u%s",
                p2p->op_reg_class, p2p->op_channel,
                force_freq ? " (forced)" : "");
 
@@ -3133,3 +3171,14 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
        return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
                                     buf, len, wait_time);
 }
+
+
+void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
+                          int freq_overall)
+{
+       wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d,"
+               "  5 GHz: %d,  overall: %d", freq_24, freq_5, freq_overall);
+       p2p->best_freq_24 = freq_24;
+       p2p->best_freq_5 = freq_5;
+       p2p->best_freq_overall = freq_overall;
+}
index a4e5d62..7c7f6c7 100644 (file)
@@ -171,6 +171,11 @@ struct p2p_config {
        u8 op_channel;
 
        /**
+        * cfg_op_channel - Whether op_channel is hardcoded in configuration
+        */
+       u8 cfg_op_channel;
+
+       /**
         * channels - Own supported regulatory classes and channels
         *
         * List of supposerted channels per regulatory class. The regulatory
@@ -1294,4 +1299,14 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
 
 void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
 
+/**
+ * p2p_set_best_channels - Update best channel information
+ * @p2p: P2P module context from p2p_init()
+ * @freq_24: Frequency (MHz) of best channel in 2.4 GHz band
+ * @freq_5: Frequency (MHz) of best channel in 5 GHz band
+ * @freq_overall: Frequency (MHz) of best channel overall
+ */
+void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
+                          int freq_overall);
+
 #endif /* P2P_H */
index be05a84..c31f23a 100644 (file)
@@ -383,6 +383,10 @@ struct p2p_data {
        u8 peer_filter[ETH_ALEN];
 
        int cross_connect;
+
+       int best_freq_24;
+       int best_freq_5;
+       int best_freq_overall;
 };
 
 /**
index b4e8a0d..39ac33b 100644 (file)
@@ -1876,6 +1876,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                wpas_p2p_interface_unavailable(wpa_s);
 #endif /* CONFIG_P2P */
                break;
+       case EVENT_BEST_CHANNEL:
+               wpa_printf(MSG_DEBUG, "Best channel event received (%d %d %d)",
+                          data->best_chan.freq_24, data->best_chan.freq_5,
+                          data->best_chan.freq_overall);
+               wpa_s->best_24_freq = data->best_chan.freq_24;
+               wpa_s->best_5_freq = data->best_chan.freq_5;
+               wpa_s->best_overall_freq = data->best_chan.freq_overall;
+#ifdef CONFIG_P2P
+               wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
+                                             data->best_chan.freq_5,
+                                             data->best_chan.freq_overall);
+#endif /* CONFIG_P2P */
+               break;
        default:
                wpa_printf(MSG_INFO, "Unknown event %d", event);
                break;
index eb4b238..2f6ae89 100644 (file)
@@ -2203,23 +2203,28 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                os_get_random((u8 *) &r, sizeof(r));
                p2p.channel = 1 + (r % 3) * 5;
        }
+       wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
 
        if (wpa_s->conf->p2p_oper_reg_class &&
            wpa_s->conf->p2p_oper_channel) {
                p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class;
                p2p.op_channel = wpa_s->conf->p2p_oper_channel;
+               p2p.cfg_op_channel = 1;
+               wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
+
        } else {
                p2p.op_reg_class = 81;
                /*
-                * For initial tests, pick the operation channel randomly.
-                * TODO: Use scan results (etc.) to select the best channel.
+                * Use random operation channel from (1, 6, 11) if no other
+                * preference is indicated.
                 */
                os_get_random((u8 *) &r, sizeof(r));
-               p2p.op_channel = 1 + r % 11;
+               p2p.op_channel = 1 + (r % 3) * 5;
+               p2p.cfg_op_channel = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
+                          "%d:%d", p2p.op_reg_class, p2p.op_channel);
        }
-       wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d  "
-                  "Own preferred operation channel: %d",
-                  p2p.channel, p2p.op_channel);
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
                os_memcpy(p2p.country, wpa_s->conf->country, 2);
                p2p.country[2] = 0x04;
@@ -2865,16 +2870,48 @@ static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 
        os_memset(params, 0, sizeof(*params));
        params->role_go = 1;
-       params->freq = 2412;
-       if (freq)
+       if (freq) {
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
+                          "frequency %d MHz", freq);
                params->freq = freq;
-       else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
-                wpa_s->conf->p2p_oper_channel >= 1 &&
-                wpa_s->conf->p2p_oper_channel <= 11)
+       else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
+                  wpa_s->conf->p2p_oper_channel >= 1 &&
+                  wpa_s->conf->p2p_oper_channel <= 11) {
                params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
-       else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
-                wpa_s->conf->p2p_oper_reg_class == 118)
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
+                  wpa_s->conf->p2p_oper_reg_class == 118) {
                params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
+                          "frequency %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_overall_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_overall_freq)) {
+               params->freq = wpa_s->best_overall_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_24_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_24_freq)) {
+               params->freq = wpa_s->best_24_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
+                          "channel %d MHz", params->freq);
+       } else if (wpa_s->conf->p2p_oper_channel == 0 &&
+                  wpa_s->best_5_freq > 0 &&
+                  p2p_supported_freq(wpa_s->global->p2p,
+                                     wpa_s->best_5_freq)) {
+               params->freq = wpa_s->best_5_freq;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
+                          "channel %d MHz", params->freq);
+       } else {
+               params->freq = 2412;
+               wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference "
+                          "known)", params->freq);
+       }
+
        if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
            wpa_s->assoc_freq && !freq) {
                wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
@@ -2927,6 +2964,46 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
                       int freq)
 {
        struct p2p_go_neg_results params;
+       unsigned int r;
+
+       if (freq == 2) {
+               wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+                          "band");
+               if (wpa_s->best_24_freq > 0 &&
+                   p2p_supported_freq(wpa_s->global->p2p,
+                                      wpa_s->best_24_freq)) {
+                       freq = wpa_s->best_24_freq;
+                       wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+                                  "channel: %d MHz", freq);
+               } else {
+                       os_get_random((u8 *) &r, sizeof(r));
+                       freq = 2412 + (r % 3) * 25;
+                       wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+                                  "channel: %d MHz", freq);
+               }
+       }
+
+       if (freq == 5) {
+               wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+                          "band");
+               if (wpa_s->best_5_freq > 0 &&
+                   p2p_supported_freq(wpa_s->global->p2p,
+                                      wpa_s->best_5_freq)) {
+                       freq = wpa_s->best_5_freq;
+                       wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+                                  "channel: %d MHz", freq);
+               } else {
+                       os_get_random((u8 *) &r, sizeof(r));
+                       freq = 5180 + (r % 4) * 20;
+                       if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                               wpa_printf(MSG_DEBUG, "P2P: Could not select "
+                                          "5 GHz channel for P2P group");
+                               return -1;
+                       }
+                       wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+                                  "channel: %d MHz", freq);
+               }
+       }
 
        if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
                wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
@@ -3790,3 +3867,13 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s)
        wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
        wpas_p2p_group_delete(wpa_s);
 }
+
+
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+                                  int freq_24, int freq_5, int freq_overall)
+{
+       struct p2p_data *p2p = wpa_s->global->p2p;
+       if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT))
+               return;
+       p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall);
+}
index a411c9a..d0221f2 100644 (file)
@@ -118,5 +118,7 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
 void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
 int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
 void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+                                  int freq_24, int freq_5, int freq_overall);
 
 #endif /* P2P_SUPPLICANT_H */
index 5d8e4d6..13abea6 100644 (file)
@@ -534,6 +534,11 @@ struct wpa_supplicant {
        unsigned int wps_freq;
        int wps_fragment_size;
        int auto_reconnect_disabled;
+
+        /* Channel preferences for AP/P2P GO use */
+       int best_24_freq;
+       int best_5_freq;
+       int best_overall_freq;
 };