From: David Spinadel <david.spinadel@xxxxxxxxx> 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@xxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap