P2P: Add mechanism for updating P2P channel list based on driver events
[libeap.git] / wpa_supplicant / p2p_supplicant.c
index 1102f56..f57e50c 100644 (file)
@@ -445,15 +445,17 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
                char psk[65];
                wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" psk=%s go_dev_addr=" MACSTR "%s",
-                       wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+                       "%s GO ssid=\"%s\" freq=%d psk=%s go_dev_addr=" MACSTR
+                       "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+                       MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
                wpas_p2p_cross_connect_setup(wpa_s);
        } else {
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
-                       wpa_s->ifname, ssid_txt,
+                       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency,
                        ssid && ssid->passphrase ? ssid->passphrase : "",
                        MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
@@ -475,6 +477,9 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
 
        without_roc = wpa_s->pending_action_without_roc;
        wpa_s->pending_action_without_roc = 0;
+       wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
+                  "pending_action_tx=%p)",
+                  without_roc, wpa_s->pending_action_tx);
 
        if (wpa_s->pending_action_tx == NULL)
                return;
@@ -609,8 +614,9 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        struct wpa_supplicant *wpa_s = ctx;
 
        wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
-                  " src=" MACSTR " bssid=" MACSTR,
-                  freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
+                  " src=" MACSTR " bssid=" MACSTR " len=%d",
+                  freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+                  (int) len);
 
        if (wpa_s->pending_action_tx) {
                wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
@@ -618,8 +624,11 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
                wpabuf_free(wpa_s->pending_action_tx);
        }
        wpa_s->pending_action_tx = wpabuf_alloc(len);
-       if (wpa_s->pending_action_tx == NULL)
+       if (wpa_s->pending_action_tx == NULL) {
+               wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
+                          "TX buffer (len=%llu)", (unsigned long long) len);
                return -1;
+       }
        wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
        os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
        os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
@@ -627,7 +636,8 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
        wpa_s->pending_action_freq = freq;
 
        if (wpa_s->off_channel_freq == freq || freq == 0) {
-               /* Already on requested channel; send immediately */
+               wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
+                          "send Action frame immediately");
                /* TODO: Would there ever be need to extend the current
                 * duration on the channel? */
                wpa_s->pending_action_without_roc = 1;
@@ -690,11 +700,14 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
                                    struct p2p_go_neg_results *res)
 {
+       wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR,
+                  MAC2STR(res->peer_interface_addr));
+       wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID",
+                         res->ssid, res->ssid_len);
        wpa_supplicant_ap_deinit(wpa_s);
        wpas_copy_go_neg_results(wpa_s, res);
        if (res->wps_method == WPS_PBC)
-               wpas_wps_start_pbc(wpa_s, NULL /* res->peer_interface_addr */,
-                                  1);
+               wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
        else {
                u16 dev_pw_id = DEV_PW_DEFAULT;
                if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
@@ -715,10 +728,11 @@ static void p2p_go_configured(void *ctx, void *data)
        if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
                wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s GO ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
+                       "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
                        wpa_s->ifname,
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+                       ssid->frequency,
                        params->passphrase ? params->passphrase : "",
                        MAC2STR(wpa_s->parent->own_addr),
                        params->persistent_group ? " [PERSISTENT]" : "");
@@ -972,9 +986,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
        eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 
        eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
-       /* TODO: add peer Config Timeout */
-       eloop_register_timeout(15, 0, wpas_p2p_group_formation_timeout, wpa_s,
-                              NULL);
+       eloop_register_timeout(15 + res->peer_config_timeout / 100,
+                              (res->peer_config_timeout % 100) * 10000,
+                              wpas_p2p_group_formation_timeout, wpa_s, NULL);
 }
 
 
@@ -1008,7 +1022,7 @@ static int wpas_start_listen(void *ctx, unsigned int freq,
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie);
+       wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
 
        if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
                wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
@@ -1035,7 +1049,7 @@ static int wpas_start_listen(void *ctx, unsigned int freq,
 static void wpas_stop_listen(void *ctx)
 {
        struct wpa_supplicant *wpa_s = ctx;
-       if (wpa_s->off_channel_freq) {
+       if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
                wpa_drv_cancel_remain_on_channel(wpa_s);
                wpa_s->off_channel_freq = 0;
                wpa_s->roc_waiting_drv_freq = 0;
@@ -1701,6 +1715,15 @@ void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods)
        else if (config_methods & WPS_CONFIG_PUSHBUTTON)
                wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_PBC_RESP MACSTR,
                        MAC2STR(peer));
+
+       if (wpa_s->pending_pd_before_join &&
+           (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+            os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+               wpa_s->pending_pd_before_join = 0;
+               wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+                          "join-existing-group operation");
+               wpas_p2p_join_start(wpa_s);
+       }
 }
 
 
@@ -1813,7 +1836,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
                if (s) {
                        wpas_p2p_group_add_persistent(
                                wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
-               } else {
+               } else if (bssid) {
                        wpas_p2p_join(wpa_s, bssid, go_dev_addr,
                                      wpa_s->p2p_wps_method);
                }
@@ -1882,151 +1905,153 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
 }
 
 
+static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
+                                    struct p2p_channels *chan)
+{
+       int i, cla = 0;
+
+       wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
+                  "band");
+
+       /* Operating class 81 - 2.4 GHz band channels 1..13 */
+       chan->reg_class[cla].reg_class = 81;
+       chan->reg_class[cla].channels = 11;
+       for (i = 0; i < 11; i++)
+               chan->reg_class[cla].channel[i] = i + 1;
+       cla++;
+
+       wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for lower 5 GHz "
+                  "band");
+
+       /* Operating class 115 - 5 GHz, channels 36-48 */
+       chan->reg_class[cla].reg_class = 115;
+       chan->reg_class[cla].channels = 4;
+       chan->reg_class[cla].channel[0] = 36;
+       chan->reg_class[cla].channel[1] = 40;
+       chan->reg_class[cla].channel[2] = 44;
+       chan->reg_class[cla].channel[3] = 48;
+       cla++;
+
+       wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for higher 5 GHz "
+                  "band");
+
+       /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
+       chan->reg_class[cla].reg_class = 124;
+       chan->reg_class[cla].channels = 4;
+       chan->reg_class[cla].channel[0] = 149;
+       chan->reg_class[cla].channel[1] = 153;
+       chan->reg_class[cla].channel[2] = 157;
+       chan->reg_class[cla].channel[3] = 161;
+       cla++;
+
+       chan->reg_classes = cla;
+       return 0;
+}
+
+
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+                                         u16 num_modes,
+                                         enum hostapd_hw_mode mode)
+{
+       u16 i;
+
+       for (i = 0; i < num_modes; i++) {
+               if (modes[i].mode == mode)
+                       return &modes[i];
+       }
+
+       return NULL;
+}
+
+
+static int has_channel(struct hostapd_hw_modes *mode, u8 chan)
+{
+       int i;
+
+       for (i = 0; i < mode->num_channels; i++) {
+               if (mode->channels[i].chan == chan) {
+                       return !(mode->channels[i].flag &
+                                (HOSTAPD_CHAN_DISABLED |
+                                 HOSTAPD_CHAN_PASSIVE_SCAN |
+                                 HOSTAPD_CHAN_NO_IBSS |
+                                 HOSTAPD_CHAN_RADAR));
+               }
+       }
+
+       return 0;
+}
+
+
+struct p2p_oper_class_map {
+       enum hostapd_hw_mode mode;
+       u8 op_class;
+       u8 min_chan;
+       u8 max_chan;
+       u8 inc;
+};
+
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
-                                  struct p2p_config *p2p)
+                                  struct p2p_channels *chan)
 {
-       struct hostapd_hw_modes *modes;
+       struct hostapd_hw_modes *modes, *mode;
        u16 num_modes, flags;
-       int i, cla;
-       int band24 = 0, band5_low = 0, band5_high = 0;
-
-       /* TODO: more detailed selection of channels within reg_class based on
-        * driver capabilities */
+       int cla, op;
+       struct p2p_oper_class_map op_class[] = {
+               { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1 },
+               { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1 },
+               { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4 },
+               { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4 },
+#if 0 /* TODO: 40 MHz channels */
+               { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1 },
+               { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1 },
+               { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8 },
+               { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8 },
+               { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8 },
+               { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8 },
+#endif
+               { -1, 0, 0, 0, 0 }
+       };
 
        modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
        if (modes == NULL) {
                wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
                           "of all supported channels; assume dualband "
                           "support");
-               band24 = band5_low = band5_high = 1;
-       } else {
-               for (i = 0; i < num_modes; i++) {
-                       struct hostapd_hw_modes *mode;
-                       mode = &modes[i];
-                       if (mode->mode == HOSTAPD_MODE_IEEE80211G) {
-                               band24 = 1;
-                       } else if (mode->mode == HOSTAPD_MODE_IEEE80211A) {
-                               int j;
-                               for (j = 0; j < mode->num_channels; j++) {
-                                       struct hostapd_channel_data *ch;
-                                       ch = &mode->channels[j];
-                                       if (ch->chan == 36)
-                                               band5_low = 1;
-                                       else if (ch->chan == 157)
-                                               band5_high = 1;
-                               }
-                       }
-               }
+               return wpas_p2p_default_channels(wpa_s, chan);
        }
 
        cla = 0;
 
-       if (band24) {
-               wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for "
-                          "2.4 GHz band");
-
-               /* Operating class 81 - 2.4 GHz band channels 1..13 */
-               p2p->channels.reg_class[cla].reg_class = 81;
-#if 0
-               p2p->channels.reg_class[cla].channels = 13;
-               for (i = 0; i < 13; i++)
-                       p2p->channels.reg_class[cla].channel[i] = i + 1;
-#else
-               p2p->channels.reg_class[cla].channels = 11;
-               for (i = 0; i < 11; i++)
-                       p2p->channels.reg_class[cla].channel[i] = i + 1;
-#endif
-               cla++;
-
-#if 0
-               /* Operating class 82 - 2.4 GHz band channel 14 */
-               p2p->channels.reg_class[cla].reg_class = 82;
-               p2p->channels.reg_class[cla].channels = 1;
-               p2p->channels.reg_class[cla].channel[0] = 14;
-               cla++;
-#endif
-
-#if 0
-               /* Operating class 83 - 2.4 GHz band channels 1..9; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 83;
-               p2p->channels.reg_class[cla].channels = 9;
-               for (i = 0; i < 9; i++)
-                       p2p->channels.reg_class[cla].channel[i] = i + 1;
-               cla++;
-
-               /* Operating class 84 - 2.4 GHz band channels 5..13; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 84;
-               p2p->channels.reg_class[cla].channels = 9;
-               for (i = 0; i < 9; i++)
-                       p2p->channels.reg_class[cla].channel[i] = i + 5;
-               cla++;
-#endif
-       }
-
-       if (band5_low) {
-               wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for "
-                          "lower 5 GHz band");
-
-               /* Operating class 115 - 5 GHz, channels 36-48 */
-               p2p->channels.reg_class[cla].reg_class = 115;
-               p2p->channels.reg_class[cla].channels = 4;
-               p2p->channels.reg_class[cla].channel[0] = 36;
-               p2p->channels.reg_class[cla].channel[1] = 40;
-               p2p->channels.reg_class[cla].channel[2] = 44;
-               p2p->channels.reg_class[cla].channel[3] = 48;
-               cla++;
-
-#if 0
-               /* Operating class 116 - 5 GHz, channels 36,44; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 116;
-               p2p->channels.reg_class[cla].channels = 2;
-               p2p->channels.reg_class[cla].channel[0] = 36;
-               p2p->channels.reg_class[cla].channel[1] = 44;
-               cla++;
-
-               /* Operating class 117 - 5 GHz, channels 40,48; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 117;
-               p2p->channels.reg_class[cla].channels = 2;
-               p2p->channels.reg_class[cla].channel[0] = 40;
-               p2p->channels.reg_class[cla].channel[1] = 48;
-               cla++;
-#endif
-       }
+       for (op = 0; op_class[op].op_class; op++) {
+               struct p2p_oper_class_map *o = &op_class[op];
+               u8 ch;
+               struct p2p_reg_class *reg = NULL;
 
-       if (band5_high) {
-               wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for "
-                          "higher 5 GHz band");
-
-               /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
-               p2p->channels.reg_class[cla].reg_class = 124;
-               p2p->channels.reg_class[cla].channels = 4;
-               p2p->channels.reg_class[cla].channel[0] = 149;
-               p2p->channels.reg_class[cla].channel[1] = 153;
-               p2p->channels.reg_class[cla].channel[2] = 157;
-               p2p->channels.reg_class[cla].channel[3] = 161;
-               cla++;
-
-#if 0
-               /* Operating class 126 - 5 GHz, channels 149,157; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 126;
-               p2p->channels.reg_class[cla].channels = 2;
-               p2p->channels.reg_class[cla].channel[0] = 149;
-               p2p->channels.reg_class[cla].channel[1] = 157;
-               cla++;
-
-               /* Operating class 127 - 5 GHz, channels 153,161; 40 MHz */
-               p2p->channels.reg_class[cla].reg_class = 127;
-               p2p->channels.reg_class[cla].channels = 2;
-               p2p->channels.reg_class[cla].channel[0] = 153;
-               p2p->channels.reg_class[cla].channel[1] = 161;
-               cla++;
-#endif
+               mode = get_mode(modes, num_modes, o->mode);
+               if (mode == NULL)
+                       continue;
+               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+                       if (!has_channel(mode, ch))
+                               continue;
+                       if (reg == NULL) {
+                               wpa_printf(MSG_DEBUG, "P2P: Add operating "
+                                          "class %u", o->op_class);
+                               reg = &chan->reg_class[cla];
+                               cla++;
+                               reg->reg_class = o->op_class;
+                       }
+                       reg->channel[reg->channels] = ch;
+                       reg->channels++;
+               }
+               if (reg) {
+                       wpa_hexdump(MSG_DEBUG, "P2P: Channels",
+                                   reg->channel, reg->channels);
+               }
        }
 
-       p2p->channels.reg_classes = cla;
+       chan->reg_classes = cla;
 
-       if (modes)
-               ieee80211_sta_free_hw_features(modes, num_modes);
+       ieee80211_sta_free_hw_features(modes, num_modes);
 
        return 0;
 }
@@ -2138,7 +2163,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
        } else
                os_memcpy(p2p.country, "US\x04", 3);
 
-       if (wpas_p2p_setup_channels(wpa_s, &p2p)) {
+       if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
                wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
                           "channel list");
                return -1;
@@ -2179,6 +2204,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
                          p2p.ssid_postfix_len);
        }
 
+       p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+
        global->p2p = p2p_init(&p2p);
        if (global->p2p == NULL)
                return -1;
@@ -2251,6 +2278,15 @@ void wpas_p2p_deinit_global(struct wpa_global *global)
                os_free(ifname);
        }
 
+       /*
+        * Deinit GO data on any possibly remaining interface (if main
+        * interface is used as GO).
+        */
+       for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+               if (wpa_s->ap_iface)
+                       wpas_p2p_group_deinit(wpa_s);
+       }
+
        p2p_deinit(global->p2p);
        global->p2p = NULL;
 }
@@ -2299,6 +2335,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
                                   struct wpa_scan_results *scan_res)
 {
        struct wpa_bss *bss;
+       int freq;
 
        eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 
@@ -2311,14 +2348,25 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
        if (scan_res)
                wpas_p2p_scan_res_handler(wpa_s, scan_res);
 
+       freq = p2p_get_oper_freq(wpa_s->global->p2p,
+                                wpa_s->pending_join_iface_addr);
+       if (freq >= 0) {
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from P2P peer table: %d MHz", freq);
+       }
        bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
        if (bss) {
+               freq = bss->freq;
+               wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
+                          "from BSS table: %d MHz", freq);
+       }
+       if (freq > 0) {
                u16 method;
 
                wpa_printf(MSG_DEBUG, "P2P: Send Provision Discovery Request "
                           "prior to joining an existing group (GO " MACSTR
                           " freq=%u MHz)",
-                          MAC2STR(wpa_s->pending_join_dev_addr), bss->freq);
+                          MAC2STR(wpa_s->pending_join_dev_addr), freq);
                wpa_s->pending_pd_before_join = 1;
 
                switch (wpa_s->pending_join_wps_method) {
@@ -2461,6 +2509,15 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
        res.wps_method = wpa_s->pending_join_wps_method;
        wpas_start_wps_enrollee(group, &res);
 
+       /*
+        * Allow a longer timeout for join-a-running-group than normal 15
+        * second group formation timeout since the GO may not have authorized
+        * our connection yet.
+        */
+       eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
+       eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
+                              wpa_s, NULL);
+
        return 0;
 }
 
@@ -2477,14 +2534,16 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
  *     initiating Group Owner negotiation
  * @go_intent: GO Intent or -1 to use default
  * @freq: Frequency for the group or 0 for auto-selection
- * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on failure
+ * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
+ *     failure, -2 on failure due to channel not currently available,
+ *     -3 if forced channel is not supported
  */
 int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                     const char *pin, enum p2p_wps_method wps_method,
                     int persistent_group, int join, int auth, int go_intent,
                     int freq)
 {
-       int force_freq = 0;
+       int force_freq = 0, oper_freq = 0;
        u8 bssid[ETH_ALEN];
        int ret = 0;
        enum wpa_driver_if_type iftype;
@@ -2530,21 +2589,52 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
                return ret;
        }
 
-       if (freq > 0)
-               force_freq = freq;
-       else if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-                wpa_s->assoc_freq)
-               force_freq = wpa_s->assoc_freq;
+       if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+           wpa_s->assoc_freq)
+               oper_freq = wpa_s->assoc_freq;
        else {
-               force_freq = wpa_drv_shared_freq(wpa_s);
-               if (force_freq < 0)
-                       force_freq = 0;
+               oper_freq = wpa_drv_shared_freq(wpa_s);
+               if (oper_freq < 0)
+                       oper_freq = 0;
        }
 
-       if (force_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_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
                           "channel we are already using (%u MHz) on another "
-                          "interface", force_freq);
+                          "interface", oper_freq);
+               force_freq = oper_freq;
        }
 
        wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
@@ -2772,6 +2862,13 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 {
        struct p2p_go_neg_results params;
 
+       if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+               wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+                          "(%u MHz) is not supported for P2P uses",
+                          freq);
+               return -1;
+       }
+
        wpas_p2p_init_go_params(wpa_s, &params, freq);
        p2p_go_params(wpa_s->global->p2p, &params);
        params.persistent_group = persistent_group;
@@ -3220,15 +3317,16 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
                char psk[65];
                wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s client ssid=\"%s\" psk=%s go_dev_addr=" MACSTR
-                       "%s",
-                       wpa_s->ifname, ssid_txt, psk, MAC2STR(go_dev_addr),
+                       "%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
+                       MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency, psk,
+                       MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
        } else {
                wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
-                       "%s client ssid=\"%s\" passphrase=\"%s\" go_dev_addr="
-                       MACSTR "%s",
-                       wpa_s->ifname, ssid_txt,
+                       "%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
+                       "go_dev_addr=" MACSTR "%s",
+                       wpa_s->ifname, ssid_txt, ssid->frequency,
                        ssid->passphrase ? ssid->passphrase : "",
                        MAC2STR(go_dev_addr),
                        persistent ? " [PERSISTENT]" : "");
@@ -3288,6 +3386,9 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
        if (p2p == NULL)
                return;
 
+       if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+               return;
+
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_NAME)
                p2p_set_dev_name(p2p, wpa_s->conf->device_name);
 
@@ -3339,6 +3440,9 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
                                     os_strlen(wpa_s->conf->p2p_ssid_postfix) :
                                     0);
        }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_P2P_INTRA_BSS)
+               p2p_set_intra_bss_dist(p2p, wpa_s->conf->p2p_intra_bss);
 }
 
 
@@ -3482,3 +3586,34 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s)
                break;
        }
 }
+
+
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT &&
+           !wpa_s->p2p_in_provisioning)
+               return 0; /* not P2P client operation */
+
+       wpa_printf(MSG_DEBUG, "P2P: Terminate connection due to WPS PBC "
+                  "session overlap");
+       wpas_group_formation_completed(wpa_s, 0);
+       return 1;
+}
+
+
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
+{
+       struct p2p_channels chan;
+
+       if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
+               return;
+
+       os_memset(&chan, 0, sizeof(chan));
+       if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+               wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
+                          "channel list");
+               return;
+       }
+
+       p2p_update_channel_list(wpa_s->global->p2p, &chan);
+}