blob: 3b08ffe3b74ec424855fa94055d7adbabe72ca74 [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;
31
32static err_t linkoutput(struct netif *netif, struct pbuf *p)
33{
34 struct udevice *udev = netif->state;
35 void *pp = NULL;
36 int err;
37
38 if ((unsigned long)p->payload % PKTALIGN) {
39 /*
40 * Some net drivers have strict alignment requirements and may
41 * fail or output invalid data if the packet is not aligned.
42 */
43 pp = memalign(PKTALIGN, p->len);
44 if (!pp)
45 return ERR_ABRT;
46 memcpy(pp, p->payload, p->len);
47 }
48
49 err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
50 free(pp);
51 if (err) {
52 log_err("send error %d\n", err);
53 return ERR_ABRT;
54 }
55
56 return ERR_OK;
57}
58
59static err_t net_lwip_if_init(struct netif *netif)
60{
61 netif->output = etharp_output;
62 netif->linkoutput = linkoutput;
63 netif->mtu = 1500;
64 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
65
66 return ERR_OK;
67}
68
69static void eth_init_rings(void)
70{
71 int i;
72
73 for (i = 0; i < PKTBUFSRX; i++)
74 net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
75}
76
77struct netif *net_lwip_get_netif(void)
78{
79 struct netif *netif, *found = NULL;
80
81 NETIF_FOREACH(netif) {
82 if (!found)
83 found = netif;
84 else
85 printf("Error: more than one netif in lwIP\n");
86 }
87 return found;
88}
89
90static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
91 ip4_addr_t *mask, ip4_addr_t *gw)
92{
93 char *ipstr = "ipaddr\0\0";
94 char *maskstr = "netmask\0\0";
95 char *gwstr = "gatewayip\0\0";
96 int idx = dev_seq(dev);
97 char *env;
98
99 if (idx < 0 || idx > 99) {
100 log_err("unexpected idx %d\n", idx);
101 return -1;
102 }
103
104 if (idx) {
105 sprintf(ipstr, "ipaddr%d", idx);
106 sprintf(maskstr, "netmask%d", idx);
107 sprintf(gwstr, "gatewayip%d", idx);
108 }
109
110 ip4_addr_set_zero(ip);
111 ip4_addr_set_zero(mask);
112 ip4_addr_set_zero(gw);
113
114 env = env_get(ipstr);
115 if (env)
116 ip4addr_aton(env, ip);
117
118 env = env_get(maskstr);
119 if (env)
120 ip4addr_aton(env, mask);
121
122 env = env_get(gwstr);
123 if (env)
124 ip4addr_aton(env, gw);
125
126 return 0;
127}
128
129static struct netif *new_netif(struct udevice *udev, bool with_ip)
130{
131 unsigned char enetaddr[ARP_HLEN];
132 char hwstr[MAC_ADDR_STRLEN];
133 ip4_addr_t ip, mask, gw;
134 struct netif *netif;
135 int ret = 0;
136 static bool first_call = true;
137
138 if (!udev)
139 return NULL;
140
141 if (first_call) {
142 eth_init_rings();
143 /* Pick a valid active device, if any */
144 eth_init();
145 lwip_init();
146 first_call = false;
147 }
148
149 if (eth_start_udev(udev) < 0) {
150 log_err("Could not start %s\n", udev->name);
151 return NULL;
152 }
153
154 netif_remove(net_lwip_get_netif());
155
156 ip4_addr_set_zero(&ip);
157 ip4_addr_set_zero(&mask);
158 ip4_addr_set_zero(&gw);
159
160 if (with_ip)
161 if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
162 return NULL;
163
164 eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
165 ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
166 if (ret < 0 || ret >= MAC_ADDR_STRLEN)
167 return NULL;
168
169 netif = calloc(1, sizeof(struct netif));
170 if (!netif)
171 return NULL;
172
173 netif->name[0] = 'e';
174 netif->name[1] = 't';
175
176 string_to_enetaddr(hwstr, netif->hwaddr);
177 netif->hwaddr_len = ETHARP_HWADDR_LEN;
178 debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
179 hwstr, ip4addr_ntoa(&ip));
180 debug("mask:%s ", ip4addr_ntoa(&mask));
181 debug("gw:%s\n", ip4addr_ntoa(&gw));
182
183 if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
184 netif_input)) {
185 printf("error: netif_add() failed\n");
186 free(netif);
187 return NULL;
188 }
189
190 netif_set_up(netif);
191 netif_set_link_up(netif);
192 /* Routing: use this interface to reach the default gateway */
193 netif_set_default(netif);
194
195 return netif;
196}
197
198struct netif *net_lwip_new_netif(struct udevice *udev)
199{
200 return new_netif(udev, true);
201}
202
203struct netif *net_lwip_new_netif_noip(struct udevice *udev)
204{
205
206 return new_netif(udev, false);
207}
208
209void net_lwip_remove_netif(struct netif *netif)
210{
211 netif_remove(netif);
212 free(netif);
213}
214
215int net_init(void)
216{
217 eth_set_current();
218
219 net_lwip_new_netif(eth_get_dev());
220
221 return 0;
222}
223
224static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
225{
226 struct pbuf *p, *q;
227
228 /* We allocate a pbuf chain of pbufs from the pool. */
229 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
230 if (!p) {
231 LINK_STATS_INC(link.memerr);
232 LINK_STATS_INC(link.drop);
233 return NULL;
234 }
235
236 for (q = p; q != NULL; q = q->next) {
237 memcpy(q->payload, data, q->len);
238 data += q->len;
239 }
240
241 LINK_STATS_INC(link.recv);
242
243 return p;
244}
245
246int net_lwip_rx(struct udevice *udev, struct netif *netif)
247{
248 struct pbuf *pbuf;
249 uchar *packet;
250 int flags;
251 int len;
252 int i;
253
254 if (!eth_is_active(udev))
255 return -EINVAL;
256
257 flags = ETH_RECV_CHECK_DEVICE;
258 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
259 len = eth_get_ops(udev)->recv(udev, flags, &packet);
260 flags = 0;
261
262 if (len > 0) {
263 pbuf = alloc_pbuf_and_copy(packet, len);
264 if (pbuf)
265 netif->input(pbuf, netif);
266 }
267 if (len >= 0 && eth_get_ops(udev)->free_pkt)
268 eth_get_ops(udev)->free_pkt(udev, packet, len);
269 if (len <= 0)
270 break;
271 }
272 if (len == -EAGAIN)
273 len = 0;
274
275 return len;
276}
277
278void net_process_received_packet(uchar *in_packet, int len)
279{
280#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
281 if (push_packet)
282 (*push_packet)(in_packet, len);
283#endif
284}
285
286u32_t sys_now(void)
287{
288 return get_timer(0);
289}