Skip to content

Commit 2c70c5d

Browse files
rlubosfabiobaltieri
authored andcommitted
net: shell: Implement DHCPv4 server shell commands
Implement DHCPv4 shell module, which allows to start/stop DHCPv4 server operation, and print server status (address leases). Signed-off-by: Robert Lubos <[email protected]>
1 parent 3bc5087 commit 2c70c5d

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

subsys/net/lib/shell/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ zephyr_library_sources(allocs.c)
1010
zephyr_library_sources(arp.c)
1111
zephyr_library_sources(capture.c)
1212
zephyr_library_sources(conn.c)
13+
zephyr_library_sources(dhcpv4.c)
1314
zephyr_library_sources(dns.c)
1415
zephyr_library_sources(events.c)
1516
zephyr_library_sources(gptp.c)

subsys/net/lib/shell/dhcpv4.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/logging/log.h>
8+
LOG_MODULE_DECLARE(net_shell);
9+
10+
#include <stdint.h>
11+
#include <zephyr/net/dhcpv4_server.h>
12+
#include <zephyr/net/socket.h>
13+
14+
#include "net_shell_private.h"
15+
16+
static int cmd_net_dhcpv4_server_start(const struct shell *sh, size_t argc, char *argv[])
17+
{
18+
#if defined(CONFIG_NET_DHCPV4_SERVER)
19+
struct net_if *iface = NULL;
20+
struct in_addr base_addr;
21+
int idx, ret;
22+
23+
idx = get_iface_idx(sh, argv[1]);
24+
if (idx < 0) {
25+
return -ENOEXEC;
26+
}
27+
28+
iface = net_if_get_by_index(idx);
29+
if (!iface) {
30+
PR_WARNING("No such interface in index %d\n", idx);
31+
return -ENOEXEC;
32+
}
33+
34+
if (net_addr_pton(AF_INET, argv[2], &base_addr)) {
35+
PR_ERROR("Invalid address: %s\n", argv[2]);
36+
return -EINVAL;
37+
}
38+
39+
ret = net_dhcpv4_server_start(iface, &base_addr);
40+
if (ret == -EALREADY) {
41+
PR_WARNING("DHCPv4 server already running on interface %d\n", idx);
42+
} else if (ret < 0) {
43+
PR_ERROR("DHCPv4 server failed to start on interface %d, error %d\n",
44+
idx, -ret);
45+
} else {
46+
PR("DHCPv4 server started on interface %d\n", idx);
47+
}
48+
#else /* CONFIG_NET_DHCPV4_SERVER */
49+
PR_INFO("Set %s to enable %s support.\n",
50+
"CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server");
51+
#endif /* CONFIG_NET_DHCPV4_SERVER */
52+
return 0;
53+
}
54+
55+
static int cmd_net_dhcpv4_server_stop(const struct shell *sh, size_t argc, char *argv[])
56+
{
57+
#if defined(CONFIG_NET_DHCPV4_SERVER)
58+
struct net_if *iface = NULL;
59+
int idx, ret;
60+
61+
idx = get_iface_idx(sh, argv[1]);
62+
if (idx < 0) {
63+
return -ENOEXEC;
64+
}
65+
66+
iface = net_if_get_by_index(idx);
67+
if (!iface) {
68+
PR_WARNING("No such interface in index %d\n", idx);
69+
return -ENOEXEC;
70+
}
71+
72+
ret = net_dhcpv4_server_stop(iface);
73+
if (ret == -ENOENT) {
74+
PR_WARNING("DHCPv4 server is not running on interface %d\n", idx);
75+
} else if (ret < 0) {
76+
PR_ERROR("DHCPv4 server failed to stop on interface %d, error %d\n",
77+
idx, -ret);
78+
} else {
79+
PR("DHCPv4 server stopped on interface %d\n", idx);
80+
}
81+
#else /* CONFIG_NET_DHCPV4_SERVER */
82+
PR_INFO("Set %s to enable %s support.\n",
83+
"CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server");
84+
#endif /* CONFIG_NET_DHCPV4_SERVER */
85+
return 0;
86+
}
87+
88+
#if defined(CONFIG_NET_DHCPV4_SERVER)
89+
static const char *dhcpv4_addr_state_to_str(enum dhcpv4_server_addr_state state)
90+
{
91+
switch (state) {
92+
case DHCPV4_SERVER_ADDR_FREE:
93+
return "FREE";
94+
case DHCPV4_SERVER_ADDR_RESERVED:
95+
return "RESERVED";
96+
case DHCPV4_SERVER_ADDR_ALLOCATED:
97+
return "ALLOCATED";
98+
case DHCPV4_SERVER_ADDR_DECLINED:
99+
return "DECLINED";
100+
}
101+
102+
return "<UNKNOWN>";
103+
}
104+
105+
static uint32_t timepoint_to_s(k_timepoint_t timepoint)
106+
{
107+
k_timeout_t timeout = sys_timepoint_timeout(timepoint);
108+
109+
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
110+
return 0;
111+
}
112+
113+
if (K_TIMEOUT_EQ(timeout, K_FOREVER)) {
114+
return UINT32_MAX;
115+
}
116+
117+
return k_ticks_to_ms_floor64(timeout.ticks) / 1000;
118+
}
119+
120+
static void dhcpv4_lease_cb(struct net_if *iface,
121+
struct dhcpv4_addr_slot *lease,
122+
void *user_data)
123+
{
124+
struct net_shell_user_data *data = user_data;
125+
const struct shell *sh = data->sh;
126+
int *count = data->user_data;
127+
char expiry_str[] = "4294967295"; /* Lease time is uint32_t, so take
128+
* theoretical max.
129+
*/
130+
char iface_name[IFNAMSIZ] = "";
131+
132+
if (*count == 0) {
133+
PR(" Iface Address\t State\tExpiry (sec)\n");
134+
}
135+
136+
(*count)++;
137+
138+
(void)net_if_get_name(iface, iface_name, sizeof(iface_name));
139+
140+
if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) {
141+
snprintk(expiry_str, sizeof(expiry_str) - 1, "infinite");
142+
} else {
143+
snprintk(expiry_str, sizeof(expiry_str) - 1, "%u",
144+
timepoint_to_s(lease->expiry));
145+
}
146+
147+
PR("%2d. %6s %15s\t%9s\t%12s\n",
148+
*count, iface_name, net_sprint_ipv4_addr(&lease->addr),
149+
dhcpv4_addr_state_to_str(lease->state), expiry_str);
150+
}
151+
#endif /* CONFIG_NET_DHCPV4_SERVER */
152+
153+
static int cmd_net_dhcpv4_server_status(const struct shell *sh, size_t argc, char *argv[])
154+
{
155+
#if defined(CONFIG_NET_DHCPV4_SERVER)
156+
struct net_shell_user_data user_data;
157+
struct net_if *iface = NULL;
158+
int idx = 0, ret;
159+
int count = 0;
160+
161+
if (argc > 1) {
162+
idx = get_iface_idx(sh, argv[1]);
163+
if (idx < 0) {
164+
return -ENOEXEC;
165+
}
166+
167+
iface = net_if_get_by_index(idx);
168+
if (!iface) {
169+
PR_WARNING("No such interface in index %d\n", idx);
170+
return -ENOEXEC;
171+
}
172+
}
173+
174+
user_data.sh = sh;
175+
user_data.user_data = &count;
176+
177+
ret = net_dhcpv4_server_foreach_lease(iface, dhcpv4_lease_cb, &user_data);
178+
if (ret == -ENOENT) {
179+
PR_WARNING("DHCPv4 server is not running on interface %d\n", idx);
180+
} else if (count == 0) {
181+
PR("DHCPv4 server - no addresses assigned\n");
182+
}
183+
#else /* CONFIG_NET_DHCPV4_SERVER */
184+
PR_INFO("Set %s to enable %s support.\n",
185+
"CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server");
186+
#endif /* CONFIG_NET_DHCPV4_SERVER */
187+
return 0;
188+
}
189+
190+
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4_server,
191+
SHELL_CMD_ARG(start, NULL, "Start the DHCPv4 server operation on the interface.\n"
192+
"'net dhcpv4 server start <index> <base address>'\n"
193+
"<index> is the network interface index.\n"
194+
"<base address> is the first address for the address pool.",
195+
cmd_net_dhcpv4_server_start, 3, 0),
196+
SHELL_CMD_ARG(stop, NULL, "Stop the DHCPv4 server operation on the interface.\n"
197+
"'net dhcpv4 server stop <index>'\n"
198+
"<index> is the network interface index.",
199+
cmd_net_dhcpv4_server_stop, 2, 0),
200+
SHELL_CMD_ARG(status, NULL, "Print the DHCPv4 server status on the interface.\n"
201+
"'net dhcpv4 server status <index>'\n"
202+
"<index> is the network interface index. Optional.",
203+
cmd_net_dhcpv4_server_status, 1, 1),
204+
SHELL_SUBCMD_SET_END
205+
);
206+
207+
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4,
208+
SHELL_CMD(server, &net_cmd_dhcpv4_server,
209+
"DHCPv4 server service management.",
210+
NULL),
211+
SHELL_SUBCMD_SET_END
212+
);
213+
214+
SHELL_SUBCMD_ADD((net), dhcpv4, &net_cmd_dhcpv4, "Manage DHPCv4 services.",
215+
NULL, 1, 0);

0 commit comments

Comments
 (0)