274 lines
6.6 KiB
C
274 lines
6.6 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(net_shell);
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "net_shell_private.h"
|
|
|
|
#include <zephyr/net/capture.h>
|
|
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
#define DEFAULT_DEV_NAME "NET_CAPTURE0"
|
|
static const struct device *capture_dev;
|
|
|
|
static void get_address_str(const struct sockaddr *addr,
|
|
char *str, int str_len)
|
|
{
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6) {
|
|
snprintk(str, str_len, "[%s]:%u",
|
|
net_sprint_ipv6_addr(&net_sin6(addr)->sin6_addr),
|
|
ntohs(net_sin6(addr)->sin6_port));
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) {
|
|
snprintk(str, str_len, "%s:%d",
|
|
net_sprint_ipv4_addr(&net_sin(addr)->sin_addr),
|
|
ntohs(net_sin(addr)->sin_port));
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
addr->sa_family == AF_PACKET) {
|
|
snprintk(str, str_len, "AF_PACKET");
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
addr->sa_family == AF_CAN) {
|
|
snprintk(str, str_len, "AF_CAN");
|
|
} else if (addr->sa_family == AF_UNSPEC) {
|
|
snprintk(str, str_len, "AF_UNSPEC");
|
|
} else {
|
|
snprintk(str, str_len, "AF_UNK(%d)", addr->sa_family);
|
|
}
|
|
}
|
|
|
|
static void capture_cb(struct net_capture_info *info, void *user_data)
|
|
{
|
|
struct net_shell_user_data *data = user_data;
|
|
const struct shell *sh = data->sh;
|
|
int *count = data->user_data;
|
|
char addr_local[ADDR_LEN + 7];
|
|
char addr_peer[ADDR_LEN + 7];
|
|
|
|
if (*count == 0) {
|
|
PR(" \t\tCapture Tunnel\n");
|
|
PR("Device\t\tiface iface Local\t\t\tPeer\n");
|
|
}
|
|
|
|
get_address_str(info->local, addr_local, sizeof(addr_local));
|
|
get_address_str(info->peer, addr_peer, sizeof(addr_peer));
|
|
|
|
PR("%s\t%c %d %s\t%s\n", info->capture_dev->name,
|
|
info->is_enabled ?
|
|
(net_if_get_by_iface(info->capture_iface) + '0') : '-',
|
|
net_if_get_by_iface(info->tunnel_iface),
|
|
addr_local, addr_peer);
|
|
|
|
(*count)++;
|
|
}
|
|
#endif
|
|
|
|
static int cmd_net_capture(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
bool ret;
|
|
|
|
if (capture_dev == NULL) {
|
|
capture_dev = device_get_binding(DEFAULT_DEV_NAME);
|
|
}
|
|
|
|
if (capture_dev == NULL) {
|
|
PR_INFO("Network packet capture %s\n", "not configured");
|
|
} else {
|
|
struct net_shell_user_data user_data;
|
|
int count = 0;
|
|
|
|
ret = net_capture_is_enabled(capture_dev);
|
|
PR_INFO("Network packet capture %s\n",
|
|
ret ? "enabled" : "disabled");
|
|
|
|
user_data.sh = sh;
|
|
user_data.user_data = &count;
|
|
|
|
net_capture_foreach(capture_cb, &user_data);
|
|
}
|
|
#else
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
PR_INFO("Set %s to enable %s support.\n",
|
|
"CONFIG_NET_CAPTURE", "network packet capture");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_capture_setup(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
int ret, arg = 1;
|
|
const char *remote, *local, *peer;
|
|
|
|
remote = argv[arg++];
|
|
if (!remote) {
|
|
PR_WARNING("Remote IP address not specified.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
local = argv[arg++];
|
|
if (!local) {
|
|
PR_WARNING("Local IP address not specified.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
peer = argv[arg];
|
|
if (!peer) {
|
|
PR_WARNING("Peer IP address not specified.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (capture_dev != NULL) {
|
|
PR_INFO("Capture already setup, cleaning up settings.\n");
|
|
net_capture_cleanup(capture_dev);
|
|
capture_dev = NULL;
|
|
}
|
|
|
|
ret = net_capture_setup(remote, local, peer, &capture_dev);
|
|
if (ret < 0) {
|
|
PR_WARNING("Capture cannot be setup (%d)\n", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
PR_INFO("Capture setup done, next enable it by "
|
|
"\"net capture enable <idx>\"\n");
|
|
#else
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
PR_INFO("Set %s to enable %s support.\n",
|
|
"CONFIG_NET_CAPTURE", "network packet capture");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_capture_cleanup(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
int ret;
|
|
|
|
if (capture_dev == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ret = net_capture_cleanup(capture_dev);
|
|
if (ret < 0) {
|
|
PR_WARNING("Capture %s failed (%d)\n", "cleanup", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
capture_dev = NULL;
|
|
#else
|
|
PR_INFO("Set %s to enable %s support.\n",
|
|
"CONFIG_NET_CAPTURE", "network packet capture");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_capture_enable(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
int ret, arg = 1, if_index;
|
|
struct net_if *iface;
|
|
|
|
if (capture_dev == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (argv[arg] == NULL) {
|
|
PR_WARNING("Interface index is missing. Please give interface "
|
|
"what you want to monitor\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if_index = atoi(argv[arg++]);
|
|
if (if_index == 0) {
|
|
PR_WARNING("Interface index %d is invalid.\n", if_index);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
iface = net_if_get_by_index(if_index);
|
|
if (iface == NULL) {
|
|
PR_WARNING("No such interface with index %d\n", if_index);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
ret = net_capture_enable(capture_dev, iface);
|
|
if (ret < 0) {
|
|
PR_WARNING("Capture %s failed (%d)\n", "enable", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
#else
|
|
PR_INFO("Set %s to enable %s support.\n",
|
|
"CONFIG_NET_CAPTURE", "network packet capture");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_capture_disable(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
#if defined(CONFIG_NET_CAPTURE)
|
|
int ret;
|
|
|
|
if (capture_dev == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
ret = net_capture_disable(capture_dev);
|
|
if (ret < 0) {
|
|
PR_WARNING("Capture %s failed (%d)\n", "disable", ret);
|
|
return -ENOEXEC;
|
|
}
|
|
#else
|
|
PR_INFO("Set %s to enable %s support.\n",
|
|
"CONFIG_NET_CAPTURE", "network packet capture");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_capture,
|
|
SHELL_CMD(setup, NULL, "Setup network packet capture.\n"
|
|
"'net capture setup <remote-ip-addr> <local-addr> <peer-addr>'\n"
|
|
"<remote> is the (outer) endpoint IP address,\n"
|
|
"<local> is the (inner) local IP address,\n"
|
|
"<peer> is the (inner) peer IP address\n"
|
|
"Local and Peer addresses can have UDP port number in them (optional)\n"
|
|
"like 198.0.51.2:9000 or [2001:db8:100::2]:4242",
|
|
cmd_net_capture_setup),
|
|
SHELL_CMD(cleanup, NULL, "Cleanup network packet capture.",
|
|
cmd_net_capture_cleanup),
|
|
SHELL_CMD(enable, NULL, "Enable network packet capture for a given "
|
|
"network interface.\n"
|
|
"'net capture enable <interface index>'",
|
|
cmd_net_capture_enable),
|
|
SHELL_CMD(disable, NULL, "Disable network packet capture.",
|
|
cmd_net_capture_disable),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_SUBCMD_ADD((net), capture, &net_cmd_capture,
|
|
"Configure network packet capture.", cmd_net_capture, 1, 0);
|