Chapter 165. Raw API
Table of Contents
- 165.1. Overview
- 165.2. Usage
- 165.3. Callbacks
- tcp_arg() — Set the application connection state
- 165.4. TCP connection setup
- tcp_new() — Create a new TCP PCB
- tcp_bind() — Bind PCB to local IP address and port
- tcp_listen() — Make PCB listen for incoming connections
- tcp_accept() — Set callback used for new incoming connections
- tcp_connect() — Open connection to remote host
- 165.5. Sending TCP data
- tcp_write() — Enqueue data for transmission
- tcp_sent() — Set callback for successful transmission
- 165.6. Receiving TCP data
- tcp_recv() — Set callback for incoming data
- tcp_recved() — Indicate receipt of data
- 165.7. Application polling
- tcp_poll() — Set application poll callback
- 165.8. Closing connections, aborting connections and errors
- tcp_close() — Close the connection
- tcp_abort() — Abort the connection
- tcp_err() — Set callback for errors
- 165.9. Lower layer TCP interface
- 165.10. UDP interface
- udp_new() — Create a new UDP pcb
- udp_remove() — Remove a UDP pcb
- udp_bind() — Bind PCB to local IP address and port
- udp_connect() — Set remote UDP peer
- udp_disconnect() — Set remote UDP peer
- udp_send() — Send UDP packet
- udp_recv() — Set callback for incoming UDP data
- 165.11. System initialization
Much of the information in this chapter has been derived from lwIP's own raw API documentation, although additions, modifications and adaptations for eCos have been made.
165.1. Overview
While the high level lwIP sequential API is good for programs that are themselves sequential and can benefit from the blocking open-read-write-close paradigm, lwIP itself is event based by nature. If an application can be written with an event-based approach, then it becomes possible to integrate directly with the event-based design of the core lwIP code.
The raw TCP/IP API allows the application program to integrate better with the TCP/IP code. Program execution is event based by having callback functions being called from within the TCP/IP code. The TCP/IP code and the application program both run in the same thread. The sequential API has a much higher overhead and is not very well suited for small systems since it forces a multithreaded paradigm on the application.
The raw TCP/IP interface is not only faster in terms of code execution time but is also less memory intensive. The drawback is that program development is somewhat harder and application programs written for the raw TCP/IP interface are more difficult to understand. Still, this is the preferred way of writing applications that should be small in code size and memory usage.
Both APIs can be used simultaneously by different application programs. In fact, the sequential API is implemented as an application program using the raw TCP/IP interface.
An example of an application using the raw API can be found in the
tests/
subdirectory of the lwIP eCos
package. This httpd2 test is built when the CDL
configuration option
CYGBLD_NET_LWIP_BUILD_MANUAL_TESTS
is enabled. This raw
API application acts as a simple HTTP server. For more information
see Section 166.2.11, “httpd2”.
165.2. Usage
The raw API is a very direct interface, and is close to the
metal. If the CYGFUN_LWIP_NO_SYS
option is
enabled then there still needs to be a single lwIP owner
thread but an application can be constructed where the main processing
loop of that thread performs lwIP support as well as other application
event processing as required so that only a single stack footprint is
required. The trueraw application is built
when CYGFUN_LWIP_NO_SYS
is configured, and
the CYGBLD_NET_LWIP_BUILD_MANUAL_TESTS
option is
enabled. This provides a simple example of an application using the
raw API without the overhead of the TCP/IP helper thread.
For true raw API applications
the cyg_lwip_init()
function can be used to
initialise the lwIP stack (as for sequential or BSD API applications),
but there is no support for waiting for the network to
be brought up within that function call, since when using a
true raw world the caller of
the cyg_lwip_init()
is also responsible for
processing network packets that may be needed to bring up the network
interface up. If required an application can perform its own lwIP
stack initialization, and does not need to use the eCos default
support.
Note that if you do decide to use cyg_lwip_init()
with the configuration
option CYGFUN_LWIP_SEQUENTIAL_API
disabled, so
that solely the raw API is available, bbut with the configuration
option CYGFUN_LWIP_NO_SYS
also disabled, then the
application will need to provide its own alternative to the
tcpip_input() function which had previously been used to inject
received packets into the stack. This function must be declared as
follows:
err_t tcpip_input
(
struct pbuf *, struct netif *)
;
See Section 165.11, “System initialization” for further details on initialization.
Declarations for the API functions are found in header files within the lwIP include tree.
The TCP functions are found in <lwip/tcp.h>
, and
UDP in <lwip/udp.h>
.
The raw API uses many of the same types and definitions used in the sequential API. In particular the raw API functions use struct ip_addr and err_t error codes.
165.3. Callbacks
- tcp_arg() — Set the application connection state
The configuration option CYGFUN_LWIP_EVENT_CALLBACK
defaults to enabled. If enabled then program execution is driven by
callbacks. Each callback is an ordinary C function that is called from within
the TCP/IP code. Every callback function is passed the current TCP or UDP
connection state as an argument. Also, in order to be able to keep program
specific state, the callback functions are called with a program specified
argument that is independent of the TCP/IP state.
If the CYGFUN_LWIP_EVENT_CALLBACK
option is disabled then a
common user-supplied function is called from within the TCP/IP code instead of
the respective callback routine:
err_t lwip_tcp_event
(
void *arg
, struct tcp_pcb *pcb
, enumlwip_event
, struct pbuf *p
, u16_tsize
, err_terr
)
;
For the individual callbacks or the shared lwip_tcp_event()
the tcp_arg()
function is used for setting the private arg
application
connection state.
165.4. TCP connection setup
- tcp_new() — Create a new TCP PCB
- tcp_bind() — Bind PCB to local IP address and port
- tcp_listen() — Make PCB listen for incoming connections
- tcp_accept() — Set callback used for new incoming connections
- tcp_connect() — Open connection to remote host
The functions used for setting up connections are similar to those of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new()
function. This PCB can then be either set to listen for new incoming
connections or be explicitly connected to another host.
165.5. Sending TCP data
- tcp_write() — Enqueue data for transmission
- tcp_sent() — Set callback for successful transmission
TCP data is sent by enqueueing the data with a call to
tcp_write()
.
When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
165.6. Receiving TCP data
- tcp_recv() — Set callback for incoming data
- tcp_recved() — Indicate receipt of data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the
tcp_recved()
function to indicate that TCP can advertise an increase in the
receive window.
165.7. Application polling
- tcp_poll() — Set application poll callback
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write()
has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
165.8. Closing connections, aborting connections and errors
- tcp_close() — Close the connection
- tcp_abort() — Abort the connection
- tcp_err() — Set callback for errors
165.9. Lower layer TCP interface
TCP provides a simple interface to the lower layers of the system. During
system initialization, the function tcp_init()
has to
be called before any other TCP function is called. When the system is
running, the two timer functions tcp_fasttmr()
and
tcp_slowtmr()
must be called at regular intervals. The
tcp_fasttmr()
should be called every
TCP_FAST_INTERVAL
milliseconds (defined in tcp.h,
and currently 250ms) and
tcp_slowtmr()
should be called every
TCP_SLOW_INTERVAL
milliseconds, currently 500ms.
165.10. UDP interface
- udp_new() — Create a new UDP pcb
- udp_remove() — Remove a UDP pcb
- udp_bind() — Bind PCB to local IP address and port
- udp_connect() — Set remote UDP peer
- udp_disconnect() — Set remote UDP peer
- udp_send() — Send UDP packet
- udp_recv() — Set callback for incoming UDP data
The UDP interface is similar to that of TCP, but due to the lower level of complexity of UDP, the interface is significantly simpler.
165.11. System initialization
When performing manual initialization of lwIP for use with the raw API, the
function lwip_init()
can be called to perform the core
setup. Depending on the
actual lwipopts.h
configuration lwip_init()
will call the necessary routines
to initialize the required lwIP sub-systems.
In this example, these functions must be called in the order of appearance:
-
lwip_init()
Calls the individual, as configured, low-level lwIP module initialization routines.
If
LWIP_ARP
is defined thenetharp_tmr()
must be called at the regularARP_TMR_INTERVAL
interval (default 5 seconds) after the system has been initialized by this call.Similarly if
LWIP_TCP
is defined then you must ensure thattcp_fasttmr()
andtcp_slowtmr()
are called at the predefined regular intervals.-
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif))
Adds your network interface to the
netif_list
. Allocate a struct netif and pass a pointer to this structure as the first argument. Give pointers to cleared struct ip_addr structures when using DHCP, or fill them with sane numbers otherwise. The state pointer may be NULL.The
init
function pointer must point to an initialization function for your ethernet netif interface. The following code illustrates an example use:err_t netif_if_init(struct netif *netif) { u8_t i; for(i = 0; i < 6; i++) netif->hwaddr[i] = some_eth_addr[i]; init_my_eth_device(); return ERR_OK; }
Normally for ethernet devices the
input
function must point to the lwIP functionethernet_input()
.-
netif_set_default(struct netif *netif)
-
Registers
netif
as the default network interface. -
netif_set_up(struct netif *netif)
-
When
netif
is fully configured, this function must be called to allow it to be used. -
dhcp_start(struct netif *netif)
If
LWIP_DHCP
is configured then this function creates a new DHCP client for this interface the first time the routine is called. Note: you must calldhcp_fine_tmr()
anddhcp_coarse_tmr()
at the predefined regular intervals after starting the client.You can peek in the
netif->dhcp
struct for the actual DHCP status.
165.11.1. Initialization detail
If required the manual raw API initialization could directly call the required
lwIP sub-system module initialization functions (rather then calling
the lwip_init()
function).
The calls should be performed in the following order:
-
stats_init()
Clears the structure where runtime statistics are gathered.
Note: The statistics support is only included if
LWIP_STATS
is configured, and then some of the statistics code is only present ifLWIP_DEBUG
is also defined.-
sys_init()
-
Not generally used with raw API, but can be called for ease of compatibility if
using sequential API in addition, initialised
manually. The
lwip_init()
implementation only calls this function ifNO_SYS
is NOT defined. -
mem_init()
-
Initializes the dynamic memory heap defined by the CDL configuration
option
CYGNUM_LWIP_MEM_SIZE
. -
memp_init()
-
Initializes the memory pools defined by the CDL configuration
options
CYGNUM_LWIP_MEMP_NUM_*
. -
pbuf_init()
-
Initializes the pbuf (packet buffer) memory pool defined by the CDL
configuration option
CYGNUM_LWIP_PBUF_POOL_SIZE
. -
netif_init()
-
This function will call
netif_add()
as appropriate to create theLWIP_HAVE_LOOPIF
configured loopback network interface. -
lwip_socket_init()
-
If
LWIP_SOCKET
is configured then this function is called to initialise the BSD-alike API module. It does not do much at present, but it should be called to handle future changes. -
ip_init()
- This function does not do much at present, but it should be called to handle future changes.
-
etharp_init()
Called if
LWIP_ARP
is configured to initialize the ARP table and queue.Note: you must regularly call the
etharp_tmr
function at theARP_TMR_INTERVAL
(default 5 seconds) interval after this initialization.-
raw_init()
-
If
LWIP_RAW
is configured then this function is called. It does not do much at present, but it should be called to handle future changes. -
udp_init()
-
If
LWIP_UDP
is configured then this function is called to initialize the required UDP support state. -
tcp_init()
If
LWIP_TCP
is configured then this function is called to initialise the required TCP support state.Note: you must call
tcp_fasttmr()
andtcp_slowtmr()
at the predefined regular intervals after this initialization.-
snmp_init()
-
If
LWIP_SNMP
is configured then this function is called to start the SNMP agent support. It allocates a UDP pcb and binds it toIP_ADDR_ANY
for theSNMP_IN_PORT
(default161
) configured port, listening for SNMP The routine will also generate a SNMP coldstart trap if configured appropriately. -
autoip_init()
-
If
LWIP_AUTOIP
is configured then this function is called for the IPv4 AutoIP support. It does not do much at present, but it should be called to handle future changes. -
igmp_init()
-
If
LWIP_IGMP
is configured then this function is called for the IPv4 IGMP support. It configures theallsystems
andallroutes
multicast addresses. -
dns_init()
-
If
LWIP_DNS
is configured then this function is called to allocate the UDP pcb for the client and initialise the default DNS server address. -
ip6_init()
-
If
LWIP_IPV6
is configured then this function is called. It does not do much at present, but it should be called to handle future changes. -
nd6_init()
-
If
LWIP_IPV6
is configured then this function is called. It does not do much at present, but it should be called to handle future changes. -
mld6_init()
-
If
LWIP_IPV6
andLWIP_IPV6_MLD
are configured then this function is called. It does not do much at present, but it should be called to handle future changes. -
sys_timeouts_init()
-
If
LWIP_TIMERS
is configured then this function is called. It uses thesys_timeout()
to register timeout callbacks for the configured lwIP features. Normally the raw API will not be providing thesys_timeout
functionality, and will, as mentioned above, have to manually ensure the relevant timeout functions are called. e.g. ARP, TCP, etc.
2024-03-18 | LWIP Documentation Notices |