Add support for raw + af_packet sockets#63
Add support for raw + af_packet sockets#63danielinux wants to merge 12 commits intowolfSSL:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds raw IP socket and AF_PACKET-style packet socket support to wolfIP, including POSIX preload shim enhancements and new example utilities for pinging via the new socket types.
Changes:
- Add RAW and PACKET socket types to the wolfIP socket API, including send/recv/bind/connect/poll support.
- Extend the POSIX LD_PRELOAD BSD socket shim with
ioctl()handling for interface/ARP queries needed by packet sockets. - Add new
raw_ping/packet_pingexamples and run them in CI.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
wolfip.h |
Adds socket constants, socket marks, and sockaddr_ll support plus ARP lookup API. |
src/wolfip.c |
Implements raw sockets + packet sockets, routing/ARP for raw TX, and capture paths for RX. |
src/test/unit/unit.c |
Adds unit tests covering raw/packet socket send/recv behaviors. |
src/test/raw_ping.c |
New raw-socket ping example for CI/manual testing. |
src/test/packet_ping.c |
New AF_PACKET ping example using ioctl-derived interface info. |
src/port/posix/bsd_socket.c |
Adds ioctl() interception and fd bookkeeping for raw/packet sockets. |
config.h |
Enables raw/packet sockets by default and sets default max counts. |
Makefile |
Builds the new ping example binaries. |
.github/workflows/linux.yml |
Runs raw_ping and packet_ping under LD_PRELOAD in CI. |
Comments suppressed due to low confidence (2)
src/test/raw_ping.c:55
- The checksum helper handles odd-length buffers incorrectly: for a trailing byte it should be added as the high-order byte of the final 16-bit word (i.e.,
byte << 8, zero-padded), not as a low-order byte. This matches how Internet checksums are computed (and how the stack’s checksum helpers handle odd lengths).
if (len == 1) {
sum += *(unsigned char *)buf;
}
src/test/packet_ping.c:99
- The checksum helper adds the trailing byte for odd-length buffers without shifting it into the high-order position of the final 16-bit word. For correctness with arbitrary payload sizes, treat the last byte as
byte << 8(zero-padded) whenlenis odd.
if (len == 1) {
sum += *(unsigned char *)buf;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add support for raw sockets and packet sockets. - Added support for BSD wrapper in posix systems. - Added 'raw_ping' and 'packet_ping' examples to craft ICMP echo requests / receive replies using the new sockets - Added automated tests to github workflow
- ioctl(): read vararg as void* to avoid UB when callers pass pointers - bsd_socket.c: fix errno assignments to use -ret (positive) per POSIX - bsd_socket.c: use -WOLFIP_EAGAIN instead of -EAGAIN in recvfrom - wolfip.c: fix packet socket TX filter loop to pop head on reject instead of advancing via fifo_next() (queue corruption fix) - wolfip.c: return -WOLFIP_EMSGSIZE on buffer-too-small in recvfrom for raw, packet, and ICMP socket paths - wolfip.c: packet setsockopt now rejects unsupported options with -WOLFIP_EINVAL instead of silently succeeding - wolfip.c: getsockopt RECVTTL returns enabled state (1/0), not TTL - wolfip.c: arp_lookup_ex returns -WOLFIP_ENOENT on miss - wolfip.h: add WOLFIP_EMSGSIZE and WOLFIP_ENOENT error codes - wolfip.c: fix IS_IP_BCAST -> wolfIP_ip_is_broadcast() after rebase - Add 7 new unit tests covering EMSGSIZE paths, setsockopt rejection, raw socket options, getsockopt behavior, packet TX via poll, and arp_lookup_ex error codes - Update existing tests to match new error return values
- Wrap test_raw_socket_close_clears_entry and test_raw_socket_recv_too_short_drop_returns_einval in #if WOLFIP_RAWSOCKETS guards: struct rawsocket is only defined when the feature is enabled, so accessing s.rawsockets[] and struct members caused compile errors when WOLFIP_RAWSOCKETS=0 - Fix ioctl() vararg: read as uintptr_t then cast to void* to avoid undefined behavior on ABIs where pointer != integer size - Pre-declare loop variable in raw_try_recv() to avoid C99-style for-init declaration inconsistent with the rest of the codebase
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fifo_push(&p->rxbuf, record, record_len); | ||
| p->events |= CB_EVENT_READABLE; |
There was a problem hiding this comment.
packet_try_recv() uses fifo_space() as a pre-check and then ignores fifo_push()'s return value. Since fifo_space() can overestimate available enqueue space due to alignment/wrap, fifo_push() may fail but CB_EVENT_READABLE is still set, leading to spurious wakeups with no data actually queued. Only set READABLE when fifo_push() succeeds (and consider using fifo_can_push_len() to match fifo_push() semantics).
| fifo_push(&p->rxbuf, record, record_len); | |
| p->events |= CB_EVENT_READABLE; | |
| if (fifo_push(&p->rxbuf, record, record_len)) | |
| p->events |= CB_EVENT_READABLE; |
| if (desc->len > len) | ||
| return -WOLFIP_EMSGSIZE; |
There was a problem hiding this comment.
In the raw-socket recvfrom path, when the caller buffer is too small the function returns -WOLFIP_EMSGSIZE but does not dequeue the pending frame or clear CB_EVENT_READABLE. This differs from the ICMP path (which pops the frame on EMSGSIZE) and can cause repeated EMSGSIZE returns with the socket permanently readable. Consider popping the frame (and updating rs->events) on EMSGSIZE to match existing datagram semantics.
| if (desc->len > len) | |
| return -WOLFIP_EMSGSIZE; | |
| if (desc->len > len) { | |
| fifo_pop(&rs->rxbuf); | |
| if (fifo_peek(&rs->rxbuf) == NULL) | |
| rs->events &= ~CB_EVENT_READABLE; | |
| return -WOLFIP_EMSGSIZE; | |
| } |
| if (desc->len - 1 > len) | ||
| return -WOLFIP_EMSGSIZE; |
There was a problem hiding this comment.
In the packet-socket recvfrom path, when the caller buffer is too small the function returns -WOLFIP_EMSGSIZE without dequeuing the frame or clearing CB_EVENT_READABLE. This can leave the same frame at the head forever, causing repeated EMSGSIZE and a permanently-readable socket. Consider dropping the frame (and clearing ps->events when the queue becomes empty) on EMSGSIZE, consistent with the ICMP recvfrom behavior.
| if (desc->len - 1 > len) | |
| return -WOLFIP_EMSGSIZE; | |
| if (desc->len - 1 > len) { | |
| fifo_pop(&ps->rxbuf); | |
| if (fifo_peek(&ps->rxbuf) == NULL) | |
| ps->events &= ~CB_EVENT_READABLE; | |
| return -WOLFIP_EMSGSIZE; | |
| } |
| struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); | ||
| if (ll && ll->send) | ||
| ll->send(ll, ip, desc->len); | ||
| } | ||
| fifo_pop(&r->txbuf); |
There was a problem hiding this comment.
wolfIP_poll() transmits raw-socket TX frames by popping from r->txbuf, but it never sets CB_EVENT_WRITABLE afterward. Since callbacks clear r->events to 0, a thread blocked in the POSIX wrapper waiting for POLLOUT on a full raw TX FIFO may never get another writable notification once space becomes available, leading to a potential deadlock. After draining/popping TX descriptors, set r->events |= CB_EVENT_WRITABLE when the TX FIFO transitions from full->has-space (or is empty / fifo_can_push_len() indicates writable).
| { | ||
| struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); | ||
| if (ll && ll->send) | ||
| ll->send(ll, frame, desc->len); | ||
| } | ||
| fifo_pop(&p->txbuf); |
There was a problem hiding this comment.
wolfIP_poll() transmits packet-socket TX frames by popping from p->txbuf, but it never sets CB_EVENT_WRITABLE afterward. Because poll callbacks clear p->events, a thread waiting for POLLOUT (e.g., via the POSIX wrapper) can block indefinitely once the TX FIFO was full, since no further writable event will be generated when space frees up. After popping TX descriptors, set p->events |= CB_EVENT_WRITABLE when the TX FIFO becomes writable again (e.g., empty or fifo_can_push_len() indicates capacity).
| void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); | ||
| int wolfIP_arp_lookup_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); |
There was a problem hiding this comment.
wolfIP_arp_lookup_ex() is declared unconditionally in the public header, but its implementation in src/wolfip.c is compiled only under #ifdef ETHERNET. In non-ETHERNET builds this can lead to an undefined reference for consumers. Either wrap the prototype in the same conditional or provide a stub implementation that returns an appropriate error when ETHERNET is disabled.
| void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); | |
| int wolfIP_arp_lookup_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); | |
| void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); | |
| #ifdef ETHERNET | |
| int wolfIP_arp_lookup_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); | |
| #endif |
Add support for raw sockets and packet sockets.
Superseeds #10