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_DECLARE(net_shell);
9 
10 #include <zephyr/net/net_pkt_filter.h>
11 
12 #include "net_shell_private.h"
13 
14 
15 #if defined(CONFIG_NET_PKT_FILTER)
rule_type2str(enum npf_rule_type type)16 static const char *rule_type2str(enum npf_rule_type type)
17 {
18 	switch (type) {
19 	case NPF_RULE_TYPE_SEND:
20 		return "send";
21 	case NPF_RULE_TYPE_RECV:
22 		return "recv";
23 	case NPF_RULE_TYPE_LOCAL_IN_RECV:
24 		return "local recv";
25 	case NPF_RULE_TYPE_IPV4_RECV:
26 		return "IPv4 recv";
27 	case NPF_RULE_TYPE_IPV6_RECV:
28 		return "IPv6 recv";
29 	case NPF_RULE_TYPE_UNKNOWN:
30 		__fallthrough;
31 	default:
32 		break;
33 	}
34 
35 	return "<UNKNOWN>";
36 }
37 
verdict2str(enum net_verdict verdict)38 static const char *verdict2str(enum net_verdict verdict)
39 {
40 	switch (verdict) {
41 	case NET_OK:
42 		return "OK";
43 	case NET_DROP:
44 		return "DROP";
45 	case NET_CONTINUE:
46 		return "CONTINUE";
47 	default:
48 		break;
49 	}
50 
51 	return "<UNK>";
52 }
53 
rule_cb(struct npf_rule * rule,enum npf_rule_type type,void * user_data)54 static void rule_cb(struct npf_rule *rule, enum npf_rule_type type, void *user_data)
55 {
56 	struct net_shell_user_data *data = user_data;
57 	const struct shell *sh = data->sh;
58 	int *count = data->user_data;
59 	uint8_t tc;
60 	int thread_prio;
61 
62 	PR("[%2d]  %-10s  %-8s  ",
63 	   (*count) + 1, rule_type2str(type), verdict2str(rule->result));
64 
65 	if (rule->result == NET_CONTINUE && type == NPF_RULE_TYPE_SEND) {
66 		tc = net_tx_priority2tc(rule->priority);
67 		if (net_tc_tx_is_immediate(tc, rule->priority)) {
68 			PR("%8d  %5d         SKIP  ", rule->priority, tc);
69 		} else {
70 			thread_prio =  net_tc_tx_thread_priority(tc);
71 			PR("%8d  %5d  %11d  ", rule->priority, tc, thread_prio);
72 		}
73 	} else if (rule->result == NET_CONTINUE) {
74 		tc = net_rx_priority2tc(rule->priority);
75 		if (net_tc_rx_is_immediate(tc, rule->priority)) {
76 			PR("%8d  %5d         SKIP  ", rule->priority, tc);
77 		} else {
78 			thread_prio =  net_tc_rx_thread_priority(tc);
79 			PR("%8d  %5d  %11d  ", rule->priority, tc, thread_prio);
80 		}
81 	} else {
82 		PR("     N/A    N/A          N/A  ");
83 	}
84 
85 	PR("%-5d", rule->nb_tests);
86 
87 	for (int i = 0; i < rule->nb_tests; i++) {
88 		/* Allocate room for storing two full IPv4/6 addresses */
89 #define MAX_BUF_LEN ((IS_ENABLED(CONFIG_NET_IPV6) ?		\
90 		      NET_INET6_ADDRSTRLEN : NET_INET_ADDRSTRLEN) * 2)
91 		char buf[MAX_BUF_LEN] = { 0 };
92 		struct npf_test *test;
93 		const char *str;
94 
95 		test = rule->tests[i];
96 
97 		str = npf_test_get_str(test, buf, sizeof(buf) - 1);
98 		PR("%s%s%s", str, buf[0] != '\0' ? buf : "",
99 		   i == rule->nb_tests - 1 ? "" : ",");
100 	}
101 
102 	PR("\n");
103 	(*count)++;
104 }
105 #endif /* CONFIG_NET_PKT_FILTER */
106 
cmd_net_filter(const struct shell * sh,size_t argc,char * argv[])107 static int cmd_net_filter(const struct shell *sh, size_t argc, char *argv[])
108 {
109 	ARG_UNUSED(argc);
110 	ARG_UNUSED(argv);
111 
112 #if defined(CONFIG_NET_PKT_FILTER)
113 	struct net_shell_user_data user_data;
114 	int count = 0;
115 
116 	PR("Rule  %-10s  Verdict   Pkt-Prio  Queue  Thread-Prio  Tests\n", "Type");
117 
118 	user_data.sh = sh;
119 	user_data.user_data = &count;
120 
121 	npf_rules_foreach(rule_cb, &user_data);
122 
123 	if (count == 0) {
124 		PR("No network packet filter rules\n");
125 	}
126 #else
127 	PR_INFO("Set %s to enable %s support.\n",
128 		"CONFIG_NET_PKT_FILTER",
129 		"packet filter information");
130 
131 #endif /* CONFIG_NET_PKT_FILTER */
132 
133 	return 0;
134 }
135 
136 
137 SHELL_SUBCMD_ADD((net), filter, NULL, "Print information about network packet filters.",
138 		 cmd_net_filter, 1, 0);
139