diff --git a/include/net/net_pkt_filter.h b/include/net/net_pkt_filter.h
index 23900e2a811..1d8c48d5300 100644
--- a/include/net/net_pkt_filter.h
+++ b/include/net/net_pkt_filter.h
@@ -41,15 +41,15 @@ typedef bool (npf_test_fn_t)(struct npf_test *test, struct net_pkt *pkt);
/** @brief common filter test structure to be embedded into larger structures */
struct npf_test {
- npf_test_fn_t *fn; /*< packet condition test function */
+ npf_test_fn_t *fn; /**< packet condition test function */
};
/** @brief filter rule structure */
struct npf_rule {
sys_snode_t node;
- enum net_verdict result; /*< result if all tests pass */
- uint32_t nb_tests; /*< number of tests in this rule */
- struct npf_test *tests[]; /*< pointers to @ref npf_test instances */
+ enum net_verdict result; /**< result if all tests pass */
+ uint32_t nb_tests; /**< number of tests for this rule */
+ struct npf_test *tests[]; /**< pointers to @ref npf_test instances */
};
/** @brief Default rule list termination for accepting a packet */
@@ -310,6 +310,7 @@ struct npf_test_eth_addr {
struct npf_test test;
unsigned int nb_addresses;
struct net_eth_addr *addresses;
+ struct net_eth_addr mask;
};
extern npf_test_fn_t npf_eth_src_addr_match;
@@ -333,6 +334,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_src_addr_match, \
+ .mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
}
/**
@@ -349,6 +351,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_src_addr_unmatch, \
+ .mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
}
/**
@@ -365,6 +368,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_dst_addr_match, \
+ .mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
}
/**
@@ -381,6 +385,43 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_dst_addr_unmatch, \
+ .mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
+ }
+
+/**
+ * @brief Statically define a "source address match with mask" packet filter condition
+ *
+ * This tests if the packet source address matches any of the Ethernet
+ * addresses contained in the provided set after applying specified mask.
+ *
+ * @param _name Name of the condition
+ * @param _addr_array Array of struct net_eth_addr items to test against
+ * @param ... up to 6 mask bytes
+ */
+#define NPF_ETH_SRC_ADDR_MASK_MATCH(_name, _addr_array, ...) \
+ struct npf_test_eth_addr _name = { \
+ .addresses = (_addr_array), \
+ .nb_addresses = ARRAY_SIZE(_addr_array), \
+ .mask.addr = { __VA_ARGS__ }, \
+ .test.fn = npf_eth_src_addr_match, \
+ }
+
+/**
+ * @brief Statically define a "destination address match with mask" packet filter condition
+ *
+ * This tests if the packet destination address matches any of the Ethernet
+ * addresses contained in the provided set after applying specified mask.
+ *
+ * @param _name Name of the condition
+ * @param _addr_array Array of struct net_eth_addr items to test against
+ * @param ... up to 6 mask bytes
+ */
+#define NPF_ETH_DST_ADDR_MASK_MATCH(_name, _addr_array, ...) \
+ struct npf_test_eth_addr _name = { \
+ .addresses = (_addr_array), \
+ .nb_addresses = ARRAY_SIZE(_addr_array), \
+ .mask.addr = { __VA_ARGS__ }, \
+ .test.fn = npf_eth_dst_addr_match, \
}
/** @cond INTERNAL_HIDDEN */
diff --git a/subsys/net/pkt_filter/ethernet.c b/subsys/net/pkt_filter/ethernet.c
index cca8a404370..1b9cd8bd0fc 100644
--- a/subsys/net/pkt_filter/ethernet.c
+++ b/subsys/net/pkt_filter/ethernet.c
@@ -10,15 +10,29 @@ LOG_MODULE_REGISTER(npf_ethernet, CONFIG_NET_PKT_FILTER_LOG_LEVEL);
#include
#include
+static bool addr_mask_compare(struct net_eth_addr *addr1,
+ struct net_eth_addr *addr2,
+ struct net_eth_addr *mask)
+{
+ for (int i = 0; i < 6; i++) {
+ if ((addr1->addr[i] & mask->addr[i]) !=
+ (addr2->addr[i] & mask->addr[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool addr_match(struct npf_test *test, struct net_eth_addr *pkt_addr)
{
struct npf_test_eth_addr *test_eth_addr =
CONTAINER_OF(test, struct npf_test_eth_addr, test);
struct net_eth_addr *addr = test_eth_addr->addresses;
+ struct net_eth_addr *mask = &test_eth_addr->mask;
unsigned int nb_addr = test_eth_addr->nb_addresses;
while (nb_addr) {
- if (memcmp(addr, pkt_addr, sizeof(struct net_eth_addr)) == 0) {
+ if (addr_mask_compare(addr, pkt_addr, mask)) {
return true;
}
addr++;
diff --git a/tests/net/npf/src/main.c b/tests/net/npf/src/main.c
index a177bd9c0b1..410e5ee78a1 100644
--- a/tests/net/npf/src/main.c
+++ b/tests/net/npf/src/main.c
@@ -281,13 +281,39 @@ static void test_npf_eth_mac_address(void)
zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), "");
}
+static NPF_ETH_SRC_ADDR_MASK_MATCH(matched_src_addr_mask, mac_address_list,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00);
+static NPF_RULE(accept_matched_src_addr_mask, NET_OK, matched_src_addr_mask);
+
+static void test_npf_eth_mac_addr_mask(void)
+{
+ struct net_pkt *pkt = build_test_pkt(NET_ETH_PTYPE_IP, 100, NULL);
+
+ /* test standard match rule from previous test */
+ npf_insert_recv_rule(&npf_default_drop);
+ npf_insert_recv_rule(&accept_matched_src_addr);
+ zassert_true(net_pkt_filter_recv_ok(pkt), "");
+
+ /* clobber one nibble of matching address from previous test */
+ mac_address_list[1].addr[5] = 0x00;
+ zassert_false(net_pkt_filter_recv_ok(pkt), "");
+
+ /* insert masked address match rule */
+ npf_insert_recv_rule(&accept_matched_src_addr_mask);
+ zassert_true(net_pkt_filter_recv_ok(pkt), "");
+
+ /* cleanup */
+ zassert_true(npf_remove_all_recv_rules(), "");
+}
+
void test_main(void)
{
ztest_test_suite(net_pkt_filter_test,
ztest_unit_test(test_npf_iface),
ztest_unit_test(test_npf_example1),
ztest_unit_test(test_npf_example2),
- ztest_unit_test(test_npf_eth_mac_address));
+ ztest_unit_test(test_npf_eth_mac_address),
+ ztest_unit_test(test_npf_eth_mac_addr_mask));
ztest_run_test_suite(net_pkt_filter_test);
}