1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2024 Linaro Ltd. */
3 
4 #include <command.h>
5 #include <console.h>
6 #include <env.h>
7 #include <lwip/dns.h>
8 #include <lwip/timeouts.h>
9 #include <net.h>
10 #include <time.h>
11 
12 #define DNS_RESEND_MS 1000
13 #define DNS_TIMEOUT_MS 10000
14 
15 struct dns_cb_arg {
16 	ip_addr_t host_ipaddr;
17 	const char *var;
18 	bool done;
19 };
20 
do_dns_tmr(void * arg)21 static void do_dns_tmr(void *arg)
22 {
23 	dns_tmr();
24 }
25 
dns_cb(const char * name,const ip_addr_t * ipaddr,void * arg)26 static void dns_cb(const char *name, const ip_addr_t *ipaddr, void *arg)
27 {
28 	struct dns_cb_arg *dns_cb_arg = arg;
29 	char *ipstr = ip4addr_ntoa(ipaddr);
30 
31 	dns_cb_arg->done = true;
32 
33 	if (!ipaddr) {
34 		printf("DNS: host not found\n");
35 		dns_cb_arg->host_ipaddr.addr = 0;
36 		return;
37 	}
38 
39 	dns_cb_arg->host_ipaddr.addr = ipaddr->addr;
40 
41 	if (dns_cb_arg->var)
42 		env_set(dns_cb_arg->var, ipstr);
43 }
44 
dns_loop(struct udevice * udev,const char * name,const char * var)45 static int dns_loop(struct udevice *udev, const char *name, const char *var)
46 {
47 	struct dns_cb_arg dns_cb_arg = { };
48 	struct netif *netif;
49 	ip_addr_t ipaddr;
50 	ulong start;
51 	int ret;
52 
53 	dns_cb_arg.var = var;
54 
55 	netif = net_lwip_new_netif(udev);
56 	if (!netif)
57 		return CMD_RET_FAILURE;
58 
59 	if (net_lwip_dns_init()) {
60 		net_lwip_remove_netif(netif);
61 		return CMD_RET_FAILURE;
62 	}
63 
64 	dns_cb_arg.done = false;
65 
66 	ret = dns_gethostbyname(name, &ipaddr, dns_cb, &dns_cb_arg);
67 
68 	if (ret == ERR_OK) {
69 		dns_cb(name, &ipaddr, &dns_cb_arg);
70 	} else if (ret == ERR_INPROGRESS) {
71 		start = get_timer(0);
72 		sys_timeout(DNS_RESEND_MS, do_dns_tmr, NULL);
73 		do {
74 			net_lwip_rx(udev, netif);
75 			if (dns_cb_arg.done)
76 				break;
77 			if (ctrlc()) {
78 				printf("\nAbort\n");
79 				break;
80 			}
81 		} while (get_timer(start) < DNS_TIMEOUT_MS);
82 		sys_untimeout(do_dns_tmr, NULL);
83 	}
84 
85 	net_lwip_remove_netif(netif);
86 
87 	if (dns_cb_arg.done && dns_cb_arg.host_ipaddr.addr != 0) {
88 		if (!var)
89 			printf("%s\n", ipaddr_ntoa(&ipaddr));
90 		return CMD_RET_SUCCESS;
91 	}
92 
93 	return CMD_RET_FAILURE;
94 }
95 
do_dns(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])96 int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
97 {
98 	char *name;
99 	char *var = NULL;
100 
101 	if (argc == 1 || argc > 3)
102 		return CMD_RET_USAGE;
103 
104 	name = argv[1];
105 
106 	if (argc == 3)
107 		var = argv[2];
108 
109 	if (net_lwip_eth_start() < 0)
110 		return CMD_RET_FAILURE;
111 
112 	return dns_loop(eth_get_dev(), name, var);
113 }
114