OSDN Git Service

wpa_supplicant: Update to 07-Jul-2012 TOT
[android-x86/external-wpa_supplicant_8.git] / wpa_supplicant / wps_supplicant.c
index 4965439..7356d1a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "common.h"
 #include "eloop.h"
 #include "uuid.h"
+#include "crypto/random.h"
 #include "crypto/dh_group5.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
@@ -20,6 +21,7 @@
 #include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
+#include "wps/wps_attr_parse.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
@@ -263,6 +265,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
                ssid->eap.eap_methods = NULL;
                if (!ssid->p2p_group)
                        ssid->temporary = 0;
+               ssid->bssid_set = 0;
        } else {
                wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
                           "received credential");
@@ -919,7 +922,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
        }
 #endif /* CONFIG_AP */
 
-       if (wpa_s->wpa_state == WPA_SCANNING) {
+       if (wpa_s->wpa_state == WPA_SCANNING ||
+           wpa_s->wpa_state == WPA_DISCONNECTED) {
                wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
                wpa_supplicant_cancel_scan(wpa_s);
                wpas_clear_wps(wpa_s);
@@ -1113,8 +1117,10 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
                while (first && first->next)
                        first = first->next;
                if (first && first != wpa_s) {
-                       os_memcpy(wps->uuid, wpa_s->global->ifaces->wps->uuid,
-                                 WPS_UUID_LEN);
+                       if (wps != wpa_s->global->ifaces->wps)
+                               os_memcpy(wps->uuid,
+                                         wpa_s->global->ifaces->wps->uuid,
+                                         WPS_UUID_LEN);
                        wpa_hexdump(MSG_DEBUG, "WPS: UUID from the first "
                                    "interface", wps->uuid, WPS_UUID_LEN);
                } else {
@@ -1130,6 +1136,23 @@ static void wpas_wps_set_uuid(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s,
+                                      struct wps_context *wps)
+{
+       wpabuf_free(wps->dev.vendor_ext_m1);
+       wps->dev.vendor_ext_m1 = NULL;
+
+       if (wpa_s->conf->wps_vendor_ext_m1) {
+               wps->dev.vendor_ext_m1 =
+                       wpabuf_dup(wpa_s->conf->wps_vendor_ext_m1);
+               if (!wps->dev.vendor_ext_m1) {
+                       wpa_printf(MSG_ERROR, "WPS: Cannot "
+                                  "allocate memory for vendor_ext_m1");
+               }
+       }
+}
+
+
 int wpas_wps_init(struct wpa_supplicant *wpa_s)
 {
        struct wps_context *wps;
@@ -1168,6 +1191,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
        os_memcpy(wps->dev.sec_dev_type, wpa_s->conf->sec_device_type,
                  WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
 
+       wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
        wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
        modes = wpa_s->hw.modes;
        if (modes) {
@@ -1228,6 +1253,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
        wpabuf_free(wpa_s->wps->dh_privkey);
        wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
        wpabuf_free(wpa_s->wps->oob_conf.dev_password);
+       wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
        os_free(wpa_s->wps->network_key);
        os_free(wpa_s->wps);
        wpa_s->wps = NULL;
@@ -1648,6 +1674,34 @@ int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
 }
 
 
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+                                            int ndef, const char *uuid)
+{
+       struct wpabuf *ret;
+       u8 u[UUID_LEN];
+
+       if (!wpa_s->wps_er)
+               return NULL;
+
+       if (uuid_str2bin(uuid, u))
+               return NULL;
+
+       ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+       if (ndef && ret) {
+               struct wpabuf *tmp;
+               tmp = ndef_build_wifi(ret);
+               wpabuf_free(ret);
+               if (tmp == NULL)
+                       return NULL;
+               ret = tmp;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
 static int callbacks_pending = 0;
 
 static void wpas_wps_terminate_cb(void *ctx)
@@ -1717,6 +1771,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                          wps->dev.num_sec_dev_types * WPS_DEV_TYPE_LEN);
        }
 
+       if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION)
+               wpas_wps_set_vendor_ext_m1(wpa_s, wps);
+
        if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION)
                wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
 
@@ -1733,3 +1790,132 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s)
                wps->dev.serial_number = wpa_s->conf->serial_number;
        }
 }
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
+{
+       return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
+                                &wpa_s->conf->wps_nfc_dh_pubkey,
+                                &wpa_s->conf->wps_nfc_dh_privkey,
+                                &wpa_s->conf->wps_nfc_dev_pw);
+}
+
+
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       struct wps_context *wps = wpa_s->wps;
+       char pw[32 * 2 + 1];
+
+       if (wpa_s->conf->wps_nfc_dh_pubkey == NULL ||
+           wpa_s->conf->wps_nfc_dh_privkey == NULL ||
+           wpa_s->conf->wps_nfc_dev_pw == NULL)
+               return -1;
+
+       dh5_free(wps->dh_ctx);
+       wpabuf_free(wps->dh_pubkey);
+       wpabuf_free(wps->dh_privkey);
+       wps->dh_privkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_privkey);
+       wps->dh_pubkey = wpabuf_dup(wpa_s->conf->wps_nfc_dh_pubkey);
+       if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+               wps->dh_ctx = NULL;
+               wpabuf_free(wps->dh_pubkey);
+               wps->dh_pubkey = NULL;
+               wpabuf_free(wps->dh_privkey);
+               wps->dh_privkey = NULL;
+               return -1;
+       }
+       wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+       if (wps->dh_ctx == NULL)
+               return -1;
+
+       wpa_snprintf_hex_uppercase(pw, sizeof(pw),
+                                  wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
+                                  wpabuf_len(wpa_s->conf->wps_nfc_dev_pw));
+       return wpas_wps_start_pin(wpa_s, bssid, pw, 0,
+                                 wpa_s->conf->wps_nfc_dev_pw_id);
+}
+
+
+static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
+                            struct wps_parse_attr *attr)
+{
+       if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
+               return -1;
+
+       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "WPS: Request reconnection with new network "
+                  "based on the received credential added");
+       wpa_s->normal_scans = 0;
+       wpa_supplicant_reinit_autoscan(wpa_s);
+       wpa_s->disconnected = 0;
+       wpa_s->reassociate = 1;
+       wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+       return 0;
+}
+
+
+static int wpas_wps_add_nfc_password_token(struct wpa_supplicant *wpa_s,
+                                          struct wps_parse_attr *attr)
+{
+       return wps_registrar_add_nfc_password_token(
+               wpa_s->wps->registrar, attr->oob_dev_password,
+               attr->oob_dev_password_len);
+}
+
+
+static int wpas_wps_nfc_tag_process(struct wpa_supplicant *wpa_s,
+                                   const struct wpabuf *wps)
+{
+       struct wps_parse_attr attr;
+
+       wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+       if (wps_parse_msg(wps, &attr)) {
+               wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+               return -1;
+       }
+
+       if (attr.num_cred)
+               return wpas_wps_use_cred(wpa_s, &attr);
+
+#ifdef CONFIG_WPS_ER
+       if (attr.oob_dev_password)
+               return wpas_wps_add_nfc_password_token(wpa_s, &attr);
+#endif /* CONFIG_WPS_ER */
+
+       wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+       return -1;
+}
+
+
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+                         const struct wpabuf *data)
+{
+       const struct wpabuf *wps = data;
+       struct wpabuf *tmp = NULL;
+       int ret;
+
+       if (wpabuf_len(data) < 4)
+               return -1;
+
+       if (*wpabuf_head_u8(data) != 0x10) {
+               /* Assume this contains full NDEF record */
+               tmp = ndef_parse_wifi(data);
+               if (tmp == NULL) {
+                       wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+                       return -1;
+               }
+               wps = tmp;
+       }
+
+       ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+       wpabuf_free(tmp);
+       return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */