1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_stats_sample, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 
13 #include <zephyr/net/net_core.h>
14 #include <zephyr/net/net_if.h>
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/net_pkt_filter.h>
17 
18 #include "net_sample_common.h"
19 
20 #define MAX_INTERFACES 3
21 
22 static struct net_if *interfaces[MAX_INTERFACES];
23 
24 /* Interface match rule. The interface value is set at runtime in init_app() */
25 static NPF_IFACE_MATCH(match_iface_vlan1, NULL);
26 static NPF_IFACE_MATCH(match_iface_vlan2, NULL);
27 static NPF_IFACE_MATCH(match_iface_eth, NULL);
28 
29 /* Allow all traffic to Ethernet interface, drop VLAN traffic except
30  * couple of exceptions for IPv4 and IPv6
31  */
32 static NPF_RULE(eth_iface_rule, NET_OK, match_iface_eth);
33 
34 /* Match max size rule */
35 static NPF_SIZE_MAX(maxsize_200, 200);
36 static NPF_ETH_VLAN_TYPE_MATCH(ipv4_packet1, NET_ETH_PTYPE_IP);
37 static NPF_RULE(small_ipv4_pkt, NET_OK, ipv4_packet1, maxsize_200,
38 		match_iface_vlan1);
39 
40 /* Match min size rule */
41 static NPF_SIZE_MIN(minsize_100, 100);
42 static NPF_ETH_VLAN_TYPE_MATCH(ipv4_packet2, NET_ETH_PTYPE_IP);
43 static NPF_RULE(large_ipv4_pkt, NET_OK, ipv4_packet2, minsize_100,
44 		match_iface_vlan2);
45 
46 /* Allow ARP for VLAN interface */
47 static NPF_ETH_VLAN_TYPE_MATCH(arp_packet, NET_ETH_PTYPE_ARP);
48 static NPF_RULE(arp_pkt_vlan1, NET_OK, arp_packet, match_iface_vlan1);
49 static NPF_RULE(arp_pkt_vlan2, NET_OK, arp_packet, match_iface_vlan2);
50 
iface_cb(struct net_if * iface,void * user_data)51 static void iface_cb(struct net_if *iface, void *user_data)
52 {
53 	int count = 0;
54 
55 	ARG_UNUSED(user_data);
56 
57 	ARRAY_FOR_EACH(interfaces, i) {
58 		if (interfaces[i] == NULL) {
59 			interfaces[i] = iface;
60 			return;
61 		}
62 
63 		count++;
64 	}
65 
66 	LOG_ERR("Too many interfaces %d (max is %d)", count, MAX_INTERFACES);
67 }
68 
init_app(void)69 static void init_app(void)
70 {
71 	struct net_if *iface, *eth = NULL, *vlan1 = NULL, *vlan2 = NULL;
72 	int found = 0;
73 
74 	ARRAY_FOR_EACH(interfaces, i) {
75 		if (interfaces[i] == NULL) {
76 			continue;
77 		}
78 
79 		iface = interfaces[i];
80 
81 		if (net_eth_is_vlan_interface(iface)) {
82 			if (vlan1 == NULL) {
83 				vlan1 = iface;
84 			} else if (vlan2 == NULL) {
85 				vlan2 = iface;
86 			}
87 		} else if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
88 			eth = iface;
89 		} else {
90 			continue;
91 		}
92 
93 		found++;
94 	}
95 
96 	if (found == 0) {
97 		LOG_ERR("No interfaces found");
98 		return;
99 	}
100 
101 	match_iface_vlan1.iface = vlan1;
102 	match_iface_vlan2.iface = vlan2;
103 	match_iface_eth.iface = eth;
104 
105 	/* The sample will setup the Ethernet interface and two VLAN
106 	 * optional interfaces (if VLAN is enabled).
107 	 * We allow all traffic to the Ethernet interface, but have
108 	 * filters for the VLAN interfaces.
109 	 */
110 
111 	/* We allow small IPv4 packets to the VLAN interface 1 */
112 	npf_append_recv_rule(&small_ipv4_pkt);
113 
114 	/* We allow large IPv4 packets to the VLAN interface 2 */
115 	npf_append_recv_rule(&large_ipv4_pkt);
116 
117 	/* We allow all traffic to the Ethernet interface */
118 	npf_append_recv_rule(&eth_iface_rule);
119 
120 	/* We allow ARP traffic to the VLAN 1 interface */
121 	npf_append_recv_rule(&arp_pkt_vlan1);
122 
123 	/* We allow ARP traffic to the VLAN 2 interface */
124 	npf_append_recv_rule(&arp_pkt_vlan2);
125 
126 	/* The remaining packets that do not match are dropped */
127 	npf_append_recv_rule(&npf_default_drop);
128 }
129 
main(void)130 int main(void)
131 {
132 	net_if_foreach(iface_cb, interfaces);
133 
134 	init_vlan();
135 	init_app();
136 
137 	return 0;
138 }
139