Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e532c85
F-9367: document the real cyw43_connect return contract
danielinux Aug 20, 2026
3c021c6
F-9368: stop claiming WPA3/SAE in cyw43_connect docs
danielinux Aug 20, 2026
da02bdb
F-9369: document when the cyw43_get_mac cache is valid
danielinux Aug 20, 2026
9556686
F-9370: correct rp2350_pio_xfer32 bit-count contract
danielinux Aug 20, 2026
8f3b60e
F-9371: describe what rp2350_spi_init actually configures
danielinux Aug 20, 2026
c148fe3
F-9372: document that the HAL port forces RMII
danielinux Aug 20, 2026
9c92b47
F-9373: soften the ETH NVIC prerequisite in the HAL docs
danielinux Aug 20, 2026
26a64d3
F-9375: correct the ap_rsn_ie NULL-fallback comment
danielinux Aug 20, 2026
bf889f8
F-9376: require zero-init of the context before first supplicant init
danielinux Aug 20, 2026
6e176da
F-9377: document which init failures zero the context
danielinux Aug 20, 2026
b36b1a0
F-9378: document the mode-specific wolfip_supplicant_kick transitions
danielinux Aug 20, 2026
1f00ca3
F-9379: document that get_pmk reports PMK availability, not success
danielinux Aug 20, 2026
2f1b399
F-10264: fix the gmac enum name in the sa_new_gcm comment
danielinux Aug 20, 2026
a15ea21
F-8572: skip anti-replay for SAs without integrity protection
danielinux Aug 20, 2026
78ba53b
F-8573: widen the ESP anti-replay window to 64 packets
danielinux Aug 20, 2026
f0b4aa9
F-8519: do not free the Hmac when wc_HmacInit failed
danielinux Aug 20, 2026
7a5edaf
F-10262: zeroize the full GCM nonce in the four ESP helpers
danielinux Aug 20, 2026
764b0bb
F-10263: drop the redundant second AES-GCM key set
danielinux Aug 20, 2026
920af46
F-6939: zero echo reply code per RFC 792
danielinux Aug 20, 2026
0ab2e47
F-10271: apply RFC 9293 acceptability in SYN_RCVD instead of exact se…
danielinux Aug 20, 2026
a95ff61
F-6473: gate TS.Recent update on the RFC 7323 4.3 preconditions
danielinux Aug 20, 2026
7ef3453
F-8520: drop dead IP length re-check in the tcp_input socket loop
danielinux Aug 20, 2026
d9f119c
F-6944: test the future-TSecr guard in tcp_process_ts
danielinux Aug 20, 2026
e612852
F-6474: RST on unacceptable ACK number in SYN_SENT (bare ACKs too)
danielinux Aug 20, 2026
9bd3217
F-10265: RST replies carry a Timestamps option when the trigger had one
danielinux Aug 20, 2026
0ee8f61
F-6943: pin the PMTU never-increase guard on peer_mss
danielinux Aug 20, 2026
3f63c55
F-10276: RENEWING/REBINDING DHCPREQUEST retries use half-remaining-time
danielinux Aug 20, 2026
7f9d3b9
F-6940: set the DHCP BROADCAST bit while the client has no bound IP
danielinux Aug 20, 2026
e58a377
F-8526: make DHCPACK config commit atomic
danielinux Aug 20, 2026
44c7204
F-10279: make the forwarding filter notification IHL-aware
danielinux Aug 20, 2026
e30d7dc
F-8559: correct the source-route drop rationale comment
danielinux Aug 20, 2026
a4197a5
F-9808: make timer_binheap_cancel eager to stop dead-slot heap exhaus…
danielinux Aug 20, 2026
13e95d6
F-6473: seed TS.Recent from the first peer timestamp
danielinux Aug 20, 2026
99c7331
wolfesp: log replay sequence numbers as unsigned
danielinux Aug 20, 2026
8a51324
F-10271: test the SYN_RCVD FIN-above-hole deferral
danielinux Aug 20, 2026
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
26 changes: 17 additions & 9 deletions src/port/rp2350_cyw43439/cyw43439_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
* channel registration.
*
* cyw43_connect() = WLC_SET_SSID + SET_KEY plumbing for an open or
* pre-shared assoc; the WPA{2,3} 4-way / SAE
* handshake itself runs in the wolfIP supplicant
* and we just shuttle EAPOL frames in/out.
* WPA2-PSK assoc only (no SAE/WPA3 on this path);
* the 4-way handshake itself runs in the wolfIP
* supplicant and we just shuttle EAPOL frames
* in/out.
*
* cyw43_tx_eapol() = push one EAPOL frame onto the F2 data channel
* (BDC encapsulation, type 0x888E).
Expand Down Expand Up @@ -70,10 +71,14 @@ int cyw43_wifi_up(const char *country);
int cyw43_set_powersave(uint32_t pm);

/* Initiate association to the named SSID. open_auth = 1 for an open
* (non-RSN) network; for WPA2/WPA3 the call kicks off MLME and the
* 4-way / SAE handshake runs in the wolfIP supplicant. Returns 0 once
* the (Re)Assoc Response arrives with a success code; the supplicant
* is responsible for finishing the handshake before traffic flows.
* (non-RSN) network; for WPA2-PSK the call kicks off MLME (WPA2_AUTH_PSK
* + WPA2-PSK RSN IE, no AKM selector) and the 4-way handshake runs in the
* wolfIP supplicant. Returns 0 once
* the WLC_SET_SSID command is accepted - the (Re)Association completes
* asynchronously; poll cyw43_assoc_up() (or the latched
* cyw43_assoc_seen()) for the later WLC_E_ASSOC / WLC_E_LINK event,
* and the supplicant is responsible for finishing the handshake before
* traffic flows.
*
* bssid may be NULL (any matching SSID). channel = 0 means scan all. */
int cyw43_connect(const uint8_t *ssid, size_t ssid_len,
Expand Down Expand Up @@ -119,8 +124,11 @@ void cyw43_set_rx_callbacks(cyw43_eapol_cb_t eapol_cb,

int cyw43_poll(void);

/* Read the radio's permanent MAC address (set during firmware load
* from OTP). out is 6 bytes. Returns 0 on success. */
/* Read the radio's STA MAC address. The 6-byte cache is populated from
* the cur_etheraddr iovar read inside cyw43_wifi_up(), so the value is
* only valid after that call; before it the cache is zero-filled. out
* is 6 bytes. Returns 0 once firmware is up (cyw43_init done), -1
* before that. */
int cyw43_get_mac(uint8_t out[6]);

/* Read the associated AP's BSSID (learned during assoc). out is 6
Expand Down
4 changes: 3 additions & 1 deletion src/port/rp2350_cyw43439/rp2350_pio.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ void rp2350_pio_init(void);
* (MSB-first, already byte-permuted for the bus mode) are clocked out
* (out_bits total), then in_bits are clocked in and returned in `rx`
* (one 32-bit word, MSB-first). CS is asserted/deasserted by the
* caller. out_bits and in_bits are each 1..32 for register access. */
* caller. out_bits and in_bits must both be exactly 32: the PIO OSR
* is drained per full word, so sub-word counts desynchronize the state
* machine (see rp2350_pio_xfer). */
uint32_t rp2350_pio_xfer32(uint32_t cmd_word, uint32_t out_bits,
uint32_t in_bits);

Expand Down
10 changes: 6 additions & 4 deletions src/port/rp2350_cyw43439/rp2350_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
extern "C" {
#endif

/* Initialise the GPIO and SPI peripheral for the CYW43439 gSPI bus.
* Pin assignment lives in board.h (CYW43_PIN_SPI_*); this function
* configures pad strength, function-mux, clock divider, and brings the
* SPI controller out of reset. Safe to call multiple times. */
/* Initialise the CPU-driven control lines for the CYW43439 gSPI bus:
* CS deasserted and WL_REG_ON driven low (radio held off). Pin
* assignment lives in board.h (CYW43_PIN_*). CLK and DATA are owned by
* the PIO transport (rp2350_pio_init), not this function. Call once,
* before power-up: repeating it while the radio is running drives
* WL_REG_ON low and powers the CYW43439 down. */
void rp2350_spi_init(void);

/* Drive WL_REG_ON high to power the CYW43439. Caller should wait
Expand Down
12 changes: 7 additions & 5 deletions src/port/stm32_hal/stm32_hal_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
*
* // Initialize wolfIP (same code on ALL STM32 boards)
* wolfIP_init_static(&ipstack);
* stm32_hal_eth_init(wolfIP_getdev(ipstack)); // Auto-configures RMII/MII!
* stm32_hal_eth_init(wolfIP_getdev(ipstack)); // Auto-configures RMII!
* wolfIP_ipconfig_set(ipstack,
* atoip4("192.168.1.100"),
* atoip4("255.255.255.0"),
Expand All @@ -78,8 +78,9 @@
* - Mode: RMII (or MII depending on your board's PHY)
*
* 2. **NVIC Settings** (System Core -> NVIC) - CRITICAL
* - ETH global interrupt: **ENABLED**
* - Without this, received frames will not be detected
* - ETH global interrupt: **ENABLED** for prompt frame notification
* - Without it, frames are still detected by the periodic RX poll
* (every 100th poll) but with added latency
*
* 3. **GPIO Configuration**
* - CubeMX auto-configures correct pins for NUCLEO boards
Expand All @@ -88,11 +89,12 @@
*
* The driver automatically:
* 1. Detects your STM32 family at compile time
* 2. Configures RMII/MII interface (SBS/SYSCFG)
* 2. Configures the RMII interface (SBS/SYSCFG) - MII boards must be
* configured manually in HAL_ETH_MspInit(); there is no mode option
* 3. Reinitializes ETH with correct settings
* 4. Starts the MAC in interrupt mode
*
* No manual MspInit changes required for supported families!
* No manual MspInit changes required for supported RMII families!
*
* ## Implementation Notes
*
Expand Down
51 changes: 36 additions & 15 deletions src/supplicant/supplicant.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,11 @@ struct wolfip_supplicant_cfg {
* M3 to detect downgrade attacks (IEEE 802.11-2020 12.7.6.4).
*
* If ap_rsn_ie is NULL, the supplicant falls back to using its own
* default WPA2-PSK RSN IE for the comparison. This is acceptable
* for a closed PSK deployment where supplicant and AP agree on
* cipher choices by configuration, but real hardware ports should
* pass the IE from the chip's scan results.
* generated RSN IE for the comparison - the AKM suite patched to
* the configured mode (PSK, SAE or 802.1X), not always WPA2-PSK.
* This is acceptable for a closed deployment where supplicant and
* AP agree on cipher choices by configuration, but real hardware
* ports should pass the IE from the chip's scan results.
*/
const uint8_t *ap_rsn_ie;
size_t ap_rsn_ie_len;
Expand Down Expand Up @@ -268,8 +269,12 @@ struct wolfip_supplicant {
* context zero but is wiped by _deinit() and _pmksa_clear().
*
* Reuse requires BOTH pmksa_magic == WOLFIP_PMKSA_MAGIC AND an exact
* SSID match, so an uninitialized (garbage) context on the very first
* init cannot be mistaken for a valid cache. */
* SSID match, so a garbage value cannot be mistaken for a valid
* cache hit. The first init still READS these fields (PMKSA
* snapshot) before zeroing the context, so caller-owned (stack /
* static / pool) contexts MUST be zero-initialized (memset /
* "= {0}") before their very first wolfip_supplicant_init(); only
* re-inits on a previously valid context may carry PMKSA state. */
uint32_t pmksa_magic;
uint8_t pmksa_pmk[WPA_PMK_LEN];
uint8_t pmksa_pmkid[16]; /* PMKID of the cached PMKSA (for reconnect) */
Expand Down Expand Up @@ -301,8 +306,11 @@ extern "C" {

/* Caller-allocated init. `out` is a struct provided by the caller (stack,
* static, or pool) and is fully populated from cfg on success. Returns 0
* on success, negative on bad args / crypto failure. On failure, the
* struct is left zeroed; caller does not need to call _deinit.
* on success, negative on bad args / crypto failure. On failure after
* initialization has begun, the struct is left zeroed and the caller
* does not need to call _deinit; bad-argument and cfg-validation
* failures return before any write and leave the supplied context
* unchanged.
*/
int wolfip_supplicant_init(struct wolfip_supplicant *out,
const struct wolfip_supplicant_cfg *cfg);
Expand All @@ -322,9 +330,16 @@ struct wolfip_supplicant *wolfip_supplicant_new(

void wolfip_supplicant_free(struct wolfip_supplicant *s);

/* Signal that the radio reports "associated" - supplicant moves from
* IDLE to 4WAY_M1_WAIT. (On real hardware, called by the driver after
* the FullMAC chip completes auth+assoc.) `now_ms` is the current
/* Start the handshake from IDLE. The transition depends on the auth
* mode:
* PSK (or SAE with a pre-installed FullMAC PMK): IDLE -> 4WAY_M1_WAIT.
* EAP (TLS / PEAP): sends EAPOL-Start, IDLE -> EAP_IDENTITY_WAIT.
* Software SAE: sends the SAE Commit, IDLE -> SAE_COMMIT_SENT. SAE
* authentication runs BEFORE radio association, so software-SAE
* callers must kick the supplicant before the driver associates -
* waiting for the association inverts the required sequencing.
* (On FullMAC hardware where the chip did auth itself, the driver calls
* this after the chip completes auth+assoc.) `now_ms` is the current
* monotonic timestamp; the supplicant uses it as the handshake start.
*/
int wolfip_supplicant_kick(struct wolfip_supplicant *s, uint64_t now_ms);
Expand Down Expand Up @@ -368,10 +383,16 @@ const uint8_t *wolfip_supplicant_kck(const struct wolfip_supplicant *s);
const uint8_t *wolfip_supplicant_tk (const struct wolfip_supplicant *s);
const uint8_t *wolfip_supplicant_snonce(const struct wolfip_supplicant *s);

/* Export the current PMK (32 bytes). Returns 0 on success, -1 if no
* PMK is available (state == IDLE / FAILED, or auth_mode never derived
* a PSK-grade PMK). Caller can persist the PMK and pass it back via
* cfg.psk_pmk on the next wolfip_supplicant_init() to skip PBKDF2. */
/* Export the current PMK (32 bytes). Reports PMK-material availability,
* NOT authentication success: PSK mode holds a PMK right after init, and
* a context with a PTK or an installed (pmk_installed) SAE PMK exports
* it from every state, FAILED included - in FAILED state a PMK that was
* never derived is exported as all zeros with rc 0. Returns -1 only
* while IDLE with no derived/installed PMK (EAP / software SAE before
* the handshake). Callers that need "did authentication complete" must
* check wolfip_supplicant_state() separately. Caller can persist the PMK
* and pass it back via cfg.psk_pmk on the next wolfip_supplicant_init()
* to skip PBKDF2. */
int wolfip_supplicant_get_pmk(const struct wolfip_supplicant *s,
uint8_t out_pmk[WPA_PMK_LEN]);

Expand Down
25 changes: 23 additions & 2 deletions src/test/unit/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_pop_timer);
tcase_add_test(tc_utils, test_is_timer_expired);
tcase_add_test(tc_utils, test_cancel_timer);
tcase_add_test(tc_utils, test_timer_pop_removes_zero_head_first);
tcase_add_test(tc_utils, test_timer_heap_no_dead_slot_accumulation);
tcase_add_test(tc_utils, test_timer_pop_skips_zero_expires);
tcase_add_test(tc_utils, test_timer_pop_reorders_heap);
tcase_add_test(tc_utils, test_timer_pop_right_child_swap);
tcase_add_test(tc_utils, test_timer_pop_break_when_root_small);
Expand Down Expand Up @@ -176,6 +177,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_wolfip_poll_preserves_tcp_events_raised_during_callback);
tcase_add_test(tc_utils, test_wolfip_poll_limits_device_drain_to_poll_budget);
tcase_add_test(tc_utils, test_filter_notify_tcp_metadata);
tcase_add_test(tc_utils, test_filter_notify_udp_ihl_options_metadata);
tcase_add_test(tc_utils, test_filter_notify_udp_ihl_truncated_no_overread);
tcase_add_test(tc_utils, test_filter_dispatch_no_callback);
tcase_add_test(tc_utils, test_filter_dispatch_mask_not_set);
tcase_add_test(tc_utils, test_filter_fresh_callback_consulted_before_mask_configured);
Expand Down Expand Up @@ -296,6 +299,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_dhcp_renewing_transitions_to_rebinding);
tcase_add_test(tc_utils, test_arp_recv_rejects_wrong_htype);
tcase_add_test(tc_utils, test_syn_sent_bad_ack_synack_sends_rst);
tcase_add_test(tc_utils, test_syn_sent_bad_ack_bare_ack_sends_rst);
tcase_add_test(tc_utils, test_rst_reply_carries_timestamp_when_incoming_had_one);
tcase_add_test(tc_utils, test_syn_rcvd_bad_ack_sends_rst);
tcase_add_test(tc_utils, test_established_fin_without_ack_dropped);
tcase_add_test(tc_utils, test_ip_recv_drops_source_routed_packet);
Expand Down Expand Up @@ -418,6 +423,10 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_dhcp_timer_cb_paths);
tcase_add_test(tc_utils, test_dhcp_discover_retransmit_backoff);
tcase_add_test(tc_utils, test_dhcp_request_retransmit_backoff);
tcase_add_test(tc_utils, test_dhcp_renew_rebind_delay_ms);
tcase_add_test(tc_utils, test_dhcp_schedule_renew_rebind_retry);
tcase_add_test(tc_utils, test_dhcp_renewing_retry_half_remaining_to_t2);
tcase_add_test(tc_utils, test_dhcp_rebinding_retry_half_remaining_to_lease);
tcase_add_test(tc_utils, test_regression_dhcp_lease_expiry_deconfigures_address);
tcase_add_test(tc_utils, test_dhcp_request_retry_exhaustion_deconfigures_lease);
tcase_add_test(tc_utils, test_dhcp_timer_cb_send_failure_does_not_consume_retry_budget);
Expand Down Expand Up @@ -487,6 +496,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_dhcp_parse_ack_ignores_zero_len_unknown_option);
tcase_add_test(tc_utils, test_dhcp_parse_ack_missing_server_id_rejected);
tcase_add_test(tc_utils, test_dhcp_parse_ack_missing_end_rejected);
tcase_add_test(tc_utils, test_dhcp_parse_ack_reject_preserves_config);
tcase_add_test(tc_utils, test_dhcp_parse_offer_bad_magic_rejected);
tcase_add_test(tc_utils, test_dhcp_parse_ack_bad_magic_rejected);
tcase_add_test(tc_utils, test_dhcp_parse_offer_rejects_boot_request_op);
Expand Down Expand Up @@ -532,6 +542,8 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils,
test_dhcp_parse_offer_option_split_across_region_boundary);
tcase_add_test(tc_utils, test_dhcp_discover_first_retry_delay_rfc2131);
tcase_add_test(tc_utils, test_dhcp_discover_sets_broadcast_flag);
tcase_add_test(tc_utils, test_dhcp_request_broadcast_flag_by_state);
tcase_add_test(tc_utils, test_dhcp_discover_retry_delay_small_base_no_underflow);
tcase_add_test(tc_utils, test_dns_wrapper_apis);
tcase_add_test(tc_utils, test_wolfip_static_instance_apis);
Expand Down Expand Up @@ -604,7 +616,11 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_tcp_input_syn_listen_mismatch);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_ack_established);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_ack_invalid_ack_rejected);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_ack_invalid_seq_rejected);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_high_seq_valid_ack_establishes);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_high_seq_data_held_ooo);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_fin_above_hole_deferred);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_out_of_window_ack_drop);
tcase_add_test(tc_utils, test_tcp_input_paws_upper_half_tsval_flows);
tcase_add_test(tc_utils, test_tcp_input_syn_rcvd_ack_fin_transitions_to_close_wait);
tcase_add_test(tc_utils, test_tcp_input_filter_drop);
tcase_add_test(tc_utils, test_tcp_input_port_mismatch_skips_socket);
Expand Down Expand Up @@ -681,6 +697,9 @@ Suite *wolf_suite(void)
tcase_add_test(tc_utils, test_tcp_process_ts_nop_then_ts);
tcase_add_test(tc_utils, test_tcp_process_ts_skips_unknown_option);
tcase_add_test(tc_utils, test_tcp_process_ts_no_ecr);
tcase_add_test(tc_utils, test_tcp_process_ts_future_ecr_rejected);
tcase_add_test(tc_utils, test_tcp_process_ts_ooo_segment_keeps_recent);
tcase_add_test(tc_utils, test_tcp_input_paws_ooo_does_not_poison_hole_fill);
tcase_add_test(tc_utils, test_tcp_process_ts_updates_rtt_when_set);
tcase_add_test(tc_utils, test_tcp_send_syn_advertises_sack_permitted);
tcase_add_test(tc_utils, test_tcp_build_ack_options_does_not_write_past_returned_len);
Expand Down Expand Up @@ -908,6 +927,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_icmp_input_echo_reply_wrong_dst_dropped);
tcase_add_test(tc_proto, test_icmp_input_echo_request_reply_sent);
tcase_add_test(tc_proto, test_icmp_input_echo_reply_sets_df);
tcase_add_test(tc_proto, test_icmp_echo_reply_code_zeroed);
tcase_add_test(tc_proto, test_icmp_input_echo_request_bad_checksum_dropped);
tcase_add_test(tc_proto, test_icmp_input_echo_request_odd_len_reply_checksum);
tcase_add_test(tc_proto, test_icmp_input_echo_request_dhcp_running_no_reply);
Expand All @@ -921,6 +941,7 @@ Suite *wolf_suite(void)
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_port_unreachable_keeps_established_tcp_socket);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_frag_needed_reduces_tcp_peer_mss);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_frag_needed_below_floor_preserves_peer_mss);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_frag_needed_larger_mtu_does_not_raise_peer_mss);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_port_unreachable_closes_syn_sent_tcp_socket);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_port_unreachable_quoted_ip_options_keep_established_tcp_socket);
tcase_add_test(tc_proto, test_icmp_input_dest_unreach_port_unreachable_mismatched_orig_src_ip_ignored);
Expand Down
Loading
Loading