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>
43 #include "lwip/memp.h"
44 #include "lwip/pbuf.h"
46 #include "netif/etharp.h"
49 #include "lwip/ip_frag.h"
53 #include "lwip/tcpip.h"
54 #include "lwip/igmp.h"
58 /* global variables */
59 static void (* tcpip_init_done)(void *arg) = NULL;
60 static void *tcpip_init_done_arg = NULL;
61 static sys_mbox_t mbox = SYS_MBOX_NULL;
63 #if LWIP_TCPIP_CORE_LOCKING
64 /** The global semaphore to lock the stack. */
65 sys_sem_t lock_tcpip_core = 0;
66 #endif /* LWIP_TCPIP_CORE_LOCKING */
69 /* global variable that shows if the tcp timer is currently scheduled or not */
70 static int tcpip_tcp_timer_active = 0;
73 * Timer callback function that calls tcp_tmr() and reschedules itself.
75 * @param arg unused argument
78 tcpip_tcp_timer(void *arg)
82 /* call TCP timer handler */
84 /* timer still needed? */
85 if (tcp_active_pcbs || tcp_tw_pcbs) {
87 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
90 tcpip_tcp_timer_active = 0;
96 * Called from TCP_REG when registering a new PCB:
97 * the reason is to have the TCP timer only running when
98 * there are active (or time-wait) PCBs.
101 tcp_timer_needed(void)
103 /* timer is off but needed again? */
104 if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
105 /* enable and start timer */
106 tcpip_tcp_timer_active = 1;
107 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
111 #endif /* LWIP_TCP */
115 * Timer callback function that calls ip_reass_tmr() and reschedules itself.
117 * @param arg unused argument
120 ip_reass_timer(void *arg)
122 LWIP_UNUSED_ARG(arg);
123 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
125 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
127 #endif /* IP_REASSEMBLY */
131 * Timer callback function that calls etharp_tmr() and reschedules itself.
133 * @param arg unused argument
138 LWIP_UNUSED_ARG(arg);
139 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
141 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
143 #endif /* LWIP_ARP */
147 * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
149 * @param arg unused argument
152 dhcp_timer_coarse(void *arg)
154 LWIP_UNUSED_ARG(arg);
155 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
157 sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
161 * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
163 * @param arg unused argument
166 dhcp_timer_fine(void *arg)
168 LWIP_UNUSED_ARG(arg);
169 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
171 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
173 #endif /* LWIP_DHCP */
177 * Timer callback function that calls autoip_tmr() and reschedules itself.
179 * @param arg unused argument
182 autoip_timer(void *arg)
184 LWIP_UNUSED_ARG(arg);
185 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
187 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
189 #endif /* LWIP_AUTOIP */
193 * Timer callback function that calls igmp_tmr() and reschedules itself.
195 * @param arg unused argument
198 igmp_timer(void *arg)
200 LWIP_UNUSED_ARG(arg);
201 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
203 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
205 #endif /* LWIP_IGMP */
207 #if ETHARP_TCPIP_ETHINPUT
209 * Process received ethernet frames. Using this function instead of directly
210 * calling ip_input and passing ARP frames through etharp in ethernetif_input,
211 * the ARP cache is protected from concurrent access.
213 * @param p the recevied packet, p->payload pointing to the ethernet header
214 * @param netif the network interface on which the packet was received
217 ethernet_input(struct pbuf *p, struct netif *netif)
219 struct eth_hdr* ethhdr;
221 /* points to packet payload, which starts with an Ethernet header */
224 switch (htons(ethhdr->type)) {
227 #if ETHARP_TRUST_IP_MAC
228 /* update ARP table */
229 etharp_ip_input( netif, p);
231 /* skip Ethernet header */
232 if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {
233 LWIP_ASSERT("Can't move over header in packet", 0);
238 /* pass to IP layer */
243 /* pass p to ARP module */
244 etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
253 #endif /* ETHARP_TCPIP_ETHINPUT */
256 * The main lwIP thread. This thread has exclusive access to lwIP core functions
257 * (unless access to them is not locked). Other threads communicate with this
258 * thread using message boxes.
260 * It also starts all the timers to make sure they are running in the right
263 * @param arg unused argument
266 tcpip_thread(void *arg)
268 struct tcpip_msg *msg;
269 LWIP_UNUSED_ARG(arg);
272 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
273 #endif /* IP_REASSEMBLY */
275 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
276 #endif /* LWIP_ARP */
278 sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL);
279 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
280 #endif /* LWIP_DHCP */
282 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
283 #endif /* LWIP_AUTOIP */
285 if (tcpip_init_done != NULL) {
286 tcpip_init_done(tcpip_init_done_arg);
291 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
292 #endif /* LWIP_IGMP */
295 while (1) { /* MAIN Loop */
296 sys_mbox_fetch(mbox, (void *)&msg);
299 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
300 msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
303 #if ETHARP_TCPIP_INPUT
304 case TCPIP_MSG_INPUT:
305 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: IP packet %p\n", (void *)msg));
306 ip_input(msg->msg.inp.p, msg->msg.inp.netif);
307 memp_free(MEMP_TCPIP_MSG, msg);
309 #endif /* ETHARP_TCPIP_INPUT */
311 #if ETHARP_TCPIP_ETHINPUT
312 case TCPIP_MSG_ETHINPUT:
313 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Ethernet packet %p\n", (void *)msg));
314 ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
315 memp_free(MEMP_TCPIP_MSG, msg);
317 #endif /* ETHARP_TCPIP_ETHINPUT */
320 case TCPIP_MSG_NETIFAPI:
321 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
322 msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
324 #endif /* LWIP_NETIF_API */
326 case TCPIP_MSG_CALLBACK:
327 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
328 msg->msg.cb.f(msg->msg.cb.ctx);
329 memp_free(MEMP_TCPIP_MSG, msg);
337 #if ETHARP_TCPIP_INPUT
339 * Pass a received IP packet to tcpip_thread for input processing
341 * @param p the recevied packet, p->payload pointing to the IP header
342 * @param netif the network interface on which the packet was received
345 tcpip_input(struct pbuf *p, struct netif *inp)
347 struct tcpip_msg *msg;
349 if (mbox != SYS_MBOX_NULL) {
350 msg = memp_malloc(MEMP_TCPIP_MSG);
355 msg->type = TCPIP_MSG_INPUT;
357 msg->msg.inp.netif = inp;
358 sys_mbox_post(mbox, msg);
363 #endif /* ETHARP_TCPIP_INPUT */
365 #if ETHARP_TCPIP_ETHINPUT
367 * Pass a received IP packet to tcpip_thread for input processing
369 * @param p the recevied packet, p->payload pointing to the ethernet header
370 * @param netif the network interface on which the packet was received
373 tcpip_ethinput(struct pbuf *p, struct netif *inp)
375 struct tcpip_msg *msg;
377 if (mbox != SYS_MBOX_NULL) {
378 msg = memp_malloc(MEMP_TCPIP_MSG);
383 msg->type = TCPIP_MSG_ETHINPUT;
385 msg->msg.inp.netif = inp;
386 sys_mbox_post(mbox, msg);
391 #endif /* ETHARP_TCPIP_ETHINPUT */
394 * Call a specific function in the thread context of
395 * tcpip_thread for easy access synchronization.
396 * A function called in that way may access lwIP core code
397 * without fearing concurrent access.
399 * @param f the function to call
400 * @param ctx parameter passed to f
401 * @return ERR_OK if the function was called, another err_t if not
404 tcpip_callback(void (*f)(void *ctx), void *ctx)
406 struct tcpip_msg *msg;
408 if (mbox != SYS_MBOX_NULL) {
409 msg = memp_malloc(MEMP_TCPIP_MSG);
414 msg->type = TCPIP_MSG_CALLBACK;
416 msg->msg.cb.ctx = ctx;
417 sys_mbox_post(mbox, msg);
424 * Call the lower part of a netconn_* function
425 * This function is then running in the thread context
426 * of tcpip_thread and has exclusive access to lwIP core code.
428 * @param apimsg a struct containing the function to call and its parameters
429 * @return ERR_OK if the function was called, another err_t if not
432 tcpip_apimsg(struct api_msg *apimsg)
434 struct tcpip_msg msg;
436 if (mbox != SYS_MBOX_NULL) {
437 msg.type = TCPIP_MSG_API;
438 msg.msg.apimsg = apimsg;
439 sys_mbox_post(mbox, &msg);
440 sys_arch_mbox_fetch(apimsg->msg.conn->mbox, NULL, 0);
446 #if LWIP_TCPIP_CORE_LOCKING
448 * Call the lower part of a netconn_* function
449 * This function has exclusive access to lwIP core code by locking it
450 * before the function is called.
452 * @param apimsg a struct containing the function to call and its parameters
453 * @return ERR_OK (only for compatibility fo tcpip_apimsg())
456 tcpip_apimsg_lock(struct api_msg *apimsg)
459 apimsg->function(&(apimsg->msg));
464 #endif /* LWIP_TCPIP_CORE_LOCKING */
467 #if !LWIP_TCPIP_CORE_LOCKING
469 * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
472 * @param netifapimsg a struct containing the function to call and its parameters
473 * @return error code given back by the function that was called
476 tcpip_netifapi(struct netifapi_msg* netifapimsg)
478 struct tcpip_msg msg;
480 if (mbox != SYS_MBOX_NULL) {
481 netifapimsg->msg.sem = sys_sem_new(0);
482 if (netifapimsg->msg.sem == SYS_SEM_NULL) {
483 netifapimsg->msg.err = ERR_MEM;
484 return netifapimsg->msg.err;
487 msg.type = TCPIP_MSG_NETIFAPI;
488 msg.msg.netifapimsg = netifapimsg;
489 sys_mbox_post(mbox, &msg);
490 sys_sem_wait(netifapimsg->msg.sem);
491 sys_sem_free(netifapimsg->msg.sem);
492 return netifapimsg->msg.err;
496 #else /* !LWIP_TCPIP_CORE_LOCKING */
498 * Call the lower part of a netifapi_* function
499 * This function has exclusive access to lwIP core code by locking it
500 * before the function is called.
502 * @param netifapimsg a struct containing the function to call and its parameters
503 * @return ERR_OK (only for compatibility fo tcpip_netifapi())
506 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
509 netifapimsg->function(&(netifapimsg->msg));
511 return netifapimsg->msg.err;
513 #endif /* !LWIP_TCPIP_CORE_LOCKING */
514 #endif /* LWIP_NETIF_API */
517 * Initialize this module:
518 * - initialize ARP, IP, UDP and TCP
519 * - start the tcpip_thread
521 * @param initfunc a function to call when tcpip_thread is running and
522 * finished initializing
523 * @param arg argument to pass to initfunc
526 tcpip_init(void (* initfunc)(void *), void *arg)
530 #endif /* LWIP_ARP */
533 #endif /* LWIP_AUTOIP */
537 #endif /* LWIP_UDP */
540 #endif /* LWIP_TCP */
542 tcpip_init_done = initfunc;
543 tcpip_init_done_arg = arg;
544 mbox = sys_mbox_new();
545 #if LWIP_TCPIP_CORE_LOCKING
546 lock_tcpip_core = sys_sem_new(1);
547 #endif /* LWIP_TCPIP_CORE_LOCKING */
549 sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);