// SPDX-License-Identifier: GPL-2.0+ /* Copyright (C) 2024 Linaro Ltd. */ #include #include #include #include #include #include #define DNS_RESEND_MS 1000 #define DNS_TIMEOUT_MS 10000 struct dns_cb_arg { ip_addr_t host_ipaddr; const char *var; bool done; }; static void do_dns_tmr(void *arg) { dns_tmr(); } static void dns_cb(const char *name, const ip_addr_t *ipaddr, void *arg) { struct dns_cb_arg *dns_cb_arg = arg; char *ipstr = ip4addr_ntoa(ipaddr); dns_cb_arg->done = true; if (!ipaddr) { printf("DNS: host not found\n"); dns_cb_arg->host_ipaddr.addr = 0; return; } if (dns_cb_arg->var) env_set(dns_cb_arg->var, ipstr); printf("%s\n", ipstr); } static int dns_loop(struct udevice *udev, const char *name, const char *var) { struct dns_cb_arg dns_cb_arg = { }; bool has_server = false; struct netif *netif; ip_addr_t ipaddr; ip_addr_t ns; ulong start; char *nsenv; int ret; dns_cb_arg.var = var; netif = net_lwip_new_netif(udev); if (!netif) return -1; dns_init(); nsenv = env_get("dnsip"); if (nsenv && ipaddr_aton(nsenv, &ns)) { dns_setserver(0, &ns); has_server = true; } nsenv = env_get("dnsip2"); if (nsenv && ipaddr_aton(nsenv, &ns)) { dns_setserver(1, &ns); has_server = true; } if (!has_server) { log_err("No valid name server (dnsip/dnsip2)\n"); net_lwip_remove_netif(netif); return CMD_RET_FAILURE; } dns_cb_arg.done = false; ret = dns_gethostbyname(name, &ipaddr, dns_cb, &dns_cb_arg); if (ret == ERR_OK) { dns_cb(name, &ipaddr, &dns_cb_arg); } else if (ret == ERR_INPROGRESS) { start = get_timer(0); sys_timeout(DNS_RESEND_MS, do_dns_tmr, NULL); do { net_lwip_rx(udev, netif); if (dns_cb_arg.done) break; sys_check_timeouts(); if (ctrlc()) { printf("\nAbort\n"); break; } } while (get_timer(start) < DNS_TIMEOUT_MS); sys_untimeout(do_dns_tmr, NULL); } net_lwip_remove_netif(netif); if (dns_cb_arg.done && dns_cb_arg.host_ipaddr.addr != 0) return CMD_RET_SUCCESS; return CMD_RET_FAILURE; } int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { char *name; char *var = NULL; if (argc == 1 || argc > 3) return CMD_RET_USAGE; name = argv[1]; if (argc == 3) var = argv[2]; eth_set_current(); return dns_loop(eth_get_dev(), name, var); }