blob: 040b51e8852ab1890066c401c1c792a8f04b811f [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 Forissier1ff00362024-10-16 12:04:03 +020010#include <lwip/ip4_addr.h>
Tim Harvey680dd862025-05-30 08:38:25 -070011#include <lwip/dns.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020012#include <lwip/err.h>
13#include <lwip/netif.h>
14#include <lwip/pbuf.h>
15#include <lwip/etharp.h>
16#include <lwip/init.h>
17#include <lwip/prot/etharp.h>
Tim Harvey799c1302025-05-30 08:38:22 -070018#include <lwip/timeouts.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020019#include <net.h>
Jerome Forissier9145d992025-04-15 23:17:39 +020020#include <timer.h>
Tim Harvey799c1302025-05-30 08:38:22 -070021#include <u-boot/schedule.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020022
23/* xx:xx:xx:xx:xx:xx\0 */
24#define MAC_ADDR_STRLEN 18
25
26#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
27void (*push_packet)(void *, int len) = 0;
28#endif
Jerome Forissierc76a9f42025-04-15 23:17:37 +020029static int net_try_count;
30static int net_restarted;
Jerome Forissier1ff00362024-10-16 12:04:03 +020031int net_restart_wrap;
32static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
33uchar *net_rx_packets[PKTBUFSRX];
34uchar *net_rx_packet;
35const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
36char *pxelinux_configfile;
37/* Our IP addr (0 = unknown) */
38struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020039char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020040
Jerome Forissier9ba21312025-03-06 15:32:21 +010041static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020042{
43 struct udevice *udev = netif->state;
44 void *pp = NULL;
45 int err;
46
Jerome Forissier5b2e2732025-03-06 15:32:22 +010047 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
48 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
49 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
50 true);
51 }
52
Jerome Forissier1ff00362024-10-16 12:04:03 +020053 if ((unsigned long)p->payload % PKTALIGN) {
54 /*
55 * Some net drivers have strict alignment requirements and may
56 * fail or output invalid data if the packet is not aligned.
57 */
58 pp = memalign(PKTALIGN, p->len);
59 if (!pp)
60 return ERR_ABRT;
61 memcpy(pp, p->payload, p->len);
62 }
63
64 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
65 free(pp);
66 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020067 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020068 return ERR_ABRT;
69 }
70
71 return ERR_OK;
72}
73
74static err_t net_lwip_if_init(struct netif *netif)
75{
76 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010077 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020078 netif->mtu = 1500;
79 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
80
81 return ERR_OK;
82}
83
84static void eth_init_rings(void)
85{
86 int i;
87
88 for (i = 0; i < PKTBUFSRX; i++)
89 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
90}
91
92struct netif *net_lwip_get_netif(void)
93{
94 struct netif *netif, *found = NULL;
95
96 NETIF_FOREACH(netif) {
97 if (!found)
98 found = netif;
99 else
100 printf("Error: more than one netif in lwIP\n");
101 }
102 return found;
103}
104
105static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
106 ip4_addr_t *mask, ip4_addr_t *gw)
107{
Jerome Forissier91596572024-11-18 15:31:25 +0100108 char ipstr[] = "ipaddr\0\0";
109 char maskstr[] = "netmask\0\0";
110 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200111 int idx = dev_seq(dev);
112 char *env;
113
114 if (idx < 0 || idx > 99) {
115 log_err("unexpected idx %d\n", idx);
116 return -1;
117 }
118
119 if (idx) {
120 sprintf(ipstr, "ipaddr%d", idx);
121 sprintf(maskstr, "netmask%d", idx);
122 sprintf(gwstr, "gatewayip%d", idx);
123 }
124
125 ip4_addr_set_zero(ip);
126 ip4_addr_set_zero(mask);
127 ip4_addr_set_zero(gw);
128
129 env = env_get(ipstr);
130 if (env)
131 ip4addr_aton(env, ip);
132
133 env = env_get(maskstr);
134 if (env)
135 ip4addr_aton(env, mask);
136
137 env = env_get(gwstr);
138 if (env)
139 ip4addr_aton(env, gw);
140
141 return 0;
142}
143
Jerome Forissier86378a52025-04-15 23:17:36 +0200144/*
Tim Harvey680dd862025-05-30 08:38:25 -0700145 * Initialize DNS via env
146 */
147int net_lwip_dns_init(void)
148{
149#if CONFIG_IS_ENABLED(CMD_DNS)
150 bool has_server = false;
151 ip_addr_t ns;
152 char *nsenv;
153
154 nsenv = env_get("dnsip");
155 if (nsenv && ipaddr_aton(nsenv, &ns)) {
156 dns_setserver(0, &ns);
157 has_server = true;
158 }
159
160 nsenv = env_get("dnsip2");
161 if (nsenv && ipaddr_aton(nsenv, &ns)) {
162 dns_setserver(1, &ns);
163 has_server = true;
164 }
165
166 if (!has_server) {
167 log_err("No valid name server (dnsip/dnsip2)\n");
168 return -EINVAL;
169 }
170
171 return 0;
172#else
173 log_err("DNS disabled\n");
174 return -EINVAL;
175#endif
176}
177
178/*
Jerome Forissier86378a52025-04-15 23:17:36 +0200179 * Initialize the network stack if needed and start the current device if valid
180 */
181int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100182{
Jerome Forissier86378a52025-04-15 23:17:36 +0200183 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100184
Jerome Forissier86378a52025-04-15 23:17:36 +0200185 net_init();
186 if (eth_is_on_demand_init()) {
187 eth_halt();
188 eth_set_current();
189 ret = eth_init();
190 if (ret < 0) {
191 eth_halt();
192 return ret;
193 }
194 } else {
195 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100196 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200197
198 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100199}
200
Jerome Forissier1ff00362024-10-16 12:04:03 +0200201static struct netif *new_netif(struct udevice *udev, bool with_ip)
202{
203 unsigned char enetaddr[ARP_HLEN];
204 char hwstr[MAC_ADDR_STRLEN];
205 ip4_addr_t ip, mask, gw;
206 struct netif *netif;
207 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200208
209 if (!udev)
210 return NULL;
211
Jerome Forissier1ff00362024-10-16 12:04:03 +0200212 if (eth_start_udev(udev) < 0) {
213 log_err("Could not start %s\n", udev->name);
214 return NULL;
215 }
216
217 netif_remove(net_lwip_get_netif());
218
219 ip4_addr_set_zero(&ip);
220 ip4_addr_set_zero(&mask);
221 ip4_addr_set_zero(&gw);
222
223 if (with_ip)
224 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
225 return NULL;
226
227 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
228 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
229 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
230 return NULL;
231
232 netif = calloc(1, sizeof(struct netif));
233 if (!netif)
234 return NULL;
235
236 netif->name[0] = 'e';
237 netif->name[1] = 't';
238
239 string_to_enetaddr(hwstr, netif->hwaddr);
240 netif->hwaddr_len = ETHARP_HWADDR_LEN;
241 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
242 hwstr, ip4addr_ntoa(&ip));
243 debug("mask:%s ", ip4addr_ntoa(&mask));
244 debug("gw:%s\n", ip4addr_ntoa(&gw));
245
246 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
247 netif_input)) {
248 printf("error: netif_add() failed\n");
249 free(netif);
250 return NULL;
251 }
252
253 netif_set_up(netif);
254 netif_set_link_up(netif);
255 /* Routing: use this interface to reach the default gateway */
256 netif_set_default(netif);
257
258 return netif;
259}
260
261struct netif *net_lwip_new_netif(struct udevice *udev)
262{
263 return new_netif(udev, true);
264}
265
266struct netif *net_lwip_new_netif_noip(struct udevice *udev)
267{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200268 return new_netif(udev, false);
269}
270
271void net_lwip_remove_netif(struct netif *netif)
272{
273 netif_remove(netif);
274 free(netif);
275}
276
Jerome Forissier86378a52025-04-15 23:17:36 +0200277/*
278 * Initialize the network buffers, an ethernet device, and the lwIP stack
279 * (once).
280 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200281int net_init(void)
282{
Jerome Forissier86378a52025-04-15 23:17:36 +0200283 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200284
Jerome Forissier86378a52025-04-15 23:17:36 +0200285 if (!init_done) {
286 eth_init_rings();
287 eth_init();
288 lwip_init();
289 init_done = true;
290 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200291
292 return 0;
293}
294
295static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
296{
Jerome Forissier97083502024-11-07 12:27:57 +0100297 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200298
Jerome Forissier97083502024-11-07 12:27:57 +0100299 /* We allocate a pbuf chain of pbufs from the pool. */
300 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
301 if (!p) {
302 LINK_STATS_INC(link.memerr);
303 LINK_STATS_INC(link.drop);
304 return NULL;
305 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200306
Jerome Forissier97083502024-11-07 12:27:57 +0100307 for (q = p; q != NULL; q = q->next) {
308 memcpy(q->payload, data, q->len);
309 data += q->len;
310 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200311
Jerome Forissier97083502024-11-07 12:27:57 +0100312 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200313
Jerome Forissier97083502024-11-07 12:27:57 +0100314 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200315}
316
317int net_lwip_rx(struct udevice *udev, struct netif *netif)
318{
319 struct pbuf *pbuf;
320 uchar *packet;
321 int flags;
322 int len;
323 int i;
324
Tim Harvey799c1302025-05-30 08:38:22 -0700325 /* lwIP timers */
326 sys_check_timeouts();
327 /* Other tasks and actions */
328 schedule();
329
Jerome Forissier1ff00362024-10-16 12:04:03 +0200330 if (!eth_is_active(udev))
331 return -EINVAL;
332
333 flags = ETH_RECV_CHECK_DEVICE;
334 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
335 len = eth_get_ops(udev)->recv(udev, flags, &packet);
336 flags = 0;
337
338 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100339 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
340 printf("net_lwip_tx: %u bytes, udev %s \n", len,
341 udev->name);
342 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
343 packet, len, true);
344 }
345
Jerome Forissier1ff00362024-10-16 12:04:03 +0200346 pbuf = alloc_pbuf_and_copy(packet, len);
347 if (pbuf)
348 netif->input(pbuf, netif);
349 }
350 if (len >= 0 && eth_get_ops(udev)->free_pkt)
351 eth_get_ops(udev)->free_pkt(udev, packet, len);
352 if (len <= 0)
353 break;
354 }
355 if (len == -EAGAIN)
356 len = 0;
357
358 return len;
359}
360
361void net_process_received_packet(uchar *in_packet, int len)
362{
363#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
364 if (push_packet)
365 (*push_packet)(in_packet, len);
366#endif
367}
368
Jerome Forissier6a78e962024-10-16 12:04:05 +0200369int net_loop(enum proto_t protocol)
370{
371 char *argv[1];
372
373 switch (protocol) {
374 case TFTPGET:
375 argv[0] = "tftpboot";
376 return do_tftpb(NULL, 0, 1, argv);
377 default:
378 return -EINVAL;
379 }
380
381 return -EINVAL;
382}
383
Jerome Forissier1ff00362024-10-16 12:04:03 +0200384u32_t sys_now(void)
385{
Jerome Forissier9145d992025-04-15 23:17:39 +0200386#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
387 return timer_early_get_count();
388#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200389 return get_timer(0);
Jerome Forissier9145d992025-04-15 23:17:39 +0200390#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200391}
Jerome Forissierc76a9f42025-04-15 23:17:37 +0200392
393int net_start_again(void)
394{
395 char *nretry;
396 int retry_forever = 0;
397 unsigned long retrycnt = 0;
398
399 nretry = env_get("netretry");
400 if (nretry) {
401 if (!strcmp(nretry, "yes"))
402 retry_forever = 1;
403 else if (!strcmp(nretry, "no"))
404 retrycnt = 0;
405 else if (!strcmp(nretry, "once"))
406 retrycnt = 1;
407 else
408 retrycnt = simple_strtoul(nretry, NULL, 0);
409 } else {
410 retrycnt = 0;
411 retry_forever = 0;
412 }
413
414 if ((!retry_forever) && (net_try_count > retrycnt)) {
415 eth_halt();
416 /*
417 * We don't provide a way for the protocol to return an error,
418 * but this is almost always the reason.
419 */
420 return -ETIMEDOUT;
421 }
422
423 net_try_count++;
424
425 eth_halt();
426#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
427 eth_try_another(!net_restarted);
428#endif
429 return eth_init();
430}