]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
net: lwip: add DHCP support and dhcp commmand
authorJerome Forissier <jerome.forissier@linaro.org>
Wed, 16 Oct 2024 10:04:03 +0000 (12:04 +0200)
committerTom Rini <trini@konsulko.com>
Wed, 16 Oct 2024 17:11:56 +0000 (11:11 -0600)
Add what it takes to enable NETDEVICES with NET_LWIP and enable DHCP as
well as the dhcp command. CMD_TFTPBOOT is selected by BOOTMETH_EFI due
to this code having an implicit dependency on do_tftpb().

Note that PXE is likely non-fonctional with NET_LWIP (or at least not
100% functional) because DHCP option 209 is not supported by the lwIP
library. Therefore, BOOTP_PXE_DHCP_OPTION cannot be enabled.

Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
21 files changed:
board/engicam/imx8mp/icore_mx8mp.c
board/polyhex/imx8mp_debix_model_a/imx8mp_debix_model_a.c
board/ti/am335x/board.c
board/xilinx/common/board.c
cmd/Kconfig
cmd/Makefile
cmd/elf.c
cmd/net-lwip.c [new file with mode: 0644]
common/board_r.c
common/usb_kbd.c
drivers/net/Kconfig
include/net-common.h
include/net-legacy.h
include/net-lwip.h
lib/tiny-printf.c
net/Makefile
net/lwip/Makefile [new file with mode: 0644]
net/lwip/dhcp.c [new file with mode: 0644]
net/lwip/eth_internal.h [new file with mode: 0644]
net/lwip/net-lwip.c [new file with mode: 0644]
net/lwip/tftp.c [new file with mode: 0644]

index e2ed70caa43a60a49c5c16fcff40464cd7d3b3e7..bfdc447c4784f7a8e73900a284b83fc9b301e503 100644 (file)
@@ -33,7 +33,7 @@ static void setup_fec(void)
        setbits_le32(&gpr->gpr[1], BIT(22));
 }
 
-#if CONFIG_IS_ENABLED(NET)
+#if CONFIG_IS_ENABLED(NET) || CONFIG_IS_ENABLED(NET_LWIP)
 int board_phy_config(struct phy_device *phydev)
 {
        if (phydev->drv->config)
index 112770ba493100f60effa0e5e3dac2867984e7e1..c709d01748315a0f45712574f773df274caa2a4f 100644 (file)
@@ -29,7 +29,7 @@ static void setup_fec(void)
        setbits_le32(&gpr->gpr[1], BIT(22));
 }
 
-#if CONFIG_IS_ENABLED(NET)
+#if CONFIG_IS_ENABLED(NET) || CONFIG_IS_ENABLED(NET_LWIP)
 int board_phy_config(struct phy_device *phydev)
 {
        if (phydev->drv->config)
index 720bf2cb3e1ccdd0824c7c3f55da017e652ae483..774ef7ac5e381c664b960444ade151a7d781d239 100644 (file)
@@ -900,7 +900,8 @@ int board_late_init(void)
 #endif
 
 /* CPSW plat */
-#if CONFIG_IS_ENABLED(NET) && !CONFIG_IS_ENABLED(OF_CONTROL)
+#if (CONFIG_IS_ENABLED(NET) || CONFIG_IS_ENABLED(NET_LWIP)) && \
+    !CONFIG_IS_ENABLED(OF_CONTROL)
 struct cpsw_slave_data slave_data[] = {
        {
                .slave_reg_ofs  = CPSW_SLAVE0_OFFSET,
index 68f401e4b348df57b74dbc6be3e0ccdbe523f68d..38dd80533fa8741ecf6ceb1cef84f53edcb8fb67 100644 (file)
@@ -491,7 +491,8 @@ int board_late_init_xilinx(void)
                                ret |= env_set_by_index("uuid", id, uuid);
                        }
 
-                       if (!CONFIG_IS_ENABLED(NET))
+                       if (!(CONFIG_IS_ENABLED(NET) ||
+                             CONFIG_IS_ENABLED(NET_LWIP)))
                                continue;
 
                        for (i = 0; i < EEPROM_HDR_NO_OF_MAC_ADDR; i++) {
index 6d20d7597cb0e14c82a1efef89e8a6af26353146..211be398937fb5ab60ec18bc57b9914b566f9c9f 100644 (file)
@@ -1789,12 +1789,16 @@ config CMD_AB_SELECT
 
 endmenu
 
-if NET
+if NET || NET_LWIP
 
 menuconfig CMD_NET
        bool "Network commands"
        default y
 
+endif
+
+if NET
+
 if CMD_NET
 
 config CMD_BOOTP
@@ -1803,12 +1807,6 @@ config CMD_BOOTP
        help
          bootp - boot image via network using BOOTP/TFTP protocol
 
-config CMD_DHCP
-       bool "dhcp"
-       depends on CMD_BOOTP
-       help
-         Boot image via network using DHCP/TFTP protocol
-
 config CMD_DHCP6
        bool "dhcp6"
        depends on IPV6
@@ -1952,12 +1950,6 @@ config BOOTP_VCI_STRING
        default "U-Boot.arm" if ARM
        default "U-Boot"
 
-config CMD_TFTPBOOT
-       bool "tftpboot"
-       default y
-       help
-         tftpboot - load file via network using TFTP protocol
-
 config CMD_TFTPPUT
        bool "tftp put"
        depends on CMD_TFTPBOOT
@@ -2017,29 +2009,6 @@ config CMD_WGET
          wget is a simple command to download kernel, or other files,
          from a http server over TCP.
 
-config CMD_MII
-       bool "mii"
-       imply CMD_MDIO
-       help
-         If set, allows 802.3(clause 22) MII Management functions interface access
-         The management interface specified in Clause 22 provides
-         a simple, two signal, serial interface to connect a
-         Station Management entity and a managed PHY for providing access
-         to management parameters and services.
-         The interface is referred to as the MII management interface.
-
-config MII_INIT
-       bool "Call mii_init() in the mii command"
-       depends on CMD_MII && (MPC8XX_FEC || FSLDMAFE || MCFFEC)
-
-config CMD_MDIO
-       bool "mdio"
-       depends on PHYLIB
-       help
-         If set, allows Enable 802.3(clause 45) MDIO interface registers access
-         The MDIO interface is orthogonal to the MII interface and extends
-         it by adding access to more registers through indirect addressing.
-
 config CMD_PING
        bool "ping"
        help
@@ -2088,7 +2057,7 @@ config IPV6_ROUTER_DISCOVERY
        help
          Will automatically perform router solicitation on first IPv6
          network operation
-endif
+endif  # if CMD_NET
 
 config CMD_ETHSW
        bool "ethsw"
@@ -2098,6 +2067,56 @@ config CMD_ETHSW
          operations such as enabling / disabling a port and
          viewing/maintaining the filtering database (FDB)
 
+config CMD_WOL
+       bool "wol"
+       help
+         Wait for wake-on-lan Magic Packet
+
+endif  # if NET
+
+if NET || NET_LWIP
+
+if CMD_NET
+
+config CMD_DHCP
+       bool "dhcp"
+       select PROT_DHCP_LWIP if NET_LWIP
+       help
+         Boot image via network using DHCP/TFTP protocol
+
+config CMD_MII
+       bool "mii"
+       imply CMD_MDIO
+       help
+         If set, allows 802.3(clause 22) MII Management functions interface access
+         The management interface specified in Clause 22 provides
+         a simple, two signal, serial interface to connect a
+         Station Management entity and a managed PHY for providing access
+         to management parameters and services.
+         The interface is referred to as the MII management interface.
+
+config MII_INIT
+       bool "Call mii_init() in the mii command"
+       depends on CMD_MII && (MPC8XX_FEC || FSLDMAFE || MCFFEC)
+
+config CMD_MDIO
+       bool "mdio"
+       depends on PHYLIB
+       help
+         If set, allows Enable 802.3(clause 45) MDIO interface registers access
+         The MDIO interface is orthogonal to the MII interface and extends
+         it by adding access to more registers through indirect addressing.
+
+config CMD_TFTPBOOT
+       bool "tftp"
+       select PROT_UDP_LWIP if NET_LWIP
+       default n
+       help
+         tftpboot - load file via network using TFTP protocol
+         Currently a placeholder (not implemented) when NET_LWIP=y.
+
+endif  # if CMD_NET
+
 config CMD_PXE
        bool "pxe"
        select PXE_UTILS
@@ -2105,12 +2124,7 @@ config CMD_PXE
        help
          Boot image via network using PXE protocol
 
-config CMD_WOL
-       bool "wol"
-       help
-         Wait for wake-on-lan Magic Packet
-
-endif
+endif  # if NET || NET_LWIP
 
 menu "Misc commands"
 
index 21d376309b964fe953ed8e5775a1d707df3207f5..94a3df41c6fc375a276436237f09bf8f42dc8503 100644 (file)
@@ -127,7 +127,11 @@ obj-y += legacy-mtd-utils.o
 endif
 obj-$(CONFIG_CMD_MUX) += mux.o
 obj-$(CONFIG_CMD_NAND) += nand.o
-obj-$(CONFIG_CMD_NET) += net.o
+ifdef CONFIG_CMD_NET
+obj-$(CONFIG_NET) += net.o
+obj-$(CONFIG_NET_LWIP) += net-lwip.o
+CFLAGS_net-lwip.o := -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot
+endif
 obj-$(CONFIG_ENV_SUPPORT) += nvedit.o
 obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o
 obj-$(CONFIG_CMD_ONENAND) += onenand.o
index 114f2caf7fab6607f297fc22c92981df4e607f83..6b49c613703ee0ecb68c62f24c6ebddccbb92743 100644 (file)
--- a/cmd/elf.c
+++ b/cmd/elf.c
@@ -133,7 +133,7 @@ int do_bootvx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
        else
                addr = hextoul(argv[1], NULL);
 
-#if defined(CONFIG_CMD_NET)
+#if defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_LWIP)
        /*
         * Check to see if we need to tftp the image ourselves
         * before starting
diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c
new file mode 100644 (file)
index 0000000..82edb5f
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <net.h>
+
+#if defined(CONFIG_CMD_DHCP)
+U_BOOT_CMD(
+        dhcp,   3,      1,      do_dhcp,
+        "boot image via network using DHCP/TFTP protocol",
+        "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+#endif
index 1acad069d929b045625778a3ebbd0dc60776e1f3..e5f33f40643b771121edf819dd4f617a98d08ad9 100644 (file)
@@ -484,7 +484,7 @@ static int initr_boot_led_on(void)
        return 0;
 }
 
-#ifdef CONFIG_CMD_NET
+#if defined(CONFIG_CMD_NET)
 static int initr_net(void)
 {
        puts("Net:   ");
@@ -749,7 +749,7 @@ static init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_PCI_ENDPOINT
        pci_ep_init,
 #endif
-#ifdef CONFIG_CMD_NET
+#if defined(CONFIG_CMD_NET)
        INIT_FUNC_WATCHDOG_RESET
        initr_net,
 #endif
index bbfee23bc2698d989e3d49efcc0f452f502e6a07..36107a3b27861ff0ee03229333fdf5f1d852c699 100644 (file)
@@ -423,7 +423,7 @@ static int usb_kbd_testc(struct stdio_dev *sdev)
         */
        unsigned long poll_delay = CONFIG_SYS_HZ / 50;
 
-#ifdef CONFIG_CMD_NET
+#if defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_LWIP)
        /*
         * If net_busy_flag is 1, NET transfer is running,
         * then we check key-pressed every second (first check may be
index fa6fc1cb8e497918e9486b964b60ac044a87dadc..89f7411bdf336d64f8cddadc3f8c077f48481455 100644 (file)
@@ -97,7 +97,7 @@ config DSA_SANDBOX
 
 menuconfig NETDEVICES
        bool "Network device support"
-       depends on NET
+       depends on NET || NET_LWIP
        select DM_ETH
        help
          You must select Y to enable any network device support
index 6bc76658d9d6ad003f480687f10329169d692d6f..cbcac178c82bf85ff5724155b3655666e945849c 100644 (file)
@@ -118,6 +118,9 @@ extern int          net_restart_wrap;       /* Tried all network devices */
 extern uchar               *net_rx_packets[PKTBUFSRX]; /* Receive packets */
 extern const u8                net_bcast_ethaddr[ARP_HLEN];    /* Ethernet broadcast address */
 extern char    net_boot_file_name[1024];/* Boot File name */
+extern struct in_addr  net_ip;         /* Our    IP addr (0 = unknown) */
+/* Indicates whether the pxe path prefix / config file was specified in dhcp option */
+extern char *pxelinux_configfile;
 
 /**
  * compute_ip_checksum() - Compute IP checksum
index ed286e3d32605a93144d83c8e1ca962d31b77a25..ca1efd17af7daff89e89ccf2d64efe50bf500774 100644 (file)
@@ -285,12 +285,9 @@ extern char        net_hostname[32];       /* Our hostname */
 #ifdef CONFIG_NET
 extern char    net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN];  /* Our root path */
 #endif
-/* Indicates whether the pxe path prefix / config file was specified in dhcp option */
-extern char *pxelinux_configfile;
 /** END OF BOOTP EXTENTIONS **/
 extern u8              net_ethaddr[ARP_HLEN];          /* Our ethernet address */
 extern u8              net_server_ethaddr[ARP_HLEN];   /* Boot server enet address */
-extern struct in_addr  net_ip;         /* Our    IP addr (0 = unknown) */
 extern struct in_addr  net_server_ip;  /* Server IP addr (0 = unknown) */
 extern uchar           *net_tx_packet;         /* THE transmit packet */
 extern uchar           *net_rx_packets[PKTBUFSRX]; /* Receive packets */
index 5c3f9e7e86c0904d0845a529b647813be5f56c07..cfd0672657734cd0b622cd2419ec43eafdbef436 100644 (file)
@@ -10,5 +10,8 @@ struct netif *net_lwip_new_netif(struct udevice *udev);
 struct netif *net_lwip_new_netif_noip(struct udevice *udev);
 void net_lwip_remove_netif(struct netif *netif);
 struct netif *net_lwip_get_netif(void);
+int net_lwip_rx(struct udevice *udev, struct netif *netif);
+
+int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 
 #endif /* __NET_LWIP_H__ */
index 64dee779c4a265fed9a9768e8ec3cb94f3601b02..cc1dfe61cf7916d01faed95f8c7c0c34fed700bd 100644 (file)
@@ -269,7 +269,8 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va)
                                }
                                break;
                        case 'p':
-                               if (CONFIG_IS_ENABLED(NET) || _DEBUG) {
+                               if (CONFIG_IS_ENABLED(NET) ||
+                                   CONFIG_IS_ENABLED(NET_LWIP) || _DEBUG) {
                                        pointer(info, fmt, va_arg(va, void *));
                                        /*
                                         * Skip this because it pulls in _ctype which is
index 34fe50133a325b27f96eaa62b2403fb1fa4ac3d7..209377aeb262449e34763e601d6565aa957f7b25 100644 (file)
@@ -12,11 +12,6 @@ obj-$(CONFIG_CMD_BOOTP) += bootp.o
 obj-$(CONFIG_CMD_CDP)  += cdp.o
 obj-$(CONFIG_CMD_DNS)  += dns.o
 obj-$(CONFIG_DM_DSA)   += dsa-uclass.o
-obj-$(CONFIG_$(XPL_)DM_ETH) += eth-uclass.o
-obj-$(CONFIG_$(PHASE_)BOOTDEV_ETH) += eth_bootdev.o
-obj-$(CONFIG_DM_MDIO)  += mdio-uclass.o
-obj-$(CONFIG_DM_MDIO_MUX) += mdio-mux-uclass.o
-obj-$(CONFIG_$(XPL_)DM_ETH) += eth_common.o
 obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
 obj-$(CONFIG_IPV6)     += ndisc.o
 obj-$(CONFIG_$(XPL_)DM_ETH) += net.o
@@ -43,4 +38,13 @@ CFLAGS_eth_common.o += -Wno-format-extra-args
 
 endif
 
+ifeq ($(filter y,$(CONFIG_NET) $(CONFIG_NET_LWIP)),y)
+obj-$(CONFIG_$(XPL_)DM_ETH) += eth-uclass.o
+obj-$(CONFIG_$(PHASE_)BOOTDEV_ETH) += eth_bootdev.o
+obj-$(CONFIG_DM_MDIO)  += mdio-uclass.o
+obj-$(CONFIG_DM_MDIO_MUX) += mdio-mux-uclass.o
+obj-$(CONFIG_$(XPL_)DM_ETH) += eth_common.o
 obj-y += net-common.o
+endif
+
+obj-$(CONFIG_NET_LWIP) += lwip/
diff --git a/net/lwip/Makefile b/net/lwip/Makefile
new file mode 100644 (file)
index 0000000..4e92a10
--- /dev/null
@@ -0,0 +1,5 @@
+ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot
+
+obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o
+obj-$(CONFIG_CMD_DHCP) += dhcp.o
+obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c
new file mode 100644 (file)
index 0000000..a2cc25d
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <console.h>
+#include <dm/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <lwip/dhcp.h>
+#include <lwip/dns.h>
+#include <lwip/timeouts.h>
+#include <net.h>
+#include <time.h>
+
+#define DHCP_TIMEOUT_MS 10000
+
+#ifdef CONFIG_CMD_TFTPBOOT
+/* Boot file obtained from DHCP (if present) */
+static char boot_file_name[DHCP_BOOT_FILE_LEN];
+#endif
+
+static void call_lwip_dhcp_fine_tmr(void *ctx)
+{
+       dhcp_fine_tmr();
+       sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
+}
+
+static int dhcp_loop(struct udevice *udev)
+{
+       char *ipstr = "ipaddr\0\0";
+       char *maskstr = "netmask\0\0";
+       char *gwstr = "gatewayip\0\0";
+       unsigned long start;
+       struct netif *netif;
+       struct dhcp *dhcp;
+       bool bound;
+       int idx;
+
+       idx = dev_seq(udev);
+       if (idx < 0 || idx > 99) {
+               log_err("unexpected idx %d\n", idx);
+               return CMD_RET_FAILURE;
+       }
+
+       netif = net_lwip_new_netif_noip(udev);
+       if (!netif)
+               return CMD_RET_FAILURE;
+
+       start = get_timer(0);
+
+       if (dhcp_start(netif))
+               return CMD_RET_FAILURE;
+
+       call_lwip_dhcp_fine_tmr(NULL);
+
+       /* Wait for DHCP to complete */
+       do {
+               net_lwip_rx(udev, netif);
+               sys_check_timeouts();
+               bound = dhcp_supplied_address(netif);
+               if (bound)
+                       break;
+               if (ctrlc()) {
+                       printf("Abort\n");
+                       break;
+               }
+               mdelay(1);
+       } while (get_timer(start) < DHCP_TIMEOUT_MS);
+
+       sys_untimeout(call_lwip_dhcp_fine_tmr, NULL);
+
+       if (!bound) {
+               net_lwip_remove_netif(netif);
+               return CMD_RET_FAILURE;
+       }
+
+       dhcp = netif_dhcp_data(netif);
+
+       env_set("bootfile", dhcp->boot_file_name);
+
+       if (idx > 0) {
+               sprintf(ipstr, "ipaddr%d", idx);
+               sprintf(maskstr, "netmask%d", idx);
+               sprintf(gwstr, "gatewayip%d", idx);
+       } else {
+               net_ip.s_addr = dhcp->offered_ip_addr.addr;
+       }
+
+       env_set(ipstr, ip4addr_ntoa(&dhcp->offered_ip_addr));
+       env_set(maskstr, ip4addr_ntoa(&dhcp->offered_sn_mask));
+       env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
+       if (dhcp->offered_gw_addr.addr != 0)
+               env_set(gwstr, ip4addr_ntoa(&dhcp->offered_gw_addr));
+
+#ifdef CONFIG_PROT_DNS_LWIP
+       env_set("dnsip", ip4addr_ntoa(dns_getserver(0)));
+       env_set("dnsip2", ip4addr_ntoa(dns_getserver(1)));
+#endif
+#ifdef CONFIG_CMD_TFTPBOOT
+       if (dhcp->boot_file_name[0] != '\0')
+               strncpy(boot_file_name, dhcp->boot_file_name,
+                       sizeof(boot_file_name));
+#endif
+
+       printf("DHCP client bound to address %pI4 (%lu ms)\n",
+              &dhcp->offered_ip_addr, get_timer(start));
+
+       net_lwip_remove_netif(netif);
+       return CMD_RET_SUCCESS;
+}
+
+int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+       eth_set_current();
+
+       return dhcp_loop(eth_get_dev());
+}
+
+int dhcp_run(ulong addr, const char *fname, bool autoload)
+{
+       char *dhcp_argv[] = {"dhcp", NULL, };
+       struct cmd_tbl cmdtp = {};      /* dummy */
+
+       if (autoload) {
+               /* Will be supported when TFTP is added */
+               return -EOPNOTSUPP;
+       }
+
+       return do_dhcp(&cmdtp, 0, 1, dhcp_argv);
+}
diff --git a/net/lwip/eth_internal.h b/net/lwip/eth_internal.h
new file mode 100644 (file)
index 0000000..0b829a8
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ */
+
+#ifndef __ETH_INTERNAL_H
+#define __ETH_INTERNAL_H
+
+/* Do init that is common to driver model and legacy networking */
+void eth_common_init(void);
+
+/**
+ * eth_env_set_enetaddr_by_index() - set the MAC address environment variable
+ *
+ * This sets up an environment variable with the given MAC address (@enetaddr).
+ * The environment variable to be set is defined by <@base_name><@index>addr.
+ * If @index is 0 it is omitted. For common Ethernet this means ethaddr,
+ * eth1addr, etc.
+ *
+ * @base_name: Base name for variable, typically "eth"
+ * @index:     Index of interface being updated (>=0)
+ * @enetaddr:  Pointer to MAC address to put into the variable
+ * Return: 0 if OK, other value on error
+ */
+int eth_env_set_enetaddr_by_index(const char *base_name, int index,
+                                uchar *enetaddr);
+
+int eth_mac_skip(int index);
+void eth_current_changed(void);
+void eth_set_dev(struct udevice *dev);
+void eth_set_current_to_next(void);
+
+#endif
diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c
new file mode 100644 (file)
index 0000000..3b08ffe
--- /dev/null
@@ -0,0 +1,289 @@
+// 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/init.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;
+const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+char *pxelinux_configfile;
+/* Our IP addr (0 = unknown) */
+struct in_addr net_ip;
+
+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)
+{
+       netif->output = etharp_output;
+       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)
+{
+       int i;
+
+       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;
+       static bool first_call = true;
+
+       if (!udev)
+               return NULL;
+
+       if (first_call) {
+               eth_init_rings();
+               /* Pick a valid active device, if any */
+               eth_init();
+               lwip_init();
+               first_call = false;
+       }
+
+       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) {
+                       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)
+{
+#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
+       if (push_packet)
+               (*push_packet)(in_packet, len);
+#endif
+}
+
+u32_t sys_now(void)
+{
+       return get_timer(0);
+}
diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c
new file mode 100644 (file)
index 0000000..1fa246f
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <net-lwip.h>
+
+int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+       /* Not implemented */
+       return CMD_RET_FAILURE;
+}