3 * Sequential API Main thread module
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
41 #if !NO_SYS /* don't build if not configured for use in lwipopts.h */
44 #include "lwip/memp.h"
46 #include "lwip/pbuf.h"
47 #include "lwip/tcpip.h"
48 #include "lwip/init.h"
49 #include "netif/etharp.h"
50 #include "netif/ppp_oe.h"
52 /* global variables */
53 static tcpip_init_done_fn tcpip_init_done
;
54 static void *tcpip_init_done_arg
;
55 static sys_mbox_t mbox
;
57 #if LWIP_TCPIP_CORE_LOCKING
58 /** The global semaphore to lock the stack. */
59 sys_mutex_t lock_tcpip_core
;
60 #endif /* LWIP_TCPIP_CORE_LOCKING */
64 * The main lwIP thread. This thread has exclusive access to lwIP core functions
65 * (unless access to them is not locked). Other threads communicate with this
66 * thread using message boxes.
68 * It also starts all the timers to make sure they are running in the right
71 * @param arg unused argument
74 tcpip_thread(void *arg
)
76 struct tcpip_msg
*msg
;
79 if (tcpip_init_done
!= NULL
) {
80 tcpip_init_done(tcpip_init_done_arg
);
84 while (1) { /* MAIN Loop */
86 LWIP_TCPIP_THREAD_ALIVE();
87 /* wait for a message, timeouts are processed while waiting */
88 sys_timeouts_mbox_fetch(&mbox
, (void **)&msg
);
93 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: API message %p\n", (void *)msg
));
94 msg
->msg
.apimsg
->function(&(msg
->msg
.apimsg
->msg
));
96 #endif /* LWIP_NETCONN */
98 #if !LWIP_TCPIP_CORE_LOCKING_INPUT
100 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: PACKET %p\n", (void *)msg
));
102 if (msg
->msg
.inp
.netif
->flags
& (NETIF_FLAG_ETHARP
| NETIF_FLAG_ETHERNET
)) {
103 ethernet_input(msg
->msg
.inp
.p
, msg
->msg
.inp
.netif
);
105 #endif /* LWIP_ETHERNET */
107 ip_input(msg
->msg
.inp
.p
, msg
->msg
.inp
.netif
);
109 memp_free(MEMP_TCPIP_MSG_INPKT
, msg
);
111 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
114 case TCPIP_MSG_NETIFAPI
:
115 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: Netif API message %p\n", (void *)msg
));
116 msg
->msg
.netifapimsg
->function(&(msg
->msg
.netifapimsg
->msg
));
118 #endif /* LWIP_NETIF_API */
120 #if LWIP_TCPIP_TIMEOUT
121 case TCPIP_MSG_TIMEOUT
:
122 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: TIMEOUT %p\n", (void *)msg
));
123 sys_timeout(msg
->msg
.tmo
.msecs
, msg
->msg
.tmo
.h
, msg
->msg
.tmo
.arg
);
124 memp_free(MEMP_TCPIP_MSG_API
, msg
);
126 case TCPIP_MSG_UNTIMEOUT
:
127 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg
));
128 sys_untimeout(msg
->msg
.tmo
.h
, msg
->msg
.tmo
.arg
);
129 memp_free(MEMP_TCPIP_MSG_API
, msg
);
131 #endif /* LWIP_TCPIP_TIMEOUT */
133 case TCPIP_MSG_CALLBACK
:
134 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: CALLBACK %p\n", (void *)msg
));
135 msg
->msg
.cb
.function(msg
->msg
.cb
.ctx
);
136 memp_free(MEMP_TCPIP_MSG_API
, msg
);
139 case TCPIP_MSG_CALLBACK_STATIC
:
140 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg
));
141 msg
->msg
.cb
.function(msg
->msg
.cb
.ctx
);
145 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_thread: invalid message: %d\n", msg
->type
));
146 LWIP_ASSERT("tcpip_thread: invalid message", 0);
153 * Pass a received packet to tcpip_thread for input processing
155 * @param p the received packet, p->payload pointing to the Ethernet header or
156 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
157 * NETIF_FLAG_ETHERNET flags)
158 * @param inp the network interface on which the packet was received
161 tcpip_input(struct pbuf
*p
, struct netif
*inp
)
163 #if LWIP_TCPIP_CORE_LOCKING_INPUT
165 LWIP_DEBUGF(TCPIP_DEBUG
, ("tcpip_input: PACKET %p/%p\n", (void *)p
, (void *)inp
));
168 if (inp
->flags
& (NETIF_FLAG_ETHARP
| NETIF_FLAG_ETHERNET
)) {
169 ret
= ethernet_input(p
, inp
);
171 #endif /* LWIP_ETHERNET */
173 ret
= ip_input(p
, inp
);
177 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
178 struct tcpip_msg
*msg
;
180 if (!sys_mbox_valid(&mbox
)) {
183 msg
= (struct tcpip_msg
*)memp_malloc(MEMP_TCPIP_MSG_INPKT
);
188 msg
->type
= TCPIP_MSG_INPKT
;
190 msg
->msg
.inp
.netif
= inp
;
191 if (sys_mbox_trypost(&mbox
, msg
) != ERR_OK
) {
192 memp_free(MEMP_TCPIP_MSG_INPKT
, msg
);
196 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
200 * Call a specific function in the thread context of
201 * tcpip_thread for easy access synchronization.
202 * A function called in that way may access lwIP core code
203 * without fearing concurrent access.
205 * @param f the function to call
206 * @param ctx parameter passed to f
207 * @param block 1 to block until the request is posted, 0 to non-blocking mode
208 * @return ERR_OK if the function was called, another err_t if not
211 tcpip_callback_with_block(tcpip_callback_fn function
, void *ctx
, u8_t block
)
213 struct tcpip_msg
*msg
;
215 if (sys_mbox_valid(&mbox
)) {
216 msg
= (struct tcpip_msg
*)memp_malloc(MEMP_TCPIP_MSG_API
);
221 msg
->type
= TCPIP_MSG_CALLBACK
;
222 msg
->msg
.cb
.function
= function
;
223 msg
->msg
.cb
.ctx
= ctx
;
225 sys_mbox_post(&mbox
, msg
);
227 if (sys_mbox_trypost(&mbox
, msg
) != ERR_OK
) {
228 memp_free(MEMP_TCPIP_MSG_API
, msg
);
237 #if LWIP_TCPIP_TIMEOUT
239 * call sys_timeout in tcpip_thread
241 * @param msec time in milliseconds for timeout
242 * @param h function to be called on timeout
243 * @param arg argument to pass to timeout function h
244 * @return ERR_MEM on memory error, ERR_OK otherwise
247 tcpip_timeout(u32_t msecs
, sys_timeout_handler h
, void *arg
)
249 struct tcpip_msg
*msg
;
251 if (sys_mbox_valid(&mbox
)) {
252 msg
= (struct tcpip_msg
*)memp_malloc(MEMP_TCPIP_MSG_API
);
257 msg
->type
= TCPIP_MSG_TIMEOUT
;
258 msg
->msg
.tmo
.msecs
= msecs
;
260 msg
->msg
.tmo
.arg
= arg
;
261 sys_mbox_post(&mbox
, msg
);
268 * call sys_untimeout in tcpip_thread
270 * @param msec time in milliseconds for timeout
271 * @param h function to be called on timeout
272 * @param arg argument to pass to timeout function h
273 * @return ERR_MEM on memory error, ERR_OK otherwise
276 tcpip_untimeout(sys_timeout_handler h
, void *arg
)
278 struct tcpip_msg
*msg
;
280 if (sys_mbox_valid(&mbox
)) {
281 msg
= (struct tcpip_msg
*)memp_malloc(MEMP_TCPIP_MSG_API
);
286 msg
->type
= TCPIP_MSG_UNTIMEOUT
;
288 msg
->msg
.tmo
.arg
= arg
;
289 sys_mbox_post(&mbox
, msg
);
294 #endif /* LWIP_TCPIP_TIMEOUT */
298 * Call the lower part of a netconn_* function
299 * This function is then running in the thread context
300 * of tcpip_thread and has exclusive access to lwIP core code.
302 * @param apimsg a struct containing the function to call and its parameters
303 * @return ERR_OK if the function was called, another err_t if not
306 tcpip_apimsg(struct api_msg
*apimsg
)
308 struct tcpip_msg msg
;
310 /* catch functions that don't set err */
311 apimsg
->msg
.err
= ERR_VAL
;
314 if (sys_mbox_valid(&mbox
)) {
315 msg
.type
= TCPIP_MSG_API
;
316 msg
.msg
.apimsg
= apimsg
;
317 sys_mbox_post(&mbox
, &msg
);
318 sys_arch_sem_wait(&apimsg
->msg
.conn
->op_completed
, 0);
319 return apimsg
->msg
.err
;
324 #if LWIP_TCPIP_CORE_LOCKING
326 * Call the lower part of a netconn_* function
327 * This function has exclusive access to lwIP core code by locking it
328 * before the function is called.
330 * @param apimsg a struct containing the function to call and its parameters
331 * @return ERR_OK (only for compatibility fo tcpip_apimsg())
334 tcpip_apimsg_lock(struct api_msg
*apimsg
)
337 /* catch functions that don't set err */
338 apimsg
->msg
.err
= ERR_VAL
;
342 apimsg
->function(&(apimsg
->msg
));
344 return apimsg
->msg
.err
;
347 #endif /* LWIP_TCPIP_CORE_LOCKING */
348 #endif /* LWIP_NETCONN */
351 #if !LWIP_TCPIP_CORE_LOCKING
353 * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
356 * @param netifapimsg a struct containing the function to call and its parameters
357 * @return error code given back by the function that was called
360 tcpip_netifapi(struct netifapi_msg
* netifapimsg
)
362 struct tcpip_msg msg
;
364 if (sys_mbox_valid(&mbox
)) {
365 err_t err
= sys_sem_new(&netifapimsg
->msg
.sem
, 0);
367 netifapimsg
->msg
.err
= err
;
371 msg
.type
= TCPIP_MSG_NETIFAPI
;
372 msg
.msg
.netifapimsg
= netifapimsg
;
373 sys_mbox_post(&mbox
, &msg
);
374 sys_sem_wait(&netifapimsg
->msg
.sem
);
375 sys_sem_free(&netifapimsg
->msg
.sem
);
376 return netifapimsg
->msg
.err
;
380 #else /* !LWIP_TCPIP_CORE_LOCKING */
382 * Call the lower part of a netifapi_* function
383 * This function has exclusive access to lwIP core code by locking it
384 * before the function is called.
386 * @param netifapimsg a struct containing the function to call and its parameters
387 * @return ERR_OK (only for compatibility fo tcpip_netifapi())
390 tcpip_netifapi_lock(struct netifapi_msg
* netifapimsg
)
393 netifapimsg
->function(&(netifapimsg
->msg
));
395 return netifapimsg
->msg
.err
;
397 #endif /* !LWIP_TCPIP_CORE_LOCKING */
398 #endif /* LWIP_NETIF_API */
401 * Allocate a structure for a static callback message and initialize it.
402 * This is intended to be used to send "static" messages from interrupt context.
404 * @param function the function to call
405 * @param ctx parameter passed to function
406 * @return a struct pointer to pass to tcpip_trycallback().
408 struct tcpip_callback_msg
* tcpip_callbackmsg_new(tcpip_callback_fn function
, void *ctx
)
410 struct tcpip_msg
*msg
= (struct tcpip_msg
*)memp_malloc(MEMP_TCPIP_MSG_API
);
414 msg
->type
= TCPIP_MSG_CALLBACK_STATIC
;
415 msg
->msg
.cb
.function
= function
;
416 msg
->msg
.cb
.ctx
= ctx
;
417 return (struct tcpip_callback_msg
*)msg
;
421 * Free a callback message allocated by tcpip_callbackmsg_new().
423 * @param msg the message to free
425 void tcpip_callbackmsg_delete(struct tcpip_callback_msg
* msg
)
427 memp_free(MEMP_TCPIP_MSG_API
, msg
);
431 * Try to post a callback-message to the tcpip_thread mbox
432 * This is intended to be used to send "static" messages from interrupt context.
434 * @param msg pointer to the message to post
435 * @return sys_mbox_trypost() return code
438 tcpip_trycallback(struct tcpip_callback_msg
* msg
)
440 if (!sys_mbox_valid(&mbox
)) {
443 return sys_mbox_trypost(&mbox
, msg
);
447 * Initialize this module:
448 * - initialize all sub modules
449 * - start the tcpip_thread
451 * @param initfunc a function to call when tcpip_thread is running and finished initializing
452 * @param arg argument to pass to initfunc
455 tcpip_init(tcpip_init_done_fn initfunc
, void *arg
)
459 tcpip_init_done
= initfunc
;
460 tcpip_init_done_arg
= arg
;
461 if(sys_mbox_new(&mbox
, TCPIP_MBOX_SIZE
) != ERR_OK
) {
462 LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
464 #if LWIP_TCPIP_CORE_LOCKING
465 if(sys_mutex_new(&lock_tcpip_core
) != ERR_OK
) {
466 LWIP_ASSERT("failed to create lock_tcpip_core", 0);
468 #endif /* LWIP_TCPIP_CORE_LOCKING */
470 sys_thread_new(TCPIP_THREAD_NAME
, tcpip_thread
, NULL
, TCPIP_THREAD_STACKSIZE
, TCPIP_THREAD_PRIO
);
474 * Simple callback function used with tcpip_callback to free a pbuf
475 * (pbuf_free has a wrong signature for tcpip_callback)
477 * @param p The pbuf (chain) to be dereferenced.
480 pbuf_free_int(void *p
)
482 struct pbuf
*q
= (struct pbuf
*)p
;
487 * A simple wrapper function that allows you to free a pbuf from interrupt context.
489 * @param p The pbuf (chain) to be dereferenced.
490 * @return ERR_OK if callback could be enqueued, an err_t if not
493 pbuf_free_callback(struct pbuf
*p
)
495 return tcpip_callback_with_block(pbuf_free_int
, p
, 0);
499 * A simple wrapper function that allows you to free heap memory from
502 * @param m the heap memory to free
503 * @return ERR_OK if callback could be enqueued, an err_t if not
506 mem_free_callback(void *m
)
508 return tcpip_callback_with_block(mem_free
, m
, 0);