Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ jobs:
set -euo pipefail
timeout --preserve-status 2m sudo LD_PRELOAD=$PWD/libwolfip.so ping -c 5 10.10.10.1

- name: Testing ICMP loopback smoke (no TUN/TAP)
timeout-minutes: 2
run: |
set -euo pipefail
timeout --preserve-status 2m sudo LD_PRELOAD=$PWD/libwolfip.so ping -4 -n -c 5 127.0.0.1

- name: Install check
run: |
sudo apt-get install -y check
Expand Down
2 changes: 1 addition & 1 deletion config.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#endif

#ifndef WOLFIP_ENABLE_LOOPBACK
#define WOLFIP_ENABLE_LOOPBACK 0
#define WOLFIP_ENABLE_LOOPBACK 1
Comment thread
danielinux marked this conversation as resolved.
Outdated
#endif

/* Enable HTTP server for POSIX builds */
Expand Down
6 changes: 5 additions & 1 deletion src/test/unit/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ Suite *wolf_suite(void)
#if WOLFIP_ENABLE_LOOPBACK
tcase_add_test(tc_utils, test_wolfip_loopback_defaults);
tcase_add_test(tc_utils, test_wolfip_loopback_send_paths);
tcase_add_test(tc_utils, test_wolfip_loopback_poll_paths);
tcase_add_test(tc_utils, test_wolfip_loopback_poll_keeps_pending_on_short_buffer);
tcase_add_test(tc_utils, test_wolfip_loopback_poll_null_container);
tcase_add_test(tc_utils, test_wolfip_loopback_send_drops_oversize);
tcase_add_test(tc_utils, test_wolfip_loopback_send_null_container);
tcase_add_test(tc_utils, test_wolfip_loopback_send_rejects_null_args);
Expand Down Expand Up @@ -770,7 +773,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_regression_syn_on_established_not_silently_processed);
tcase_add_test(tc_proto, test_regression_syn_on_last_ack_not_silently_processed);
tcase_add_test(tc_proto, test_regression_full_txbuf_still_sends_pure_ack);
tcase_add_test(tc_proto, test_regression_loopback_immediate_pure_ack_uses_loopback_ll);
tcase_add_test(tc_proto, test_regression_loopback_pure_ack_uses_deferred_buffer_until_poll);
tcase_add_test(tc_proto, test_regression_loopback_pure_ack_drain_allows_next_send_cycle);
tcase_add_test(tc_proto, test_regression_tcp_tx_desc_payload_len_keeps_descriptor_layout_sanity);
tcase_add_test(tc_proto, test_regression_fast_recovery_cwnd_ssthresh_rfc5681);
tcase_add_test(tc_proto, test_regression_paws_rejects_stale_timestamp);
Expand Down
122 changes: 117 additions & 5 deletions src/test/unit/unit_tests_proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2967,6 +2967,7 @@ START_TEST(test_wolfip_loopback_defaults)
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
ck_assert_ptr_nonnull(loop);
ck_assert_ptr_nonnull(loop->send);
ck_assert_ptr_eq(loop->poll, wolfIP_loopback_poll);
ck_assert_uint_eq(loop->mac[0], 0x02);

wolfIP_ipconfig_get_ex(&s, TEST_LOOPBACK_IF, &ip, &mask, &gw);
Expand Down Expand Up @@ -2998,6 +2999,66 @@ START_TEST(test_wolfip_loopback_send_paths)
ck_assert_int_eq(wolfIP_loopback_send(NULL, frame, sizeof(frame)), -1);
ck_assert_int_eq(wolfIP_loopback_send(loop, NULL, sizeof(frame)), -1);
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, sizeof(frame)), (int)sizeof(frame));
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, sizeof(frame)), 0);
}
Comment thread
danielinux marked this conversation as resolved.
END_TEST

START_TEST(test_wolfip_loopback_poll_paths)
{
struct wolfIP s;
struct wolfIP_ll_dev *loop;
uint8_t tx[16];
uint8_t rx[16];

wolfIP_init(&s);
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
ck_assert_ptr_nonnull(loop);

memset(tx, 0x5A, sizeof(tx));
memset(rx, 0, sizeof(rx));

ck_assert_int_eq(wolfIP_loopback_poll(NULL, rx, sizeof(rx)), 0);
ck_assert_int_eq(wolfIP_loopback_poll(loop, rx, sizeof(rx)), 0);

ck_assert_int_eq(wolfIP_loopback_send(loop, tx, sizeof(tx)), (int)sizeof(tx));
ck_assert_int_eq(wolfIP_loopback_poll(loop, rx, sizeof(rx)), (int)sizeof(rx));
ck_assert_mem_eq(rx, tx, sizeof(tx));
ck_assert_int_eq(wolfIP_loopback_poll(loop, rx, sizeof(rx)), 0);
}
END_TEST

START_TEST(test_wolfip_loopback_poll_keeps_pending_on_short_buffer)
{
struct wolfIP s;
struct wolfIP_ll_dev *loop;
uint8_t tx[16];
uint8_t rx[16];

wolfIP_init(&s);
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
ck_assert_ptr_nonnull(loop);

memset(tx, 0xC3, sizeof(tx));
memset(rx, 0, sizeof(rx));

ck_assert_int_eq(wolfIP_loopback_send(loop, tx, sizeof(tx)), (int)sizeof(tx));
ck_assert_int_eq(wolfIP_loopback_poll(loop, rx, sizeof(rx) - 1U), 0);
ck_assert_int_eq(wolfIP_loopback_poll(loop, rx, sizeof(rx)), (int)sizeof(rx));
ck_assert_mem_eq(rx, tx, sizeof(tx));
}
END_TEST

START_TEST(test_wolfip_loopback_poll_null_container)
Comment thread
danielinux marked this conversation as resolved.
Outdated
{
uintptr_t off = (uintptr_t)offsetof(struct wolfIP, ll_dev);
struct wolfIP_ll_dev *ll;
uint8_t frame[4] = {0};

if (off == 0)
return;

ll = (struct wolfIP_ll_dev *)off;
ck_assert_int_eq(wolfIP_loopback_poll(ll, frame, sizeof(frame)), 0);
}
END_TEST

Expand Down Expand Up @@ -4786,17 +4847,18 @@ START_TEST(test_regression_full_txbuf_still_sends_pure_ack)
}
END_TEST

START_TEST(test_regression_loopback_immediate_pure_ack_uses_loopback_ll)
START_TEST(test_regression_loopback_pure_ack_uses_deferred_buffer_until_poll)
{
struct wolfIP s;
struct tsocket *ts;
struct wolfIP_ll_dev *loop;
struct wolfIP_tcp_seg seg;
uint32_t expected_pending_len;

wolfIP_init(&s);
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
ck_assert_ptr_nonnull(loop);
loop->send = mock_send;
ck_assert_ptr_eq(loop->send, wolfIP_loopback_send);
last_frame_sent_size = 0;
memset(last_frame_sent, 0, sizeof(last_frame_sent));

Expand All @@ -4822,13 +4884,63 @@ START_TEST(test_regression_loopback_immediate_pure_ack_uses_loopback_ll)
seg.ack = ee32(ts->sock.tcp.ack);
seg.hlen = TCP_HEADER_LEN << 2;
seg.flags = TCP_FLAG_ACK;
expected_pending_len = (uint32_t)sizeof(seg) - ETH_HEADER_LEN;

ck_assert_int_eq(tcp_send_empty_immediate(ts, &seg,
(uint32_t)sizeof(seg)), 0);
ck_assert_uint_eq(ts->sock.tcp.last_ack, ts->sock.tcp.ack);
ck_assert_uint_eq(last_frame_sent_size, (uint32_t)sizeof(seg));
ck_assert_mem_eq(seg.ip.eth.dst, loop->mac, 6);
ck_assert_mem_eq(seg.ip.eth.src, loop->mac, 6);
ck_assert_uint_eq(last_frame_sent_size, 0U);
ck_assert_uint_eq(s.loopback_pending_len, expected_pending_len);

(void)wolfIP_poll(&s, 200);
ck_assert_uint_eq(s.loopback_pending_len, 0U);
}
END_TEST

START_TEST(test_regression_loopback_pure_ack_drain_allows_next_send_cycle)
{
struct wolfIP s;
struct tsocket *ts;
struct wolfIP_ll_dev *loop;
struct wolfIP_tcp_seg seg;
uint8_t rx[IP_MTU_MAX];
uint32_t expected_pending_len = (uint32_t)sizeof(seg) - ETH_HEADER_LEN;

wolfIP_init(&s);
loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF);
ck_assert_ptr_nonnull(loop);

ts = &s.tcpsockets[0];
memset(ts, 0, sizeof(*ts));
ts->proto = WI_IPPROTO_TCP;
ts->S = &s;
ts->if_idx = TEST_LOOPBACK_IF;
ts->sock.tcp.state = TCP_ESTABLISHED;
ts->sock.tcp.ack = 100;
ts->sock.tcp.seq = 1000;
ts->sock.tcp.snd_una = 900;
ts->sock.tcp.cwnd = TXBUF_SIZE;
ts->sock.tcp.peer_rwnd = TXBUF_SIZE;
ts->src_port = 1234;
ts->dst_port = 4321;
ts->local_ip = 0x7F000001U;
ts->remote_ip = 0x7F000001U;
memset(&seg, 0, sizeof(seg));
seg.src_port = ee16(ts->src_port);
seg.dst_port = ee16(ts->dst_port);
seg.seq = ee32(ts->sock.tcp.seq);
seg.ack = ee32(ts->sock.tcp.ack);
seg.hlen = TCP_HEADER_LEN << 2;
seg.flags = TCP_FLAG_ACK;

ck_assert_int_eq(tcp_send_empty_immediate(ts, &seg, (uint32_t)sizeof(seg)), 0);
ck_assert_uint_eq(s.loopback_pending_len, expected_pending_len);

ck_assert_int_eq(loop->poll(loop, rx, sizeof(rx)), (int)expected_pending_len);
ck_assert_uint_eq(s.loopback_pending_len, 0U);

ck_assert_int_eq(tcp_send_empty_immediate(ts, &seg, (uint32_t)sizeof(seg)), 0);
ck_assert_uint_eq(s.loopback_pending_len, expected_pending_len);
}
END_TEST

Expand Down
48 changes: 38 additions & 10 deletions src/wolfip.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
#include <stdint.h>
#include <string.h>
#include <stddef.h>
#ifdef WOLF_POSIX
#include <unistd.h>
#include <stdlib.h>
#ifdef WOLF_POSIX
#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
Expand Down Expand Up @@ -1259,6 +1259,10 @@ struct wolfIP {
} arp;
struct arp_pending_entry arp_pending[WOLFIP_ARP_PENDING_MAX];
#endif
#if WOLFIP_ENABLE_LOOPBACK
uint8_t loopback_buf[IP_MTU_MAX];
uint32_t loopback_pending_len;
#endif
};

static inline int tx_has_writable_space(const struct tsocket *t)
Expand Down Expand Up @@ -1365,18 +1369,40 @@ static inline uint32_t tcp_tx_payload_cap(const struct tsocket *t)
static int wolfIP_loopback_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
{
struct wolfIP *s;
uint32_t copy = len;
uint8_t frame[LINK_MTU];
if (!ll || !buf)
return -1;
s = WOLFIP_CONTAINER_OF(ll, struct wolfIP, ll_dev);
if (!s)
return -1;
if (copy > wolfIP_ll_frame_mtu(ll))
if (len > IP_MTU_MAX)
return 0;
if (s->loopback_pending_len > 0)
return 0; /* buffer busy, drop */
/* buf is the IP payload (ETH header already stripped by
* wolfIP_ll_send_frame for non-ethernet devices).
Comment thread
danielinux marked this conversation as resolved.
* Store as-is; wolfIP_poll will re-add the ETH prefix. */
memcpy(s->loopback_buf, buf, len);
s->loopback_pending_len = len;
Comment thread
danielinux marked this conversation as resolved.
Outdated
return (int)len;
}

static int wolfIP_loopback_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len)
{
struct wolfIP *s;
uint32_t pending;
if (!ll)
return 0;
s = WOLFIP_CONTAINER_OF(ll, struct wolfIP, ll_dev);
if (!s)
return 0;
pending = s->loopback_pending_len;
if (pending == 0)
return 0;
if (pending > len)
return 0;
memcpy(frame, buf, copy);
wolfIP_recv_on(s, WOLFIP_LOOPBACK_IF_IDX, frame, copy);
return (int)copy;
s->loopback_pending_len = 0;
memcpy(buf, s->loopback_buf, pending);
return (int)pending;
}
Comment thread
danielinux marked this conversation as resolved.
#endif

Expand Down Expand Up @@ -6634,7 +6660,9 @@ void wolfIP_init(struct wolfIP *s)
memcpy(loop->mac, loop_mac, sizeof(loop_mac));
strncpy(loop->ifname, "lo", sizeof(loop->ifname) - 1);
loop->ifname[sizeof(loop->ifname) - 1] = '\0';
loop->poll = NULL;
loop->non_ethernet = 1;
loop->mtu = LINK_MTU;
loop->poll = wolfIP_loopback_poll;
loop->send = wolfIP_loopback_send;
}
if (loop_conf) {
Comment thread
danielinux marked this conversation as resolved.
Expand Down Expand Up @@ -6705,9 +6733,9 @@ size_t wolfIP_instance_size(void)
return sizeof(struct wolfIP);
}

#if defined(DEBUG)
#if defined(DEBUG) || defined(DEBUG_ETH) || defined(DEBUG_IP) || defined(DEBUG_UDP)
#include "src/wolfip_debug.c"
#endif /* DEBUG */
#endif /* DEBUG || DEBUG_ETH || DEBUG_IP || DEBUG_UDP */

static inline void ip_recv(struct wolfIP *s, unsigned int if_idx,
struct wolfIP_ip_packet *ip, uint32_t len)
Expand Down
1 change: 0 additions & 1 deletion wolfip.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ typedef uint32_t ip4;
#define PACKED __attribute__((packed))
#define ee16(x) __builtin_bswap16(x)
#define ee32(x) __builtin_bswap32(x)
#define DEBUG

Comment thread
danielinux marked this conversation as resolved.
#ifndef WOLFIP_EAGAIN
Comment thread
danielinux marked this conversation as resolved.
#ifdef EAGAIN
Expand Down
Loading