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"
45 #include "lwip/pbuf.h"
46 #include "lwip/ip_frag.h"
48 #include "lwip/autoip.h"
49 #include "lwip/dhcp.h"
50 #include "lwip/igmp.h"
51 #include "lwip/tcpip.h"
52 #include "lwip/init.h"
53 #include "netif/etharp.h"
54 #include "netif/ppp_oe.h"
56 /* global variables */
57 static void (* tcpip_init_done)(void *arg);
58 static void *tcpip_init_done_arg;
59 static sys_mbox_t mbox = SYS_MBOX_NULL;
61 #if LWIP_TCPIP_CORE_LOCKING
62 /** The global semaphore to lock the stack. */
63 sys_sem_t lock_tcpip_core;
64 #endif /* LWIP_TCPIP_CORE_LOCKING */
67 /* global variable that shows if the tcp timer is currently scheduled or not */
68 static int tcpip_tcp_timer_active;
71 * Timer callback function that calls tcp_tmr() and reschedules itself.
73 * @param arg unused argument
76 tcpip_tcp_timer(void *arg)
80 /* call TCP timer handler */
82 /* timer still needed? */
83 if (tcp_active_pcbs || tcp_tw_pcbs) {
85 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
88 tcpip_tcp_timer_active = 0;
94 * Called from TCP_REG when registering a new PCB:
95 * the reason is to have the TCP timer only running when
96 * there are active (or time-wait) PCBs.
99 tcp_timer_needed(void)
101 /* timer is off but needed again? */
102 if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
103 /* enable and start timer */
104 tcpip_tcp_timer_active = 1;
105 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
109 #endif /* LWIP_TCP */
113 * Timer callback function that calls ip_reass_tmr() and reschedules itself.
115 * @param arg unused argument
118 ip_reass_timer(void *arg)
120 LWIP_UNUSED_ARG(arg);
121 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
123 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
125 #endif /* IP_REASSEMBLY */
129 * Timer callback function that calls etharp_tmr() and reschedules itself.
131 * @param arg unused argument
136 LWIP_UNUSED_ARG(arg);
137 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
139 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
141 #endif /* LWIP_ARP */
145 * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
147 * @param arg unused argument
150 dhcp_timer_coarse(void *arg)
152 LWIP_UNUSED_ARG(arg);
153 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
155 sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
159 * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
161 * @param arg unused argument
164 dhcp_timer_fine(void *arg)
166 LWIP_UNUSED_ARG(arg);
167 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
169 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
171 #endif /* LWIP_DHCP */
175 * Timer callback function that calls autoip_tmr() and reschedules itself.
177 * @param arg unused argument
180 autoip_timer(void *arg)
182 LWIP_UNUSED_ARG(arg);
183 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
185 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
187 #endif /* LWIP_AUTOIP */
191 * Timer callback function that calls igmp_tmr() and reschedules itself.
193 * @param arg unused argument
196 igmp_timer(void *arg)
198 LWIP_UNUSED_ARG(arg);
199 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
201 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
203 #endif /* LWIP_IGMP */
206 * The main lwIP thread. This thread has exclusive access to lwIP core functions
207 * (unless access to them is not locked). Other threads communicate with this
208 * thread using message boxes.
210 * It also starts all the timers to make sure they are running in the right
213 * @param arg unused argument
216 tcpip_thread(void *arg)
218 struct tcpip_msg *msg;
219 LWIP_UNUSED_ARG(arg);
222 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
223 #endif /* IP_REASSEMBLY */
225 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
226 #endif /* LWIP_ARP */
228 sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
229 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
230 #endif /* LWIP_DHCP */
232 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
233 #endif /* LWIP_AUTOIP */
235 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
236 #endif /* LWIP_IGMP */
238 if (tcpip_init_done != NULL) {
239 tcpip_init_done(tcpip_init_done_arg);
243 while (1) { /* MAIN Loop */
244 sys_mbox_fetch(mbox, (void *)&msg);
248 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
249 msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
251 #endif /* LWIP_NETCONN */
253 case TCPIP_MSG_INPKT:
254 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
256 if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
257 ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
259 #endif /* LWIP_ARP */
260 { ip_input(msg->msg.inp.p, msg->msg.inp.netif);
262 memp_free(MEMP_TCPIP_MSG_INPKT, msg);
266 case TCPIP_MSG_NETIFAPI:
267 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
268 msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
270 #endif /* LWIP_NETIF_API */
272 case TCPIP_MSG_CALLBACK:
273 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
274 msg->msg.cb.f(msg->msg.cb.ctx);
275 memp_free(MEMP_TCPIP_MSG_API, msg);
278 case TCPIP_MSG_TIMEOUT:
279 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
281 if(msg->msg.tmo.msecs != 0xffffffff)
282 sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
284 sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
285 memp_free(MEMP_TCPIP_MSG_API, msg);
295 * Pass a received packet to tcpip_thread for input processing
297 * @param p the received packet, p->payload pointing to the Ethernet header or
298 * to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
299 * @param netif the network interface on which the packet was received
302 tcpip_input(struct pbuf *p, struct netif *inp)
304 struct tcpip_msg *msg;
306 if (mbox != SYS_MBOX_NULL) {
307 msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
312 msg->type = TCPIP_MSG_INPKT;
314 msg->msg.inp.netif = inp;
315 sys_mbox_post(mbox, msg);
322 * Call a specific function in the thread context of
323 * tcpip_thread for easy access synchronization.
324 * A function called in that way may access lwIP core code
325 * without fearing concurrent access.
327 * @param f the function to call
328 * @param ctx parameter passed to f
329 * @return ERR_OK if the function was called, another err_t if not
332 tcpip_callback(void (*f)(void *ctx), void *ctx)
334 struct tcpip_msg *msg;
336 if (mbox != SYS_MBOX_NULL) {
337 msg = memp_malloc(MEMP_TCPIP_MSG_API);
342 msg->type = TCPIP_MSG_CALLBACK;
344 msg->msg.cb.ctx = ctx;
345 sys_mbox_post(mbox, msg);
352 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
354 struct tcpip_msg *msg;
356 if (mbox != SYS_MBOX_NULL) {
357 msg = memp_malloc(MEMP_TCPIP_MSG_API);
362 msg->type = TCPIP_MSG_TIMEOUT;
363 msg->msg.tmo.msecs = msecs;
365 msg->msg.tmo.arg = arg;
366 sys_mbox_post(mbox, msg);
374 * Call the lower part of a netconn_* function
375 * This function is then running in the thread context
376 * of tcpip_thread and has exclusive access to lwIP core code.
378 * @param apimsg a struct containing the function to call and its parameters
379 * @return ERR_OK if the function was called, another err_t if not
382 tcpip_apimsg(struct api_msg *apimsg)
384 struct tcpip_msg msg;
386 if (mbox != SYS_MBOX_NULL) {
387 msg.type = TCPIP_MSG_API;
388 msg.msg.apimsg = apimsg;
389 sys_mbox_post(mbox, &msg);
390 sys_arch_mbox_fetch(apimsg->msg.conn->mbox, NULL, 0);
396 #if LWIP_TCPIP_CORE_LOCKING
398 * Call the lower part of a netconn_* function
399 * This function has exclusive access to lwIP core code by locking it
400 * before the function is called.
402 * @param apimsg a struct containing the function to call and its parameters
403 * @return ERR_OK (only for compatibility fo tcpip_apimsg())
406 tcpip_apimsg_lock(struct api_msg *apimsg)
409 apimsg->function(&(apimsg->msg));
414 #endif /* LWIP_TCPIP_CORE_LOCKING */
415 #endif /* LWIP_NETCONN */
418 #if !LWIP_TCPIP_CORE_LOCKING
420 * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
423 * @param netifapimsg a struct containing the function to call and its parameters
424 * @return error code given back by the function that was called
427 tcpip_netifapi(struct netifapi_msg* netifapimsg)
429 struct tcpip_msg msg;
431 if (mbox != SYS_MBOX_NULL) {
432 netifapimsg->msg.sem = sys_sem_new(0);
433 if (netifapimsg->msg.sem == SYS_SEM_NULL) {
434 netifapimsg->msg.err = ERR_MEM;
435 return netifapimsg->msg.err;
438 msg.type = TCPIP_MSG_NETIFAPI;
439 msg.msg.netifapimsg = netifapimsg;
440 sys_mbox_post(mbox, &msg);
441 sys_sem_wait(netifapimsg->msg.sem);
442 sys_sem_free(netifapimsg->msg.sem);
443 return netifapimsg->msg.err;
447 #else /* !LWIP_TCPIP_CORE_LOCKING */
449 * Call the lower part of a netifapi_* function
450 * This function has exclusive access to lwIP core code by locking it
451 * before the function is called.
453 * @param netifapimsg a struct containing the function to call and its parameters
454 * @return ERR_OK (only for compatibility fo tcpip_netifapi())
457 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
460 netifapimsg->function(&(netifapimsg->msg));
462 return netifapimsg->msg.err;
464 #endif /* !LWIP_TCPIP_CORE_LOCKING */
465 #endif /* LWIP_NETIF_API */
468 * Initialize this module:
469 * - initialize all sub modules
470 * - start the tcpip_thread
472 * @param initfunc a function to call when tcpip_thread is running and finished initializing
473 * @param arg argument to pass to initfunc
476 tcpip_init(void (* initfunc)(void *), void *arg)
480 tcpip_init_done = initfunc;
481 tcpip_init_done_arg = arg;
482 mbox = sys_mbox_new();
483 #if LWIP_TCPIP_CORE_LOCKING
484 lock_tcpip_core = sys_sem_new(1);
485 #endif /* LWIP_TCPIP_CORE_LOCKING */
487 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);