Skip to content

Latest commit

 

History

History
341 lines (287 loc) · 17.1 KB

File metadata and controls

341 lines (287 loc) · 17.1 KB

wolfIP API Documentation

Overview

wolfIP is a minimal TCP/IP stack designed for resource-constrained embedded systems. It features zero dynamic memory allocation, using pre-allocated buffers and a fixed number of concurrent sockets.

Key Features

  • No dynamic memory allocation
  • Fixed number of concurrent sockets
  • Pre-allocated buffers for packet processing
  • BSD-like non-blocking socket API with callbacks
  • Protocol Support:
    • ARP (RFC 826)
    • IPv4 (RFC 791)
    • ICMP (RFC 792) - ping replies only
    • DHCP (RFC 2131) - client only
    • DNS (RFC 1035) - client only
    • TFTP (RFC 1350, RFC 2347, RFC 2348, RFC 2349, RFC 7440) via the reusable src/tftp/ module
    • UDP (RFC 768) - unicast, optional IPv4 multicast with IP_MULTICAST
    • TCP (RFC 793) with options (Timestamps, MSS)
    • IPsec ESP (RFC 4303) - transport mode, manual keying, with WOLFIP_ESP

Module How-To Guides

The core socket and stack APIs are documented below. Optional modules and features have dedicated getting-started guides:

  • TLS over wolfIP — running wolfSSL/TLS on wolfIP sockets (WOLFSSL_WOLFIP), the I/O-callback bridge, and non-blocking handshakes.
  • HTTP/HTTPS server — the src/http/ server module (WOLFIP_ENABLE_HTTP), handler registration, and enabling HTTPS via a WOLFSSL_CTX.
  • IPsec ESP how-to — build with WOLFIP_ESP, install Security Associations, and interoperate with Linux ip xfrm.
  • wolfGuard (FIPS WireGuard) — the in-stack WireGuard tunnel (WOLFGUARD), peer/key setup, and kernel interop.
  • TFTP how-to — the callback-driven, allocation-free TFTP client/server in src/tftp/, including the firmware-download pattern.
  • DHCP & DNS clients — acquiring a lease, resolving names with nslookup, and the poll-loop lifecycle.
  • Advanced IPv4 — multicast/IGMP, IPv4 forwarding, multiple interfaces, and loopback.
  • Porting guide — writing device drivers and porting wolfIP to a new OS.

Build Integration

The top-level build systems register reusable module sources from src/tftp/ automatically:

  • Makefile adds any src/tftp/*.c files to the shared library, static library, and top-level executable link sets.
  • CMakeLists.txt globs src/tftp/*.c with CONFIGURE_DEPENDS so the same sources are compiled into the main wolfip and tcpip targets.

The TFTP module is callback-driven and allocation-free. Callers provide the UDP send hook plus open/read/write/close callbacks for storage, and may additionally provide streaming hash-update and final verification callbacks for firmware download flows.

Core Data Structures

Device Driver Interface

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 internal frame budget, 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
};

wolfIP maintains an array of these descriptors sized by WOLFIP_MAX_INTERFACES (default 1). Call wolfIP_getdev_ex() to access a specific slot; the legacy wolfIP_getdev() helper targets the first hardware slot (index 0 normally, or 1 when the optional loopback interface is enabled).

When non_ethernet is set, the interface is treated as L3-only point-to-point: the stack skips ARP/neighbor resolution, omits Ethernet headers on transmit, and expects receive buffers to begin at the IP header. The mtu field still describes wolfIP's internal frame budget including Ethernet headroom, so on non-Ethernet links the payload passed to ll->send() is effectively capped at mtu - ETH_HEADER_LEN on Ethernet-enabled builds.

IP Configuration

struct ipconf {
    struct wolfIP_ll_dev *ll;           // Link layer device
    ip4 ip;                  // IPv4 address
    ip4 mask;                // Subnet mask
    ip4 gw;                  // Default gateway
};

Each struct wolfIP instance owns WOLFIP_MAX_INTERFACES ipconf entries—one per link-layer slot. Use the _ex helpers to read or update a specific interface; the legacy accessors operate on the first hardware interface (index 0 unless loopback support is compiled in).

If WOLFIP_ENABLE_FORWARDING is set to 1 at compile time, the stack performs simple IPv4 forwarding between interfaces. Packets received on one interface whose destinations match another configured interface are re-sent with the IP TTL decreased by one (or an ICMP TTL-exceeded response if the TTL would drop to zero).

Enabling WOLFIP_ENABLE_LOOPBACK (requires WOLFIP_MAX_INTERFACES > 1) creates an internal loopback device at index 0 with the fixed address 127.0.0.1/8. Traffic sent to that address is reflected back through the stack so local sockets, pings, and other services behave as they would on a standard loopback interface; the first hardware interface then shifts to index 1 for legacy helpers.

Socket Address Structures

struct wolfIP_sockaddr_in {
    uint16_t sin_family;     // Address family (AF_INET)
    uint16_t sin_port;       // Port number
    struct sin_addr {
        uint32_t s_addr;     // IPv4 address
    } sin_addr;
};

struct wolfIP_sockaddr {
    uint16_t sa_family;      // Address family
};

Socket Interface Functions

Socket Creation and Control

int wolfIP_sock_socket(struct wolfIP *s, int domain, int type, int protocol);

Creates a new socket.

  • Parameters:
    • s: wolfIP instance
    • domain: Address family (AF_INET)
    • type: Socket type (SOCK_STREAM/SOCK_DGRAM)
    • protocol: Protocol (usually 0)
  • Returns: Socket descriptor or negative error code
int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen);

Binds a socket to a local address.

  • Parameters:
    • s: wolfIP instance
    • sockfd: Socket descriptor
    • addr: Local address to bind to
    • addrlen: Length of address structure
  • Returns: 0 on success, negative error code on failure
int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog);

Marks a socket as passive (listening for connections).

  • Parameters:
    • s: wolfIP instance
    • sockfd: Socket descriptor
    • backlog: Maximum length of pending connections queue
  • Returns: 0 on success, negative error code on failure

Connection Management

int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen);

Initiates a connection on a socket.

  • Parameters:
    • s: wolfIP instance
    • sockfd: Socket descriptor
    • addr: Address to connect to
    • addrlen: Length of address structure
  • Returns: 0 on success, negative error code on failure
int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, socklen_t *addrlen);

Accepts a connection on a listening socket. Only a connection whose handshake has completed (ESTABLISHED, or CLOSE_WAIT when the peer already sent its FIN) is returned. A call while the handshake is still running moves it to a child socket the stack holds back and returns -WOLFIP_EAGAIN; the listener reports CB_EVENT_READABLE again once the child is established, and the next call returns it. So -WOLFIP_EAGAIN can follow CB_EVENT_READABLE, and the caller must not treat it as a connection. A held-back child that is reset or gets no answer after TCP_SYNACK_MAXRTX SYN-ACK retransmissions (default 3) is released silently, and closing the listener resets the ones still held. When the socket table is full, one still in its handshake gives up its slot before a socket the application closed in FIN_WAIT_1, CLOSING or LAST_ACK does. One that completes but is not accepted within TCP_PREACCEPT_TIMEOUT_MS (default 5 s) is reset, as a connection the listener completed itself would be.

  • Parameters:
    • s: wolfIP instance
    • sockfd: Listening socket descriptor
    • addr: Address of connecting peer
    • addrlen: Length of address structure
  • Returns: New socket descriptor, -WOLFIP_EAGAIN when no connection is ready, or another negative error code
int wolfIP_sock_abort(struct wolfIP *s, int sockfd);

Abortive close, like SO_LINGER with a zero timeout: sends an RST in SYN_RCVD, ESTABLISHED, CLOSE_WAIT, FIN_WAIT_1 and FIN_WAIT_2 (other states, such as CLOSING and LAST_ACK, are released without one), and releases the socket at once instead of waiting for a FIN exchange the peer may never complete. Also valid on a socket that wolfIP_sock_close() is still closing, until the stack releases it and its slot is handed out again (see the return values under Data Transfer).

  • Parameters:
    • s: wolfIP instance
    • sockfd: TCP socket descriptor
  • Returns: 0 on success, -WOLFIP_EINVAL for a bad or non-TCP descriptor, -WOLFIP_EBADF for a stale one

Data Transfer

int wolfIP_sock_send(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags);
int wolfIP_sock_recv(struct wolfIP *s, int sockfd, void *buf, size_t len, int flags);

Send/receive data on a connected socket.

  • Parameters:
    • s: wolfIP instance
    • sockfd: Socket descriptor
    • buf: Data buffer
    • len: Buffer length
    • flags: Operation flags
  • Returns: Number of bytes transferred or negative error code
int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags, const struct wolfIP_sockaddr *dest_addr, socklen_t addrlen);
int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, int flags, struct wolfIP_sockaddr *src_addr, socklen_t *addrlen);

Send/receive data on a datagram socket.

  • Parameters similar to send/recv with additional address parameters

wolfIP never blocks, so every call above can ask the caller to retry. On a TCP socket they return:

Value Meaning
> 0 Bytes transferred, possibly fewer than requested
0 End of stream: the peer closed and nothing is left to read
-WOLFIP_EAGAIN Retry later: no data queued, no transmit space, or the socket is still connecting (SYN_SENT/SYN_RCVD)
-WOLFIP_EINVAL Bad descriptor or arguments
-WOLFIP_EBADF Stale descriptor: its socket was released and the slot handed out again
-1 The operation cannot succeed on this socket (a listener, or a closing state)

On a connected socket wolfIP_sock_close() queues a FIN and returns 0, or returns -WOLFIP_EAGAIN when the transmit buffer has no room for the FIN yet, in which case the caller retries. Once the FIN is queued, the stack finishes the exchange and releases the socket by itself, without notification, once the exchange completes, the peer resets, or the close times out. Until then, calling wolfIP_sock_close() again returns 0 without effect; after that, the next wolfIP_sock_socket() or wolfIP_sock_accept() can reuse its slot. When every TCP slot is taken, wolfIP_sock_socket() and wolfIP_sock_accept() take the slot of a socket the application has already closed or has not accepted yet: one in TIME_WAIT first, then FIN_WAIT_2, then a held-back connection still in its handshake, then FIN_WAIT_1, CLOSING or LAST_ACK, resetting the peer where the exchange has not finished. A descriptor carries the generation of its slot in bits 16-30, so once the slot has been handed out again, every call on the old descriptor returns -WOLFIP_EBADF instead of acting on the new socket. The generation wraps after 32768 reuses of the same slot. A slot the stack released on its own (peer reset, retransmission timeout) while the application still holds the descriptor is reused only when no other slot is free; from then on that descriptor, too, answers -WOLFIP_EBADF instead of reporting the connection as closed.

Stack Interface Functions

void wolfIP_init(struct wolfIP *s);

Initializes the TCP/IP stack.

  • Parameters:
    • s: wolfIP instance to initialize
void wolfIP_init_static(struct wolfIP **s);

Initializes a static wolfIP instance.

  • Parameters:
    • s: Pointer to wolfIP instance pointer
size_t wolfIP_instance_size(void);

Returns the size (in bytes) required to store a struct wolfIP. Use this when allocating stacks from custom memory managers.

int wolfIP_poll(struct wolfIP *s, uint64_t now);

Processes pending network events.

  • Parameters:
    • s: wolfIP instance
    • now: Current timestamp
  • Returns: Milliseconds until the stack next needs wolfIP_poll() for its own deadlines, at most WOLFIP_POLL_MAX_WAIT_MS (default 1000); 0 when work is still pending; negative on error. Received frames are not included: a caller that sleeps for the returned time must also wake when its link driver has a frame.
typedef void (*wolfIP_wake_cb)(void *arg);
void wolfIP_set_wake_cb(struct wolfIP *s, wolfIP_wake_cb cb, void *arg);

Registers a callback the stack calls when a socket call (or wolfIP_recv() outside wolfIP_poll()) leaves work for the next wolfIP_poll(), such as a queued frame, a newly armed timer or a socket event raised again after a partial read. While a callback is set, a timer armed between polls starts at the next wolfIP_poll(), when its frame goes out, instead of at the time of the previous one. It is never called from inside wolfIP_poll(), and runs in the caller's context with whatever lock the caller holds, so it should only signal the thread that runs wolfIP_poll(). Pass NULL to unregister. Call it before other threads use the stack, or under the lock that serializes wolfIP_poll() and the socket calls.

void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len);
void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len);

Pass inbound frames to the stack. _ex allows the caller to specify which interface slot produced the frame.

void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw);
void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw);

Set/get IP configuration.

  • Parameters:
    • s: wolfIP instance
    • ip: IPv4 address
    • mask: Subnet mask
    • gw: Default gateway
void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw);
void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw);

Per-interface versions of the IP configuration helpers. The legacy functions target interface 0.

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. For non_ethernet devices this value remains the internal frame budget; the maximum IP bytes handed to the driver are reduced by ETH_HEADER_LEN when Ethernet support is compiled in.

  • Returns: wolfIP_getdev()/wolfIP_getdev_ex() return a pointer to the link-layer descriptor or NULL on invalid interface index; wolfIP_mtu_set() returns 0 on success or a negative error code on failure; wolfIP_mtu_get() returns 0 on success or a negative error code on failure and stores the effective MTU in *mtu.

DHCP Client Functions

Compiled unless WOLFIP_ENABLE_DHCP is set to 0.

int dhcp_client_init(struct wolfIP *s);

Initializes DHCP client.

  • Parameters:
    • s: wolfIP instance
  • Returns: 0 on success, negative error code on failure
int dhcp_bound(struct wolfIP *s);

Checks if DHCP client is bound.

  • Parameters:
    • s: wolfIP instance
  • Returns: 1 if bound, 0 otherwise

DNS Client Functions

int nslookup(struct wolfIP *s, const char *name, uint16_t *id, void (*lookup_cb)(uint32_t ip));

Performs DNS lookup.

  • Parameters:
    • s: wolfIP instance
    • name: Hostname to resolve
    • id: Transaction ID
    • lookup_cb: Callback function for result
  • Returns: 0 on success, negative error code on failure

Utility Functions

uint32_t atou(const char *s);

Converts ASCII string to unsigned integer.

ip4 atoip4(const char *ip);

Converts dotted decimal IP address string to 32-bit integer.

void iptoa(ip4 ip, char *buf);

Converts 32-bit IP address to dotted decimal string.

Event Callback Registration

void wolfIP_register_callback(struct wolfIP *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg);

Registers event callback for a socket.

  • Parameters:
    • s: wolfIP instance
    • sock_fd: Socket descriptor
    • cb: Callback function
    • arg: User data for callback

Event flags:

  • CB_EVENT_READABLE (0x01): Data available or connection accepted
  • CB_EVENT_TIMEOUT (0x02): Operation timed out
  • CB_EVENT_WRITABLE (0x04): Connected or space available to send
  • CB_EVENT_CLOSED (0x10): Connection closed by peer