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