2016-04-06 19:42:07 +03:00
|
|
|
/*
|
|
|
|
* 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"
|
2021-07-27 16:42:16 -07:00
|
|
|
#include "utils/crc32.h"
|
2016-04-06 19:42:07 +03:00
|
|
|
#include "hostapd.h"
|
2018-08-20 14:20:44 +02:00
|
|
|
#include "ieee802_11.h"
|
2016-04-06 19:42:07 +03:00
|
|
|
#include "neighbor_db.h"
|
|
|
|
|
|
|
|
|
2016-04-06 19:42:12 +03:00
|
|
|
struct hostapd_neighbor_entry *
|
2016-04-06 19:42:07 +03:00
|
|
|
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
|
|
|
|
const struct wpa_ssid_value *ssid)
|
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr;
|
|
|
|
|
|
|
|
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
|
|
|
list) {
|
Use ether_addr_equal() to compare whether two MAC addresses are equal
This was done with spatch using the following semantic patch and minor
manual edits to clean up coding style and avoid compiler warnings in
driver_wext.c:
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- os_memcmp(a, b, ETH_ALEN) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !os_memcmp(a, b, ETH_ALEN)
+ ether_addr_equal(a, b)
Signed-off-by: Jouni Malinen <j@w1.fi>
2024-01-13 23:15:36 +02:00
|
|
|
if (ether_addr_equal(bssid, nr->bssid) &&
|
2016-04-06 19:42:12 +03:00
|
|
|
(!ssid ||
|
|
|
|
(ssid->ssid_len == nr->ssid.ssid_len &&
|
|
|
|
os_memcmp(ssid->ssid, nr->ssid.ssid,
|
|
|
|
ssid->ssid_len) == 0)))
|
2016-04-06 19:42:07 +03:00
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-19 10:09:50 -07:00
|
|
|
int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr;
|
|
|
|
char *pos, *end;
|
|
|
|
|
|
|
|
pos = buf;
|
|
|
|
end = buf + buflen;
|
|
|
|
|
|
|
|
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
|
|
|
list) {
|
|
|
|
int ret;
|
|
|
|
char nrie[2 * 255 + 1];
|
|
|
|
char lci[2 * 255 + 1];
|
|
|
|
char civic[2 * 255 + 1];
|
|
|
|
char ssid[SSID_MAX_LEN * 2 + 1];
|
|
|
|
|
|
|
|
ssid[0] = '\0';
|
|
|
|
wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
|
|
|
|
nr->ssid.ssid_len);
|
|
|
|
|
|
|
|
nrie[0] = '\0';
|
|
|
|
if (nr->nr)
|
|
|
|
wpa_snprintf_hex(nrie, sizeof(nrie),
|
|
|
|
wpabuf_head(nr->nr),
|
|
|
|
wpabuf_len(nr->nr));
|
|
|
|
|
|
|
|
lci[0] = '\0';
|
|
|
|
if (nr->lci)
|
|
|
|
wpa_snprintf_hex(lci, sizeof(lci),
|
|
|
|
wpabuf_head(nr->lci),
|
|
|
|
wpabuf_len(nr->lci));
|
|
|
|
|
|
|
|
civic[0] = '\0';
|
|
|
|
if (nr->civic)
|
|
|
|
wpa_snprintf_hex(civic, sizeof(civic),
|
|
|
|
wpabuf_head(nr->civic),
|
|
|
|
wpabuf_len(nr->civic));
|
|
|
|
|
|
|
|
ret = os_snprintf(pos, end - pos, MACSTR
|
|
|
|
" ssid=%s%s%s%s%s%s%s%s\n",
|
|
|
|
MAC2STR(nr->bssid), ssid,
|
|
|
|
nr->nr ? " nr=" : "", nrie,
|
|
|
|
nr->lci ? " lci=" : "", lci,
|
|
|
|
nr->civic ? " civic=" : "", civic,
|
|
|
|
nr->stationary ? " stat" : "");
|
|
|
|
if (os_snprintf_error(end - pos, ret))
|
|
|
|
break;
|
|
|
|
pos += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos - buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-06 19:42:07 +03:00
|
|
|
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
|
|
|
|
{
|
|
|
|
wpabuf_free(nr->nr);
|
|
|
|
nr->nr = NULL;
|
|
|
|
wpabuf_free(nr->lci);
|
|
|
|
nr->lci = NULL;
|
|
|
|
wpabuf_free(nr->civic);
|
|
|
|
nr->civic = NULL;
|
|
|
|
os_memset(nr->bssid, 0, sizeof(nr->bssid));
|
|
|
|
os_memset(&nr->ssid, 0, sizeof(nr->ssid));
|
2024-03-03 20:39:29 +02:00
|
|
|
os_memset(&nr->lci_date, 0, sizeof(nr->lci_date));
|
2016-10-27 15:18:25 +03:00
|
|
|
nr->stationary = 0;
|
2024-03-03 20:39:29 +02:00
|
|
|
nr->short_ssid = 0;
|
|
|
|
nr->bss_parameters = 0;
|
2016-04-06 19:42:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
const struct wpa_ssid_value *ssid,
|
|
|
|
const struct wpabuf *nr, const struct wpabuf *lci,
|
2021-07-27 16:42:17 -07:00
|
|
|
const struct wpabuf *civic, int stationary,
|
|
|
|
u8 bss_parameters)
|
2016-04-06 19:42:07 +03:00
|
|
|
{
|
|
|
|
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));
|
2022-09-05 23:18:23 +03:00
|
|
|
entry->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
|
2016-04-06 19:42:07 +03:00
|
|
|
|
|
|
|
entry->nr = wpabuf_dup(nr);
|
|
|
|
if (!entry->nr)
|
|
|
|
goto fail;
|
|
|
|
|
2016-10-27 15:18:23 +03:00
|
|
|
if (lci && wpabuf_len(lci)) {
|
2016-04-06 19:42:07 +03:00
|
|
|
entry->lci = wpabuf_dup(lci);
|
|
|
|
if (!entry->lci || os_get_time(&entry->lci_date))
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-10-27 15:18:23 +03:00
|
|
|
if (civic && wpabuf_len(civic)) {
|
2016-04-06 19:42:07 +03:00
|
|
|
entry->civic = wpabuf_dup(civic);
|
|
|
|
if (!entry->civic)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-10-27 15:18:25 +03:00
|
|
|
entry->stationary = stationary;
|
2021-07-27 16:42:17 -07:00
|
|
|
entry->bss_parameters = bss_parameters;
|
2016-10-27 15:18:25 +03:00
|
|
|
|
2016-04-06 19:42:07 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
hostapd_neighbor_remove(hapd, bssid, ssid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-03 20:41:30 +02:00
|
|
|
static void hostapd_neighbor_free(struct hostapd_neighbor_entry *nr)
|
|
|
|
{
|
|
|
|
hostapd_neighbor_clear_entry(nr);
|
|
|
|
dl_list_del(&nr->list);
|
|
|
|
os_free(nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-06 19:42:07 +03:00
|
|
|
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
|
|
|
const struct wpa_ssid_value *ssid)
|
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr;
|
|
|
|
|
|
|
|
nr = hostapd_neighbor_get(hapd, bssid, ssid);
|
|
|
|
if (!nr)
|
|
|
|
return -1;
|
|
|
|
|
2024-03-03 20:41:30 +02:00
|
|
|
hostapd_neighbor_free(nr);
|
2016-04-06 19:42:07 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-02 16:40:34 +02:00
|
|
|
void hostapd_free_neighbor_db(struct hostapd_data *hapd)
|
2016-04-06 19:42:07 +03:00
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr, *prev;
|
|
|
|
|
|
|
|
dl_list_for_each_safe(nr, prev, &hapd->nr_db,
|
|
|
|
struct hostapd_neighbor_entry, list) {
|
2024-03-03 20:41:30 +02:00
|
|
|
hostapd_neighbor_free(nr);
|
2016-04-06 19:42:07 +03:00
|
|
|
}
|
|
|
|
}
|
2018-08-20 14:20:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef NEED_AP_MLME
|
|
|
|
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
2019-05-20 09:55:09 +02:00
|
|
|
int ht, int vht, int he)
|
2018-08-20 14:20:44 +02:00
|
|
|
{
|
2022-05-13 21:47:40 +05:30
|
|
|
enum oper_chan_width oper_chwidth;
|
|
|
|
|
|
|
|
oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
|
2019-05-20 09:55:07 +02:00
|
|
|
|
2019-05-20 09:55:09 +02:00
|
|
|
if (!ht && !vht && !he)
|
2018-08-20 14:20:44 +02:00
|
|
|
return NR_CHAN_WIDTH_20;
|
|
|
|
if (!hapd->iconf->secondary_channel)
|
|
|
|
return NR_CHAN_WIDTH_20;
|
2022-05-13 21:47:40 +05:30
|
|
|
if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
|
2018-08-20 14:20:44 +02:00
|
|
|
return NR_CHAN_WIDTH_40;
|
2022-05-13 21:47:40 +05:30
|
|
|
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
|
2018-08-20 14:20:44 +02:00
|
|
|
return NR_CHAN_WIDTH_80;
|
2022-05-13 21:47:40 +05:30
|
|
|
if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
|
2018-08-20 14:20:44 +02:00
|
|
|
return NR_CHAN_WIDTH_160;
|
2022-05-13 21:47:40 +05:30
|
|
|
if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
|
2018-08-20 14:20:44 +02:00
|
|
|
return NR_CHAN_WIDTH_80P80;
|
|
|
|
return NR_CHAN_WIDTH_20;
|
|
|
|
}
|
|
|
|
#endif /* NEED_AP_MLME */
|
|
|
|
|
|
|
|
|
|
|
|
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
|
|
|
{
|
|
|
|
#ifdef NEED_AP_MLME
|
|
|
|
u16 capab = hostapd_own_capab_info(hapd);
|
|
|
|
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
|
|
|
|
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
2020-06-30 17:23:46 +03:00
|
|
|
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
|
2022-04-19 11:04:15 -07:00
|
|
|
bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
|
2018-08-20 14:20:44 +02:00
|
|
|
struct wpa_ssid_value ssid;
|
|
|
|
u8 channel, op_class;
|
|
|
|
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
|
|
|
enum nr_chan_width width;
|
|
|
|
u32 bssid_info;
|
|
|
|
struct wpabuf *nr;
|
|
|
|
|
|
|
|
if (!(hapd->conf->radio_measurements[0] &
|
|
|
|
WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
|
|
|
return;
|
|
|
|
|
|
|
|
bssid_info = 3; /* AP is reachable */
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
|
|
|
|
|
|
|
|
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
|
|
|
|
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
|
|
|
|
|
|
|
|
if (hapd->conf->wmm_enabled) {
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_QOS;
|
|
|
|
|
|
|
|
if (hapd->conf->wmm_uapsd &&
|
|
|
|
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_APSD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ht) {
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_HT |
|
|
|
|
NEI_REP_BSSID_INFO_DELAYED_BA;
|
|
|
|
|
|
|
|
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
|
|
|
if (vht)
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
|
|
|
}
|
|
|
|
|
2022-04-19 11:04:15 -07:00
|
|
|
if (he)
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_HE;
|
|
|
|
if (eht)
|
|
|
|
bssid_info |= NEI_REP_BSSID_INFO_EHT;
|
2018-08-20 14:20:44 +02:00
|
|
|
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
|
|
|
|
|
|
|
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
|
|
|
hapd->iconf->secondary_channel,
|
2019-05-20 09:55:07 +02:00
|
|
|
hostapd_get_oper_chwidth(hapd->iconf),
|
2018-08-20 14:20:44 +02:00
|
|
|
&op_class, &channel) ==
|
|
|
|
NUM_HOSTAPD_MODES)
|
|
|
|
return;
|
2019-05-20 09:55:09 +02:00
|
|
|
width = hostapd_get_nr_chan_width(hapd, ht, vht, he);
|
2018-08-20 14:20:44 +02:00
|
|
|
if (vht) {
|
2019-05-20 09:55:07 +02:00
|
|
|
center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx(
|
|
|
|
hapd->iconf);
|
2018-08-20 14:20:44 +02:00
|
|
|
if (width == NR_CHAN_WIDTH_80P80)
|
|
|
|
center_freq2_idx =
|
2019-05-20 09:55:07 +02:00
|
|
|
hostapd_get_oper_centr_freq_seg1_idx(
|
|
|
|
hapd->iconf);
|
2018-08-20 14:20:44 +02:00
|
|
|
} else if (ht) {
|
|
|
|
ieee80211_freq_to_chan(hapd->iface->freq +
|
|
|
|
10 * hapd->iconf->secondary_channel,
|
|
|
|
¢er_freq1_idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
|
|
|
os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Neighbor Report element size = BSSID + BSSID info + op_class + chan +
|
|
|
|
* phy type + wide bandwidth channel subelement.
|
|
|
|
*/
|
|
|
|
nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
|
|
|
|
if (!nr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
|
|
|
|
wpabuf_put_le32(nr, bssid_info);
|
|
|
|
wpabuf_put_u8(nr, op_class);
|
|
|
|
wpabuf_put_u8(nr, channel);
|
|
|
|
wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wide Bandwidth Channel subelement may be needed to allow the
|
|
|
|
* receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
|
|
|
|
* Figure 9-301.
|
|
|
|
*/
|
|
|
|
wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
|
|
|
|
wpabuf_put_u8(nr, 3);
|
|
|
|
wpabuf_put_u8(nr, width);
|
|
|
|
wpabuf_put_u8(nr, center_freq1_idx);
|
|
|
|
wpabuf_put_u8(nr, center_freq2_idx);
|
|
|
|
|
|
|
|
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
2021-07-27 16:42:17 -07:00
|
|
|
hapd->iconf->civic, hapd->iconf->stationary_ap, 0);
|
2018-08-20 14:20:44 +02:00
|
|
|
|
|
|
|
wpabuf_free(nr);
|
|
|
|
#endif /* NEED_AP_MLME */
|
|
|
|
}
|
2024-02-01 18:05:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
static struct hostapd_neighbor_entry *
|
|
|
|
hostapd_neighbor_get_diff_short_ssid(struct hostapd_data *hapd, const u8 *bssid)
|
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr;
|
|
|
|
|
|
|
|
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
|
|
|
list) {
|
|
|
|
if (ether_addr_equal(bssid, nr->bssid) &&
|
|
|
|
nr->short_ssid != hapd->conf->ssid.short_ssid)
|
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd)
|
|
|
|
{
|
|
|
|
struct hostapd_neighbor_entry *nr;
|
|
|
|
|
|
|
|
nr = hostapd_neighbor_get_diff_short_ssid(hapd, hapd->own_addr);
|
|
|
|
if (!nr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Clear old entry due to SSID change */
|
2024-03-03 20:41:30 +02:00
|
|
|
hostapd_neighbor_free(nr);
|
2024-02-01 18:05:02 +02:00
|
|
|
|
|
|
|
hostapd_neighbor_set_own_report(hapd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|