1 /*
2 * Copyright (c) 2016 Intel Corporation
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10
11 #include <stdlib.h>
12
13 #include "net_shell_private.h"
14
15 #include <zephyr/net/capture.h>
16
17 #if defined(CONFIG_NET_CAPTURE)
18 #define DEFAULT_DEV_NAME "NET_CAPTURE0"
19 static const struct device *capture_dev;
20
get_address_str(const struct sockaddr * addr,char * str,int str_len)21 static void get_address_str(const struct sockaddr *addr,
22 char *str, int str_len)
23 {
24 if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6) {
25 snprintk(str, str_len, "[%s]:%u",
26 net_sprint_ipv6_addr(&net_sin6(addr)->sin6_addr),
27 ntohs(net_sin6(addr)->sin6_port));
28
29 } else if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) {
30 snprintk(str, str_len, "%s:%d",
31 net_sprint_ipv4_addr(&net_sin(addr)->sin_addr),
32 ntohs(net_sin(addr)->sin_port));
33
34 } else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
35 addr->sa_family == AF_PACKET) {
36 snprintk(str, str_len, "AF_PACKET");
37 } else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
38 addr->sa_family == AF_CAN) {
39 snprintk(str, str_len, "AF_CAN");
40 } else if (addr->sa_family == AF_UNSPEC) {
41 snprintk(str, str_len, "AF_UNSPEC");
42 } else {
43 snprintk(str, str_len, "AF_UNK(%d)", addr->sa_family);
44 }
45 }
46
capture_cb(struct net_capture_info * info,void * user_data)47 static void capture_cb(struct net_capture_info *info, void *user_data)
48 {
49 struct net_shell_user_data *data = user_data;
50 const struct shell *sh = data->sh;
51 int *count = data->user_data;
52 char addr_local[ADDR_LEN + 7];
53 char addr_peer[ADDR_LEN + 7];
54
55 if (*count == 0) {
56 PR(" \t\tCapture Tunnel\n");
57 PR("Device\t\tiface iface Local\t\t\tPeer\n");
58 }
59
60 get_address_str(info->local, addr_local, sizeof(addr_local));
61 get_address_str(info->peer, addr_peer, sizeof(addr_peer));
62
63 PR("%s\t%c %d %s\t%s\n", info->capture_dev->name,
64 info->is_enabled ?
65 (net_if_get_by_iface(info->capture_iface) + '0') : '-',
66 net_if_get_by_iface(info->tunnel_iface),
67 addr_local, addr_peer);
68
69 (*count)++;
70 }
71 #endif
72
cmd_net_capture(const struct shell * sh,size_t argc,char * argv[])73 static int cmd_net_capture(const struct shell *sh, size_t argc, char *argv[])
74 {
75 #if defined(CONFIG_NET_CAPTURE)
76 bool ret;
77
78 if (capture_dev == NULL) {
79 capture_dev = device_get_binding(DEFAULT_DEV_NAME);
80 }
81
82 if (capture_dev == NULL) {
83 PR_INFO("Network packet capture %s\n", "not configured");
84 } else {
85 struct net_shell_user_data user_data;
86 int count = 0;
87
88 ret = net_capture_is_enabled(capture_dev);
89 PR_INFO("Network packet capture %s\n",
90 ret ? "enabled" : "disabled");
91
92 user_data.sh = sh;
93 user_data.user_data = &count;
94
95 net_capture_foreach(capture_cb, &user_data);
96 }
97 #else
98 ARG_UNUSED(argc);
99 ARG_UNUSED(argv);
100
101 PR_INFO("Set %s to enable %s support.\n",
102 "CONFIG_NET_CAPTURE", "network packet capture");
103 #endif
104 return 0;
105 }
106
cmd_net_capture_setup(const struct shell * sh,size_t argc,char * argv[])107 static int cmd_net_capture_setup(const struct shell *sh, size_t argc, char *argv[])
108 {
109 #if defined(CONFIG_NET_CAPTURE)
110 int ret, arg = 1;
111 const char *remote, *local, *peer;
112
113 remote = argv[arg++];
114 if (!remote) {
115 PR_WARNING("Remote IP address not specified.\n");
116 return -ENOEXEC;
117 }
118
119 local = argv[arg++];
120 if (!local) {
121 PR_WARNING("Local IP address not specified.\n");
122 return -ENOEXEC;
123 }
124
125 peer = argv[arg];
126 if (!peer) {
127 PR_WARNING("Peer IP address not specified.\n");
128 return -ENOEXEC;
129 }
130
131 if (capture_dev != NULL) {
132 PR_INFO("Capture already setup, cleaning up settings.\n");
133 net_capture_cleanup(capture_dev);
134 capture_dev = NULL;
135 }
136
137 ret = net_capture_setup(remote, local, peer, &capture_dev);
138 if (ret < 0) {
139 PR_WARNING("Capture cannot be setup (%d)\n", ret);
140 return -ENOEXEC;
141 }
142
143 PR_INFO("Capture setup done, next enable it by "
144 "\"net capture enable <idx>\"\n");
145 #else
146 ARG_UNUSED(argc);
147 ARG_UNUSED(argv);
148
149 PR_INFO("Set %s to enable %s support.\n",
150 "CONFIG_NET_CAPTURE", "network packet capture");
151 #endif
152
153 return 0;
154 }
155
cmd_net_capture_cleanup(const struct shell * sh,size_t argc,char * argv[])156 static int cmd_net_capture_cleanup(const struct shell *sh, size_t argc, char *argv[])
157 {
158 ARG_UNUSED(argc);
159 ARG_UNUSED(argv);
160
161 #if defined(CONFIG_NET_CAPTURE)
162 int ret;
163
164 if (capture_dev == NULL) {
165 return 0;
166 }
167
168 ret = net_capture_cleanup(capture_dev);
169 if (ret < 0) {
170 PR_WARNING("Capture %s failed (%d)\n", "cleanup", ret);
171 return -ENOEXEC;
172 }
173
174 capture_dev = NULL;
175 #else
176 PR_INFO("Set %s to enable %s support.\n",
177 "CONFIG_NET_CAPTURE", "network packet capture");
178 #endif
179
180 return 0;
181 }
182
cmd_net_capture_enable(const struct shell * sh,size_t argc,char * argv[])183 static int cmd_net_capture_enable(const struct shell *sh, size_t argc, char *argv[])
184 {
185 ARG_UNUSED(argc);
186 ARG_UNUSED(argv);
187
188 #if defined(CONFIG_NET_CAPTURE)
189 int ret, arg = 1, if_index;
190 struct net_if *iface;
191
192 if (capture_dev == NULL) {
193 return 0;
194 }
195
196 if (argv[arg] == NULL) {
197 PR_WARNING("Interface index is missing. Please give interface "
198 "what you want to monitor\n");
199 return -ENOEXEC;
200 }
201
202 if_index = atoi(argv[arg++]);
203 if (if_index == 0) {
204 PR_WARNING("Interface index %d is invalid.\n", if_index);
205 return -ENOEXEC;
206 }
207
208 iface = net_if_get_by_index(if_index);
209 if (iface == NULL) {
210 PR_WARNING("No such interface with index %d\n", if_index);
211 return -ENOEXEC;
212 }
213
214 ret = net_capture_enable(capture_dev, iface);
215 if (ret < 0) {
216 PR_WARNING("Capture %s failed (%d)\n", "enable", ret);
217 return -ENOEXEC;
218 }
219 #else
220 PR_INFO("Set %s to enable %s support.\n",
221 "CONFIG_NET_CAPTURE", "network packet capture");
222 #endif
223
224 return 0;
225 }
226
cmd_net_capture_disable(const struct shell * sh,size_t argc,char * argv[])227 static int cmd_net_capture_disable(const struct shell *sh, size_t argc, char *argv[])
228 {
229 ARG_UNUSED(argc);
230 ARG_UNUSED(argv);
231
232 #if defined(CONFIG_NET_CAPTURE)
233 int ret;
234
235 if (capture_dev == NULL) {
236 return 0;
237 }
238
239 ret = net_capture_disable(capture_dev);
240 if (ret < 0) {
241 PR_WARNING("Capture %s failed (%d)\n", "disable", ret);
242 return -ENOEXEC;
243 }
244 #else
245 PR_INFO("Set %s to enable %s support.\n",
246 "CONFIG_NET_CAPTURE", "network packet capture");
247 #endif
248
249 return 0;
250 }
251
252 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_capture,
253 SHELL_CMD(setup, NULL, "Setup network packet capture.\n"
254 "'net capture setup <remote-ip-addr> <local-addr> <peer-addr>'\n"
255 "<remote> is the (outer) endpoint IP address,\n"
256 "<local> is the (inner) local IP address,\n"
257 "<peer> is the (inner) peer IP address\n"
258 "Local and Peer addresses can have UDP port number in them (optional)\n"
259 "like 198.0.51.2:9000 or [2001:db8:100::2]:4242",
260 cmd_net_capture_setup),
261 SHELL_CMD(cleanup, NULL, "Cleanup network packet capture.",
262 cmd_net_capture_cleanup),
263 SHELL_CMD(enable, NULL, "Enable network packet capture for a given "
264 "network interface.\n"
265 "'net capture enable <interface index>'",
266 cmd_net_capture_enable),
267 SHELL_CMD(disable, NULL, "Disable network packet capture.",
268 cmd_net_capture_disable),
269 SHELL_SUBCMD_SET_END
270 );
271
272 SHELL_SUBCMD_ADD((net), capture, &net_cmd_capture,
273 "Configure network packet capture.", cmd_net_capture, 1, 0);
274