| /* |
| * Copyright (c) 2024 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_DECLARE(net_shell); |
| |
| #include <stdint.h> |
| #include <zephyr/net/dhcpv4_server.h> |
| #include <zephyr/net/socket.h> |
| |
| #include "net_shell_private.h" |
| |
| static int cmd_net_dhcpv4_server_start(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| #if defined(CONFIG_NET_DHCPV4_SERVER) |
| struct net_if *iface = NULL; |
| struct in_addr base_addr; |
| int idx, ret; |
| |
| idx = get_iface_idx(sh, argv[1]); |
| if (idx < 0) { |
| return -ENOEXEC; |
| } |
| |
| iface = net_if_get_by_index(idx); |
| if (!iface) { |
| PR_WARNING("No such interface in index %d\n", idx); |
| return -ENOEXEC; |
| } |
| |
| if (net_addr_pton(AF_INET, argv[2], &base_addr)) { |
| PR_ERROR("Invalid address: %s\n", argv[2]); |
| return -EINVAL; |
| } |
| |
| ret = net_dhcpv4_server_start(iface, &base_addr); |
| if (ret == -EALREADY) { |
| PR_WARNING("DHCPv4 server already running on interface %d\n", idx); |
| } else if (ret < 0) { |
| PR_ERROR("DHCPv4 server failed to start on interface %d, error %d\n", |
| idx, -ret); |
| } else { |
| PR("DHCPv4 server started on interface %d\n", idx); |
| } |
| #else /* CONFIG_NET_DHCPV4_SERVER */ |
| PR_INFO("Set %s to enable %s support.\n", |
| "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); |
| #endif /* CONFIG_NET_DHCPV4_SERVER */ |
| return 0; |
| } |
| |
| static int cmd_net_dhcpv4_server_stop(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| #if defined(CONFIG_NET_DHCPV4_SERVER) |
| struct net_if *iface = NULL; |
| int idx, ret; |
| |
| idx = get_iface_idx(sh, argv[1]); |
| if (idx < 0) { |
| return -ENOEXEC; |
| } |
| |
| iface = net_if_get_by_index(idx); |
| if (!iface) { |
| PR_WARNING("No such interface in index %d\n", idx); |
| return -ENOEXEC; |
| } |
| |
| ret = net_dhcpv4_server_stop(iface); |
| if (ret == -ENOENT) { |
| PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); |
| } else if (ret < 0) { |
| PR_ERROR("DHCPv4 server failed to stop on interface %d, error %d\n", |
| idx, -ret); |
| } else { |
| PR("DHCPv4 server stopped on interface %d\n", idx); |
| } |
| #else /* CONFIG_NET_DHCPV4_SERVER */ |
| PR_INFO("Set %s to enable %s support.\n", |
| "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); |
| #endif /* CONFIG_NET_DHCPV4_SERVER */ |
| return 0; |
| } |
| |
| #if defined(CONFIG_NET_DHCPV4_SERVER) |
| static const char *dhcpv4_addr_state_to_str(enum dhcpv4_server_addr_state state) |
| { |
| switch (state) { |
| case DHCPV4_SERVER_ADDR_FREE: |
| return "FREE"; |
| case DHCPV4_SERVER_ADDR_RESERVED: |
| return "RESERVED"; |
| case DHCPV4_SERVER_ADDR_ALLOCATED: |
| return "ALLOCATED"; |
| case DHCPV4_SERVER_ADDR_DECLINED: |
| return "DECLINED"; |
| } |
| |
| return "<UNKNOWN>"; |
| } |
| |
| static uint32_t timepoint_to_s(k_timepoint_t timepoint) |
| { |
| k_timeout_t timeout = sys_timepoint_timeout(timepoint); |
| |
| if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { |
| return 0; |
| } |
| |
| if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { |
| return UINT32_MAX; |
| } |
| |
| return k_ticks_to_ms_floor64(timeout.ticks) / 1000; |
| } |
| |
| static void dhcpv4_lease_cb(struct net_if *iface, |
| struct dhcpv4_addr_slot *lease, |
| void *user_data) |
| { |
| struct net_shell_user_data *data = user_data; |
| const struct shell *sh = data->sh; |
| int *count = data->user_data; |
| char expiry_str[] = "4294967295"; /* Lease time is uint32_t, so take |
| * theoretical max. |
| */ |
| char iface_name[IFNAMSIZ] = ""; |
| |
| if (*count == 0) { |
| PR(" Iface Address\t State\tExpiry (sec)\n"); |
| } |
| |
| (*count)++; |
| |
| (void)net_if_get_name(iface, iface_name, sizeof(iface_name)); |
| |
| if (lease->state == DHCPV4_SERVER_ADDR_DECLINED) { |
| snprintk(expiry_str, sizeof(expiry_str) - 1, "infinite"); |
| } else { |
| snprintk(expiry_str, sizeof(expiry_str) - 1, "%u", |
| timepoint_to_s(lease->expiry)); |
| } |
| |
| PR("%2d. %6s %15s\t%9s\t%12s\n", |
| *count, iface_name, net_sprint_ipv4_addr(&lease->addr), |
| dhcpv4_addr_state_to_str(lease->state), expiry_str); |
| } |
| #endif /* CONFIG_NET_DHCPV4_SERVER */ |
| |
| static int cmd_net_dhcpv4_server_status(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| #if defined(CONFIG_NET_DHCPV4_SERVER) |
| struct net_shell_user_data user_data; |
| struct net_if *iface = NULL; |
| int idx = 0, ret; |
| int count = 0; |
| |
| if (argc > 1) { |
| idx = get_iface_idx(sh, argv[1]); |
| if (idx < 0) { |
| return -ENOEXEC; |
| } |
| |
| iface = net_if_get_by_index(idx); |
| if (!iface) { |
| PR_WARNING("No such interface in index %d\n", idx); |
| return -ENOEXEC; |
| } |
| } |
| |
| user_data.sh = sh; |
| user_data.user_data = &count; |
| |
| ret = net_dhcpv4_server_foreach_lease(iface, dhcpv4_lease_cb, &user_data); |
| if (ret == -ENOENT) { |
| PR_WARNING("DHCPv4 server is not running on interface %d\n", idx); |
| } else if (count == 0) { |
| PR("DHCPv4 server - no addresses assigned\n"); |
| } |
| #else /* CONFIG_NET_DHCPV4_SERVER */ |
| PR_INFO("Set %s to enable %s support.\n", |
| "CONFIG_NET_DHCPV4_SERVER", "DHCPv4 server"); |
| #endif /* CONFIG_NET_DHCPV4_SERVER */ |
| return 0; |
| } |
| |
| SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4_server, |
| SHELL_CMD_ARG(start, NULL, "Start the DHCPv4 server operation on the interface.\n" |
| "'net dhcpv4 server start <index> <base address>'\n" |
| "<index> is the network interface index.\n" |
| "<base address> is the first address for the address pool.", |
| cmd_net_dhcpv4_server_start, 3, 0), |
| SHELL_CMD_ARG(stop, NULL, "Stop the DHCPv4 server operation on the interface.\n" |
| "'net dhcpv4 server stop <index>'\n" |
| "<index> is the network interface index.", |
| cmd_net_dhcpv4_server_stop, 2, 0), |
| SHELL_CMD_ARG(status, NULL, "Print the DHCPv4 server status on the interface.\n" |
| "'net dhcpv4 server status <index>'\n" |
| "<index> is the network interface index. Optional.", |
| cmd_net_dhcpv4_server_status, 1, 1), |
| SHELL_SUBCMD_SET_END |
| ); |
| |
| SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dhcpv4, |
| SHELL_CMD(server, &net_cmd_dhcpv4_server, |
| "DHCPv4 server service management.", |
| NULL), |
| SHELL_SUBCMD_SET_END |
| ); |
| |
| SHELL_SUBCMD_ADD((net), dhcpv4, &net_cmd_dhcpv4, "Manage DHPCv4 services.", |
| NULL, 1, 0); |