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