lwIP Wiki

The raw API (sometimes called native API) is an event-driven API designed to be used without an operating system that implements zero-copy send and receive. This API is also used by the core stack for interaction between the various protocols. It is the only API available when running lwIP without an operating system.

Applications utilizing the lwIP stack are implemented as a set of callback functions, which are then invoked by the lwIP core when activity related to that application occurs. A particular application may register to be notified via a callback function for events such as incoming data available, outgoing data sent, error notifications, poll timer expiration, connection closed, etc. An application can provide a callback function to perform processing for any or all of these events.

Do not confuse the LwIP raw API with raw ethernet or ip sockets. The former is a way of interfacing the lwip network stack (including tcp and udp), the later refers to processing raw ethernet or ip data instead of tcp connections or udp packets.

Multithreading issues[]

When running in a multithreaded environment, raw API functions may only be called from the core thread (aka. the tcpip-thread) since raw API functions are not protected from concurrent access (aside from pbuf- and memory management functions).

Raw API applications may never block since all packet processing (input and output) as well as timer processing (TCP mainly) is done in a single execution context.


The raw API provides access to

  • network layer protocol (IPv4/IPv6)
  • transport layer protocols
  • application layer protocols
    • DHCP
    • AUTOIP
    • SNMP
    • DNS (as of 1.3.0)
  • network interface management functions
  • memory and packet buffer management functions (both dedicated pools and a heap)
  • the operating system abstraction layer

@todo: create sub-chapters for each module!


Official function descriptions for the relevant functions can be found in doc/rawapi.txt. Here are some additional remarks:

  • void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err));
    AFAICS: tcp_accept() should be called after tcp_listen(), as
    • previous calls to tcp_accept() probably get lost when calling tcp_listen().
      The reason is that tcp_listen() allocates a new pcb and apparently does not copy the relevant field (pcb->accept) from the old to the new pcb (see tcp_listen_with_backlog() in lwip/src/core/tcp.c).
    • as the LwIP raw API executes all in one thread, no rx packages will be processed between the call to tcp_listen() and a call to tcp_accept() immediately after. So here there is no danger that the call to tcp_listen() will lead to accepted connections, before the pcb is properly configured via tcp_accept().
  • void tcp_setprio(struct tcp_pcb *pcb, u8_t prio);
    This function is not (yet) documented in doc/rawapi.txt, but it is used in examples without proper documentation. It seems like LwIP can kill low priority tcp connections in favor of higher priority connections if it runs short on memory. This function specifies that priority for a connection.
  • receive callback: err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
    The application can return an error. (A value different from ERR_OK) In this case, the data is hold by the LwIP stack. On the next call of fasttmr(), this data will be passed to the application again and the application can take it or refuse it again. If there is already a data "on hold" and a further package arrives, while the connection is still holding data the application refused, the callback will be called again, trying to pass the data already hold. If the application refuses the data again the package just received will be dropped. (relevant source files: tcp.c and tcp_in.c, search for TCP_EVENT_RECV and refused_data).