summaryrefslogtreecommitdiff
path: root/net/lwip/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/lwip/dhcp.c')
-rw-r--r--net/lwip/dhcp.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c
new file mode 100644
index 00000000000..23b56226921
--- /dev/null
+++ b/net/lwip/dhcp.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <console.h>
+#include <dm/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <lwip/dhcp.h>
+#include <lwip/dns.h>
+#include <lwip/timeouts.h>
+#include <net.h>
+#include <time.h>
+
+#define DHCP_TIMEOUT_MS 10000
+
+#ifdef CONFIG_CMD_TFTPBOOT
+/* Boot file obtained from DHCP (if present) */
+static char boot_file_name[DHCP_BOOT_FILE_LEN];
+#endif
+
+static void call_lwip_dhcp_fine_tmr(void *ctx)
+{
+ dhcp_fine_tmr();
+ sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
+}
+
+static int dhcp_loop(struct udevice *udev)
+{
+ char *ipstr = "ipaddr\0\0";
+ char *maskstr = "netmask\0\0";
+ char *gwstr = "gatewayip\0\0";
+ unsigned long start;
+ struct netif *netif;
+ struct dhcp *dhcp;
+ bool bound;
+ int idx;
+
+ idx = dev_seq(udev);
+ if (idx < 0 || idx > 99) {
+ log_err("unexpected idx %d\n", idx);
+ return CMD_RET_FAILURE;
+ }
+
+ netif = net_lwip_new_netif_noip(udev);
+ if (!netif)
+ return CMD_RET_FAILURE;
+
+ start = get_timer(0);
+
+ if (dhcp_start(netif))
+ return CMD_RET_FAILURE;
+
+ call_lwip_dhcp_fine_tmr(NULL);
+
+ /* Wait for DHCP to complete */
+ do {
+ net_lwip_rx(udev, netif);
+ sys_check_timeouts();
+ bound = dhcp_supplied_address(netif);
+ if (bound)
+ break;
+ if (ctrlc()) {
+ printf("Abort\n");
+ break;
+ }
+ mdelay(1);
+ } while (get_timer(start) < DHCP_TIMEOUT_MS);
+
+ sys_untimeout(call_lwip_dhcp_fine_tmr, NULL);
+
+ if (!bound) {
+ net_lwip_remove_netif(netif);
+ return CMD_RET_FAILURE;
+ }
+
+ dhcp = netif_dhcp_data(netif);
+
+ env_set("bootfile", dhcp->boot_file_name);
+
+ if (idx > 0) {
+ sprintf(ipstr, "ipaddr%d", idx);
+ sprintf(maskstr, "netmask%d", idx);
+ sprintf(gwstr, "gatewayip%d", idx);
+ } else {
+ net_ip.s_addr = dhcp->offered_ip_addr.addr;
+ }
+
+ env_set(ipstr, ip4addr_ntoa(&dhcp->offered_ip_addr));
+ env_set(maskstr, ip4addr_ntoa(&dhcp->offered_sn_mask));
+ env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
+ if (dhcp->offered_gw_addr.addr != 0)
+ env_set(gwstr, ip4addr_ntoa(&dhcp->offered_gw_addr));
+
+#ifdef CONFIG_PROT_DNS_LWIP
+ env_set("dnsip", ip4addr_ntoa(dns_getserver(0)));
+ env_set("dnsip2", ip4addr_ntoa(dns_getserver(1)));
+#endif
+#ifdef CONFIG_CMD_TFTPBOOT
+ if (dhcp->boot_file_name[0] != '\0')
+ strncpy(boot_file_name, dhcp->boot_file_name,
+ sizeof(boot_file_name));
+#endif
+
+ printf("DHCP client bound to address %pI4 (%lu ms)\n",
+ &dhcp->offered_ip_addr, get_timer(start));
+
+ net_lwip_remove_netif(netif);
+ return CMD_RET_SUCCESS;
+}
+
+int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ eth_set_current();
+
+ return dhcp_loop(eth_get_dev());
+}
+
+int dhcp_run(ulong addr, const char *fname, bool autoload)
+{
+ char *dhcp_argv[] = {"dhcp", NULL, };
+#ifdef CONFIG_CMD_TFTPBOOT
+ char *tftp_argv[] = {"tftpboot", boot_file_name, NULL, };
+#endif
+ struct cmd_tbl cmdtp = {}; /* dummy */
+
+ if (autoload) {
+#ifdef CONFIG_CMD_TFTPBOOT
+ /* Assume DHCP was already performed */
+ if (boot_file_name[0])
+ return do_tftpb(&cmdtp, 0, 2, tftp_argv);
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
+ }
+
+ return do_dhcp(&cmdtp, 0, 1, dhcp_argv);
+}