Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
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 config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

#define ETHERNET
#define LINK_MTU 1536
#ifndef LINK_MTU_MIN
#define LINK_MTU_MIN 64
#endif
#if LINK_MTU < LINK_MTU_MIN
#error "LINK_MTU must be greater than or equal to LINK_MTU_MIN"
#endif
Comment thread
danielinux marked this conversation as resolved.

#define MAX_TCPSOCKETS 4
#define MAX_UDPSOCKETS 2
Expand Down
4 changes: 4 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct wolfIP_ll_dev {
uint8_t mac[6]; // Device MAC address
char ifname[16]; // Interface name
uint8_t non_ethernet; // L3-only link (no Ethernet header/ARP when set)
uint32_t mtu; // Optional max frame size, defaults to LINK_MTU
int (*poll)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); // Receive function
int (*send)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); // Transmit function
Comment thread
danielinux marked this conversation as resolved.
};
Expand Down Expand Up @@ -203,8 +204,11 @@ Per-interface versions of the IP configuration helpers. The legacy functions tar
```c
struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s);
struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx);
int wolfIP_mtu_set(struct wolfIP *s, unsigned int if_idx, uint32_t mtu);
int wolfIP_mtu_get(struct wolfIP *s, unsigned int if_idx, uint32_t *mtu);
```
Access the link-layer descriptor(s) that should be wired to hardware drivers. `_ex` returns `NULL` if `if_idx` exceeds `WOLFIP_MAX_INTERFACES`.
`wolfIP_mtu_set()` updates the effective per-interface MTU, treating `0` as the default `LINK_MTU` and clamping to `[LINK_MTU_MIN, LINK_MTU]`. `wolfIP_mtu_get()` returns the effective MTU currently used by the stack.

## DHCP Client Functions

Expand Down
260 changes: 260 additions & 0 deletions src/test/unit/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,45 @@ START_TEST(test_udp_sendto_and_recvfrom)
}
END_TEST

START_TEST(test_udp_sendto_respects_mtu_api)
{
struct wolfIP s;
int sd;
struct wolfIP_sockaddr_in sin;
uint8_t small_payload[38] = {0};
uint8_t large_payload[39] = {0};
struct tsocket *ts;
uint32_t mtu = 0;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, 80U), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, 80U);

sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
ck_assert_int_gt(sd, 0);
ts = &s.udpsockets[SOCKET_UNMARK(sd)];
fifo_init(&ts->sock.udp.txbuf, ts->txmem, TXBUF_SIZE);

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(5000);
sin.sin_addr.s_addr = ee32(0x0A000002U);

ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, small_payload, sizeof(small_payload), 0,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), (int)sizeof(small_payload));
ck_assert_ptr_nonnull(fifo_peek(&ts->sock.udp.txbuf));

fifo_init(&ts->sock.udp.txbuf, ts->txmem, TXBUF_SIZE);
ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, large_payload, sizeof(large_payload), 0,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -1);
ck_assert_ptr_null(fifo_peek(&ts->sock.udp.txbuf));
}
END_TEST

START_TEST(test_udp_recvfrom_sets_remote_ip)
{
struct wolfIP s;
Expand Down Expand Up @@ -13764,6 +13803,46 @@ START_TEST(test_tcp_input_synack_negotiates_peer_mss)
}
END_TEST

START_TEST(test_tcp_connect_syn_advertises_interface_mss)
{
struct wolfIP s;
int tcp_sd;
struct tsocket *ts;
struct wolfIP_sockaddr_in sin;
struct pkt_desc *desc;
struct wolfIP_tcp_seg *syn;
struct tcp_parsed_opts po;
uint16_t expected_mss;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_getdev(&s)->mtu = 640U;
Comment thread
danielinux marked this conversation as resolved.
Outdated
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);

tcp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_STREAM, WI_IPPROTO_TCP);
ck_assert_int_gt(tcp_sd, 0);
ts = &s.tcpsockets[SOCKET_UNMARK(tcp_sd)];

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(5004);
sin.sin_addr.s_addr = ee32(0x0A000002U);
ck_assert_int_eq(wolfIP_sock_connect(&s, tcp_sd,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -WOLFIP_EAGAIN);

desc = fifo_peek(&ts->sock.tcp.txbuf);
ck_assert_ptr_nonnull(desc);
syn = (struct wolfIP_tcp_seg *)(ts->txmem + desc->pos + sizeof(*desc));
ck_assert_uint_eq((uint32_t)(syn->flags & TCP_FLAG_SYN), TCP_FLAG_SYN);

memset(&po, 0, sizeof(po));
tcp_parse_options(syn, desc->len, &po);
expected_mss = (uint16_t)(640U - ETH_HEADER_LEN - IP_HEADER_LEN - TCP_HEADER_LEN);
ck_assert_int_eq(po.mss_found, 1);
ck_assert_uint_eq(po.mss, expected_mss);
}
END_TEST

START_TEST(test_sock_sendto_tcp_respects_negotiated_peer_mss)
{
struct wolfIP s;
Expand Down Expand Up @@ -13924,6 +14003,88 @@ START_TEST(test_sock_sendto_tcp_defaults_to_rfc_mss_when_unset_by_peer)
}
END_TEST

START_TEST(test_sock_sendto_tcp_respects_interface_mtu)
{
struct wolfIP s;
int tcp_sd;
struct tsocket *ts;
struct wolfIP_sockaddr_in sin;
struct wolfIP_tcp_seg synack;
uint8_t payload[700];
int ret;
struct pkt_desc *desc;
uint32_t max_payload;
int seg_count = 0;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_getdev(&s)->mtu = 320U;
Comment thread
danielinux marked this conversation as resolved.
Outdated
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);

tcp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_STREAM, WI_IPPROTO_TCP);
ck_assert_int_gt(tcp_sd, 0);
ts = &s.tcpsockets[SOCKET_UNMARK(tcp_sd)];
ts->src_port = 23459;

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = ee16(5005);
sin.sin_addr.s_addr = ee32(0x0A000002U);
ck_assert_int_eq(wolfIP_sock_connect(&s, tcp_sd,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -WOLFIP_EAGAIN);
ck_assert_int_eq(ts->sock.tcp.state, TCP_SYN_SENT);

memset(&synack, 0, sizeof(synack));
synack.ip.ver_ihl = 0x45;
synack.ip.proto = WI_IPPROTO_TCP;
synack.ip.ttl = 64;
synack.ip.src = ee32(0x0A000002U);
synack.ip.dst = ee32(0x0A000001U);
synack.ip.len = ee16(IP_HEADER_LEN + TCP_HEADER_LEN);
synack.src_port = ee16(5005);
synack.dst_port = ee16(ts->src_port);
synack.seq = ee32(100);
synack.ack = ee32(ts->sock.tcp.seq + 1);
synack.hlen = TCP_HEADER_LEN << 2;
synack.flags = (TCP_FLAG_SYN | TCP_FLAG_ACK);
synack.win = ee16(65535);
fix_tcp_checksums(&synack);

tcp_input(&s, TEST_PRIMARY_IF, &synack,
(uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN));
ck_assert_int_eq(ts->sock.tcp.state, TCP_ESTABLISHED);

max_payload = wolfIP_socket_tcp_mss(ts);
ck_assert_uint_gt(max_payload, TCP_OPTIONS_LEN);
max_payload -= TCP_OPTIONS_LEN;

fifo_init(&ts->sock.tcp.txbuf, ts->txmem, TXBUF_SIZE);
memset(payload, 0x3C, sizeof(payload));
ret = wolfIP_sock_sendto(&s, tcp_sd, payload, sizeof(payload), 0, NULL, 0);
ck_assert_int_eq(ret, (int)sizeof(payload));

desc = fifo_peek(&ts->sock.tcp.txbuf);
ck_assert_ptr_nonnull(desc);
while (desc != NULL) {
struct wolfIP_tcp_seg *seg;
uint32_t seg_payload;
uint32_t hdr_len;
uint32_t base_len;

seg = (struct wolfIP_tcp_seg *)(ts->txmem + desc->pos + sizeof(*desc));
hdr_len = (uint32_t)(seg->hlen >> 2);
base_len = (uint32_t)(sizeof(struct wolfIP_tcp_seg) + (hdr_len - TCP_HEADER_LEN));
ck_assert_uint_ge(desc->len, base_len);
seg_payload = desc->len - base_len;
ck_assert_uint_le(seg_payload, max_payload);

seg_count++;
desc = fifo_next(&ts->sock.tcp.txbuf, desc);
}
ck_assert_int_ge(seg_count, 3);
}
END_TEST

START_TEST(test_tcp_input_syn_rcvd_ack_established)
{
struct wolfIP s;
Expand Down Expand Up @@ -17215,9 +17376,11 @@ START_TEST(test_wolfip_getdev_ex_api)
wolfIP_init(&s);
ll_def = wolfIP_getdev(&s);
ck_assert_ptr_nonnull(ll_def);
ck_assert_uint_eq(ll_def->mtu, LINK_MTU);
ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF));
#if WOLFIP_ENABLE_LOOPBACK
ck_assert_ptr_ne(ll_def, wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF));
ck_assert_uint_eq(wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF)->mtu, LINK_MTU);
#endif
ck_assert_ptr_null(wolfIP_getdev_ex(&s, WOLFIP_MAX_INTERFACES));
}
Expand All @@ -17236,6 +17399,53 @@ START_TEST(test_wolfip_ll_at_and_ipconf_at_invalid)
}
END_TEST

START_TEST(test_wolfip_ll_frame_mtu_enforces_minimum)
{
struct wolfIP s;
struct wolfIP_ll_dev *ll;

wolfIP_init(&s);
mock_link_init(&s);
ll = wolfIP_getdev(&s);
ck_assert_ptr_nonnull(ll);

ll->mtu = LINK_MTU_MIN - 1U;
ck_assert_uint_eq(wolfIP_ll_frame_mtu(ll), LINK_MTU_MIN);
}
END_TEST

START_TEST(test_wolfip_mtu_set_get_api)
{
struct wolfIP s;
uint32_t mtu = 0;

wolfIP_init(&s);
mock_link_init(&s);

ck_assert_int_eq(wolfIP_mtu_set(NULL, TEST_PRIMARY_IF, 128U), -WOLFIP_EINVAL);
ck_assert_int_eq(wolfIP_mtu_set(&s, WOLFIP_MAX_INTERFACES, 128U), -WOLFIP_EINVAL);
ck_assert_int_eq(wolfIP_mtu_get(NULL, TEST_PRIMARY_IF, &mtu), -WOLFIP_EINVAL);
ck_assert_int_eq(wolfIP_mtu_get(&s, WOLFIP_MAX_INTERFACES, &mtu), -WOLFIP_EINVAL);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, NULL), -WOLFIP_EINVAL);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, 256U), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, 256U);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, LINK_MTU_MIN - 1U), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, LINK_MTU_MIN);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, LINK_MTU + 1U), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, LINK_MTU);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, 0), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, LINK_MTU);
}
END_TEST

START_TEST(test_ip_is_local_conf_variants)
{
struct ipconf conf;
Expand Down Expand Up @@ -17309,6 +17519,9 @@ START_TEST(test_wolfip_loopback_send_truncates)

memset(frame, 0xAB, sizeof(frame));
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, (uint32_t)sizeof(frame)), LINK_MTU);

loop->mtu = LINK_MTU_MIN - 1U;
ck_assert_int_eq(wolfIP_loopback_send(loop, frame, (uint32_t)sizeof(frame)), LINK_MTU_MIN);
}
END_TEST

Expand Down Expand Up @@ -18297,6 +18510,47 @@ START_TEST(test_icmp_sendto_respects_bound_local_ip_interface)
}
END_TEST

START_TEST(test_icmp_sendto_respects_mtu_api)
{
struct wolfIP s;
int sd;
struct wolfIP_sockaddr_in sin;
uint8_t small_payload[30] = {0};
uint8_t large_payload[31] = {0};
struct tsocket *ts;
uint32_t mtu = 0;

wolfIP_init(&s);
mock_link_init(&s);
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);

ck_assert_int_eq(wolfIP_mtu_set(&s, TEST_PRIMARY_IF, 64U), 0);
ck_assert_int_eq(wolfIP_mtu_get(&s, TEST_PRIMARY_IF, &mtu), 0);
ck_assert_uint_eq(mtu, 64U);

sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_ICMP);
ck_assert_int_gt(sd, 0);
ts = &s.icmpsockets[SOCKET_UNMARK(sd)];
fifo_init(&ts->sock.udp.txbuf, ts->txmem, TXBUF_SIZE);

memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ee32(0x0A000002U);

small_payload[0] = ICMP_ECHO_REQUEST;
large_payload[0] = ICMP_ECHO_REQUEST;

ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, small_payload, sizeof(small_payload), 0,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), (int)sizeof(small_payload));
ck_assert_ptr_nonnull(fifo_peek(&ts->sock.udp.txbuf));

fifo_init(&ts->sock.udp.txbuf, ts->txmem, TXBUF_SIZE);
ck_assert_int_eq(wolfIP_sock_sendto(&s, sd, large_payload, sizeof(large_payload), 0,
(struct wolfIP_sockaddr *)&sin, sizeof(sin)), -WOLFIP_EINVAL);
ck_assert_ptr_null(fifo_peek(&ts->sock.udp.txbuf));
}
END_TEST

START_TEST(test_regression_snd_una_initialized_on_syn_rcvd)
{
struct wolfIP s;
Expand Down Expand Up @@ -18733,6 +18987,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_timer_pop_break_when_root_small);
tcase_add_test(tc_utils, test_is_timer_expired_skips_zero_head);
tcase_add_test(tc_utils, test_wolfip_getdev_ex_api);
tcase_add_test(tc_utils, test_wolfip_ll_frame_mtu_enforces_minimum);
tcase_add_test(tc_utils, test_wolfip_mtu_set_get_api);
tcase_add_test(tc_utils, test_wolfip_ll_at_and_ipconf_at_invalid);
tcase_add_test(tc_utils, test_ip_is_local_conf_variants);
#if WOLFIP_ENABLE_LOOPBACK
Expand Down Expand Up @@ -19054,8 +19310,10 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_tcp_ack_inflight_deflate_sets_writable_without_acked_desc);
tcase_add_test(tc_utils, test_tcp_input_peer_rwnd_growth_sets_writable);
tcase_add_test(tc_utils, test_tcp_input_synack_negotiates_peer_mss);
tcase_add_test(tc_utils, test_tcp_connect_syn_advertises_interface_mss);
tcase_add_test(tc_utils, test_sock_sendto_tcp_respects_negotiated_peer_mss);
tcase_add_test(tc_utils, test_sock_sendto_tcp_defaults_to_rfc_mss_when_unset_by_peer);
tcase_add_test(tc_utils, test_sock_sendto_tcp_respects_interface_mtu);
tcase_add_test(tc_utils, test_tcp_recv_queues_payload_and_advances_ack);
tcase_add_test(tc_utils, test_tcp_recv_wrong_state_does_nothing);
tcase_add_test(tc_utils, test_tcp_recv_ack_mismatch_does_nothing);
Expand All @@ -19072,6 +19330,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_tcp_build_ack_options_does_not_write_past_returned_len);
tcase_add_test(tc_utils, test_tcp_build_ack_options_omits_ts_when_not_negotiated);
tcase_add_test(tc_utils, test_icmp_sendto_respects_bound_local_ip_interface);
tcase_add_test(tc_utils, test_icmp_sendto_respects_mtu_api);
tcase_add_test(tc_utils, test_tcp_sort_sack_blocks_swaps_out_of_order);
tcase_add_test(tc_utils, test_tcp_sort_sack_blocks_wrap_order);
tcase_add_test(tc_utils, test_tcp_merge_sack_blocks_adjacent_and_disjoint);
Expand Down Expand Up @@ -19231,6 +19490,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_icmp_input_echo_request_eth_filter_drop);
tcase_add_test(tc_proto, test_icmp_input_filter_drop_receiving);
tcase_add_test(tc_proto, test_udp_sendto_and_recvfrom);
tcase_add_test(tc_proto, test_udp_sendto_respects_mtu_api);
tcase_add_test(tc_proto, test_udp_recvfrom_sets_remote_ip);
tcase_add_test(tc_proto, test_udp_recvfrom_null_src_addr_len);
tcase_add_test(tc_proto, test_udp_recvfrom_preserves_remote_ip);
Expand Down
Loading
Loading