blob: cab1dd7d483c4d69d7111444c798ca9f98d8cb88 [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>
8#include <lwip/ip4_addr.h>
9#include <lwip/err.h>
10#include <lwip/netif.h>
11#include <lwip/pbuf.h>
12#include <lwip/etharp.h>
13#include <lwip/init.h>
14#include <lwip/prot/etharp.h>
15#include <net.h>
16
17/* xx:xx:xx:xx:xx:xx\0 */
18#define MAC_ADDR_STRLEN 18
19
20#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
21void (*push_packet)(void *, int len) = 0;
22#endif
23int net_restart_wrap;
24static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
25uchar *net_rx_packets[PKTBUFSRX];
26uchar *net_rx_packet;
27const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
28char *pxelinux_configfile;
29/* Our IP addr (0 = unknown) */
30struct in_addr net_ip;
Jerome Forissier6a78e962024-10-16 12:04:05 +020031char net_boot_file_name[1024];
Jerome Forissier1ff00362024-10-16 12:04:03 +020032
33static err_t linkoutput(struct netif *netif, struct pbuf *p)
34{
35 struct udevice *udev = netif->state;
36 void *pp = NULL;
37 int err;
38
39 if ((unsigned long)p->payload % PKTALIGN) {
40 /*
41 * Some net drivers have strict alignment requirements and may
42 * fail or output invalid data if the packet is not aligned.
43 */
44 pp = memalign(PKTALIGN, p->len);
45 if (!pp)
46 return ERR_ABRT;
47 memcpy(pp, p->payload, p->len);
48 }
49
50 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
51 free(pp);
52 if (err) {
53 log_err("send error %d\n", err);
54 return ERR_ABRT;
55 }
56
57 return ERR_OK;
58}
59
60static err_t net_lwip_if_init(struct netif *netif)
61{
62 netif->output = etharp_output;
63 netif->linkoutput = linkoutput;
64 netif->mtu = 1500;
65 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
66
67 return ERR_OK;
68}
69
70static void eth_init_rings(void)
71{
72 int i;
73
74 for (i = 0; i < PKTBUFSRX; i++)
75 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
76}
77
78struct netif *net_lwip_get_netif(void)
79{
80 struct netif *netif, *found = NULL;
81
82 NETIF_FOREACH(netif) {
83 if (!found)
84 found = netif;
85 else
86 printf("Error: more than one netif in lwIP\n");
87 }
88 return found;
89}
90
91static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
92 ip4_addr_t *mask, ip4_addr_t *gw)
93{
Jerome Forissier91596572024-11-18 15:31:25 +010094 char ipstr[] = "ipaddr\0\0";
95 char maskstr[] = "netmask\0\0";
96 char gwstr[] = "gatewayip\0\0";
Jerome Forissier1ff00362024-10-16 12:04:03 +020097 int idx = dev_seq(dev);
98 char *env;
99
100 if (idx < 0 || idx > 99) {
101 log_err("unexpected idx %d\n", idx);
102 return -1;
103 }
104
105 if (idx) {
106 sprintf(ipstr, "ipaddr%d", idx);
107 sprintf(maskstr, "netmask%d", idx);
108 sprintf(gwstr, "gatewayip%d", idx);
109 }
110
111 ip4_addr_set_zero(ip);
112 ip4_addr_set_zero(mask);
113 ip4_addr_set_zero(gw);
114
115 env = env_get(ipstr);
116 if (env)
117 ip4addr_aton(env, ip);
118
119 env = env_get(maskstr);
120 if (env)
121 ip4addr_aton(env, mask);
122
123 env = env_get(gwstr);
124 if (env)
125 ip4addr_aton(env, gw);
126
127 return 0;
128}
129
Jerome Forissier37829282025-01-30 09:22:20 +0100130/* Initialize the lwIP stack and the ethernet devices and set current device */
131void net_lwip_set_current(void)
132{
133 static bool init_done;
134
135 if (!init_done) {
136 eth_init_rings();
137 eth_init();
138 lwip_init();
139 init_done = true;
140 }
141 eth_set_current();
142}
143
Jerome Forissier1ff00362024-10-16 12:04:03 +0200144static struct netif *new_netif(struct udevice *udev, bool with_ip)
145{
146 unsigned char enetaddr[ARP_HLEN];
147 char hwstr[MAC_ADDR_STRLEN];
148 ip4_addr_t ip, mask, gw;
149 struct netif *netif;
150 int ret = 0;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200151
152 if (!udev)
153 return NULL;
154
Jerome Forissier1ff00362024-10-16 12:04:03 +0200155 if (eth_start_udev(udev) < 0) {
156 log_err("Could not start %s\n", udev->name);
157 return NULL;
158 }
159
160 netif_remove(net_lwip_get_netif());
161
162 ip4_addr_set_zero(&ip);
163 ip4_addr_set_zero(&mask);
164 ip4_addr_set_zero(&gw);
165
166 if (with_ip)
167 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
168 return NULL;
169
170 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
171 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
172 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
173 return NULL;
174
175 netif = calloc(1, sizeof(struct netif));
176 if (!netif)
177 return NULL;
178
179 netif->name[0] = 'e';
180 netif->name[1] = 't';
181
182 string_to_enetaddr(hwstr, netif->hwaddr);
183 netif->hwaddr_len = ETHARP_HWADDR_LEN;
184 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
185 hwstr, ip4addr_ntoa(&ip));
186 debug("mask:%s ", ip4addr_ntoa(&mask));
187 debug("gw:%s\n", ip4addr_ntoa(&gw));
188
189 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
190 netif_input)) {
191 printf("error: netif_add() failed\n");
192 free(netif);
193 return NULL;
194 }
195
196 netif_set_up(netif);
197 netif_set_link_up(netif);
198 /* Routing: use this interface to reach the default gateway */
199 netif_set_default(netif);
200
201 return netif;
202}
203
204struct netif *net_lwip_new_netif(struct udevice *udev)
205{
206 return new_netif(udev, true);
207}
208
209struct netif *net_lwip_new_netif_noip(struct udevice *udev)
210{
Jerome Forissier1ff00362024-10-16 12:04:03 +0200211 return new_netif(udev, false);
212}
213
214void net_lwip_remove_netif(struct netif *netif)
215{
216 netif_remove(netif);
217 free(netif);
218}
219
220int net_init(void)
221{
222 eth_set_current();
223
224 net_lwip_new_netif(eth_get_dev());
225
226 return 0;
227}
228
229static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
230{
Jerome Forissier97083502024-11-07 12:27:57 +0100231 struct pbuf *p, *q;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200232
Jerome Forissier97083502024-11-07 12:27:57 +0100233 /* We allocate a pbuf chain of pbufs from the pool. */
234 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
235 if (!p) {
236 LINK_STATS_INC(link.memerr);
237 LINK_STATS_INC(link.drop);
238 return NULL;
239 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200240
Jerome Forissier97083502024-11-07 12:27:57 +0100241 for (q = p; q != NULL; q = q->next) {
242 memcpy(q->payload, data, q->len);
243 data += q->len;
244 }
Jerome Forissier1ff00362024-10-16 12:04:03 +0200245
Jerome Forissier97083502024-11-07 12:27:57 +0100246 LINK_STATS_INC(link.recv);
Jerome Forissier1ff00362024-10-16 12:04:03 +0200247
Jerome Forissier97083502024-11-07 12:27:57 +0100248 return p;
Jerome Forissier1ff00362024-10-16 12:04:03 +0200249}
250
251int net_lwip_rx(struct udevice *udev, struct netif *netif)
252{
253 struct pbuf *pbuf;
254 uchar *packet;
255 int flags;
256 int len;
257 int i;
258
259 if (!eth_is_active(udev))
260 return -EINVAL;
261
262 flags = ETH_RECV_CHECK_DEVICE;
263 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
264 len = eth_get_ops(udev)->recv(udev, flags, &packet);
265 flags = 0;
266
267 if (len > 0) {
268 pbuf = alloc_pbuf_and_copy(packet, len);
269 if (pbuf)
270 netif->input(pbuf, netif);
271 }
272 if (len >= 0 && eth_get_ops(udev)->free_pkt)
273 eth_get_ops(udev)->free_pkt(udev, packet, len);
274 if (len <= 0)
275 break;
276 }
277 if (len == -EAGAIN)
278 len = 0;
279
280 return len;
281}
282
283void net_process_received_packet(uchar *in_packet, int len)
284{
285#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
286 if (push_packet)
287 (*push_packet)(in_packet, len);
288#endif
289}
290
Jerome Forissier6a78e962024-10-16 12:04:05 +0200291int net_loop(enum proto_t protocol)
292{
293 char *argv[1];
294
295 switch (protocol) {
296 case TFTPGET:
297 argv[0] = "tftpboot";
298 return do_tftpb(NULL, 0, 1, argv);
299 default:
300 return -EINVAL;
301 }
302
303 return -EINVAL;
304}
305
Jerome Forissier1ff00362024-10-16 12:04:03 +0200306u32_t sys_now(void)
307{
308 return get_timer(0);
309}