/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* See README and COPYING for more details.
*/
-#include "includes.h"
+#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <sys/stat.h>
#include <stddef.h>
-#include "hostapd.h"
-#include "eloop.h"
-#include "config.h"
-#include "ieee802_1x.h"
-#include "wpa.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
#include "radius/radius_client.h"
-#include "ieee802_11.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ieee802_1x.h"
+#include "ap/wpa_auth.h"
+#include "ap/ieee802_11.h"
+#include "ap/sta_info.h"
+#include "ap/accounting.h"
+#include "ap/wps_hostapd.h"
+#include "ap/ctrl_iface_ap.h"
#include "ctrl_iface.h"
-#include "sta_info.h"
-#include "accounting.h"
-#include "wps_hostapd.h"
-#include "drivers/driver.h"
struct wpa_ctrl_dst {
}
-static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
- struct sta_info *sta,
- char *buf, size_t buflen)
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
{
- int len, res, ret;
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
- if (sta == NULL) {
- ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
- return 0;
- return ret;
- }
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
- len = 0;
- ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
- MAC2STR(sta->addr));
- if (ret < 0 || (size_t) ret >= buflen - len)
- return len;
- len += ret;
-
- res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
- if (res >= 0)
- len += res;
- res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
- if (res >= 0)
- len += res;
- res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
- if (res >= 0)
- len += res;
-
- return len;
-}
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ return 0;
-static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
- char *buf, size_t buflen)
-{
- return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
+ wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+ "notification", MAC2STR(addr));
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+
+ hostapd_new_assoc_sta(hapd, sta, 0);
+ return 0;
}
-static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
- const char *txtaddr,
- char *buf, size_t buflen)
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+ u8 minor_reason_code, const u8 *addr)
{
- u8 addr[ETH_ALEN];
+ struct ieee80211_mgmt *mgmt;
int ret;
+ u8 *pos;
- if (hwaddr_aton(txtaddr, addr)) {
- ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
- return 0;
- return ret;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+
+ mgmt = os_zalloc(sizeof(*mgmt) + 100);
+ if (mgmt == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
+ "reason code %u (stype=%u)",
+ MAC2STR(addr), minor_reason_code, stype);
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ if (stype == WLAN_FC_STYPE_DEAUTH) {
+ mgmt->u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+ } else {
+ mgmt->u.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
}
- return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
- buf, buflen);
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 3 + 1;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = P2P_OUI_TYPE;
+
+ *pos++ = P2P_ATTR_MINOR_REASON_CODE;
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ *pos++ = minor_reason_code;
+
+ ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+ pos - (u8 *) mgmt, 1);
+ os_free(mgmt);
+
+ return ret < 0 ? -1 : 0;
}
+#endif /* CONFIG_P2P_MANAGER */
-static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
- const char *txtaddr,
- char *buf, size_t buflen)
+static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+ const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
- int ret;
+ const char *pos;
- if (hwaddr_aton(txtaddr, addr) ||
- (sta = ap_get_sta(hapd, addr)) == NULL) {
- ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
- return 0;
- return ret;
- }
- return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
+ return 0;
+ }
+
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+ return 0;
}
-static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
- const char *txtaddr)
+static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+ const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
+ const char *pos;
- wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
if (hwaddr_aton(txtaddr, addr))
return -1;
- sta = ap_get_sta(hapd, addr);
- if (sta)
+ pos = os_strstr(txtaddr, " test=");
+ if (pos) {
+ struct ieee80211_mgmt mgmt;
+ int encrypt;
+ if (hapd->driver->send_frame == NULL)
+ return -1;
+ pos += 6;
+ encrypt = atoi(pos);
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code =
+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ encrypt) < 0)
+ return -1;
return 0;
+ }
- wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
- "notification", MAC2STR(addr));
- sta = ap_sta_add(hapd, addr);
- if (sta == NULL)
- return -1;
+#ifdef CONFIG_P2P_MANAGER
+ pos = os_strstr(txtaddr, " p2p=");
+ if (pos) {
+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+ atoi(pos + 5), addr);
+ }
+#endif /* CONFIG_P2P_MANAGER */
+
+ hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ ap_sta_disassociate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
- hostapd_new_assoc_sta(hapd, sta, 0);
return 0;
}
#ifdef CONFIG_IEEE80211W
-#ifdef NEED_MLME
+#ifdef NEED_AP_MLME
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
{
wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
- if (hwaddr_aton(txtaddr, addr))
+ if (hwaddr_aton(txtaddr, addr) ||
+ os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
return -1;
- os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
ieee802_11_send_sa_query_req(hapd, addr, trans_id);
return 0;
}
-#endif /* NEED_MLME */
+#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211W */
char *pin = os_strchr(txt, ' ');
char *timeout_txt;
int timeout;
+ u8 addr_buf[ETH_ALEN], *addr = NULL;
+ char *pos;
if (pin == NULL)
return -1;
if (timeout_txt) {
*timeout_txt++ = '\0';
timeout = atoi(timeout_txt);
+ pos = os_strchr(timeout_txt, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ if (hwaddr_aton(pos, addr_buf) == 0)
+ addr = addr_buf;
+ }
} else
timeout = 0;
- return hostapd_wps_add_pin(hapd, txt, pin, timeout);
+ return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
}
return hostapd_wps_start_oob(hapd, txt, path, method, name);
}
#endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
+ char *buf, size_t buflen)
+{
+ int timeout = 300;
+ char *pos;
+ const char *pin_txt;
+
+ pos = os_strchr(txt, ' ');
+ if (pos)
+ *pos++ = '\0';
+
+ if (os_strcmp(txt, "disable") == 0) {
+ hostapd_wps_ap_pin_disable(hapd);
+ return os_snprintf(buf, buflen, "OK\n");
+ }
+
+ if (os_strcmp(txt, "random") == 0) {
+ if (pos)
+ timeout = atoi(pos);
+ pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(txt, "get") == 0) {
+ pin_txt = hostapd_wps_ap_pin_get(hapd);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(txt, "set") == 0) {
+ char *pin;
+ if (pos == NULL)
+ return -1;
+ pin = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ if (os_strlen(pin) > buflen)
+ return -1;
+ if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin);
+ }
+
+ return -1;
+}
#endif /* CONFIG_WPS */
else
reply_len += res;
}
+#ifndef CONFIG_NO_RADIUS
if (reply_len >= 0) {
res = radius_client_get_mib(hapd->radius,
reply + reply_len,
else
reply_len += res;
}
+#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
reply_size);
} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+ if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+ if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
+ reply_len = -1;
#ifdef CONFIG_IEEE80211W
-#ifdef NEED_MLME
+#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
-#endif /* NEED_MLME */
+#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
reply_len = -1;
#endif /* CONFIG_WPS_OOB */
+ } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+ reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
+ reply, reply_size);
#endif /* CONFIG_WPS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
hapd->ctrl_sock = s;
eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
NULL);
+ hapd->msg_ctx = hapd;
wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
return 0;