WPS 2.0: Add support for AuthorizedMACs attribute
[mech_eap.git] / wpa_supplicant / ctrl_iface.c
index 48e445d..4a2412f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2010, 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
  * See README and COPYING for more details.
  */
 
-#include "includes.h"
+#include "utils/includes.h"
 
-#include "common.h"
-#include "eloop.h"
-#include "wpa.h"
-#include "config.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "l2_packet/l2_packet.h"
+#include "wps/wps.h"
+#include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
-#include "ctrl_iface.h"
-#include "l2_packet/l2_packet.h"
-#include "preauth.h"
-#include "pmksa_cache.h"
-#include "wpa_ctrl.h"
-#include "eap_peer/eap.h"
-#include "ieee802_11_defs.h"
 #include "wps_supplicant.h"
-#include "wps/wps.h"
 #include "ibss_rsn.h"
 #include "ap.h"
 #include "notify.h"
+#include "bss.h"
+#include "scan.h"
+#include "ctrl_iface.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -117,7 +119,7 @@ static int wpa_supplicant_ctrl_iface_stkstart(
 
        if (hwaddr_aton(addr, peer)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
-                          "address '%s'", peer);
+                          "address '%s'", addr);
                return -1;
        }
 
@@ -134,16 +136,24 @@ static int wpa_supplicant_ctrl_iface_ft_ds(
        struct wpa_supplicant *wpa_s, char *addr)
 {
        u8 target_ap[ETH_ALEN];
+       struct wpa_bss *bss;
+       const u8 *mdie;
 
        if (hwaddr_aton(addr, target_ap)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
-                          "address '%s'", target_ap);
+                          "address '%s'", addr);
                return -1;
        }
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
 
-       return wpa_ft_start_over_ds(wpa_s->wpa, target_ap);
+       bss = wpa_bss_get_bssid(wpa_s, target_ap);
+       if (bss)
+               mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+       else
+               mdie = NULL;
+
+       return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
 }
 #endif /* CONFIG_IEEE80211R */
 
@@ -301,12 +311,19 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
 static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
                                                char *cmd)
 {
-       char *uuid = cmd, *pin;
+       char *uuid = cmd, *pin, *pos;
+       u8 addr_buf[ETH_ALEN], *addr = NULL;
        pin = os_strchr(uuid, ' ');
        if (pin == NULL)
                return -1;
        *pin++ = '\0';
-       return wpas_wps_er_add_pin(wpa_s, uuid, pin);
+       pos = os_strchr(pin, ' ');
+       if (pos) {
+               *pos++ = '\0';
+               if (hwaddr_aton(pos, addr_buf) == 0)
+                       addr = addr_buf;
+       }
+       return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
 }
 
 
@@ -320,6 +337,50 @@ static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
        *pin++ = '\0';
        return wpas_wps_er_learn(wpa_s, uuid, pin);
 }
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_config(
+       struct wpa_supplicant *wpa_s, char *cmd)
+{
+       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)
+               return -1;
+       *pin++ = '\0';
+
+       new_ssid = os_strchr(pin, ' ');
+       if (new_ssid == NULL)
+               return -1;
+       *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_er_config(wpa_s, cmd, pin, &ap);
+}
 #endif /* CONFIG_WPS_ER */
 
 #endif /* CONFIG_WPS */
@@ -333,7 +394,7 @@ static int wpa_supplicant_ctrl_iface_ibss_rsn(
 
        if (hwaddr_aton(addr, peer)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
-                          "address '%s'", peer);
+                          "address '%s'", addr);
                return -1;
        }
 
@@ -473,6 +534,27 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
                                        return pos - buf;
                                pos += ret;
                        }
+
+                       switch (ssid->mode) {
+                       case WPAS_MODE_INFRA:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=station\n");
+                               break;
+                       case WPAS_MODE_IBSS:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=IBSS\n");
+                               break;
+                       case WPAS_MODE_AP:
+                               ret = os_snprintf(pos, end - pos,
+                                                 "mode=AP\n");
+                               break;
+                       default:
+                               ret = 0;
+                               break;
+                       }
+                       if (ret < 0 || ret >= end - pos)
+                               return pos - buf;
+                       pos += ret;
                }
 
 #ifdef CONFIG_AP
@@ -741,20 +823,21 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
        return pos;
 }
 
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
-                                       const struct wpa_scan_res *res)
-{
+
 #ifdef CONFIG_WPS
-       struct wpabuf *wps_ie;
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+                                           char *pos, char *end,
+                                           struct wpabuf *wps_ie)
+{
        int ret;
        const char *txt;
 
-       wps_ie = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
        if (wps_ie == NULL)
                return pos;
-
        if (wps_is_selected_pbc_registrar(wps_ie))
                txt = "[WPS-PBC]";
+       else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+               txt = "[WPS-AUTH]";
        else if (wps_is_selected_pin_registrar(wps_ie))
                txt = "[WPS-PIN]";
        else
@@ -764,15 +847,29 @@ static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
        if (ret >= 0 && ret < end - pos)
                pos += ret;
        wpabuf_free(wps_ie);
+       return pos;
+}
 #endif /* CONFIG_WPS */
 
+
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+                                       char *pos, char *end,
+                                       const struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+       struct wpabuf *wps_ie;
+       wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+       return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
+#else /* CONFIG_WPS */
        return pos;
+#endif /* CONFIG_WPS */
 }
 
 
 /* Format one result on one text line into a buffer. */
 static int wpa_supplicant_ctrl_iface_scan_result(
-       const struct wpa_scan_res *res, char *buf, size_t buflen)
+       struct wpa_supplicant *wpa_s,
+       const struct wpa_bss *bss, char *buf, size_t buflen)
 {
        char *pos, *end;
        int ret;
@@ -782,33 +879,38 @@ static int wpa_supplicant_ctrl_iface_scan_result(
        end = buf + buflen;
 
        ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
-                         MAC2STR(res->bssid), res->freq, res->level);
+                         MAC2STR(bss->bssid), bss->freq, bss->level);
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
-       ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
+       ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        if (ie)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
-       ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
+       ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, res);
-       if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
+       pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+       if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
                pos += ret;
        }
-       if (res->caps & IEEE80211_CAP_IBSS) {
+       if (bss->caps & IEEE80211_CAP_IBSS) {
                ret = os_snprintf(pos, end - pos, "[IBSS]");
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
                pos += ret;
        }
+       if (bss->caps & IEEE80211_CAP_ESS) {
+               ret = os_snprintf(pos, end - pos, "[ESS]");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
 
-       ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
        ret = os_snprintf(pos, end - pos, "\t%s",
-                         ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
+                         wpa_ssid_txt(bss->ssid, bss->ssid_len));
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
@@ -826,13 +928,8 @@ static int wpa_supplicant_ctrl_iface_scan_results(
        struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
 {
        char *pos, *end;
-       struct wpa_scan_res *res;
+       struct wpa_bss *bss;
        int ret;
-       size_t i;
-
-       if (wpa_s->scan_res == NULL &&
-           wpa_supplicant_get_scan_results(wpa_s) < 0)
-               return 0;
 
        pos = buf;
        end = buf + buflen;
@@ -842,9 +939,8 @@ static int wpa_supplicant_ctrl_iface_scan_results(
                return pos - buf;
        pos += ret;
 
-       for (i = 0; i < wpa_s->scan_res->num; i++) {
-               res = wpa_s->scan_res->res[i];
-               ret = wpa_supplicant_ctrl_iface_scan_result(res, pos,
+       dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+               ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
                                                            end - pos);
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
@@ -1060,6 +1156,8 @@ static int wpa_supplicant_ctrl_iface_set_network(
             value[0] == '"' && ssid->ssid_len) ||
            (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
                wpa_config_update_psk(ssid);
+       else if (os_strcmp(name, "priority") == 0)
+               wpa_config_update_prio_list(wpa_s->conf);
 
        return 0;
 }
@@ -1446,36 +1544,49 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
 {
        u8 bssid[ETH_ALEN];
        size_t i;
-       struct wpa_scan_results *results;
-       struct wpa_scan_res *bss;
+       struct wpa_bss *bss;
        int ret;
        char *pos, *end;
        const u8 *ie, *ie2;
 
-       if (wpa_s->scan_res == NULL &&
-           wpa_supplicant_get_scan_results(wpa_s) < 0)
-               return 0;
-
-       results = wpa_s->scan_res;
-       if (results == NULL)
-               return 0;
-
-       if (hwaddr_aton(cmd, bssid) == 0) {
-               for (i = 0; i < results->num; i++) {
-                       if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN)
-                           == 0)
-                               break;
+       if (os_strcmp(cmd, "FIRST") == 0)
+               bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
+       else if (os_strncmp(cmd, "ID-", 3) == 0) {
+               i = atoi(cmd + 3);
+               bss = wpa_bss_get_id(wpa_s, i);
+       } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+               i = atoi(cmd + 5);
+               bss = wpa_bss_get_id(wpa_s, i);
+               if (bss) {
+                       struct dl_list *next = bss->list_id.next;
+                       if (next == &wpa_s->bss_id)
+                               bss = NULL;
+                       else
+                               bss = dl_list_entry(next, struct wpa_bss,
+                                                   list_id);
                }
-       } else
+       } else if (hwaddr_aton(cmd, bssid) == 0)
+               bss = wpa_bss_get_bssid(wpa_s, bssid);
+       else {
+               struct wpa_bss *tmp;
                i = atoi(cmd);
+               bss = NULL;
+               dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
+               {
+                       if (i-- == 0) {
+                               bss = tmp;
+                               break;
+                       }
+               }
+       }
 
-       if (i >= results->num || results->res[i] == NULL)
-               return 0; /* no match found */
+       if (bss == NULL)
+               return 0;
 
-       bss = results->res[i];
        pos = buf;
        end = buf + buflen;
        ret = os_snprintf(pos, end - pos,
+                         "id=%u\n"
                          "bssid=" MACSTR "\n"
                          "freq=%d\n"
                          "beacon_int=%d\n"
@@ -1485,6 +1596,7 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                          "level=%d\n"
                          "tsf=%016llu\n"
                          "ie=",
+                         bss->id,
                          MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
                          bss->caps, bss->qual, bss->noise, bss->level,
                          (unsigned long long) bss->tsf);
@@ -1510,13 +1622,13 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                return pos - buf;
        pos += ret;
 
-       ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+       ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
        if (ie)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
-       ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+       ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
+       pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
        if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
                if (ret < 0 || ret >= end - pos)
@@ -1529,15 +1641,20 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
                        return pos - buf;
                pos += ret;
        }
+       if (bss->caps & IEEE80211_CAP_ESS) {
+               ret = os_snprintf(pos, end - pos, "[ESS]");
+               if (ret < 0 || ret >= end - pos)
+                       return pos - buf;
+               pos += ret;
+       }
 
        ret = os_snprintf(pos, end - pos, "\n");
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
 
-       ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
        ret = os_snprintf(pos, end - pos, "ssid=%s\n",
-                         ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
+                         wpa_ssid_txt(bss->ssid, bss->ssid_len));
        if (ret < 0 || ret >= end - pos)
                return pos - buf;
        pos += ret;
@@ -1562,6 +1679,71 @@ static int wpa_supplicant_ctrl_iface_ap_scan(
 }
 
 
+static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
+{
+       u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
+
+       wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
+       /* MLME-DELETEKEYS.request */
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
+
+       wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
+                       0);
+       /* MLME-SETPROTECTION.request(None) */
+       wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
+                                  MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+                                  MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+       wpa_sm_drop_sa(wpa_s->wpa);
+}
+
+
+static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
+                                         char *addr)
+{
+       u8 bssid[ETH_ALEN];
+       struct wpa_bss *bss;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+       if (hwaddr_aton(addr, bssid)) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
+                          "address '%s'", addr);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
+
+       bss = wpa_bss_get_bssid(wpa_s, bssid);
+       if (!bss) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
+                          "from BSS table");
+               return -1;
+       }
+
+       /*
+        * TODO: Find best network configuration block from configuration to
+        * allow roaming to other networks
+        */
+
+       if (!ssid) {
+               wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+                          "configuration known for the target AP");
+               return -1;
+       }
+
+       wpa_s->reassociate = 1;
+       wpa_supplicant_connect(wpa_s, bss, ssid);
+
+       return 0;
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                                         char *buf, size_t *resp_len)
 {
@@ -1591,6 +1773,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        if (os_strcmp(buf, "PING") == 0) {
                os_memcpy(reply, "PONG\n", 5);
                reply_len = 5;
+       } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+               wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
        } else if (os_strcmp(buf, "MIB") == 0) {
                reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
                if (reply_len >= 0) {
@@ -1616,11 +1800,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "LOGOFF") == 0) {
                eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
        } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
-               wpa_s->disconnected = 0;
-               wpa_s->reassociate = 1;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+                       reply_len = -1;
+               else {
+                       wpa_s->disconnected = 0;
+                       wpa_s->reassociate = 1;
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+               }
        } else if (os_strcmp(buf, "RECONNECT") == 0) {
-               if (wpa_s->disconnected) {
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+                       reply_len = -1;
+               else if (wpa_s->disconnected) {
                        wpa_s->disconnected = 0;
                        wpa_s->reassociate = 1;
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1661,7 +1851,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
 #ifdef CONFIG_WPS_ER
        } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
-               if (wpas_wps_er_start(wpa_s))
+               if (wpas_wps_er_start(wpa_s, NULL))
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
+               if (wpas_wps_er_start(wpa_s, buf + 13))
                        reply_len = -1;
        } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
                if (wpas_wps_er_stop(wpa_s))
@@ -1675,6 +1868,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } 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;
+       } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
+               if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
+                       reply_len = -1;
 #endif /* CONFIG_WPS_ER */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_IBSS_RSN
@@ -1693,7 +1889,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                if (wpa_supplicant_reload_configuration(wpa_s))
                        reply_len = -1;
        } else if (os_strcmp(buf, "TERMINATE") == 0) {
-               eloop_terminate();
+               wpa_supplicant_terminate_proc(wpa_s->global);
        } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
                if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
                        reply_len = -1;
@@ -1703,10 +1899,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strcmp(buf, "DISCONNECT") == 0) {
                wpa_s->reassociate = 0;
                wpa_s->disconnected = 1;
-               wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
        } else if (os_strcmp(buf, "SCAN") == 0) {
-               wpa_s->scan_req = 2;
-               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+                       reply_len = -1;
+               else {
+                       wpa_s->scan_req = 2;
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+               }
        } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
                reply_len = wpa_supplicant_ctrl_iface_scan_results(
                        wpa_s, reply, reply_size);
@@ -1761,6 +1962,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
                                                   reply_size);
 #endif /* CONFIG_AP */
+       } else if (os_strcmp(buf, "SUSPEND") == 0) {
+               wpas_notify_suspend(wpa_s->global);
+       } else if (os_strcmp(buf, "RESUME") == 0) {
+               wpas_notify_resume(wpa_s->global);
+       } else if (os_strcmp(buf, "DROP_SA") == 0) {
+               wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
+       } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
+               if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
+                       reply_len = -1;
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -1896,7 +2106,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,
                struct wpa_driver_ops *drv = wpa_drivers[i];
                if (drv->get_interfaces == NULL)
                        continue;
-               tmp = drv->get_interfaces(global->drv_priv);
+               tmp = drv->get_interfaces(global->drv_priv[i]);
                if (tmp == NULL)
                        continue;
 
@@ -1986,7 +2196,11 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                reply_len = wpa_supplicant_global_iface_interfaces(
                        global, reply, reply_size);
        } else if (os_strcmp(buf, "TERMINATE") == 0) {
-               eloop_terminate();
+               wpa_supplicant_terminate_proc(global);
+       } else if (os_strcmp(buf, "SUSPEND") == 0) {
+               wpas_notify_suspend(global);
+       } else if (os_strcmp(buf, "RESUME") == 0) {
+               wpas_notify_resume(global);
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;