aboutsummaryrefslogtreecommitdiffstats
path: root/hostapd
diff options
context:
space:
mode:
authorDavid Spinadel <david.spinadel@intel.com>2016-04-06 16:42:07 (GMT)
committerJouni Malinen <j@w1.fi>2016-04-16 18:05:40 (GMT)
commit9b4b226426b169d0e9d0292cd8a0c822df867bd8 (patch)
treeb97014a690339808371632598e4729580345461d /hostapd
parentbf767ac136d15020630dcfc8334105d04233cb57 (diff)
downloadhostap-9b4b226426b169d0e9d0292cd8a0c822df867bd8.zip
hostap-9b4b226426b169d0e9d0292cd8a0c822df867bd8.tar.gz
hostap-9b4b226426b169d0e9d0292cd8a0c822df867bd8.tar.bz2
hostapd: Add a database of neighboring APs
Add a configurable neighbor database that includes the content of Nighbor Report element, LCI and Location Civic subelements and SSID. All parameters for a neighbor must be updated at once; Neighbor Report element and SSID are mandatory, LCI and civic are optional. The age of LCI is set to the time of neighbor update. The control interface API is: SET_NEIGHBOR <BSSID> <ssid=SSID> <nr=data> [lci=<data>] [civic=<data>] To delete a neighbor use: REMOVE_NEIGHBOR <BSSID> <SSID> Signed-off-by: David Spinadel <david.spinadel@intel.com>
Diffstat (limited to 'hostapd')
-rw-r--r--hostapd/Android.mk1
-rw-r--r--hostapd/Makefile1
-rw-r--r--hostapd/ctrl_iface.c124
-rw-r--r--hostapd/hostapd_cli.c45
4 files changed, 171 insertions, 0 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 67ca129..42f67bc 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -96,6 +96,7 @@ OBJS += src/ap/pmksa_cache_auth.c
OBJS += src/ap/ieee802_11_shared.c
OBJS += src/ap/beacon.c
OBJS += src/ap/bss_load.c
+OBJS += src/ap/neighbor_db.c
OBJS_d =
OBJS_p =
LIBS =
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fa4af82..35b055c 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -84,6 +84,7 @@ OBJS += ../src/ap/pmksa_cache_auth.o
OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
+OBJS += ../src/ap/neighbor_db.o
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 6f22f65..dd115df 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -47,6 +47,7 @@
#include "ap/wnm_ap.h"
#include "ap/wpa_auth.h"
#include "ap/beacon.h"
+#include "ap/neighbor_db.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -2071,6 +2072,123 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ struct wpabuf *nr, *lci = NULL, *civic = NULL;
+ char *tmp;
+ int ret;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+ return -1;
+ }
+ buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+ if (!buf)
+ return -1;
+
+ tmp = os_strstr(buf, "nr=");
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+ return -1;
+ }
+
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+
+ nr = wpabuf_parse_bin(tmp + 3);
+ if (!nr) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+ return -1;
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "lci=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ lci = wpabuf_parse_bin(tmp + 4);
+ if (!lci) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+ wpabuf_free(nr);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "civic=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ civic = wpabuf_parse_bin(tmp + 6);
+ if (!civic) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad civic subelement");
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ return -1;
+ }
+ }
+
+set:
+ ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic);
+
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ wpabuf_free(civic);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+ char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ char *tmp;
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
+ return -1;
+ }
+
+ return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -2315,6 +2433,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
hostapd_ctrl_iface_pmksa_flush(hapd);
+ } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
+ if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
+ if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index bf86d37..ec91f7e 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1143,6 +1143,49 @@ static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[2048];
+ int res;
+
+ if (argc < 3 || argc > 5) {
+ printf("Invalid set_neighbor command: needs 3-5 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
+ argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+ argc == 5 ? argv[4] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long SET_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[400];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid remove_neighbor command: needs 2 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REMOVE_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1204,6 +1247,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "log_level", hostapd_cli_cmd_log_level },
{ "pmksa", hostapd_cli_cmd_pmksa },
{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
+ { "set_neighbor", hostapd_cli_cmd_set_neighbor },
+ { "remove_neighbor", hostapd_cli_cmd_remove_neighbor },
{ NULL, NULL }
};