blob: 63b624067020677122894b3345509b1422069501 [file] [log] [blame]
/*
* 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 "net_shell_private.h"
static int cmd_net_nbr_rm(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_IPV6)
struct in6_addr addr;
int ret;
#endif
#if defined(CONFIG_NET_IPV6)
if (!argv[1]) {
PR_WARNING("Neighbor IPv6 address missing.\n");
return -ENOEXEC;
}
ret = net_addr_pton(AF_INET6, argv[1], &addr);
if (ret < 0) {
PR_WARNING("Cannot parse '%s'\n", argv[1]);
return -ENOEXEC;
}
if (!net_ipv6_nbr_rm(NULL, &addr)) {
PR_WARNING("Cannot remove neighbor %s\n",
net_sprint_ipv6_addr(&addr));
return -ENOEXEC;
}
PR("Neighbor %s removed.\n", net_sprint_ipv6_addr(&addr));
#else
ARG_UNUSED(argc);
ARG_UNUSED(argv);
PR_INFO("IPv6 not enabled.\n");
#endif
return 0;
}
#if defined(CONFIG_NET_IPV6)
static void nbr_cb(struct net_nbr *nbr, void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
int *count = data->user_data;
char *padding = "";
char *state_pad = "";
const char *state_str;
#if defined(CONFIG_NET_IPV6_ND)
int64_t remaining;
#endif
#if defined(CONFIG_NET_L2_IEEE802154)
padding = " ";
#endif
if (*count == 0) {
PR(" Neighbor Interface Flags State "
"Remain Link %sAddress\n", padding);
}
(*count)++;
state_str = net_ipv6_nbr_state2str(net_ipv6_nbr_data(nbr)->state);
/* This is not a proper way but the minimal libc does not honor
* string lengths in %s modifier so in order the output to look
* nice, do it like this.
*/
if (strlen(state_str) == 5) {
state_pad = " ";
}
#if defined(CONFIG_NET_IPV6_ND)
remaining = net_ipv6_nbr_data(nbr)->reachable +
net_ipv6_nbr_data(nbr)->reachable_timeout -
k_uptime_get();
#endif
PR("[%2d] %p %d %5d/%d/%d/%d %s%s %6d %17s%s %s\n",
*count, nbr, net_if_get_by_iface(nbr->iface),
net_ipv6_nbr_data(nbr)->link_metric,
nbr->ref,
net_ipv6_nbr_data(nbr)->ns_count,
net_ipv6_nbr_data(nbr)->is_router,
state_str,
state_pad,
#if defined(CONFIG_NET_IPV6_ND)
(int)(remaining > 0 ? remaining : 0),
#else
0,
#endif
nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
net_sprint_ll_addr(
net_nbr_get_lladdr(nbr->idx)->addr,
net_nbr_get_lladdr(nbr->idx)->len),
nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "" :
(net_nbr_get_lladdr(nbr->idx)->len == 8U ? "" : padding),
net_sprint_ipv6_addr(&net_ipv6_nbr_data(nbr)->addr));
}
#endif
static int cmd_net_nbr(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_IPV6)
int count = 0;
struct net_shell_user_data user_data;
#endif
ARG_UNUSED(argc);
ARG_UNUSED(argv);
#if defined(CONFIG_NET_IPV6)
user_data.sh = sh;
user_data.user_data = &count;
net_ipv6_nbr_foreach(nbr_cb, &user_data);
if (count == 0) {
PR("No neighbors.\n");
}
#else
PR_INFO("IPv6 not enabled.\n");
#endif /* CONFIG_NET_IPV6 */
return 0;
}
#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
static char nbr_address_buffer[CONFIG_NET_IPV6_MAX_NEIGHBORS][NET_IPV6_ADDR_LEN];
static void nbr_address_cb(struct net_nbr *nbr, void *user_data)
{
int *count = user_data;
if (*count >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
return;
}
snprintk(nbr_address_buffer[*count], NET_IPV6_ADDR_LEN,
"%s", net_sprint_ipv6_addr(&net_ipv6_nbr_data(nbr)->addr));
(*count)++;
}
static void nbr_populate_addresses(void)
{
int count = 0;
net_ipv6_nbr_foreach(nbr_address_cb, &count);
}
static char *set_nbr_address(size_t idx)
{
if (idx == 0) {
memset(nbr_address_buffer, 0, sizeof(nbr_address_buffer));
nbr_populate_addresses();
}
if (idx >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
return NULL;
}
if (!nbr_address_buffer[idx][0]) {
return NULL;
}
return nbr_address_buffer[idx];
}
static void nbr_address_get(size_t idx, struct shell_static_entry *entry);
SHELL_DYNAMIC_CMD_CREATE(nbr_address, nbr_address_get);
#define NBR_ADDRESS_CMD &nbr_address
static void nbr_address_get(size_t idx, struct shell_static_entry *entry)
{
entry->handler = NULL;
entry->help = NULL;
entry->subcmd = &nbr_address;
entry->syntax = set_nbr_address(idx);
}
#else
#define NBR_ADDRESS_CMD NULL
#endif /* CONFIG_NET_IPV6 && CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_nbr,
SHELL_CMD(rm, NBR_ADDRESS_CMD,
"'net nbr rm <address>' removes neighbor from cache.",
cmd_net_nbr_rm),
SHELL_SUBCMD_SET_END
);
SHELL_SUBCMD_ADD((net), nbr, &net_cmd_nbr,
"Print neighbor information.",
cmd_net_nbr, 1, 0);