WPS: Add support for AP reconfiguration with wps_reg
[mech_eap.git] / wpa_supplicant / ctrl_iface.c
index 2b737bc..5e2030e 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
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "wpa_supplicant_i.h"
+#include "driver_i.h"
 #include "ctrl_iface.h"
 #include "l2_packet/l2_packet.h"
 #include "preauth.h"
 #include "ieee802_11_defs.h"
 #include "wps_supplicant.h"
 #include "wps/wps.h"
+#include "ibss_rsn.h"
+#include "ap.h"
+
+extern struct wpa_driver_ops *wpa_drivers[];
 
 static int wpa_supplicant_global_iface_list(struct wpa_global *global,
                                            char *buf, int len);
@@ -146,18 +151,22 @@ static int wpa_supplicant_ctrl_iface_ft_ds(
 static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
-       u8 bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN], *_bssid = bssid;
 
        if (cmd == NULL || os_strcmp(cmd, "any") == 0)
-               return wpas_wps_start_pbc(wpa_s, NULL);
-
-       if (hwaddr_aton(cmd, bssid)) {
+               _bssid = NULL;
+       else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
                           cmd);
                return -1;
        }
 
-       return wpas_wps_start_pbc(wpa_s, bssid);
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface)
+               return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
+#endif /* CONFIG_AP */
+
+       return wpas_wps_start_pbc(wpa_s, _bssid);
 }
 
 
@@ -181,6 +190,12 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface)
+               return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
+                                                buf, buflen);
+#endif /* CONFIG_AP */
+
        if (pin) {
                ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
                if (ret < 0)
@@ -203,11 +218,41 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_WPS_OOB
+static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
+                                            char *cmd)
+{
+       char *path, *method, *name;
+
+       path = os_strchr(cmd, ' ');
+       if (path == NULL)
+               return -1;
+       *path++ = '\0';
+
+       method = os_strchr(path, ' ');
+       if (method == NULL)
+               return -1;
+       *method++ = '\0';
+
+       name = os_strchr(method, ' ');
+       if (name != NULL)
+               *name++ = '\0';
+
+       return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
+}
+#endif /* CONFIG_WPS_OOB */
+
+
 static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
                                             char *cmd)
 {
        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)
@@ -222,11 +267,56 @@ 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 */
 
 
+#ifdef CONFIG_IBSS_RSN
+static int wpa_supplicant_ctrl_iface_ibss_rsn(
+       struct wpa_supplicant *wpa_s, char *addr)
+{
+       u8 peer[ETH_ALEN];
+
+       if (hwaddr_aton(addr, peer)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
+                          "address '%s'", peer);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
+                  MAC2STR(peer));
+
+       return ibss_rsn_start(wpa_s->ibss_rsn, peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
                                              char *rsp)
 {
@@ -1517,7 +1607,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_status(
                        wpa_s, buf + 6, reply, reply_size);
        } else if (os_strcmp(buf, "PMKSA") == 0) {
-               reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
+               reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
+                                                   reply_size);
        } else if (os_strncmp(buf, "SET ", 4) == 0) {
                if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
                        reply_len = -1;
@@ -1561,10 +1652,20 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
                                                              reply,
                                                              reply_size);
+#ifdef CONFIG_WPS_OOB
+       } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
+                       reply_len = -1;
+#endif /* CONFIG_WPS_OOB */
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
                        reply_len = -1;
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_IBSS_RSN
+       } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
+               if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
+                       reply_len = -1;
+#endif /* CONFIG_IBSS_RSN */
        } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
        {
                if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -1765,8 +1866,8 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
        struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
        char *pos, *end;
 
-       for (i = 0; wpa_supplicant_drivers[i]; i++) {
-               struct wpa_driver_ops *drv = wpa_supplicant_drivers[i];
+       for (i = 0; wpa_drivers[i]; i++) {
+               struct wpa_driver_ops *drv = wpa_drivers[i];
                if (drv->get_interfaces == NULL)
                        continue;
                tmp = drv->get_interfaces(global->drv_priv);