From d0bebced98ba03307de7426d121cc466cb261565 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Thu, 11 Jun 2026 09:49:47 -0700 Subject: [PATCH 1/4] Initial wolfIP_poll refactor Mainly extracted the phases into separated static helpers, minor removal of some dupplicates and superflous part of the code (mostly repetitions) --- src/wolfip.c | 333 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 194 insertions(+), 139 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index cd4bd124..5cf16bb0 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -9994,31 +9994,12 @@ int wolfIP_dns_ptr_lookup(struct wolfIP *s, uint32_t ip, uint16_t *id, void (*lo return dns_send_query(s, ptr_name, id, DNS_PTR); } -/* wolfIP_poll: poll the network stack for incoming packets - * This function should be called in a loop to process incoming packets. - * It will call the poll function of the device driver and process the - * received packets. - * - * This function also handles timers for all supported protocols. - * - * It returns the number of milliseconds to wait before - * calling it again (TODO). - */ -int wolfIP_poll(struct wolfIP *s, uint64_t now) +static void poll_devices(struct wolfIP *s) { - int len = 0; - int i = 0; uint8_t buf[LINK_MTU]; + int len = 0; unsigned int if_idx; - struct wolfIP_timer tmr; - memset(buf, 0, LINK_MTU); - - if (!s) - return -WOLFIP_EINVAL; - - s->last_tick = now; - /* Step 1: Poll the device */ for (if_idx = 0; if_idx < s->if_count; if_idx++) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); int budget = WOLFIP_POLL_BUDGET; @@ -10046,12 +10027,35 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } } while (len > 0 && budget > 0); } - /* Step 2: Handle timers */ - while(is_timer_expired(&s->timers, now)) { +} + +static void handle_timers(struct wolfIP *s) +{ + struct wolfIP_timer tmr; + + while(is_timer_expired(&s->timers, s->last_tick)) { tmr = timers_binheap_pop(&s->timers); tmr.cb(tmr.arg); } - /* Step 3: handle DHCP and application callbacks */ +} + +static void dispatch_events(struct tsocket *socks, int count, uint32_t mark) +{ + int i; + for (i = 0; i < count; i++) { + struct tsocket *ts = &socks[i]; + if (ts->callback && ts->events) { + uint16_t events = ts->events; + ts->events = 0; + ts->callback(i | mark, events, ts->callback_arg); + } + } +} + +static void handle_socket_callbacks(struct wolfIP *s) +{ + int i = 0; + for (i = 0; i < MAX_TCPSOCKETS; i++) { struct tsocket *ts = &s->tcpsockets[i]; @@ -10084,6 +10088,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) ts->events = 0; ts->callback(i | MARK_TCP_SOCKET, events, ts->callback_arg); } + /* Now that CB_EVENT_CLOSED has been delivered, reap the deferred-close * socket. Disarm the callback first so close_socket() takes the plain * teardown path instead of re-deferring (it re-arms close_notify_pending @@ -10095,22 +10100,10 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) close_socket(ts); } } - for (i = 0; i < MAX_UDPSOCKETS; i++) { - struct tsocket *ts = &s->udpsockets[i]; - if ((ts->callback) && (ts->events)) { - uint16_t events = ts->events; - ts->events = 0; - ts->callback(i | MARK_UDP_SOCKET, events, ts->callback_arg); - } - } - for (i = 0; i < MAX_ICMPSOCKETS; i++) { - struct tsocket *ts = &s->icmpsockets[i]; - if ((ts->callback) && (ts->events)) { - uint16_t events = ts->events; - ts->events = 0; - ts->callback(i | MARK_ICMP_SOCKET, events, ts->callback_arg); - } - } + + dispatch_events(s->udpsockets, MAX_UDPSOCKETS, MARK_UDP_SOCKET); + dispatch_events(s->icmpsockets, MAX_ICMPSOCKETS, MARK_ICMP_SOCKET); + #if WOLFIP_RAWSOCKETS for (i = 0; i < WOLFIP_MAX_RAWSOCKETS; i++) { struct rawsocket *r = &s->rawsockets[i]; @@ -10129,14 +10122,15 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } } #endif +} + +static void flush_tcp_tx(struct wolfIP *s, uint64_t now) +{ + int i; - /* Step 4: attempt to write any pending data */ - /** - * TCP - * */ for (i = 0; i < MAX_TCPSOCKETS; i++) { struct tsocket *ts = &s->tcpsockets[i]; - uint32_t in_flight = ts->sock.tcp.bytes_in_flight; + uint32_t in_flight; uint32_t size = 0; uint32_t send_guard = 0; uint32_t send_budget = fifo_desc_budget(&ts->sock.tcp.txbuf); @@ -10152,7 +10146,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } in_flight = ts->sock.tcp.bytes_in_flight; if (ts->sock.tcp.persist_active && (ts->sock.tcp.peer_rwnd > 0 || - !tcp_has_pending_unsent_payload(ts))) + !tcp_has_pending_unsent_payload(ts))) tcp_persist_stop(ts); desc = fifo_peek(&ts->sock.tcp.txbuf); while (desc && send_guard++ < send_budget) { @@ -10166,8 +10160,10 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) break; desc = next_desc; continue; - } else { + } + #ifdef ETHERNET + { ip4 nexthop = wolfIP_select_nexthop_ex(s, &tx_if, ts->remote_ip); if (wolfIP_is_loopback_if(tx_if)) { struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, tx_if); @@ -10180,115 +10176,117 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) break; } } + } #endif - { - uint32_t snd_wnd = ts->sock.tcp.cwnd; - int is_retrans; - uint32_t seg_ip_len; - uint32_t seg_hdr_len; - uint32_t seg_payload_len; - if (ts->sock.tcp.peer_rwnd < snd_wnd) - snd_wnd = ts->sock.tcp.peer_rwnd; - is_retrans = (desc->flags & PKT_FLAG_RETRANS) ? 1 : 0; - seg_ip_len = tcp_tx_desc_ip_len(ts, desc, tcp); - seg_hdr_len = IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2); - seg_payload_len = (seg_ip_len > seg_hdr_len) ? (seg_ip_len - seg_hdr_len) : 0; - if (is_retrans || seg_payload_len == 0 || - (in_flight < snd_wnd && seg_payload_len <= (snd_wnd - in_flight))) { - struct wolfIP_timer new_tmr = {}; - size = seg_ip_len; - tcp = (struct wolfIP_tcp_seg *)(ts->txmem + desc->pos + sizeof(*desc)); - /* Refresh ack counter */ - ts->sock.tcp.last_ack = ts->sock.tcp.ack; - tcp->ack = ee32(ts->sock.tcp.ack); - tcp->win = ee16(tcp_adv_win(ts, 1)); - ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, WI_IPPROTO_TCP, size); - if (wolfIP_filter_notify_tcp(WOLFIP_FILT_SENDING, ts->S, tx_if, tcp, desc->len) != 0) { - break; - } - if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, ts->S, tx_if, &tcp->ip, desc->len) != 0) { - break; - } + { + uint32_t snd_wnd = ts->sock.tcp.cwnd; + int is_retrans; + uint32_t seg_ip_len; + uint32_t seg_hdr_len; + uint32_t seg_payload_len; + if (ts->sock.tcp.peer_rwnd < snd_wnd) + snd_wnd = ts->sock.tcp.peer_rwnd; + is_retrans = (desc->flags & PKT_FLAG_RETRANS) ? 1 : 0; + seg_ip_len = tcp_tx_desc_ip_len(ts, desc, tcp); + seg_hdr_len = IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2); + seg_payload_len = (seg_ip_len > seg_hdr_len) ? (seg_ip_len - seg_hdr_len) : 0; + if (is_retrans || seg_payload_len == 0 || + (in_flight < snd_wnd && seg_payload_len <= (snd_wnd - in_flight))) { + struct wolfIP_timer new_tmr = {}; + size = seg_ip_len; + /* Refresh ack counter */ + ts->sock.tcp.last_ack = ts->sock.tcp.ack; + tcp->ack = ee32(ts->sock.tcp.ack); + tcp->win = ee16(tcp_adv_win(ts, 1)); + ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, WI_IPPROTO_TCP, size); + if (wolfIP_filter_notify_tcp(WOLFIP_FILT_SENDING, ts->S, tx_if, tcp, desc->len) != 0) { + break; + } + if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, ts->S, tx_if, &tcp->ip, desc->len) != 0) { + break; + } #ifdef ETHERNET - if (!wolfIP_ll_is_non_ethernet(ts->S, tx_if)) { - if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, ts->S, tx_if, &tcp->ip.eth, desc->len) != 0) { - break; - } + if (!wolfIP_ll_is_non_ethernet(ts->S, tx_if)) { + if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, ts->S, tx_if, &tcp->ip.eth, desc->len) != 0) { + break; } + } #endif - { - #ifdef WOLFIP_ESP - if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { - struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); - int esp_err = esp_send(ll, (struct wolfIP_ip_packet *)tcp, size); - if (esp_err == 1) { - /* ipsec not configured on this interface. - * send plaintext. */ - send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); - } - } else { + { +#ifdef WOLFIP_ESP + if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); + int esp_err = esp_send(ll, (struct wolfIP_ip_packet *)tcp, size); + if (esp_err == 1) { + /* ipsec not configured on this interface. + * send plaintext. */ send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); } - #else + } else { send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); - #endif /* WOLFIP_ESP */ } - if (send_ret == -WOLFIP_EAGAIN) { - if (tx_has_writable_space(ts)) - ts->events |= CB_EVENT_WRITABLE; - break; - } - if (send_ret < 0) - break; - desc->flags |= PKT_FLAG_SENT; - desc->flags &= ~PKT_FLAG_RETRANS; - if (is_retrans) - desc->flags |= PKT_FLAG_WAS_RETRANS; - desc->time_sent = now; - if (size == IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2)) { - desc = fifo_pop(&ts->sock.tcp.txbuf); - } else { - uint32_t payload_len = size - (IP_HEADER_LEN + (tcp->hlen >> 2)); - if (ts->sock.tcp.tmr_rto != NO_TIMER) { - timer_binheap_cancel(&s->timers, ts->sock.tcp.tmr_rto); - ts->sock.tcp.tmr_rto = NO_TIMER; - } - new_tmr.cb = tcp_rto_cb; - new_tmr.expires = now + (ts->sock.tcp.rto << ts->sock.tcp.rto_backoff); - new_tmr.arg = ts; - ts->sock.tcp.tmr_rto = timers_binheap_insert(&s->timers, new_tmr); - if (!is_retrans) { - in_flight += payload_len; - ts->sock.tcp.bytes_in_flight += payload_len; - } - next_desc = fifo_next(&ts->sock.tcp.txbuf, desc); - if (next_desc == desc) - break; - desc = next_desc; - if (ts->sock.tcp.persist_active && ts->sock.tcp.peer_rwnd > 0) - tcp_persist_stop(ts); +#else + send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); +#endif /* WOLFIP_ESP */ + } + if (send_ret == -WOLFIP_EAGAIN) { + if (tx_has_writable_space(ts)) + ts->events |= CB_EVENT_WRITABLE; + break; + } + if (send_ret < 0) + break; + desc->flags |= PKT_FLAG_SENT; + desc->flags &= ~PKT_FLAG_RETRANS; + if (is_retrans) + desc->flags |= PKT_FLAG_WAS_RETRANS; + desc->time_sent = now; + if (size == IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2)) { + desc = fifo_pop(&ts->sock.tcp.txbuf); + } else { + uint32_t payload_len = size - (IP_HEADER_LEN + (tcp->hlen >> 2)); + if (ts->sock.tcp.tmr_rto != NO_TIMER) { + timer_binheap_cancel(&s->timers, ts->sock.tcp.tmr_rto); + ts->sock.tcp.tmr_rto = NO_TIMER; } - } else { - struct pkt_desc *rexmit_desc = NULL; - if (seg_payload_len > 0 && ts->sock.tcp.peer_rwnd == 0) - tcp_persist_start(ts, now); + new_tmr.cb = tcp_rto_cb; + new_tmr.expires = now + (ts->sock.tcp.rto << ts->sock.tcp.rto_backoff); + new_tmr.arg = ts; + ts->sock.tcp.tmr_rto = timers_binheap_insert(&s->timers, new_tmr); if (!is_retrans) { - rexmit_desc = tcp_find_pending_retrans(ts, desc); - if (rexmit_desc && rexmit_desc != desc) { - desc = rexmit_desc; - continue; - } + in_flight += payload_len; + ts->sock.tcp.bytes_in_flight += payload_len; } - break; + next_desc = fifo_next(&ts->sock.tcp.txbuf, desc); + if (next_desc == desc) + break; + desc = next_desc; + if (ts->sock.tcp.persist_active && ts->sock.tcp.peer_rwnd > 0) + tcp_persist_stop(ts); } + } else { + struct pkt_desc *rexmit_desc = NULL; + if (seg_payload_len > 0 && ts->sock.tcp.peer_rwnd == 0) + tcp_persist_start(ts, now); + if (!is_retrans) { + rexmit_desc = tcp_find_pending_retrans(ts, desc); + if (rexmit_desc && rexmit_desc != desc) { + desc = rexmit_desc; + continue; + } } + break; + } } } } +} + +static void flush_udp_tx(struct wolfIP *s) +{ + int i; + int len; - /* - * UDP - * */ for (i = 0; i < MAX_UDPSOCKETS; i++) { struct tsocket *t = &s->udpsockets[i]; struct pkt_desc *desc = fifo_peek(&t->sock.udp.txbuf); @@ -10375,6 +10373,13 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) if (tx_drained && tx_has_writable_space(t)) t->events |= CB_EVENT_WRITABLE; } +} + +static void flush_icmp_tx(struct wolfIP *s) +{ + int i; + int len; + for (i = 0; i < MAX_ICMPSOCKETS; i++) { struct tsocket *t = &s->icmpsockets[i]; struct pkt_desc *desc = fifo_peek(&t->sock.udp.txbuf); @@ -10434,7 +10439,13 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) desc = fifo_peek(&t->sock.udp.txbuf); } } +} + +static void flush_raw_tx(struct wolfIP *s) +{ #if WOLFIP_RAWSOCKETS + int i; + for (i = 0; i < WOLFIP_MAX_RAWSOCKETS; i++) { struct rawsocket *r = &s->rawsockets[i]; struct pkt_desc *desc; @@ -10491,8 +10502,15 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) (void)nexthop; } } +#else + (void)s; #endif +} + +static void flush_packet_tx(struct wolfIP *s) +{ #if WOLFIP_PACKET_SOCKETS + int i; for (i = 0; i < WOLFIP_MAX_PACKETSOCKETS; i++) { struct packetsocket *p = &s->packetsockets[i]; struct pkt_desc *desc; @@ -10519,7 +10537,44 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) desc = fifo_peek(&p->txbuf); } } +#else + (void)s; #endif +} + +/* wolfIP_poll: poll the network stack for incoming packets + * This function should be called in a loop to process incoming packets. + * It will call the poll function of the device driver and process the + * received packets. + * + * This function also handles timers for all supported protocols. + * + * TODO: Return the number of milliseconds to wait before + * calling it again. + */ +int wolfIP_poll(struct wolfIP *s, uint64_t now) +{ + if (!s) + return -WOLFIP_EINVAL; + + s->last_tick = now; + + /* Poll the device */ + poll_devices(s); + + /* Handle timers */ + handle_timers(s); + + /* Handle socket callbacks */ + handle_socket_callbacks(s); + + /* Attempt to write any pending data for all supported protocols */ + flush_tcp_tx(s, now); + flush_udp_tx(s); + flush_icmp_tx(s); + flush_raw_tx(s); + flush_packet_tx(s); + return 0; } From 30b052b9378b384eb12d3428f494274f309c75ce Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Fri, 12 Jun 2026 03:04:42 -0700 Subject: [PATCH 2/4] Merge the non-ethernet/ethernet logic in poll_devices We only do the actual poll once with the offset to differ between the two branches --- src/wolfip.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 5cf16bb0..233d87b1 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -10006,22 +10006,20 @@ static void poll_devices(struct wolfIP *s) if (!ll || !ll->poll) continue; do { - if (ll->non_ethernet) { - uint32_t frame_mtu = wolfIP_ll_frame_mtu(ll); - if (frame_mtu <= ETH_HEADER_LEN) - break; -#if ETH_HEADER_LEN > 0 - memset(buf, 0, ETH_HEADER_LEN); -#endif - len = ll->poll(ll, buf + ETH_HEADER_LEN, - frame_mtu - ETH_HEADER_LEN); - if (len > 0) - len += ETH_HEADER_LEN; - } else { - len = ll->poll(ll, buf, wolfIP_ll_frame_mtu(ll)); - } + unsigned int off = ll->non_ethernet ? ETH_HEADER_LEN : 0; + uint32_t mtu = wolfIP_ll_frame_mtu(ll); + + if (off && mtu <= off) + break; + + if (off) + memset(buf, 0, off); + + len = ll->poll(ll, buf + off, mtu - off); + if (len > 0) { /* Process packet */ + len += off; wolfIP_recv_on(s, if_idx, buf, len); budget--; } From 1fbb15da608d8eccbe1aaa6cd490b9b78f7c055b Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Fri, 12 Jun 2026 03:07:18 -0700 Subject: [PATCH 3/4] Add now as a parameter to the timer(s) function --- src/wolfip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 233d87b1..930d7173 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -10027,11 +10027,11 @@ static void poll_devices(struct wolfIP *s) } } -static void handle_timers(struct wolfIP *s) +static void handle_timers(struct wolfIP *s, uint64_t now) { struct wolfIP_timer tmr; - while(is_timer_expired(&s->timers, s->last_tick)) { + while(is_timer_expired(&s->timers, now)) { tmr = timers_binheap_pop(&s->timers); tmr.cb(tmr.arg); } @@ -10561,7 +10561,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) poll_devices(s); /* Handle timers */ - handle_timers(s); + handle_timers(s, now); /* Handle socket callbacks */ handle_socket_callbacks(s); From 878a0c85afd99920f2f06c61cf28ebed80d4bdc7 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Fri, 12 Jun 2026 03:37:36 -0700 Subject: [PATCH 4/4] Merge icmp and udp into one single function when reading datagrams The is_udp flag was introduced to differ in 4 bits where udp does something different from icmp: - any multicast interaction (this includes the next jump (hop) and the loopback); - tx_drained logic (that checks if we sent at least one datagram), so that we can "wake" the sender whenever we actually have freed some space in the buffer; One minor bit is the notify logic was using t->S instead of directly using the stack pointer already passed into the function. --- src/wolfip.c | 162 ++++++++++++++++----------------------------------- 1 file changed, 50 insertions(+), 112 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 930d7173..18f32020 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -10280,17 +10280,20 @@ static void flush_tcp_tx(struct wolfIP *s, uint64_t now) } } -static void flush_udp_tx(struct wolfIP *s) +static void flush_datagram_tx(struct wolfIP *s, struct tsocket *socks, + int count, uint8_t proto) { int i; - int len; + int is_udp = (proto == WI_IPPROTO_UDP); - for (i = 0; i < MAX_UDPSOCKETS; i++) { - struct tsocket *t = &s->udpsockets[i]; + for (i = 0; i < count; i++) { + struct tsocket *t = &socks[i]; struct pkt_desc *desc = fifo_peek(&t->sock.udp.txbuf); int tx_drained = 0; + int len; while (desc) { - struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)(t->txmem + desc->pos + sizeof(*desc)); + struct wolfIP_ip_packet *ip = + (struct wolfIP_ip_packet *)(t->txmem + desc->pos + sizeof(*desc)); unsigned int tx_if = wolfIP_socket_if_idx(t); int send_ret = 0; #ifdef ETHERNET @@ -10301,144 +10304,79 @@ static void flush_udp_tx(struct wolfIP *s) memcpy(t->nexthop_mac, loop->mac, 6); } else if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { #ifdef IP_MULTICAST - if (wolfIP_ip_is_multicast(t->remote_ip)) { + if (is_udp && wolfIP_ip_is_multicast(t->remote_ip)) { mcast_ip_to_eth(t->remote_ip, t->nexthop_mac); } else #endif - if ((!wolfIP_ip_is_broadcast(s, nexthop) && - (arp_lookup(s, tx_if, nexthop, t->nexthop_mac) < 0))) { - /* Send ARP request */ - arp_request(s, tx_if, nexthop); - break; - } + if (!wolfIP_ip_is_broadcast(s, nexthop) && + arp_lookup(s, tx_if, nexthop, t->nexthop_mac) < 0) { + /* Send ARP request */ + arp_request(s, tx_if, nexthop); + break; + } if (wolfIP_ip_is_broadcast(s, nexthop)) memset(t->nexthop_mac, 0xFF, 6); } #endif len = desc->len - ETH_HEADER_LEN; - ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len); - if (wolfIP_filter_notify_udp(WOLFIP_FILT_SENDING, t->S, tx_if, udp, desc->len) != 0) - break; - if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, t->S, tx_if, &udp->ip, desc->len) != 0) + ip_output_add_header(t, ip, proto, len); + + if (is_udp) { + if (wolfIP_filter_notify_udp(WOLFIP_FILT_SENDING, s, tx_if, + (struct wolfIP_udp_datagram *)ip, desc->len) != 0) + break; + } else { + if (wolfIP_filter_notify_icmp(WOLFIP_FILT_SENDING, s, tx_if, + (struct wolfIP_icmp_packet *)ip, desc->len) != 0) + break; + } + if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, s, tx_if, ip, desc->len) != 0) break; #ifdef ETHERNET if (!wolfIP_ll_is_non_ethernet(t->S, tx_if)) { - if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, t->S, tx_if, &udp->ip.eth, desc->len) != 0) + if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, s, tx_if, + &ip->eth, desc->len) != 0) break; } #endif - { - #ifdef DEBUG_UDP - wolfIP_print_udp(udp); - #endif /* DEBUG_UDP */ - #ifdef WOLFIP_ESP - if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { - struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); - if (esp_send(ll, (struct wolfIP_ip_packet *)udp, len) == 1) { - /* ipsec not configured on this interface. - * send plaintext. */ - send_ret = wolfIP_ll_send_frame(s, tx_if, udp, desc->len); - } - } else { - send_ret = wolfIP_ll_send_frame(s, tx_if, udp, desc->len); - } - #else - send_ret = wolfIP_ll_send_frame(s, tx_if, udp, desc->len); - #endif /* WOLFIP_ESP */ +#ifdef WOLFIP_ESP + if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); + /* IPsec not configured on this interface. + * Send plaintext instead. + * */ + if (esp_send(ll, ip, len) == 1) + send_ret = wolfIP_ll_send_frame(s, tx_if, ip, desc->len); + } else { + send_ret = wolfIP_ll_send_frame(s, tx_if, ip, desc->len); } - if (send_ret == -WOLFIP_EAGAIN) - break; - if (send_ret < 0) +#else + send_ret = wolfIP_ll_send_frame(s, tx_if, ip, desc->len); +#endif + if (send_ret == -WOLFIP_EAGAIN || send_ret < 0) break; #ifdef IP_MULTICAST - /* Loopback only after a successful wire send. Running udp_try_recv + /* UDP: Loopback only after a successful wire send. Running udp_try_recv * before the filter/send path caused repeated local deliveries * when a SENDING filter blocked the frame or the driver returned * -EAGAIN: the descriptor stays in the txbuf and every subsequent * wolfIP_poll() re-enters the loop and re-loops the datagram. */ - if (wolfIP_ip_is_multicast(t->remote_ip) && t->sock.udp.mcast_loop) { - udp_try_recv(s, tx_if, udp, desc->len); - } + if (is_udp && wolfIP_ip_is_multicast(t->remote_ip) && t->sock.udp.mcast_loop) + udp_try_recv(s, tx_if, (struct wolfIP_udp_datagram *)ip, desc->len); #endif fifo_pop(&t->sock.udp.txbuf); tx_drained = 1; desc = fifo_peek(&t->sock.udp.txbuf); } - /* Draining the txbuf frees space; raise CB_EVENT_WRITABLE so a sender + /* UDP: Draining the txbuf frees space; raise CB_EVENT_WRITABLE so a sender * blocked on a full buffer (e.g. the FreeRTOS BSD shim's sendto()) is * woken. The loopback path is handled separately via * wolfIP_notify_loopback_space_available(). */ - if (tx_drained && tx_has_writable_space(t)) + if (is_udp && tx_drained && tx_has_writable_space(t)) t->events |= CB_EVENT_WRITABLE; } } -static void flush_icmp_tx(struct wolfIP *s) -{ - int i; - int len; - - for (i = 0; i < MAX_ICMPSOCKETS; i++) { - struct tsocket *t = &s->icmpsockets[i]; - struct pkt_desc *desc = fifo_peek(&t->sock.udp.txbuf); - while (desc) { - struct wolfIP_icmp_packet *icmp = (struct wolfIP_icmp_packet *)(t->txmem + desc->pos + sizeof(*desc)); - unsigned int tx_if = wolfIP_socket_if_idx(t); - int send_ret = 0; -#ifdef ETHERNET - ip4 nexthop = wolfIP_select_nexthop_ex(s, &tx_if, t->remote_ip); - if (wolfIP_is_loopback_if(tx_if)) { - struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, tx_if); - if (loop) - memcpy(t->nexthop_mac, loop->mac, 6); - } else if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { - if ((!wolfIP_ip_is_broadcast(s, nexthop) && - (arp_lookup(s, tx_if, nexthop, t->nexthop_mac) < 0))) { - arp_request(s, tx_if, nexthop); - break; - } - if (wolfIP_ip_is_broadcast(s, nexthop)) - memset(t->nexthop_mac, 0xFF, 6); - } -#endif - len = desc->len - ETH_HEADER_LEN; - ip_output_add_header(t, (struct wolfIP_ip_packet *)icmp, WI_IPPROTO_ICMP, len); - if (wolfIP_filter_notify_icmp(WOLFIP_FILT_SENDING, t->S, tx_if, icmp, desc->len) != 0) - break; - if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, t->S, tx_if, &icmp->ip, desc->len) != 0) - break; -#ifdef ETHERNET - if (!wolfIP_ll_is_non_ethernet(t->S, tx_if)) { - if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, t->S, tx_if, &icmp->ip.eth, desc->len) != 0) - break; - } -#endif - { - #ifdef WOLFIP_ESP - if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { - struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); - if (esp_send(ll, (struct wolfIP_ip_packet *)icmp, len) == 1) { - /* ipsec not configured on this interface. - * send plaintext. */ - send_ret = wolfIP_ll_send_frame(s, tx_if, icmp, desc->len); - } - } else { - send_ret = wolfIP_ll_send_frame(s, tx_if, icmp, desc->len); - } - #else - send_ret = wolfIP_ll_send_frame(s, tx_if, icmp, desc->len); - #endif /* WOLFIP_ESP */ - } - if (send_ret == -WOLFIP_EAGAIN) - break; - if (send_ret < 0) - break; - fifo_pop(&t->sock.udp.txbuf); - desc = fifo_peek(&t->sock.udp.txbuf); - } - } -} - static void flush_raw_tx(struct wolfIP *s) { #if WOLFIP_RAWSOCKETS @@ -10568,8 +10506,8 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) /* Attempt to write any pending data for all supported protocols */ flush_tcp_tx(s, now); - flush_udp_tx(s); - flush_icmp_tx(s); + flush_datagram_tx(s, s->udpsockets, MAX_UDPSOCKETS, WI_IPPROTO_UDP); + flush_datagram_tx(s, s->icmpsockets, MAX_ICMPSOCKETS, WI_IPPROTO_ICMP); flush_raw_tx(s); flush_packet_tx(s);