blob: 3918d57d7e588ea93161693c6aa2e5e99120ea05 [file] [log] [blame]
Jerome Forissier1ff00362024-10-16 12:04:03 +02001// SPDX-License-Identifier: GPL-2.0
2
3/* Copyright (C) 2024 Linaro Ltd. */
4
5#include <command.h>
Tom Rinic31301c2025-05-15 17:31:50 -06006#include <env.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +02007#include <dm/device.h>
8#include <dm/uclass.h>
Jerome Forissier5b2e2732025-03-06 15:32:22 +01009#include <hexdump.h>
Jerome Forissiere9a5ed82025-06-25 15:19:16 +020010#include <linux/kernel.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020011#include <lwip/ip4_addr.h>
Tim Harvey680dd862025-05-30 08:38:25 -070012#include <lwip/dns.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020013#include <lwip/err.h>
14#include <lwip/netif.h>
15#include <lwip/pbuf.h>
16#include <lwip/etharp.h>
17#include <lwip/init.h>
18#include <lwip/prot/etharp.h>
Tim Harvey799c1302025-05-30 08:38:22 -070019#include <lwip/timeouts.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020020#include <net.h>
Jerome Forissier9145d992025-04-15 23:17:39 +020021#include <timer.h>
Tim Harvey799c1302025-05-30 08:38:22 -070022#include <u-boot/schedule.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020023
24/* xx:xx:xx:xx:xx:xx\0 */
25#define MAC_ADDR_STRLEN 18
26
27#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
28void (*push_packet)(void *, int len) = 0;
29#endif
Jerome Forissierc76a9f42025-04-15 23:17:37 +020030static int net_try_count;
31static int net_restarted;
Jerome Forissier1ff00362024-10-16 12:04:03 +020032int net_restart_wrap;
33static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
34uchar *net_rx_packets[PKTBUFSRX];
35uchar *net_rx_packet;
36const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
37char *pxelinux_configfile;
38/* Our IP addr (0 = unknown) */
39struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020040char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020041
Jerome Forissier9ba21312025-03-06 15:32:21 +010042static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020043{
44 struct udevice *udev = netif->state;
45 void *pp = NULL;
46 int err;
47
Jerome Forissier5b2e2732025-03-06 15:32:22 +010048 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
49 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
50 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
51 true);
52 }
53
Jerome Forissier1ff00362024-10-16 12:04:03 +020054 if ((unsigned long)p->payload % PKTALIGN) {
55 /*
56 * Some net drivers have strict alignment requirements and may
57 * fail or output invalid data if the packet is not aligned.
58 */
59 pp = memalign(PKTALIGN, p->len);
60 if (!pp)
61 return ERR_ABRT;
62 memcpy(pp, p->payload, p->len);
63 }
64
65 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
66 free(pp);
67 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020068 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020069 return ERR_ABRT;
70 }
71
72 return ERR_OK;
73}
74
75static err_t net_lwip_if_init(struct netif *netif)
76{
77 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010078 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020079 netif->mtu = 1500;
80 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
81
82 return ERR_OK;
83}
84
85static void eth_init_rings(void)
86{
87 int i;
88
89 for (i = 0; i < PKTBUFSRX; i++)
90 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
91}
92
93struct netif *net_lwip_get_netif(void)
94{
95 struct netif *netif, *found = NULL;
96
97 NETIF_FOREACH(netif) {
98 if (!found)
99 found = netif;
100 else
101 printf("Error: more than one netif in lwIP\n");
102 }
103 return found;
104}
105
106static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
107 ip4_addr_t *mask, ip4_addr_t *gw)
108{
Jerome Forissier91596572024-11-18 15:31:25 +0100109 char ipstr[] = "ipaddr\0\0";
110 char maskstr[] = "netmask\0\0";
111 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200112 int idx = dev_seq(dev);
113 char *env;
114
115 if (idx < 0 || idx > 99) {
116 log_err("unexpected idx %d\n", idx);
117 return -1;
118 }
119
120 if (idx) {
121 sprintf(ipstr, "ipaddr%d", idx);
122 sprintf(maskstr, "netmask%d", idx);
123 sprintf(gwstr, "gatewayip%d", idx);
124 }
125
126 ip4_addr_set_zero(ip);
127 ip4_addr_set_zero(mask);
128 ip4_addr_set_zero(gw);
129
130 env = env_get(ipstr);
131 if (env)
132 ip4addr_aton(env, ip);
133
134 env = env_get(maskstr);
135 if (env)
136 ip4addr_aton(env, mask);
137
138 env = env_get(gwstr);
139 if (env)
140 ip4addr_aton(env, gw);
141
142 return 0;
143}
144
Jerome Forissier86378a52025-04-15 23:17:36 +0200145/*
Tim Harvey680dd862025-05-30 08:38:25 -0700146 * Initialize DNS via env
147 */
148int net_lwip_dns_init(void)
149{
150#if CONFIG_IS_ENABLED(CMD_DNS)
151 bool has_server = false;
152 ip_addr_t ns;
153 char *nsenv;
154
155 nsenv = env_get("dnsip");
156 if (nsenv && ipaddr_aton(nsenv, &ns)) {
157 dns_setserver(0, &ns);
158 has_server = true;
159 }
160
161 nsenv = env_get("dnsip2");
162 if (nsenv && ipaddr_aton(nsenv, &ns)) {
163 dns_setserver(1, &ns);
164 has_server = true;
165 }
166
167 if (!has_server) {
168 log_err("No valid name server (dnsip/dnsip2)\n");
169 return -EINVAL;
170 }
171
172 return 0;
173#else
174 log_err("DNS disabled\n");
175 return -EINVAL;
176#endif
177}
178
179/*
Jerome Forissier86378a52025-04-15 23:17:36 +0200180 * Initialize the network stack if needed and start the current device if valid
181 */
182int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100183{
Jerome Forissier86378a52025-04-15 23:17:36 +0200184 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100185
Jerome Forissier86378a52025-04-15 23:17:36 +0200186 net_init();
187 if (eth_is_on_demand_init()) {
188 eth_halt();
189 eth_set_current();
190 ret = eth_init();
191 if (ret < 0) {
192 eth_halt();
193 return ret;
194 }
195 } else {
196 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100197 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200198
199 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100200}
201
Jerome Forissier1ff00362024-10-16 12:04:03 +0200202static struct netif *new_netif(struct udevice *udev, bool with_ip)
203{
204 unsigned char enetaddr[ARP_HLEN];
205 char hwstr[MAC_ADDR_STRLEN];
206 ip4_addr_t ip, mask, gw;
207 struct netif *netif;
208 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200209
210 if (!udev)
211 return NULL;
212
Jerome Forissier1ff00362024-10-16 12:04:03 +0200213 if (eth_start_udev(udev) < 0) {
214 log_err("Could not start %s\n", udev->name);
215 return NULL;
216 }
217
218 netif_remove(net_lwip_get_netif());
219
220 ip4_addr_set_zero(&ip);
221 ip4_addr_set_zero(&mask);
222 ip4_addr_set_zero(&gw);
223
224 if (with_ip)
225 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
226 return NULL;
227
228 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
229 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
230 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
231 return NULL;
232
233 netif = calloc(1, sizeof(struct netif));
234 if (!netif)
235 return NULL;
236
237 netif->name[0] = 'e';
238 netif->name[1] = 't';
239
240 string_to_enetaddr(hwstr, netif->hwaddr);
241 netif->hwaddr_len = ETHARP_HWADDR_LEN;
242 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
243 hwstr, ip4addr_ntoa(&ip));
244 debug("mask:%s ", ip4addr_ntoa(&mask));
245 debug("gw:%s\n", ip4addr_ntoa(&gw));
246
247 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
248 netif_input)) {
249 printf("error: netif_add() failed\n");
250 free(netif);
251 return NULL;
252 }
253
254 netif_set_up(netif);
255 netif_set_link_up(netif);
256 /* Routing: use this interface to reach the default gateway */
257 netif_set_default(netif);
258
259 return netif;
260}
261
262struct netif *net_lwip_new_netif(struct udevice *udev)
263{
264 return new_netif(udev, true);
265}
266
267struct netif *net_lwip_new_netif_noip(struct udevice *udev)
268{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200269 return new_netif(udev, false);
270}
271
272void net_lwip_remove_netif(struct netif *netif)
273{
274 netif_remove(netif);
275 free(netif);
276}
277
Jerome Forissier86378a52025-04-15 23:17:36 +0200278/*
279 * Initialize the network buffers, an ethernet device, and the lwIP stack
280 * (once).
281 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200282int net_init(void)
283{
Jerome Forissier86378a52025-04-15 23:17:36 +0200284 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200285
Jerome Forissier86378a52025-04-15 23:17:36 +0200286 if (!init_done) {
287 eth_init_rings();
288 eth_init();
289 lwip_init();
290 init_done = true;
291 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200292
293 return 0;
294}
295
296static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
297{
Jerome Forissier97083502024-11-07 12:27:57 +0100298 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200299
Jerome Forissier97083502024-11-07 12:27:57 +0100300 /* We allocate a pbuf chain of pbufs from the pool. */
301 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
302 if (!p) {
303 LINK_STATS_INC(link.memerr);
304 LINK_STATS_INC(link.drop);
305 return NULL;
306 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200307
Jerome Forissier97083502024-11-07 12:27:57 +0100308 for (q = p; q != NULL; q = q->next) {
309 memcpy(q->payload, data, q->len);
310 data += q->len;
311 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200312
Jerome Forissier97083502024-11-07 12:27:57 +0100313 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200314
Jerome Forissier97083502024-11-07 12:27:57 +0100315 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200316}
317
318int net_lwip_rx(struct udevice *udev, struct netif *netif)
319{
320 struct pbuf *pbuf;
321 uchar *packet;
322 int flags;
323 int len;
324 int i;
325
Tim Harvey799c1302025-05-30 08:38:22 -0700326 /* lwIP timers */
327 sys_check_timeouts();
328 /* Other tasks and actions */
329 schedule();
330
Jerome Forissier1ff00362024-10-16 12:04:03 +0200331 if (!eth_is_active(udev))
332 return -EINVAL;
333
334 flags = ETH_RECV_CHECK_DEVICE;
335 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
336 len = eth_get_ops(udev)->recv(udev, flags, &packet);
337 flags = 0;
338
339 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100340 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
341 printf("net_lwip_tx: %u bytes, udev %s \n", len,
342 udev->name);
343 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
344 packet, len, true);
345 }
346
Jerome Forissier1ff00362024-10-16 12:04:03 +0200347 pbuf = alloc_pbuf_and_copy(packet, len);
348 if (pbuf)
349 netif->input(pbuf, netif);
350 }
351 if (len >= 0 && eth_get_ops(udev)->free_pkt)
352 eth_get_ops(udev)->free_pkt(udev, packet, len);
353 if (len <= 0)
354 break;
355 }
356 if (len == -EAGAIN)
357 len = 0;
358
359 return len;
360}
361
Jerome Forissiere9a5ed82025-06-25 15:19:16 +0200362/**
363 * net_lwip_dns_resolve() - find IP address from name or IP
364 *
365 * @name_or_ip: host name or IP address
366 * @ip: output IP address
367 *
368 * Return value: 0 on success, -1 on failure.
369 */
370int net_lwip_dns_resolve(char *name_or_ip, ip_addr_t *ip)
371{
372#if defined(CONFIG_CMD_DNS)
373 char *var = "_dnsres";
374 char *argv[] = { "dns", name_or_ip, var, NULL };
375 int argc = ARRAY_SIZE(argv) - 1;
376#endif
377
378 if (ipaddr_aton(name_or_ip, ip))
379 return 0;
380
381#if defined(CONFIG_CMD_DNS)
382 if (do_dns(NULL, 0, argc, argv) != CMD_RET_SUCCESS)
383 return -1;
384
385 name_or_ip = env_get(var);
386 if (!name_or_ip)
387 return -1;
388
389 if (!ipaddr_aton(name_or_ip, ip))
390 return -1;
391
392 env_set(var, NULL);
393
394 return 0;
395#else
396 return -1;
397#endif
398}
399
Jerome Forissier1ff00362024-10-16 12:04:03 +0200400void net_process_received_packet(uchar *in_packet, int len)
401{
402#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
403 if (push_packet)
404 (*push_packet)(in_packet, len);
405#endif
406}
407
Jerome Forissier6a78e962024-10-16 12:04:05 +0200408int net_loop(enum proto_t protocol)
409{
410 char *argv[1];
411
412 switch (protocol) {
413 case TFTPGET:
414 argv[0] = "tftpboot";
415 return do_tftpb(NULL, 0, 1, argv);
416 default:
417 return -EINVAL;
418 }
419
420 return -EINVAL;
421}
422
Jerome Forissier1ff00362024-10-16 12:04:03 +0200423u32_t sys_now(void)
424{
Jerome Forissier9145d992025-04-15 23:17:39 +0200425#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
426 return timer_early_get_count();
427#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200428 return get_timer(0);
Jerome Forissier9145d992025-04-15 23:17:39 +0200429#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200430}
Jerome Forissierc76a9f42025-04-15 23:17:37 +0200431
432int net_start_again(void)
433{
434 char *nretry;
435 int retry_forever = 0;
436 unsigned long retrycnt = 0;
437
438 nretry = env_get("netretry");
439 if (nretry) {
440 if (!strcmp(nretry, "yes"))
441 retry_forever = 1;
442 else if (!strcmp(nretry, "no"))
443 retrycnt = 0;
444 else if (!strcmp(nretry, "once"))
445 retrycnt = 1;
446 else
447 retrycnt = simple_strtoul(nretry, NULL, 0);
448 } else {
449 retrycnt = 0;
450 retry_forever = 0;
451 }
452
453 if ((!retry_forever) && (net_try_count > retrycnt)) {
454 eth_halt();
455 /*
456 * We don't provide a way for the protocol to return an error,
457 * but this is almost always the reason.
458 */
459 return -ETIMEDOUT;
460 }
461
462 net_try_count++;
463
464 eth_halt();
465#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
466 eth_try_another(!net_restarted);
467#endif
468 return eth_init();
469}