[RFC 26/34] NAN: Support Service Response Filters (SRF)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for MAC list and Bloom filter SRFs.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx>
---
 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 b688517bb5..0fb71edc4e 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"
@@ -69,6 +70,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 {
@@ -133,6 +139,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);
 }
@@ -255,6 +262,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 */
@@ -284,6 +297,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);
@@ -1197,6 +1226,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)
@@ -1264,6 +1349,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;
 	}
 
@@ -1613,6 +1704,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,
@@ -1698,6 +1849,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);
 	srv->id = subscribe_id;
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 5c2ee6419f..f7a90de9f9 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -163,6 +163,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 21f5ce986b..313e7cf1e5 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 6119378b08..18a0c7cb48 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -12845,6 +12845,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


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux