Message ID | 1455663bf6d4f8537d3919b755ef5148b65975c5.1718638104.git.jerome.forissier@linaro.org |
---|---|
State | New |
Headers | show |
Series | Introduce the lwIP network stack | expand |
On 17.06.24 17:32, Jerome Forissier wrote: > 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(). > > Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org> > --- > Makefile | 6 + > boot/Kconfig | 3 +- > cmd/Kconfig | 26 ++++ > cmd/Makefile | 4 + > cmd/net-lwip.c | 13 ++ > common/board_r.c | 4 +- > drivers/net/Kconfig | 2 +- > include/net-lwip.h | 2 + > net-lwip/Makefile | 15 +++ > net-lwip/dhcp.c | 99 +++++++++++++++ > net-lwip/eth_internal.h | 35 ++++++ > net-lwip/net-lwip.c | 270 ++++++++++++++++++++++++++++++++++++++++ > net-lwip/tftp.c | 11 ++ > 13 files changed, 486 insertions(+), 4 deletions(-) > create mode 100644 cmd/net-lwip.c > create mode 100644 net-lwip/Makefile > create mode 100644 net-lwip/dhcp.c > create mode 100644 net-lwip/eth_internal.h > create mode 100644 net-lwip/net-lwip.c > create mode 100644 net-lwip/tftp.c > > diff --git a/Makefile b/Makefile > index 0fe1623c550..92a0ab770bb 100644 > --- a/Makefile > +++ b/Makefile > @@ -862,6 +862,7 @@ libs-y += env/ > libs-y += lib/ > libs-y += fs/ > libs-$(CONFIG_NET) += net/ > +libs-$(CONFIG_NET_LWIP) += net-lwip/ > libs-y += disk/ > libs-y += drivers/ > libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/ > @@ -2132,6 +2133,11 @@ etags: > cscope: > $(FIND) $(FINDFLAGS) $(TAG_SUBDIRS) -name '*.[chS]' -print > \ > cscope.files > +ifdef CONFIG_NET_LWIP > + echo net/eth-uclass.c net/eth_common.c net/eth_bootdev.c \ > + net/mdio-uclass.c net/mdio-mux-uclass.c >> \ > + cscope.files > +endif > @find $(TAG_SUBDIRS) -name '*.[chS]' -type l -print | \ > grep -xvf - cscope.files > cscope.files.no-symlinks; \ > mv cscope.files.no-symlinks cscope.files > diff --git a/boot/Kconfig b/boot/Kconfig > index 6f3096c15a6..004e69dd92a 100644 > --- a/boot/Kconfig > +++ b/boot/Kconfig > @@ -378,7 +378,7 @@ config BOOT_DEFAULTS_CMDS > select CMD_FAT > select CMD_FS_GENERIC > select CMD_PART if PARTITIONS > - select CMD_DHCP if CMD_NET > + select CMD_DHCP if CMD_NET || CMD_NET_LWIP > select CMD_PING if CMD_NET > select CMD_PXE if CMD_NET > select CMD_BOOTI if ARM64 > @@ -540,6 +540,7 @@ config BOOTMETH_EXTLINUX_PXE > config BOOTMETH_EFILOADER > bool "Bootdev support for EFI boot" > depends on EFI_BINARY_EXEC > + select CMD_TFTPBOOT if CMD_NET_LWIP > default y > help > Enables support for EFI boot using bootdevs. This makes the > diff --git a/cmd/Kconfig b/cmd/Kconfig > index b026439c773..1bfa528e945 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -2084,6 +2084,32 @@ config CMD_WOL > > endif > > +if NET_LWIP > + > +menuconfig CMD_NET_LWIP > + bool "Network commands (lwIP)" > + default y > + > +if CMD_NET_LWIP > + > +config CMD_DHCP > + bool "dhcp" > + select PROT_DHCP_LWIP > + help > + Boot image via network using DHCP/TFTP protocol > + > +config CMD_TFTPBOOT > + bool "tftp" > + select PROT_UDP_LWIP > + default n > + help > + tftpboot - load file via network using TFTP protocol > + Currently a placeholder (not implemented) > + > +endif > + > +endif > + > menu "Misc commands" > > config CMD_2048 > diff --git a/cmd/Makefile b/cmd/Makefile > index 87133cc27a8..535b6838ca5 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -128,6 +128,10 @@ endif > obj-$(CONFIG_CMD_MUX) += mux.o > obj-$(CONFIG_CMD_NAND) += nand.o > obj-$(CONFIG_CMD_NET) += net.o > +obj-$(CONFIG_CMD_NET_LWIP) += net-lwip.o > +ifdef CONFIG_CMD_NET_LWIP > +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 > diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c > new file mode 100644 > index 00000000000..82edb5fd2e6 > --- /dev/null > +++ b/cmd/net-lwip.c > @@ -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 > diff --git a/common/board_r.c b/common/board_r.c > index da0b80f24ff..6548eb8fdd5 100644 > --- a/common/board_r.c > +++ b/common/board_r.c > @@ -472,7 +472,7 @@ static int initr_status_led(void) > } > #endif > > -#ifdef CONFIG_CMD_NET > +#if defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_NET_LWIP) > static int initr_net(void) > { > puts("Net: "); > @@ -727,7 +727,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) || defined(CONFIG_CMD_NET_LWIP) > INIT_FUNC_WATCHDOG_RESET > initr_net, > #endif > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > index efc55e45ca8..640c4218518 100644 > --- a/drivers/net/Kconfig > +++ b/drivers/net/Kconfig > @@ -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 > diff --git a/include/net-lwip.h b/include/net-lwip.h > index f5c743b8d11..46cf6875f7e 100644 > --- a/include/net-lwip.h > +++ b/include/net-lwip.h > @@ -11,4 +11,6 @@ struct netif *net_lwip_new_netif_noip(void); > void net_lwip_remove_netif(struct netif *netif); > struct netif *net_lwip_get_netif(void); > > +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); > + > #endif /* __NET_LWIP_H__ */ > diff --git a/net-lwip/Makefile b/net-lwip/Makefile > new file mode 100644 > index 00000000000..a56c32bfa74 > --- /dev/null > +++ b/net-lwip/Makefile > @@ -0,0 +1,15 @@ > +ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot > + > +obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_ETH) += ../net/eth_bootdev.o > +obj-$(CONFIG_DM_MDIO) += ../net/mdio-uclass.o > +obj-$(CONFIG_DM_MDIO_MUX) += ../net/mdio-mux-uclass.o > +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth_common.o > +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth-uclass.o > +obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o > +obj-$(CONFIG_CMD_DHCP) += dhcp.o > +obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o > + > +# Disable this warning as it is triggered by: > +# sprintf(buf, index ? "foo%d" : "foo", index) > +# and this is intentional usage. > +CFLAGS_eth_common.o += -Wno-format-extra-args > diff --git a/net-lwip/dhcp.c b/net-lwip/dhcp.c > new file mode 100644 > index 00000000000..38ea565508f > --- /dev/null > +++ b/net-lwip/dhcp.c > @@ -0,0 +1,99 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* Copyright (C) 2024 Linaro Ltd. */ > + > +#include <command.h> > +#include <console.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); > +} > + > +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) > +{ > + unsigned long start; > + struct netif *netif; > + struct dhcp *dhcp; > + bool bound; > + > + netif = net_lwip_new_netif_noip(); > + if (!netif) > + return CMD_RET_FAILURE; > + > + start = get_timer(0); > + dhcp_start(netif); > + call_lwip_dhcp_fine_tmr(NULL); > + > + /* Wait for DHCP to complete */ > + do { > + eth_rx(); > + 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 (dhcp->offered_gw_addr.addr != 0) > + env_set("gatewayip", ip4addr_ntoa(&dhcp->offered_gw_addr)); > + env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr)); > + env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask)); > + env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_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 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 > index 00000000000..0b829a8d388 > --- /dev/null > +++ b/net-lwip/eth_internal.h > @@ -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 > index 00000000000..39e7e51e542 > --- /dev/null > +++ b/net-lwip/net-lwip.c > @@ -0,0 +1,270 @@ > +// 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+1) * PKTSIZE_ALIGN + PKTALIGN]; > +uchar *net_rx_packets[PKTBUFSRX]; > +uchar *net_rx_packet; > +uchar *net_tx_packet; > + > +static err_t low_level_output(struct netif *netif, struct pbuf *p) > +{ > + int err; > + > + /* > + * lwIP is alwys configured to use one device, the active one, so > + * there is no need to use the netif parameter. > + */ > + > + /* switch dev to active state */ > + eth_init_state_only(); > + > + err = eth_send(p->payload, p->len); > + if (err) { > + log_err("eth_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 = low_level_output; > + 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; > + > + net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1); > + net_tx_packet -= (ulong)net_tx_packet % PKTALIGN; > + for (i = 0; i < PKTBUFSRX; i++) > + net_rx_packets[i] = net_tx_packet + (i + 1) * 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[9] = { 'i', 'p', 'a' , 'd', 'd', 'r', }; > + char maskstr[10] = { 'n', 'e', 't', 'm', 'a', 's', 'k', }; > + char gwstr[12] = { 'g', 'a', 't', 'e', 'w', 'a', 'y', 'i', 'p', }; > + char *env; > + int ret; > + > + if (dev_seq(dev) > 0) { > + ret = snprintf(ipstr, sizeof(ipstr), "ipaddr%d", dev_seq(dev)); > + if (ret < 0 || ret >= sizeof(ipstr)) > + return -1; > + snprintf(maskstr, sizeof(maskstr), "netmask%d", dev_seq(dev)); > + if (ret < 0 || ret >= sizeof(maskstr)) > + return -1; > + snprintf(gwstr, sizeof(gwstr), "gw%d", dev_seq(dev)); > + if (ret < 0 || ret >= sizeof(gwstr)) > + return -1; > + } > + > + ip4_addr_set_zero(ip); > + ip4_addr_set_zero(mask); > + ip4_addr_set_zero(gw); > + > + env = env_get(ipstr); > + if (env) > + ipaddr_aton(env, ip); > + > + env = env_get(maskstr); > + if (env) > + ipaddr_aton(env, mask); > + > + env = env_get(gwstr); > + if (env) > + ipaddr_aton(env, gw); > + > + return 0; > +} > + > +static struct netif *new_netif(bool with_ip) > +{ > + unsigned char enetaddr[ARP_HLEN]; > + char hwstr[MAC_ADDR_STRLEN]; > + ip4_addr_t ip, mask, gw; > + struct udevice *dev; > + struct netif *netif; This does not fit into the driver model. In the EFI subsystem we want to implement network protocols like the EFI_DHCP4_PROTOCOL. Please, carve out functions to which we can pass a UCLASS_ETH udevice to execute DHCP. > + int ret; > + static bool first_call = true; > + > + eth_init_rings(); > + > + if (first_call) { > + if (eth_init()) { > + printf("eth_init() error\n"); > + return NULL; > + } > + first_call = false; > + } > + > + netif_remove(net_lwip_get_netif()); > + > + eth_set_current(); > + > + dev = eth_get_dev(); > + if (!dev) > + return NULL; > + > + ip4_addr_set_zero(&ip); > + ip4_addr_set_zero(&mask); > + ip4_addr_set_zero(&gw); > + > + if (with_ip) > + if (get_udev_ipv4_info(dev, &ip, &mask, &gw) < 0) > + return NULL; > + > + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), 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; > + > + if (!netif_add(netif, &ip, &mask, &gw, netif, 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; > +} > + > +/* Configure lwIP to use the currently active network device */ > +struct netif *net_lwip_new_netif() > +{ > + return new_netif(true); > +} > + > +struct netif *net_lwip_new_netif_noip() > +{ > + > + return new_netif(false); > +} > + > +void net_lwip_remove_netif(struct netif *netif) > +{ > + netif_remove(netif); > + free(netif); > +} > + > +int net_init(void) > +{ > + net_lwip_new_netif(); > + > + 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; > +} > + > +void net_process_received_packet(uchar *in_packet, int len) Library functions should take a udevice as an argument. Please, do not use the concept of "active device" in these library functions. The command line interface may implement such a concept for backwards compatibility. Best regards Heinrich > +{ > + struct netif *netif; > + struct pbuf *pbuf; > + > + if (len < ETHER_HDR_SIZE) > + return; > + > +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) > + if (push_packet) { > + (*push_packet)(in_packet, len); > + return; > + } > +#endif > + > + netif = net_lwip_get_netif(); > + if (!netif) > + return; > + > + pbuf = alloc_pbuf_and_copy(in_packet, len); > + if (!pbuf) > + return; > + > + netif->input(pbuf, netif); > +} > + > +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 > index 00000000000..1fa246f55d9 > --- /dev/null > +++ b/net-lwip/tftp.c > @@ -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; > +}
On 6/17/24 18:54, Heinrich Schuchardt wrote: > On 17.06.24 17:32, Jerome Forissier wrote: >> 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(). >> >> Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org> >> --- >> Makefile | 6 + >> boot/Kconfig | 3 +- >> cmd/Kconfig | 26 ++++ >> cmd/Makefile | 4 + >> cmd/net-lwip.c | 13 ++ >> common/board_r.c | 4 +- >> drivers/net/Kconfig | 2 +- >> include/net-lwip.h | 2 + >> net-lwip/Makefile | 15 +++ >> net-lwip/dhcp.c | 99 +++++++++++++++ >> net-lwip/eth_internal.h | 35 ++++++ >> net-lwip/net-lwip.c | 270 ++++++++++++++++++++++++++++++++++++++++ >> net-lwip/tftp.c | 11 ++ >> 13 files changed, 486 insertions(+), 4 deletions(-) >> create mode 100644 cmd/net-lwip.c >> create mode 100644 net-lwip/Makefile >> create mode 100644 net-lwip/dhcp.c >> create mode 100644 net-lwip/eth_internal.h >> create mode 100644 net-lwip/net-lwip.c >> create mode 100644 net-lwip/tftp.c >> >> diff --git a/Makefile b/Makefile >> index 0fe1623c550..92a0ab770bb 100644 >> --- a/Makefile >> +++ b/Makefile >> @@ -862,6 +862,7 @@ libs-y += env/ >> libs-y += lib/ >> libs-y += fs/ >> libs-$(CONFIG_NET) += net/ >> +libs-$(CONFIG_NET_LWIP) += net-lwip/ >> libs-y += disk/ >> libs-y += drivers/ >> libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/ >> @@ -2132,6 +2133,11 @@ etags: >> cscope: >> $(FIND) $(FINDFLAGS) $(TAG_SUBDIRS) -name '*.[chS]' -print > \ >> cscope.files >> +ifdef CONFIG_NET_LWIP >> + echo net/eth-uclass.c net/eth_common.c net/eth_bootdev.c \ >> + net/mdio-uclass.c net/mdio-mux-uclass.c >> \ >> + cscope.files >> +endif >> @find $(TAG_SUBDIRS) -name '*.[chS]' -type l -print | \ >> grep -xvf - cscope.files > cscope.files.no-symlinks; \ >> mv cscope.files.no-symlinks cscope.files >> diff --git a/boot/Kconfig b/boot/Kconfig >> index 6f3096c15a6..004e69dd92a 100644 >> --- a/boot/Kconfig >> +++ b/boot/Kconfig >> @@ -378,7 +378,7 @@ config BOOT_DEFAULTS_CMDS >> select CMD_FAT >> select CMD_FS_GENERIC >> select CMD_PART if PARTITIONS >> - select CMD_DHCP if CMD_NET >> + select CMD_DHCP if CMD_NET || CMD_NET_LWIP >> select CMD_PING if CMD_NET >> select CMD_PXE if CMD_NET >> select CMD_BOOTI if ARM64 >> @@ -540,6 +540,7 @@ config BOOTMETH_EXTLINUX_PXE >> config BOOTMETH_EFILOADER >> bool "Bootdev support for EFI boot" >> depends on EFI_BINARY_EXEC >> + select CMD_TFTPBOOT if CMD_NET_LWIP >> default y >> help >> Enables support for EFI boot using bootdevs. This makes the >> diff --git a/cmd/Kconfig b/cmd/Kconfig >> index b026439c773..1bfa528e945 100644 >> --- a/cmd/Kconfig >> +++ b/cmd/Kconfig >> @@ -2084,6 +2084,32 @@ config CMD_WOL >> >> endif >> >> +if NET_LWIP >> + >> +menuconfig CMD_NET_LWIP >> + bool "Network commands (lwIP)" >> + default y >> + >> +if CMD_NET_LWIP >> + >> +config CMD_DHCP >> + bool "dhcp" >> + select PROT_DHCP_LWIP >> + help >> + Boot image via network using DHCP/TFTP protocol >> + >> +config CMD_TFTPBOOT >> + bool "tftp" >> + select PROT_UDP_LWIP >> + default n >> + help >> + tftpboot - load file via network using TFTP protocol >> + Currently a placeholder (not implemented) >> + >> +endif >> + >> +endif >> + >> menu "Misc commands" >> >> config CMD_2048 >> diff --git a/cmd/Makefile b/cmd/Makefile >> index 87133cc27a8..535b6838ca5 100644 >> --- a/cmd/Makefile >> +++ b/cmd/Makefile >> @@ -128,6 +128,10 @@ endif >> obj-$(CONFIG_CMD_MUX) += mux.o >> obj-$(CONFIG_CMD_NAND) += nand.o >> obj-$(CONFIG_CMD_NET) += net.o >> +obj-$(CONFIG_CMD_NET_LWIP) += net-lwip.o >> +ifdef CONFIG_CMD_NET_LWIP >> +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 >> diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c >> new file mode 100644 >> index 00000000000..82edb5fd2e6 >> --- /dev/null >> +++ b/cmd/net-lwip.c >> @@ -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 >> diff --git a/common/board_r.c b/common/board_r.c >> index da0b80f24ff..6548eb8fdd5 100644 >> --- a/common/board_r.c >> +++ b/common/board_r.c >> @@ -472,7 +472,7 @@ static int initr_status_led(void) >> } >> #endif >> >> -#ifdef CONFIG_CMD_NET >> +#if defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_NET_LWIP) >> static int initr_net(void) >> { >> puts("Net: "); >> @@ -727,7 +727,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) || defined(CONFIG_CMD_NET_LWIP) >> INIT_FUNC_WATCHDOG_RESET >> initr_net, >> #endif >> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig >> index efc55e45ca8..640c4218518 100644 >> --- a/drivers/net/Kconfig >> +++ b/drivers/net/Kconfig >> @@ -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 >> diff --git a/include/net-lwip.h b/include/net-lwip.h >> index f5c743b8d11..46cf6875f7e 100644 >> --- a/include/net-lwip.h >> +++ b/include/net-lwip.h >> @@ -11,4 +11,6 @@ struct netif *net_lwip_new_netif_noip(void); >> void net_lwip_remove_netif(struct netif *netif); >> struct netif *net_lwip_get_netif(void); >> >> +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); >> + >> #endif /* __NET_LWIP_H__ */ >> diff --git a/net-lwip/Makefile b/net-lwip/Makefile >> new file mode 100644 >> index 00000000000..a56c32bfa74 >> --- /dev/null >> +++ b/net-lwip/Makefile >> @@ -0,0 +1,15 @@ >> +ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot >> + >> +obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_ETH) += ../net/eth_bootdev.o >> +obj-$(CONFIG_DM_MDIO) += ../net/mdio-uclass.o >> +obj-$(CONFIG_DM_MDIO_MUX) += ../net/mdio-mux-uclass.o >> +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth_common.o >> +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth-uclass.o >> +obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o >> +obj-$(CONFIG_CMD_DHCP) += dhcp.o >> +obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o >> + >> +# Disable this warning as it is triggered by: >> +# sprintf(buf, index ? "foo%d" : "foo", index) >> +# and this is intentional usage. >> +CFLAGS_eth_common.o += -Wno-format-extra-args >> diff --git a/net-lwip/dhcp.c b/net-lwip/dhcp.c >> new file mode 100644 >> index 00000000000..38ea565508f >> --- /dev/null >> +++ b/net-lwip/dhcp.c >> @@ -0,0 +1,99 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* Copyright (C) 2024 Linaro Ltd. */ >> + >> +#include <command.h> >> +#include <console.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); >> +} >> + >> +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) >> +{ >> + unsigned long start; >> + struct netif *netif; >> + struct dhcp *dhcp; >> + bool bound; >> + >> + netif = net_lwip_new_netif_noip(); >> + if (!netif) >> + return CMD_RET_FAILURE; >> + >> + start = get_timer(0); >> + dhcp_start(netif); >> + call_lwip_dhcp_fine_tmr(NULL); >> + >> + /* Wait for DHCP to complete */ >> + do { >> + eth_rx(); >> + 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 (dhcp->offered_gw_addr.addr != 0) >> + env_set("gatewayip", ip4addr_ntoa(&dhcp->offered_gw_addr)); >> + env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr)); >> + env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask)); >> + env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_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 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 >> index 00000000000..0b829a8d388 >> --- /dev/null >> +++ b/net-lwip/eth_internal.h >> @@ -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 >> index 00000000000..39e7e51e542 >> --- /dev/null >> +++ b/net-lwip/net-lwip.c >> @@ -0,0 +1,270 @@ >> +// 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+1) * PKTSIZE_ALIGN + PKTALIGN]; >> +uchar *net_rx_packets[PKTBUFSRX]; >> +uchar *net_rx_packet; >> +uchar *net_tx_packet; >> + >> +static err_t low_level_output(struct netif *netif, struct pbuf *p) >> +{ >> + int err; >> + >> + /* >> + * lwIP is alwys configured to use one device, the active one, so >> + * there is no need to use the netif parameter. >> + */ >> + >> + /* switch dev to active state */ >> + eth_init_state_only(); >> + >> + err = eth_send(p->payload, p->len); >> + if (err) { >> + log_err("eth_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 = low_level_output; >> + 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; >> + >> + net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1); >> + net_tx_packet -= (ulong)net_tx_packet % PKTALIGN; >> + for (i = 0; i < PKTBUFSRX; i++) >> + net_rx_packets[i] = net_tx_packet + (i + 1) * 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[9] = { 'i', 'p', 'a' , 'd', 'd', 'r', }; >> + char maskstr[10] = { 'n', 'e', 't', 'm', 'a', 's', 'k', }; >> + char gwstr[12] = { 'g', 'a', 't', 'e', 'w', 'a', 'y', 'i', 'p', }; >> + char *env; >> + int ret; >> + >> + if (dev_seq(dev) > 0) { >> + ret = snprintf(ipstr, sizeof(ipstr), "ipaddr%d", dev_seq(dev)); >> + if (ret < 0 || ret >= sizeof(ipstr)) >> + return -1; >> + snprintf(maskstr, sizeof(maskstr), "netmask%d", dev_seq(dev)); >> + if (ret < 0 || ret >= sizeof(maskstr)) >> + return -1; >> + snprintf(gwstr, sizeof(gwstr), "gw%d", dev_seq(dev)); >> + if (ret < 0 || ret >= sizeof(gwstr)) >> + return -1; >> + } >> + >> + ip4_addr_set_zero(ip); >> + ip4_addr_set_zero(mask); >> + ip4_addr_set_zero(gw); >> + >> + env = env_get(ipstr); >> + if (env) >> + ipaddr_aton(env, ip); >> + >> + env = env_get(maskstr); >> + if (env) >> + ipaddr_aton(env, mask); >> + >> + env = env_get(gwstr); >> + if (env) >> + ipaddr_aton(env, gw); >> + >> + return 0; >> +} >> + >> +static struct netif *new_netif(bool with_ip) >> +{ >> + unsigned char enetaddr[ARP_HLEN]; >> + char hwstr[MAC_ADDR_STRLEN]; >> + ip4_addr_t ip, mask, gw; >> + struct udevice *dev; >> + struct netif *netif; > > This does not fit into the driver model. > > In the EFI subsystem we want to implement network protocols like the > EFI_DHCP4_PROTOCOL. > > Please, carve out functions to which we can pass a UCLASS_ETH udevice to > execute DHCP. v6 will have: static struct netif *new_netif(struct udevice *udev, bool with_ip) struct netif *net_lwip_new_netif(struct udevice *udev) struct netif *net_lwip_new_netif_noip(struct udevice *udev) static int dhcp_loop(struct udevice *udev) > >> + int ret; >> + static bool first_call = true; >> + >> + eth_init_rings(); >> + >> + if (first_call) { >> + if (eth_init()) { >> + printf("eth_init() error\n"); >> + return NULL; >> + } >> + first_call = false; >> + } >> + >> + netif_remove(net_lwip_get_netif()); >> + >> + eth_set_current(); >> + >> + dev = eth_get_dev(); >> + if (!dev) >> + return NULL; >> + >> + ip4_addr_set_zero(&ip); >> + ip4_addr_set_zero(&mask); >> + ip4_addr_set_zero(&gw); >> + >> + if (with_ip) >> + if (get_udev_ipv4_info(dev, &ip, &mask, &gw) < 0) >> + return NULL; >> + >> + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), 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; >> + >> + if (!netif_add(netif, &ip, &mask, &gw, netif, 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; >> +} >> + >> +/* Configure lwIP to use the currently active network device */ >> +struct netif *net_lwip_new_netif() >> +{ >> + return new_netif(true); >> +} >> + >> +struct netif *net_lwip_new_netif_noip() >> +{ >> + >> + return new_netif(false); >> +} >> + >> +void net_lwip_remove_netif(struct netif *netif) >> +{ >> + netif_remove(netif); >> + free(netif); >> +} >> + >> +int net_init(void) >> +{ >> + net_lwip_new_netif(); >> + >> + 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; >> +} >> + >> +void net_process_received_packet(uchar *in_packet, int len) > > Library functions should take a udevice as an argument. Please, do not > use the concept of "active device" in these library functions. OK, I have unified the naming in v6 and all functions will take a udevice: static int dhcp_loop(struct udevice *udev) static int dns_loop(struct udevice *udev, const char *name, const char *var) static int ping_loop(struct udevice *udev, const ip_addr_t* addr) static int tftp_loop(struct udevice *udev, ulong addr, char *fname, ip_addr_t srvip) static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) > > The command line interface may implement such a concept for backwards > compatibility. Sure. Thanks,
[...] > >> + > >> +static struct netif *new_netif(bool with_ip) > >> +{ > >> + unsigned char enetaddr[ARP_HLEN]; > >> + char hwstr[MAC_ADDR_STRLEN]; > >> + ip4_addr_t ip, mask, gw; > >> + struct udevice *dev; > >> + struct netif *netif; > > > > This does not fit into the driver model. > > > > In the EFI subsystem we want to implement network protocols like the > > EFI_DHCP4_PROTOCOL. > > > > Please, carve out functions to which we can pass a UCLASS_ETH udevice to > > execute DHCP. > > v6 will have: > > static struct netif *new_netif(struct udevice *udev, bool with_ip) > struct netif *net_lwip_new_netif(struct udevice *udev) > struct netif *net_lwip_new_netif_noip(struct udevice *udev) Heinrich, any other EFI protocols you have in mind that would require similar tweaking? e.g the EFI_TCP4 and HTTP protocols? > > static int dhcp_loop(struct udevice *udev) > > > > >> + int ret; > >> + static bool first_call = true; > >> + > >> + eth_init_rings(); > >> + > >> + if (first_call) { > >> + if (eth_init()) { > >> + printf("eth_init() error\n"); > >> + return NULL; > >> + } > >> + first_call = false; > >> + } > >> + > >> + netif_remove(net_lwip_get_netif()); > >> + > >> + eth_set_current(); > >> + > >> + dev = eth_get_dev(); > >> + if (!dev) > >> + return NULL; > >> + > >> + ip4_addr_set_zero(&ip); > >> + ip4_addr_set_zero(&mask); > >> + ip4_addr_set_zero(&gw); > >> + > >> + if (with_ip) > >> + if (get_udev_ipv4_info(dev, &ip, &mask, &gw) < 0) > >> + return NULL; > >> + > >> + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), 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; > >> + > >> + if (!netif_add(netif, &ip, &mask, &gw, netif, 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; > >> +} > >> + > >> +/* Configure lwIP to use the currently active network device */ > >> +struct netif *net_lwip_new_netif() > >> +{ > >> + return new_netif(true); > >> +} > >> + > >> +struct netif *net_lwip_new_netif_noip() > >> +{ > >> + > >> + return new_netif(false); > >> +} > >> + > >> +void net_lwip_remove_netif(struct netif *netif) > >> +{ > >> + netif_remove(netif); > >> + free(netif); > >> +} > >> + > >> +int net_init(void) > >> +{ > >> + net_lwip_new_netif(); > >> + > >> + 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; > >> +} > >> + > >> +void net_process_received_packet(uchar *in_packet, int len) > > > > Library functions should take a udevice as an argument. Please, do not > > use the concept of "active device" in these library functions. > > OK, I have unified the naming in v6 and all functions will take a udevice: > > static int dhcp_loop(struct udevice *udev) > static int dns_loop(struct udevice *udev, const char *name, const char *var) > static int ping_loop(struct udevice *udev, const ip_addr_t* addr) > static int tftp_loop(struct udevice *udev, ulong addr, char *fname, > ip_addr_t srvip) > static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) > > > > > The command line interface may implement such a concept for backwards > > compatibility. > > Sure. > > Thanks, > -- > Jerome > > > > > Best regards > > > > Heinrich > > > >> +{ > >> + struct netif *netif; > >> + struct pbuf *pbuf; > >> + > >> + if (len < ETHER_HDR_SIZE) > >> + return; > >> + > >> +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) > >> + if (push_packet) { > >> + (*push_packet)(in_packet, len); > >> + return; > >> + } > >> +#endif > >> + > >> + netif = net_lwip_get_netif(); > >> + if (!netif) > >> + return; > >> + > >> + pbuf = alloc_pbuf_and_copy(in_packet, len); > >> + if (!pbuf) > >> + return; > >> + > >> + netif->input(pbuf, netif); > >> +} > >> + > >> +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 > >> index 00000000000..1fa246f55d9 > >> --- /dev/null > >> +++ b/net-lwip/tftp.c > >> @@ -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; > >> +} > >
diff --git a/Makefile b/Makefile index 0fe1623c550..92a0ab770bb 100644 --- a/Makefile +++ b/Makefile @@ -862,6 +862,7 @@ libs-y += env/ libs-y += lib/ libs-y += fs/ libs-$(CONFIG_NET) += net/ +libs-$(CONFIG_NET_LWIP) += net-lwip/ libs-y += disk/ libs-y += drivers/ libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/ @@ -2132,6 +2133,11 @@ etags: cscope: $(FIND) $(FINDFLAGS) $(TAG_SUBDIRS) -name '*.[chS]' -print > \ cscope.files +ifdef CONFIG_NET_LWIP + echo net/eth-uclass.c net/eth_common.c net/eth_bootdev.c \ + net/mdio-uclass.c net/mdio-mux-uclass.c >> \ + cscope.files +endif @find $(TAG_SUBDIRS) -name '*.[chS]' -type l -print | \ grep -xvf - cscope.files > cscope.files.no-symlinks; \ mv cscope.files.no-symlinks cscope.files diff --git a/boot/Kconfig b/boot/Kconfig index 6f3096c15a6..004e69dd92a 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -378,7 +378,7 @@ config BOOT_DEFAULTS_CMDS select CMD_FAT select CMD_FS_GENERIC select CMD_PART if PARTITIONS - select CMD_DHCP if CMD_NET + select CMD_DHCP if CMD_NET || CMD_NET_LWIP select CMD_PING if CMD_NET select CMD_PXE if CMD_NET select CMD_BOOTI if ARM64 @@ -540,6 +540,7 @@ config BOOTMETH_EXTLINUX_PXE config BOOTMETH_EFILOADER bool "Bootdev support for EFI boot" depends on EFI_BINARY_EXEC + select CMD_TFTPBOOT if CMD_NET_LWIP default y help Enables support for EFI boot using bootdevs. This makes the diff --git a/cmd/Kconfig b/cmd/Kconfig index b026439c773..1bfa528e945 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2084,6 +2084,32 @@ config CMD_WOL endif +if NET_LWIP + +menuconfig CMD_NET_LWIP + bool "Network commands (lwIP)" + default y + +if CMD_NET_LWIP + +config CMD_DHCP + bool "dhcp" + select PROT_DHCP_LWIP + help + Boot image via network using DHCP/TFTP protocol + +config CMD_TFTPBOOT + bool "tftp" + select PROT_UDP_LWIP + default n + help + tftpboot - load file via network using TFTP protocol + Currently a placeholder (not implemented) + +endif + +endif + menu "Misc commands" config CMD_2048 diff --git a/cmd/Makefile b/cmd/Makefile index 87133cc27a8..535b6838ca5 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -128,6 +128,10 @@ endif obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o +obj-$(CONFIG_CMD_NET_LWIP) += net-lwip.o +ifdef CONFIG_CMD_NET_LWIP +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 diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c new file mode 100644 index 00000000000..82edb5fd2e6 --- /dev/null +++ b/cmd/net-lwip.c @@ -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 diff --git a/common/board_r.c b/common/board_r.c index da0b80f24ff..6548eb8fdd5 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -472,7 +472,7 @@ static int initr_status_led(void) } #endif -#ifdef CONFIG_CMD_NET +#if defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_NET_LWIP) static int initr_net(void) { puts("Net: "); @@ -727,7 +727,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) || defined(CONFIG_CMD_NET_LWIP) INIT_FUNC_WATCHDOG_RESET initr_net, #endif diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index efc55e45ca8..640c4218518 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -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 diff --git a/include/net-lwip.h b/include/net-lwip.h index f5c743b8d11..46cf6875f7e 100644 --- a/include/net-lwip.h +++ b/include/net-lwip.h @@ -11,4 +11,6 @@ struct netif *net_lwip_new_netif_noip(void); void net_lwip_remove_netif(struct netif *netif); struct netif *net_lwip_get_netif(void); +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); + #endif /* __NET_LWIP_H__ */ diff --git a/net-lwip/Makefile b/net-lwip/Makefile new file mode 100644 index 00000000000..a56c32bfa74 --- /dev/null +++ b/net-lwip/Makefile @@ -0,0 +1,15 @@ +ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot + +obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_ETH) += ../net/eth_bootdev.o +obj-$(CONFIG_DM_MDIO) += ../net/mdio-uclass.o +obj-$(CONFIG_DM_MDIO_MUX) += ../net/mdio-mux-uclass.o +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth_common.o +obj-$(CONFIG_$(SPL_)DM_ETH) += ../net/eth-uclass.o +obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o +obj-$(CONFIG_CMD_DHCP) += dhcp.o +obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o + +# Disable this warning as it is triggered by: +# sprintf(buf, index ? "foo%d" : "foo", index) +# and this is intentional usage. +CFLAGS_eth_common.o += -Wno-format-extra-args diff --git a/net-lwip/dhcp.c b/net-lwip/dhcp.c new file mode 100644 index 00000000000..38ea565508f --- /dev/null +++ b/net-lwip/dhcp.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2024 Linaro Ltd. */ + +#include <command.h> +#include <console.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); +} + +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + unsigned long start; + struct netif *netif; + struct dhcp *dhcp; + bool bound; + + netif = net_lwip_new_netif_noip(); + if (!netif) + return CMD_RET_FAILURE; + + start = get_timer(0); + dhcp_start(netif); + call_lwip_dhcp_fine_tmr(NULL); + + /* Wait for DHCP to complete */ + do { + eth_rx(); + 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 (dhcp->offered_gw_addr.addr != 0) + env_set("gatewayip", ip4addr_ntoa(&dhcp->offered_gw_addr)); + env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr)); + env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask)); + env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_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 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 index 00000000000..0b829a8d388 --- /dev/null +++ b/net-lwip/eth_internal.h @@ -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 index 00000000000..39e7e51e542 --- /dev/null +++ b/net-lwip/net-lwip.c @@ -0,0 +1,270 @@ +// 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+1) * PKTSIZE_ALIGN + PKTALIGN]; +uchar *net_rx_packets[PKTBUFSRX]; +uchar *net_rx_packet; +uchar *net_tx_packet; + +static err_t low_level_output(struct netif *netif, struct pbuf *p) +{ + int err; + + /* + * lwIP is alwys configured to use one device, the active one, so + * there is no need to use the netif parameter. + */ + + /* switch dev to active state */ + eth_init_state_only(); + + err = eth_send(p->payload, p->len); + if (err) { + log_err("eth_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 = low_level_output; + 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; + + net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1); + net_tx_packet -= (ulong)net_tx_packet % PKTALIGN; + for (i = 0; i < PKTBUFSRX; i++) + net_rx_packets[i] = net_tx_packet + (i + 1) * 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[9] = { 'i', 'p', 'a' , 'd', 'd', 'r', }; + char maskstr[10] = { 'n', 'e', 't', 'm', 'a', 's', 'k', }; + char gwstr[12] = { 'g', 'a', 't', 'e', 'w', 'a', 'y', 'i', 'p', }; + char *env; + int ret; + + if (dev_seq(dev) > 0) { + ret = snprintf(ipstr, sizeof(ipstr), "ipaddr%d", dev_seq(dev)); + if (ret < 0 || ret >= sizeof(ipstr)) + return -1; + snprintf(maskstr, sizeof(maskstr), "netmask%d", dev_seq(dev)); + if (ret < 0 || ret >= sizeof(maskstr)) + return -1; + snprintf(gwstr, sizeof(gwstr), "gw%d", dev_seq(dev)); + if (ret < 0 || ret >= sizeof(gwstr)) + return -1; + } + + ip4_addr_set_zero(ip); + ip4_addr_set_zero(mask); + ip4_addr_set_zero(gw); + + env = env_get(ipstr); + if (env) + ipaddr_aton(env, ip); + + env = env_get(maskstr); + if (env) + ipaddr_aton(env, mask); + + env = env_get(gwstr); + if (env) + ipaddr_aton(env, gw); + + return 0; +} + +static struct netif *new_netif(bool with_ip) +{ + unsigned char enetaddr[ARP_HLEN]; + char hwstr[MAC_ADDR_STRLEN]; + ip4_addr_t ip, mask, gw; + struct udevice *dev; + struct netif *netif; + int ret; + static bool first_call = true; + + eth_init_rings(); + + if (first_call) { + if (eth_init()) { + printf("eth_init() error\n"); + return NULL; + } + first_call = false; + } + + netif_remove(net_lwip_get_netif()); + + eth_set_current(); + + dev = eth_get_dev(); + if (!dev) + return NULL; + + ip4_addr_set_zero(&ip); + ip4_addr_set_zero(&mask); + ip4_addr_set_zero(&gw); + + if (with_ip) + if (get_udev_ipv4_info(dev, &ip, &mask, &gw) < 0) + return NULL; + + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), 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; + + if (!netif_add(netif, &ip, &mask, &gw, netif, 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; +} + +/* Configure lwIP to use the currently active network device */ +struct netif *net_lwip_new_netif() +{ + return new_netif(true); +} + +struct netif *net_lwip_new_netif_noip() +{ + + return new_netif(false); +} + +void net_lwip_remove_netif(struct netif *netif) +{ + netif_remove(netif); + free(netif); +} + +int net_init(void) +{ + net_lwip_new_netif(); + + 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; +} + +void net_process_received_packet(uchar *in_packet, int len) +{ + struct netif *netif; + struct pbuf *pbuf; + + if (len < ETHER_HDR_SIZE) + return; + +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) + if (push_packet) { + (*push_packet)(in_packet, len); + return; + } +#endif + + netif = net_lwip_get_netif(); + if (!netif) + return; + + pbuf = alloc_pbuf_and_copy(in_packet, len); + if (!pbuf) + return; + + netif->input(pbuf, netif); +} + +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 index 00000000000..1fa246f55d9 --- /dev/null +++ b/net-lwip/tftp.c @@ -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; +}
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(). Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org> --- Makefile | 6 + boot/Kconfig | 3 +- cmd/Kconfig | 26 ++++ cmd/Makefile | 4 + cmd/net-lwip.c | 13 ++ common/board_r.c | 4 +- drivers/net/Kconfig | 2 +- include/net-lwip.h | 2 + net-lwip/Makefile | 15 +++ net-lwip/dhcp.c | 99 +++++++++++++++ net-lwip/eth_internal.h | 35 ++++++ net-lwip/net-lwip.c | 270 ++++++++++++++++++++++++++++++++++++++++ net-lwip/tftp.c | 11 ++ 13 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 cmd/net-lwip.c create mode 100644 net-lwip/Makefile create mode 100644 net-lwip/dhcp.c create mode 100644 net-lwip/eth_internal.h create mode 100644 net-lwip/net-lwip.c create mode 100644 net-lwip/tftp.c