1 |
Raw TCP/IP interface for lwIP |
---|
2 |
|
---|
3 |
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons |
---|
4 |
|
---|
5 |
lwIP provides two Application Program's Interfaces (APIs) for programs |
---|
6 |
to use for communication with the TCP/IP code: |
---|
7 |
* low-level "core" / "callback" or "raw" API. |
---|
8 |
* higher-level "sequential" API. |
---|
9 |
|
---|
10 |
The sequential API provides a way for ordinary, sequential, programs |
---|
11 |
to use the lwIP stack. It is quite similar to the BSD socket API. The |
---|
12 |
model of execution is based on the blocking open-read-write-close |
---|
13 |
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP |
---|
14 |
code and the application program must reside in different execution |
---|
15 |
contexts (threads). |
---|
16 |
|
---|
17 |
** The remainder of this document discusses the "raw" API. ** |
---|
18 |
|
---|
19 |
The raw TCP/IP interface allows the application program to integrate |
---|
20 |
better with the TCP/IP code. Program execution is event based by |
---|
21 |
having callback functions being called from within the TCP/IP |
---|
22 |
code. The TCP/IP code and the application program both run in the same |
---|
23 |
thread. The sequential API has a much higher overhead and is not very |
---|
24 |
well suited for small systems since it forces a multithreaded paradigm |
---|
25 |
on the application. |
---|
26 |
|
---|
27 |
The raw TCP/IP interface is not only faster in terms of code execution |
---|
28 |
time but is also less memory intensive. The drawback is that program |
---|
29 |
development is somewhat harder and application programs written for |
---|
30 |
the raw TCP/IP interface are more difficult to understand. Still, this |
---|
31 |
is the preferred way of writing applications that should be small in |
---|
32 |
code size and memory usage. |
---|
33 |
|
---|
34 |
Both APIs can be used simultaneously by different application |
---|
35 |
programs. In fact, the sequential API is implemented as an application |
---|
36 |
program using the raw TCP/IP interface. |
---|
37 |
|
---|
38 |
--- Callbacks |
---|
39 |
|
---|
40 |
Program execution is driven by callbacks. Each callback is an ordinary |
---|
41 |
C function that is called from within the TCP/IP code. Every callback |
---|
42 |
function is passed the current TCP or UDP connection state as an |
---|
43 |
argument. Also, in order to be able to keep program specific state, |
---|
44 |
the callback functions are called with a program specified argument |
---|
45 |
that is independent of the TCP/IP state. |
---|
46 |
|
---|
47 |
The function for setting the application connection state is: |
---|
48 |
|
---|
49 |
- void tcp_arg(struct tcp_pcb *pcb, void *arg) |
---|
50 |
|
---|
51 |
Specifies the program specific state that should be passed to all |
---|
52 |
other callback functions. The "pcb" argument is the current TCP |
---|
53 |
connection control block, and the "arg" argument is the argument |
---|
54 |
that will be passed to the callbacks. |
---|
55 |
|
---|
56 |
|
---|
57 |
--- TCP connection setup |
---|
58 |
|
---|
59 |
The functions used for setting up connections is similar to that of |
---|
60 |
the sequential API and of the BSD socket API. A new TCP connection |
---|
61 |
identifier (i.e., a protocol control block - PCB) is created with the |
---|
62 |
tcp_new() function. This PCB can then be either set to listen for new |
---|
63 |
incoming connections or be explicitly connected to another host. |
---|
64 |
|
---|
65 |
- struct tcp_pcb *tcp_new(void) |
---|
66 |
|
---|
67 |
Creates a new connection identifier (PCB). If memory is not |
---|
68 |
available for creating the new pcb, NULL is returned. |
---|
69 |
|
---|
70 |
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, |
---|
71 |
u16_t port) |
---|
72 |
|
---|
73 |
Binds the pcb to a local IP address and port number. The IP address |
---|
74 |
can be specified as IP_ADDR_ANY in order to bind the connection to |
---|
75 |
all local IP addresses. |
---|
76 |
|
---|
77 |
If another connection is bound to the same port, the function will |
---|
78 |
return ERR_USE, otherwise ERR_OK is returned. |
---|
79 |
|
---|
80 |
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) |
---|
81 |
|
---|
82 |
Commands a pcb to start listening for incoming connections. When an |
---|
83 |
incoming connection is accepted, the function specified with the |
---|
84 |
tcp_accept() function will be called. The pcb will have to be bound |
---|
85 |
to a local port with the tcp_bind() function. |
---|
86 |
|
---|
87 |
The tcp_listen() function returns a new connection identifier, and |
---|
88 |
the one passed as an argument to the function will be |
---|
89 |
deallocated. The reason for this behavior is that less memory is |
---|
90 |
needed for a connection that is listening, so tcp_listen() will |
---|
91 |
reclaim the memory needed for the original connection and allocate a |
---|
92 |
new smaller memory block for the listening connection. |
---|
93 |
|
---|
94 |
tcp_listen() may return NULL if no memory was available for the |
---|
95 |
listening connection. If so, the memory associated with the pcb |
---|
96 |
passed as an argument to tcp_listen() will not be deallocated. |
---|
97 |
|
---|
98 |
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) |
---|
99 |
|
---|
100 |
Same as tcp_listen, but limits the number of outstanding connections |
---|
101 |
in the listen queue to the value specified by the backlog argument. |
---|
102 |
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. |
---|
103 |
|
---|
104 |
- void tcp_accepted(struct tcp_pcb *pcb) |
---|
105 |
|
---|
106 |
Inform lwIP that an incoming connection has been accepted. This would |
---|
107 |
usually be called from the accept callback. This allows lwIP to perform |
---|
108 |
housekeeping tasks, such as allowing further incoming connections to be |
---|
109 |
queued in the listen backlog. |
---|
110 |
|
---|
111 |
- void tcp_accept(struct tcp_pcb *pcb, |
---|
112 |
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, |
---|
113 |
err_t err)) |
---|
114 |
|
---|
115 |
Specified the callback function that should be called when a new |
---|
116 |
connection arrives on a listening connection. |
---|
117 |
|
---|
118 |
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, |
---|
119 |
u16_t port, err_t (* connected)(void *arg, |
---|
120 |
struct tcp_pcb *tpcb, |
---|
121 |
err_t err)); |
---|
122 |
|
---|
123 |
Sets up the pcb to connect to the remote host and sends the |
---|
124 |
initial SYN segment which opens the connection. |
---|
125 |
|
---|
126 |
The tcp_connect() function returns immediately; it does not wait for |
---|
127 |
the connection to be properly setup. Instead, it will call the |
---|
128 |
function specified as the fourth argument (the "connected" argument) |
---|
129 |
when the connection is established. If the connection could not be |
---|
130 |
properly established, either because the other host refused the |
---|
131 |
connection or because the other host didn't answer, the "connected" |
---|
132 |
function will be called with an the "err" argument set accordingly. |
---|
133 |
|
---|
134 |
The tcp_connect() function can return ERR_MEM if no memory is |
---|
135 |
available for enqueueing the SYN segment. If the SYN indeed was |
---|
136 |
enqueued successfully, the tcp_connect() function returns ERR_OK. |
---|
137 |
|
---|
138 |
|
---|
139 |
--- Sending TCP data |
---|
140 |
|
---|
141 |
TCP data is sent by enqueueing the data with a call to |
---|
142 |
tcp_write(). When the data is successfully transmitted to the remote |
---|
143 |
host, the application will be notified with a call to a specified |
---|
144 |
callback function. |
---|
145 |
|
---|
146 |
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, |
---|
147 |
u8_t copy) |
---|
148 |
|
---|
149 |
Enqueues the data pointed to by the argument dataptr. The length of |
---|
150 |
the data is passed as the len parameter. The copy argument is either |
---|
151 |
0 or 1 and indicates whether the new memory should be allocated for |
---|
152 |
the data to be copied into. If the argument is 0, no new memory |
---|
153 |
should be allocated and the data should only be referenced by |
---|
154 |
pointer. |
---|
155 |
|
---|
156 |
The tcp_write() function will fail and return ERR_MEM if the length |
---|
157 |
of the data exceeds the current send buffer size or if the length of |
---|
158 |
the queue of outgoing segment is larger than the upper limit defined |
---|
159 |
in lwipopts.h. The number of bytes available in the output queue can |
---|
160 |
be retrieved with the tcp_sndbuf() function. |
---|
161 |
|
---|
162 |
The proper way to use this function is to call the function with at |
---|
163 |
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, |
---|
164 |
the application should wait until some of the currently enqueued |
---|
165 |
data has been successfully received by the other host and try again. |
---|
166 |
|
---|
167 |
- void tcp_sent(struct tcp_pcb *pcb, |
---|
168 |
err_t (* sent)(void *arg, struct tcp_pcb *tpcb, |
---|
169 |
u16_t len)) |
---|
170 |
|
---|
171 |
Specifies the callback function that should be called when data has |
---|
172 |
successfully been received (i.e., acknowledged) by the remote |
---|
173 |
host. The len argument passed to the callback function gives the |
---|
174 |
amount bytes that was acknowledged by the last acknowledgment. |
---|
175 |
|
---|
176 |
|
---|
177 |
--- Receiving TCP data |
---|
178 |
|
---|
179 |
TCP data reception is callback based - an application specified |
---|
180 |
callback function is called when new data arrives. When the |
---|
181 |
application has taken the data, it has to call the tcp_recved() |
---|
182 |
function to indicate that TCP can advertise increase the receive |
---|
183 |
window. |
---|
184 |
|
---|
185 |
- void tcp_recv(struct tcp_pcb *pcb, |
---|
186 |
err_t (* recv)(void *arg, struct tcp_pcb *tpcb, |
---|
187 |
struct pbuf *p, err_t err)) |
---|
188 |
|
---|
189 |
Sets the callback function that will be called when new data |
---|
190 |
arrives. The callback function will be passed a NULL pbuf to |
---|
191 |
indicate that the remote host has closed the connection. If |
---|
192 |
there are no errors and the callback function is to return |
---|
193 |
ERR_OK, then it must free the pbuf. Otherwise, it must not |
---|
194 |
free the pbuf so that lwIP core code can store it. |
---|
195 |
|
---|
196 |
- void tcp_recved(struct tcp_pcb *pcb, u16_t len) |
---|
197 |
|
---|
198 |
Must be called when the application has received the data. The len |
---|
199 |
argument indicates the length of the received data. |
---|
200 |
|
---|
201 |
|
---|
202 |
--- Application polling |
---|
203 |
|
---|
204 |
When a connection is idle (i.e., no data is either transmitted or |
---|
205 |
received), lwIP will repeatedly poll the application by calling a |
---|
206 |
specified callback function. This can be used either as a watchdog |
---|
207 |
timer for killing connections that have stayed idle for too long, or |
---|
208 |
as a method of waiting for memory to become available. For instance, |
---|
209 |
if a call to tcp_write() has failed because memory wasn't available, |
---|
210 |
the application may use the polling functionality to call tcp_write() |
---|
211 |
again when the connection has been idle for a while. |
---|
212 |
|
---|
213 |
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval, |
---|
214 |
err_t (* poll)(void *arg, struct tcp_pcb *tpcb)) |
---|
215 |
|
---|
216 |
Specifies the polling interval and the callback function that should |
---|
217 |
be called to poll the application. The interval is specified in |
---|
218 |
number of TCP coarse grained timer shots, which typically occurs |
---|
219 |
twice a second. An interval of 10 means that the application would |
---|
220 |
be polled every 5 seconds. |
---|
221 |
|
---|
222 |
|
---|
223 |
--- Closing and aborting connections |
---|
224 |
|
---|
225 |
- err_t tcp_close(struct tcp_pcb *pcb) |
---|
226 |
|
---|
227 |
Closes the connection. The function may return ERR_MEM if no memory |
---|
228 |
was available for closing the connection. If so, the application |
---|
229 |
should wait and try again either by using the acknowledgment |
---|
230 |
callback or the polling functionality. If the close succeeds, the |
---|
231 |
function returns ERR_OK. |
---|
232 |
|
---|
233 |
The pcb is deallocated by the TCP code after a call to tcp_close(). |
---|
234 |
|
---|
235 |
- void tcp_abort(struct tcp_pcb *pcb) |
---|
236 |
|
---|
237 |
Aborts the connection by sending a RST (reset) segment to the remote |
---|
238 |
host. The pcb is deallocated. This function never fails. |
---|
239 |
|
---|
240 |
If a connection is aborted because of an error, the application is |
---|
241 |
alerted of this event by the err callback. Errors that might abort a |
---|
242 |
connection are when there is a shortage of memory. The callback |
---|
243 |
function to be called is set using the tcp_err() function. |
---|
244 |
|
---|
245 |
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, |
---|
246 |
err_t err)) |
---|
247 |
|
---|
248 |
The error callback function does not get the pcb passed to it as a |
---|
249 |
parameter since the pcb may already have been deallocated. |
---|
250 |
|
---|
251 |
|
---|
252 |
--- Lower layer TCP interface |
---|
253 |
|
---|
254 |
TCP provides a simple interface to the lower layers of the |
---|
255 |
system. During system initialization, the function tcp_init() has |
---|
256 |
to be called before any other TCP function is called. When the system |
---|
257 |
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr() |
---|
258 |
must be called with regular intervals. The tcp_fasttmr() should be |
---|
259 |
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and |
---|
260 |
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds. |
---|
261 |
|
---|
262 |
|
---|
263 |
--- UDP interface |
---|
264 |
|
---|
265 |
The UDP interface is similar to that of TCP, but due to the lower |
---|
266 |
level of complexity of UDP, the interface is significantly simpler. |
---|
267 |
|
---|
268 |
- struct udp_pcb *udp_new(void) |
---|
269 |
|
---|
270 |
Creates a new UDP pcb which can be used for UDP communication. The |
---|
271 |
pcb is not active until it has either been bound to a local address |
---|
272 |
or connected to a remote address. |
---|
273 |
|
---|
274 |
- void udp_remove(struct udp_pcb *pcb) |
---|
275 |
|
---|
276 |
Removes and deallocates the pcb. |
---|
277 |
|
---|
278 |
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, |
---|
279 |
u16_t port) |
---|
280 |
|
---|
281 |
Binds the pcb to a local address. The IP-address argument "ipaddr" |
---|
282 |
can be IP_ADDR_ANY to indicate that it should listen to any local IP |
---|
283 |
address. The function currently always return ERR_OK. |
---|
284 |
|
---|
285 |
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, |
---|
286 |
u16_t port) |
---|
287 |
|
---|
288 |
Sets the remote end of the pcb. This function does not generate any |
---|
289 |
network traffic, but only set the remote address of the pcb. |
---|
290 |
|
---|
291 |
- err_t udp_disconnect(struct udp_pcb *pcb) |
---|
292 |
|
---|
293 |
Remove the remote end of the pcb. This function does not generate |
---|
294 |
any network traffic, but only removes the remote address of the pcb. |
---|
295 |
|
---|
296 |
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) |
---|
297 |
|
---|
298 |
Sends the pbuf p. The pbuf is not deallocated. |
---|
299 |
|
---|
300 |
- void udp_recv(struct udp_pcb *pcb, |
---|
301 |
void (* recv)(void *arg, struct udp_pcb *upcb, |
---|
302 |
struct pbuf *p, |
---|
303 |
struct ip_addr *addr, |
---|
304 |
u16_t port), |
---|
305 |
void *recv_arg) |
---|
306 |
|
---|
307 |
Specifies a callback function that should be called when a UDP |
---|
308 |
datagram is received. |
---|
309 |
|
---|
310 |
|
---|
311 |
--- System initalization |
---|
312 |
|
---|
313 |
A truly complete and generic sequence for initializing the lwip stack |
---|
314 |
cannot be given because it depends on the build configuration (lwipopts.h) |
---|
315 |
and additional initializations for your runtime environment (e.g. timers). |
---|
316 |
|
---|
317 |
We can give you some idea on how to proceed when using the raw API. |
---|
318 |
We assume a configuration using a single Ethernet netif and the |
---|
319 |
UDP and TCP transport layers, IPv4 and the DHCP client. |
---|
320 |
|
---|
321 |
Call these functions in the order of appearance: |
---|
322 |
|
---|
323 |
- stats_init() |
---|
324 |
|
---|
325 |
Clears the structure where runtime statistics are gathered. |
---|
326 |
|
---|
327 |
- sys_init() |
---|
328 |
|
---|
329 |
Not of much use since we set the NO_SYS 1 option in lwipopts.h, |
---|
330 |
to be called for easy configuration changes. |
---|
331 |
|
---|
332 |
- mem_init() |
---|
333 |
|
---|
334 |
Initializes the dynamic memory heap defined by MEM_SIZE. |
---|
335 |
|
---|
336 |
- memp_init() |
---|
337 |
|
---|
338 |
Initializes the memory pools defined by MEMP_NUM_x. |
---|
339 |
|
---|
340 |
- pbuf_init() |
---|
341 |
|
---|
342 |
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE. |
---|
343 |
|
---|
344 |
- etharp_init() |
---|
345 |
|
---|
346 |
Initializes the ARP table and queue. |
---|
347 |
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval |
---|
348 |
after this initialization. |
---|
349 |
|
---|
350 |
- ip_init() |
---|
351 |
|
---|
352 |
Doesn't do much, it should be called to handle future changes. |
---|
353 |
|
---|
354 |
- udp_init() |
---|
355 |
|
---|
356 |
Clears the UDP PCB list. |
---|
357 |
|
---|
358 |
- tcp_init() |
---|
359 |
|
---|
360 |
Clears the TCP PCB list and clears some internal TCP timers. |
---|
361 |
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the |
---|
362 |
predefined regular intervals after this initialization. |
---|
363 |
|
---|
364 |
- netif_add(struct netif *netif, struct ip_addr *ipaddr, |
---|
365 |
struct ip_addr *netmask, struct ip_addr *gw, |
---|
366 |
void *state, err_t (* init)(struct netif *netif), |
---|
367 |
err_t (* input)(struct pbuf *p, struct netif *netif)) |
---|
368 |
|
---|
369 |
Adds your network interface to the netif_list. Allocate a struct |
---|
370 |
netif and pass a pointer to this structure as the first argument. |
---|
371 |
Give pointers to cleared ip_addr structures when using DHCP, |
---|
372 |
or fill them with sane numbers otherwise. The state pointer may be NULL. |
---|
373 |
|
---|
374 |
The init function pointer must point to a initialization function for |
---|
375 |
your ethernet netif interface. The following code illustrates it's use. |
---|
376 |
|
---|
377 |
err_t netif_if_init(struct netif *netif) |
---|
378 |
{ |
---|
379 |
u8_t i; |
---|
380 |
|
---|
381 |
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i]; |
---|
382 |
init_my_eth_device(); |
---|
383 |
return ERR_OK; |
---|
384 |
} |
---|
385 |
|
---|
386 |
For ethernet drivers, the input function pointer must point to the lwip |
---|
387 |
function ethernet_input() declared in "netif/etharp.h". Other drivers |
---|
388 |
must use ip_input() declared in "lwip/ip.h". |
---|
389 |
|
---|
390 |
- netif_set_default(struct netif *netif) |
---|
391 |
|
---|
392 |
Registers the default network interface. |
---|
393 |
|
---|
394 |
- netif_set_up(struct netif *netif) |
---|
395 |
|
---|
396 |
When the netif is fully configured this function must be called. |
---|
397 |
|
---|
398 |
- dhcp_start(struct netif *netif) |
---|
399 |
|
---|
400 |
Creates a new DHCP client for this interface on the first call. |
---|
401 |
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at |
---|
402 |
the predefined regular intervals after starting the client. |
---|
403 |
|
---|
404 |
You can peek in the netif->dhcp struct for the actual DHCP status. |
---|
405 |
|
---|
406 |
|
---|
407 |
--- Optimalization hints |
---|
408 |
|
---|
409 |
The first thing you want to optimize is the lwip_standard_checksum() |
---|
410 |
routine from src/core/inet.c. You can override this standard |
---|
411 |
function with the #define LWIP_CHKSUM <your_checksum_routine>. |
---|
412 |
|
---|
413 |
There are C examples given in inet.c or you might want to |
---|
414 |
craft an assembly function for this. RFC1071 is a good |
---|
415 |
introduction to this subject. |
---|
416 |
|
---|
417 |
Other significant improvements can be made by supplying |
---|
418 |
assembly or inline replacements for htons() and htonl() |
---|
419 |
if you're using a little-endian architecture. |
---|
420 |
#define LWIP_PLATFORM_BYTESWAP 1 |
---|
421 |
#define LWIP_PLATFORM_HTONS(x) <your_htons> |
---|
422 |
#define LWIP_PLATFORM_HTONL(x) <your_htonl> |
---|
423 |
|
---|
424 |
Check your network interface driver if it reads at |
---|
425 |
a higher speed than the maximum wire-speed. If the |
---|
426 |
hardware isn't serviced frequently and fast enough |
---|
427 |
buffer overflows are likely to occur. |
---|
428 |
|
---|
429 |
E.g. when using the cs8900 driver, call cs8900if_service(ethif) |
---|
430 |
as frequently as possible. When using an RTOS let the cs8900 interrupt |
---|
431 |
wake a high priority task that services your driver using a binary |
---|
432 |
semaphore or event flag. Some drivers might allow additional tuning |
---|
433 |
to match your application and network. |
---|
434 |
|
---|
435 |
For a production release it is recommended to set LWIP_STATS to 0. |
---|
436 |
Note that speed performance isn't influenced much by simply setting |
---|
437 |
high values to the memory options. |
---|