P2P: Use SSID from GO Negotiation to limit WPS provisioning step
[libeap.git] / wpa_supplicant / wps_supplicant.c
index 99fcabc..55a03e2 100644 (file)
@@ -32,6 +32,8 @@
 #include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
+#include "p2p/p2p.h"
+#include "p2p_supplicant.h"
 #include "wps_supplicant.h"
 
 
@@ -240,6 +242,8 @@ static int wpa_supplicant_wps_cred(void *ctx,
                ssid->eap.phase1 = NULL;
                os_free(ssid->eap.eap_methods);
                ssid->eap.eap_methods = NULL;
+               if (!ssid->p2p_group)
+                       ssid->temporary = 0;
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
                           "received credential");
@@ -397,6 +401,9 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
        wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
        wpa_s->wps_success = 1;
        wpas_notify_wps_event_success(wpa_s);
+#ifdef CONFIG_P2P
+       wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -596,6 +603,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
                return NULL;
        wpas_notify_network_added(wpa_s, ssid);
        wpa_config_set_network_defaults(ssid);
+       ssid->temporary = 1;
        if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
            wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
            wpa_config_set(ssid, "identity", registrar ?
@@ -607,12 +615,20 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
        }
 
        if (bssid) {
+#ifndef CONFIG_P2P
                struct wpa_bss *bss;
                int count = 0;
+#endif /* CONFIG_P2P */
 
                os_memcpy(ssid->bssid, bssid, ETH_ALEN);
                ssid->bssid_set = 1;
 
+               /*
+                * Note: With P2P, the SSID may change at the time the WPS
+                * provisioning is started, so better not filter the AP based
+                * on the current SSID in the scan results.
+                */
+#ifndef CONFIG_P2P
                dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
                        if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
                                continue;
@@ -636,6 +652,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
                        ssid->ssid = NULL;
                        ssid->ssid_len = 0;
                }
+#endif /* CONFIG_P2P */
        }
 
        return ssid;
@@ -665,13 +682,26 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
 }
 
 
-int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+                      int p2p_group)
 {
        struct wpa_ssid *ssid;
        wpas_clear_wps(wpa_s);
        ssid = wpas_wps_add_network(wpa_s, 0, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
+       ssid->p2p_group = p2p_group;
+       if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+               ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
+               if (ssid->ssid) {
+                       ssid->ssid_len = wpa_s->go_params->ssid_len;
+                       os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+                                 ssid->ssid_len);
+                       wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+                                         "SSID", ssid->ssid, ssid->ssid_len);
+               }
+       }
        wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
        if (wpa_s->wps_fragment_size)
                ssid->eap.fragment_size = wpa_s->wps_fragment_size;
@@ -683,7 +713,7 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 
 
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      const char *pin)
+                      const char *pin, int p2p_group, u16 dev_pw_id)
 {
        struct wpa_ssid *ssid;
        char val[128];
@@ -693,11 +723,25 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
        ssid = wpas_wps_add_network(wpa_s, 0, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
+       ssid->p2p_group = p2p_group;
+       if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
+               ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
+               if (ssid->ssid) {
+                       ssid->ssid_len = wpa_s->go_params->ssid_len;
+                       os_memcpy(ssid->ssid, wpa_s->go_params->ssid,
+                                 ssid->ssid_len);
+                       wpa_hexdump_ascii(MSG_DEBUG, "WPS: Use specific AP "
+                                         "SSID", ssid->ssid, ssid->ssid_len);
+               }
+       }
        if (pin)
-               os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
+               os_snprintf(val, sizeof(val), "\"pin=%s dev_pw_id=%u\"",
+                           pin, dev_pw_id);
        else {
                rpin = wps_generate_pin();
-               os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
+               os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
+                           rpin, dev_pw_id);
        }
        wpa_config_set(ssid, "phase1", val, 0);
        if (wpa_s->wps_fragment_size)
@@ -751,7 +795,7 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
        if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
             wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
            wpas_wps_start_pin(wpa_s, NULL,
-                              wpabuf_head(wps->oob_conf.dev_password)) < 0)
+                              wpabuf_head(wps->oob_conf.dev_password), 0) < 0)
                        return -1;
 
        return 0;
@@ -773,6 +817,7 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
        ssid = wpas_wps_add_network(wpa_s, 1, bssid);
        if (ssid == NULL)
                return -1;
+       ssid->temporary = 1;
        pos = val;
        end = pos + sizeof(val);
        res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
@@ -1322,3 +1367,54 @@ int wpas_wps_in_progress(struct wpa_supplicant *wpa_s)
 
        return 0;
 }
+
+
+void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
+{
+       struct wps_context *wps = wpa_s->wps;
+
+       if (wps == NULL)
+               return;
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_CONFIG_METHODS) {
+               wps->config_methods = wps_config_methods_str2bin(
+                       wpa_s->conf->config_methods);
+               if ((wps->config_methods &
+                    (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) ==
+                   (WPS_CONFIG_DISPLAY | WPS_CONFIG_LABEL)) {
+                       wpa_printf(MSG_ERROR, "WPS: Both Label and Display "
+                                  "config methods are not allowed at the "
+                                  "same time");
+                       wps->config_methods &= ~WPS_CONFIG_LABEL;
+               }
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_DEVICE_TYPE) {
+               if (wpa_s->conf->device_type &&
+                   wps_dev_type_str2bin(wpa_s->conf->device_type,
+                                        wps->dev.pri_dev_type) < 0)
+                       wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+       }
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
+               wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
+
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_UUID) {
+               if (is_nil_uuid(wpa_s->conf->uuid)) {
+                       uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
+                       wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+                                   "address", wps->uuid, WPS_UUID_LEN);
+               } else
+                       os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+       }
+
+       if (wpa_s->conf->changed_parameters &
+           (CFG_CHANGED_DEVICE_NAME | CFG_CHANGED_WPS_STRING)) {
+               /* Update pointers to make sure they refer current values */
+               wps->dev.device_name = wpa_s->conf->device_name;
+               wps->dev.manufacturer = wpa_s->conf->manufacturer;
+               wps->dev.model_name = wpa_s->conf->model_name;
+               wps->dev.model_number = wpa_s->conf->model_number;
+               wps->dev.serial_number = wpa_s->conf->serial_number;
+       }
+}