Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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 #include "netif/ethernet.h"
00052 
00053 #define TCPIP_MSG_VAR_REF(name)     API_VAR_REF(name)
00054 #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
00055 #define TCPIP_MSG_VAR_ALLOC(name)   API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
00056 #define TCPIP_MSG_VAR_FREE(name)    API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
00057 
00058 /* global variables */
00059 static tcpip_init_done_fn tcpip_init_done;
00060 static void *tcpip_init_done_arg;
00061 static sys_mbox_t tcpip_mbox;
00062 
00063 #if LWIP_TCPIP_CORE_LOCKING
00064 /** The global semaphore to lock the stack. */
00065 sys_mutex_t lock_tcpip_core;
00066 #endif /* LWIP_TCPIP_CORE_LOCKING */
00067 
00068 static void tcpip_thread_handle_msg(struct tcpip_msg *msg);
00069 
00070 #if !LWIP_TIMERS
00071 /* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
00072 #define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
00073 #else /* !LWIP_TIMERS */
00074 /* wait for a message, timeouts are processed while waiting */
00075 #define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg)
00076 /**
00077  * Wait (forever) for a message to arrive in an mbox.
00078  * While waiting, timeouts are processed.
00079  *
00080  * @param mbox the mbox to fetch the message from
00081  * @param msg the place to store the message
00082  */
00083 static void
00084 tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
00085 {
00086   u32_t sleeptime, res;
00087 
00088 again:
00089   LWIP_ASSERT_CORE_LOCKED();
00090 
00091   sleeptime = sys_timeouts_sleeptime();
00092   if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {
00093     UNLOCK_TCPIP_CORE();
00094     sys_arch_mbox_fetch(mbox, msg, 0);
00095     LOCK_TCPIP_CORE();
00096     return;
00097   } else if (sleeptime == 0) {
00098     sys_check_timeouts();
00099     /* We try again to fetch a message from the mbox. */
00100     goto again;
00101   }
00102 
00103   UNLOCK_TCPIP_CORE();
00104   res = sys_arch_mbox_fetch(mbox, msg, sleeptime);
00105   LOCK_TCPIP_CORE();
00106   if (res == SYS_ARCH_TIMEOUT) {
00107     /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
00108        before a message could be fetched. */
00109     sys_check_timeouts();
00110     /* We try again to fetch a message from the mbox. */
00111     goto again;
00112   }
00113 }
00114 #endif /* !LWIP_TIMERS */
00115 
00116 /**
00117  * The main lwIP thread. This thread has exclusive access to lwIP core functions
00118  * (unless access to them is not locked). Other threads communicate with this
00119  * thread using message boxes.
00120  *
00121  * It also starts all the timers to make sure they are running in the right
00122  * thread context.
00123  *
00124  * @param arg unused argument
00125  */
00126 static void
00127 tcpip_thread(void *arg)
00128 {
00129   struct tcpip_msg *msg;
00130   LWIP_UNUSED_ARG(arg);
00131 
00132   LWIP_MARK_TCPIP_THREAD();
00133 
00134   LOCK_TCPIP_CORE();
00135   if (tcpip_init_done != NULL) {
00136     tcpip_init_done(tcpip_init_done_arg);
00137   }
00138 
00139   while (1) {                          /* MAIN Loop */
00140     LWIP_TCPIP_THREAD_ALIVE();
00141     /* wait for a message, timeouts are processed while waiting */
00142     TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
00143     if (msg == NULL) {
00144       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
00145       LWIP_ASSERT("tcpip_thread: invalid message", 0);
00146       continue;
00147     }
00148     tcpip_thread_handle_msg(msg);
00149   }
00150 }
00151 
00152 /* Handle a single tcpip_msg
00153  * This is in its own function for access by tests only.
00154  */
00155 static void
00156 tcpip_thread_handle_msg(struct tcpip_msg *msg)
00157 {
00158   switch (msg->type) {
00159 #if !LWIP_TCPIP_CORE_LOCKING
00160     case TCPIP_MSG_API:
00161       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
00162       msg->msg.api_msg.function(msg->msg.api_msg.msg);
00163       break;
00164     case TCPIP_MSG_API_CALL:
00165       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
00166       msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
00167       sys_sem_signal(msg->msg.api_call.sem);
00168       break;
00169 #endif /* !LWIP_TCPIP_CORE_LOCKING */
00170 
00171 #if !LWIP_TCPIP_CORE_LOCKING_INPUT
00172     case TCPIP_MSG_INPKT:
00173       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
00174       if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) {
00175         pbuf_free(msg->msg.inp.p);
00176       }
00177       memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00178       break;
00179 #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
00180 
00181 #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
00182     case TCPIP_MSG_TIMEOUT:
00183       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
00184       sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
00185       memp_free(MEMP_TCPIP_MSG_API, msg);
00186       break;
00187     case TCPIP_MSG_UNTIMEOUT:
00188       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
00189       sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
00190       memp_free(MEMP_TCPIP_MSG_API, msg);
00191       break;
00192 #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
00193 
00194     case TCPIP_MSG_CALLBACK:
00195       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
00196       msg->msg.cb.function(msg->msg.cb.ctx);
00197       memp_free(MEMP_TCPIP_MSG_API, msg);
00198       break;
00199 
00200     case TCPIP_MSG_CALLBACK_STATIC:
00201       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
00202       msg->msg.cb.function(msg->msg.cb.ctx);
00203       break;
00204 
00205     default:
00206       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
00207       LWIP_ASSERT("tcpip_thread: invalid message", 0);
00208       break;
00209   }
00210 }
00211 
00212 #ifdef TCPIP_THREAD_TEST
00213 /** Work on queued items in single-threaded test mode */
00214 int
00215 tcpip_thread_poll_one(void)
00216 {
00217   int ret = 0;
00218   struct tcpip_msg *msg;
00219 
00220   if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_ARCH_TIMEOUT) {
00221     LOCK_TCPIP_CORE();
00222     if (msg != NULL) {
00223       tcpip_thread_handle_msg(msg);
00224       ret = 1;
00225     }
00226     UNLOCK_TCPIP_CORE();
00227   }
00228   return ret;
00229 }
00230 #endif
00231 
00232 /**
00233  * Pass a received packet to tcpip_thread for input processing
00234  *
00235  * @param p the received packet
00236  * @param inp the network interface on which the packet was received
00237  * @param input_fn input function to call
00238  */
00239 err_t
00240 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
00241 {
00242 #if LWIP_TCPIP_CORE_LOCKING_INPUT
00243   err_t ret;
00244   LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
00245   LOCK_TCPIP_CORE();
00246   ret = input_fn(p, inp);
00247   UNLOCK_TCPIP_CORE();
00248   return ret;
00249 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00250   struct tcpip_msg *msg;
00251 
00252   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00253 
00254   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
00255   if (msg == NULL) {
00256     return ERR_MEM;
00257   }
00258 
00259   msg->type = TCPIP_MSG_INPKT;
00260   msg->msg.inp.p = p;
00261   msg->msg.inp.netif = inp;
00262   msg->msg.inp.input_fn = input_fn;
00263   if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
00264     memp_free(MEMP_TCPIP_MSG_INPKT, msg);
00265     return ERR_MEM;
00266   }
00267   return ERR_OK;
00268 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
00269 }
00270 
00271 /**
00272  * @ingroup lwip_os
00273  * Pass a received packet to tcpip_thread for input processing with
00274  * ethernet_input or ip_input. Don't call directly, pass to netif_add()
00275  * and call netif->input().
00276  *
00277  * @param p the received packet, p->payload pointing to the Ethernet header or
00278  *          to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
00279  *          NETIF_FLAG_ETHERNET flags)
00280  * @param inp the network interface on which the packet was received
00281  */
00282 err_t
00283 tcpip_input(struct pbuf *p, struct netif *inp)
00284 {
00285 #if LWIP_ETHERNET
00286   if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
00287     return tcpip_inpkt(p, inp, ethernet_input);
00288   } else
00289 #endif /* LWIP_ETHERNET */
00290     return tcpip_inpkt(p, inp, ip_input);
00291 }
00292 
00293 /**
00294  * @ingroup lwip_os
00295  * Call a specific function in the thread context of
00296  * tcpip_thread for easy access synchronization.
00297  * A function called in that way may access lwIP core code
00298  * without fearing concurrent access.
00299  * Blocks until the request is posted.
00300  * Must not be called from interrupt context!
00301  *
00302  * @param function the function to call
00303  * @param ctx parameter passed to f
00304  * @return ERR_OK if the function was called, another err_t if not
00305  *
00306  * @see tcpip_try_callback
00307  */
00308 err_t
00309 tcpip_callback(tcpip_callback_fn function, void *ctx)
00310 {
00311   struct tcpip_msg *msg;
00312 
00313   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00314 
00315   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00316   if (msg == NULL) {
00317     return ERR_MEM;
00318   }
00319 
00320   msg->type = TCPIP_MSG_CALLBACK;
00321   msg->msg.cb.function = function;
00322   msg->msg.cb.ctx = ctx;
00323 
00324   sys_mbox_post(&tcpip_mbox, msg);
00325   return ERR_OK;
00326 }
00327 
00328 /**
00329  * @ingroup lwip_os
00330  * Call a specific function in the thread context of
00331  * tcpip_thread for easy access synchronization.
00332  * A function called in that way may access lwIP core code
00333  * without fearing concurrent access.
00334  * Does NOT block when the request cannot be posted because the
00335  * tcpip_mbox is full, but returns ERR_MEM instead.
00336  * Can be called from interrupt context.
00337  *
00338  * @param function the function to call
00339  * @param ctx parameter passed to f
00340  * @return ERR_OK if the function was called, another err_t if not
00341  *
00342  * @see tcpip_callback
00343  */
00344 err_t
00345 tcpip_try_callback(tcpip_callback_fn function, void *ctx)
00346 {
00347   struct tcpip_msg *msg;
00348 
00349   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00350 
00351   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00352   if (msg == NULL) {
00353     return ERR_MEM;
00354   }
00355 
00356   msg->type = TCPIP_MSG_CALLBACK;
00357   msg->msg.cb.function = function;
00358   msg->msg.cb.ctx = ctx;
00359 
00360   if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
00361     memp_free(MEMP_TCPIP_MSG_API, msg);
00362     return ERR_MEM;
00363   }
00364   return ERR_OK;
00365 }
00366 
00367 #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
00368 /**
00369  * call sys_timeout in tcpip_thread
00370  *
00371  * @param msecs time in milliseconds for timeout
00372  * @param h function to be called on timeout
00373  * @param arg argument to pass to timeout function h
00374  * @return ERR_MEM on memory error, ERR_OK otherwise
00375  */
00376 err_t
00377 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
00378 {
00379   struct tcpip_msg *msg;
00380 
00381   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00382 
00383   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00384   if (msg == NULL) {
00385     return ERR_MEM;
00386   }
00387 
00388   msg->type = TCPIP_MSG_TIMEOUT;
00389   msg->msg.tmo.msecs = msecs;
00390   msg->msg.tmo.h = h;
00391   msg->msg.tmo.arg = arg;
00392   sys_mbox_post(&tcpip_mbox, msg);
00393   return ERR_OK;
00394 }
00395 
00396 /**
00397  * call sys_untimeout in tcpip_thread
00398  *
00399  * @param h function to be called on timeout
00400  * @param arg argument to pass to timeout function h
00401  * @return ERR_MEM on memory error, ERR_OK otherwise
00402  */
00403 err_t
00404 tcpip_untimeout(sys_timeout_handler h, void *arg)
00405 {
00406   struct tcpip_msg *msg;
00407 
00408   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00409 
00410   msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00411   if (msg == NULL) {
00412     return ERR_MEM;
00413   }
00414 
00415   msg->type = TCPIP_MSG_UNTIMEOUT;
00416   msg->msg.tmo.h = h;
00417   msg->msg.tmo.arg = arg;
00418   sys_mbox_post(&tcpip_mbox, msg);
00419   return ERR_OK;
00420 }
00421 #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
00422 
00423 
00424 /**
00425  * Sends a message to TCPIP thread to call a function. Caller thread blocks on
00426  * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread,
00427  * this has to be done by the user.
00428  * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
00429  * with least runtime overhead.
00430  *
00431  * @param fn function to be called from TCPIP thread
00432  * @param apimsg argument to API function
00433  * @param sem semaphore to wait on
00434  * @return ERR_OK if the function was called, another err_t if not
00435  */
00436 err_t
00437 tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
00438 {
00439 #if LWIP_TCPIP_CORE_LOCKING
00440   LWIP_UNUSED_ARG(sem);
00441   LOCK_TCPIP_CORE();
00442   fn(apimsg);
00443   UNLOCK_TCPIP_CORE();
00444   return ERR_OK;
00445 #else /* LWIP_TCPIP_CORE_LOCKING */
00446   TCPIP_MSG_VAR_DECLARE(msg);
00447 
00448   LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
00449   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00450 
00451   TCPIP_MSG_VAR_ALLOC(msg);
00452   TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
00453   TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
00454   TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
00455   sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
00456   sys_arch_sem_wait(sem, 0);
00457   TCPIP_MSG_VAR_FREE(msg);
00458   return ERR_OK;
00459 #endif /* LWIP_TCPIP_CORE_LOCKING */
00460 }
00461 
00462 /**
00463  * Synchronously calls function in TCPIP thread and waits for its completion.
00464  * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
00465  * LWIP_NETCONN_SEM_PER_THREAD.
00466  * If not, a semaphore is created and destroyed on every call which is usually
00467  * an expensive/slow operation.
00468  * @param fn Function to call
00469  * @param call Call parameters
00470  * @return Return value from tcpip_api_call_fn
00471  */
00472 err_t
00473 tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
00474 {
00475 #if LWIP_TCPIP_CORE_LOCKING
00476   err_t err;
00477   LOCK_TCPIP_CORE();
00478   err = fn(call);
00479   UNLOCK_TCPIP_CORE();
00480   return err;
00481 #else /* LWIP_TCPIP_CORE_LOCKING */
00482   TCPIP_MSG_VAR_DECLARE(msg);
00483 
00484 #if !LWIP_NETCONN_SEM_PER_THREAD
00485   err_t err = sys_sem_new(&call->sem, 0);
00486   if (err != ERR_OK) {
00487     return err;
00488   }
00489 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00490 
00491   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00492 
00493   TCPIP_MSG_VAR_ALLOC(msg);
00494   TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
00495   TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
00496   TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
00497 #if LWIP_NETCONN_SEM_PER_THREAD
00498   TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
00499 #else /* LWIP_NETCONN_SEM_PER_THREAD */
00500   TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
00501 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00502   sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
00503   sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
00504   TCPIP_MSG_VAR_FREE(msg);
00505 
00506 #if !LWIP_NETCONN_SEM_PER_THREAD
00507   sys_sem_free(&call->sem);
00508 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00509 
00510   return call->err;
00511 #endif /* LWIP_TCPIP_CORE_LOCKING */
00512 }
00513 
00514 /**
00515  * @ingroup lwip_os
00516  * Allocate a structure for a static callback message and initialize it.
00517  * The message has a special type such that lwIP never frees it.
00518  * This is intended to be used to send "static" messages from interrupt context,
00519  * e.g. the message is allocated once and posted several times from an IRQ
00520  * using tcpip_callbackmsg_trycallback().
00521  * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context.
00522  * 
00523  * @param function the function to call
00524  * @param ctx parameter passed to function
00525  * @return a struct pointer to pass to tcpip_callbackmsg_trycallback().
00526  *
00527  * @see tcpip_callbackmsg_trycallback()
00528  * @see tcpip_callbackmsg_delete()
00529  */
00530 struct tcpip_callback_msg *
00531 tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
00532 {
00533   struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
00534   if (msg == NULL) {
00535     return NULL;
00536   }
00537   msg->type = TCPIP_MSG_CALLBACK_STATIC;
00538   msg->msg.cb.function = function;
00539   msg->msg.cb.ctx = ctx;
00540   return (struct tcpip_callback_msg *)msg;
00541 }
00542 
00543 /**
00544  * @ingroup lwip_os
00545  * Free a callback message allocated by tcpip_callbackmsg_new().
00546  *
00547  * @param msg the message to free
00548  *
00549  * @see tcpip_callbackmsg_new()
00550  */
00551 void
00552 tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg)
00553 {
00554   memp_free(MEMP_TCPIP_MSG_API, msg);
00555 }
00556 
00557 /**
00558  * @ingroup lwip_os
00559  * Try to post a callback-message to the tcpip_thread tcpip_mbox.
00560  *
00561  * @param msg pointer to the message to post
00562  * @return sys_mbox_trypost() return code
00563  *
00564  * @see tcpip_callbackmsg_new()
00565  */
00566 err_t
00567 tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg)
00568 {
00569   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00570   return sys_mbox_trypost(&tcpip_mbox, msg);
00571 }
00572 
00573 /**
00574  * @ingroup lwip_os
00575  * Try to post a callback-message to the tcpip_thread mbox.
00576  * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(),
00577  * mainly to help FreeRTOS, where calls differ between task level and ISR level.
00578  *
00579  * @param msg pointer to the message to post
00580  * @return sys_mbox_trypost_fromisr() return code (without change, so this
00581  *         knowledge can be used to e.g. propagate "bool needs_scheduling")
00582  *
00583  * @see tcpip_callbackmsg_new()
00584  */
00585 err_t
00586 tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg)
00587 {
00588   LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
00589   return sys_mbox_trypost_fromisr(&tcpip_mbox, msg);
00590 }
00591 
00592 /**
00593  * @ingroup lwip_os
00594  * Initialize this module:
00595  * - initialize all sub modules
00596  * - start the tcpip_thread
00597  *
00598  * @param initfunc a function to call when tcpip_thread is running and finished initializing
00599  * @param arg argument to pass to initfunc
00600  */
00601 void
00602 tcpip_init(tcpip_init_done_fn initfunc, void *arg)
00603 {
00604   lwip_init();
00605 
00606   tcpip_init_done = initfunc;
00607   tcpip_init_done_arg = arg;
00608   if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
00609     LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
00610   }
00611 #if LWIP_TCPIP_CORE_LOCKING
00612   if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
00613     LWIP_ASSERT("failed to create lock_tcpip_core", 0);
00614   }
00615 #endif /* LWIP_TCPIP_CORE_LOCKING */
00616 
00617   sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
00618 }
00619 
00620 /**
00621  * Simple callback function used with tcpip_callback to free a pbuf
00622  * (pbuf_free has a wrong signature for tcpip_callback)
00623  *
00624  * @param p The pbuf (chain) to be dereferenced.
00625  */
00626 static void
00627 pbuf_free_int(void *p)
00628 {
00629   struct pbuf *q = (struct pbuf *)p;
00630   pbuf_free(q);
00631 }
00632 
00633 /**
00634  * A simple wrapper function that allows you to free a pbuf from interrupt context.
00635  *
00636  * @param p The pbuf (chain) to be dereferenced.
00637  * @return ERR_OK if callback could be enqueued, an err_t if not
00638  */
00639 err_t
00640 pbuf_free_callback(struct pbuf *p)
00641 {
00642   return tcpip_try_callback(pbuf_free_int, p);
00643 }
00644 
00645 /**
00646  * A simple wrapper function that allows you to free heap memory from
00647  * interrupt context.
00648  *
00649  * @param m the heap memory to free
00650  * @return ERR_OK if callback could be enqueued, an err_t if not
00651  */
00652 err_t
00653 mem_free_callback(void *m)
00654 {
00655   return tcpip_try_callback(mem_free, m);
00656 }
00657 
00658 #endif /* !NO_SYS */