Merge tag 'net-20260813' of https://git.u-boot-project.org/u-boot/custodians/u-boot-net
Pull request net-20260813. net: - phy: dp83867: enable extended read / write for driver - phy: fix duplicate eth_phy binding - Drop unnecessary device_set_name - dwc_eth_xgmac: Return -ENODEV when phy_connect() fails - nfs: clean up bounds checks in nfs_readlink_reply() - rtl8169: add support for RTL8126A and RTL8127A - srand_mac(): fix -ENODEV crash with CONFIG_DM_RNG net-legacy: - Fix out-of-bounds write in IP fragment reassembly - test: net: add regression test for IP reassembly overflow net-lwip: - Add tftpsrv command - Handle chained pbufs in transmit path - sntp: fix netif leak when ntpserverip is unset - wget: free mbedtls x509 cert context to avoid memory leak - Fix DHCP fine timer interval
This commit is contained in:
+8
-6
@@ -2135,12 +2135,6 @@ config CMD_TFTPPUT
|
||||
help
|
||||
TFTP put command, for uploading files to a server
|
||||
|
||||
config CMD_TFTPSRV
|
||||
bool "tftpsrv"
|
||||
depends on CMD_TFTPBOOT
|
||||
help
|
||||
Act as a TFTP server and boot the first received file
|
||||
|
||||
config NET_TFTP_VARS
|
||||
bool "Control TFTP timeout and count through environment"
|
||||
depends on CMD_TFTPBOOT
|
||||
@@ -2287,6 +2281,14 @@ config CMD_TFTPBOOT
|
||||
help
|
||||
tftpboot - load file via network using TFTP protocol
|
||||
|
||||
config CMD_TFTPSRV
|
||||
bool "tftpsrv"
|
||||
depends on CMD_TFTPBOOT
|
||||
help
|
||||
Act as a TFTP server and receive the first incoming file into
|
||||
memory. The command returns successfully after the transfer so
|
||||
boot scripts can boot the received image from the load address.
|
||||
|
||||
config CMD_WGET
|
||||
bool "wget"
|
||||
default y if SANDBOX || ARCH_QEMU
|
||||
|
||||
@@ -4,4 +4,5 @@ obj-$(CONFIG_CMD_NFS) += nfs.o
|
||||
obj-$(CONFIG_CMD_PING) += ping.o
|
||||
obj-$(CONFIG_CMD_SNTP) += sntp.o
|
||||
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
|
||||
obj-$(CONFIG_CMD_TFTPSRV) += tftpsrv.o
|
||||
obj-$(CONFIG_CMD_WGET) += wget.o
|
||||
|
||||
@@ -71,6 +71,7 @@ static int sntp_loop(struct udevice *udev, ip_addr_t *srvip)
|
||||
} else {
|
||||
if (!ntp_server_known()) {
|
||||
log_err("error: ntpserverip not set\n");
|
||||
net_lwip_remove_netif(netif);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
|
||||
U_BOOT_CMD(tftpsrv, 2, 1, do_tftpsrv,
|
||||
"act as a TFTP server and receive the first file",
|
||||
"[loadAddress]\n"
|
||||
"Listen for an incoming TFTP transfer and receive a file into memory.\n"
|
||||
"The transfer is aborted if a transfer has not been started after\n"
|
||||
"about 50 seconds or if Ctrl-C is pressed.");
|
||||
@@ -67,12 +67,15 @@ static int _set_cacert(const void *addr, size_t sz)
|
||||
if (ret) {
|
||||
if (!wget_info->silent)
|
||||
printf("Could not parse certificates (%d)\n", ret);
|
||||
mbedtls_x509_crt_free(&crt);
|
||||
free(cacert);
|
||||
cacert = NULL;
|
||||
cacert_size = 0;
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_free(&crt);
|
||||
|
||||
#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT)
|
||||
cacert_initialized = true;
|
||||
#endif
|
||||
|
||||
@@ -89,9 +89,9 @@ static int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
|
||||
U_BOOT_CMD(
|
||||
tftpsrv, 2, 1, do_tftpsrv,
|
||||
"act as a TFTP server and boot the first received file",
|
||||
"act as a TFTP server and receive the first file",
|
||||
"[loadAddress]\n"
|
||||
"Listen for an incoming TFTP transfer, receive a file and boot it.\n"
|
||||
"Listen for an incoming TFTP transfer and receive a file into memory.\n"
|
||||
"The transfer is aborted if a transfer has not been started after\n"
|
||||
"about 50 seconds or if Ctrl-C is pressed."
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ CONFIG_NET_LWIP=y
|
||||
CONFIG_CMD_DNS=y
|
||||
CONFIG_CMD_NFS=y
|
||||
CONFIG_CMD_SNTP=y
|
||||
CONFIG_CMD_TFTPSRV=y
|
||||
CONFIG_CMD_WGET=y
|
||||
CONFIG_EFI_HTTP_BOOT=y
|
||||
CONFIG_WGET_HTTPS=y
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
.. index::
|
||||
single: tftpsrv (command)
|
||||
|
||||
tftpsrv command
|
||||
===============
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
tftpsrv [loadAddress]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The tftpsrv command listens for an incoming TFTP write request and receives
|
||||
the first transferred file into memory.
|
||||
|
||||
loadAddress
|
||||
memory address where the received file is stored. If not provided, the
|
||||
address is taken from the *loadaddr* environment variable or the default
|
||||
image load address.
|
||||
|
||||
After a successful transfer, the *fileaddr* and *filesize* environment
|
||||
variables describe the received file. The command returns successfully after
|
||||
the transfer has completed. It does not boot the file automatically; boot
|
||||
scripts can use commands such as bootm, booti or bootefi to boot from the
|
||||
load address.
|
||||
|
||||
The transfer is aborted if no transfer has started after about 50 seconds or
|
||||
if Ctrl-C is pressed.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
In the example the following steps are executed:
|
||||
|
||||
* setup the board network address
|
||||
* receive a FIT image from a host
|
||||
* boot the received FIT image
|
||||
|
||||
::
|
||||
|
||||
=> setenv autoload no
|
||||
=> dhcp
|
||||
BOOTP broadcast 1
|
||||
DHCP client bound to address 192.168.1.40 (7 ms)
|
||||
=> tftpsrv $loadaddr
|
||||
Using ethernet@1c30000 device
|
||||
Listening for TFTP transfer on 192.168.1.40
|
||||
Load address: 0x42000000
|
||||
Loading: #################################################################
|
||||
6.5 MiB/s
|
||||
done
|
||||
Bytes transferred = 1048576 (100000 hex)
|
||||
=> bootm $fileaddr
|
||||
|
||||
On the host, send the file to the board while U-Boot is listening:
|
||||
|
||||
::
|
||||
|
||||
$ curl --upload-file image.fit tftp://192.168.1.40/image.fit
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The command is only available if CONFIG_CMD_TFTPSRV=y.
|
||||
|
||||
The command is supported by both the legacy network stack and the lwIP network
|
||||
stack.
|
||||
@@ -638,11 +638,6 @@ static int dm9000_read_rom_hwaddr(struct udevice *dev)
|
||||
return !is_valid_ethaddr(pdata->enetaddr);
|
||||
}
|
||||
|
||||
static int dm9000_bind(struct udevice *dev)
|
||||
{
|
||||
return device_set_name(dev, dev->name);
|
||||
}
|
||||
|
||||
static int dm9000_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct dm9000_priv *db = dev_get_priv(dev);
|
||||
@@ -673,7 +668,6 @@ U_BOOT_DRIVER(dm9000) = {
|
||||
.name = "eth_dm9000",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = dm9000_ids,
|
||||
.bind = dm9000_bind,
|
||||
.of_to_plat = dm9000_of_to_plat,
|
||||
.ops = &dm9000_ops,
|
||||
.priv_auto = sizeof(struct dm9000_priv),
|
||||
|
||||
@@ -507,6 +507,7 @@ static int xgmac_start(struct udevice *dev)
|
||||
xgmac->config->interface(dev));
|
||||
if (!xgmac->phy) {
|
||||
pr_err("%s phy_connect() failed\n", dev->name);
|
||||
ret = -ENODEV;
|
||||
goto err_stop_resets;
|
||||
}
|
||||
|
||||
|
||||
@@ -429,11 +429,6 @@ static int ftmac100_remove(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftmac100_bind(struct udevice *dev)
|
||||
{
|
||||
return device_set_name(dev, dev->name);
|
||||
}
|
||||
|
||||
static const struct eth_ops ftmac100_ops = {
|
||||
.start = ftmac100_start,
|
||||
.send = ftmac100_send,
|
||||
@@ -451,7 +446,6 @@ U_BOOT_DRIVER(ftmac100) = {
|
||||
.name = "ftmac100",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = ftmac100_ids,
|
||||
.bind = ftmac100_bind,
|
||||
.of_to_plat = ftmac100_of_to_plat,
|
||||
.probe = ftmac100_probe,
|
||||
.remove = ftmac100_remove,
|
||||
|
||||
@@ -571,11 +571,6 @@ static int ks8851_read_rom_hwaddr(struct udevice *dev)
|
||||
return !is_valid_ethaddr(pdata->enetaddr);
|
||||
}
|
||||
|
||||
static int ks8851_bind(struct udevice *dev)
|
||||
{
|
||||
return device_set_name(dev, dev->name);
|
||||
}
|
||||
|
||||
static int ks8851_probe(struct udevice *dev)
|
||||
{
|
||||
struct ks_net *ks = dev_get_priv(dev);
|
||||
@@ -615,7 +610,6 @@ U_BOOT_DRIVER(ks8851) = {
|
||||
.name = "eth_ks8851",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = ks8851_ids,
|
||||
.bind = ks8851_bind,
|
||||
.of_to_plat = ks8851_of_to_plat,
|
||||
.probe = ks8851_probe,
|
||||
.ops = &ks8851_ops,
|
||||
|
||||
@@ -126,6 +126,22 @@ struct dp83867_private {
|
||||
bool sgmii_ref_clk_en;
|
||||
};
|
||||
|
||||
static int dp83867_phy_extread(struct phy_device *phydev,
|
||||
int addr, int devad, int reg)
|
||||
{
|
||||
if (devad != DP83867_DEVADDR)
|
||||
return -EINVAL;
|
||||
return phy_read_mmd(phydev, devad, addr);
|
||||
};
|
||||
|
||||
static int dp83867_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devad, int reg, u16 val)
|
||||
{
|
||||
if (devad != DP83867_DEVADDR)
|
||||
return -EINVAL;
|
||||
return phy_write_mmd(phydev, devad, addr, (u32)val);
|
||||
};
|
||||
|
||||
static int dp83867_config_port_mirroring(struct phy_device *phydev)
|
||||
{
|
||||
struct dp83867_private *dp83867 =
|
||||
@@ -410,4 +426,6 @@ U_BOOT_PHY_DRIVER(dp83867) = {
|
||||
.config = &dp83867_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.readext = dp83867_phy_extread,
|
||||
.writeext = dp83867_phy_extwrite,
|
||||
};
|
||||
|
||||
+28
-1
@@ -20,6 +20,7 @@
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/of_extra.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
@@ -921,6 +922,27 @@ static struct phy_device *phy_connect_fixed(struct mii_dev *bus,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_ETH_PHY
|
||||
static struct phy_device *phy_connect_dm_bound(struct mii_dev *bus,
|
||||
struct udevice *dev,
|
||||
uint mask)
|
||||
{
|
||||
struct udevice *dm_phy_dev;
|
||||
struct phy_device *phydev;
|
||||
|
||||
if (!uclass_find_device_by_phandle(UCLASS_ETH_PHY, dev,
|
||||
"phy-handle", &dm_phy_dev)) {
|
||||
phydev = phy_find_by_mask(bus, mask);
|
||||
if (phydev)
|
||||
phydev->node = dev_ofnode(dm_phy_dev);
|
||||
|
||||
return phydev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct phy_device *phy_connect(struct mii_dev *bus, int addr,
|
||||
struct udevice *dev,
|
||||
phy_interface_t interface)
|
||||
@@ -928,8 +950,13 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
|
||||
struct phy_device *phydev = NULL;
|
||||
uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff;
|
||||
|
||||
#ifdef CONFIG_DM_ETH_PHY
|
||||
phydev = phy_connect_dm_bound(bus, dev, mask);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHY_FIXED
|
||||
phydev = phy_connect_fixed(bus, dev);
|
||||
if (!phydev)
|
||||
phydev = phy_connect_fixed(bus, dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHY_NCSI
|
||||
|
||||
+94
-9
@@ -49,6 +49,7 @@
|
||||
#include <asm/cache.h>
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
@@ -152,8 +153,24 @@ enum RTL8125_registers {
|
||||
IntrMask_8125 = 0x38,
|
||||
IntrStatus_8125 = 0x3C,
|
||||
TxPoll_8125 = 0x90,
|
||||
RX_DESC_MODE = 0xd8,
|
||||
MACOCP = 0xb0,
|
||||
RADMFIFO_PROTECT = 0x0402,
|
||||
TX_DESC_MODE = 0xeb58,
|
||||
};
|
||||
|
||||
/* MAC OCP indirect access via the MACOCP register */
|
||||
#define RTL8125_OCP_WRITE 0x80000000
|
||||
#define RTL8125_OCP_ADDR_SHIFT 16
|
||||
#define RX_DESC_CRC_DROP BIT(0)
|
||||
#define RX_DESC_TYPE BIT(1)
|
||||
|
||||
/* TX_DESC_MODE (MAC OCP 0xeb58): TX descriptor format select, bits [1:0] */
|
||||
#define TX_DESC_FMT_MASK GENMASK(1, 0)
|
||||
#define TX_DESC_FMT_STD BIT(0)
|
||||
#define TX_DESC_FMT_V3 BIT(1)
|
||||
#define RX_PAUSE_SLOT_ON BIT(11)
|
||||
|
||||
enum RTL8169_register_content {
|
||||
/*InterruptStatusBits */
|
||||
SYSErr = 0x8000,
|
||||
@@ -271,6 +288,8 @@ static struct {
|
||||
{"RTL-8168h/8111h", 0x54, 0xff7e1880,},
|
||||
{"RTL-8125B", 0x64, 0xff7e1880,},
|
||||
{"RTL-8125d", 0x6a, 0xff7e5880,},
|
||||
{"RTL-8126A", 0x66, 0xff7e5880,},
|
||||
{"RTL-8127A", 0x6e, 0xff7e5880,},
|
||||
};
|
||||
|
||||
enum _DescStatusBit {
|
||||
@@ -355,6 +374,8 @@ static const unsigned int rtl8169_rx_config =
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8126) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8127) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
|
||||
@@ -398,6 +419,33 @@ int mdio_read(int RegAddr)
|
||||
return value;
|
||||
}
|
||||
|
||||
/* RTL8125/8126/8127 share the same register layout and quirks */
|
||||
static bool rtl_is_8125(struct pci_child_plat *pplat)
|
||||
{
|
||||
return pplat->device == 0x8125 || pplat->device == 0x8126 ||
|
||||
pplat->device == 0x8127;
|
||||
}
|
||||
|
||||
static void rtl_mac_ocp_write(u16 reg_addr, u16 value)
|
||||
{
|
||||
u32 data32;
|
||||
|
||||
data32 = (u32)(reg_addr / 2) << RTL8125_OCP_ADDR_SHIFT;
|
||||
data32 += value;
|
||||
data32 |= RTL8125_OCP_WRITE;
|
||||
RTL_W32(MACOCP, data32);
|
||||
}
|
||||
|
||||
static u16 rtl_mac_ocp_read(u16 reg_addr)
|
||||
{
|
||||
u32 data32;
|
||||
|
||||
data32 = (u32)(reg_addr / 2) << RTL8125_OCP_ADDR_SHIFT;
|
||||
RTL_W32(MACOCP, data32);
|
||||
|
||||
return (u16)RTL_R32(MACOCP);
|
||||
}
|
||||
|
||||
static int rtl8169_init_board(unsigned long dev_iobase, const char *name)
|
||||
{
|
||||
int i;
|
||||
@@ -571,12 +619,15 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase,
|
||||
return length;
|
||||
|
||||
} else {
|
||||
u32 IntrStatus = IntrStatus_8169;
|
||||
u32 sts;
|
||||
|
||||
if (pplat->device == 0x8125)
|
||||
IntrStatus = IntrStatus_8125;
|
||||
ushort sts = RTL_R8(IntrStatus);
|
||||
RTL_W8(IntrStatus, sts & ~(TxErr | RxErr | SYSErr));
|
||||
if (rtl_is_8125(pplat)) {
|
||||
sts = RTL_R32(IntrStatus_8125);
|
||||
RTL_W32(IntrStatus_8125, sts & ~(TxErr | RxErr | SYSErr));
|
||||
} else {
|
||||
sts = RTL_R16(IntrStatus_8169);
|
||||
RTL_W16(IntrStatus_8169, sts & ~(TxErr | RxErr | SYSErr));
|
||||
}
|
||||
udelay(100); /* wait */
|
||||
}
|
||||
tpc->cur_rx = cur_rx;
|
||||
@@ -636,8 +687,8 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase,
|
||||
((len > ETH_ZLEN) ? len : ETH_ZLEN));
|
||||
}
|
||||
rtl_flush_tx_desc(&tpc->TxDescArray[entry]);
|
||||
if (pplat->device == 0x8125)
|
||||
RTL_W8(TxPoll_8125, 0x1); /* set polling bit */
|
||||
if (rtl_is_8125(pplat))
|
||||
RTL_W32(TxPoll_8125, 0x1); /* set polling bit */
|
||||
else
|
||||
RTL_W8(TxPoll_8169, 0x40); /* set polling bit */
|
||||
|
||||
@@ -697,6 +748,8 @@ static void rtl8169_set_rx_mode(void)
|
||||
|
||||
static void rtl8169_hw_start(struct udevice *dev)
|
||||
{
|
||||
u8 version = rtl_chip_info[tpc->chipset].version;
|
||||
u16 tx_desc_mode;
|
||||
u32 i;
|
||||
|
||||
#ifdef DEBUG_RTL8169
|
||||
@@ -719,6 +772,36 @@ static void rtl8169_hw_start(struct udevice *dev)
|
||||
|
||||
RTL_W8(Cfg9346, Cfg9346_Unlock);
|
||||
|
||||
/*
|
||||
* RTL8125D/8126A/8127A require explicit descriptor-type and CRC-drop setup.
|
||||
* RTL8125B (0x64) is intentionally excluded to avoid regressing working hardware.
|
||||
*/
|
||||
switch (version) {
|
||||
case 0x6a:
|
||||
case 0x66:
|
||||
case 0x6e:
|
||||
/* Reg 0xD8: Disable CRC drop and force legacy 16-byte RX desc */
|
||||
RTL_W8(RX_DESC_MODE, RTL_R8(RX_DESC_MODE) & ~(RX_DESC_CRC_DROP | RX_DESC_TYPE));
|
||||
|
||||
/* RxConfig 0x44: enable RX pause slot (RTL8125B and later) */
|
||||
RTL_W32(RxConfig, RTL_R32(RxConfig) | RX_PAUSE_SLOT_ON);
|
||||
|
||||
/* MAC OCP 0xEB58: TX descriptor format setup */
|
||||
tx_desc_mode = rtl_mac_ocp_read(TX_DESC_MODE) & ~TX_DESC_FMT_MASK;
|
||||
|
||||
if (version == 0x6e) {
|
||||
/* RTL8127A specific: Tx desc V3 and RADM FIFO protection */
|
||||
rtl_mac_ocp_write(TX_DESC_MODE, tx_desc_mode | TX_DESC_FMT_V3);
|
||||
RTL_W16(RADMFIFO_PROTECT, 0x2001);
|
||||
} else {
|
||||
/* RTL8125D / RTL8126A specific: standard Tx desc */
|
||||
rtl_mac_ocp_write(TX_DESC_MODE, tx_desc_mode | TX_DESC_FMT_STD);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* RTL-8169sb/8110sb or previous version */
|
||||
if (tpc->chipset <= 5)
|
||||
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
|
||||
@@ -860,8 +943,8 @@ static void rtl_halt_common(struct udevice *dev)
|
||||
RTL_W8(ChipCmd, 0x00);
|
||||
|
||||
/* Disable interrupts by clearing the interrupt mask. */
|
||||
if (pplat->device == 0x8125)
|
||||
RTL_W16(IntrMask_8125, 0x0000);
|
||||
if (rtl_is_8125(pplat))
|
||||
RTL_W32(IntrMask_8125, 0x00000000);
|
||||
else
|
||||
RTL_W16(IntrMask_8169, 0x0000);
|
||||
|
||||
@@ -1052,6 +1135,8 @@ static int rtl8169_eth_probe(struct udevice *dev)
|
||||
|
||||
switch (pplat->device) {
|
||||
case 0x8125:
|
||||
case 0x8126:
|
||||
case 0x8127:
|
||||
case 0x8161:
|
||||
case 0x8168:
|
||||
region = 2;
|
||||
|
||||
@@ -431,11 +431,6 @@ static int smc911x_read_rom_hwaddr(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smc911x_bind(struct udevice *dev)
|
||||
{
|
||||
return device_set_name(dev, dev->name);
|
||||
}
|
||||
|
||||
static int smc911x_probe(struct udevice *dev)
|
||||
{
|
||||
struct smc911x_priv *priv = dev_get_priv(dev);
|
||||
@@ -487,7 +482,6 @@ U_BOOT_DRIVER(smc911x) = {
|
||||
.name = "eth_smc911x",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = smc911x_ids,
|
||||
.bind = smc911x_bind,
|
||||
.of_to_plat = smc911x_of_to_plat,
|
||||
.probe = smc911x_probe,
|
||||
.ops = &smc911x_ops,
|
||||
|
||||
@@ -53,6 +53,7 @@ bool wget_validate_uri(char *uri);
|
||||
|
||||
int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
|
||||
int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
|
||||
int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
|
||||
int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
|
||||
|
||||
#endif /* __NET_LWIP_H__ */
|
||||
|
||||
@@ -72,6 +72,17 @@
|
||||
#define PBUF_POOL_RESERVE 4
|
||||
#define TFTP_BLOCKSIZE_THRESHOLD 4096
|
||||
|
||||
/*
|
||||
* Match the legacy U-Boot TFTP filename buffer. The legacy
|
||||
* CONFIG_TFTP_FILE_NAME_MAX_LEN value is a buffer size including the trailing
|
||||
* NUL, while lwIP's TFTP_MAX_FILENAME_LEN is the usable string length.
|
||||
*/
|
||||
#ifdef CONFIG_TFTP_FILE_NAME_MAX_LEN
|
||||
#define TFTP_MAX_FILENAME_LEN (CONFIG_TFTP_FILE_NAME_MAX_LEN - 1)
|
||||
#else
|
||||
#define TFTP_MAX_FILENAME_LEN 127
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TFTP_BLOCKSIZE) && (CONFIG_TFTP_BLOCKSIZE > TFTP_BLOCKSIZE_THRESHOLD)
|
||||
#define PBUF_POOL_SIZE (((CONFIG_TFTP_BLOCKSIZE + (IP_FRAG_MTU_USABLE - 1)) / \
|
||||
IP_FRAG_MTU_USABLE) + PBUF_POOL_HEADROOM)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ static char boot_file_name[DHCP_BOOT_FILE_LEN];
|
||||
static void call_lwip_dhcp_fine_tmr(void *ctx)
|
||||
{
|
||||
dhcp_fine_tmr();
|
||||
sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
|
||||
sys_timeout(DHCP_FINE_TIMER_MSECS, call_lwip_dhcp_fine_tmr, NULL);
|
||||
}
|
||||
|
||||
static int dhcp_loop(struct udevice *udev)
|
||||
|
||||
+32
-13
@@ -40,28 +40,47 @@ char *pxelinux_configfile;
|
||||
static err_t net_lwip_tx(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct udevice *udev = netif->state;
|
||||
void *pp = NULL;
|
||||
bool pp_allocated = false;
|
||||
u32 plen;
|
||||
void *pp;
|
||||
int err;
|
||||
|
||||
if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
|
||||
printf("net_lwip_tx: %u bytes, udev %s\n", p->len, udev->name);
|
||||
print_hex_dump("net_lwip_tx: ", 0, 16, 1, p->payload, p->len,
|
||||
true);
|
||||
}
|
||||
|
||||
if ((unsigned long)p->payload % PKTALIGN) {
|
||||
if ((unsigned long)p->payload % PKTALIGN || p->len != p->tot_len) {
|
||||
/*
|
||||
* Some net drivers have strict alignment requirements and may
|
||||
* fail or output invalid data if the packet is not aligned.
|
||||
*
|
||||
* A packet may also be stored in multiple chained pbufs. In
|
||||
* this case, assemble the fragments into one contiguous packet
|
||||
* buffer before passing it to the Ethernet driver.
|
||||
*/
|
||||
pp = memalign(PKTALIGN, p->len);
|
||||
|
||||
pp = memalign(PKTALIGN, p->tot_len);
|
||||
if (!pp)
|
||||
return ERR_ABRT;
|
||||
memcpy(pp, p->payload, p->len);
|
||||
return ERR_MEM;
|
||||
|
||||
pp_allocated = true;
|
||||
|
||||
plen = pbuf_copy_partial(p, pp, p->tot_len, 0);
|
||||
if (plen != p->tot_len) {
|
||||
free(pp);
|
||||
return ERR_BUF;
|
||||
}
|
||||
} else {
|
||||
pp = p->payload;
|
||||
plen = p->len;
|
||||
}
|
||||
|
||||
err = eth_get_ops(udev)->send(udev, pp ? pp : p->payload, p->len);
|
||||
free(pp);
|
||||
if (CONFIG_IS_ENABLED(LWIP_DEBUG_RXTX)) {
|
||||
printf("net_lwip_tx: %u bytes, udev %s\n", plen, udev->name);
|
||||
print_hex_dump("net_lwip_tx: ", 0, 16, 1, pp, plen, true);
|
||||
}
|
||||
|
||||
err = eth_get_ops(udev)->send(udev, pp, plen);
|
||||
|
||||
if (pp_allocated)
|
||||
free(pp);
|
||||
|
||||
if (err) {
|
||||
debug("send error %d\n", err);
|
||||
return ERR_ABRT;
|
||||
|
||||
+183
-5
@@ -11,6 +11,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <lwip/apps/tftp_client.h>
|
||||
#include <lwip/apps/tftp_server.h>
|
||||
#include <lwip/timeouts.h>
|
||||
#include <mapmem.h>
|
||||
#include <net.h>
|
||||
@@ -19,6 +20,8 @@
|
||||
#define PROGRESS_PRINT_STEP_BYTES (10 * 1024)
|
||||
/* Max time to wait for first data packet from server */
|
||||
#define NO_RSP_TIMEOUT_MS 10000
|
||||
/* Max time to wait for an incoming TFTP write request */
|
||||
#define TFTPSRV_LISTEN_TIMEOUT_MS 50000
|
||||
|
||||
enum done_state {
|
||||
NOT_DONE = 0,
|
||||
@@ -34,8 +37,31 @@ struct tftp_ctx {
|
||||
ulong hash_count;
|
||||
ulong start_time;
|
||||
enum done_state done;
|
||||
bool is_server;
|
||||
bool wrq_accepted;
|
||||
char fname[TFTP_MAX_FILENAME_LEN + 1];
|
||||
};
|
||||
|
||||
/*
|
||||
* The lwIP TFTP server open callback has no user-data argument. Keep the
|
||||
* current server context here so tftp_open() can return it.
|
||||
*/
|
||||
static struct tftp_ctx *tftpsrv_active_ctx;
|
||||
|
||||
static void transfer_timeout(void *arg)
|
||||
{
|
||||
struct tftp_ctx *ctx = (struct tftp_ctx *)arg;
|
||||
|
||||
printf("Timeout!\n");
|
||||
ctx->done = FAILURE;
|
||||
}
|
||||
|
||||
static void restart_transfer_timeout(struct tftp_ctx *ctx)
|
||||
{
|
||||
sys_untimeout(transfer_timeout, ctx);
|
||||
sys_timeout(TFTP_TIMEOUT_MSECS, transfer_timeout, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* store_block() - copy received data
|
||||
*
|
||||
@@ -71,7 +97,7 @@ static int store_block(struct tftp_ctx *ctx, void *src, u16_t len)
|
||||
ctx->size += len;
|
||||
ctx->block_count++;
|
||||
|
||||
tftp_tsize = tftp_client_get_tsize();
|
||||
tftp_tsize = ctx->is_server ? 0 : tftp_client_get_tsize();
|
||||
if (tftp_tsize) {
|
||||
pos = clamp(ctx->size, 0UL, tftp_tsize);
|
||||
|
||||
@@ -92,7 +118,20 @@ static int store_block(struct tftp_ctx *ctx, void *src, u16_t len)
|
||||
|
||||
static void *tftp_open(const char *fname, const char *mode, u8_t is_write)
|
||||
{
|
||||
return NULL;
|
||||
struct tftp_ctx *ctx = tftpsrv_active_ctx;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_CMD_TFTPSRV) || !ctx || !is_write)
|
||||
return NULL;
|
||||
|
||||
ctx->wrq_accepted = true;
|
||||
ctx->start_time = get_timer(0);
|
||||
snprintf(ctx->fname, sizeof(ctx->fname), "%s", fname);
|
||||
restart_transfer_timeout(ctx);
|
||||
|
||||
printf("\nReceiving '%s' mode '%s'\n", fname, mode);
|
||||
puts("Loading: ");
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void tftp_close(void *handle)
|
||||
@@ -101,13 +140,15 @@ static void tftp_close(void *handle)
|
||||
ulong tftp_tsize;
|
||||
ulong elapsed;
|
||||
|
||||
sys_untimeout(transfer_timeout, ctx);
|
||||
|
||||
if (ctx->done == FAILURE || ctx->done == ABORTED) {
|
||||
/* Closing after an error or Ctrl-C */
|
||||
return;
|
||||
}
|
||||
ctx->done = SUCCESS;
|
||||
|
||||
tftp_tsize = tftp_client_get_tsize();
|
||||
tftp_tsize = ctx->is_server ? 0 : tftp_client_get_tsize();
|
||||
if (tftp_tsize) {
|
||||
/* Print hash marks for the last packet received */
|
||||
while (ctx->hash_count < 49) {
|
||||
@@ -142,9 +183,14 @@ static int tftp_write(void *handle, struct pbuf *p)
|
||||
struct tftp_ctx *ctx = handle;
|
||||
struct pbuf *q;
|
||||
|
||||
for (q = p; q; q = q->next)
|
||||
if (store_block(ctx, q->payload, q->len) < 0)
|
||||
for (q = p; q; q = q->next) {
|
||||
if (store_block(ctx, q->payload, q->len) < 0) {
|
||||
ctx->done = FAILURE;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
restart_transfer_timeout(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -204,6 +250,9 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
|
||||
ctx.block_count = 0;
|
||||
ctx.hash_count = 0;
|
||||
ctx.daddr = addr;
|
||||
ctx.is_server = false;
|
||||
ctx.wrq_accepted = false;
|
||||
ctx.fname[0] = '\0';
|
||||
|
||||
printf("Using %s device\n", udev->name);
|
||||
printf("TFTP from server %s; our IP address is %s\n",
|
||||
@@ -258,6 +307,135 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void no_request(void *arg)
|
||||
{
|
||||
struct tftp_ctx *ctx = (struct tftp_ctx *)arg;
|
||||
|
||||
if (ctx->wrq_accepted)
|
||||
return;
|
||||
|
||||
printf("Timeout!\n");
|
||||
ctx->done = FAILURE;
|
||||
}
|
||||
|
||||
static int tftpsrv_loop(struct udevice *udev, ulong addr)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct tftp_ctx ctx;
|
||||
const char *ipaddr;
|
||||
int ret = -1;
|
||||
err_t err;
|
||||
|
||||
if (addr == 0)
|
||||
return -1;
|
||||
|
||||
ipaddr = env_get("ipaddr");
|
||||
if (!ipaddr || !*ipaddr) {
|
||||
log_err("error: ipaddr has to be set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
netif = net_lwip_new_netif(udev);
|
||||
if (!netif)
|
||||
return -1;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.done = NOT_DONE;
|
||||
ctx.daddr = addr;
|
||||
ctx.is_server = true;
|
||||
|
||||
printf("Using %s device\n", udev->name);
|
||||
printf("Listening for TFTP transfer on %s\n", ipaddr);
|
||||
printf("Load address: 0x%lx\n", ctx.daddr);
|
||||
|
||||
tftpsrv_active_ctx = &ctx;
|
||||
err = tftp_init_server(&tftp_context);
|
||||
if (err != ERR_OK) {
|
||||
log_err("tftp_init_server err: %d\n", err);
|
||||
goto out_remove_netif;
|
||||
}
|
||||
|
||||
ctx.start_time = get_timer(0);
|
||||
sys_timeout(TFTPSRV_LISTEN_TIMEOUT_MS, no_request, &ctx);
|
||||
while (!ctx.done) {
|
||||
net_lwip_rx(udev, netif);
|
||||
if (ctrlc()) {
|
||||
printf("\nAbort\n");
|
||||
ctx.done = ABORTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sys_untimeout(no_request, &ctx);
|
||||
sys_untimeout(transfer_timeout, &ctx);
|
||||
|
||||
tftp_cleanup();
|
||||
|
||||
if (ctx.done == SUCCESS) {
|
||||
if (env_set_hex("fileaddr", addr)) {
|
||||
log_err("fileaddr not updated\n");
|
||||
goto out_remove_netif;
|
||||
}
|
||||
efi_set_bootdev("Net", "", ctx.fname, map_sysmem(addr, 0),
|
||||
ctx.size);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out_remove_netif:
|
||||
tftpsrv_active_ctx = NULL;
|
||||
net_lwip_remove_netif(netif);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
char *end;
|
||||
ulong laddr;
|
||||
ulong addr;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_CMD_TFTPSRV))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
laddr = env_get_ulong("loadaddr", 16, image_load_addr);
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
addr = hextoul(argv[1], &end);
|
||||
if (end == argv[1] || *end) {
|
||||
ret = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
laddr = addr;
|
||||
break;
|
||||
default:
|
||||
ret = CMD_RET_USAGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!laddr) {
|
||||
log_err("error: no load address\n");
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (net_lwip_eth_start() < 0) {
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tftpsrv_loop(eth_get_dev(), laddr) < 0)
|
||||
ret = CMD_RET_FAILURE;
|
||||
else
|
||||
image_load_addr = laddr;
|
||||
net_lwip_eth_stop();
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
|
||||
@@ -1076,6 +1076,8 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
|
||||
} else if (h >= thisfrag) {
|
||||
/* overlaps with initial part of the hole: move this hole */
|
||||
newh = thisfrag + (len / 8);
|
||||
if ((uchar *)(newh + 1) > pkt_buff + IP_PKTSIZE)
|
||||
return NULL; /* hole descriptor would overflow pkt_buff */
|
||||
*newh = *h;
|
||||
h = newh;
|
||||
if (h->next_hole)
|
||||
@@ -1088,6 +1090,8 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
|
||||
} else {
|
||||
/* fragment sits in the middle: split the hole */
|
||||
newh = thisfrag + (len / 8);
|
||||
if ((uchar *)(newh + 1) > pkt_buff + IP_PKTSIZE)
|
||||
return NULL; /* hole descriptor would overflow pkt_buff */
|
||||
*newh = *h;
|
||||
h->last_byte = start;
|
||||
h->next_hole = (newh - payload);
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ static inline void srand_mac(void)
|
||||
|
||||
if (CONFIG_IS_ENABLED(DM_RNG)) {
|
||||
ret = uclass_get_device(UCLASS_RNG, 0, &devp);
|
||||
if (ret) {
|
||||
if (!ret) {
|
||||
ret = dm_rng_read(devp, &randv, sizeof(randv));
|
||||
if (ret < 0)
|
||||
randv = 0;
|
||||
|
||||
+9
-3
@@ -671,18 +671,24 @@ static int nfs_readlink_reply(uchar *pkt, unsigned int len)
|
||||
|
||||
if (*((char *)&rpc_pkt.u.reply.data[2 + nfsv3_data_offset]) != '/') {
|
||||
int pathlen;
|
||||
int new_len;
|
||||
|
||||
strcat(nfs_path, "/");
|
||||
pathlen = strlen(nfs_path);
|
||||
if (pathlen + rlen >= sizeof(nfs_path_buff))
|
||||
new_len = pathlen + rlen;
|
||||
if (new_len >= sizeof(nfs_path_buff)) {
|
||||
printf("NFS: symlink too long (%d bytes)\n", new_len);
|
||||
return -NFS_RPC_DROP;
|
||||
}
|
||||
memcpy(nfs_path + pathlen,
|
||||
(uchar *)&rpc_pkt.u.reply.data[2 + nfsv3_data_offset],
|
||||
rlen);
|
||||
nfs_path[pathlen + rlen] = 0;
|
||||
nfs_path[new_len] = 0;
|
||||
} else {
|
||||
if (rlen >= sizeof(nfs_path_buff))
|
||||
if (rlen >= sizeof(nfs_path_buff)) {
|
||||
printf("NFS: symlink too long (%d bytes)\n", rlen);
|
||||
return -NFS_RPC_DROP;
|
||||
}
|
||||
memcpy(nfs_path,
|
||||
(uchar *)&rpc_pkt.u.reply.data[2 + nfsv3_data_offset],
|
||||
rlen);
|
||||
|
||||
@@ -80,3 +80,39 @@ static int dm_test_net_ip_defrag_dup_last(struct unit_test_state *uts)
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_net_ip_defrag_dup_last, 0);
|
||||
|
||||
/*
|
||||
* A fragment placed at the very top of the reassembly buffer takes the
|
||||
* split-hole branch, which writes an 8-byte "struct hole" at
|
||||
* pkt_buff + IP_HDR_SIZE + (offset8 + len / 8) * 8. With start + len equal to
|
||||
* IP_MAXUDP that write reaches the end of pkt_buff and spills past it. pkt_buff
|
||||
* is a static array, so this is flagged under AddressSanitizer; the fix rejects
|
||||
* such a fragment instead. The datagram is incomplete, so nothing is delivered
|
||||
* either way.
|
||||
*/
|
||||
static int dm_test_net_ip_defrag_oob(struct unit_test_state *uts)
|
||||
{
|
||||
rxhand_f *saved_handler = net_get_udp_handler();
|
||||
uchar frame[FRAME_LEN];
|
||||
struct ip_udp_hdr *ip = (struct ip_udp_hdr *)(frame + ETHER_HDR_SIZE);
|
||||
u16 payload[4] = { 0, 0, 0, 0 };
|
||||
/* Offset (8-byte units) so that start + FRAG_LEN == IP_MAXUDP. */
|
||||
u16 off8 = (CONFIG_NET_MAXDEFRAG - IP_HDR_SIZE - FRAG_LEN) / 8;
|
||||
|
||||
udp_rx_count = 0;
|
||||
net_set_udp_handler(defrag_udp_handler);
|
||||
|
||||
build_frag(frame, IP_FLAGS_MFRAG | off8, payload);
|
||||
/* A distinct id forces a fresh reassembly independent of earlier tests. */
|
||||
ip->ip_id = htons(0x7abc);
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
|
||||
net_process_received_packet(frame, FRAME_LEN);
|
||||
|
||||
ut_asserteq(0, udp_rx_count);
|
||||
|
||||
net_set_udp_handler(saved_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_net_ip_defrag_oob, 0);
|
||||
|
||||
@@ -59,6 +59,19 @@ For example:
|
||||
'fnu': 'ubtest-upload.bin',
|
||||
}
|
||||
|
||||
# Details regarding a file that may be written to U-Boot using the tftpsrv
|
||||
# command. This variable may be omitted or set to None if tftpsrv testing
|
||||
# is not possible or desired. The test uses host-side curl TFTP support to
|
||||
# upload a generated file to U-Boot. The optional tftpsrv_url entry may be
|
||||
# used when the host must use a forwarded address instead of U-Boot's
|
||||
# ipaddr value.
|
||||
env__net_tftpsrv_file = {
|
||||
'fn': 'ubtest-tftpsrv.bin',
|
||||
'addr': 0x10000000,
|
||||
'size': 4096,
|
||||
'timeout': 50000,
|
||||
}
|
||||
|
||||
# Details regarding a file that may be read from a NFS server. This variable
|
||||
# may be omitted or set to None if NFS testing is not possible or desired.
|
||||
env__net_nfs_readable_file = {
|
||||
@@ -89,6 +102,8 @@ import utils
|
||||
import uuid
|
||||
import datetime
|
||||
import re
|
||||
import tempfile
|
||||
import zlib
|
||||
|
||||
net_set_up = False
|
||||
net6_set_up = False
|
||||
@@ -460,3 +475,82 @@ def test_net_tftpput(ubman):
|
||||
|
||||
output = ubman.run_command("crc32 $fileaddr $filesize")
|
||||
assert expected_tftpb_crc in output
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec("cmd_crc32")
|
||||
@pytest.mark.buildconfigspec("cmd_tftpsrv")
|
||||
@pytest.mark.requiredtool("curl")
|
||||
def test_net_tftpsrv(ubman):
|
||||
"""Test the tftpsrv command.
|
||||
|
||||
A file is generated on the host, uploaded to U-Boot using TFTP and then
|
||||
validated in U-Boot using its size and CRC32.
|
||||
|
||||
The details of the file to upload are provided by the boardenv_* file;
|
||||
see the comment at the beginning of this file.
|
||||
"""
|
||||
|
||||
if not net_set_up:
|
||||
pytest.skip("Network not initialized")
|
||||
|
||||
f = ubman.config.env.get("env__net_tftpsrv_file", None)
|
||||
if not f:
|
||||
pytest.skip("No tftpsrv file to write")
|
||||
|
||||
curl_version = utils.run_and_log(ubman, ["curl", "--version"])
|
||||
if "tftp" not in curl_version.split():
|
||||
pytest.skip("curl does not support TFTP")
|
||||
|
||||
addr = f.get("addr", None)
|
||||
if not addr:
|
||||
addr = utils.find_ram_base(ubman)
|
||||
|
||||
timeout = f.get("timeout", ubman.p.timeout)
|
||||
timeout_secs = max(1, (timeout + 999) // 1000)
|
||||
size = f.get("size", 4096)
|
||||
fn = f.get("fn", "ubtest-tftpsrv.bin")
|
||||
url = f.get("tftpsrv_url", None)
|
||||
data = bytes([i % 251 for i in range(size)])
|
||||
crc = "%08x" % (zlib.crc32(data) & 0xffffffff)
|
||||
|
||||
ip = ubman.run_command("echo $ipaddr").strip()
|
||||
if not ip:
|
||||
pytest.skip("No U-Boot IP address")
|
||||
if not url:
|
||||
url = "tftp://%s/%s" % (ip, fn)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as tmp:
|
||||
tmp.write(data)
|
||||
tmp.flush()
|
||||
|
||||
done = False
|
||||
with ubman.temporary_timeout(timeout):
|
||||
try:
|
||||
ubman.run_command("tftpsrv %x" % addr,
|
||||
wait_for_prompt=False)
|
||||
ubman.wait_for("Listening for TFTP transfer")
|
||||
utils.run_and_log(
|
||||
ubman,
|
||||
[
|
||||
"curl",
|
||||
"--fail",
|
||||
"--max-time",
|
||||
str(timeout_secs),
|
||||
"--upload-file",
|
||||
tmp.name,
|
||||
url,
|
||||
],
|
||||
)
|
||||
ubman.wait_for("Bytes transferred = %d" % size)
|
||||
ubman.wait_for(ubman.prompt)
|
||||
done = True
|
||||
finally:
|
||||
if not done:
|
||||
ubman.ctrlc()
|
||||
ubman.drain_console()
|
||||
|
||||
output = ubman.run_command("echo $filesize")
|
||||
assert "%x" % size in output
|
||||
|
||||
output = ubman.run_command("crc32 $fileaddr $filesize")
|
||||
assert crc in output
|
||||
|
||||
Reference in New Issue
Block a user