blob: f05c4cd3f64f37a665d92d43230520fb9e5ae6c6 [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>
6#include <dm/device.h>
7#include <dm/uclass.h>
Jerome Forissier5b2e2732025-03-06 15:32:22 +01008#include <hexdump.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +02009#include <lwip/ip4_addr.h>
10#include <lwip/err.h>
11#include <lwip/netif.h>
12#include <lwip/pbuf.h>
13#include <lwip/etharp.h>
14#include <lwip/init.h>
15#include <lwip/prot/etharp.h>
16#include <net.h>
Jerome Forissier9145d992025-04-15 23:17:39 +020017#include <timer.h>
Jerome Forissier1ff00362024-10-16 12:04:03 +020018
19/* xx:xx:xx:xx:xx:xx\0 */
20#define MAC_ADDR_STRLEN 18
21
22#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
23void (*push_packet)(void *, int len) = 0;
24#endif
Jerome Forissierc76a9f42025-04-15 23:17:37 +020025static int net_try_count;
26static int net_restarted;
Jerome Forissier1ff00362024-10-16 12:04:03 +020027int net_restart_wrap;
28static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
29uchar *net_rx_packets[PKTBUFSRX];
30uchar *net_rx_packet;
31const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
32char *pxelinux_configfile;
33/* Our IP addr (0 = unknown) */
34struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020035char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020036
Jerome Forissier9ba21312025-03-06 15:32:21 +010037static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020038{
39 struct udevice *udev = netif->state;
40 void *pp = NULL;
41 int err;
42
Jerome Forissier5b2e2732025-03-06 15:32:22 +010043 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
44 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
45 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
46 true);
47 }
48
Jerome Forissier1ff00362024-10-16 12:04:03 +020049 if ((unsigned long)p->payload % PKTALIGN) {
50 /*
51 * Some net drivers have strict alignment requirements and may
52 * fail or output invalid data if the packet is not aligned.
53 */
54 pp = memalign(PKTALIGN, p->len);
55 if (!pp)
56 return ERR_ABRT;
57 memcpy(pp, p->payload, p->len);
58 }
59
60 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
61 free(pp);
62 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020063 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020064 return ERR_ABRT;
65 }
66
67 return ERR_OK;
68}
69
70static err_t net_lwip_if_init(struct netif *netif)
71{
72 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010073 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020074 netif->mtu = 1500;
75 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
76
77 return ERR_OK;
78}
79
80static void eth_init_rings(void)
81{
82 int i;
83
84 for (i = 0; i < PKTBUFSRX; i++)
85 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
86}
87
88struct netif *net_lwip_get_netif(void)
89{
90 struct netif *netif, *found = NULL;
91
92 NETIF_FOREACH(netif) {
93 if (!found)
94 found = netif;
95 else
96 printf("Error: more than one netif in lwIP\n");
97 }
98 return found;
99}
100
101static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
102 ip4_addr_t *mask, ip4_addr_t *gw)
103{
Jerome Forissier91596572024-11-18 15:31:25 +0100104 char ipstr[] = "ipaddr\0\0";
105 char maskstr[] = "netmask\0\0";
106 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200107 int idx = dev_seq(dev);
108 char *env;
109
110 if (idx < 0 || idx > 99) {
111 log_err("unexpected idx %d\n", idx);
112 return -1;
113 }
114
115 if (idx) {
116 sprintf(ipstr, "ipaddr%d", idx);
117 sprintf(maskstr, "netmask%d", idx);
118 sprintf(gwstr, "gatewayip%d", idx);
119 }
120
121 ip4_addr_set_zero(ip);
122 ip4_addr_set_zero(mask);
123 ip4_addr_set_zero(gw);
124
125 env = env_get(ipstr);
126 if (env)
127 ip4addr_aton(env, ip);
128
129 env = env_get(maskstr);
130 if (env)
131 ip4addr_aton(env, mask);
132
133 env = env_get(gwstr);
134 if (env)
135 ip4addr_aton(env, gw);
136
137 return 0;
138}
139
Jerome Forissier86378a52025-04-15 23:17:36 +0200140/*
141 * Initialize the network stack if needed and start the current device if valid
142 */
143int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100144{
Jerome Forissier86378a52025-04-15 23:17:36 +0200145 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100146
Jerome Forissier86378a52025-04-15 23:17:36 +0200147 net_init();
148 if (eth_is_on_demand_init()) {
149 eth_halt();
150 eth_set_current();
151 ret = eth_init();
152 if (ret < 0) {
153 eth_halt();
154 return ret;
155 }
156 } else {
157 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100158 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200159
160 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100161}
162
Jerome Forissier1ff00362024-10-16 12:04:03 +0200163static struct netif *new_netif(struct udevice *udev, bool with_ip)
164{
165 unsigned char enetaddr[ARP_HLEN];
166 char hwstr[MAC_ADDR_STRLEN];
167 ip4_addr_t ip, mask, gw;
168 struct netif *netif;
169 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200170
171 if (!udev)
172 return NULL;
173
Jerome Forissier1ff00362024-10-16 12:04:03 +0200174 if (eth_start_udev(udev) < 0) {
175 log_err("Could not start %s\n", udev->name);
176 return NULL;
177 }
178
179 netif_remove(net_lwip_get_netif());
180
181 ip4_addr_set_zero(&ip);
182 ip4_addr_set_zero(&mask);
183 ip4_addr_set_zero(&gw);
184
185 if (with_ip)
186 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
187 return NULL;
188
189 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
190 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
191 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
192 return NULL;
193
194 netif = calloc(1, sizeof(struct netif));
195 if (!netif)
196 return NULL;
197
198 netif->name[0] = 'e';
199 netif->name[1] = 't';
200
201 string_to_enetaddr(hwstr, netif->hwaddr);
202 netif->hwaddr_len = ETHARP_HWADDR_LEN;
203 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
204 hwstr, ip4addr_ntoa(&ip));
205 debug("mask:%s ", ip4addr_ntoa(&mask));
206 debug("gw:%s\n", ip4addr_ntoa(&gw));
207
208 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
209 netif_input)) {
210 printf("error: netif_add() failed\n");
211 free(netif);
212 return NULL;
213 }
214
215 netif_set_up(netif);
216 netif_set_link_up(netif);
217 /* Routing: use this interface to reach the default gateway */
218 netif_set_default(netif);
219
220 return netif;
221}
222
223struct netif *net_lwip_new_netif(struct udevice *udev)
224{
225 return new_netif(udev, true);
226}
227
228struct netif *net_lwip_new_netif_noip(struct udevice *udev)
229{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200230 return new_netif(udev, false);
231}
232
233void net_lwip_remove_netif(struct netif *netif)
234{
235 netif_remove(netif);
236 free(netif);
237}
238
Jerome Forissier86378a52025-04-15 23:17:36 +0200239/*
240 * Initialize the network buffers, an ethernet device, and the lwIP stack
241 * (once).
242 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200243int net_init(void)
244{
Jerome Forissier86378a52025-04-15 23:17:36 +0200245 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200246
Jerome Forissier86378a52025-04-15 23:17:36 +0200247 if (!init_done) {
248 eth_init_rings();
249 eth_init();
250 lwip_init();
251 init_done = true;
252 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200253
254 return 0;
255}
256
257static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
258{
Jerome Forissier97083502024-11-07 12:27:57 +0100259 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200260
Jerome Forissier97083502024-11-07 12:27:57 +0100261 /* We allocate a pbuf chain of pbufs from the pool. */
262 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
263 if (!p) {
264 LINK_STATS_INC(link.memerr);
265 LINK_STATS_INC(link.drop);
266 return NULL;
267 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200268
Jerome Forissier97083502024-11-07 12:27:57 +0100269 for (q = p; q != NULL; q = q->next) {
270 memcpy(q->payload, data, q->len);
271 data += q->len;
272 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200273
Jerome Forissier97083502024-11-07 12:27:57 +0100274 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200275
Jerome Forissier97083502024-11-07 12:27:57 +0100276 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200277}
278
279int net_lwip_rx(struct udevice *udev, struct netif *netif)
280{
281 struct pbuf *pbuf;
282 uchar *packet;
283 int flags;
284 int len;
285 int i;
286
287 if (!eth_is_active(udev))
288 return -EINVAL;
289
290 flags = ETH_RECV_CHECK_DEVICE;
291 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
292 len = eth_get_ops(udev)->recv(udev, flags, &packet);
293 flags = 0;
294
295 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100296 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
297 printf("net_lwip_tx: %u bytes, udev %s \n", len,
298 udev->name);
299 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
300 packet, len, true);
301 }
302
Jerome Forissier1ff00362024-10-16 12:04:03 +0200303 pbuf = alloc_pbuf_and_copy(packet, len);
304 if (pbuf)
305 netif->input(pbuf, netif);
306 }
307 if (len >= 0 && eth_get_ops(udev)->free_pkt)
308 eth_get_ops(udev)->free_pkt(udev, packet, len);
309 if (len <= 0)
310 break;
311 }
312 if (len == -EAGAIN)
313 len = 0;
314
315 return len;
316}
317
318void net_process_received_packet(uchar *in_packet, int len)
319{
320#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
321 if (push_packet)
322 (*push_packet)(in_packet, len);
323#endif
324}
325
Jerome Forissier6a78e962024-10-16 12:04:05 +0200326int net_loop(enum proto_t protocol)
327{
328 char *argv[1];
329
330 switch (protocol) {
331 case TFTPGET:
332 argv[0] = "tftpboot";
333 return do_tftpb(NULL, 0, 1, argv);
334 default:
335 return -EINVAL;
336 }
337
338 return -EINVAL;
339}
340
Jerome Forissier1ff00362024-10-16 12:04:03 +0200341u32_t sys_now(void)
342{
Jerome Forissier9145d992025-04-15 23:17:39 +0200343#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
344 return timer_early_get_count();
345#else
Jerome Forissier1ff00362024-10-16 12:04:03 +0200346 return get_timer(0);
Jerome Forissier9145d992025-04-15 23:17:39 +0200347#endif
Jerome Forissier1ff00362024-10-16 12:04:03 +0200348}
Jerome Forissierc76a9f42025-04-15 23:17:37 +0200349
350int net_start_again(void)
351{
352 char *nretry;
353 int retry_forever = 0;
354 unsigned long retrycnt = 0;
355
356 nretry = env_get("netretry");
357 if (nretry) {
358 if (!strcmp(nretry, "yes"))
359 retry_forever = 1;
360 else if (!strcmp(nretry, "no"))
361 retrycnt = 0;
362 else if (!strcmp(nretry, "once"))
363 retrycnt = 1;
364 else
365 retrycnt = simple_strtoul(nretry, NULL, 0);
366 } else {
367 retrycnt = 0;
368 retry_forever = 0;
369 }
370
371 if ((!retry_forever) && (net_try_count > retrycnt)) {
372 eth_halt();
373 /*
374 * We don't provide a way for the protocol to return an error,
375 * but this is almost always the reason.
376 */
377 return -ETIMEDOUT;
378 }
379
380 net_try_count++;
381
382 eth_halt();
383#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
384 eth_try_another(!net_restarted);
385#endif
386 return eth_init();
387}