
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;
+}