Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_tcpip.c
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 */
Generated on Tue Jul 12 2022 13:54:30 by
