X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fctrl_iface.c;h=6c7b561503fdf1ae117f32eb59893f972ca1bafd;hb=HEAD;hp=98ac08f1e73ade3f51971482310ba4960c766d54;hpb=a8e16edc8638d18b972e2b053d17b54167ce5aa5;p=libeap.git diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 98ac08f..6c7b561 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -12,23 +12,36 @@ * 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 "wps_supplicant.h" +#include "ibss_rsn.h" +#include "ap.h" +#include "p2p_supplicant.h" +#include "p2p/p2p.h" +#include "notify.h" +#include "bss.h" +#include "scan.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" +extern struct wpa_driver_ops *wpa_drivers[]; +static int wpa_supplicant_global_iface_list(struct wpa_global *global, + char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, char *buf, int len); @@ -69,8 +82,37 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) { if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value))) ret = -1; - } else - ret = -1; + } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) { + wpa_s->wps_fragment_size = atoi(value); +#ifdef CONFIG_WPS_TESTING + } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { + long int val; + val = strtol(value, NULL, 0); + if (val < 0 || val > 0xff) { + ret = -1; + wpa_printf(MSG_DEBUG, "WPS: Invalid " + "wps_version_number %ld", val); + } else { + wps_version_number = val; + wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " + "version %u.%u", + (wps_version_number & 0xf0) >> 4, + wps_version_number & 0x0f); + } + } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { + wps_testing_dummy_cred = atoi(value); + wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", + wps_testing_dummy_cred); +#endif /* CONFIG_WPS_TESTING */ + } else if (os_strcasecmp(cmd, "ampdu") == 0) { + if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0) + ret = -1; + } else { + value[-1] = '='; + ret = wpa_config_process_global(wpa_s->conf, cmd, -1); + if (ret == 0) + wpa_supplicant_update_config(wpa_s); + } return ret; } @@ -108,7 +150,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; } @@ -125,20 +167,322 @@ 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 */ +#ifdef CONFIG_WPS +static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, + char *cmd) +{ + u8 bssid[ETH_ALEN], *_bssid = bssid; + + if (cmd == NULL || os_strcmp(cmd, "any") == 0) + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", + cmd); + return -1; + } + +#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, 0); +} + + +static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s, + char *cmd, char *buf, + size_t buflen) +{ + u8 bssid[ETH_ALEN], *_bssid = bssid; + char *pin; + int ret; + + pin = os_strchr(cmd, ' '); + if (pin) + *pin++ = '\0'; + + if (os_strcmp(cmd, "any") == 0) + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'", + cmd); + 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, 0, + DEV_PW_DEFAULT); + if (ret < 0) + return -1; + ret = os_snprintf(buf, buflen, "%s", pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + + ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT); + if (ret < 0) + return -1; + + /* Return the generated PIN */ + ret = os_snprintf(buf, buflen, "%08d", ret); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpa_supplicant_ctrl_iface_wps_check_pin( + struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) +{ + char pin[9]; + size_t len; + char *pos; + int ret; + + wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", + (u8 *) cmd, os_strlen(cmd)); + for (pos = cmd, len = 0; *pos != '\0'; pos++) { + if (*pos < '0' || *pos > '9') + continue; + pin[len++] = *pos; + if (len == 9) { + wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); + return -1; + } + } + if (len != 4 && len != 8) { + wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); + return -1; + } + pin[len] = '\0'; + + if (len == 8) { + unsigned int pin_val; + pin_val = atoi(pin); + if (!wps_pin_valid(pin_val)) { + wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); + ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + } + + ret = os_snprintf(buf, buflen, "%s", pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + + return ret; +} + + +#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) + return -1; + *pin++ = '\0'; + + if (os_strcmp(cmd, "any") == 0) + _bssid = NULL; + else if (hwaddr_aton(cmd, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'", + cmd); + return -1; + } + + 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, *pos; + u8 addr_buf[ETH_ALEN], *addr = NULL; + pin = os_strchr(uuid, ' '); + if (pin == NULL) + return -1; + *pin++ = '\0'; + 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); +} + + +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); +} + + +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 */ + + +#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'", addr); + 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) { @@ -267,8 +611,45 @@ 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; + case WPAS_MODE_P2P_GO: + ret = os_snprintf(pos, end - pos, + "mode=P2P GO\n"); + break; + case WPAS_MODE_P2P_GROUP_FORMATION: + ret = os_snprintf(pos, end - pos, + "mode=P2P GO - group " + "formation\n"); + break; + default: + ret = 0; + break; + } + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; } +#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", @@ -285,9 +666,24 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } - if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || - wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA || - wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { +#ifdef CONFIG_P2P + if (wpa_s->global->p2p) { + ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR + "\n", MAC2STR(wpa_s->global->p2p_dev_addr)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + + ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n", + MAC2STR(wpa_s->own_addr)); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; +#endif /* CONFIG_P2P */ + + if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) || + wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, verbose); if (res >= 0) @@ -368,10 +764,12 @@ static int wpa_supplicant_ctrl_iface_list_networks( if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; - ret = os_snprintf(pos, end - pos, "\t%s%s", + ret = os_snprintf(pos, end - pos, "\t%s%s%s", ssid == wpa_s->current_ssid ? "[CURRENT]" : "", - ssid->disabled ? "[DISABLED]" : ""); + ssid->disabled ? "[DISABLED]" : "", + ssid->disabled == 2 ? "[P2P-PERSISTENT]" : + ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; @@ -493,6 +891,24 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, first = 0; } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { + ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } + if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { + ret = os_snprintf(pos, end - pos, "%sPSK-SHA256", + first ? "" : "+"); + if (ret < 0 || ret >= end - pos) + return pos; + pos += ret; + first = 0; + } +#endif /* CONFIG_IEEE80211W */ pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); @@ -512,44 +928,107 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, } +#ifdef CONFIG_WPS +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; + + if (wps_ie == NULL) + return pos; + if (wps_is_selected_pbc_registrar(wps_ie)) + txt = "[WPS-PBC]"; +#ifdef CONFIG_WPS2 + else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0)) + txt = "[WPS-AUTH]"; +#endif /* CONFIG_WPS2 */ + else if (wps_is_selected_pin_registrar(wps_ie)) + txt = "[WPS-PIN]"; + else + txt = "[WPS]"; + + ret = os_snprintf(pos, end - pos, "%s", txt); + 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; - const u8 *ie, *ie2; + const u8 *ie, *ie2, *p2p; + + p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); + if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN && + os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == + 0) + return 0; /* Do not show P2P listen discovery results here */ pos = buf; 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]); - 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; + } + if (p2p) { + ret = os_snprintf(pos, end - pos, "[P2P]"); + 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; @@ -567,13 +1046,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; @@ -583,9 +1057,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; @@ -605,37 +1078,25 @@ static int wpa_supplicant_ctrl_iface_select_network( /* cmd: "" 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->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "SELECT_NETWORK with persistent P2P group"); + 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; } @@ -650,36 +1111,24 @@ static int wpa_supplicant_ctrl_iface_enable_network( /* cmd: "" 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; + } + if (ssid->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "ENABLE_NETWORK with persistent P2P group"); + return -1; + } } - ssid->disabled = 0; + wpa_supplicant_enable_network(wpa_s, ssid); return 0; } @@ -694,33 +1143,28 @@ static int wpa_supplicant_ctrl_iface_disable_network( /* cmd: "" 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; + 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; + } + if (ssid->disabled == 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use " + "DISABLE_NETWORK with persistent P2P " + "group"); + return -1; } - if (wpa_s->current_ssid) - wpa_supplicant_disassociate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); - return 0; } + wpa_supplicant_disable_network(wpa_s, ssid); - 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; - } - - if (ssid == wpa_s->current_ssid) - wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - ssid->disabled = 1; - - return 0; -} + return 0; +} static int wpa_supplicant_ctrl_iface_add_network( @@ -734,6 +1178,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); @@ -755,8 +1202,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) { @@ -841,6 +1290,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; } @@ -1227,57 +1678,81 @@ 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; - 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 = snprintf(pos, end - pos, - "bssid=" MACSTR "\n" - "freq=%d\n" - "beacon_int=%d\n" - "capabilities=0x%04x\n" - "qual=%d\n" - "noise=%d\n" - "level=%d\n" - "tsf=%016llu\n" - "ie=", - MAC2STR(bss->bssid), bss->freq, bss->beacon_int, - bss->caps, bss->qual, bss->noise, bss->level, - (unsigned long long) bss->tsf); + ret = os_snprintf(pos, end - pos, + "id=%u\n" + "bssid=" MACSTR "\n" + "freq=%d\n" + "beacon_int=%d\n" + "capabilities=0x%04x\n" + "qual=%d\n" + "noise=%d\n" + "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); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ie = (const u8 *) (bss + 1); for (i = 0; i < bss->ie_len; i++) { - ret = snprintf(pos, end - pos, "%02x", *ie++); + ret = os_snprintf(pos, end - pos, "%02x", *ie++); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + } + if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) { + ret = os_snprintf(pos, end - pos, "[P2P]"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } - ret = snprintf(pos, end - pos, "\n"); + ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; @@ -1287,12 +1762,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(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) @@ -1305,18 +1781,39 @@ 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 = snprintf(pos, end - pos, "\n"); + 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; + +#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 */ + +#ifdef CONFIG_P2P + ie = (const u8 *) (bss + 1); + ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; +#endif /* CONFIG_P2P */ return pos - buf; } @@ -1326,225 +1823,1244 @@ static int wpa_supplicant_ctrl_iface_ap_scan( struct wpa_supplicant *wpa_s, char *cmd) { int ap_scan = atoi(cmd); + return wpa_supplicant_set_ap_scan(wpa_s, ap_scan); +} - if (ap_scan < 0 || ap_scan > 2) - return -1; - wpa_s->conf->ap_scan = ap_scan; - return 0; + +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); } -char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, - char *buf, size_t *resp_len) +static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s, + char *addr) { - char *reply; - const int reply_size = 2048; - int ctrl_rsp = 0; - int reply_len; + u8 bssid[ETH_ALEN]; + struct wpa_bss *bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; - if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || - os_strncmp(buf, "SET_NETWORK ", 12) == 0) { - wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", - (const u8 *) buf, os_strlen(buf)); - } else { - wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", - (const u8 *) buf, os_strlen(buf)); + if (hwaddr_aton(addr, bssid)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid " + "address '%s'", addr); + return -1; } - reply = os_malloc(reply_size); - if (reply == NULL) { - *resp_len = 1; - return NULL; + 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; } - os_memcpy(reply, "OK\n", 3); - reply_len = 3; + /* + * TODO: Find best network configuration block from configuration to + * allow roaming to other networks + */ - if (os_strcmp(buf, "PING") == 0) { - os_memcpy(reply, "PONG\n", 5); - reply_len = 5; - } else if (os_strcmp(buf, "MIB") == 0) { - reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); - if (reply_len >= 0) { - int res; - res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, - reply_size - reply_len); - if (res < 0) - reply_len = -1; - else - reply_len += res; - } - } else if (os_strncmp(buf, "STATUS", 6) == 0) { - 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); - } else if (os_strncmp(buf, "SET ", 4) == 0) { - if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) - reply_len = -1; - } else if (os_strcmp(buf, "LOGON") == 0) { - eapol_sm_notify_logoff(wpa_s->eapol, FALSE); - } 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); - } else if (os_strcmp(buf, "RECONNECT") == 0) { - if (wpa_s->disconnected) { - wpa_s->disconnected = 0; - wpa_s->reassociate = 1; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } -#ifdef IEEE8021X_EAPOL - } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { - if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) - reply_len = -1; -#endif /* IEEE8021X_EAPOL */ -#ifdef CONFIG_PEERKEY - } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { - if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) - reply_len = -1; -#endif /* CONFIG_PEERKEY */ -#ifdef CONFIG_IEEE80211R - } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { - if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) - reply_len = -1; -#endif /* CONFIG_IEEE80211R */ - } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) - { - if (wpa_supplicant_ctrl_iface_ctrl_rsp( - wpa_s, buf + os_strlen(WPA_CTRL_RSP))) - reply_len = -1; - else - ctrl_rsp = 1; - } else if (os_strcmp(buf, "RECONFIGURE") == 0) { - if (wpa_supplicant_reload_configuration(wpa_s)) - reply_len = -1; - } else if (os_strcmp(buf, "TERMINATE") == 0) { - eloop_terminate(); - } else if (os_strncmp(buf, "BSSID ", 6) == 0) { - if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6)) - reply_len = -1; - } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { - reply_len = wpa_supplicant_ctrl_iface_list_networks( - wpa_s, reply, reply_size); - } else if (os_strcmp(buf, "DISCONNECT") == 0) { - wpa_s->reassociate = 0; - wpa_s->disconnected = 1; - wpa_supplicant_disassociate(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); - } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { - reply_len = wpa_supplicant_ctrl_iface_scan_results( - wpa_s, reply, reply_size); - } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { - if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) - reply_len = -1; - } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { - if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) - reply_len = -1; - } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { - if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) - reply_len = -1; - } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { - reply_len = wpa_supplicant_ctrl_iface_add_network( - wpa_s, reply, reply_size); - } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { - if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) - reply_len = -1; - } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { - if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) - reply_len = -1; - } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { - reply_len = wpa_supplicant_ctrl_iface_get_network( - wpa_s, buf + 12, reply, reply_size); -#ifndef CONFIG_NO_CONFIG_WRITE - } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { - if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) - reply_len = -1; -#endif /* CONFIG_NO_CONFIG_WRITE */ - } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { - reply_len = wpa_supplicant_ctrl_iface_get_capability( - wpa_s, buf + 15, reply, reply_size); - } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { - if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) - reply_len = -1; - } else if (os_strcmp(buf, "INTERFACES") == 0) { - reply_len = wpa_supplicant_global_iface_interfaces( - wpa_s->global, reply, reply_size); - } else if (os_strncmp(buf, "BSS ", 4) == 0) { - reply_len = wpa_supplicant_ctrl_iface_bss( - wpa_s, buf + 4, reply, reply_size); - } else { - os_memcpy(reply, "UNKNOWN COMMAND\n", 16); - reply_len = 16; + if (!ssid) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network " + "configuration known for the target AP"); + return -1; } - if (reply_len < 0) { - os_memcpy(reply, "FAIL\n", 5); - reply_len = 5; - } + wpa_s->reassociate = 1; + wpa_supplicant_connect(wpa_s, bss, ssid); - if (ctrl_rsp) - eapol_sm_notify_ctrl_response(wpa_s->eapol); + return 0; +} - *resp_len = reply_len; - return reply; + +#ifdef CONFIG_P2P +static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd) +{ + unsigned int timeout = atoi(cmd); + enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL; + + if (os_strstr(cmd, "type=social")) + type = P2P_FIND_ONLY_SOCIAL; + else if (os_strstr(cmd, "type=progressive")) + type = P2P_FIND_PROGRESSIVE; + + wpas_p2p_find(wpa_s, timeout, type); + return 0; } -static int wpa_supplicant_global_iface_add(struct wpa_global *global, - char *cmd) +static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) { - struct wpa_interface iface; - char *pos; + u8 addr[ETH_ALEN]; + char *pos, *pos2; + char *pin = NULL; + enum p2p_wps_method wps_method; + int new_pin; + int ret; + int persistent_group; + int join; + int auth; + int go_intent = -1; + int freq = 0; - /* - * TABTABTABTAB - * TAB - */ - wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); + /* <"pbc" | "pin" | PIN> [label|display|keypad] [persistent] + * [join] [auth] [go_intent=<0..15>] [freq=] */ - os_memset(&iface, 0, sizeof(iface)); + if (hwaddr_aton(cmd, addr)) + return -1; - do { - iface.ifname = pos = cmd; - pos = os_strchr(pos, '\t'); - if (pos) - *pos++ = '\0'; - if (iface.ifname[0] == '\0') + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + persistent_group = os_strstr(pos, " persistent") != NULL; + join = os_strstr(pos, " join") != NULL; + auth = os_strstr(pos, " auth") != NULL; + + pos2 = os_strstr(pos, " go_intent="); + if (pos2) { + pos2 += 11; + go_intent = atoi(pos2); + if (go_intent < 0 || go_intent > 15) return -1; - if (pos == NULL) - break; + } - iface.confname = pos; - pos = os_strchr(pos, '\t'); - if (pos) - *pos++ = '\0'; - if (iface.confname[0] == '\0') - iface.confname = NULL; - if (pos == NULL) - break; + pos2 = os_strstr(pos, " freq="); + if (pos2) { + pos2 += 6; + freq = atoi(pos2); + if (freq <= 0) + return -1; + } - iface.driver = pos; - pos = os_strchr(pos, '\t'); - if (pos) + if (os_strncmp(pos, "pin", 3) == 0) { + /* Request random PIN (to be displayed) and enable the PIN */ + wps_method = WPS_PIN_DISPLAY; + } else if (os_strncmp(pos, "pbc", 3) == 0) { + wps_method = WPS_PBC; + } else { + pin = pos; + pos = os_strchr(pin, ' '); + wps_method = WPS_PIN_KEYPAD; + if (pos) { *pos++ = '\0'; - if (iface.driver[0] == '\0') - iface.driver = NULL; - if (pos == NULL) - break; + if (os_strncmp(pos, "label", 5) == 0) + wps_method = WPS_PIN_LABEL; + else if (os_strncmp(pos, "display", 7) == 0) + wps_method = WPS_PIN_DISPLAY; + } + } - iface.ctrl_interface = pos; - pos = os_strchr(pos, '\t'); - if (pos) - *pos++ = '\0'; - if (iface.ctrl_interface[0] == '\0') - iface.ctrl_interface = NULL; - if (pos == NULL) - break; + new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, + persistent_group, join, auth, go_intent, + freq); + if (new_pin == -2) { + os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); + return 25; + } + if (new_pin == -3) { + os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25); + return 25; + } + if (new_pin < 0) + return -1; + if (wps_method == WPS_PIN_DISPLAY && pin == NULL) { + ret = os_snprintf(buf, buflen, "%08d", new_pin); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; + } + + os_memcpy(buf, "OK\n", 3); + return 3; +} + + +static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd) +{ + unsigned int timeout = atoi(cmd); + return wpas_p2p_listen(wpa_s, timeout); +} + + +static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + char *pos; + + /* */ + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + return wpas_p2p_prov_disc(wpa_s, addr, pos); +} + + +static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf, + size_t buflen) +{ + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO || + ssid->passphrase == NULL) + return -1; + + os_strlcpy(buf, ssid->passphrase, buflen); + return os_strlen(buf); +} + + +static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + u64 ref; + int res; + u8 dst_buf[ETH_ALEN], *dst; + struct wpabuf *tlvs; + char *pos; + size_t len; + + if (hwaddr_aton(cmd, dst_buf)) + return -1; + dst = dst_buf; + if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) + dst = NULL; + pos = cmd + 17; + if (*pos != ' ') + return -1; + pos++; + + if (os_strncmp(pos, "upnp ", 5) == 0) { + u8 version; + pos += 5; + if (hexstr2bin(pos, &version, 1) < 0) + return -1; + pos += 2; + if (*pos != ' ') + return -1; + pos++; + ref = (u64) wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos); + } else { + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + tlvs = wpabuf_alloc(len); + if (tlvs == NULL) + return -1; + if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) { + wpabuf_free(tlvs); + return -1; + } + + ref = (u64) wpas_p2p_sd_request(wpa_s, dst, tlvs); + wpabuf_free(tlvs); + } + res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref); + if (res < 0 || (unsigned) res >= buflen) + return -1; + return res; +} + + +static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s, + char *cmd) +{ + long long unsigned val; + u64 req; + if (sscanf(cmd, "%llx", &val) != 1) + return -1; + req = val; + return wpas_p2p_sd_cancel_request(wpa_s, (void *) req); +} + + +static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq; + u8 dst_buf[ETH_ALEN], *dst; + u8 dialog_token; + struct wpabuf *resp_tlvs; + char *pos, *pos2; + size_t len; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + freq = atoi(cmd); + if (freq == 0) + return -1; + + if (hwaddr_aton(pos, dst_buf)) + return -1; + dst = dst_buf; + if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) + dst = NULL; + pos += 17; + if (*pos != ' ') + return -1; + pos++; + + pos2 = os_strchr(pos, ' '); + if (pos2 == NULL) + return -1; + *pos2++ = '\0'; + dialog_token = atoi(pos); + + len = os_strlen(pos2); + if (len & 1) + return -1; + len /= 2; + resp_tlvs = wpabuf_alloc(len); + if (resp_tlvs == NULL) + return -1; + if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) { + wpabuf_free(resp_tlvs); + return -1; + } + + wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs); + wpabuf_free(resp_tlvs); + return 0; +} + + +static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s, + char *cmd) +{ + wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd); + return 0; +} + + +static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *pos; + size_t len; + struct wpabuf *query, *resp; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + query = wpabuf_alloc(len); + if (query == NULL) + return -1; + if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { + wpabuf_free(query); + return -1; + } + + len = os_strlen(pos); + if (len & 1) { + wpabuf_free(query); + return -1; + } + len /= 2; + resp = wpabuf_alloc(len); + if (resp == NULL) { + wpabuf_free(query); + return -1; + } + if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { + wpabuf_free(query); + wpabuf_free(resp); + return -1; + } + + if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { + wpabuf_free(query); + wpabuf_free(resp); + return -1; + } + return 0; +} + + +static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 version; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (hexstr2bin(cmd, &version, 1) < 0) + return -1; + + return wpas_p2p_service_add_upnp(wpa_s, version, pos); +} + + +static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (os_strcmp(cmd, "bonjour") == 0) + return p2p_ctrl_service_add_bonjour(wpa_s, pos); + if (os_strcmp(cmd, "upnp") == 0) + return p2p_ctrl_service_add_upnp(wpa_s, pos); + wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); + return -1; +} + + +static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s, + char *cmd) +{ + size_t len; + struct wpabuf *query; + int ret; + + len = os_strlen(cmd); + if (len & 1) + return -1; + len /= 2; + query = wpabuf_alloc(len); + if (query == NULL) + return -1; + if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { + wpabuf_free(query); + return -1; + } + + ret = wpas_p2p_service_del_bonjour(wpa_s, query); + wpabuf_free(query); + return ret; +} + + +static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 version; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (hexstr2bin(cmd, &version, 1) < 0) + return -1; + + return wpas_p2p_service_del_upnp(wpa_s, version, pos); +} + + +static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + if (os_strcmp(cmd, "bonjour") == 0) + return p2p_ctrl_service_del_bonjour(wpa_s, pos); + if (os_strcmp(cmd, "upnp") == 0) + return p2p_ctrl_service_del_upnp(wpa_s, pos); + wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd); + return -1; +} + + +static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd) +{ + u8 addr[ETH_ALEN]; + + /* */ + + if (hwaddr_aton(cmd, addr)) + return -1; + + return wpas_p2p_reject(wpa_s, addr); +} + + +static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + int id; + struct wpa_ssid *ssid; + u8 peer[ETH_ALEN]; + + id = atoi(cmd); + pos = os_strstr(cmd, " peer="); + if (pos) { + pos += 6; + if (hwaddr_aton(pos, peer)) + return -1; + } + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL || ssid->disabled != 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "for persistent P2P group", + id); + return -1; + } + + return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL); +} + + +static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL; + + pos = os_strstr(cmd, " peer="); + if (!pos) + return -1; + + *pos = '\0'; + pos += 6; + if (hwaddr_aton(pos, peer)) { + wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos); + return -1; + } + + pos = os_strstr(pos, " go_dev_addr="); + if (pos) { + pos += 13; + if (hwaddr_aton(pos, go_dev_addr)) { + wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", + pos); + return -1; + } + go_dev = go_dev_addr; + } + + return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev); +} + + +static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) +{ + if (os_strncmp(cmd, "persistent=", 11) == 0) + return p2p_ctrl_invite_persistent(wpa_s, cmd + 11); + if (os_strncmp(cmd, "group=", 6) == 0) + return p2p_ctrl_invite_group(wpa_s, cmd + 6); + + return -1; +} + + +static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, + char *cmd, int freq) +{ + int id; + struct wpa_ssid *ssid; + + id = atoi(cmd); + ssid = wpa_config_get_network(wpa_s->conf, id); + if (ssid == NULL || ssid->disabled != 2) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " + "for persistent P2P group", + id); + return -1; + } + + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq); +} + + +static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) +{ + int freq = 0; + char *pos; + + pos = os_strstr(cmd, "freq="); + if (pos) + freq = atoi(pos + 5); + + if (os_strncmp(cmd, "persistent=", 11) == 0) + return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq); + if (os_strcmp(cmd, "persistent") == 0 || + os_strncmp(cmd, "persistent ", 11) == 0) + return wpas_p2p_group_add(wpa_s, 1, freq); + if (os_strncmp(cmd, "freq=", 5) == 0) + return wpas_p2p_group_add(wpa_s, 0, freq); + + wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'", + cmd); + return -1; +} + + +static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + u8 addr[ETH_ALEN], *addr_ptr; + int next; + + if (!wpa_s->global->p2p) + return -1; + + if (os_strcmp(cmd, "FIRST") == 0) { + addr_ptr = NULL; + next = 0; + } else if (os_strncmp(cmd, "NEXT-", 5) == 0) { + if (hwaddr_aton(cmd + 5, addr) < 0) + return -1; + addr_ptr = addr; + next = 1; + } else { + if (hwaddr_aton(cmd, addr) < 0) + return -1; + addr_ptr = addr; + next = 0; + } + + return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next, + buf, buflen); +} + + +static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *param; + + if (wpa_s->global->p2p == NULL) + return -1; + + param = os_strchr(cmd, ' '); + if (param == NULL) + return -1; + *param++ = '\0'; + + if (os_strcmp(cmd, "discoverability") == 0) { + p2p_set_client_discoverability(wpa_s->global->p2p, + atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "managed") == 0) { + p2p_set_managed_oper(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "listen_channel") == 0) { + return p2p_set_listen_channel(wpa_s->global->p2p, 81, + atoi(param)); + } + + if (os_strcmp(cmd, "ssid_postfix") == 0) { + return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param, + os_strlen(param)); + } + + if (os_strcmp(cmd, "noa") == 0) { + char *pos; + int count, start, duration; + /* GO NoA parameters: count,start_offset(ms),duration(ms) */ + count = atoi(param); + pos = os_strchr(param, ','); + if (pos == NULL) + return -1; + pos++; + start = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + duration = atoi(pos); + if (count < 0 || count > 255 || start < 0 || duration < 0) + return -1; + if (count == 0 && duration > 0) + return -1; + wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d " + "start=%d duration=%d", count, start, duration); + return wpas_p2p_set_noa(wpa_s, count, start, duration); + } + + if (os_strcmp(cmd, "ps") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1); + + if (os_strcmp(cmd, "oppps") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1); + + if (os_strcmp(cmd, "ctwindow") == 0) + return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param)); + + if (os_strcmp(cmd, "disabled") == 0) { + wpa_s->global->p2p_disabled = atoi(param); + wpa_printf(MSG_DEBUG, "P2P functionality %s", + wpa_s->global->p2p_disabled ? + "disabled" : "enabled"); + if (wpa_s->global->p2p_disabled) { + wpas_p2p_stop_find(wpa_s); + os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); + p2p_flush(wpa_s->global->p2p); + } + return 0; + } + + if (os_strcmp(cmd, "force_long_sd") == 0) { + wpa_s->force_long_sd = atoi(param); + return 0; + } + + if (os_strcmp(cmd, "peer_filter") == 0) { + u8 addr[ETH_ALEN]; + if (hwaddr_aton(param, addr)) + return -1; + p2p_set_peer_filter(wpa_s->global->p2p, addr); + return 0; + } + + if (os_strcmp(cmd, "cross_connect") == 0) + return wpas_p2p_set_cross_connect(wpa_s, atoi(param)); + + if (os_strcmp(cmd, "go_apsd") == 0) { + if (os_strcmp(param, "disable") == 0) + wpa_s->set_ap_uapsd = 0; + else { + wpa_s->set_ap_uapsd = 1; + wpa_s->ap_uapsd = atoi(param); + } + return 0; + } + + if (os_strcmp(cmd, "client_apsd") == 0) { + if (os_strcmp(param, "disable") == 0) + wpa_s->set_sta_uapsd = 0; + else { + int be, bk, vi, vo; + char *pos; + /* format: BE,BK,VI,VO;max SP Length */ + be = atoi(param); + pos = os_strchr(param, ','); + if (pos == NULL) + return -1; + pos++; + bk = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + vi = atoi(pos); + pos = os_strchr(pos, ','); + if (pos == NULL) + return -1; + pos++; + vo = atoi(pos); + /* ignore max SP Length for now */ + + wpa_s->set_sta_uapsd = 1; + wpa_s->sta_uapsd = 0; + if (be) + wpa_s->sta_uapsd |= BIT(0); + if (bk) + wpa_s->sta_uapsd |= BIT(1); + if (vi) + wpa_s->sta_uapsd |= BIT(2); + if (vo) + wpa_s->sta_uapsd |= BIT(3); + } + return 0; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", + cmd); + + return -1; +} + + +static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos, *pos2; + unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; + + if (cmd[0]) { + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + dur1 = atoi(cmd); + + pos2 = os_strchr(pos, ' '); + if (pos2) + *pos2++ = '\0'; + int1 = atoi(pos); + } else + pos2 = NULL; + + if (pos2) { + pos = os_strchr(pos2, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + dur2 = atoi(pos2); + int2 = atoi(pos); + } + + return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2); +} + + +static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + unsigned int period = 0, interval = 0; + + if (cmd[0]) { + pos = os_strchr(cmd, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + period = atoi(cmd); + interval = atoi(pos); + } + + return wpas_p2p_ext_listen(wpa_s, period, interval); +} + +#endif /* CONFIG_P2P */ + + +static int wpa_supplicant_ctrl_iface_sta_autoconnect( + struct wpa_supplicant *wpa_s, char *cmd) +{ + wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0; + return 0; +} + + +char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, + char *buf, size_t *resp_len) +{ + char *reply; + const int reply_size = 4096; + int ctrl_rsp = 0; + int reply_len; + + if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 || + os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface", + (const u8 *) buf, os_strlen(buf)); + } else { + int level = MSG_DEBUG; + if (os_strcmp(buf, "PING") == 0) + level = MSG_EXCESSIVE; + wpa_hexdump_ascii(level, "RX ctrl_iface", + (const u8 *) buf, os_strlen(buf)); + } + + reply = os_malloc(reply_size); + if (reply == NULL) { + *resp_len = 1; + return NULL; + } + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + 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) { + int res; + res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len, + reply_size - reply_len); + if (res < 0) + reply_len = -1; + else + reply_len += res; + } + } else if (os_strncmp(buf, "STATUS", 6) == 0) { + reply_len = wpa_supplicant_ctrl_iface_status( + wpa_s, buf + 6, reply, reply_size); + } else if (os_strcmp(buf, "PMKSA") == 0) { + 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; + } else if (os_strcmp(buf, "LOGON") == 0) { + eapol_sm_notify_logoff(wpa_s->eapol, FALSE); + } else if (os_strcmp(buf, "LOGOFF") == 0) { + eapol_sm_notify_logoff(wpa_s->eapol, TRUE); + } else if (os_strcmp(buf, "REASSOCIATE") == 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->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); + } +#ifdef IEEE8021X_EAPOL + } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8)) + reply_len = -1; +#endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_PEERKEY + } else if (os_strncmp(buf, "STKSTART ", 9) == 0) { + if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9)) + reply_len = -1; +#endif /* CONFIG_PEERKEY */ +#ifdef CONFIG_IEEE80211R + } else if (os_strncmp(buf, "FT_DS ", 6) == 0) { + if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6)) + reply_len = -1; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_WPS + } else if (os_strcmp(buf, "WPS_PBC") == 0) { + if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL)) + reply_len = -1; + } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8)) + reply_len = -1; + } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { + reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8, + reply, + reply_size); + } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { + reply_len = wpa_supplicant_ctrl_iface_wps_check_pin( + wpa_s, buf + 14, reply, reply_size); + } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { + if (wpas_wps_cancel(wpa_s)) + reply_len = -1; +#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; +#ifdef CONFIG_WPS_ER + } else if (os_strcmp(buf, "WPS_ER_START") == 0) { + 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)) + 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; + } 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 + } 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 */ +#ifdef CONFIG_P2P + } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) { + if (p2p_ctrl_find(wpa_s, buf + 9)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_FIND") == 0) { + if (p2p_ctrl_find(wpa_s, "")) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) { + wpas_p2p_stop_find(wpa_s); + } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) { + reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) { + if (p2p_ctrl_listen(wpa_s, buf + 11)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_LISTEN") == 0) { + if (p2p_ctrl_listen(wpa_s, "")) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) { + if (wpas_p2p_group_remove(wpa_s, buf + 17)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { + if (wpas_p2p_group_add(wpa_s, 0, 0)) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) { + if (p2p_ctrl_group_add(wpa_s, buf + 14)) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) { + if (p2p_ctrl_prov_disc(wpa_s, buf + 14)) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { + reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { + reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) { + if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) { + if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) { + wpas_p2p_sd_service_update(wpa_s); + } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) { + if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) { + wpas_p2p_service_flush(wpa_s); + } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) { + if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) { + if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) { + if (p2p_ctrl_reject(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) { + if (p2p_ctrl_invite(wpa_s, buf + 11) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) { + reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply, + reply_size); + } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) { + if (p2p_ctrl_set(wpa_s, buf + 8) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_FLUSH") == 0) { + os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); + wpa_s->force_long_sd = 0; + p2p_flush(wpa_s->global->p2p); + } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) { + if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) { + if (p2p_ctrl_presence_req(wpa_s, "") < 0) + reply_len = -1; + } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) { + if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) { + if (p2p_ctrl_ext_listen(wpa_s, "") < 0) + reply_len = -1; +#endif /* CONFIG_P2P */ + } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) + { + if (wpa_supplicant_ctrl_iface_ctrl_rsp( + wpa_s, buf + os_strlen(WPA_CTRL_RSP))) + reply_len = -1; + else + ctrl_rsp = 1; + } else if (os_strcmp(buf, "RECONFIGURE") == 0) { + if (wpa_supplicant_reload_configuration(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf, "TERMINATE") == 0) { + 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; + } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) { + reply_len = wpa_supplicant_ctrl_iface_list_networks( + wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "DISCONNECT") == 0) { + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + } else if (os_strcmp(buf, "SCAN") == 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); + } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) { + if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16)) + reply_len = -1; + } else if (os_strcmp(buf, "ADD_NETWORK") == 0) { + reply_len = wpa_supplicant_ctrl_iface_add_network( + wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) { + if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12)) + reply_len = -1; + } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { + reply_len = wpa_supplicant_ctrl_iface_get_network( + wpa_s, buf + 12, reply, reply_size); +#ifndef CONFIG_NO_CONFIG_WRITE + } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { + if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) + reply_len = -1; +#endif /* CONFIG_NO_CONFIG_WRITE */ + } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { + reply_len = wpa_supplicant_ctrl_iface_get_capability( + wpa_s, buf + 15, reply, reply_size); + } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) { + if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8)) + reply_len = -1; + } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { + reply_len = wpa_supplicant_global_iface_list( + wpa_s->global, reply, reply_size); + } else if (os_strcmp(buf, "INTERFACES") == 0) { + reply_len = wpa_supplicant_global_iface_interfaces( + wpa_s->global, reply, reply_size); + } 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 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 if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { + if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16)) + reply_len = -1; + } else { + os_memcpy(reply, "UNKNOWN COMMAND\n", 16); + reply_len = 16; + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + if (ctrl_rsp) + eapol_sm_notify_ctrl_response(wpa_s->eapol); + + *resp_len = reply_len; + return reply; +} + + +static int wpa_supplicant_global_iface_add(struct wpa_global *global, + char *cmd) +{ + struct wpa_interface iface; + char *pos; + + /* + * TABTABTABTAB + * TAB + */ + wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); + + os_memset(&iface, 0, sizeof(iface)); + + do { + iface.ifname = pos = cmd; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.ifname[0] == '\0') + return -1; + if (pos == NULL) + break; + + iface.confname = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.confname[0] == '\0') + iface.confname = NULL; + if (pos == NULL) + break; + + iface.driver = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.driver[0] == '\0') + iface.driver = NULL; + if (pos == NULL) + break; + + iface.ctrl_interface = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (iface.ctrl_interface[0] == '\0') + iface.ctrl_interface = NULL; + if (pos == NULL) + break; iface.driver_param = pos; pos = os_strchr(pos, '\t'); @@ -1586,6 +3102,63 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global, } +static void wpa_free_iface_info(struct wpa_interface_info *iface) +{ + struct wpa_interface_info *prev; + + while (iface) { + prev = iface; + iface = iface->next; + + os_free(prev->ifname); + os_free(prev->desc); + os_free(prev); + } +} + + +static int wpa_supplicant_global_iface_list(struct wpa_global *global, + char *buf, int len) +{ + int i, res; + struct wpa_interface_info *iface = NULL, *last = NULL, *tmp; + char *pos, *end; + + 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[i]); + if (tmp == NULL) + continue; + + if (last == NULL) + iface = last = tmp; + else + last->next = tmp; + while (last->next) + last = last->next; + } + + pos = buf; + end = buf + len; + for (tmp = iface; tmp; tmp = tmp->next) { + res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n", + tmp->drv_name, tmp->ifname, + tmp->desc ? tmp->desc : ""); + if (res < 0 || res >= end - pos) { + *pos = '\0'; + break; + } + pos += res; + } + + wpa_free_iface_info(iface); + + return pos - buf; +} + + static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, char *buf, int len) { @@ -1638,11 +3211,18 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { if (wpa_supplicant_global_iface_remove(global, buf + 17)) reply_len = -1; + } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { + reply_len = wpa_supplicant_global_iface_list( + global, reply, reply_size); } else if (os_strcmp(buf, "INTERFACES") == 0) { 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;