[PATCH 27/35] NAN: Support Service Response Filters (SRF)
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Mon Oct 20 05:28:02 PDT 2025
Add support for MAC list and Bloom filter SRFs.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/common/nan_de.c | 176 ++++++++++++++++++++++++++++++++++++
src/common/nan_de.h | 12 +++
src/common/nan_defs.h | 7 ++
wpa_supplicant/ctrl_iface.c | 20 ++++
4 files changed, 215 insertions(+)
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index b9208fc89c..7b16d165d0 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/crc32.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
#include "ieee802_11_defs.h"
@@ -70,6 +71,11 @@ struct nan_de_service {
/* Filters */
struct wpabuf *matching_filter_tx;
struct wpabuf *matching_filter_rx;
+
+ bool srf_include;
+ bool srf_type_bloom_filter;
+ u8 srf_bf_idx;
+ struct wpabuf *srf;
};
struct nan_de {
@@ -134,6 +140,7 @@ static void nan_de_service_free(struct nan_de_service *srv)
wpabuf_free(srv->elems);
wpabuf_free(srv->matching_filter_tx);
wpabuf_free(srv->matching_filter_rx);
+ wpabuf_free(srv->srf);
os_free(srv->freq_list);
os_free(srv);
}
@@ -256,6 +263,12 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv,
ctrl |= NAN_SRV_CTRL_MATCHING_FILTER;
}
+ if (srv->srf && wpabuf_len(srv->srf)) {
+ /* SRF length + SRF control */
+ sda_len += 1 + 1 + wpabuf_len(srv->srf);
+ ctrl |= NAN_SRV_CTRL_RESP_FILTER;
+ }
+
len += NAN_ATTR_HDR_LEN + sda_len;
/* Service Descriptor Extension attribute */
@@ -285,6 +298,22 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv,
wpabuf_put_buf(buf, srv->matching_filter_tx);
}
+ if (ctrl & NAN_SRV_CTRL_RESP_FILTER) {
+ u8 srf_ctrl = 0;
+
+ if (srv->srf_type_bloom_filter)
+ srf_ctrl = NAN_SRF_CTRL_BF;
+
+ if (srv->srf_include)
+ srf_ctrl |= NAN_SRF_CTRL_INCLUDE;
+
+ srf_ctrl |= (srv->srf_bf_idx & NAN_SRF_CTRL_BF_IDX_MSK) <<
+ NAN_SRF_CTRL_BF_IDX_POS;
+ wpabuf_put_u8(buf, wpabuf_len(srv->srf) + 1);
+ wpabuf_put_u8(buf, srf_ctrl);
+ wpabuf_put_buf(buf, srv->srf);
+ }
+
/* Service Descriptor Extension attribute */
if (srv->type == NAN_DE_PUBLISH || ssi) {
wpabuf_put_u8(buf, NAN_ATTR_SDEA);
@@ -1143,6 +1172,62 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
}
+static bool nan_check_bloom_filter(const u8 *nmi, const u8 *bf,
+ size_t bf_len, u8 bf_idx)
+{
+ u8 a_j_x[1 + ETH_ALEN];
+ int j;
+ u32 crc;
+
+ for (j = 4 * bf_idx; j < 4 * (bf_idx + 1); j++) {
+ a_j_x[0] = j;
+ os_memcpy(&a_j_x[1], nmi, ETH_ALEN);
+ crc = (~ieee80211_crc32(a_j_x, 1 + ETH_ALEN)) & 0xFFFF;
+ crc %= bf_len * 8;
+ if (!(bf[crc / 8] & BIT(crc % 8)))
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool nan_srf_match(struct nan_de *de, const u8 *srf, size_t srf_len)
+{
+ u8 srf_ctrl;
+ bool srf_type_bf;
+ bool include;
+ u8 srf_bf_idx;
+
+ if (srf_len < 1)
+ return false;
+
+ srf_ctrl = *srf++;
+ srf_len--;
+
+ srf_type_bf = !!(srf_ctrl & NAN_SRF_CTRL_BF);
+ include = !!(srf_ctrl & NAN_SRF_CTRL_INCLUDE);
+ srf_bf_idx = (srf_ctrl >> NAN_SRF_CTRL_BF_IDX_POS) &
+ NAN_SRF_CTRL_BF_IDX_MSK;
+
+ if (srf_type_bf) {
+ if (nan_check_bloom_filter(de->nmi, srf, srf_len, srf_bf_idx))
+ return include;
+ } else {
+ /* MAC Address filter */
+ while (srf_len >= ETH_ALEN) {
+ if (ether_addr_equal(srf, de->nmi))
+ return include;
+
+ srf += ETH_ALEN;
+ srf_len -= ETH_ALEN;
+ }
+ }
+
+ return !include;
+}
+
+
static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
unsigned int freq, const u8 *buf, size_t len,
const u8 *sda, size_t sda_len)
@@ -1210,6 +1295,12 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
flen = *sda++;
if (end - sda < flen)
return;
+
+ if (!nan_srf_match(de, sda, flen)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Discard SDA with non-matching SRF");
+ return;
+ }
sda += flen;
}
@@ -1574,6 +1665,66 @@ int nan_de_unpause_publish(struct nan_de *de, int publish_id,
}
+static void bloom_filter_add(u8 *bf, u8 bf_idx, u8 bf_len, const u8 *mac)
+{
+ u8 a_j_x[1 + ETH_ALEN];
+ int j;
+ u32 crc;
+
+ for (j = 4 * bf_idx; j < 4 * (bf_idx + 1); j++) {
+ a_j_x[0] = j;
+ os_memcpy(&a_j_x[1], mac, ETH_ALEN);
+ crc = (~ieee80211_crc32(a_j_x, 1 + ETH_ALEN)) & 0xFFFF;
+ crc %= bf_len * 8;
+ bf[crc / 8] |= (1 << (crc % 8));
+ }
+}
+
+
+static struct wpabuf * nan_build_bloom_filter(const char *srf_mac_list,
+ u8 srf_bf_len, u8 srf_bf_idx)
+{
+ struct wpabuf *srf;
+ int i, n;
+ u8 mac[ETH_ALEN];
+ u8 *bf;
+
+ if (srf_bf_idx > 3)
+ return NULL;
+
+ if (os_strlen(srf_mac_list) % (ETH_ALEN * 2)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Invalid SRF MAC list length %zu",
+ os_strlen(srf_mac_list));
+ return NULL;
+ }
+
+ n = os_strlen(srf_mac_list) / (ETH_ALEN * 2);
+
+ srf = wpabuf_alloc(srf_bf_len);
+ if (!srf)
+ return NULL;
+
+ bf = wpabuf_put(srf, srf_bf_len);
+
+ for (i = 0; i < n; i++) {
+ if (hexstr2bin(srf_mac_list + i * 2 * ETH_ALEN, mac, ETH_ALEN)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Invalid SRF MAC address %s",
+ srf_mac_list + i * 2 * ETH_ALEN);
+ goto out;
+ }
+
+ bloom_filter_add(bf, srf_bf_idx, srf_bf_len, mac);
+ }
+
+ return srf;
+out:
+ wpabuf_free(srf);
+ return NULL;
+}
+
+
int nan_de_subscribe(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
@@ -1672,6 +1823,31 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name,
}
}
+ if (params->srf_mac_list) {
+ if (params->srf_bf_len) {
+ srv->srf = nan_build_bloom_filter(params->srf_mac_list,
+ params->srf_bf_len,
+ params->srf_bf_idx);
+ srv->srf_type_bloom_filter = true;
+ srv->srf_bf_idx = params->srf_bf_idx;
+ } else {
+ srv->srf = wpabuf_parse_bin(params->srf_mac_list);
+ if (wpabuf_len(srv->srf) % ETH_ALEN) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Invalid SRF MAC list length");
+ goto fail;
+ }
+ }
+
+ if (!srv->srf || wpabuf_len(srv->srf) > 254) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Failed to parse SRF MAC list");
+ goto fail;
+ }
+
+ srv->srf_include = params->srf_include;
+ }
+
wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s",
subscribe_id, service_name ? service_name : "Ranging");
srv->id = subscribe_id;
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 837db4ef02..cb35dd13d6 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -174,6 +174,18 @@ struct nan_subscribe_params {
*/
const char *match_filter_tx;
const char *match_filter_rx;
+
+ /* Service response filter include flag */
+ bool srf_include;
+
+ /* Service response filter MAC list */
+ const char *srf_mac_list;
+
+ /* Bloom filter length in octets. If 0, MAC list is used instead */
+ u8 srf_bf_len;
+
+ /* Bloom filter index (0-3) */
+ u8 srf_bf_idx;
};
/* Returns -1 on failure or >0 subscribe_id */
diff --git a/src/common/nan_defs.h b/src/common/nan_defs.h
index 756c58c807..7d58665036 100644
--- a/src/common/nan_defs.h
+++ b/src/common/nan_defs.h
@@ -90,6 +90,13 @@ enum nan_service_protocol_type {
NAN_SRV_PROTO_CSA_MATTER = 3,
};
+/* SRF control field */
+#define NAN_SRF_CTRL_BF BIT(0)
+#define NAN_SRF_CTRL_INCLUDE BIT(1)
+
+#define NAN_SRF_CTRL_BF_IDX_MSK (BIT(0) | BIT(1))
+#define NAN_SRF_CTRL_BF_IDX_POS 2
+
#define NAN_ATTR_HDR_LEN 3
#define NAN_SERVICE_ID_LEN 6
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 77ee987c7f..680529238e 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -12987,6 +12987,26 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd,
continue;
}
+ if (os_strncmp(token, "srf_include=", 12) == 0) {
+ params.srf_include = !!atoi(token + 12);
+ continue;
+ }
+
+ if (os_strncmp(token, "srf_mac_list=", 13) == 0) {
+ params.srf_mac_list = token + 13;
+ continue;
+ }
+
+ if (os_strncmp(token, "srf_bf_len=", 11) == 0) {
+ params.srf_bf_len = atoi(token + 11);
+ continue;
+ }
+
+ if (os_strncmp(token, "srf_bf_idx=", 11) == 0) {
+ params.srf_bf_idx = atoi(token + 11);
+ continue;
+ }
+
wpa_printf(MSG_INFO,
"CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
token);
--
2.49.0
More information about the Hostap
mailing list