blob: abc52b32049cdd186657b625f9d1b155dcdda520 [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>
17#include <net.h>
Jerome Forissier9145d992025-04-15 23:17:39 +020018#include <timer.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020019
20/* xx:xx:xx:xx:xx:xx\0 */
21#define MAC_ADDR_STRLEN 18
22
23#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
24void (*push_packet)(void *, int len) = 0;
25#endif
Jerome Forissierc76a9f42025-04-15 23:17:37 +020026static int net_try_count;
27static int net_restarted;
Jerome Forissier1ff00362024-10-16 12:04:03 +020028int net_restart_wrap;
29static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
30uchar *net_rx_packets[PKTBUFSRX];
31uchar *net_rx_packet;
32const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
33char *pxelinux_configfile;
34/* Our IP addr (0 = unknown) */
35struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020036char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020037
Jerome Forissier9ba21312025-03-06 15:32:21 +010038static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020039{
40 struct udevice *udev = netif->state;
41 void *pp = NULL;
42 int err;
43
Jerome Forissier5b2e2732025-03-06 15:32:22 +010044 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
45 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
46 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
47 true);
48 }
49
Jerome Forissier1ff00362024-10-16 12:04:03 +020050 if ((unsigned long)p->payload % PKTALIGN) {
51 /*
52 * Some net drivers have strict alignment requirements and may
53 * fail or output invalid data if the packet is not aligned.
54 */
55 pp = memalign(PKTALIGN, p->len);
56 if (!pp)
57 return ERR_ABRT;
58 memcpy(pp, p->payload, p->len);
59 }
60
61 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
62 free(pp);
63 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020064 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020065 return ERR_ABRT;
66 }
67
68 return ERR_OK;
69}
70
71static err_t net_lwip_if_init(struct netif *netif)
72{
73 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010074 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020075 netif->mtu = 1500;
76 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
77
78 return ERR_OK;
79}
80
81static void eth_init_rings(void)
82{
83 int i;
84
85 for (i = 0; i < PKTBUFSRX; i++)
86 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
87}
88
89struct netif *net_lwip_get_netif(void)
90{
91 struct netif *netif, *found = NULL;
92
93 NETIF_FOREACH(netif) {
94 if (!found)
95 found = netif;
96 else
97 printf("Error: more than one netif in lwIP\n");
98 }
99 return found;
100}
101
102static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
103 ip4_addr_t *mask, ip4_addr_t *gw)
104{
Jerome Forissier91596572024-11-18 15:31:25 +0100105 char ipstr[] = "ipaddr\0\0";
106 char maskstr[] = "netmask\0\0";
107 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200108 int idx = dev_seq(dev);
109 char *env;
110
111 if (idx < 0 || idx > 99) {
112 log_err("unexpected idx %d\n", idx);
113 return -1;
114 }
115
116 if (idx) {
117 sprintf(ipstr, "ipaddr%d", idx);
118 sprintf(maskstr, "netmask%d", idx);
119 sprintf(gwstr, "gatewayip%d", idx);
120 }
121
122 ip4_addr_set_zero(ip);
123 ip4_addr_set_zero(mask);
124 ip4_addr_set_zero(gw);
125
126 env = env_get(ipstr);
127 if (env)
128 ip4addr_aton(env, ip);
129
130 env = env_get(maskstr);
131 if (env)
132 ip4addr_aton(env, mask);
133
134 env = env_get(gwstr);
135 if (env)
136 ip4addr_aton(env, gw);
137
138 return 0;
139}
140
Jerome Forissier86378a52025-04-15 23:17:36 +0200141/*
142 * Initialize the network stack if needed and start the current device if valid
143 */
144int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100145{
Jerome Forissier86378a52025-04-15 23:17:36 +0200146 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100147
Jerome Forissier86378a52025-04-15 23:17:36 +0200148 net_init();
149 if (eth_is_on_demand_init()) {
150 eth_halt();
151 eth_set_current();
152 ret = eth_init();
153 if (ret < 0) {
154 eth_halt();
155 return ret;
156 }
157 } else {
158 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100159 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200160
161 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100162}
163
Jerome Forissier1ff00362024-10-16 12:04:03 +0200164static struct netif *new_netif(struct udevice *udev, bool with_ip)
165{
166 unsigned char enetaddr[ARP_HLEN];
167 char hwstr[MAC_ADDR_STRLEN];
168 ip4_addr_t ip, mask, gw;
169 struct netif *netif;
170 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200171
172 if (!udev)
173 return NULL;
174
Jerome Forissier1ff00362024-10-16 12:04:03 +0200175 if (eth_start_udev(udev) < 0) {
176 log_err("Could not start %s\n", udev->name);
177 return NULL;
178 }
179
180 netif_remove(net_lwip_get_netif());
181
182 ip4_addr_set_zero(&ip);
183 ip4_addr_set_zero(&mask);
184 ip4_addr_set_zero(&gw);
185
186 if (with_ip)
187 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
188 return NULL;
189
190 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
191 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
192 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
193 return NULL;
194
195 netif = calloc(1, sizeof(struct netif));
196 if (!netif)
197 return NULL;
198
199 netif->name[0] = 'e';
200 netif->name[1] = 't';
201
202 string_to_enetaddr(hwstr, netif->hwaddr);
203 netif->hwaddr_len = ETHARP_HWADDR_LEN;
204 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
205 hwstr, ip4addr_ntoa(&ip));
206 debug("mask:%s ", ip4addr_ntoa(&mask));
207 debug("gw:%s\n", ip4addr_ntoa(&gw));
208
209 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
210 netif_input)) {
211 printf("error: netif_add() failed\n");
212 free(netif);
213 return NULL;
214 }
215
216 netif_set_up(netif);
217 netif_set_link_up(netif);
218 /* Routing: use this interface to reach the default gateway */
219 netif_set_default(netif);
220
221 return netif;
222}
223
224struct netif *net_lwip_new_netif(struct udevice *udev)
225{
226 return new_netif(udev, true);
227}
228
229struct netif *net_lwip_new_netif_noip(struct udevice *udev)
230{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200231 return new_netif(udev, false);
232}
233
234void net_lwip_remove_netif(struct netif *netif)
235{
236 netif_remove(netif);
237 free(netif);
238}
239
Jerome Forissier86378a52025-04-15 23:17:36 +0200240/*
241 * Initialize the network buffers, an ethernet device, and the lwIP stack
242 * (once).
243 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200244int net_init(void)
245{
Jerome Forissier86378a52025-04-15 23:17:36 +0200246 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200247
Jerome Forissier86378a52025-04-15 23:17:36 +0200248 if (!init_done) {
249 eth_init_rings();
250 eth_init();
251 lwip_init();
252 init_done = true;
253 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200254
255 return 0;
256}
257
258static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
259{
Jerome Forissier97083502024-11-07 12:27:57 +0100260 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200261
Jerome Forissier97083502024-11-07 12:27:57 +0100262 /* We allocate a pbuf chain of pbufs from the pool. */
263 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
264 if (!p) {
265 LINK_STATS_INC(link.memerr);
266 LINK_STATS_INC(link.drop);
267 return NULL;
268 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200269
Jerome Forissier97083502024-11-07 12:27:57 +0100270 for (q = p; q != NULL; q = q->next) {
271 memcpy(q->payload, data, q->len);
272 data += q->len;
273 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200274
Jerome Forissier97083502024-11-07 12:27:57 +0100275 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200276
Jerome Forissier97083502024-11-07 12:27:57 +0100277 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200278}
279
280int net_lwip_rx(struct udevice *udev, struct netif *netif)
281{
282 struct pbuf *pbuf;
283 uchar *packet;
284 int flags;
285 int len;
286 int i;
287
288 if (!eth_is_active(udev))
289 return -EINVAL;
290
291 flags = ETH_RECV_CHECK_DEVICE;
292 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
293 len = eth_get_ops(udev)->recv(udev, flags, &packet);
294 flags = 0;
295
296 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100297 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
298 printf("net_lwip_tx: %u bytes, udev %s \n", len,
299 udev->name);
300 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
301 packet, len, true);
302 }
303
Jerome Forissier1ff00362024-10-16 12:04:03 +0200304 pbuf = alloc_pbuf_and_copy(packet, len);
305 if (pbuf)
306 netif->input(pbuf, netif);
307 }
308 if (len >= 0 && eth_get_ops(udev)->free_pkt)
309 eth_get_ops(udev)->free_pkt(udev, packet, len);
310 if (len <= 0)
311 break;
312 }
313 if (len == -EAGAIN)
314 len = 0;
315
316 return len;
317}
318
319void net_process_received_packet(uchar *in_packet, int len)
320{
321#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
322 if (push_packet)
323 (*push_packet)(in_packet, len);
324#endif
325}
326
Jerome Forissier6a78e962024-10-16 12:04:05 +0200327int net_loop(enum proto_t protocol)
328{
329 char *argv[1];
330
331 switch (protocol) {
332 case TFTPGET:
333 argv[0] = "tftpboot";
334 return do_tftpb(NULL, 0, 1, argv);
335 default:
336 return -EINVAL;
337 }
338
339 return -EINVAL;
340}
341
Jerome Forissier1ff00362024-10-16 12:04:03 +0200342u32_t sys_now(void)
343{
Jerome Forissier9145d992025-04-15 23:17:39 +0200344#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
345 return timer_early_get_count();
346#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200347 return get_timer(0);
Jerome Forissier9145d992025-04-15 23:17:39 +0200348#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200349}
Jerome Forissierc76a9f42025-04-15 23:17:37 +0200350
351int net_start_again(void)
352{
353 char *nretry;
354 int retry_forever = 0;
355 unsigned long retrycnt = 0;
356
357 nretry = env_get("netretry");
358 if (nretry) {
359 if (!strcmp(nretry, "yes"))
360 retry_forever = 1;
361 else if (!strcmp(nretry, "no"))
362 retrycnt = 0;
363 else if (!strcmp(nretry, "once"))
364 retrycnt = 1;
365 else
366 retrycnt = simple_strtoul(nretry, NULL, 0);
367 } else {
368 retrycnt = 0;
369 retry_forever = 0;
370 }
371
372 if ((!retry_forever) && (net_try_count > retrycnt)) {
373 eth_halt();
374 /*
375 * We don't provide a way for the protocol to return an error,
376 * but this is almost always the reason.
377 */
378 return -ETIMEDOUT;
379 }
380
381 net_try_count++;
382
383 eth_halt();
384#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
385 eth_try_another(!net_restarted);
386#endif
387 return eth_init();
388}