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 <zephyr/net/igmp.h>
12 
13 #include "net_shell_private.h"
14 #include "../ip/ipv4.h"
15 
16 #if defined(CONFIG_NET_IPV4)
ip_address_lifetime_cb(struct net_if * iface,void * user_data)17 static void ip_address_lifetime_cb(struct net_if *iface, void *user_data)
18 {
19 	struct net_shell_user_data *data = user_data;
20 	const struct shell *sh = data->sh;
21 	struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
22 	const char *extra;
23 
24 	ARG_UNUSED(user_data);
25 
26 	PR("\nIPv4 addresses for interface %d (%p) (%s)\n",
27 	   net_if_get_by_iface(iface), iface, iface2str(iface, &extra));
28 	PR("============================================%s\n", extra);
29 
30 	if (!ipv4) {
31 		PR("No IPv4 config found for this interface.\n");
32 		return;
33 	}
34 
35 	PR("Type      \tState    \tRef\tAddress\n");
36 
37 	ARRAY_FOR_EACH(ipv4->unicast, i) {
38 		if (!ipv4->unicast[i].ipv4.is_used ||
39 		    ipv4->unicast[i].ipv4.address.family != AF_INET) {
40 			continue;
41 		}
42 
43 		PR("%s  \t%s    \t%ld\t%s/%s\n",
44 		   addrtype2str(ipv4->unicast[i].ipv4.addr_type),
45 		   addrstate2str(ipv4->unicast[i].ipv4.addr_state),
46 		   atomic_get(&ipv4->unicast[i].ipv4.atomic_ref),
47 		   net_sprint_ipv4_addr(
48 			   &ipv4->unicast[i].ipv4.address.in_addr),
49 		   net_sprint_ipv4_addr(
50 			   &ipv4->unicast[i].netmask));
51 	}
52 }
53 #endif /* CONFIG_NET_IPV4 */
54 
cmd_net_ipv4(const struct shell * sh,size_t argc,char * argv[])55 static int cmd_net_ipv4(const struct shell *sh, size_t argc, char *argv[])
56 {
57 	PR("IPv4 support                              : %s\n",
58 	   IS_ENABLED(CONFIG_NET_IPV4) ?
59 	   "enabled" : "disabled");
60 	if (!IS_ENABLED(CONFIG_NET_IPV4)) {
61 		return -ENOEXEC;
62 	}
63 
64 #if defined(CONFIG_NET_NATIVE_IPV4)
65 	PR("IPv4 fragmentation support                : %s\n",
66 	   IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT) ? "enabled" :
67 	   "disabled");
68 	PR("IPv4 conflict detection support           : %s\n",
69 	   IS_ENABLED(CONFIG_NET_IPV4_ACD) ? "enabled" :
70 	   "disabled");
71 	PR("Path MTU Discovery (PMTU)                 : %s\n",
72 	   IS_ENABLED(CONFIG_NET_IPV4_PMTU) ? "enabled" : "disabled");
73 #endif /* CONFIG_NET_NATIVE_IPV4 */
74 
75 #if defined(CONFIG_NET_IPV4)
76 	struct net_shell_user_data user_data;
77 
78 	PR("Max number of IPv4 network interfaces "
79 	   "in the system          : %d\n",
80 	   CONFIG_NET_IF_MAX_IPV4_COUNT);
81 	PR("Max number of unicast IPv4 addresses "
82 	   "per network interface   : %d\n",
83 	   CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT);
84 	PR("Max number of multicast IPv4 addresses "
85 	   "per network interface : %d\n",
86 	   CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT);
87 
88 	user_data.sh = sh;
89 	user_data.user_data = NULL;
90 
91 	/* Print information about address lifetime */
92 	net_if_foreach(ip_address_lifetime_cb, &user_data);
93 #endif /* CONFIG_NET_IPV4 */
94 
95 	return 0;
96 }
97 
cmd_net_ip_add(const struct shell * sh,size_t argc,char * argv[])98 static int cmd_net_ip_add(const struct shell *sh, size_t argc, char *argv[])
99 {
100 #if defined(CONFIG_NET_IPV4)
101 	struct net_if *iface = NULL;
102 	int idx;
103 	struct in_addr addr;
104 
105 	if (argc < 3) {
106 		PR_ERROR("Correct usage: net ipv4 add <index> <address> [<netmask>]\n");
107 		return -EINVAL;
108 	}
109 
110 	idx = get_iface_idx(sh, argv[1]);
111 	if (idx < 0) {
112 		return -ENOEXEC;
113 	}
114 
115 	iface = net_if_get_by_index(idx);
116 	if (!iface) {
117 		PR_WARNING("No such interface in index %d\n", idx);
118 		return -ENOEXEC;
119 	}
120 
121 	if (net_addr_pton(AF_INET, argv[2], &addr)) {
122 		PR_ERROR("Invalid address: %s\n", argv[2]);
123 		return -EINVAL;
124 	}
125 
126 	if (net_ipv4_is_addr_mcast(&addr)) {
127 		int ret;
128 
129 		ret = net_ipv4_igmp_join(iface, &addr, NULL);
130 		if (ret < 0) {
131 			PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n",
132 				 "join", net_sprint_ipv4_addr(&addr), idx, ret);
133 			return ret;
134 		}
135 	} else {
136 		struct net_if_addr *ifaddr;
137 		struct in_addr netmask;
138 
139 		if (argc < 4) {
140 			PR_ERROR("Netmask is missing.\n");
141 			return -EINVAL;
142 		}
143 
144 		ifaddr = net_if_ipv4_addr_add(iface, &addr, NET_ADDR_MANUAL, 0);
145 		if (ifaddr == NULL) {
146 			PR_ERROR("Cannot add address %s to interface %d\n",
147 				 net_sprint_ipv4_addr(&addr), idx);
148 			return -ENOMEM;
149 		}
150 
151 		if (net_addr_pton(AF_INET, argv[3], &netmask)) {
152 			PR_ERROR("Invalid netmask: %s", argv[3]);
153 			return -EINVAL;
154 		}
155 
156 		net_if_ipv4_set_netmask_by_addr(iface, &addr, &netmask);
157 	}
158 
159 #else /* CONFIG_NET_IPV4 */
160 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_IPV4", "IPv4");
161 #endif /* CONFIG_NET_IPV4 */
162 	return 0;
163 }
164 
cmd_net_ip_del(const struct shell * sh,size_t argc,char * argv[])165 static int cmd_net_ip_del(const struct shell *sh, size_t argc, char *argv[])
166 {
167 #if defined(CONFIG_NET_IPV4)
168 	struct net_if *iface = NULL;
169 	int idx;
170 	struct in_addr addr;
171 
172 	if (argc != 3) {
173 		PR_ERROR("Correct usage: net ipv4 del <index> <address>");
174 		return -EINVAL;
175 	}
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_INET, argv[2], &addr)) {
189 		PR_ERROR("Invalid address: %s\n", argv[2]);
190 		return -EINVAL;
191 	}
192 
193 	if (net_ipv4_is_addr_mcast(&addr)) {
194 		int ret;
195 
196 		ret = net_ipv4_igmp_leave(iface, &addr);
197 		if (ret < 0) {
198 			PR_ERROR("Cannot %s multicast group %s for interface %d (%d)\n",
199 				 "leave", net_sprint_ipv4_addr(&addr), idx, ret);
200 			return ret;
201 		}
202 	} else {
203 		if (!net_if_ipv4_addr_rm(iface, &addr)) {
204 			PR_ERROR("Failed to delete %s\n", argv[2]);
205 			return -ENOEXEC;
206 		}
207 	}
208 #else /* CONFIG_NET_IPV4 */
209 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_IPV4", "IPv4");
210 #endif /* CONFIG_NET_IPV4 */
211 	return 0;
212 }
213 
cmd_net_ip_gateway(const struct shell * sh,size_t argc,char * argv[])214 static int cmd_net_ip_gateway(const struct shell *sh, size_t argc, char *argv[])
215 {
216 #if defined(CONFIG_NET_IPV4)
217 	struct net_if *iface;
218 	int idx;
219 	struct in_addr addr;
220 
221 	if (argc != 3) {
222 		PR_ERROR("Correct usage: net ipv4 gateway <index> <gateway_ip>\n");
223 		return -ENOEXEC;
224 	}
225 
226 	idx = get_iface_idx(sh, argv[1]);
227 	if (idx < 0) {
228 		return -ENOEXEC;
229 	}
230 
231 	iface = net_if_get_by_index(idx);
232 	if (!iface) {
233 		PR_WARNING("No such interface in index %d\n", idx);
234 		return -ENOEXEC;
235 	}
236 
237 	if (net_addr_pton(AF_INET, argv[2], &addr)) {
238 		PR_ERROR("Invalid address: %s\n", argv[2]);
239 		return -EINVAL;
240 	}
241 
242 	net_if_ipv4_set_gw(iface, &addr);
243 
244 #else /* CONFIG_NET_IPV4 */
245 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_IPV4", "IPv4");
246 #endif /* CONFIG_NET_IPV4 */
247 	return 0;
248 }
249 
250 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_ip,
251 	SHELL_CMD(add, NULL,
252 		  "'net ipv4 add <index> <address> [<netmask>]' adds the address to the interface.",
253 		  cmd_net_ip_add),
254 	SHELL_CMD(del, NULL,
255 		  "'net ipv4 del <index> <address>' deletes the address from the interface.",
256 		  cmd_net_ip_del),
257 	SHELL_CMD(gateway, NULL,
258 		  "'net ipv4 gateway <index> <gateway_ip>' sets IPv4 gateway for the interface.",
259 		  cmd_net_ip_gateway),
260 	SHELL_SUBCMD_SET_END
261 );
262 
263 SHELL_SUBCMD_ADD((net), ipv4, &net_cmd_ip,
264 		 "Print information about IPv4 specific information and "
265 		 "configuration.",
266 		 cmd_net_ipv4, 1, 0);
267