| /* |
| * 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); |