blob: 6748008736b768e9e5747f977aea4e3f49926a9c [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>
17
18/* xx:xx:xx:xx:xx:xx\0 */
19#define MAC_ADDR_STRLEN 18
20
21#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
22void (*push_packet)(void *, int len) = 0;
23#endif
24int net_restart_wrap;
25static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
26uchar *net_rx_packets[PKTBUFSRX];
27uchar *net_rx_packet;
28const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
29char *pxelinux_configfile;
30/* Our IP addr (0 = unknown) */
31struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020032char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020033
Jerome Forissier9ba21312025-03-06 15:32:21 +010034static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
Jerome Forissier1ff00362024-10-16 12:04:03 +020035{
36 struct udevice *udev = netif->state;
37 void *pp = NULL;
38 int err;
39
Jerome Forissier5b2e2732025-03-06 15:32:22 +010040 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
41 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
42 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
43 true);
44 }
45
Jerome Forissier1ff00362024-10-16 12:04:03 +020046 if ((unsigned long)p->payload % PKTALIGN) {
47 /*
48 * Some net drivers have strict alignment requirements and may
49 * fail or output invalid data if the packet is not aligned.
50 */
51 pp = memalign(PKTALIGN, p->len);
52 if (!pp)
53 return ERR_ABRT;
54 memcpy(pp, p->payload, p->len);
55 }
56
57 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
58 free(pp);
59 if (err) {
Ilias Apalodimasc99a1022025-03-26 10:28:58 +020060 debug("send error %d\n", err);
Jerome Forissier1ff00362024-10-16 12:04:03 +020061 return ERR_ABRT;
62 }
63
64 return ERR_OK;
65}
66
67static err_t net_lwip_if_init(struct netif *netif)
68{
69 netif->output = etharp_output;
Jerome Forissier9ba21312025-03-06 15:32:21 +010070 netif->linkoutput = net_lwip_tx;
Jerome Forissier1ff00362024-10-16 12:04:03 +020071 netif->mtu = 1500;
72 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
73
74 return ERR_OK;
75}
76
77static void eth_init_rings(void)
78{
79 int i;
80
81 for (i = 0; i < PKTBUFSRX; i++)
82 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
83}
84
85struct netif *net_lwip_get_netif(void)
86{
87 struct netif *netif, *found = NULL;
88
89 NETIF_FOREACH(netif) {
90 if (!found)
91 found = netif;
92 else
93 printf("Error: more than one netif in lwIP\n");
94 }
95 return found;
96}
97
98static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
99 ip4_addr_t *mask, ip4_addr_t *gw)
100{
Jerome Forissier91596572024-11-18 15:31:25 +0100101 char ipstr[] = "ipaddr\0\0";
102 char maskstr[] = "netmask\0\0";
103 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +0200104 int idx = dev_seq(dev);
105 char *env;
106
107 if (idx < 0 || idx > 99) {
108 log_err("unexpected idx %d\n", idx);
109 return -1;
110 }
111
112 if (idx) {
113 sprintf(ipstr, "ipaddr%d", idx);
114 sprintf(maskstr, "netmask%d", idx);
115 sprintf(gwstr, "gatewayip%d", idx);
116 }
117
118 ip4_addr_set_zero(ip);
119 ip4_addr_set_zero(mask);
120 ip4_addr_set_zero(gw);
121
122 env = env_get(ipstr);
123 if (env)
124 ip4addr_aton(env, ip);
125
126 env = env_get(maskstr);
127 if (env)
128 ip4addr_aton(env, mask);
129
130 env = env_get(gwstr);
131 if (env)
132 ip4addr_aton(env, gw);
133
134 return 0;
135}
136
Jerome Forissier86378a52025-04-15 23:17:36 +0200137/*
138 * Initialize the network stack if needed and start the current device if valid
139 */
140int net_lwip_eth_start(void)
Jerome Forissier37829282025-01-30 09:22:20 +0100141{
Jerome Forissier86378a52025-04-15 23:17:36 +0200142 int ret;
Jerome Forissier37829282025-01-30 09:22:20 +0100143
Jerome Forissier86378a52025-04-15 23:17:36 +0200144 net_init();
145 if (eth_is_on_demand_init()) {
146 eth_halt();
147 eth_set_current();
148 ret = eth_init();
149 if (ret < 0) {
150 eth_halt();
151 return ret;
152 }
153 } else {
154 eth_init_state_only();
Jerome Forissier37829282025-01-30 09:22:20 +0100155 }
Jerome Forissier86378a52025-04-15 23:17:36 +0200156
157 return 0;
Jerome Forissier37829282025-01-30 09:22:20 +0100158}
159
Jerome Forissier1ff00362024-10-16 12:04:03 +0200160static struct netif *new_netif(struct udevice *udev, bool with_ip)
161{
162 unsigned char enetaddr[ARP_HLEN];
163 char hwstr[MAC_ADDR_STRLEN];
164 ip4_addr_t ip, mask, gw;
165 struct netif *netif;
166 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200167
168 if (!udev)
169 return NULL;
170
Jerome Forissier1ff00362024-10-16 12:04:03 +0200171 if (eth_start_udev(udev) < 0) {
172 log_err("Could not start %s\n", udev->name);
173 return NULL;
174 }
175
176 netif_remove(net_lwip_get_netif());
177
178 ip4_addr_set_zero(&ip);
179 ip4_addr_set_zero(&mask);
180 ip4_addr_set_zero(&gw);
181
182 if (with_ip)
183 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
184 return NULL;
185
186 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
187 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
188 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
189 return NULL;
190
191 netif = calloc(1, sizeof(struct netif));
192 if (!netif)
193 return NULL;
194
195 netif->name[0] = 'e';
196 netif->name[1] = 't';
197
198 string_to_enetaddr(hwstr, netif->hwaddr);
199 netif->hwaddr_len = ETHARP_HWADDR_LEN;
200 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
201 hwstr, ip4addr_ntoa(&ip));
202 debug("mask:%s ", ip4addr_ntoa(&mask));
203 debug("gw:%s\n", ip4addr_ntoa(&gw));
204
205 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
206 netif_input)) {
207 printf("error: netif_add() failed\n");
208 free(netif);
209 return NULL;
210 }
211
212 netif_set_up(netif);
213 netif_set_link_up(netif);
214 /* Routing: use this interface to reach the default gateway */
215 netif_set_default(netif);
216
217 return netif;
218}
219
220struct netif *net_lwip_new_netif(struct udevice *udev)
221{
222 return new_netif(udev, true);
223}
224
225struct netif *net_lwip_new_netif_noip(struct udevice *udev)
226{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200227 return new_netif(udev, false);
228}
229
230void net_lwip_remove_netif(struct netif *netif)
231{
232 netif_remove(netif);
233 free(netif);
234}
235
Jerome Forissier86378a52025-04-15 23:17:36 +0200236/*
237 * Initialize the network buffers, an ethernet device, and the lwIP stack
238 * (once).
239 */
Jerome Forissier1ff00362024-10-16 12:04:03 +0200240int net_init(void)
241{
Jerome Forissier86378a52025-04-15 23:17:36 +0200242 static bool init_done;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200243
Jerome Forissier86378a52025-04-15 23:17:36 +0200244 if (!init_done) {
245 eth_init_rings();
246 eth_init();
247 lwip_init();
248 init_done = true;
249 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200250
251 return 0;
252}
253
254static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
255{
Jerome Forissier97083502024-11-07 12:27:57 +0100256 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200257
Jerome Forissier97083502024-11-07 12:27:57 +0100258 /* We allocate a pbuf chain of pbufs from the pool. */
259 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
260 if (!p) {
261 LINK_STATS_INC(link.memerr);
262 LINK_STATS_INC(link.drop);
263 return NULL;
264 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200265
Jerome Forissier97083502024-11-07 12:27:57 +0100266 for (q = p; q != NULL; q = q->next) {
267 memcpy(q->payload, data, q->len);
268 data += q->len;
269 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200270
Jerome Forissier97083502024-11-07 12:27:57 +0100271 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200272
Jerome Forissier97083502024-11-07 12:27:57 +0100273 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200274}
275
276int net_lwip_rx(struct udevice *udev, struct netif *netif)
277{
278 struct pbuf *pbuf;
279 uchar *packet;
280 int flags;
281 int len;
282 int i;
283
284 if (!eth_is_active(udev))
285 return -EINVAL;
286
287 flags = ETH_RECV_CHECK_DEVICE;
288 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
289 len = eth_get_ops(udev)->recv(udev, flags, &packet);
290 flags = 0;
291
292 if (len > 0) {
Jerome Forissier5b2e2732025-03-06 15:32:22 +0100293 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
294 printf("net_lwip_tx: %u bytes, udev %s \n", len,
295 udev->name);
296 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
297 packet, len, true);
298 }
299
Jerome Forissier1ff00362024-10-16 12:04:03 +0200300 pbuf = alloc_pbuf_and_copy(packet, len);
301 if (pbuf)
302 netif->input(pbuf, netif);
303 }
304 if (len >= 0 && eth_get_ops(udev)->free_pkt)
305 eth_get_ops(udev)->free_pkt(udev, packet, len);
306 if (len <= 0)
307 break;
308 }
309 if (len == -EAGAIN)
310 len = 0;
311
312 return len;
313}
314
315void net_process_received_packet(uchar *in_packet, int len)
316{
317#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
318 if (push_packet)
319 (*push_packet)(in_packet, len);
320#endif
321}
322
Jerome Forissier6a78e962024-10-16 12:04:05 +0200323int net_loop(enum proto_t protocol)
324{
325 char *argv[1];
326
327 switch (protocol) {
328 case TFTPGET:
329 argv[0] = "tftpboot";
330 return do_tftpb(NULL, 0, 1, argv);
331 default:
332 return -EINVAL;
333 }
334
335 return -EINVAL;
336}
337
Jerome Forissier1ff00362024-10-16 12:04:03 +0200338u32_t sys_now(void)
339{
340 return get_timer(0);
341}