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