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 "net_shell_private.h"
12
cmd_net_nbr_rm(const struct shell * sh,size_t argc,char * argv[])13 static int cmd_net_nbr_rm(const struct shell *sh, size_t argc, char *argv[])
14 {
15 #if defined(CONFIG_NET_NATIVE_IPV6)
16 struct in6_addr addr;
17 int ret;
18
19 if (!argv[1]) {
20 PR_WARNING("Neighbor IPv6 address missing.\n");
21 return -ENOEXEC;
22 }
23
24 ret = net_addr_pton(AF_INET6, argv[1], &addr);
25 if (ret < 0) {
26 PR_WARNING("Cannot parse '%s'\n", argv[1]);
27 return -ENOEXEC;
28 }
29
30 if (!net_ipv6_nbr_rm(NULL, &addr)) {
31 PR_WARNING("Cannot remove neighbor %s\n",
32 net_sprint_ipv6_addr(&addr));
33 return -ENOEXEC;
34 }
35
36 PR("Neighbor %s removed.\n", net_sprint_ipv6_addr(&addr));
37 #else
38 ARG_UNUSED(sh);
39 ARG_UNUSED(argc);
40 ARG_UNUSED(argv);
41
42 PR_INFO("Native IPv6 not enabled.\n");
43 #endif
44
45 return 0;
46 }
47
48 #if defined(CONFIG_NET_NATIVE_IPV6)
nbr_cb(struct net_nbr * nbr,void * user_data)49 static void nbr_cb(struct net_nbr *nbr, void *user_data)
50 {
51 struct net_shell_user_data *data = user_data;
52 const struct shell *sh = data->sh;
53 int *count = data->user_data;
54 char *padding = "";
55 char *state_pad = "";
56 const char *state_str;
57 #if defined(CONFIG_NET_IPV6_ND)
58 int64_t remaining;
59 #endif
60
61 #if defined(CONFIG_NET_L2_IEEE802154)
62 padding = " ";
63 #endif
64
65 if (*count == 0) {
66 PR(" Neighbor Interface Flags State "
67 "Remain Link %sAddress\n", padding);
68 }
69
70 (*count)++;
71
72 state_str = net_ipv6_nbr_state2str(net_ipv6_nbr_data(nbr)->state);
73
74 /* This is not a proper way but the minimal libc does not honor
75 * string lengths in %s modifier so in order the output to look
76 * nice, do it like this.
77 */
78 if (strlen(state_str) == 5) {
79 state_pad = " ";
80 }
81
82 #if defined(CONFIG_NET_IPV6_ND)
83 remaining = net_ipv6_nbr_data(nbr)->reachable +
84 net_ipv6_nbr_data(nbr)->reachable_timeout -
85 k_uptime_get();
86 #endif
87
88 PR("[%2d] %p %d %5d/%d/%d/%d %s%s %6d %17s%s %s\n",
89 *count, nbr, net_if_get_by_iface(nbr->iface),
90 net_ipv6_nbr_data(nbr)->link_metric,
91 nbr->ref,
92 net_ipv6_nbr_data(nbr)->ns_count,
93 net_ipv6_nbr_data(nbr)->is_router,
94 state_str,
95 state_pad,
96 #if defined(CONFIG_NET_IPV6_ND)
97 (int)(remaining > 0 ? remaining : 0),
98 #else
99 0,
100 #endif
101 nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
102 net_sprint_ll_addr(
103 net_nbr_get_lladdr(nbr->idx)->addr,
104 net_nbr_get_lladdr(nbr->idx)->len),
105 nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "" :
106 (net_nbr_get_lladdr(nbr->idx)->len == 8U ? "" : padding),
107 net_sprint_ipv6_addr(&net_ipv6_nbr_data(nbr)->addr));
108 }
109 #endif
110
cmd_net_nbr(const struct shell * sh,size_t argc,char * argv[])111 static int cmd_net_nbr(const struct shell *sh, size_t argc, char *argv[])
112 {
113 #if defined(CONFIG_NET_NATIVE_IPV6)
114 int count = 0;
115 struct net_shell_user_data user_data;
116
117 user_data.sh = sh;
118 user_data.user_data = &count;
119
120 net_ipv6_nbr_foreach(nbr_cb, &user_data);
121
122 if (count == 0) {
123 PR("No neighbors.\n");
124 }
125 #else
126 ARG_UNUSED(sh);
127 ARG_UNUSED(argc);
128 ARG_UNUSED(argv);
129
130 PR_INFO("Native IPv6 not enabled.\n");
131 #endif /* CONFIG_NET_NATIVE_IPV6 */
132
133 return 0;
134 }
135
136 #if defined(CONFIG_NET_NATIVE_IPV6) && defined(CONFIG_NET_SHELL_DYN_CMD_COMPLETION)
137 static char nbr_address_buffer[CONFIG_NET_IPV6_MAX_NEIGHBORS][NET_IPV6_ADDR_LEN];
138
nbr_address_cb(struct net_nbr * nbr,void * user_data)139 static void nbr_address_cb(struct net_nbr *nbr, void *user_data)
140 {
141 int *count = user_data;
142
143 if (*count >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
144 return;
145 }
146
147 snprintk(nbr_address_buffer[*count], NET_IPV6_ADDR_LEN,
148 "%s", net_sprint_ipv6_addr(&net_ipv6_nbr_data(nbr)->addr));
149
150 (*count)++;
151 }
152
nbr_populate_addresses(void)153 static void nbr_populate_addresses(void)
154 {
155 int count = 0;
156
157 net_ipv6_nbr_foreach(nbr_address_cb, &count);
158 }
159
set_nbr_address(size_t idx)160 static char *set_nbr_address(size_t idx)
161 {
162 if (idx == 0) {
163 memset(nbr_address_buffer, 0, sizeof(nbr_address_buffer));
164 nbr_populate_addresses();
165 }
166
167 if (idx >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
168 return NULL;
169 }
170
171 if (!nbr_address_buffer[idx][0]) {
172 return NULL;
173 }
174
175 return nbr_address_buffer[idx];
176 }
177
178 static void nbr_address_get(size_t idx, struct shell_static_entry *entry);
179
180 SHELL_DYNAMIC_CMD_CREATE(nbr_address, nbr_address_get);
181
182 #define NBR_ADDRESS_CMD &nbr_address
183
nbr_address_get(size_t idx,struct shell_static_entry * entry)184 static void nbr_address_get(size_t idx, struct shell_static_entry *entry)
185 {
186 entry->handler = NULL;
187 entry->help = NULL;
188 entry->subcmd = &nbr_address;
189 entry->syntax = set_nbr_address(idx);
190 }
191
192 #else
193 #define NBR_ADDRESS_CMD NULL
194 #endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_SHELL_DYN_CMD_COMPLETION */
195
196 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_nbr,
197 SHELL_CMD(rm, NBR_ADDRESS_CMD,
198 "'net nbr rm <address>' removes neighbor from cache.",
199 cmd_net_nbr_rm),
200 SHELL_SUBCMD_SET_END
201 );
202
203 SHELL_SUBCMD_ADD((net), nbr, &net_cmd_nbr,
204 "Print neighbor information.",
205 cmd_net_nbr, 1, 0);
206