Skip to content

Commit cdc4a77

Browse files
committed
DHCP: escalate failed enqueues
Program next-tick retry instead of arming the DHCP retry timer.
1 parent 0fdb455 commit cdc4a77

3 files changed

Lines changed: 77 additions & 8 deletions

File tree

src/test/unit/unit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ Suite *wolf_suite(void)
314314
tcase_add_test(tc_utils, test_dhcp_client_init_and_bound);
315315
tcase_add_test(tc_utils, test_dhcp_send_request_renewing_sets_ciaddr_and_rebind_deadline);
316316
tcase_add_test(tc_utils, test_dhcp_send_request_rebinding_broadcasts_to_lease_expiry);
317+
tcase_add_test(tc_utils, test_dhcp_send_request_send_failure_retries_next_tick);
318+
tcase_add_test(tc_utils, test_dhcp_send_discover_send_failure_retries_next_tick);
317319
tcase_add_test(tc_utils, test_dhcp_poll_offer_and_ack);
318320
tcase_add_test(tc_utils, test_dhcp_poll_renewing_ack_binds_client);
319321
tcase_add_test(tc_utils, test_dhcp_poll_rebinding_ack_binds_client);

src/test/unit/unit_tests_dns_dhcp.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,60 @@ START_TEST(test_dhcp_send_request_rebinding_broadcasts_to_lease_expiry)
903903
}
904904
END_TEST
905905

906+
START_TEST(test_dhcp_send_request_send_failure_retries_next_tick)
907+
{
908+
struct wolfIP s;
909+
struct tsocket *ts;
910+
struct ipconf *primary;
911+
uint8_t tiny[2];
912+
913+
wolfIP_init(&s);
914+
mock_link_init(&s);
915+
primary = wolfIP_primary_ipconf(&s);
916+
ck_assert_ptr_nonnull(primary);
917+
primary->ip = 0x0A000064U;
918+
primary->mask = 0xFFFFFF00U;
919+
s.dhcp_server_ip = 0x0A000001U;
920+
s.dhcp_ip = primary->ip;
921+
s.dhcp_xid = 1U;
922+
s.dhcp_state = DHCP_REQUEST_SENT;
923+
s.last_tick = 1000U;
924+
925+
s.dhcp_udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
926+
ck_assert_int_gt(s.dhcp_udp_sd, 0);
927+
ts = &s.udpsockets[SOCKET_UNMARK(s.dhcp_udp_sd)];
928+
fifo_init(&ts->sock.udp.txbuf, tiny, sizeof(tiny));
929+
930+
ck_assert_int_eq(dhcp_send_request(&s), -WOLFIP_EAGAIN);
931+
ck_assert_ptr_eq(fifo_peek(&ts->sock.udp.txbuf), NULL);
932+
ck_assert_uint_eq(ts->local_ip, 0U);
933+
ck_assert_uint_eq(find_timer_expiry(&s, s.dhcp_timer), s.last_tick + 1U);
934+
}
935+
END_TEST
936+
937+
START_TEST(test_dhcp_send_discover_send_failure_retries_next_tick)
938+
{
939+
struct wolfIP s;
940+
struct tsocket *ts;
941+
uint8_t tiny[2];
942+
943+
wolfIP_init(&s);
944+
mock_link_init(&s);
945+
s.dhcp_xid = 1U;
946+
s.last_tick = 1000U;
947+
948+
s.dhcp_udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
949+
ck_assert_int_gt(s.dhcp_udp_sd, 0);
950+
ts = &s.udpsockets[SOCKET_UNMARK(s.dhcp_udp_sd)];
951+
fifo_init(&ts->sock.udp.txbuf, tiny, sizeof(tiny));
952+
953+
ck_assert_int_eq(dhcp_send_discover(&s), -WOLFIP_EAGAIN);
954+
ck_assert_ptr_eq(fifo_peek(&ts->sock.udp.txbuf), NULL);
955+
ck_assert_int_eq(s.dhcp_state, DHCP_OFF);
956+
ck_assert_uint_eq(find_timer_expiry(&s, s.dhcp_timer), s.last_tick + 1U);
957+
}
958+
END_TEST
959+
906960
START_TEST(test_sock_connect_tcp_src_port_low)
907961
{
908962
struct wolfIP s;

src/wolfip.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5599,8 +5599,10 @@ static int dhcp_send_request(struct wolfIP *s)
55995599
struct dhcp_option *opt = (struct dhcp_option *)(req.options);
56005600
struct wolfIP_sockaddr_in sin;
56015601
struct ipconf *primary = wolfIP_primary_ipconf(s);
5602+
uint64_t retry_at = s ? (s->last_tick + 1U) : 0;
56025603
int renewing = (s->dhcp_state == DHCP_RENEWING);
56035604
int rebinding = (s->dhcp_state == DHCP_REBINDING);
5605+
int ret;
56045606
uint32_t opt_sz = 0;
56055607
/* Prepare DHCP request */
56065608
memset(&req, 0, sizeof(struct dhcp_msg));
@@ -5655,13 +5657,21 @@ static int dhcp_send_request(struct wolfIP *s)
56555657
else
56565658
sin.sin_addr.s_addr = ee32(0xFFFFFFFF); /* Broadcast */
56575659
sin.sin_family = AF_INET;
5658-
wolfIP_sock_sendto(s, s->dhcp_udp_sd, &req, DHCP_HEADER_LEN + opt_sz, 0,
5660+
ret = wolfIP_sock_sendto(s, s->dhcp_udp_sd, &req, DHCP_HEADER_LEN + opt_sz, 0,
56595661
(struct wolfIP_sockaddr *)&sin, sizeof(struct wolfIP_sockaddr_in));
56605662
if (!renewing && !rebinding) {
56615663
/* Reset local_ip so DHCP ACK matches via DHCP_IS_RUNNING path in
56625664
* udp_try_recv(). wolfIP_sock_sendto() sets local_ip from conf->ip
56635665
* (the offered IP), but we haven't confirmed the lease yet. */
56645666
s->udpsockets[SOCKET_UNMARK(s->dhcp_udp_sd)].local_ip = 0;
5667+
}
5668+
if (ret < 0) {
5669+
/* Retry on the next tick after local backpressure instead of
5670+
* waiting a full DHCP timeout for a request that never queued. */
5671+
dhcp_schedule_timer_at(s, retry_at);
5672+
return ret;
5673+
}
5674+
if (!renewing && !rebinding) {
56655675
dhcp_schedule_retry_timer(s, 0);
56665676
} else if (renewing) {
56675677
dhcp_schedule_retry_timer(s, s->dhcp_rebind_at);
@@ -5685,8 +5695,9 @@ static int dhcp_send_discover(struct wolfIP *s)
56855695
{
56865696
struct dhcp_msg disc;
56875697
struct dhcp_option *opt = (struct dhcp_option *)(disc.options);
5688-
struct wolfIP_timer tmr = { };
56895698
struct wolfIP_sockaddr_in sin;
5699+
uint64_t retry_at = s ? (s->last_tick + 1U) : 0;
5700+
int ret;
56905701
uint32_t opt_sz = 0;
56915702
/* Prepare DHCP discover */
56925703
memset(&disc, 0, sizeof(struct dhcp_msg));
@@ -5722,14 +5733,16 @@ static int dhcp_send_discover(struct wolfIP *s)
57225733
sin.sin_port = ee16(DHCP_SERVER_PORT);
57235734
sin.sin_addr.s_addr = ee32(0xFFFFFFFF); /* Broadcast */
57245735
sin.sin_family = AF_INET;
5725-
wolfIP_sock_sendto(s, s->dhcp_udp_sd, &disc, DHCP_HEADER_LEN + opt_sz, 0,
5736+
ret = wolfIP_sock_sendto(s, s->dhcp_udp_sd, &disc, DHCP_HEADER_LEN + opt_sz, 0,
57265737
(struct wolfIP_sockaddr *)&sin, sizeof(struct wolfIP_sockaddr_in));
5727-
tmr.expires = s->last_tick + DHCP_DISCOVER_TIMEOUT + (wolfIP_getrandom() % 200);
5728-
tmr.arg = s;
5729-
tmr.cb = dhcp_timer_cb;
5738+
if (ret < 0) {
5739+
/* Retry on the next tick after local backpressure instead of
5740+
* waiting a full discover timeout for a packet that never queued. */
5741+
dhcp_schedule_timer_at(s, retry_at);
5742+
return ret;
5743+
}
5744+
dhcp_schedule_timer_at(s, s->last_tick + DHCP_DISCOVER_TIMEOUT + (wolfIP_getrandom() % 200U));
57305745
s->dhcp_state = DHCP_DISCOVER_SENT;
5731-
5732-
s->dhcp_timer = timers_binheap_insert(&s->timers, tmr);
57335746
return 0;
57345747
}
57355748

0 commit comments

Comments
 (0)