blob: 23b56226921d4a96b30daf38eaaa918b05432751 [file] [log] [blame]
Jerome Forissier1ff00362024-10-16 12:04:03 +02001// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (C) 2024 Linaro Ltd. */
3
4#include <command.h>
5#include <console.h>
6#include <dm/device.h>
7#include <linux/delay.h>
8#include <linux/errno.h>
9#include <lwip/dhcp.h>
10#include <lwip/dns.h>
11#include <lwip/timeouts.h>
12#include <net.h>
13#include <time.h>
14
15#define DHCP_TIMEOUT_MS 10000
16
17#ifdef CONFIG_CMD_TFTPBOOT
18/* Boot file obtained from DHCP (if present) */
19static char boot_file_name[DHCP_BOOT_FILE_LEN];
20#endif
21
22static void call_lwip_dhcp_fine_tmr(void *ctx)
23{
24 dhcp_fine_tmr();
25 sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
26}
27
28static int dhcp_loop(struct udevice *udev)
29{
30 char *ipstr = "ipaddr\0\0";
31 char *maskstr = "netmask\0\0";
32 char *gwstr = "gatewayip\0\0";
33 unsigned long start;
34 struct netif *netif;
35 struct dhcp *dhcp;
36 bool bound;
37 int idx;
38
39 idx = dev_seq(udev);
40 if (idx < 0 || idx > 99) {
41 log_err("unexpected idx %d\n", idx);
42 return CMD_RET_FAILURE;
43 }
44
45 netif = net_lwip_new_netif_noip(udev);
46 if (!netif)
47 return CMD_RET_FAILURE;
48
49 start = get_timer(0);
50
51 if (dhcp_start(netif))
52 return CMD_RET_FAILURE;
53
54 call_lwip_dhcp_fine_tmr(NULL);
55
56 /* Wait for DHCP to complete */
57 do {
58 net_lwip_rx(udev, netif);
59 sys_check_timeouts();
60 bound = dhcp_supplied_address(netif);
61 if (bound)
62 break;
63 if (ctrlc()) {
64 printf("Abort\n");
65 break;
66 }
67 mdelay(1);
68 } while (get_timer(start) < DHCP_TIMEOUT_MS);
69
70 sys_untimeout(call_lwip_dhcp_fine_tmr, NULL);
71
72 if (!bound) {
73 net_lwip_remove_netif(netif);
74 return CMD_RET_FAILURE;
75 }
76
77 dhcp = netif_dhcp_data(netif);
78
79 env_set("bootfile", dhcp->boot_file_name);
80
81 if (idx > 0) {
82 sprintf(ipstr, "ipaddr%d", idx);
83 sprintf(maskstr, "netmask%d", idx);
84 sprintf(gwstr, "gatewayip%d", idx);
85 } else {
86 net_ip.s_addr = dhcp->offered_ip_addr.addr;
87 }
88
89 env_set(ipstr, ip4addr_ntoa(&dhcp->offered_ip_addr));
90 env_set(maskstr, ip4addr_ntoa(&dhcp->offered_sn_mask));
91 env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
92 if (dhcp->offered_gw_addr.addr != 0)
93 env_set(gwstr, ip4addr_ntoa(&dhcp->offered_gw_addr));
94
95#ifdef CONFIG_PROT_DNS_LWIP
96 env_set("dnsip", ip4addr_ntoa(dns_getserver(0)));
97 env_set("dnsip2", ip4addr_ntoa(dns_getserver(1)));
98#endif
99#ifdef CONFIG_CMD_TFTPBOOT
100 if (dhcp->boot_file_name[0] != '\0')
101 strncpy(boot_file_name, dhcp->boot_file_name,
102 sizeof(boot_file_name));
103#endif
104
105 printf("DHCP client bound to address %pI4 (%lu ms)\n",
106 &dhcp->offered_ip_addr, get_timer(start));
107
108 net_lwip_remove_netif(netif);
109 return CMD_RET_SUCCESS;
110}
111
112int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
113{
114 eth_set_current();
115
116 return dhcp_loop(eth_get_dev());
117}
118
119int dhcp_run(ulong addr, const char *fname, bool autoload)
120{
121 char *dhcp_argv[] = {"dhcp", NULL, };
Jerome Forissier6a78e962024-10-16 12:04:05 +0200122#ifdef CONFIG_CMD_TFTPBOOT
123 char *tftp_argv[] = {"tftpboot", boot_file_name, NULL, };
124#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200125 struct cmd_tbl cmdtp = {}; /* dummy */
126
127 if (autoload) {
Jerome Forissier6a78e962024-10-16 12:04:05 +0200128#ifdef CONFIG_CMD_TFTPBOOT
129 /* Assume DHCP was already performed */
130 if (boot_file_name[0])
131 return do_tftpb(&cmdtp, 0, 2, tftp_argv);
132 return 0;
133#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200134 return -EOPNOTSUPP;
Jerome Forissier6a78e962024-10-16 12:04:05 +0200135#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200136 }
137
138 return do_dhcp(&cmdtp, 0, 1, dhcp_argv);
139}