ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_tcpip.c Source File

lwip_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/priv/tcpip_priv.h"
00044 #include "lwip/sys.h"
00045 #include "lwip/memp.h"
00046 #include "lwip/mem.h"
00047 #include "lwip/init.h"
00048 #include "lwip/ip.h"
00049 #include "lwip/pbuf.h"
00050 #include "lwip/etharp.h"
00051 
00052 #define TCPIP_MSG_VAR_REF(name)     API_VAR_REF(name)
00053 #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
00054 #define TCPIP_MSG_VAR_ALLOC(name)   API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
00055 #define TCPIP_MSG_VAR_FREE(name)    API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
00056 
00057 /* global variables */
00058 static tcpip_init_done_fn tcpip_init_done;
00059 static void *tcpip_init_done_arg;
00060 static sys_mbox_t mbox;
00061 
00062 #if LWIP_TCPIP_CORE_LOCKING
00063 /** The global semaphore to lock the stack. */
00064 sys_mutex_t lock_tcpip_core;
00065 #endif /* LWIP_TCPIP_CORE_LOCKING */
00066 
00067 
00068 /**
00069  * The main lwIP thread. This thread has exclusive access to lwIP core functions
00070  * (unless access to them is not locked). Other threads communicate with this
00071  * thread using message boxes.
00072  *
00073  * It also starts all the timers to make sure they are running in the right
00074  * thread context.
00075  *
00076  * @param arg unused argument
00077  */
00078 static void
00079 tcpip_thread(void *arg)
00080 {
00081   struct tcpip_msg *msg;
00082   LWIP_UNUSED_ARG(arg);
00083 
00084   if (tcpip_init_done != NULL) {
00085     tcpip_init_done(tcpip_init_done_arg);
00086   }
00087 
00088   LOCK_TCPIP_CORE();
00089   while (1) {                          /* MAIN Loop */
00090     UNLOCK_TCPIP_CORE();
00091     LWIP_TCPIP_THREAD_ALIVE();
00092     /* wait for a message, timeouts are processed while waiting */
00093     sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
00094     LOCK_TCPIP_CORE();
00095     if (msg == NULL) {
00096       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
00097       LWIP_ASSERT("tcpip_thread: invalid message", 0);
00098       continue;
00099     }
00100     switch (msg->type) {
00101 #if !LWIP_TCPIP_CORE_LOCKING
00102     case TCPIP_MSG_API:
00103       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
00104       msg->msg.api_msg.function(msg->msg.api_msg.msg);
00105       break;
00106     case TCPIP_MSG_API_CALL:
00107       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
00108       msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
00109       sys_sem_signal(msg->msg.api_call.sem);
00110       break;
00111 #endif /* !LWIP_TCPIP_CORE_LOCKING */
00112 
00113 #if !LWIP_TCPIP_CORE_LOCKING_INPUT
00114     case TCPIP_MSG_INPKT:
00115       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
00116       msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif);
00117       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00118       break;
00119 #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
00120 
00121 #if LWIP_TCPIP_TIMEOUT
00122     case TCPIP_MSG_TIMEOUT:
00123       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
00124       sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
00125       memp_free(MEMP_TCPIP_MSG_API, msg);
00126       break;
00127     case TCPIP_MSG_UNTIMEOUT:
00128       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
00129       sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
00130       memp_free(MEMP_TCPIP_MSG_API, msg);
00131       break;
00132 #endif /* LWIP_TCPIP_TIMEOUT */
00133 
00134     case TCPIP_MSG_CALLBACK:
00135       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
00136       msg->msg.cb.function(msg->msg.cb.ctx);
00137       memp_free(MEMP_TCPIP_MSG_API, msg);
00138       break;
00139 
00140     case TCPIP_MSG_CALLBACK_STATIC:
00141       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
00142       msg->msg.cb.function(msg->msg.cb.ctx);
00143       break;
00144 
00145     default:
00146       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
00147       LWIP_ASSERT("tcpip_thread: invalid message", 0);
00148       break;
00149     }
00150   }
00151 }
00152 
00153 /**
00154  * Pass a received packet to tcpip_thread for input processing
00155  *
00156  * @param p the received packet
00157  * @param inp the network interface on which the packet was received
00158  * @param input_fn input function to call
00159  */
00160 err_t
00161 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
00162 {
00163 #if LWIP_TCPIP_CORE_LOCKING_INPUT
00164   err_t ret;
00165   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
00166   LOCK_TCPIP_CORE();
00167   ret = input_fn(p, inp);
00168   UNLOCK_TCPIP_CORE();
00169   return ret;
00170 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00171   struct tcpip_msg *msg;
00172 
00173   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00174 
00175   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
00176   if (msg == NULL) {
00177     return ERR_MEM;
00178   }
00179 
00180   msg->type = TCPIP_MSG_INPKT;
00181   msg->msg.inp.p = p;
00182   msg->msg.inp.netif = inp;
00183   msg->msg.inp.input_fn = input_fn;
00184   if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
00185     memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00186     return ERR_MEM;
00187   }
00188   return ERR_OK;
00189 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00190 }
00191 
00192 /**
00193  * @ingroup lwip_os
00194  * Pass a received packet to tcpip_thread for input processing with
00195  * ethernet_input or ip_input. Don't call directly, pass to netif_add()
00196  * and call netif->input().
00197  *
00198  * @param p the received packet, p->payload pointing to the Ethernet header or
00199  *          to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
00200  *          NETIF_FLAG_ETHERNET flags)
00201  * @param inp the network interface on which the packet was received
00202  */
00203 err_t
00204 tcpip_input(struct pbuf *p, struct netif *inp)
00205 {
00206 #if LWIP_ETHERNET
00207   if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
00208     return tcpip_inpkt(p, inp, ethernet_input);
00209   } else
00210 #endif /* LWIP_ETHERNET */
00211   return tcpip_inpkt(p, inp, ip_input);
00212 }
00213 
00214 /**
00215  * Call a specific function in the thread context of
00216  * tcpip_thread for easy access synchronization.
00217  * A function called in that way may access lwIP core code
00218  * without fearing concurrent access.
00219  *
00220  * @param function the function to call
00221  * @param ctx parameter passed to f
00222  * @param block 1 to block until the request is posted, 0 to non-blocking mode
00223  * @return ERR_OK if the function was called, another err_t if not
00224  */
00225 err_t
00226 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
00227 {
00228   struct tcpip_msg *msg;
00229 
00230   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00231 
00232   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00233   if (msg == NULL) {
00234     return ERR_MEM;
00235   }
00236 
00237   msg->type = TCPIP_MSG_CALLBACK;
00238   msg->msg.cb.function = function;
00239   msg->msg.cb.ctx = ctx;
00240   if (block) {
00241     sys_mbox_post(&mbox, msg);
00242   } else {
00243     if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
00244       memp_free(MEMP_TCPIP_MSG_API, msg);
00245       return ERR_MEM;
00246     }
00247   }
00248   return ERR_OK;
00249 }
00250 
00251 #if LWIP_TCPIP_TIMEOUT
00252 /**
00253  * call sys_timeout in tcpip_thread
00254  *
00255  * @param msec time in milliseconds for timeout
00256  * @param h function to be called on timeout
00257  * @param arg argument to pass to timeout function h
00258  * @return ERR_MEM on memory error, ERR_OK otherwise
00259  */
00260 err_t
00261 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
00262 {
00263   struct tcpip_msg *msg;
00264 
00265   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00266 
00267   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00268   if (msg == NULL) {
00269     return ERR_MEM;
00270   }
00271 
00272   msg->type = TCPIP_MSG_TIMEOUT;
00273   msg->msg.tmo.msecs = msecs;
00274   msg->msg.tmo.h = h;
00275   msg->msg.tmo.arg = arg;
00276   sys_mbox_post(&mbox, msg);
00277   return ERR_OK;
00278 }
00279 
00280 /**
00281  * call sys_untimeout in tcpip_thread
00282  *
00283  * @param msec time in milliseconds for timeout
00284  * @param h function to be called on timeout
00285  * @param arg argument to pass to timeout function h
00286  * @return ERR_MEM on memory error, ERR_OK otherwise
00287  */
00288 err_t
00289 tcpip_untimeout(sys_timeout_handler h, void *arg)
00290 {
00291   struct tcpip_msg *msg;
00292 
00293   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00294 
00295   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00296   if (msg == NULL) {
00297     return ERR_MEM;
00298   }
00299 
00300   msg->type = TCPIP_MSG_UNTIMEOUT;
00301   msg->msg.tmo.h = h;
00302   msg->msg.tmo.arg = arg;
00303   sys_mbox_post(&mbox, msg);
00304   return ERR_OK;
00305 }
00306 #endif /* LWIP_TCPIP_TIMEOUT */
00307 
00308 
00309 /**
00310  * Sends a message to TCPIP thread to call a function. Caller thread blocks on
00311  * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread,
00312  * this has to be done by the user.
00313  * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
00314  * with least runtime overhead.
00315  *
00316  * @param fn function to be called from TCPIP thread
00317  * @param apimsg argument to API function
00318  * @param sem semaphore to wait on
00319  * @return ERR_OK if the function was called, another err_t if not
00320  */
00321 err_t
00322 tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
00323 {
00324 #if LWIP_TCPIP_CORE_LOCKING
00325   LWIP_UNUSED_ARG(sem);
00326   LOCK_TCPIP_CORE();
00327   fn(apimsg);
00328   UNLOCK_TCPIP_CORE();
00329   return ERR_OK;
00330 #else /* LWIP_TCPIP_CORE_LOCKING */
00331   TCPIP_MSG_VAR_DECLARE(msg);
00332 
00333   LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
00334   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00335 
00336   TCPIP_MSG_VAR_ALLOC(msg);
00337   TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
00338   TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
00339   TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
00340   sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
00341   sys_arch_sem_wait(sem, 0);
00342   TCPIP_MSG_VAR_FREE(msg);
00343   return ERR_OK;
00344 #endif /* LWIP_TCPIP_CORE_LOCKING */
00345 }
00346 
00347 /**
00348  * Synchronously calls function in TCPIP thread and waits for its completion.
00349  * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
00350  * LWIP_NETCONN_SEM_PER_THREAD. 
00351  * If not, a semaphore is created and destroyed on every call which is usually
00352  * an expensive/slow operation.
00353  * @param fn Function to call
00354  * @param call Call parameters
00355  * @return Return value from tcpip_api_call_fn
00356  */
00357 err_t
00358 tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
00359 {
00360 #if LWIP_TCPIP_CORE_LOCKING
00361   err_t err;
00362   LOCK_TCPIP_CORE();
00363   err = fn(call);
00364   UNLOCK_TCPIP_CORE();
00365   return err;
00366 #else /* LWIP_TCPIP_CORE_LOCKING */
00367   TCPIP_MSG_VAR_DECLARE(msg);
00368 
00369 #if !LWIP_NETCONN_SEM_PER_THREAD
00370   err_t err = sys_sem_new(&call->sem, 0);
00371   if (err != ERR_OK) {
00372     return err;
00373   }
00374 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00375 
00376   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00377     
00378   TCPIP_MSG_VAR_ALLOC(msg);
00379   TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
00380   TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
00381   TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
00382 #if LWIP_NETCONN_SEM_PER_THREAD
00383   TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
00384 #else /* LWIP_NETCONN_SEM_PER_THREAD */
00385   TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
00386 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00387   sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
00388   sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
00389   TCPIP_MSG_VAR_FREE(msg);
00390 
00391 #if !LWIP_NETCONN_SEM_PER_THREAD
00392   sys_sem_free(&call->sem);
00393 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00394 
00395   return call->err;
00396 #endif /* LWIP_TCPIP_CORE_LOCKING */
00397 }
00398 
00399 /**
00400  * Allocate a structure for a static callback message and initialize it.
00401  * This is intended to be used to send "static" messages from interrupt context.
00402  *
00403  * @param function the function to call
00404  * @param ctx parameter passed to function
00405  * @return a struct pointer to pass to tcpip_trycallback().
00406  */
00407 struct tcpip_callback_msg*
00408 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
00426 tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
00427 {
00428   memp_free(MEMP_TCPIP_MSG_API, msg);
00429 }
00430 
00431 /**
00432  * Try to post a callback-message to the tcpip_thread mbox
00433  * This is intended to be used to send "static" messages from interrupt context.
00434  *
00435  * @param msg pointer to the message to post
00436  * @return sys_mbox_trypost() return code
00437  */
00438 err_t
00439 tcpip_trycallback(struct tcpip_callback_msg* msg)
00440 {
00441   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
00442   return sys_mbox_trypost(&mbox, msg);
00443 }
00444 
00445 /**
00446  * @ingroup lwip_os
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 */