blob: ff4d634d1d14317db0aa79a0dd4b3d86db34d160 [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>
11#include <lwip/err.h>
12#include <lwip/netif.h>
13#include <lwip/pbuf.h>
14#include <lwip/etharp.h>
15#include <lwip/init.h>
16#include <lwip/prot/etharp.h>
Tim Harvey799c1302025-05-30 08:38:22 -070017#include <lwip/timeouts.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020018#include <net.h>
Jerome Forissier9145d992025-04-15 23:17:39 +020019#include <timer.h>
Tim Harvey799c1302025-05-30 08:38:22 -070020#include <u-boot/schedule.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020021
22/* xx:xx:xx:xx:xx:xx\0 */
23#define MAC_ADDR_STRLEN 18
24
25#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
26void (*push_packet)(void *, int len) = 0;
27#endif
Jerome Forissierc76a9f42025-04-15 23:17:37 +020028static int net_try_count;
29static int net_restarted;
Jerome Forissier1ff00362024-10-16 12:04:03 +020030int net_restart_wrap;
31static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
32uchar *net_rx_packets[PKTBUFSRX];
33uchar *net_rx_packet;
34const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
35char *pxelinux_configfile;
36/* Our IP addr (0 = unknown) */
37struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020038char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020039
Jerome Forissier9ba21312025-03-06 15:32:21 +010040static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020041{
42 struct udevice *udev = netif->state;
43 void *pp = NULL;
44 int err;
45
Jerome Forissier5b2e2732025-03-06 15:32:22 +010046 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
47 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
48 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
49 true);
50 }
51
Jerome Forissier1ff00362024-10-16 12:04:03 +020052 if ((unsigned long)p->payload % PKTALIGN) {
53 /*
54 * Some net drivers have strict alignment requirements and may
55 * fail or output invalid data if the packet is not aligned.
56 */
57 pp = memalign(PKTALIGN, p->len);
58 if (!pp)
59 return ERR_ABRT;
60 memcpy(pp, p->payload, p->len);
61 }
62
63 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
64 free(pp);
65 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020066 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020067 return ERR_ABRT;
68 }
69
70 return ERR_OK;
71}
72
73static err_t net_lwip_if_init(struct netif *netif)
74{
75 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010076 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020077 netif->mtu = 1500;
78 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
79
80 return ERR_OK;
81}
82
83static void eth_init_rings(void)
84{
85 int i;
86
87 for (i = 0; i < PKTBUFSRX; i++)
88 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
89}
90
91struct netif *net_lwip_get_netif(void)
92{
93 struct netif *netif, *found = NULL;
94
95 NETIF_FOREACH(netif) {
96 if (!found)
97 found = netif;
98 else
99 printf("Error: more than one netif in lwIP\n");
100 }
101 return found;
102}
103
104static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
105 ip4_addr_t *mask, ip4_addr_t *gw)
106{
Jerome Forissier91596572024-11-18 15:31:25 +0100107 char ipstr[] = "ipaddr\0\0";
108 char maskstr[] = "netmask\0\0";
109 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200110 int idx = dev_seq(dev);
111 char *env;
112
113 if (idx < 0 || idx > 99) {
114 log_err("unexpected idx %d\n", idx);
115 return -1;
116 }
117
118 if (idx) {
119 sprintf(ipstr, "ipaddr%d", idx);
120 sprintf(maskstr, "netmask%d", idx);
121 sprintf(gwstr, "gatewayip%d", idx);
122 }
123
124 ip4_addr_set_zero(ip);
125 ip4_addr_set_zero(mask);
126 ip4_addr_set_zero(gw);
127
128 env = env_get(ipstr);
129 if (env)
130 ip4addr_aton(env, ip);
131
132 env = env_get(maskstr);
133 if (env)
134 ip4addr_aton(env, mask);
135
136 env = env_get(gwstr);
137 if (env)
138 ip4addr_aton(env, gw);
139
140 return 0;
141}
142
Jerome Forissier86378a52025-04-15 23:17:36 +0200143/*
144 * Initialize the network stack if needed and start the current device if valid
145 */
146int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100147{
Jerome Forissier86378a52025-04-15 23:17:36 +0200148 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100149
Jerome Forissier86378a52025-04-15 23:17:36 +0200150 net_init();
151 if (eth_is_on_demand_init()) {
152 eth_halt();
153 eth_set_current();
154 ret = eth_init();
155 if (ret < 0) {
156 eth_halt();
157 return ret;
158 }
159 } else {
160 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100161 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200162
163 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100164}
165
Jerome Forissier1ff00362024-10-16 12:04:03 +0200166static struct netif *new_netif(struct udevice *udev, bool with_ip)
167{
168 unsigned char enetaddr[ARP_HLEN];
169 char hwstr[MAC_ADDR_STRLEN];
170 ip4_addr_t ip, mask, gw;
171 struct netif *netif;
172 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200173
174 if (!udev)
175 return NULL;
176
Jerome Forissier1ff00362024-10-16 12:04:03 +0200177 if (eth_start_udev(udev) < 0) {
178 log_err("Could not start %s\n", udev->name);
179 return NULL;
180 }
181
182 netif_remove(net_lwip_get_netif());
183
184 ip4_addr_set_zero(&ip);
185 ip4_addr_set_zero(&mask);
186 ip4_addr_set_zero(&gw);
187
188 if (with_ip)
189 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
190 return NULL;
191
192 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
193 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
194 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
195 return NULL;
196
197 netif = calloc(1, sizeof(struct netif));
198 if (!netif)
199 return NULL;
200
201 netif->name[0] = 'e';
202 netif->name[1] = 't';
203
204 string_to_enetaddr(hwstr, netif->hwaddr);
205 netif->hwaddr_len = ETHARP_HWADDR_LEN;
206 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
207 hwstr, ip4addr_ntoa(&ip));
208 debug("mask:%s ", ip4addr_ntoa(&mask));
209 debug("gw:%s\n", ip4addr_ntoa(&gw));
210
211 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
212 netif_input)) {
213 printf("error: netif_add() failed\n");
214 free(netif);
215 return NULL;
216 }
217
218 netif_set_up(netif);
219 netif_set_link_up(netif);
220 /* Routing: use this interface to reach the default gateway */
221 netif_set_default(netif);
222
223 return netif;
224}
225
226struct netif *net_lwip_new_netif(struct udevice *udev)
227{
228 return new_netif(udev, true);
229}
230
231struct netif *net_lwip_new_netif_noip(struct udevice *udev)
232{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200233 return new_netif(udev, false);
234}
235
236void net_lwip_remove_netif(struct netif *netif)
237{
238 netif_remove(netif);
239 free(netif);
240}
241
Jerome Forissier86378a52025-04-15 23:17:36 +0200242/*
243 * Initialize the network buffers, an ethernet device, and the lwIP stack
244 * (once).
245 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200246int net_init(void)
247{
Jerome Forissier86378a52025-04-15 23:17:36 +0200248 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200249
Jerome Forissier86378a52025-04-15 23:17:36 +0200250 if (!init_done) {
251 eth_init_rings();
252 eth_init();
253 lwip_init();
254 init_done = true;
255 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200256
257 return 0;
258}
259
260static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
261{
Jerome Forissier97083502024-11-07 12:27:57 +0100262 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200263
Jerome Forissier97083502024-11-07 12:27:57 +0100264 /* We allocate a pbuf chain of pbufs from the pool. */
265 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
266 if (!p) {
267 LINK_STATS_INC(link.memerr);
268 LINK_STATS_INC(link.drop);
269 return NULL;
270 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200271
Jerome Forissier97083502024-11-07 12:27:57 +0100272 for (q = p; q != NULL; q = q->next) {
273 memcpy(q->payload, data, q->len);
274 data += q->len;
275 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200276
Jerome Forissier97083502024-11-07 12:27:57 +0100277 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200278
Jerome Forissier97083502024-11-07 12:27:57 +0100279 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200280}
281
282int net_lwip_rx(struct udevice *udev, struct netif *netif)
283{
284 struct pbuf *pbuf;
285 uchar *packet;
286 int flags;
287 int len;
288 int i;
289
Tim Harvey799c1302025-05-30 08:38:22 -0700290 /* lwIP timers */
291 sys_check_timeouts();
292 /* Other tasks and actions */
293 schedule();
294
Jerome Forissier1ff00362024-10-16 12:04:03 +0200295 if (!eth_is_active(udev))
296 return -EINVAL;
297
298 flags = ETH_RECV_CHECK_DEVICE;
299 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
300 len = eth_get_ops(udev)->recv(udev, flags, &packet);
301 flags = 0;
302
303 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100304 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
305 printf("net_lwip_tx: %u bytes, udev %s \n", len,
306 udev->name);
307 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
308 packet, len, true);
309 }
310
Jerome Forissier1ff00362024-10-16 12:04:03 +0200311 pbuf = alloc_pbuf_and_copy(packet, len);
312 if (pbuf)
313 netif->input(pbuf, netif);
314 }
315 if (len >= 0 && eth_get_ops(udev)->free_pkt)
316 eth_get_ops(udev)->free_pkt(udev, packet, len);
317 if (len <= 0)
318 break;
319 }
320 if (len == -EAGAIN)
321 len = 0;
322
323 return len;
324}
325
326void net_process_received_packet(uchar *in_packet, int len)
327{
328#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
329 if (push_packet)
330 (*push_packet)(in_packet, len);
331#endif
332}
333
Jerome Forissier6a78e962024-10-16 12:04:05 +0200334int net_loop(enum proto_t protocol)
335{
336 char *argv[1];
337
338 switch (protocol) {
339 case TFTPGET:
340 argv[0] = "tftpboot";
341 return do_tftpb(NULL, 0, 1, argv);
342 default:
343 return -EINVAL;
344 }
345
346 return -EINVAL;
347}
348
Jerome Forissier1ff00362024-10-16 12:04:03 +0200349u32_t sys_now(void)
350{
Jerome Forissier9145d992025-04-15 23:17:39 +0200351#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
352 return timer_early_get_count();
353#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200354 return get_timer(0);
Jerome Forissier9145d992025-04-15 23:17:39 +0200355#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200356}
Jerome Forissierc76a9f42025-04-15 23:17:37 +0200357
358int net_start_again(void)
359{
360 char *nretry;
361 int retry_forever = 0;
362 unsigned long retrycnt = 0;
363
364 nretry = env_get("netretry");
365 if (nretry) {
366 if (!strcmp(nretry, "yes"))
367 retry_forever = 1;
368 else if (!strcmp(nretry, "no"))
369 retrycnt = 0;
370 else if (!strcmp(nretry, "once"))
371 retrycnt = 1;
372 else
373 retrycnt = simple_strtoul(nretry, NULL, 0);
374 } else {
375 retrycnt = 0;
376 retry_forever = 0;
377 }
378
379 if ((!retry_forever) && (net_try_count > retrycnt)) {
380 eth_halt();
381 /*
382 * We don't provide a way for the protocol to return an error,
383 * but this is almost always the reason.
384 */
385 return -ETIMEDOUT;
386 }
387
388 net_try_count++;
389
390 eth_halt();
391#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
392 eth_try_another(!net_restarted);
393#endif
394 return eth_init();
395}