Merge tag 'net-20260623' of https://source.denx.de/u-boot/custodians/u-boot-net
Pull request net-20260623. net: - airoha_eth: fix mt7531 mdio related initialization bug net-legacy: - cdp: reject CDP TLVs with a length below the 4-byte header - Clear IP defragmentation state after returning a complete packet net-lwip: - Halt ethernet after network commands
This commit is contained in:
+11
-8
@@ -163,6 +163,7 @@ static int ping_loop(struct udevice *udev, const ip_addr_t *addr)
|
||||
int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
ip_addr_t addr;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
@@ -171,13 +172,15 @@ int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
net_try_count = 1;
|
||||
restart:
|
||||
if (net_lwip_eth_start() < 0 || ping_loop(eth_get_dev(), &addr) < 0) {
|
||||
if (net_start_again() == 0)
|
||||
goto restart;
|
||||
else
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
do {
|
||||
if (net_lwip_eth_start() == 0) {
|
||||
ret = ping_loop(eth_get_dev(), &addr);
|
||||
net_lwip_eth_stop();
|
||||
if (ret == 0)
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
} while (net_start_again() == 0);
|
||||
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
+8
-2
@@ -101,6 +101,7 @@ int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
ip_addr_t *srvip;
|
||||
char *server;
|
||||
ip_addr_t ipaddr;
|
||||
int ret = CMD_RET_FAILURE;
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
@@ -127,7 +128,12 @@ int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (sntp_loop(eth_get_dev(), srvip) < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
goto out;
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
ret = CMD_RET_SUCCESS;
|
||||
|
||||
out:
|
||||
net_lwip_eth_stop();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+48
-30
@@ -845,11 +845,45 @@ static int airoha_alloc_gdm_port(struct udevice *dev, ofnode node)
|
||||
(ulong)eth, node, &gdm_dev);
|
||||
}
|
||||
|
||||
static struct udevice *airoha_switch_mdio_init(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
|
||||
ofnode switch_node, mdio_node;
|
||||
struct udevice *mdio_dev;
|
||||
int ret;
|
||||
|
||||
if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO))
|
||||
return NULL;
|
||||
|
||||
switch_node = ofnode_by_compatible(ofnode_null(),
|
||||
data->switch_compatible);
|
||||
if (!ofnode_valid(switch_node)) {
|
||||
debug("Warning: missing airoha switch node\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
mdio_node = ofnode_find_subnode(switch_node, "mdio");
|
||||
if (!ofnode_valid(mdio_node)) {
|
||||
debug("Warning: missing airoha switch mdio subnode\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio",
|
||||
mdio_node, &mdio_dev);
|
||||
if (ret) {
|
||||
debug("Warning: failed to bind airoha switch mdio\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return mdio_dev;
|
||||
}
|
||||
|
||||
static int airoha_eth_probe(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct regmap *scu_regmap;
|
||||
struct udevice *mdio_dev;
|
||||
ofnode node;
|
||||
int i, ret;
|
||||
|
||||
@@ -908,10 +942,10 @@ static int airoha_eth_probe(struct udevice *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (eth->switch_mdio_dev) {
|
||||
if (!device_probe(eth->switch_mdio_dev))
|
||||
debug("Warning: failed to probe airoha switch mdio\n");
|
||||
}
|
||||
/* Airoha switch mdio PHYs maybe used by several GDM devices */
|
||||
mdio_dev = airoha_switch_mdio_init(dev);
|
||||
if (!IS_ERR_OR_NULL(mdio_dev))
|
||||
eth->switch_mdio_dev = mdio_dev;
|
||||
|
||||
ofnode_for_each_subnode(node, dev_ofnode(dev)) {
|
||||
if (!ofnode_device_is_compatible(node, "airoha,eth-mac"))
|
||||
@@ -957,6 +991,16 @@ static int airoha_eth_port_probe(struct udevice *dev)
|
||||
#else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* GDM1 device connected to airoha switch. Probe airoha switch
|
||||
* mdio to be able set/query states of corresponding LAN ports.
|
||||
*/
|
||||
ret = device_probe(eth->switch_mdio_dev);
|
||||
if (ret) {
|
||||
debug("Warning: failed to probe airoha switch mdio\n");
|
||||
eth->switch_mdio_dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1202,38 +1246,12 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
|
||||
|
||||
static int airoha_eth_bind(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
ofnode switch_node, mdio_node;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Force Probe as we set the Main ETH driver as misc
|
||||
* to register multiple eth port for each GDM
|
||||
*/
|
||||
dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
|
||||
|
||||
if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO))
|
||||
return 0;
|
||||
|
||||
switch_node = ofnode_by_compatible(ofnode_null(),
|
||||
data->switch_compatible);
|
||||
if (!ofnode_valid(switch_node)) {
|
||||
debug("Warning: missing switch node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mdio_node = ofnode_find_subnode(switch_node, "mdio");
|
||||
if (!ofnode_valid(mdio_node)) {
|
||||
debug("Warning: missing mdio node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio",
|
||||
mdio_node, ð->switch_mdio_dev);
|
||||
if (ret)
|
||||
debug("Warning: failed to bind mdio controller\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ int eth_init_state_only(void); /* Set active state */
|
||||
|
||||
int net_lwip_dns_init(void);
|
||||
int net_lwip_eth_start(void);
|
||||
void net_lwip_eth_stop(void);
|
||||
struct netif *net_lwip_new_netif(struct udevice *udev);
|
||||
struct netif *net_lwip_new_netif_noip(struct udevice *udev);
|
||||
void net_lwip_remove_netif(struct netif *netif);
|
||||
|
||||
@@ -276,7 +276,13 @@ void cdp_receive(const uchar *pkt, unsigned len)
|
||||
ss = (const ushort *)pkt;
|
||||
type = ntohs(ss[0]);
|
||||
tlen = ntohs(ss[1]);
|
||||
if (tlen > len)
|
||||
/*
|
||||
* tlen includes the 4-byte TLV header, so it must be at
|
||||
* least 4. Without this check a crafted tlen < 4 makes the
|
||||
* "tlen -= 4" below underflow (tlen is a ushort), and a tlen
|
||||
* of 0 also fails to advance pkt/len, hanging the loop.
|
||||
*/
|
||||
if (tlen < 4 || tlen > len)
|
||||
goto pkt_short;
|
||||
|
||||
pkt += tlen;
|
||||
|
||||
+11
-4
@@ -138,18 +138,25 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
dev = eth_get_dev();
|
||||
if (!dev) {
|
||||
log_err("No network device\n");
|
||||
return CMD_RET_FAILURE;
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dhcp_loop(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
if (argc > 1) {
|
||||
struct cmd_tbl cmdtp = {};
|
||||
|
||||
return do_tftpb(&cmdtp, 0, argc, argv);
|
||||
ret = do_tftpb(&cmdtp, 0, argc, argv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
ret = CMD_RET_SUCCESS;
|
||||
|
||||
out:
|
||||
net_lwip_eth_stop();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+6
-1
@@ -91,6 +91,7 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
char *name;
|
||||
char *var = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
return CMD_RET_USAGE;
|
||||
@@ -103,5 +104,9 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
if (net_lwip_eth_start() < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return dns_loop(eth_get_dev(), name, var);
|
||||
ret = dns_loop(eth_get_dev(), name, var);
|
||||
|
||||
net_lwip_eth_stop();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ void (*push_packet)(void *, int len) = 0;
|
||||
int net_try_count;
|
||||
static int net_restarted;
|
||||
int net_restart_wrap;
|
||||
static int net_lwip_eth_started;
|
||||
static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN]
|
||||
__aligned(PKTALIGN);
|
||||
const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
@@ -180,11 +181,15 @@ int net_lwip_eth_start(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (net_lwip_eth_started++ > 0)
|
||||
return 0;
|
||||
|
||||
net_init();
|
||||
eth_halt();
|
||||
eth_set_current();
|
||||
ret = eth_init();
|
||||
if (ret < 0) {
|
||||
net_lwip_eth_started--;
|
||||
eth_halt();
|
||||
return ret;
|
||||
}
|
||||
@@ -192,6 +197,17 @@ int net_lwip_eth_start(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void net_lwip_eth_stop(void)
|
||||
{
|
||||
if (!net_lwip_eth_started)
|
||||
return;
|
||||
|
||||
if (--net_lwip_eth_started)
|
||||
return;
|
||||
|
||||
eth_halt();
|
||||
}
|
||||
|
||||
static struct netif *new_netif(struct udevice *udev, bool with_ip)
|
||||
{
|
||||
unsigned char enetaddr[ARP_HLEN];
|
||||
|
||||
@@ -187,6 +187,7 @@ static int nfs_loop(struct udevice *udev, ulong addr, char *fname,
|
||||
int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
bool started = false;
|
||||
char *arg = NULL;
|
||||
char *words[2] = { };
|
||||
char *fname = NULL;
|
||||
@@ -281,10 +282,13 @@ int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
started = true;
|
||||
|
||||
if (nfs_loop(eth_get_dev(), laddr, fname, srvip) < 0)
|
||||
ret = CMD_RET_FAILURE;
|
||||
out:
|
||||
if (started)
|
||||
net_lwip_eth_stop();
|
||||
if (arg != net_boot_file_name)
|
||||
free(arg);
|
||||
return ret;
|
||||
|
||||
@@ -261,6 +261,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
|
||||
int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
int ret = CMD_RET_SUCCESS;
|
||||
bool started = false;
|
||||
char *arg = NULL;
|
||||
char *words[3] = { };
|
||||
char *fname = NULL;
|
||||
@@ -365,12 +366,15 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||
ret = CMD_RET_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
started = true;
|
||||
|
||||
if (tftp_loop(eth_get_dev(), laddr, fname, srvip, port) < 0)
|
||||
ret = CMD_RET_FAILURE;
|
||||
else
|
||||
image_load_addr = laddr;
|
||||
out:
|
||||
if (started)
|
||||
net_lwip_eth_stop();
|
||||
if (arg != net_boot_file_name)
|
||||
free(arg);
|
||||
return ret;
|
||||
|
||||
+61
-46
@@ -292,46 +292,22 @@ static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct
|
||||
#if CONFIG_IS_ENABLED(WGET_CACERT)
|
||||
#endif
|
||||
|
||||
int wget_do_request(ulong dst_addr, char *uri)
|
||||
static int wget_handle_request(struct wget_ctx *ctx, bool is_https,
|
||||
struct udevice *udev, struct netif *netif)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(WGET_HTTPS)
|
||||
altcp_allocator_t tls_allocator;
|
||||
#endif
|
||||
httpc_connection_t conn;
|
||||
httpc_state_t *state;
|
||||
struct udevice *udev;
|
||||
struct netif *netif;
|
||||
struct wget_ctx ctx;
|
||||
char *path;
|
||||
bool is_https;
|
||||
|
||||
ctx.daddr = dst_addr;
|
||||
ctx.saved_daddr = dst_addr;
|
||||
ctx.done = NOT_DONE;
|
||||
ctx.size = 0;
|
||||
ctx.prevsize = 0;
|
||||
ctx.start_time = 0;
|
||||
ctx.content_len = 0;
|
||||
ctx.hash_count = 0;
|
||||
|
||||
if (parse_url(uri, ctx.server_name, &ctx.port, &path, &is_https))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (net_lwip_eth_start() < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
if (!wget_info)
|
||||
wget_info = &default_wget_info;
|
||||
|
||||
udev = eth_get_dev();
|
||||
|
||||
netif = net_lwip_new_netif(udev);
|
||||
if (!netif)
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
/* if URL with hostname init dns */
|
||||
if (!ipaddr_aton(ctx.server_name, NULL) && net_lwip_dns_init())
|
||||
return CMD_RET_FAILURE;
|
||||
if (!ipaddr_aton(ctx->server_name, NULL)) {
|
||||
ret = net_lwip_dns_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
#if CONFIG_IS_ENABLED(WGET_HTTPS)
|
||||
@@ -353,7 +329,7 @@ int wget_do_request(ulong dst_addr, char *uri)
|
||||
printf("Error: cacert authentication "
|
||||
"mode is 'required' but no CA "
|
||||
"certificates given\n");
|
||||
return CMD_RET_FAILURE;
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (cacert_auth_mode == AUTH_NONE) {
|
||||
ca = NULL;
|
||||
@@ -374,12 +350,11 @@ int wget_do_request(ulong dst_addr, char *uri)
|
||||
tls_allocator.alloc = &altcp_tls_alloc;
|
||||
tls_allocator.arg =
|
||||
altcp_tls_create_config_client(ca, ca_sz,
|
||||
ctx.server_name);
|
||||
ctx->server_name);
|
||||
|
||||
if (!tls_allocator.arg) {
|
||||
log_err("error: Cannot create a TLS connection\n");
|
||||
net_lwip_remove_netif(netif);
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
conn.altcp_allocator = &tls_allocator;
|
||||
@@ -388,30 +363,70 @@ int wget_do_request(ulong dst_addr, char *uri)
|
||||
|
||||
conn.result_fn = httpc_result_cb;
|
||||
conn.headers_done_fn = httpc_headers_done_cb;
|
||||
ctx.path = path;
|
||||
if (httpc_get_file_dns(ctx.server_name, ctx.port, path, &conn, httpc_recv_cb,
|
||||
&ctx, &state)) {
|
||||
net_lwip_remove_netif(netif);
|
||||
return CMD_RET_FAILURE;
|
||||
if (httpc_get_file_dns(ctx->server_name, ctx->port, ctx->path, &conn,
|
||||
httpc_recv_cb, ctx, &state)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
while (!ctx.done) {
|
||||
while (!ctx->done) {
|
||||
net_lwip_rx(udev, netif);
|
||||
if (ctrlc())
|
||||
break;
|
||||
}
|
||||
|
||||
net_lwip_remove_netif(netif);
|
||||
|
||||
if (ctx.done == SUCCESS)
|
||||
if (ctx->done == SUCCESS)
|
||||
return 0;
|
||||
|
||||
if (errno == EPERM && !wget_info->silent)
|
||||
printf("Certificate verification failed\n");
|
||||
|
||||
return -1;
|
||||
return -errno ?: -EIO;
|
||||
}
|
||||
|
||||
int wget_do_request(ulong dst_addr, char *uri)
|
||||
{
|
||||
struct udevice *udev;
|
||||
struct wget_ctx ctx;
|
||||
struct netif *netif;
|
||||
bool is_https;
|
||||
int ret;
|
||||
|
||||
ctx.daddr = dst_addr;
|
||||
ctx.saved_daddr = dst_addr;
|
||||
ctx.done = NOT_DONE;
|
||||
ctx.size = 0;
|
||||
ctx.prevsize = 0;
|
||||
ctx.start_time = 0;
|
||||
ctx.content_len = 0;
|
||||
ctx.hash_count = 0;
|
||||
|
||||
ret = parse_url(uri, ctx.server_name, &ctx.port, &ctx.path, &is_https);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = net_lwip_eth_start();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!wget_info)
|
||||
wget_info = &default_wget_info;
|
||||
|
||||
udev = eth_get_dev();
|
||||
|
||||
netif = net_lwip_new_netif(udev);
|
||||
if (!netif) {
|
||||
net_lwip_eth_stop();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = wget_handle_request(&ctx, is_https, udev, netif);
|
||||
|
||||
net_lwip_remove_netif(netif);
|
||||
net_lwip_eth_stop();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1103,6 +1103,15 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
|
||||
|
||||
*lenp = total_len + IP_HDR_SIZE;
|
||||
localip->ip_len = htons(*lenp);
|
||||
|
||||
/*
|
||||
* Mark the reassembly state empty so that any further
|
||||
* fragment goes through the normal re-init path and
|
||||
* rebuilds a clean hole list
|
||||
*/
|
||||
total_len = 0;
|
||||
first_hole = 0;
|
||||
|
||||
return localip;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux-emul.o
|
||||
obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
|
||||
obj-y += fdtdec.o
|
||||
obj-$(CONFIG_MTD_RAW_NAND) += nand.o
|
||||
obj-$(CONFIG_IP_DEFRAG) += net_defrag.o
|
||||
obj-$(CONFIG_UT_DM) += nop.o
|
||||
obj-y += ofnode.o
|
||||
obj-y += ofread.o
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Regression test for IP fragment reassembly.
|
||||
*
|
||||
* The test drives the real RX path via net_process_received_packet(). Final IP
|
||||
* fragment (MF=0) is duplicated, crafted payload triggers redelivery of the datagram,
|
||||
* which fails the test for the unfixed code.
|
||||
*/
|
||||
|
||||
#include <net.h>
|
||||
#include <string.h>
|
||||
#include <test/ut.h>
|
||||
#include <dm/test.h>
|
||||
|
||||
#define FRAG_LEN (8)
|
||||
#define PAYLOAD_OFFSET (ETHER_HDR_SIZE + IP_HDR_SIZE)
|
||||
#define FRAME_LEN (PAYLOAD_OFFSET + FRAG_LEN)
|
||||
|
||||
static int udp_rx_count;
|
||||
|
||||
static void defrag_udp_handler(uchar *pkt, unsigned int dport,
|
||||
struct in_addr sip, unsigned int sport,
|
||||
unsigned int len)
|
||||
{
|
||||
udp_rx_count++;
|
||||
}
|
||||
|
||||
static int build_frag(uchar *buf, u16 off_flags, const u16 *payload)
|
||||
{
|
||||
struct ethernet_hdr *et = (struct ethernet_hdr *)buf;
|
||||
struct ip_udp_hdr *ip = (struct ip_udp_hdr *)(buf + ETHER_HDR_SIZE);
|
||||
|
||||
memset(buf, 0, FRAME_LEN);
|
||||
et->et_protlen = htons(PROT_IP);
|
||||
|
||||
ip->ip_hl_v = 0x45;
|
||||
ip->ip_len = htons(IP_HDR_SIZE + FRAG_LEN);
|
||||
ip->ip_id = htons(0x4321);
|
||||
ip->ip_off = htons(off_flags);
|
||||
ip->ip_ttl = 64;
|
||||
ip->ip_p = IPPROTO_UDP;
|
||||
/* Broadcast destination is accepted regardless of net_ip. */
|
||||
ip->ip_dst.s_addr = 0xffffffff;
|
||||
ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
|
||||
|
||||
memcpy(buf + PAYLOAD_OFFSET, payload, FRAG_LEN);
|
||||
|
||||
return FRAME_LEN;
|
||||
}
|
||||
|
||||
static int dm_test_net_ip_defrag_dup_last(struct unit_test_state *uts)
|
||||
{
|
||||
rxhand_f *saved_handler = net_get_udp_handler();
|
||||
uchar frame[FRAME_LEN];
|
||||
/* UDP header, carried by first fragment. */
|
||||
u16 udp_hdr[4] = { htons(5000), htons(5001),
|
||||
htons(UDP_HDR_SIZE + FRAG_LEN), 0 };
|
||||
/*
|
||||
* Second fragment's payload doubles as a fake hole
|
||||
* {last_byte >= FRAG_LEN, next_hole = 0, prev_hole = 0}, so that the
|
||||
* buggy code re-reading it on a duplicate re-delivers the datagram.
|
||||
*/
|
||||
u16 frag_b[4] = { 2 * FRAG_LEN, 0, 0, 0 };
|
||||
|
||||
udp_rx_count = 0;
|
||||
net_set_udp_handler(defrag_udp_handler);
|
||||
|
||||
/* UDP header, offset 0, MF=1; then data, offset 1, MF=0 */
|
||||
net_process_received_packet(frame, build_frag(frame, IP_FLAGS_MFRAG, udp_hdr));
|
||||
net_process_received_packet(frame, build_frag(frame, 1, frag_b));
|
||||
ut_asserteq(1, udp_rx_count);
|
||||
|
||||
/* Duplicate the final fragment: UDP datagram must not be delivered again. */
|
||||
net_process_received_packet(frame, build_frag(frame, 1, frag_b));
|
||||
ut_asserteq(1, udp_rx_count);
|
||||
|
||||
net_set_udp_handler(saved_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_TEST(dm_test_net_ip_defrag_dup_last, 0);
|
||||
Reference in New Issue
Block a user