1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (C) 2024 Linaro Ltd. */
4
5 #include <command.h>
6 #include <env.h>
7 #include <dm/device.h>
8 #include <dm/uclass.h>
9 #include <hexdump.h>
10 #include <linux/kernel.h>
11 #include <lwip/ip4_addr.h>
12 #include <lwip/dns.h>
13 #include <lwip/err.h>
14 #include <lwip/netif.h>
15 #include <lwip/pbuf.h>
16 #include <lwip/etharp.h>
17 #include <lwip/init.h>
18 #include <lwip/prot/etharp.h>
19 #include <lwip/timeouts.h>
20 #include <net.h>
21 #include <timer.h>
22 #include <u-boot/schedule.h>
23
24 /* xx:xx:xx:xx:xx:xx\0 */
25 #define MAC_ADDR_STRLEN 18
26
27 #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
28 void (*push_packet)(void *, int len) = 0;
29 #endif
30 int net_try_count;
31 static int net_restarted;
32 int net_restart_wrap;
33 static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
34 uchar *net_rx_packets[PKTBUFSRX];
35 uchar *net_rx_packet;
36 const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
37 char *pxelinux_configfile;
38 /* Our IP addr (0 = unknown) */
39 struct in_addr net_ip;
40 char net_boot_file_name[1024];
41
net_lwip_tx(struct netif * netif,struct pbuf * p)42 static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
43 {
44 struct udevice *udev = netif->state;
45 void *pp = NULL;
46 int err;
47
48 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
49 printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
50 print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
51 true);
52 }
53
54 if ((unsigned long)p->payload % PKTALIGN) {
55 /*
56 * Some net drivers have strict alignment requirements and may
57 * fail or output invalid data if the packet is not aligned.
58 */
59 pp = memalign(PKTALIGN, p->len);
60 if (!pp)
61 return ERR_ABRT;
62 memcpy(pp, p->payload, p->len);
63 }
64
65 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
66 free(pp);
67 if (err) {
68 debug("send error %d\n", err);
69 return ERR_ABRT;
70 }
71
72 return ERR_OK;
73 }
74
net_lwip_if_init(struct netif * netif)75 static err_t net_lwip_if_init(struct netif *netif)
76 {
77 netif->output = etharp_output;
78 netif->linkoutput = net_lwip_tx;
79 netif->mtu = 1500;
80 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
81
82 return ERR_OK;
83 }
84
eth_init_rings(void)85 static void eth_init_rings(void)
86 {
87 int i;
88
89 for (i = 0; i < PKTBUFSRX; i++)
90 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
91 }
92
net_lwip_get_netif(void)93 struct netif *net_lwip_get_netif(void)
94 {
95 struct netif *netif, *found = NULL;
96
97 NETIF_FOREACH(netif) {
98 if (!found)
99 found = netif;
100 else
101 printf("Error: more than one netif in lwIP\n");
102 }
103 return found;
104 }
105
get_udev_ipv4_info(struct udevice * dev,ip4_addr_t * ip,ip4_addr_t * mask,ip4_addr_t * gw)106 static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
107 ip4_addr_t *mask, ip4_addr_t *gw)
108 {
109 char ipstr[] = "ipaddr\0\0";
110 char maskstr[] = "netmask\0\0";
111 char gwstr[] = "gatewayip\0\0";
112 int idx = dev_seq(dev);
113 char *env;
114
115 if (idx < 0 || idx > 99) {
116 log_err("unexpected idx %d\n", idx);
117 return -1;
118 }
119
120 if (idx) {
121 sprintf(ipstr, "ipaddr%d", idx);
122 sprintf(maskstr, "netmask%d", idx);
123 sprintf(gwstr, "gatewayip%d", idx);
124 }
125
126 ip4_addr_set_zero(ip);
127 ip4_addr_set_zero(mask);
128 ip4_addr_set_zero(gw);
129
130 env = env_get(ipstr);
131 if (env)
132 ip4addr_aton(env, ip);
133
134 env = env_get(maskstr);
135 if (env)
136 ip4addr_aton(env, mask);
137
138 env = env_get(gwstr);
139 if (env)
140 ip4addr_aton(env, gw);
141
142 return 0;
143 }
144
145 /*
146 * Initialize DNS via env
147 */
net_lwip_dns_init(void)148 int net_lwip_dns_init(void)
149 {
150 #if CONFIG_IS_ENABLED(DNS)
151 bool has_server = false;
152 ip_addr_t ns;
153 char *nsenv;
154
155 nsenv = env_get("dnsip");
156 if (nsenv && ipaddr_aton(nsenv, &ns)) {
157 dns_setserver(0, &ns);
158 has_server = true;
159 }
160
161 nsenv = env_get("dnsip2");
162 if (nsenv && ipaddr_aton(nsenv, &ns)) {
163 dns_setserver(1, &ns);
164 has_server = true;
165 }
166
167 if (!has_server) {
168 log_err("No valid name server (dnsip/dnsip2)\n");
169 return -EINVAL;
170 }
171
172 return 0;
173 #else
174 log_err("DNS disabled\n");
175 return -EINVAL;
176 #endif
177 }
178
179 /*
180 * Initialize the network stack if needed and start the current device if valid
181 */
net_lwip_eth_start(void)182 int net_lwip_eth_start(void)
183 {
184 int ret;
185
186 net_init();
187 eth_halt();
188 eth_set_current();
189 ret = eth_init();
190 if (ret < 0) {
191 eth_halt();
192 return ret;
193 }
194
195 return 0;
196 }
197
new_netif(struct udevice * udev,bool with_ip)198 static struct netif *new_netif(struct udevice *udev, bool with_ip)
199 {
200 unsigned char enetaddr[ARP_HLEN];
201 char hwstr[MAC_ADDR_STRLEN];
202 ip4_addr_t ip, mask, gw;
203 struct netif *netif;
204 int ret = 0;
205
206 if (!udev)
207 return NULL;
208
209 if (eth_start_udev(udev) < 0) {
210 log_err("Could not start %s\n", udev->name);
211 return NULL;
212 }
213
214 netif_remove(net_lwip_get_netif());
215
216 ip4_addr_set_zero(&ip);
217 ip4_addr_set_zero(&mask);
218 ip4_addr_set_zero(&gw);
219
220 if (with_ip)
221 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
222 return NULL;
223
224 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
225 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
226 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
227 return NULL;
228
229 netif = calloc(1, sizeof(struct netif));
230 if (!netif)
231 return NULL;
232
233 netif->name[0] = 'e';
234 netif->name[1] = 't';
235
236 string_to_enetaddr(hwstr, netif->hwaddr);
237 netif->hwaddr_len = ETHARP_HWADDR_LEN;
238 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
239 hwstr, ip4addr_ntoa(&ip));
240 debug("mask:%s ", ip4addr_ntoa(&mask));
241 debug("gw:%s\n", ip4addr_ntoa(&gw));
242
243 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
244 netif_input)) {
245 printf("error: netif_add() failed\n");
246 free(netif);
247 return NULL;
248 }
249
250 netif_set_up(netif);
251 netif_set_link_up(netif);
252 /* Routing: use this interface to reach the default gateway */
253 netif_set_default(netif);
254
255 return netif;
256 }
257
net_lwip_new_netif(struct udevice * udev)258 struct netif *net_lwip_new_netif(struct udevice *udev)
259 {
260 return new_netif(udev, true);
261 }
262
net_lwip_new_netif_noip(struct udevice * udev)263 struct netif *net_lwip_new_netif_noip(struct udevice *udev)
264 {
265 return new_netif(udev, false);
266 }
267
net_lwip_remove_netif(struct netif * netif)268 void net_lwip_remove_netif(struct netif *netif)
269 {
270 netif_remove(netif);
271 free(netif);
272 }
273
274 /*
275 * Initialize the network buffers, an ethernet device, and the lwIP stack
276 * (once).
277 */
net_init(void)278 int net_init(void)
279 {
280 static bool init_done;
281
282 if (!init_done) {
283 eth_init_rings();
284 lwip_init();
285 init_done = true;
286 }
287
288 return 0;
289 }
290
alloc_pbuf_and_copy(uchar * data,int len)291 static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
292 {
293 struct pbuf *p, *q;
294
295 /* We allocate a pbuf chain of pbufs from the pool. */
296 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
297 if (!p) {
298 LINK_STATS_INC(link.memerr);
299 LINK_STATS_INC(link.drop);
300 return NULL;
301 }
302
303 for (q = p; q != NULL; q = q->next) {
304 memcpy(q->payload, data, q->len);
305 data += q->len;
306 }
307
308 LINK_STATS_INC(link.recv);
309
310 return p;
311 }
312
net_lwip_rx(struct udevice * udev,struct netif * netif)313 int net_lwip_rx(struct udevice *udev, struct netif *netif)
314 {
315 struct pbuf *pbuf;
316 uchar *packet;
317 int flags;
318 int len;
319 int i;
320
321 /* lwIP timers */
322 sys_check_timeouts();
323 /* Other tasks and actions */
324 schedule();
325
326 if (!eth_is_active(udev))
327 return -EINVAL;
328
329 flags = ETH_RECV_CHECK_DEVICE;
330 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
331 len = eth_get_ops(udev)->recv(udev, flags, &packet);
332 flags = 0;
333
334 if (len > 0) {
335 if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
336 printf("net_lwip_tx: %u bytes, udev %s \n", len,
337 udev->name);
338 print_hex_dump("net_lwip_rx: ", 0, 16, 1,
339 packet, len, true);
340 }
341
342 pbuf = alloc_pbuf_and_copy(packet, len);
343 if (pbuf)
344 netif->input(pbuf, netif);
345 }
346 if (len >= 0 && eth_get_ops(udev)->free_pkt)
347 eth_get_ops(udev)->free_pkt(udev, packet, len);
348 if (len <= 0)
349 break;
350 }
351 if (len == -EAGAIN)
352 len = 0;
353
354 return len;
355 }
356
357 /**
358 * net_lwip_dns_resolve() - find IP address from name or IP
359 *
360 * @name_or_ip: host name or IP address
361 * @ip: output IP address
362 *
363 * Return value: 0 on success, -1 on failure.
364 */
net_lwip_dns_resolve(char * name_or_ip,ip_addr_t * ip)365 int net_lwip_dns_resolve(char *name_or_ip, ip_addr_t *ip)
366 {
367 #if defined(CONFIG_DNS)
368 char *var = "_dnsres";
369 char *argv[] = { "dns", name_or_ip, var, NULL };
370 int argc = ARRAY_SIZE(argv) - 1;
371 #endif
372
373 if (ipaddr_aton(name_or_ip, ip))
374 return 0;
375
376 #if defined(CONFIG_DNS)
377 if (do_dns(NULL, 0, argc, argv) != CMD_RET_SUCCESS)
378 return -1;
379
380 name_or_ip = env_get(var);
381 if (!name_or_ip)
382 return -1;
383
384 if (!ipaddr_aton(name_or_ip, ip))
385 return -1;
386
387 env_set(var, NULL);
388
389 return 0;
390 #else
391 return -1;
392 #endif
393 }
394
net_process_received_packet(uchar * in_packet,int len)395 void net_process_received_packet(uchar *in_packet, int len)
396 {
397 #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
398 if (push_packet)
399 (*push_packet)(in_packet, len);
400 #endif
401 }
402
net_loop(enum proto_t protocol)403 int net_loop(enum proto_t protocol)
404 {
405 char *argv[1];
406
407 switch (protocol) {
408 case TFTPGET:
409 argv[0] = "tftpboot";
410 return do_tftpb(NULL, 0, 1, argv);
411 default:
412 return -EINVAL;
413 }
414
415 return -EINVAL;
416 }
417
sys_now(void)418 u32_t sys_now(void)
419 {
420 #if CONFIG_IS_ENABLED(SANDBOX_TIMER)
421 return timer_early_get_count();
422 #else
423 return get_timer(0);
424 #endif
425 }
426
net_start_again(void)427 int net_start_again(void)
428 {
429 char *nretry;
430 int retry_forever = 0;
431 unsigned long retrycnt = 0;
432
433 nretry = env_get("netretry");
434 if (nretry) {
435 if (!strcmp(nretry, "yes"))
436 retry_forever = 1;
437 else if (!strcmp(nretry, "no"))
438 retrycnt = 0;
439 else if (!strcmp(nretry, "once"))
440 retrycnt = 1;
441 else
442 retrycnt = simple_strtoul(nretry, NULL, 0);
443 } else {
444 retrycnt = 0;
445 retry_forever = 0;
446 }
447
448 if ((!retry_forever) && (net_try_count > retrycnt)) {
449 eth_halt();
450 /*
451 * We don't provide a way for the protocol to return an error,
452 * but this is almost always the reason.
453 */
454 return -ETIMEDOUT;
455 }
456
457 net_try_count++;
458
459 eth_halt();
460 #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
461 eth_try_another(!net_restarted);
462 #endif
463 return eth_init();
464 }
465