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