lwip-1.4.1 (partial)

Dependents:   IGLOO_board

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcpip.c Source File

tcpip.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sequential API Main thread module
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 #include "lwip/opt.h"
00040 
00041 #if !NO_SYS /* don't build if not configured for use in lwipopts.h */
00042 
00043 #include "lwip/sys.h"
00044 #include "lwip/memp.h"
00045 #include "lwip/mem.h"
00046 #include "lwip/pbuf.h"
00047 #include "lwip/tcpip.h"
00048 #include "lwip/init.h"
00049 #include "netif/etharp.h"
00050 #include "netif/ppp_oe.h"
00051 
00052 /* global variables */
00053 static tcpip_init_done_fn tcpip_init_done;
00054 static void *tcpip_init_done_arg;
00055 static sys_mbox_t mbox;
00056 
00057 #if LWIP_TCPIP_CORE_LOCKING
00058 /** The global semaphore to lock the stack. */
00059 sys_mutex_t lock_tcpip_core;
00060 #endif /* LWIP_TCPIP_CORE_LOCKING */
00061 
00062 
00063 /**
00064  * The main lwIP thread. This thread has exclusive access to lwIP core functions
00065  * (unless access to them is not locked). Other threads communicate with this
00066  * thread using message boxes.
00067  *
00068  * It also starts all the timers to make sure they are running in the right
00069  * thread context.
00070  *
00071  * @param arg unused argument
00072  */
00073 static void
00074 tcpip_thread(void *arg)
00075 {
00076   struct tcpip_msg *msg;
00077   LWIP_UNUSED_ARG(arg);
00078 
00079   if (tcpip_init_done != NULL) {
00080     tcpip_init_done(tcpip_init_done_arg);
00081   }
00082 
00083   LOCK_TCPIP_CORE();
00084   while (1) {                          /* MAIN Loop */
00085     UNLOCK_TCPIP_CORE();
00086     LWIP_TCPIP_THREAD_ALIVE();
00087     /* wait for a message, timeouts are processed while waiting */
00088     sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
00089     LOCK_TCPIP_CORE();
00090     switch (msg->type) {
00091 #if LWIP_NETCONN
00092     case TCPIP_MSG_API:
00093       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
00094       msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
00095       break;
00096 #endif /* LWIP_NETCONN */
00097 
00098 #if !LWIP_TCPIP_CORE_LOCKING_INPUT
00099     case TCPIP_MSG_INPKT:
00100       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
00101 #if LWIP_ETHERNET
00102       if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
00103         ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
00104       } else
00105 #endif /* LWIP_ETHERNET */
00106       {
00107         ip_input(msg->msg.inp.p, msg->msg.inp.netif);
00108       }
00109       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00110       break;
00111 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00112 
00113 #if LWIP_NETIF_API
00114     case TCPIP_MSG_NETIFAPI:
00115       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
00116       msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
00117       break;
00118 #endif /* LWIP_NETIF_API */
00119 
00120 #if LWIP_TCPIP_TIMEOUT
00121     case TCPIP_MSG_TIMEOUT:
00122       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
00123       sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
00124       memp_free(MEMP_TCPIP_MSG_API, msg);
00125       break;
00126     case TCPIP_MSG_UNTIMEOUT:
00127       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
00128       sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
00129       memp_free(MEMP_TCPIP_MSG_API, msg);
00130       break;
00131 #endif /* LWIP_TCPIP_TIMEOUT */
00132 
00133     case TCPIP_MSG_CALLBACK:
00134       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
00135       msg->msg.cb.function(msg->msg.cb.ctx);
00136       memp_free(MEMP_TCPIP_MSG_API, msg);
00137       break;
00138 
00139     case TCPIP_MSG_CALLBACK_STATIC:
00140       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
00141       msg->msg.cb.function(msg->msg.cb.ctx);
00142       break;
00143 
00144     default:
00145       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
00146       LWIP_ASSERT("tcpip_thread: invalid message", 0);
00147       break;
00148     }
00149   }
00150 }
00151 
00152 /**
00153  * Pass a received packet to tcpip_thread for input processing
00154  *
00155  * @param p the received packet, p->payload pointing to the Ethernet header or
00156  *          to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
00157  *          NETIF_FLAG_ETHERNET flags)
00158  * @param inp the network interface on which the packet was received
00159  */
00160 err_t
00161 tcpip_input(struct pbuf *p, struct netif *inp)
00162 {
00163 #if LWIP_TCPIP_CORE_LOCKING_INPUT
00164   err_t ret;
00165   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
00166   LOCK_TCPIP_CORE();
00167 #if LWIP_ETHERNET
00168   if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
00169     ret = ethernet_input(p, inp);
00170   } else
00171 #endif /* LWIP_ETHERNET */
00172   {
00173     ret = ip_input(p, inp);
00174   }
00175   UNLOCK_TCPIP_CORE();
00176   return ret;
00177 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00178   struct tcpip_msg *msg;
00179 
00180   if (!sys_mbox_valid(&mbox)) {
00181     return ERR_VAL;
00182   }
00183   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
00184   if (msg == NULL) {
00185     return ERR_MEM;
00186   }
00187 
00188   msg->type = TCPIP_MSG_INPKT;
00189   msg->msg.inp.p = p;
00190   msg->msg.inp.netif = inp;
00191   if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
00192     memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00193     return ERR_MEM;
00194   }
00195   return ERR_OK;
00196 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00197 }
00198 
00199 /**
00200  * Call a specific function in the thread context of
00201  * tcpip_thread for easy access synchronization.
00202  * A function called in that way may access lwIP core code
00203  * without fearing concurrent access.
00204  *
00205  * @param f the function to call
00206  * @param ctx parameter passed to f
00207  * @param block 1 to block until the request is posted, 0 to non-blocking mode
00208  * @return ERR_OK if the function was called, another err_t if not
00209  */
00210 err_t
00211 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
00212 {
00213   struct tcpip_msg *msg;
00214 
00215   if (sys_mbox_valid(&mbox)) {
00216     msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00217     if (msg == NULL) {
00218       return ERR_MEM;
00219     }
00220 
00221     msg->type = TCPIP_MSG_CALLBACK;
00222     msg->msg.cb.function = function;
00223     msg->msg.cb.ctx = ctx;
00224     if (block) {
00225       sys_mbox_post(&mbox, msg);
00226     } else {
00227       if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
00228         memp_free(MEMP_TCPIP_MSG_API, msg);
00229         return ERR_MEM;
00230       }
00231     }
00232     return ERR_OK;
00233   }
00234   return ERR_VAL;
00235 }
00236 
00237 #if LWIP_TCPIP_TIMEOUT
00238 /**
00239  * call sys_timeout in tcpip_thread
00240  *
00241  * @param msec time in milliseconds for timeout
00242  * @param h function to be called on timeout
00243  * @param arg argument to pass to timeout function h
00244  * @return ERR_MEM on memory error, ERR_OK otherwise
00245  */
00246 err_t
00247 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
00248 {
00249   struct tcpip_msg *msg;
00250 
00251   if (sys_mbox_valid(&mbox)) {
00252     msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00253     if (msg == NULL) {
00254       return ERR_MEM;
00255     }
00256 
00257     msg->type = TCPIP_MSG_TIMEOUT;
00258     msg->msg.tmo.msecs = msecs;
00259     msg->msg.tmo.h = h;
00260     msg->msg.tmo.arg = arg;
00261     sys_mbox_post(&mbox, msg);
00262     return ERR_OK;
00263   }
00264   return ERR_VAL;
00265 }
00266 
00267 /**
00268  * call sys_untimeout in tcpip_thread
00269  *
00270  * @param msec time in milliseconds for timeout
00271  * @param h function to be called on timeout
00272  * @param arg argument to pass to timeout function h
00273  * @return ERR_MEM on memory error, ERR_OK otherwise
00274  */
00275 err_t
00276 tcpip_untimeout(sys_timeout_handler h, void *arg)
00277 {
00278   struct tcpip_msg *msg;
00279 
00280   if (sys_mbox_valid(&mbox)) {
00281     msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00282     if (msg == NULL) {
00283       return ERR_MEM;
00284     }
00285 
00286     msg->type = TCPIP_MSG_UNTIMEOUT;
00287     msg->msg.tmo.h = h;
00288     msg->msg.tmo.arg = arg;
00289     sys_mbox_post(&mbox, msg);
00290     return ERR_OK;
00291   }
00292   return ERR_VAL;
00293 }
00294 #endif /* LWIP_TCPIP_TIMEOUT */
00295 
00296 #if LWIP_NETCONN
00297 /**
00298  * Call the lower part of a netconn_* function
00299  * This function is then running in the thread context
00300  * of tcpip_thread and has exclusive access to lwIP core code.
00301  *
00302  * @param apimsg a struct containing the function to call and its parameters
00303  * @return ERR_OK if the function was called, another err_t if not
00304  */
00305 err_t
00306 tcpip_apimsg(struct api_msg *apimsg)
00307 {
00308   struct tcpip_msg msg;
00309 #ifdef LWIP_DEBUG
00310   /* catch functions that don't set err */
00311   apimsg->msg.err = ERR_VAL;
00312 #endif
00313   
00314   if (sys_mbox_valid(&mbox)) {
00315     msg.type = TCPIP_MSG_API;
00316     msg.msg.apimsg = apimsg;
00317     sys_mbox_post(&mbox, &msg);
00318     sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
00319     return apimsg->msg.err;
00320   }
00321   return ERR_VAL;
00322 }
00323 
00324 #if LWIP_TCPIP_CORE_LOCKING
00325 /**
00326  * Call the lower part of a netconn_* function
00327  * This function has exclusive access to lwIP core code by locking it
00328  * before the function is called.
00329  *
00330  * @param apimsg a struct containing the function to call and its parameters
00331  * @return ERR_OK (only for compatibility fo tcpip_apimsg())
00332  */
00333 err_t
00334 tcpip_apimsg_lock(struct api_msg *apimsg)
00335 {
00336 #ifdef LWIP_DEBUG
00337   /* catch functions that don't set err */
00338   apimsg->msg.err = ERR_VAL;
00339 #endif
00340 
00341   LOCK_TCPIP_CORE();
00342   apimsg->function(&(apimsg->msg));
00343   UNLOCK_TCPIP_CORE();
00344   return apimsg->msg.err;
00345 
00346 }
00347 #endif /* LWIP_TCPIP_CORE_LOCKING */
00348 #endif /* LWIP_NETCONN */
00349 
00350 #if LWIP_NETIF_API
00351 #if !LWIP_TCPIP_CORE_LOCKING
00352 /**
00353  * Much like tcpip_apimsg, but calls the lower part of a netifapi_*
00354  * function.
00355  *
00356  * @param netifapimsg a struct containing the function to call and its parameters
00357  * @return error code given back by the function that was called
00358  */
00359 err_t
00360 tcpip_netifapi(struct netifapi_msg* netifapimsg)
00361 {
00362   struct tcpip_msg msg;
00363   
00364   if (sys_mbox_valid(&mbox)) {
00365     err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
00366     if (err != ERR_OK) {
00367       netifapimsg->msg.err = err;
00368       return err;
00369     }
00370     
00371     msg.type = TCPIP_MSG_NETIFAPI;
00372     msg.msg.netifapimsg = netifapimsg;
00373     sys_mbox_post(&mbox, &msg);
00374     sys_sem_wait(&netifapimsg->msg.sem);
00375     sys_sem_free(&netifapimsg->msg.sem);
00376     return netifapimsg->msg.err;
00377   }
00378   return ERR_VAL;
00379 }
00380 #else /* !LWIP_TCPIP_CORE_LOCKING */
00381 /**
00382  * Call the lower part of a netifapi_* function
00383  * This function has exclusive access to lwIP core code by locking it
00384  * before the function is called.
00385  *
00386  * @param netifapimsg a struct containing the function to call and its parameters
00387  * @return ERR_OK (only for compatibility fo tcpip_netifapi())
00388  */
00389 err_t
00390 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
00391 {
00392   LOCK_TCPIP_CORE();  
00393   netifapimsg->function(&(netifapimsg->msg));
00394   UNLOCK_TCPIP_CORE();
00395   return netifapimsg->msg.err;
00396 }
00397 #endif /* !LWIP_TCPIP_CORE_LOCKING */
00398 #endif /* LWIP_NETIF_API */
00399 
00400 /**
00401  * Allocate a structure for a static callback message and initialize it.
00402  * This is intended to be used to send "static" messages from interrupt context.
00403  *
00404  * @param function the function to call
00405  * @param ctx parameter passed to function
00406  * @return a struct pointer to pass to tcpip_trycallback().
00407  */
00408 struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
00409 {
00410   struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00411   if (msg == NULL) {
00412     return NULL;
00413   }
00414   msg->type = TCPIP_MSG_CALLBACK_STATIC;
00415   msg->msg.cb.function = function;
00416   msg->msg.cb.ctx = ctx;
00417   return (struct tcpip_callback_msg*)msg;
00418 }
00419 
00420 /**
00421  * Free a callback message allocated by tcpip_callbackmsg_new().
00422  *
00423  * @param msg the message to free
00424  */
00425 void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
00426 {
00427   memp_free(MEMP_TCPIP_MSG_API, msg);
00428 }
00429 
00430 /**
00431  * Try to post a callback-message to the tcpip_thread mbox
00432  * This is intended to be used to send "static" messages from interrupt context.
00433  *
00434  * @param msg pointer to the message to post
00435  * @return sys_mbox_trypost() return code
00436  */
00437 err_t
00438 tcpip_trycallback(struct tcpip_callback_msg* msg)
00439 {
00440   if (!sys_mbox_valid(&mbox)) {
00441     return ERR_VAL;
00442   }
00443   return sys_mbox_trypost(&mbox, msg);
00444 }
00445 
00446 /**
00447  * Initialize this module:
00448  * - initialize all sub modules
00449  * - start the tcpip_thread
00450  *
00451  * @param initfunc a function to call when tcpip_thread is running and finished initializing
00452  * @param arg argument to pass to initfunc
00453  */
00454 void
00455 tcpip_init(tcpip_init_done_fn initfunc, void *arg)
00456 {
00457   lwip_init();
00458 
00459   tcpip_init_done = initfunc;
00460   tcpip_init_done_arg = arg;
00461   if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
00462     LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
00463   }
00464 #if LWIP_TCPIP_CORE_LOCKING
00465   if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
00466     LWIP_ASSERT("failed to create lock_tcpip_core", 0);
00467   }
00468 #endif /* LWIP_TCPIP_CORE_LOCKING */
00469 
00470   sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
00471 }
00472 
00473 /**
00474  * Simple callback function used with tcpip_callback to free a pbuf
00475  * (pbuf_free has a wrong signature for tcpip_callback)
00476  *
00477  * @param p The pbuf (chain) to be dereferenced.
00478  */
00479 static void
00480 pbuf_free_int(void *p)
00481 {
00482   struct pbuf *q = (struct pbuf *)p;
00483   pbuf_free(q);
00484 }
00485 
00486 /**
00487  * A simple wrapper function that allows you to free a pbuf from interrupt context.
00488  *
00489  * @param p The pbuf (chain) to be dereferenced.
00490  * @return ERR_OK if callback could be enqueued, an err_t if not
00491  */
00492 err_t
00493 pbuf_free_callback(struct pbuf *p)
00494 {
00495   return tcpip_callback_with_block(pbuf_free_int, p, 0);
00496 }
00497 
00498 /**
00499  * A simple wrapper function that allows you to free heap memory from
00500  * interrupt context.
00501  *
00502  * @param m the heap memory to free
00503  * @return ERR_OK if callback could be enqueued, an err_t if not
00504  */
00505 err_t
00506 mem_free_callback(void *m)
00507 {
00508   return tcpip_callback_with_block(mem_free, m, 0);
00509 }
00510 
00511 #endif /* !NO_SYS */