aboutsummaryrefslogtreecommitdiffstats
path: root/net/lwip/net-lwip.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/lwip/net-lwip.c')
-rw-r--r--net/lwip/net-lwip.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c
new file mode 100644
index 00000000000..e258d3df3ef
--- /dev/null
+++ b/net/lwip/net-lwip.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <lwip/ip4_addr.h>
+#include <lwip/err.h>
+#include <lwip/netif.h>
+#include <lwip/pbuf.h>
+#include <lwip/etharp.h>
+#include <lwip/prot/etharp.h>
+#include <net.h>
+
+/* xx:xx:xx:xx:xx:xx\0 */
+#define MAC_ADDR_STRLEN 18
+
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
+void (*push_packet)(void *, int len) = 0;
+#endif
+int net_restart_wrap;
+static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
+uchar *net_rx_packets[PKTBUFSRX];
+uchar *net_rx_packet;
+
+static err_t linkoutput(struct netif *netif, struct pbuf *p)
+{
+ struct udevice *udev = netif->state;
+ void *pp = NULL;
+ int err;
+
+ if ((unsigned long)p->payload % PKTALIGN) {
+ /*
+ * Some net drivers have strict alignment requirements and may
+ * fail or output invalid data if the packet is not aligned.
+ */
+ pp = memalign(PKTALIGN, p->len);
+ if (!pp)
+ return ERR_ABRT;
+ memcpy(pp, p->payload, p->len);
+ }
+
+ err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
+ free(pp);
+ if (err) {
+ log_err("send error %d\n", err);
+ return ERR_ABRT;
+ }
+
+ return ERR_OK;
+}
+
+static err_t net_lwip_if_init(struct netif *netif)
+{
+#if LWIP_IPV4
+ netif->output = etharp_output;
+#endif
+ netif->linkoutput = linkoutput;
+ netif->mtu = 1500;
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
+
+ return ERR_OK;
+}
+
+static void eth_init_rings(void)
+{
+ static bool called;
+ int i;
+
+ if (called)
+ return;
+ called = true;
+
+ for (i = 0; i < PKTBUFSRX; i++)
+ net_rx_packets[i] = net_pkt_buf + i * PKTSIZE_ALIGN;
+}
+
+struct netif *net_lwip_get_netif(void)
+{
+ struct netif *netif, *found = NULL;
+
+ NETIF_FOREACH(netif) {
+ if (!found)
+ found = netif;
+ else
+ printf("Error: more than one netif in lwIP\n");
+ }
+ return found;
+}
+
+static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
+ ip4_addr_t *mask, ip4_addr_t *gw)
+{
+ char *ipstr = "ipaddr\0\0";
+ char *maskstr = "netmask\0\0";
+ char *gwstr = "gatewayip\0\0";
+ int idx = dev_seq(dev);
+ char *env;
+
+ if (idx < 0 || idx > 99) {
+ log_err("unexpected idx %d\n", idx);
+ return -1;
+ }
+
+ if (idx) {
+ sprintf(ipstr, "ipaddr%d", idx);
+ sprintf(maskstr, "netmask%d", idx);
+ sprintf(gwstr, "gatewayip%d", idx);
+ }
+
+ ip4_addr_set_zero(ip);
+ ip4_addr_set_zero(mask);
+ ip4_addr_set_zero(gw);
+
+ env = env_get(ipstr);
+ if (env)
+ ip4addr_aton(env, ip);
+
+ env = env_get(maskstr);
+ if (env)
+ ip4addr_aton(env, mask);
+
+ env = env_get(gwstr);
+ if (env)
+ ip4addr_aton(env, gw);
+
+ return 0;
+}
+
+static struct netif *new_netif(struct udevice *udev, bool with_ip)
+{
+ unsigned char enetaddr[ARP_HLEN];
+ char hwstr[MAC_ADDR_STRLEN];
+ ip4_addr_t ip, mask, gw;
+ struct netif *netif;
+ int ret = 0;
+ bool first_call = true;
+
+ if (!udev)
+ return NULL;
+
+ if (first_call) {
+ /* Pick a valid active device, if any */
+ eth_init();
+ first_call = false;
+ }
+
+ eth_init_rings();
+
+ if (eth_start_udev(udev) < 0) {
+ log_err("Could not start %s\n", udev->name);
+ return NULL;
+ }
+
+ netif_remove(net_lwip_get_netif());
+
+ ip4_addr_set_zero(&ip);
+ ip4_addr_set_zero(&mask);
+ ip4_addr_set_zero(&gw);
+
+ if (with_ip)
+ if (get_udev_ipv4_info(udev, &ip, &mask, &gw) < 0)
+ return NULL;
+
+ eth_env_get_enetaddr_by_index("eth", dev_seq(udev), enetaddr);
+ ret = snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", enetaddr);
+ if (ret < 0 || ret >= MAC_ADDR_STRLEN)
+ return NULL;
+
+ netif = calloc(1, sizeof(struct netif));
+ if (!netif)
+ return NULL;
+
+ netif->name[0] = 'e';
+ netif->name[1] = 't';
+
+ string_to_enetaddr(hwstr, netif->hwaddr);
+ netif->hwaddr_len = ETHARP_HWADDR_LEN;
+ debug("adding lwIP netif for %s with hwaddr:%s ip:%s ", udev->name,
+ hwstr, ip4addr_ntoa(&ip));
+ debug("mask:%s ", ip4addr_ntoa(&mask));
+ debug("gw:%s\n", ip4addr_ntoa(&gw));
+
+ if (!netif_add(netif, &ip, &mask, &gw, udev, net_lwip_if_init,
+ netif_input)) {
+ printf("error: netif_add() failed\n");
+ free(netif);
+ return NULL;
+ }
+
+ netif_set_up(netif);
+ netif_set_link_up(netif);
+ /* Routing: use this interface to reach the default gateway */
+ netif_set_default(netif);
+
+ return netif;
+}
+
+struct netif *net_lwip_new_netif(struct udevice *udev)
+{
+ return new_netif(udev, true);
+}
+
+struct netif *net_lwip_new_netif_noip(struct udevice *udev)
+{
+
+ return new_netif(udev, false);
+}
+
+void net_lwip_remove_netif(struct netif *netif)
+{
+ netif_remove(netif);
+ free(netif);
+}
+
+int net_init(void)
+{
+ eth_set_current();
+
+ net_lwip_new_netif(eth_get_dev());
+
+ return 0;
+}
+
+static struct pbuf *alloc_pbuf_and_copy(uchar *data, int len)
+{
+ struct pbuf *p, *q;
+
+ /* We allocate a pbuf chain of pbufs from the pool. */
+ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+ if (!p) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ return NULL;
+ }
+
+ for (q = p; q != NULL; q = q->next) {
+ memcpy(q->payload, data, q->len);
+ data += q->len;
+ }
+
+ LINK_STATS_INC(link.recv);
+
+ return p;
+}
+
+int net_lwip_rx(struct udevice *udev, struct netif *netif)
+{
+ struct pbuf *pbuf;
+ uchar *packet;
+ int flags;
+ int len;
+ int i;
+
+ if (!eth_is_active(udev))
+ return -EINVAL;
+
+ flags = ETH_RECV_CHECK_DEVICE;
+ for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
+ len = eth_get_ops(udev)->recv(udev, flags, &packet);
+ flags = 0;
+
+ if (len > 0) {
+
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
+ if (push_packet)
+ (*push_packet)(packet, len);
+#endif
+ pbuf = alloc_pbuf_and_copy(packet, len);
+ if (pbuf)
+ netif->input(pbuf, netif);
+ }
+ if (len >= 0 && eth_get_ops(udev)->free_pkt)
+ eth_get_ops(udev)->free_pkt(udev, packet, len);
+ if (len <= 0)
+ break;
+ }
+ if (len == -EAGAIN)
+ len = 0;
+
+ return len;
+}
+
+void net_process_received_packet(uchar *in_packet, int len)
+{
+}
+
+u32_t sys_now(void)
+{
+ return get_timer(0);
+}