blob: e7d9147455c21e44782658341650a6694460b90b [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>
Heinrich Schuchardtee9712a2024-12-05 20:17:36 +01006#include <log.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +02007#include <dm/device.h>
8#include <linux/delay.h>
9#include <linux/errno.h>
10#include <lwip/dhcp.h>
11#include <lwip/dns.h>
12#include <lwip/timeouts.h>
13#include <net.h>
14#include <time.h>
15
16#define DHCP_TIMEOUT_MS 10000
17
18#ifdef CONFIG_CMD_TFTPBOOT
19/* Boot file obtained from DHCP (if present) */
20static char boot_file_name[DHCP_BOOT_FILE_LEN];
21#endif
22
23static void call_lwip_dhcp_fine_tmr(void *ctx)
24{
25 dhcp_fine_tmr();
26 sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
27}
28
29static int dhcp_loop(struct udevice *udev)
30{
Jerome Forissier595bf7d2024-11-22 13:35:29 +010031 char ipstr[] = "ipaddr\0\0";
32 char maskstr[] = "netmask\0\0";
33 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +020034 unsigned long start;
35 struct netif *netif;
36 struct dhcp *dhcp;
37 bool bound;
38 int idx;
39
40 idx = dev_seq(udev);
41 if (idx < 0 || idx > 99) {
42 log_err("unexpected idx %d\n", idx);
43 return CMD_RET_FAILURE;
44 }
45
46 netif = net_lwip_new_netif_noip(udev);
47 if (!netif)
48 return CMD_RET_FAILURE;
49
50 start = get_timer(0);
51
52 if (dhcp_start(netif))
53 return CMD_RET_FAILURE;
54
55 call_lwip_dhcp_fine_tmr(NULL);
56
57 /* Wait for DHCP to complete */
58 do {
59 net_lwip_rx(udev, netif);
60 sys_check_timeouts();
61 bound = dhcp_supplied_address(netif);
62 if (bound)
63 break;
64 if (ctrlc()) {
65 printf("Abort\n");
66 break;
67 }
68 mdelay(1);
69 } while (get_timer(start) < DHCP_TIMEOUT_MS);
70
71 sys_untimeout(call_lwip_dhcp_fine_tmr, NULL);
72
73 if (!bound) {
74 net_lwip_remove_netif(netif);
75 return CMD_RET_FAILURE;
76 }
77
78 dhcp = netif_dhcp_data(netif);
79
80 env_set("bootfile", dhcp->boot_file_name);
81
82 if (idx > 0) {
83 sprintf(ipstr, "ipaddr%d", idx);
84 sprintf(maskstr, "netmask%d", idx);
85 sprintf(gwstr, "gatewayip%d", idx);
86 } else {
87 net_ip.s_addr = dhcp->offered_ip_addr.addr;
88 }
89
90 env_set(ipstr, ip4addr_ntoa(&dhcp->offered_ip_addr));
91 env_set(maskstr, ip4addr_ntoa(&dhcp->offered_sn_mask));
92 env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
93 if (dhcp->offered_gw_addr.addr != 0)
94 env_set(gwstr, ip4addr_ntoa(&dhcp->offered_gw_addr));
95
96#ifdef CONFIG_PROT_DNS_LWIP
97 env_set("dnsip", ip4addr_ntoa(dns_getserver(0)));
98 env_set("dnsip2", ip4addr_ntoa(dns_getserver(1)));
99#endif
100#ifdef CONFIG_CMD_TFTPBOOT
101 if (dhcp->boot_file_name[0] != '\0')
102 strncpy(boot_file_name, dhcp->boot_file_name,
103 sizeof(boot_file_name));
104#endif
105
106 printf("DHCP client bound to address %pI4 (%lu ms)\n",
107 &dhcp->offered_ip_addr, get_timer(start));
108
109 net_lwip_remove_netif(netif);
110 return CMD_RET_SUCCESS;
111}
112
113int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
114{
Jerome Forissier8cc52832024-11-14 18:20:07 +0100115 int ret;
Heinrich Schuchardtee9712a2024-12-05 20:17:36 +0100116 struct udevice *dev;
Jerome Forissier8cc52832024-11-14 18:20:07 +0100117
Jerome Forissier1ff00362024-10-16 12:04:03 +0200118 eth_set_current();
119
Heinrich Schuchardtee9712a2024-12-05 20:17:36 +0100120 dev = eth_get_dev();
121 if (!dev) {
122 log_err("No network device\n");
123 return CMD_RET_FAILURE;
124 }
125
126 ret = dhcp_loop(dev);
Jerome Forissier8cc52832024-11-14 18:20:07 +0100127 if (ret)
128 return ret;
129
130 if (argc > 1) {
131 struct cmd_tbl cmdtp = {};
132
133 return do_tftpb(&cmdtp, 0, argc, argv);
134 }
135
136 return CMD_RET_SUCCESS;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200137}
138
139int dhcp_run(ulong addr, const char *fname, bool autoload)
140{
141 char *dhcp_argv[] = {"dhcp", NULL, };
Jerome Forissier6a78e962024-10-16 12:04:05 +0200142#ifdef CONFIG_CMD_TFTPBOOT
143 char *tftp_argv[] = {"tftpboot", boot_file_name, NULL, };
144#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200145 struct cmd_tbl cmdtp = {}; /* dummy */
146
147 if (autoload) {
Jerome Forissier6a78e962024-10-16 12:04:05 +0200148#ifdef CONFIG_CMD_TFTPBOOT
149 /* Assume DHCP was already performed */
150 if (boot_file_name[0])
151 return do_tftpb(&cmdtp, 0, 2, tftp_argv);
152 return 0;
153#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200154 return -EOPNOTSUPP;
Jerome Forissier6a78e962024-10-16 12:04:05 +0200155#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200156 }
157
158 return do_dhcp(&cmdtp, 0, 1, dhcp_argv);
159}