Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/lwip/api/tcpip.c need to be fixed.

0001 /**
0002  * @file
0003  * Sequential API Main thread module
0004  *
0005  */
0006 
0007 /*
0008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
0009  * All rights reserved.
0010  *
0011  * Redistribution and use in source and binary forms, with or without modification,
0012  * are permitted provided that the following conditions are met:
0013  *
0014  * 1. Redistributions of source code must retain the above copyright notice,
0015  *    this list of conditions and the following disclaimer.
0016  * 2. Redistributions in binary form must reproduce the above copyright notice,
0017  *    this list of conditions and the following disclaimer in the documentation
0018  *    and/or other materials provided with the distribution.
0019  * 3. The name of the author may not be used to endorse or promote products
0020  *    derived from this software without specific prior written permission.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
0023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
0025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
0027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
0030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
0031  * OF SUCH DAMAGE.
0032  *
0033  * This file is part of the lwIP TCP/IP stack.
0034  *
0035  * Author: Adam Dunkels <adam@sics.se>
0036  *
0037  */
0038 
0039 #include "lwip/opt.h"
0040 
0041 #if !NO_SYS /* don't build if not configured for use in lwipopts.h */
0042 
0043 #include "lwip/sys.h"
0044 #include "lwip/memp.h"
0045 #include "lwip/pbuf.h"
0046 #include "lwip/ip_frag.h"
0047 #include "lwip/tcp.h"
0048 #include "lwip/autoip.h"
0049 #include "lwip/dhcp.h"
0050 #include "lwip/igmp.h"
0051 #include "lwip/dns.h"
0052 #include "lwip/tcpip.h"
0053 #include "lwip/init.h"
0054 #include "netif/etharp.h"
0055 #include "netif/ppp_oe.h"
0056 
0057 /* global variables */
0058 static void (* tcpip_init_done)(void *arg);
0059 static void *tcpip_init_done_arg;
0060 static sys_mbox_t mbox = SYS_MBOX_NULL;
0061 
0062 #if LWIP_TCPIP_CORE_LOCKING
0063 /** The global semaphore to lock the stack. */
0064 sys_sem_t lock_tcpip_core;
0065 #endif /* LWIP_TCPIP_CORE_LOCKING */
0066 
0067 #if LWIP_TCP
0068 /* global variable that shows if the tcp timer is currently scheduled or not */
0069 static int tcpip_tcp_timer_active;
0070 
0071 /**
0072  * Timer callback function that calls tcp_tmr() and reschedules itself.
0073  *
0074  * @param arg unused argument
0075  */
0076 static void
0077 tcpip_tcp_timer(void *arg)
0078 {
0079   LWIP_UNUSED_ARG(arg);
0080 
0081   /* call TCP timer handler */
0082   tcp_tmr();
0083   /* timer still needed? */
0084   if (tcp_active_pcbs || tcp_tw_pcbs) {
0085     /* restart timer */
0086     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
0087   } else {
0088     /* disable timer */
0089     tcpip_tcp_timer_active = 0;
0090   }
0091 }
0092 
0093 #if !NO_SYS
0094 /**
0095  * Called from TCP_REG when registering a new PCB:
0096  * the reason is to have the TCP timer only running when
0097  * there are active (or time-wait) PCBs.
0098  */
0099 void
0100 tcp_timer_needed(void)
0101 {
0102   /* timer is off but needed again? */
0103   if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
0104     /* enable and start timer */
0105     tcpip_tcp_timer_active = 1;
0106     sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
0107   }
0108 }
0109 #endif /* !NO_SYS */
0110 #endif /* LWIP_TCP */
0111 
0112 #if IP_REASSEMBLY
0113 /**
0114  * Timer callback function that calls ip_reass_tmr() and reschedules itself.
0115  *
0116  * @param arg unused argument
0117  */
0118 static void
0119 ip_reass_timer(void *arg)
0120 {
0121   LWIP_UNUSED_ARG(arg);
0122   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
0123   ip_reass_tmr();
0124   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
0125 }
0126 #endif /* IP_REASSEMBLY */
0127 
0128 #if LWIP_ARP
0129 /**
0130  * Timer callback function that calls etharp_tmr() and reschedules itself.
0131  *
0132  * @param arg unused argument
0133  */
0134 static void
0135 arp_timer(void *arg)
0136 {
0137   LWIP_UNUSED_ARG(arg);
0138   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
0139   etharp_tmr();
0140   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
0141 }
0142 #endif /* LWIP_ARP */
0143 
0144 #if LWIP_DHCP
0145 /**
0146  * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
0147  *
0148  * @param arg unused argument
0149  */
0150 static void
0151 dhcp_timer_coarse(void *arg)
0152 {
0153   LWIP_UNUSED_ARG(arg);
0154   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
0155   dhcp_coarse_tmr();
0156   sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
0157 }
0158 
0159 /**
0160  * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
0161  *
0162  * @param arg unused argument
0163  */
0164 static void
0165 dhcp_timer_fine(void *arg)
0166 {
0167   LWIP_UNUSED_ARG(arg);
0168   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
0169   dhcp_fine_tmr();
0170   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
0171 }
0172 #endif /* LWIP_DHCP */
0173 
0174 #if LWIP_AUTOIP
0175 /**
0176  * Timer callback function that calls autoip_tmr() and reschedules itself.
0177  *
0178  * @param arg unused argument
0179  */
0180 static void
0181 autoip_timer(void *arg)
0182 {
0183   LWIP_UNUSED_ARG(arg);
0184   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
0185   autoip_tmr();
0186   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
0187 }
0188 #endif /* LWIP_AUTOIP */
0189 
0190 #if LWIP_IGMP
0191 /**
0192  * Timer callback function that calls igmp_tmr() and reschedules itself.
0193  *
0194  * @param arg unused argument
0195  */
0196 static void
0197 igmp_timer(void *arg)
0198 {
0199   LWIP_UNUSED_ARG(arg);
0200   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
0201   igmp_tmr();
0202   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
0203 }
0204 #endif /* LWIP_IGMP */
0205 
0206 #if LWIP_DNS
0207 /**
0208  * Timer callback function that calls dns_tmr() and reschedules itself.
0209  *
0210  * @param arg unused argument
0211  */
0212 static void
0213 dns_timer(void *arg)
0214 {
0215   LWIP_UNUSED_ARG(arg);
0216   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));
0217   dns_tmr();
0218   sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
0219 }
0220 #endif /* LWIP_DNS */
0221 
0222 /**
0223  * The main lwIP thread. This thread has exclusive access to lwIP core functions
0224  * (unless access to them is not locked). Other threads communicate with this
0225  * thread using message boxes.
0226  *
0227  * It also starts all the timers to make sure they are running in the right
0228  * thread context.
0229  *
0230  * @param arg unused argument
0231  */
0232 static void
0233 tcpip_thread(void *arg)
0234 {
0235   struct tcpip_msg *msg;
0236   LWIP_UNUSED_ARG(arg);
0237 
0238 #if IP_REASSEMBLY
0239   sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
0240 #endif /* IP_REASSEMBLY */
0241 #if LWIP_ARP
0242   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
0243 #endif /* LWIP_ARP */
0244 #if LWIP_DHCP
0245   sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
0246   sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
0247 #endif /* LWIP_DHCP */
0248 #if LWIP_AUTOIP
0249   sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
0250 #endif /* LWIP_AUTOIP */
0251 #if LWIP_IGMP
0252   sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
0253 #endif /* LWIP_IGMP */
0254 #if LWIP_DNS
0255   sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
0256 #endif /* LWIP_DNS */
0257 
0258   if (tcpip_init_done != NULL) {
0259     tcpip_init_done(tcpip_init_done_arg);
0260   }
0261 
0262   LOCK_TCPIP_CORE();
0263   while (1) {                          /* MAIN Loop */
0264     sys_mbox_fetch(mbox, (void *)&msg);
0265     switch (msg->type) {
0266 #if LWIP_NETCONN
0267     case TCPIP_MSG_API:
0268       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
0269       msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
0270       break;
0271 #endif /* LWIP_NETCONN */
0272 
0273     case TCPIP_MSG_INPKT:
0274       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
0275 #if LWIP_ARP
0276       if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
0277         ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
0278       } else
0279 #endif /* LWIP_ARP */
0280       { ip_input(msg->msg.inp.p, msg->msg.inp.netif);
0281       }
0282       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
0283       break;
0284 
0285 #if LWIP_NETIF_API
0286     case TCPIP_MSG_NETIFAPI:
0287       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
0288       msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
0289       break;
0290 #endif /* LWIP_NETIF_API */
0291 
0292     case TCPIP_MSG_CALLBACK:
0293       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
0294       msg->msg.cb.f(msg->msg.cb.ctx);
0295       memp_free(MEMP_TCPIP_MSG_API, msg);
0296       break;
0297 
0298     case TCPIP_MSG_TIMEOUT:
0299       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
0300       sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
0301       memp_free(MEMP_TCPIP_MSG_API, msg);
0302       break;
0303     case TCPIP_MSG_UNTIMEOUT:
0304       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
0305       sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
0306       memp_free(MEMP_TCPIP_MSG_API, msg);
0307       break;
0308 
0309     default:
0310       break;
0311     }
0312   }
0313 }
0314 
0315 /**
0316  * Pass a received packet to tcpip_thread for input processing
0317  *
0318  * @param p the received packet, p->payload pointing to the Ethernet header or
0319  *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
0320  * @param inp the network interface on which the packet was received
0321  */
0322 err_t
0323 tcpip_input(struct pbuf *p, struct netif *inp)
0324 {
0325   struct tcpip_msg *msg;
0326 
0327   if (mbox != SYS_MBOX_NULL) {
0328     msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
0329     if (msg == NULL) {
0330       return ERR_MEM;
0331     }
0332 
0333     msg->type = TCPIP_MSG_INPKT;
0334     msg->msg.inp.p = p;
0335     msg->msg.inp.netif = inp;
0336     if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
0337       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
0338       return ERR_MEM;
0339     }
0340     return ERR_OK;
0341   }
0342   return ERR_VAL;
0343 }
0344 
0345 /**
0346  * Call a specific function in the thread context of
0347  * tcpip_thread for easy access synchronization.
0348  * A function called in that way may access lwIP core code
0349  * without fearing concurrent access.
0350  *
0351  * @param f the function to call
0352  * @param ctx parameter passed to f
0353  * @param block 1 to block until the request is posted, 0 to non-blocking mode
0354  * @return ERR_OK if the function was called, another err_t if not
0355  */
0356 err_t
0357 tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
0358 {
0359   struct tcpip_msg *msg;
0360 
0361   if (mbox != SYS_MBOX_NULL) {
0362     msg = memp_malloc(MEMP_TCPIP_MSG_API);
0363     if (msg == NULL) {
0364       return ERR_MEM;
0365     }
0366 
0367     msg->type = TCPIP_MSG_CALLBACK;
0368     msg->msg.cb.f = f;
0369     msg->msg.cb.ctx = ctx;
0370     if (block) {
0371       sys_mbox_post(mbox, msg);
0372     } else {
0373       if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
0374         memp_free(MEMP_TCPIP_MSG_API, msg);
0375         return ERR_MEM;
0376       }
0377     }
0378     return ERR_OK;
0379   }
0380   return ERR_VAL;
0381 }
0382 
0383 /**
0384  * call sys_timeout in tcpip_thread
0385  *
0386  * @param msec time in miliseconds for timeout
0387  * @param h function to be called on timeout
0388  * @param arg argument to pass to timeout function h
0389  * @return ERR_MEM on memory error, ERR_OK otherwise
0390  */
0391 err_t
0392 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
0393 {
0394   struct tcpip_msg *msg;
0395 
0396   if (mbox != SYS_MBOX_NULL) {
0397     msg = memp_malloc(MEMP_TCPIP_MSG_API);
0398     if (msg == NULL) {
0399       return ERR_MEM;
0400     }
0401 
0402     msg->type = TCPIP_MSG_TIMEOUT;
0403     msg->msg.tmo.msecs = msecs;
0404     msg->msg.tmo.h = h;
0405     msg->msg.tmo.arg = arg;
0406     sys_mbox_post(mbox, msg);
0407     return ERR_OK;
0408   }
0409   return ERR_VAL;
0410 }
0411 
0412 /**
0413  * call sys_untimeout in tcpip_thread
0414  *
0415  * @param msec time in miliseconds for timeout
0416  * @param h function to be called on timeout
0417  * @param arg argument to pass to timeout function h
0418  * @return ERR_MEM on memory error, ERR_OK otherwise
0419  */
0420 err_t
0421 tcpip_untimeout(sys_timeout_handler h, void *arg)
0422 {
0423   struct tcpip_msg *msg;
0424 
0425   if (mbox != SYS_MBOX_NULL) {
0426     msg = memp_malloc(MEMP_TCPIP_MSG_API);
0427     if (msg == NULL) {
0428       return ERR_MEM;
0429     }
0430 
0431     msg->type = TCPIP_MSG_UNTIMEOUT;
0432     msg->msg.tmo.h = h;
0433     msg->msg.tmo.arg = arg;
0434     sys_mbox_post(mbox, msg);
0435     return ERR_OK;
0436   }
0437   return ERR_VAL;
0438 }
0439 
0440 #if LWIP_NETCONN
0441 /**
0442  * Call the lower part of a netconn_* function
0443  * This function is then running in the thread context
0444  * of tcpip_thread and has exclusive access to lwIP core code.
0445  *
0446  * @param apimsg a struct containing the function to call and its parameters
0447  * @return ERR_OK if the function was called, another err_t if not
0448  */
0449 err_t
0450 tcpip_apimsg(struct api_msg *apimsg)
0451 {
0452   struct tcpip_msg msg;
0453   
0454   if (mbox != SYS_MBOX_NULL) {
0455     msg.type = TCPIP_MSG_API;
0456     msg.msg.apimsg = apimsg;
0457     sys_mbox_post(mbox, &msg);
0458     sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
0459     return ERR_OK;
0460   }
0461   return ERR_VAL;
0462 }
0463 
0464 #if LWIP_TCPIP_CORE_LOCKING
0465 /**
0466  * Call the lower part of a netconn_* function
0467  * This function has exclusive access to lwIP core code by locking it
0468  * before the function is called.
0469  *
0470  * @param apimsg a struct containing the function to call and its parameters
0471  * @return ERR_OK (only for compatibility fo tcpip_apimsg())
0472  */
0473 err_t
0474 tcpip_apimsg_lock(struct api_msg *apimsg)
0475 {
0476   LOCK_TCPIP_CORE();
0477   apimsg->function(&(apimsg->msg));
0478   UNLOCK_TCPIP_CORE();
0479   return ERR_OK;
0480 
0481 }
0482 #endif /* LWIP_TCPIP_CORE_LOCKING */
0483 #endif /* LWIP_NETCONN */
0484 
0485 #if LWIP_NETIF_API
0486 #if !LWIP_TCPIP_CORE_LOCKING
0487 /**
0488  * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
0489  * function.
0490  *
0491  * @param netifapimsg a struct containing the function to call and its parameters
0492  * @return error code given back by the function that was called
0493  */
0494 err_t
0495 tcpip_netifapi(struct netifapi_msg* netifapimsg)
0496 {
0497   struct tcpip_msg msg;
0498   
0499   if (mbox != SYS_MBOX_NULL) {
0500     netifapimsg->msg.sem = sys_sem_new(0);
0501     if (netifapimsg->msg.sem == SYS_SEM_NULL) {
0502       netifapimsg->msg.err = ERR_MEM;
0503       return netifapimsg->msg.err;
0504     }
0505     
0506     msg.type = TCPIP_MSG_NETIFAPI;
0507     msg.msg.netifapimsg = netifapimsg;
0508     sys_mbox_post(mbox, &msg);
0509     sys_sem_wait(netifapimsg->msg.sem);
0510     sys_sem_free(netifapimsg->msg.sem);
0511     return netifapimsg->msg.err;
0512   }
0513   return ERR_VAL;
0514 }
0515 #else /* !LWIP_TCPIP_CORE_LOCKING */
0516 /**
0517  * Call the lower part of a netifapi_* function
0518  * This function has exclusive access to lwIP core code by locking it
0519  * before the function is called.
0520  *
0521  * @param netifapimsg a struct containing the function to call and its parameters
0522  * @return ERR_OK (only for compatibility fo tcpip_netifapi())
0523  */
0524 err_t
0525 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
0526 {
0527   LOCK_TCPIP_CORE();  
0528   netifapimsg->function(&(netifapimsg->msg));
0529   UNLOCK_TCPIP_CORE();
0530   return netifapimsg->msg.err;
0531 }
0532 #endif /* !LWIP_TCPIP_CORE_LOCKING */
0533 #endif /* LWIP_NETIF_API */
0534 
0535 /**
0536  * Initialize this module:
0537  * - initialize all sub modules
0538  * - start the tcpip_thread
0539  *
0540  * @param initfunc a function to call when tcpip_thread is running and finished initializing
0541  * @param arg argument to pass to initfunc
0542  */
0543 void
0544 tcpip_init(void (* initfunc)(void *), void *arg)
0545 {
0546   lwip_init();
0547 
0548   tcpip_init_done = initfunc;
0549   tcpip_init_done_arg = arg;
0550   mbox = sys_mbox_new(TCPIP_MBOX_SIZE);
0551 #if LWIP_TCPIP_CORE_LOCKING
0552   lock_tcpip_core = sys_sem_new(1);
0553 #endif /* LWIP_TCPIP_CORE_LOCKING */
0554 
0555   sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
0556 }
0557 
0558 /**
0559  * Simple callback function used with tcpip_callback to free a pbuf
0560  * (pbuf_free has a wrong signature for tcpip_callback)
0561  *
0562  * @param p The pbuf (chain) to be dereferenced.
0563  */
0564 static void
0565 pbuf_free_int(void *p)
0566 {
0567   struct pbuf *q = p;
0568   pbuf_free(q);
0569 }
0570 
0571 /**
0572  * A simple wrapper function that allows you to free a pbuf from interrupt context.
0573  *
0574  * @param p The pbuf (chain) to be dereferenced.
0575  * @return ERR_OK if callback could be enqueued, an err_t if not
0576  */
0577 err_t
0578 pbuf_free_callback(struct pbuf *p)
0579 {
0580   return tcpip_callback_with_block(pbuf_free_int, p, 0);
0581 }
0582 
0583 /**
0584  * A simple wrapper function that allows you to free heap memory from
0585  * interrupt context.
0586  *
0587  * @param m the heap memory to free
0588  * @return ERR_OK if callback could be enqueued, an err_t if not
0589  */
0590 err_t
0591 mem_free_callback(void *m)
0592 {
0593   return tcpip_callback_with_block(mem_free, m, 0);
0594 }
0595 
0596 #endif /* !NO_SYS */