/*
* 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
#include "ap.h"
#include "notify.h"
#include "bss.h"
+#include "scan.h"
#include "ctrl_iface.h"
extern struct wpa_driver_ops *wpa_drivers[];
} 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);
+ } else {
+ value[-1] = '=';
+ ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
+ if (ret == 0)
+ wpa_supplicant_update_config(wpa_s);
+ }
return ret;
}
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
- "address '%s'", peer);
+ "address '%s'", addr);
return -1;
}
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 */
return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
#endif /* CONFIG_AP */
- return wpas_wps_start_pbc(wpa_s, _bssid);
+ return wpas_wps_start_pbc(wpa_s, _bssid, 0);
}
#endif /* CONFIG_AP */
if (pin) {
- ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
+ ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0);
if (ret < 0)
return -1;
ret = os_snprintf(buf, buflen, "%s", pin);
return ret;
}
- ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
+ ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0);
if (ret < 0)
return -1;
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);
}
*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 */
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
- "address '%s'", peer);
+ "address '%s'", addr);
return -1;
}
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;
- 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;
#ifdef CONFIG_WPS
-static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+ char *pos, char *end,
struct wpabuf *wps_ie)
{
int ret;
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
#endif /* CONFIG_WPS */
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
+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(pos, end, wps_ie);
+ 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(
+ struct wpa_supplicant *wpa_s,
const struct wpa_bss *bss, char *buf, size_t buflen)
{
char *pos, *end;
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)
pos += ret;
dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
- ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
+ ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
end - pos);
if (ret < 0 || ret >= end - pos)
return pos - buf;
"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;
+ }
}
wpa_supplicant_select_network(wpa_s, ssid);
"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;
+ }
}
wpa_supplicant_enable_network(wpa_s, ssid);
"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;
+ }
}
wpa_supplicant_disable_network(wpa_s, ssid);
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;
}
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)
}
+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)
{
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) {
} 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);
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))
} 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_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);
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;
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;
global, reply, reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) {
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;