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
13 #include "../ip/route.h"
14
15 #if defined(CONFIG_NET_ROUTE) && defined(CONFIG_NET_NATIVE)
route_cb(struct net_route_entry * entry,void * user_data)16 static void route_cb(struct net_route_entry *entry, void *user_data)
17 {
18 struct net_shell_user_data *data = user_data;
19 const struct shell *sh = data->sh;
20 struct net_if *iface = data->user_data;
21 struct net_route_nexthop *nexthop_route;
22 int count;
23 uint32_t now = k_uptime_get_32();
24
25 if (entry->iface != iface) {
26 return;
27 }
28
29 PR("IPv6 prefix : %s/%d\n", net_sprint_ipv6_addr(&entry->addr),
30 entry->prefix_len);
31
32 count = 0;
33
34 SYS_SLIST_FOR_EACH_CONTAINER(&entry->nexthop, nexthop_route, node) {
35 struct net_linkaddr_storage *lladdr;
36 char remaining_str[sizeof("01234567890 sec")];
37 uint32_t remaining;
38
39 if (!nexthop_route->nbr) {
40 continue;
41 }
42
43 PR("\tneighbor : %p\t", nexthop_route->nbr);
44
45 if (nexthop_route->nbr->idx == NET_NBR_LLADDR_UNKNOWN) {
46 PR("addr : <unknown>\t");
47 } else {
48 lladdr = net_nbr_get_lladdr(nexthop_route->nbr->idx);
49
50 PR("addr : %s\t", net_sprint_ll_addr(lladdr->addr,
51 lladdr->len));
52 }
53
54 if (entry->is_infinite) {
55 snprintk(remaining_str, sizeof(remaining_str) - 1,
56 "infinite");
57 } else {
58 remaining = net_timeout_remaining(&entry->lifetime, now);
59 snprintk(remaining_str, sizeof(remaining_str) - 1,
60 "%u sec", remaining);
61 }
62
63 PR("lifetime : %s\n", remaining_str);
64
65 count++;
66 }
67
68 if (count == 0) {
69 PR("\t<none>\n");
70 }
71 }
72
iface_per_route_cb(struct net_if * iface,void * user_data)73 static void iface_per_route_cb(struct net_if *iface, void *user_data)
74 {
75 struct net_shell_user_data *data = user_data;
76 const struct shell *sh = data->sh;
77 const char *extra;
78
79 PR("\nIPv6 routes for interface %d (%p) (%s)\n",
80 net_if_get_by_iface(iface), iface,
81 iface2str(iface, &extra));
82 PR("=========================================%s\n", extra);
83
84 data->user_data = iface;
85
86 net_route_foreach(route_cb, data);
87 }
88 #endif /* CONFIG_NET_ROUTE */
89
90 #if defined(CONFIG_NET_ROUTE_MCAST) && defined(CONFIG_NET_NATIVE)
route_mcast_cb(struct net_route_entry_mcast * entry,void * user_data)91 static void route_mcast_cb(struct net_route_entry_mcast *entry,
92 void *user_data)
93 {
94 struct net_shell_user_data *data = user_data;
95 const struct shell *sh = data->sh;
96
97 PR("IPv6 multicast route (%p)\n", entry);
98 PR("=================================\n");
99
100 PR("IPv6 group : %s\n", net_sprint_ipv6_addr(&entry->group));
101 PR("IPv6 group len : %d\n", entry->prefix_len);
102 PR("Lifetime : %u\n", entry->lifetime);
103
104 for (int i = 0; i < CONFIG_NET_MCAST_ROUTE_MAX_IFACES; ++i) {
105 if (entry->ifaces[i]) {
106 PR("Interface : %d (%p) %s\n", net_if_get_by_iface(entry->ifaces[i]),
107 entry->ifaces[i], iface2str(entry->ifaces[i], NULL));
108 }
109 }
110 }
111 #endif /* CONFIG_NET_ROUTE_MCAST */
112
cmd_net_ip6_route_add(const struct shell * sh,size_t argc,char * argv[])113 static int cmd_net_ip6_route_add(const struct shell *sh, size_t argc, char *argv[])
114 {
115 #if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
116 struct net_if *iface = NULL;
117 int idx;
118 struct net_route_entry *route;
119 struct in6_addr gw = {0};
120 struct in6_addr prefix = {0};
121
122 if (argc != 4) {
123 PR_ERROR("Correct usage: net route add <index> "
124 "<destination> <gateway>\n");
125 return -EINVAL;
126 }
127
128 idx = get_iface_idx(sh, argv[1]);
129 if (idx < 0) {
130 return -ENOEXEC;
131 }
132
133 iface = net_if_get_by_index(idx);
134 if (!iface) {
135 PR_WARNING("No such interface in index %d\n", idx);
136 return -ENOEXEC;
137 }
138
139 if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
140 PR_ERROR("Invalid address: %s\n", argv[2]);
141 return -EINVAL;
142 }
143
144 if (net_addr_pton(AF_INET6, argv[3], &gw)) {
145 PR_ERROR("Invalid gateway: %s\n", argv[3]);
146 return -EINVAL;
147 }
148
149 route = net_route_add(iface, &prefix, NET_IPV6_DEFAULT_PREFIX_LEN,
150 &gw, NET_IPV6_ND_INFINITE_LIFETIME,
151 NET_ROUTE_PREFERENCE_MEDIUM);
152 if (route == NULL) {
153 PR_ERROR("Failed to add route\n");
154 return -ENOEXEC;
155 }
156
157 #else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
158 PR_INFO("Set %s and %s to enable native %s support."
159 " And enable CONFIG_NET_ROUTE.\n",
160 "CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
161 #endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
162 return 0;
163 }
164
cmd_net_ip6_route_del(const struct shell * sh,size_t argc,char * argv[])165 static int cmd_net_ip6_route_del(const struct shell *sh, size_t argc, char *argv[])
166 {
167 #if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
168 struct net_if *iface = NULL;
169 int idx;
170 struct net_route_entry *route;
171 struct in6_addr prefix = { 0 };
172
173 if (argc != 3) {
174 PR_ERROR("Correct usage: net route del <index> <destination>\n");
175 return -EINVAL;
176 }
177 idx = get_iface_idx(sh, argv[1]);
178 if (idx < 0) {
179 return -ENOEXEC;
180 }
181
182 iface = net_if_get_by_index(idx);
183 if (!iface) {
184 PR_WARNING("No such interface in index %d\n", idx);
185 return -ENOEXEC;
186 }
187
188 if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
189 PR_ERROR("Invalid address: %s\n", argv[2]);
190 return -EINVAL;
191 }
192
193 route = net_route_lookup(iface, &prefix);
194 if (route) {
195 net_route_del(route);
196 }
197 #else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
198 PR_INFO("Set %s and %s to enable native %s support."
199 " And enable CONFIG_NET_ROUTE\n",
200 "CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
201 #endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
202 return 0;
203 }
204
cmd_net_route(const struct shell * sh,size_t argc,char * argv[])205 static int cmd_net_route(const struct shell *sh, size_t argc, char *argv[])
206 {
207 ARG_UNUSED(argc);
208 ARG_UNUSED(argv);
209
210 #if defined(CONFIG_NET_NATIVE)
211 #if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
212 struct net_shell_user_data user_data;
213 #endif
214
215 #if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
216 user_data.sh = sh;
217 #endif
218
219 #if defined(CONFIG_NET_ROUTE)
220 net_if_foreach(iface_per_route_cb, &user_data);
221 #else
222 PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_ROUTE",
223 "network route");
224 #endif
225
226 #if defined(CONFIG_NET_ROUTE_MCAST)
227 net_route_mcast_foreach(route_mcast_cb, NULL, &user_data);
228 #endif
229 #endif
230 return 0;
231 }
232
233 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_route,
234 SHELL_CMD(add, NULL,
235 "'net route add <index> <destination> <gateway>'"
236 " adds the route to the destination.",
237 cmd_net_ip6_route_add),
238 SHELL_CMD(del, NULL,
239 "'net route del <index> <destination>'"
240 " deletes the route to the destination.",
241 cmd_net_ip6_route_del),
242 SHELL_SUBCMD_SET_END
243 );
244
245 SHELL_SUBCMD_ADD((net), route, &net_cmd_route,
246 "Show network route.",
247 cmd_net_route, 1, 0);
248