[PATCH v3 07/19] hostapd: Add neighboring APs DB

Ilan Peer ilan.peer at intel.com
Wed Apr 6 09:42:07 PDT 2016


From: David Spinadel <david.spinadel at intel.com>

Add a configurable neighbor DB that includes the content of neighbor
report IE, LCI and location civic subelements and SSID.

All neighbor's parameters must be updated at once; neighbor report IE
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_neigbor:
remove_neighbor <BSSID> <SSID>

Signed-off-by: David Spinadel <david.spinadel at intel.com>
---
 hostapd/Android.mk        |   1 +
 hostapd/Makefile          |   1 +
 hostapd/ctrl_iface.c      | 130 ++++++++++++++++++++++++++++++++++++++++++++++
 hostapd/hostapd_cli.c     |  46 ++++++++++++++++
 src/ap/hostapd.c          |   4 ++
 src/ap/hostapd.h          |  12 +++++
 src/ap/neighbor_db.c      | 126 ++++++++++++++++++++++++++++++++++++++++++++
 src/ap/neighbor_db.h      |  20 +++++++
 wpa_supplicant/Android.mk |   1 +
 wpa_supplicant/Makefile   |   1 +
 10 files changed, 342 insertions(+)
 create mode 100644 src/ap/neighbor_db.c
 create mode 100644 src/ap/neighbor_db.h

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 a87f117..bfe3731 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -52,6 +52,7 @@
 #include "fst/fst_ctrl_iface.h"
 #include "config_file.h"
 #include "ctrl_iface.h"
+#include "ap/neighbor_db.h"
 
 
 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
@@ -2071,6 +2072,129 @@ 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 = NULL, *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 isn't supported");
+		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 IE");
+		return -1;
+	}
+
+	buf = os_strchr(tmp, ' ');
+	if (buf) {
+		*buf = '\0';
+		buf++;
+	}
+
+	nr = wpabuf_parse_bin(tmp + 3);
+	if (!nr) {
+		wpa_printf(MSG_ERROR,
+			   "CTRL: set_neighbor: bad neighbor report IE");
+		return -1;
+	}
+
+	if (!buf)
+		goto set;
+
+	tmp = os_strstr(buf, "lci=");
+	if (tmp) {
+		buf = os_strchr(tmp, ' ');
+		if (buf) {
+			*buf = '\0';
+			buf++;
+		}
+		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';
+			buf++;
+		}
+		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_neighbor: 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,
@@ -2312,6 +2436,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..863db42 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1096,6 +1096,50 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+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, 4 or 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);
+}
+
+
+
 static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
 				     char *argv[])
 {
@@ -1204,6 +1248,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 }
 };
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ee80f4f..1ad7510 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -43,6 +43,7 @@
 #include "x_snoop.h"
 #include "dhcp_snoop.h"
 #include "ndisc_snoop.h"
+#include "neighbor_db.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -335,6 +336,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 	wpabuf_free(hapd->mesh_pending_auth);
 	hapd->mesh_pending_auth = NULL;
 #endif /* CONFIG_MESH */
+
+	hostpad_free_neighbor_db(hapd);
 }
 
 
@@ -906,6 +909,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
 		return -1;
 	}
 	hapd->started = 1;
+	dl_list_init(&hapd->nr_db);
 
 	if (!first || first == -1) {
 		u8 *addr = hapd->own_addr;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75a7c04..e2c4913 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -99,6 +99,16 @@ struct wps_stat {
 	u8 peer_addr[ETH_ALEN];
 };
 
+struct hostapd_neighbor_entry {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	struct wpa_ssid_value ssid;
+	struct wpabuf *nr;
+	struct wpabuf *lci;
+	struct wpabuf *civic;
+	/* lci update time */
+	struct os_time lci_date;
+};
 
 /**
  * struct hostapd_data - hostapd per-BSS data structure
@@ -286,6 +296,8 @@ struct hostapd_data {
 #ifdef CONFIG_MBO
 	unsigned int mbo_assoc_disallow;
 #endif /* CONFIG_MBO */
+
+	struct dl_list nr_db;
 };
 
 
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
new file mode 100644
index 0000000..e3084e3
--- /dev/null
+++ b/src/ap/neighbor_db.c
@@ -0,0 +1,126 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "hostapd.h"
+#include "neighbor_db.h"
+
+
+static struct hostapd_neighbor_entry
+*hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+		      struct wpa_ssid_value *ssid)
+{
+	struct hostapd_neighbor_entry *nr;
+
+	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list)
+		if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
+		    ssid->ssid_len == nr->ssid.ssid_len &&
+		    os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) == 0)
+			return nr;
+	return NULL;
+}
+
+
+static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+{
+	wpabuf_free(nr->nr);
+	wpabuf_free(nr->lci);
+	wpabuf_free(nr->civic);
+	nr->nr = NULL;
+	nr->lci = NULL;
+	nr->civic = NULL;
+	os_memset(nr->bssid, 0, sizeof(nr->bssid));
+	os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+}
+
+
+static struct hostapd_neighbor_entry
+*hostapd_neighbor_add(struct hostapd_data *hapd)
+{
+	struct hostapd_neighbor_entry *nr;
+
+	nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
+	if (!nr)
+		return NULL;
+
+	dl_list_add(&hapd->nr_db, &nr->list);
+
+	return nr;
+}
+
+
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+			 struct wpa_ssid_value *ssid, struct wpabuf *nr,
+			 struct wpabuf *lci, struct wpabuf *civic)
+{
+	struct hostapd_neighbor_entry *entry;
+
+	entry = hostapd_neighbor_get(hapd, bssid, ssid);
+	if (!entry)
+		entry = hostapd_neighbor_add(hapd);
+	if (!entry)
+		return -1;
+
+	hostapd_neighbor_clear_entry(entry);
+
+	os_memcpy(entry->bssid, bssid, ETH_ALEN);
+	os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+
+	entry->nr = wpabuf_dup(nr);
+	if (!entry->nr)
+		goto free;
+
+	if (lci) {
+		entry->lci = wpabuf_dup(lci);
+		if (!entry->lci || os_get_time(&entry->lci_date))
+			goto free;
+	}
+
+	if (civic) {
+		entry->civic = wpabuf_dup(civic);
+		if (!entry->civic)
+			goto free;
+	}
+
+	return 0;
+free:
+	hostapd_neighbor_remove(hapd, bssid, ssid);
+	return -1;
+}
+
+
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+			    struct wpa_ssid_value *ssid)
+{
+	struct hostapd_neighbor_entry *nr;
+
+	nr = hostapd_neighbor_get(hapd, bssid, ssid);
+	if (!nr)
+		return -1;
+
+	hostapd_neighbor_clear_entry(nr);
+	dl_list_del(&nr->list);
+	os_free(nr);
+
+	return 0;
+}
+
+
+void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+{
+	struct hostapd_neighbor_entry *nr, *prev;
+
+	dl_list_for_each_safe(nr, prev, &hapd->nr_db,
+			      struct hostapd_neighbor_entry, list) {
+		hostapd_neighbor_clear_entry(nr);
+		dl_list_del(&nr->list);
+		os_free(nr);
+	}
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
new file mode 100644
index 0000000..35084a7
--- /dev/null
+++ b/src/ap/neighbor_db.h
@@ -0,0 +1,20 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NEIGHBOR_DB_H
+#define NEIGHBOR_DB_H
+
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+			 struct wpa_ssid_value *ssid, struct wpabuf *nr,
+			 struct wpabuf *lci, struct wpabuf *civic);
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+			    struct wpa_ssid_value *ssid);
+void hostpad_free_neighbor_db(struct hostapd_data *hapd);
+
+#endif /* NEIGHBOR_DB_H */
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index f65076c..d1adda5 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -797,6 +797,7 @@ OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
 OBJS += src/ap/bss_load.c
 OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/neighbor_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 ifdef CONFIG_IEEE80211AC
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 550d44b..06c26d2 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -844,6 +844,7 @@ OBJS += ../src/ap/ap_drv_ops.o
 OBJS += ../src/ap/beacon.o
 OBJS += ../src/ap/bss_load.o
 OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/neighbor_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 ifdef CONFIG_IEEE80211AC
-- 
1.9.1




More information about the Hostap mailing list