WPS ER: Add command for fetching current AP settings
[libeap.git] / wpa_supplicant / ctrl_iface.c
index a7536d3..48e445d 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
@@ -31,6 +31,8 @@
 #include "wps_supplicant.h"
 #include "wps/wps.h"
 #include "ibss_rsn.h"
+#include "ap.h"
+#include "notify.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -150,18 +152,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);
 }
 
 
@@ -185,6 +191,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)
@@ -237,6 +249,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)
@@ -251,8 +268,60 @@ 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);
+}
+
+
+#ifdef CONFIG_WPS_ER
+static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
+                                               char *cmd)
+{
+       char *uuid = cmd, *pin;
+       pin = os_strchr(uuid, ' ');
+       if (pin == NULL)
+               return -1;
+       *pin++ = '\0';
+       return wpas_wps_er_add_pin(wpa_s, uuid, pin);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
+                                                 char *cmd)
+{
+       char *uuid = cmd, *pin;
+       pin = os_strchr(uuid, ' ');
+       if (pin == NULL)
+               return -1;
+       *pin++ = '\0';
+       return wpas_wps_er_learn(wpa_s, uuid, pin);
 }
+#endif /* CONFIG_WPS_ER */
+
 #endif /* CONFIG_WPS */
 
 
@@ -406,6 +475,13 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                        }
                }
 
+#ifdef CONFIG_AP
+               if (wpa_s->ap_iface) {
+                       pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
+                                                           end - pos,
+                                                           verbose);
+               } else
+#endif /* CONFIG_AP */
                pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
        }
        ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
@@ -788,37 +864,20 @@ static int wpa_supplicant_ctrl_iface_select_network(
        /* cmd: "<network id>" or "any" */
        if (os_strcmp(cmd, "any") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
-               ssid = wpa_s->conf->ssid;
-               while (ssid) {
-                       ssid->disabled = 0;
-                       ssid = ssid->next;
-               }
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
-               return 0;
-       }
-
-       id = atoi(cmd);
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
+               ssid = NULL;
+       } else {
+               id = atoi(cmd);
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-                          "id=%d", id);
-               return -1;
+               ssid = wpa_config_get_network(wpa_s->conf, id);
+               if (ssid == NULL) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+                                  "network id=%d", id);
+                       return -1;
+               }
        }
 
-       if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
-       /* Mark all other networks disabled and trigger reassociation */
-       ssid = wpa_s->conf->ssid;
-       while (ssid) {
-               ssid->disabled = id != ssid->id;
-               ssid = ssid->next;
-       }
-       wpa_s->reassociate = 1;
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       wpa_supplicant_select_network(wpa_s, ssid);
 
        return 0;
 }
@@ -833,36 +892,19 @@ static int wpa_supplicant_ctrl_iface_enable_network(
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
-               ssid = wpa_s->conf->ssid;
-               while (ssid) {
-                       if (ssid == wpa_s->current_ssid && ssid->disabled)
-                               wpa_s->reassociate = 1;
-                       ssid->disabled = 0;
-                       ssid = ssid->next;
-               }
-               if (wpa_s->reassociate)
-                       wpa_supplicant_req_scan(wpa_s, 0, 0);
-               return 0;
-       }
-
-       id = atoi(cmd);
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
-
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-                          "id=%d", id);
-               return -1;
-       }
+               ssid = NULL;
+       } else {
+               id = atoi(cmd);
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
 
-       if (wpa_s->current_ssid == NULL && ssid->disabled) {
-               /*
-                * Try to reassociate since there is no current configuration
-                * and a new network was made available. */
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               ssid = wpa_config_get_network(wpa_s->conf, id);
+               if (ssid == NULL) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+                                  "network id=%d", id);
+                       return -1;
+               }
        }
-       ssid->disabled = 0;
+       wpa_supplicant_enable_network(wpa_s, ssid);
 
        return 0;
 }
@@ -877,30 +919,19 @@ static int wpa_supplicant_ctrl_iface_disable_network(
        /* cmd: "<network id>" or "all" */
        if (os_strcmp(cmd, "all") == 0) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
-               ssid = wpa_s->conf->ssid;
-               while (ssid) {
-                       ssid->disabled = 1;
-                       ssid = ssid->next;
-               }
-               if (wpa_s->current_ssid)
-                       wpa_supplicant_disassociate(wpa_s,
-                                                   WLAN_REASON_DEAUTH_LEAVING);
-               return 0;
-       }
-
-       id = atoi(cmd);
-       wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
+               ssid = NULL;
+       } else {
+               id = atoi(cmd);
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
 
-       ssid = wpa_config_get_network(wpa_s->conf, id);
-       if (ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
-                          "id=%d", id);
-               return -1;
+               ssid = wpa_config_get_network(wpa_s->conf, id);
+               if (ssid == NULL) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+                                  "network id=%d", id);
+                       return -1;
+               }
        }
-
-       if (ssid == wpa_s->current_ssid)
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-       ssid->disabled = 1;
+       wpa_supplicant_disable_network(wpa_s, ssid);
 
        return 0;
 }
@@ -917,6 +948,9 @@ static int wpa_supplicant_ctrl_iface_add_network(
        ssid = wpa_config_add_network(wpa_s->conf);
        if (ssid == NULL)
                return -1;
+
+       wpas_notify_network_added(wpa_s, ssid);
+
        ssid->disabled = 1;
        wpa_config_set_network_defaults(ssid);
 
@@ -938,8 +972,10 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
                ssid = wpa_s->conf->ssid;
                while (ssid) {
+                       struct wpa_ssid *remove_ssid = ssid;
                        id = ssid->id;
                        ssid = ssid->next;
+                       wpas_notify_network_removed(wpa_s, remove_ssid);
                        wpa_config_remove_network(wpa_s->conf, id);
                }
                if (wpa_s->current_ssid) {
@@ -1506,6 +1542,14 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                return pos - buf;
        pos += ret;
 
+#ifdef CONFIG_WPS
+       ie = (const u8 *) (bss + 1);
+       ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
+       if (ret < 0 || ret >= end - pos)
+               return pos - buf;
+       pos += ret;
+#endif /* CONFIG_WPS */
+
        return pos - buf;
 }
 
@@ -1514,11 +1558,7 @@ static int wpa_supplicant_ctrl_iface_ap_scan(
        struct wpa_supplicant *wpa_s, char *cmd)
 {
        int ap_scan = atoi(cmd);
-
-       if (ap_scan < 0 || ap_scan > 2)
-               return -1;
-       wpa_s->conf->ap_scan = ap_scan;
-       return 0;
+       return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
 }
 
 
@@ -1619,6 +1659,23 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
                        reply_len = -1;
+#ifdef CONFIG_WPS_ER
+       } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
+               if (wpas_wps_er_start(wpa_s))
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
+               if (wpas_wps_er_stop(wpa_s))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
+               if (wpas_wps_er_pbc(wpa_s, buf + 11))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
+                       reply_len = -1;
+#endif /* CONFIG_WPS_ER */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_IBSS_RSN
        } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
@@ -1694,6 +1751,16 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "BSS ", 4) == 0) {
                reply_len = wpa_supplicant_ctrl_iface_bss(
                        wpa_s, buf + 4, reply, reply_size);
+#ifdef CONFIG_AP
+       } else if (os_strcmp(buf, "STA-FIRST") == 0) {
+               reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
+       } else if (os_strncmp(buf, "STA ", 4) == 0) {
+               reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
+                                             reply_size);
+       } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+               reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
+                                                  reply_size);
+#endif /* CONFIG_AP */
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;