]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - build-utilities/hostap.git/commitdiff
WPS: Add support for AP reconfiguration with wps_reg
authorJouni Malinen <j@w1.fi>
Sun, 6 Sep 2009 10:58:15 +0000 (13:58 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 6 Sep 2009 10:58:15 +0000 (13:58 +0300)
wpa_supplicant can now reconfigure the AP by acting as an External
Registrar with the wps_reg command. Previously, this was only used
to fetch the current AP settings, but now the wps_reg command has
optional arguments which can be used to provide the new AP
configuration. When the new parameters are set, the WPS protocol run
is allowed to continue through M8 to reconfigure the AP instead of
stopping at M7.

src/eap_peer/eap_wsc.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_i.h
src/wps/wps_registrar.c
wpa_supplicant/README-WPS
wpa_supplicant/ctrl_iface.c
wpa_supplicant/ctrl_iface_dbus_handlers.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 7c8ad2fdad9854b0b780b6696562ce431a9e907b..9a0354e10b9d7f208553459aa1402bc56d81cfb2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -65,6 +65,72 @@ static void eap_wsc_state(struct eap_wsc_data *data, int state)
 }
 
 
+static int eap_wsc_new_ap_settings(struct wps_credential *cred,
+                                  const char *params)
+{
+       const char *pos, *end;
+       size_t len;
+
+       os_memset(cred, 0, sizeof(*cred));
+
+       pos = os_strstr(params, "new_ssid=");
+       if (pos == NULL)
+               return 0;
+       pos += 9;
+       end = os_strchr(pos, ' ');
+       if (end == NULL)
+               len = os_strlen(pos);
+       else
+               len = end - pos;
+       if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
+           hexstr2bin(pos, cred->ssid, len / 2))
+               return -1;
+       cred->ssid_len = len / 2;
+
+       pos = os_strstr(params, "new_auth=");
+       if (pos == NULL)
+               return -1;
+       if (os_strncmp(pos + 9, "OPEN", 4) == 0)
+               cred->auth_type = WPS_AUTH_OPEN;
+       else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
+               cred->auth_type = WPS_AUTH_WPAPSK;
+       else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
+               cred->auth_type = WPS_AUTH_WPA2PSK;
+       else
+               return -1;
+
+       pos = os_strstr(params, "new_encr=");
+       if (pos == NULL)
+               return -1;
+       if (os_strncmp(pos + 9, "NONE", 4) == 0)
+               cred->encr_type = WPS_ENCR_NONE;
+       else if (os_strncmp(pos + 9, "WEP", 3) == 0)
+               cred->encr_type = WPS_ENCR_WEP;
+       else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
+               cred->encr_type = WPS_ENCR_TKIP;
+       else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
+               cred->encr_type = WPS_ENCR_AES;
+       else
+               return -1;
+
+       pos = os_strstr(params, "new_key=");
+       if (pos == NULL)
+               return 0;
+       pos += 8;
+       end = os_strchr(pos, ' ');
+       if (end == NULL)
+               len = os_strlen(pos);
+       else
+               len = end - pos;
+       if ((len & 1) || len > 2 * sizeof(cred->key) ||
+           hexstr2bin(pos, cred->key, len / 2))
+               return -1;
+       cred->key_len = len / 2;
+
+       return 1;
+}
+
+
 static void * eap_wsc_init(struct eap_sm *sm)
 {
        struct eap_wsc_data *data;
@@ -75,6 +141,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
        const char *pos;
        const char *phase1;
        struct wps_context *wps;
+       struct wps_credential new_ap_settings;
+       int res;
 
        wps = sm->wps;
        if (wps == NULL) {
@@ -135,6 +203,17 @@ static void * eap_wsc_init(struct eap_sm *sm)
                return NULL;
        }
 
+       res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
+       if (res < 0) {
+               os_free(data);
+               return NULL;
+       }
+       if (res == 1) {
+               wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
+                          "WPS");
+               cfg.new_ap_settings = &new_ap_settings;
+       }
+
        data->wps = wps_init(&cfg);
        if (data->wps == NULL) {
                os_free(data);
index dde16d17a5968e156b2b05a251888d204b2ae6a8..e0e19c8880b52b93e4faca594af64eca49378dc7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -89,6 +89,17 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                }
        }
 
+       if (cfg->new_ap_settings) {
+               data->new_ap_settings =
+                       os_malloc(sizeof(*data->new_ap_settings));
+               if (data->new_ap_settings == NULL) {
+                       os_free(data);
+                       return NULL;
+               }
+               os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
+                         sizeof(*data->new_ap_settings));
+       }
+
        return data;
 }
 
@@ -115,6 +126,7 @@ void wps_deinit(struct wps_data *data)
        os_free(data->dev_password);
        os_free(data->new_psk);
        wps_device_data_free(&data->peer_dev);
+       os_free(data->new_ap_settings);
        os_free(data);
 }
 
index 9807ad425e546da960dd47d6ae56caeadf4572ba..c33e8013a1ef1d850ad53ee4edc23b0fc3606bbe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup
- * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -132,6 +132,16 @@ struct wps_config {
         * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
         */
        const struct wpabuf *assoc_wps_ie;
+
+       /**
+        * new_ap_settings - New AP settings (%NULL if not used)
+        *
+        * This parameter provides new AP settings when using a wireless
+        * stations as a Registrar to configure the AP. %NULL means that AP
+        * will not be reconfigured, i.e., the station will only learn the
+        * current AP settings by using AP PIN.
+        */
+       const struct wps_credential *new_ap_settings;
 };
 
 struct wps_data * wps_init(const struct wps_config *cfg);
index e3cf2365495e6514e481a633b3988efc4c5e3722..b79c5291fde561dcbcf5dfa7f94f279fcf337077 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - internal definitions
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -103,6 +103,8 @@ struct wps_data {
        u16 config_error;
 
        int ext_reg;
+
+       struct wps_credential *new_ap_settings;
 };
 
 
index 185db8c0ce74f0160e701b664949b16c6270412d..b625d21c4b5c076538f159e071e7561ef571056a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Wi-Fi Protected Setup - Registrar
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -2041,6 +2041,19 @@ static void wps_sta_cred_cb(struct wps_data *wps)
 }
 
 
+static void wps_cred_update(struct wps_credential *dst,
+                           struct wps_credential *src)
+{
+       os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
+       dst->ssid_len = src->ssid_len;
+       dst->auth_type = src->auth_type;
+       dst->encr_type = src->encr_type;
+       dst->key_idx = src->key_idx;
+       os_memcpy(dst->key, src->key, sizeof(dst->key));
+       dst->key_len = src->key_len;
+}
+
+
 static int wps_process_ap_settings_r(struct wps_data *wps,
                                     struct wps_parse_attr *attr)
 {
@@ -2053,21 +2066,19 @@ static int wps_process_ap_settings_r(struct wps_data *wps,
 
        wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
 
-#if 0
-       /*
-        * TODO: Provide access to AP settings and allow changes before sending
-        * out M8. For now, just copy the settings unchanged into M8.
-        */
-
-       return 0;
-#else
-       /*
-        * For now, use the AP PIN only to receive the current AP settings,
-        * not to reconfigure the AP.
-        */
-       wps_sta_cred_cb(wps);
-       return 1;
-#endif
+       if (wps->new_ap_settings) {
+               wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
+                          "new settings");
+               wps_cred_update(&wps->cred, wps->new_ap_settings);
+               return 0;
+       } else {
+               /*
+                * Use the AP PIN only to receive the current AP settings, not
+                * to reconfigure the AP.
+                */
+               wps_sta_cred_cb(wps);
+               return 1;
+       }
 }
 
 
index 6b826a794f976cb97177167e0f39e6c7a6dc3f03..2b1ded0e039fd6e03c668d30dc3236eab5a4a6e5 100644 (file)
@@ -131,17 +131,29 @@ negotiation which will generate a new WPA PSK in the same way as the
 PIN method described above.
 
 
-If the client wants to operate in the Registrar role to configure an
-AP, wpa_supplicant is notified over the control interface, e.g., with
+If the client wants to operate in the Registrar role to learn the
+current AP configuration and optionally, to configure an AP,
+wpa_supplicant is notified over the control interface, e.g., with
 wpa_cli:
 
 wpa_cli wps_reg <AP BSSID> <AP PIN>
 (example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
 
-This is currently only used to fetch the current AP settings instead
-of actually changing them. The main difference with the wps_pin
-command is that wps_reg uses the AP PIN (e.g., from a label on the AP)
-instead of a PIN generated at the client.
+This is used to fetch the current AP settings instead of actually
+changing them. The main difference with the wps_pin command is that
+wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a
+PIN generated at the client.
+
+In order to change the AP configuration, the new configuration
+parameters are given to the wps_reg command:
+
+wpa_cli wps_reg <AP BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
+examples:
+  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678
+  wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
 
 
 Scanning
index 08121b6ddc984dce1c366cede830585277b373e4..5e2030ec106c797c0d44bd8d5418db6b3d216664 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -248,6 +248,11 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
 {
        u8 bssid[ETH_ALEN], *_bssid = bssid;
        char *pin;
+       char *new_ssid;
+       char *new_auth;
+       char *new_encr;
+       char *new_key;
+       struct wps_new_ap_settings ap;
 
        pin = os_strchr(cmd, ' ');
        if (pin == NULL)
@@ -262,7 +267,32 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       return wpas_wps_start_reg(wpa_s, _bssid, pin);
+       new_ssid = os_strchr(pin, ' ');
+       if (new_ssid == NULL)
+               return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
+       *new_ssid++ = '\0';
+
+       new_auth = os_strchr(new_ssid, ' ');
+       if (new_auth == NULL)
+               return -1;
+       *new_auth++ = '\0';
+
+       new_encr = os_strchr(new_auth, ' ');
+       if (new_encr == NULL)
+               return -1;
+       *new_encr++ = '\0';
+
+       new_key = os_strchr(new_encr, ' ');
+       if (new_key == NULL)
+               return -1;
+       *new_key++ = '\0';
+
+       os_memset(&ap, 0, sizeof(ap));
+       ap.ssid_hex = new_ssid;
+       ap.auth = new_auth;
+       ap.encr = new_encr;
+       ap.key_hex = new_key;
+       return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
 }
 #endif /* CONFIG_WPS */
 
index 53a18467f667a821664852e01c1e49163aaa1aab..f9bd7ed4f4eb2e211f87fb98cb81a90c3d99982a 100644 (file)
@@ -1615,9 +1615,9 @@ DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
                return wpas_dbus_new_invalid_opts_error(message, NULL);
 
        if (!os_strcmp(arg_bssid, "any"))
-               ret = wpas_wps_start_reg(wpa_s, NULL, pin);
+               ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
        else if (!hwaddr_aton(arg_bssid, bssid))
-               ret = wpas_wps_start_reg(wpa_s, bssid, pin);
+               ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
        else {
                return wpas_dbus_new_invalid_opts_error(message,
                                                        "Invalid BSSID");
index 73937d71e1899c726760246c7048ce74d8fec41f..b5b346939a03cc4f34210fd706cabb60aaf5f5e1 100644 (file)
@@ -484,14 +484,47 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
        char cmd[256];
        int res;
 
-       if (argc != 2) {
+       if (argc == 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
+                                 argv[0], argv[1]);
+       else if (argc == 6) {
+               char ssid_hex[2 * 32 + 1];
+               char key_hex[2 * 64 + 1];
+               int i;
+
+               ssid_hex[0] = '\0';
+               for (i = 0; i < 32; i++) {
+                       if (argv[2][i] == '\0')
+                               break;
+                       os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
+               }
+
+               key_hex[0] = '\0';
+               for (i = 0; i < 64; i++) {
+                       if (argv[5][i] == '\0')
+                               break;
+                       os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
+               }
+
+               res = os_snprintf(cmd, sizeof(cmd),
+                                 "WPS_REG %s %s %s %s %s %s",
+                                 argv[0], argv[1], ssid_hex, argv[3], argv[4],
+                                 key_hex);
+       } else {
                printf("Invalid WPS_REG command: need two arguments:\n"
                       "- BSSID: use 'any' to select any\n"
                       "- AP PIN\n");
+               printf("Alternatively, six arguments can be used to "
+                      "reconfigure the AP:\n"
+                      "- BSSID: use 'any' to select any\n"
+                      "- AP PIN\n"
+                      "- new SSID\n"
+                      "- new auth (OPEN, WPAPSK, WPA2PSK)\n"
+                      "- new encr (NONE, WEP, TKIP, CCMP)\n"
+                      "- new key\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]);
        if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
                printf("Too long WPS_REG command.\n");
                return -1;
index 6fb1aa33355b873e052d9065350e87f382c9f339..0ca67459df340007477d0e8425811b4501ffa574 100644 (file)
@@ -630,10 +630,12 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
 
 
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      const char *pin)
+                      const char *pin, struct wps_new_ap_settings *settings)
 {
        struct wpa_ssid *ssid;
-       char val[30];
+       char val[200];
+       char *pos, *end;
+       int res;
 
        if (!pin)
                return -1;
@@ -641,7 +643,24 @@ 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;
-       os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
+       pos = val;
+       end = pos + sizeof(val);
+       res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
+       if (res < 0 || res >= end - pos)
+               return -1;
+       pos += res;
+       if (settings) {
+               res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
+                                 "new_encr=%s new_key=%s",
+                                 settings->ssid_hex, settings->auth,
+                                 settings->encr, settings->key_hex);
+               if (res < 0 || res >= end - pos)
+                       return -1;
+               pos += res;
+       }
+       res = os_snprintf(pos, end - pos, "\"");
+       if (res < 0 || res >= end - pos)
+               return -1;
        wpa_config_set(ssid, "phase1", val, 0);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
                               wpa_s, NULL);
index abc4b92257e741f6e4bfb7e27025a10fbb0069be..47253126fa8d500901ad390e99332ab15eb7eff0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant / WPS integration
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include "wps/wps.h"
 #include "wps/wps_defs.h"
 
+struct wps_new_ap_settings {
+       const char *ssid_hex;
+       const char *auth;
+       const char *encr;
+       const char *key_hex;
+};
+
 int wpas_wps_init(struct wpa_supplicant *wpa_s);
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
@@ -30,7 +37,7 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
                       char *path, char *method, char *name);
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      const char *pin);
+                      const char *pin, struct wps_new_ap_settings *settings);
 int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                            struct wpa_ssid *ssid, struct wpa_scan_res *bss);
 int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,