P2P: Allow P2P client to specify preferred group channel
[mech_eap.git] / wpa_supplicant / p2p_supplicant.c
index 7d4f2bf..004cf74 100644 (file)
@@ -106,8 +106,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 
        for (i = 0; i < scan_res->num; i++) {
                struct wpa_scan_res *bss = scan_res->res[i];
+               struct os_time time_tmp_age, entry_ts;
+               time_tmp_age.sec = bss->age / 1000;
+               time_tmp_age.usec = (bss->age % 1000) * 1000;
+               os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
                if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
-                                        bss->freq, bss->age, bss->level,
+                                        bss->freq, &entry_ts, bss->level,
                                         (const u8 *) (bss + 1),
                                         bss->ie_len) > 0)
                        break;
@@ -3545,6 +3549,60 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
 }
 
 
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+                               int *force_freq, int *pref_freq,
+                               int *oper_freq)
+{
+       if (freq > 0) {
+               if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+                       wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+                                  "(%u MHz) is not supported for P2P uses",
+                                  freq);
+                       return -3;
+               }
+
+               if (*oper_freq > 0 && freq != *oper_freq &&
+                   !(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "on %u MHz while connected on another "
+                                  "channel (%u MHz)", freq, *oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "requested channel (%u MHz)", freq);
+               *force_freq = freq;
+       } else if (*oper_freq > 0 &&
+                  !p2p_supported_freq(wpa_s->global->p2p, *oper_freq)) {
+               if (!(wpa_s->drv_flags &
+                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+                                  "while connected on non-P2P supported "
+                                  "channel (%u MHz)", *oper_freq);
+                       return -2;
+               }
+               wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+                          "(%u MHz) not available for P2P - try to use "
+                          "another channel", *oper_freq);
+               *force_freq = 0;
+       } else if (*oper_freq > 0 && *pref_freq == 0 &&
+                  (wpa_s->drv_flags &
+                   WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+                          "are already using (%u MHz) on another interface",
+                          *oper_freq);
+               *pref_freq = *oper_freq;
+       } else if (*oper_freq > 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+                          "channel we are already using (%u MHz) on another "
+                          "interface", *oper_freq);
+               *force_freq = *oper_freq;
+       }
+
+       return 0;
+}
+
+
 /**
  * wpas_p2p_connect - Request P2P Group Formation to be started
  * @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -3575,7 +3633,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 {
        int force_freq = 0, pref_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
-       int ret = 0;
+       int ret = 0, res;
        enum wpa_driver_if_type iftype;
        const u8 *if_addr;
        struct wpa_ssid *ssid = NULL;
@@ -3647,59 +3705,18 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
 
        if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-           wpa_s->assoc_freq)
+           wpa_s->assoc_freq) {
                oper_freq = wpa_s->assoc_freq;
-       else {
+       else {
                oper_freq = wpa_drv_shared_freq(wpa_s);
                if (oper_freq < 0)
                        oper_freq = 0;
        }
 
-       if (freq > 0) {
-               if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
-                       wpa_printf(MSG_DEBUG, "P2P: The forced channel "
-                                  "(%u MHz) is not supported for P2P uses",
-                                  freq);
-                       return -3;
-               }
-
-               if (oper_freq > 0 && freq != oper_freq &&
-                   !(wpa_s->drv_flags &
-                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-                                  "on %u MHz while connected on another "
-                                  "channel (%u MHz)", freq, oper_freq);
-                       return -2;
-               }
-               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-                          "requested channel (%u MHz)", freq);
-               force_freq = freq;
-       } else if (oper_freq > 0 &&
-                  !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
-               if (!(wpa_s->drv_flags &
-                     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-                       wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-                                  "while connected on non-P2P supported "
-                                  "channel (%u MHz)", oper_freq);
-                       return -2;
-               }
-               wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
-                          "(%u MHz) not available for P2P - try to use "
-                          "another channel", oper_freq);
-               force_freq = 0;
-       } else if (oper_freq > 0 &&
-                  (wpa_s->drv_flags &
-                   WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-               wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
-                          "are already using (%u MHz) on another interface",
-                          oper_freq);
-               pref_freq = oper_freq;
-       } else if (oper_freq > 0) {
-               wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-                          "channel we are already using (%u MHz) on another "
-                          "interface", oper_freq);
-               force_freq = oper_freq;
-       }
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
 
        wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -4566,10 +4583,12 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
 /* Invite to reinvoke a persistent group */
 int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
-                   int ht40)
+                   int ht40, int pref_freq)
 {
        enum p2p_invite_role role;
-       u8 *bssid = NULL;
+       u8 *bssid = NULL, bssid_buf[ETH_ALEN];
+       int force_freq = 0, oper_freq = 0;
+       int res;
 
        wpa_s->p2p_persistent_go_freq = freq;
        wpa_s->p2p_go_ht40 = !!ht40;
@@ -4597,6 +4616,22 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
        }
        wpa_s->pending_invite_ssid_id = ssid->id;
 
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+           wpa_s->assoc_freq) {
+               oper_freq = wpa_s->assoc_freq;
+               if (bssid == NULL)
+                       bssid = bssid_buf;
+       } else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
+
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
                return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
                                          ssid->ssid, ssid->ssid_len,
@@ -4606,7 +4641,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return -1;
 
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-                         ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
+                         ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+                         1, pref_freq);
 }
 
 
@@ -4616,9 +4652,11 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
 {
        struct wpa_global *global = wpa_s->global;
        enum p2p_invite_role role;
-       u8 *bssid = NULL;
+       u8 *bssid = NULL, bssid_buf[ETH_ALEN];
        struct wpa_ssid *ssid;
        int persistent;
+       int force_freq = 0, oper_freq = 0, pref_freq = 0;
+       int res;
 
        wpa_s->p2p_persistent_go_freq = 0;
        wpa_s->p2p_go_ht40 = 0;
@@ -4670,9 +4708,25 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
        if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
                return -1;
 
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+           wpa_s->assoc_freq) {
+               oper_freq = wpa_s->assoc_freq;
+               if (bssid == NULL)
+                       bssid = bssid_buf;
+       } else {
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
+       }
+
+       res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq,
+                                  &oper_freq);
+       if (res)
+               return res;
+
        return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
-                         ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
-                         go_dev_addr, persistent);
+                         ssid->ssid, ssid->ssid_len, force_freq,
+                         go_dev_addr, persistent, pref_freq);
 }