zephyr/subsys/net/lib/shell/route.c
Jukka Rissanen ac3cb9dac0 net: Change the net_linkaddr struct to not use pointers
Previously the net_linkaddr struct had pointers to the link address.
This is error prone and difficult to handle if cloning the packet as
those pointers can point to wrong place. Mitigate this issue by
allocating the space for link address in net_linkaddr struct. This will
increase the size of the net_pkt by 4 octets for IEEE 802.15.4 where the
link address length is 8, but there no increase in size if link address
is 6 bytes like in Ethernet/Wi-Fi.

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
2025-03-17 16:25:22 +01:00

248 lines
6.2 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 "net_shell_private.h"
#include "../ip/route.h"
#if defined(CONFIG_NET_ROUTE) && defined(CONFIG_NET_NATIVE)
static void route_cb(struct net_route_entry *entry, void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
struct net_if *iface = data->user_data;
struct net_route_nexthop *nexthop_route;
int count;
uint32_t now = k_uptime_get_32();
if (entry->iface != iface) {
return;
}
PR("IPv6 prefix : %s/%d\n", net_sprint_ipv6_addr(&entry->addr),
entry->prefix_len);
count = 0;
SYS_SLIST_FOR_EACH_CONTAINER(&entry->nexthop, nexthop_route, node) {
struct net_linkaddr *lladdr;
char remaining_str[sizeof("01234567890 sec")];
uint32_t remaining;
if (!nexthop_route->nbr) {
continue;
}
PR("\tneighbor : %p\t", nexthop_route->nbr);
if (nexthop_route->nbr->idx == NET_NBR_LLADDR_UNKNOWN) {
PR("addr : <unknown>\t");
} else {
lladdr = net_nbr_get_lladdr(nexthop_route->nbr->idx);
PR("addr : %s\t", net_sprint_ll_addr(lladdr->addr,
lladdr->len));
}
if (entry->is_infinite) {
snprintk(remaining_str, sizeof(remaining_str) - 1,
"infinite");
} else {
remaining = net_timeout_remaining(&entry->lifetime, now);
snprintk(remaining_str, sizeof(remaining_str) - 1,
"%u sec", remaining);
}
PR("lifetime : %s\n", remaining_str);
count++;
}
if (count == 0) {
PR("\t<none>\n");
}
}
static void iface_per_route_cb(struct net_if *iface, void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
const char *extra;
PR("\nIPv6 routes for interface %d (%p) (%s)\n",
net_if_get_by_iface(iface), iface,
iface2str(iface, &extra));
PR("=========================================%s\n", extra);
data->user_data = iface;
net_route_foreach(route_cb, data);
}
#endif /* CONFIG_NET_ROUTE */
#if defined(CONFIG_NET_ROUTE_MCAST) && defined(CONFIG_NET_NATIVE)
static void route_mcast_cb(struct net_route_entry_mcast *entry,
void *user_data)
{
struct net_shell_user_data *data = user_data;
const struct shell *sh = data->sh;
PR("IPv6 multicast route (%p)\n", entry);
PR("=================================\n");
PR("IPv6 group : %s\n", net_sprint_ipv6_addr(&entry->group));
PR("IPv6 group len : %d\n", entry->prefix_len);
PR("Lifetime : %u\n", entry->lifetime);
for (int i = 0; i < CONFIG_NET_MCAST_ROUTE_MAX_IFACES; ++i) {
if (entry->ifaces[i]) {
PR("Interface : %d (%p) %s\n", net_if_get_by_iface(entry->ifaces[i]),
entry->ifaces[i], iface2str(entry->ifaces[i], NULL));
}
}
}
#endif /* CONFIG_NET_ROUTE_MCAST */
static int cmd_net_ip6_route_add(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
struct net_if *iface = NULL;
int idx;
struct net_route_entry *route;
struct in6_addr gw = {0};
struct in6_addr prefix = {0};
if (argc != 4) {
PR_ERROR("Correct usage: net route add <index> "
"<destination> <gateway>\n");
return -EINVAL;
}
idx = get_iface_idx(sh, argv[1]);
if (idx < 0) {
return -ENOEXEC;
}
iface = net_if_get_by_index(idx);
if (!iface) {
PR_WARNING("No such interface in index %d\n", idx);
return -ENOEXEC;
}
if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
PR_ERROR("Invalid address: %s\n", argv[2]);
return -EINVAL;
}
if (net_addr_pton(AF_INET6, argv[3], &gw)) {
PR_ERROR("Invalid gateway: %s\n", argv[3]);
return -EINVAL;
}
route = net_route_add(iface, &prefix, NET_IPV6_DEFAULT_PREFIX_LEN,
&gw, NET_IPV6_ND_INFINITE_LIFETIME,
NET_ROUTE_PREFERENCE_MEDIUM);
if (route == NULL) {
PR_ERROR("Failed to add route\n");
return -ENOEXEC;
}
#else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
PR_INFO("Set %s and %s to enable native %s support."
" And enable CONFIG_NET_ROUTE.\n",
"CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
#endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
return 0;
}
static int cmd_net_ip6_route_del(const struct shell *sh, size_t argc, char *argv[])
{
#if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
struct net_if *iface = NULL;
int idx;
struct net_route_entry *route;
struct in6_addr prefix = { 0 };
if (argc != 3) {
PR_ERROR("Correct usage: net route del <index> <destination>\n");
return -EINVAL;
}
idx = get_iface_idx(sh, argv[1]);
if (idx < 0) {
return -ENOEXEC;
}
iface = net_if_get_by_index(idx);
if (!iface) {
PR_WARNING("No such interface in index %d\n", idx);
return -ENOEXEC;
}
if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
PR_ERROR("Invalid address: %s\n", argv[2]);
return -EINVAL;
}
route = net_route_lookup(iface, &prefix);
if (route) {
net_route_del(route);
}
#else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
PR_INFO("Set %s and %s to enable native %s support."
" And enable CONFIG_NET_ROUTE\n",
"CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
#endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
return 0;
}
static int cmd_net_route(const struct shell *sh, size_t argc, char *argv[])
{
ARG_UNUSED(argc);
ARG_UNUSED(argv);
#if defined(CONFIG_NET_NATIVE)
#if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
struct net_shell_user_data user_data;
#endif
#if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
user_data.sh = sh;
#endif
#if defined(CONFIG_NET_ROUTE)
net_if_foreach(iface_per_route_cb, &user_data);
#else
PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_ROUTE",
"network route");
#endif
#if defined(CONFIG_NET_ROUTE_MCAST)
net_route_mcast_foreach(route_mcast_cb, NULL, &user_data);
#endif
#endif
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_route,
SHELL_CMD(add, NULL,
"'net route add <index> <destination> <gateway>'"
" adds the route to the destination.",
cmd_net_ip6_route_add),
SHELL_CMD(del, NULL,
"'net route del <index> <destination>'"
" deletes the route to the destination.",
cmd_net_ip6_route_del),
SHELL_SUBCMD_SET_END
);
SHELL_SUBCMD_ADD((net), route, &net_cmd_route,
"Show network route.",
cmd_net_route, 1, 0);