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(ð_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