1/** 2 * @file 3 * Sequential API Main thread module 4 * 5 */ 6 7/* 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, 12 * are permitted provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation 18 * and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31 * OF SUCH DAMAGE. 32 * 33 * This file is part of the lwIP TCP/IP stack. 34 * 35 * Author: Adam Dunkels <adam@sics.se> 36 * 37 */ 38 39#include "lwip/opt.h" 40 41#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ 42 43#include "lwip/priv/tcpip_priv.h" 44#include "lwip/sys.h" 45#include "lwip/memp.h" 46#include "lwip/mem.h" 47#include "lwip/init.h" 48#include "lwip/ip.h" 49#include "lwip/pbuf.h" 50#include "lwip/etharp.h" 51#include "netif/ethernet.h" 52 53#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) 54#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) 55#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) 56#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) 57 58/* global variables */ 59static tcpip_init_done_fn tcpip_init_done; 60static void *tcpip_init_done_arg; 61static sys_mbox_t tcpip_mbox; 62 63#if LWIP_TCPIP_CORE_LOCKING 64/** The global semaphore to lock the stack. */ 65sys_mutex_t lock_tcpip_core; 66#endif /* LWIP_TCPIP_CORE_LOCKING */ 67 68static void tcpip_thread_handle_msg(struct tcpip_msg *msg); 69 70#if !LWIP_TIMERS 71/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ 72#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) 73#else /* !LWIP_TIMERS */ 74/* wait for a message, timeouts are processed while waiting */ 75#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg) 76/** 77 * Wait (forever) for a message to arrive in an mbox. 78 * While waiting, timeouts are processed. 79 * 80 * @param mbox the mbox to fetch the message from 81 * @param msg the place to store the message 82 */ 83static void 84tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 85{ 86 u32_t sleeptime, res; 87 88again: 89 LWIP_ASSERT_CORE_LOCKED(); 90 91 sleeptime = sys_timeouts_sleeptime(); 92 if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { 93 UNLOCK_TCPIP_CORE(); 94 sys_arch_mbox_fetch(mbox, msg, 0); 95 LOCK_TCPIP_CORE(); 96 return; 97 } else if (sleeptime == 0) { 98 sys_check_timeouts(); 99 /* We try again to fetch a message from the mbox. */ 100 goto again; 101 } 102 103 UNLOCK_TCPIP_CORE(); 104 res = sys_arch_mbox_fetch(mbox, msg, sleeptime); 105 LOCK_TCPIP_CORE(); 106 if (res == SYS_ARCH_TIMEOUT) { 107 /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred 108 before a message could be fetched. */ 109 sys_check_timeouts(); 110 /* We try again to fetch a message from the mbox. */ 111 goto again; 112 } 113} 114#endif /* !LWIP_TIMERS */ 115 116/** 117 * The main lwIP thread. This thread has exclusive access to lwIP core functions 118 * (unless access to them is not locked). Other threads communicate with this 119 * thread using message boxes. 120 * 121 * It also starts all the timers to make sure they are running in the right 122 * thread context. 123 * 124 * @param arg unused argument 125 */ 126static void 127tcpip_thread(void *arg) 128{ 129 struct tcpip_msg *msg; 130 LWIP_UNUSED_ARG(arg); 131 132 LWIP_MARK_TCPIP_THREAD(); 133 134 LOCK_TCPIP_CORE(); 135 if (tcpip_init_done != NULL) { 136 tcpip_init_done(tcpip_init_done_arg); 137 } 138 139 while (1) { /* MAIN Loop */ 140 LWIP_TCPIP_THREAD_ALIVE(); 141 /* wait for a message, timeouts are processed while waiting */ 142 TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); 143 if (msg == NULL) { 144 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); 145 LWIP_ASSERT("tcpip_thread: invalid message", 0); 146 continue; 147 } 148 tcpip_thread_handle_msg(msg); 149 } 150} 151 152/* Handle a single tcpip_msg 153 * This is in its own function for access by tests only. 154 */ 155static void 156tcpip_thread_handle_msg(struct tcpip_msg *msg) 157{ 158 switch (msg->type) { 159#if !LWIP_TCPIP_CORE_LOCKING 160 case TCPIP_MSG_API: 161 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 162 msg->msg.api_msg.function(msg->msg.api_msg.msg); 163 break; 164 case TCPIP_MSG_API_CALL: 165 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); 166 msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); 167 sys_sem_signal(msg->msg.api_call.sem); 168 break; 169#endif /* !LWIP_TCPIP_CORE_LOCKING */ 170 171#if !LWIP_TCPIP_CORE_LOCKING_INPUT 172 case TCPIP_MSG_INPKT: 173 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 174 if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) { 175 pbuf_free(msg->msg.inp.p); 176 } 177 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 178 break; 179#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ 180 181#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 182 case TCPIP_MSG_TIMEOUT: 183 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 184 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 185 memp_free(MEMP_TCPIP_MSG_API, msg); 186 break; 187 case TCPIP_MSG_UNTIMEOUT: 188 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 189 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 190 memp_free(MEMP_TCPIP_MSG_API, msg); 191 break; 192#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 193 194 case TCPIP_MSG_CALLBACK: 195 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 196 msg->msg.cb.function(msg->msg.cb.ctx); 197 memp_free(MEMP_TCPIP_MSG_API, msg); 198 break; 199 200 case TCPIP_MSG_CALLBACK_STATIC: 201 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); 202 msg->msg.cb.function(msg->msg.cb.ctx); 203 break; 204 205 default: 206 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 207 LWIP_ASSERT("tcpip_thread: invalid message", 0); 208 break; 209 } 210} 211 212#ifdef TCPIP_THREAD_TEST 213/** Work on queued items in single-threaded test mode */ 214int 215tcpip_thread_poll_one(void) 216{ 217 int ret = 0; 218 struct tcpip_msg *msg; 219 220 if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_ARCH_TIMEOUT) { 221 LOCK_TCPIP_CORE(); 222 if (msg != NULL) { 223 tcpip_thread_handle_msg(msg); 224 ret = 1; 225 } 226 UNLOCK_TCPIP_CORE(); 227 } 228 return ret; 229} 230#endif 231 232/** 233 * Pass a received packet to tcpip_thread for input processing 234 * 235 * @param p the received packet 236 * @param inp the network interface on which the packet was received 237 * @param input_fn input function to call 238 */ 239err_t 240tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 241{ 242#if LWIP_TCPIP_CORE_LOCKING_INPUT 243 err_t ret; 244 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); 245 LOCK_TCPIP_CORE(); 246 ret = input_fn(p, inp); 247 UNLOCK_TCPIP_CORE(); 248 return ret; 249#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 250 struct tcpip_msg *msg; 251 252 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 253 254 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 255 if (msg == NULL) { 256 return ERR_MEM; 257 } 258 259 msg->type = TCPIP_MSG_INPKT; 260 msg->msg.inp.p = p; 261 msg->msg.inp.netif = inp; 262 msg->msg.inp.input_fn = input_fn; 263 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 264 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 265 return ERR_MEM; 266 } 267 return ERR_OK; 268#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 269} 270 271/** 272 * @ingroup lwip_os 273 * Pass a received packet to tcpip_thread for input processing with 274 * ethernet_input or ip_input. Don't call directly, pass to netif_add() 275 * and call netif->input(). 276 * 277 * @param p the received packet, p->payload pointing to the Ethernet header or 278 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 279 * NETIF_FLAG_ETHERNET flags) 280 * @param inp the network interface on which the packet was received 281 */ 282err_t 283tcpip_input(struct pbuf *p, struct netif *inp) 284{ 285#if LWIP_ETHERNET 286 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 287 return tcpip_inpkt(p, inp, ethernet_input); 288 } else 289#endif /* LWIP_ETHERNET */ 290 return tcpip_inpkt(p, inp, ip_input); 291} 292 293/** 294 * @ingroup lwip_os 295 * Call a specific function in the thread context of 296 * tcpip_thread for easy access synchronization. 297 * A function called in that way may access lwIP core code 298 * without fearing concurrent access. 299 * Blocks until the request is posted. 300 * Must not be called from interrupt context! 301 * 302 * @param function the function to call 303 * @param ctx parameter passed to f 304 * @return ERR_OK if the function was called, another err_t if not 305 * 306 * @see tcpip_try_callback 307 */ 308err_t 309tcpip_callback(tcpip_callback_fn function, void *ctx) 310{ 311 struct tcpip_msg *msg; 312 313 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 314 315 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 316 if (msg == NULL) { 317 return ERR_MEM; 318 } 319 320 msg->type = TCPIP_MSG_CALLBACK; 321 msg->msg.cb.function = function; 322 msg->msg.cb.ctx = ctx; 323 324 sys_mbox_post(&tcpip_mbox, msg); 325 return ERR_OK; 326} 327 328/** 329 * @ingroup lwip_os 330 * Call a specific function in the thread context of 331 * tcpip_thread for easy access synchronization. 332 * A function called in that way may access lwIP core code 333 * without fearing concurrent access. 334 * Does NOT block when the request cannot be posted because the 335 * tcpip_mbox is full, but returns ERR_MEM instead. 336 * Can be called from interrupt context. 337 * 338 * @param function the function to call 339 * @param ctx parameter passed to f 340 * @return ERR_OK if the function was called, another err_t if not 341 * 342 * @see tcpip_callback 343 */ 344err_t 345tcpip_try_callback(tcpip_callback_fn function, void *ctx) 346{ 347 struct tcpip_msg *msg; 348 349 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 350 351 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 352 if (msg == NULL) { 353 return ERR_MEM; 354 } 355 356 msg->type = TCPIP_MSG_CALLBACK; 357 msg->msg.cb.function = function; 358 msg->msg.cb.ctx = ctx; 359 360 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 361 memp_free(MEMP_TCPIP_MSG_API, msg); 362 return ERR_MEM; 363 } 364 return ERR_OK; 365} 366 367#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 368/** 369 * call sys_timeout in tcpip_thread 370 * 371 * @param msecs time in milliseconds for timeout 372 * @param h function to be called on timeout 373 * @param arg argument to pass to timeout function h 374 * @return ERR_MEM on memory error, ERR_OK otherwise 375 */ 376err_t 377tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 378{ 379 struct tcpip_msg *msg; 380 381 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 382 383 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 384 if (msg == NULL) { 385 return ERR_MEM; 386 } 387 388 msg->type = TCPIP_MSG_TIMEOUT; 389 msg->msg.tmo.msecs = msecs; 390 msg->msg.tmo.h = h; 391 msg->msg.tmo.arg = arg; 392 sys_mbox_post(&tcpip_mbox, msg); 393 return ERR_OK; 394} 395 396/** 397 * call sys_untimeout in tcpip_thread 398 * 399 * @param h function to be called on timeout 400 * @param arg argument to pass to timeout function h 401 * @return ERR_MEM on memory error, ERR_OK otherwise 402 */ 403err_t 404tcpip_untimeout(sys_timeout_handler h, void *arg) 405{ 406 struct tcpip_msg *msg; 407 408 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 409 410 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 411 if (msg == NULL) { 412 return ERR_MEM; 413 } 414 415 msg->type = TCPIP_MSG_UNTIMEOUT; 416 msg->msg.tmo.h = h; 417 msg->msg.tmo.arg = arg; 418 sys_mbox_post(&tcpip_mbox, msg); 419 return ERR_OK; 420} 421#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 422 423 424/** 425 * Sends a message to TCPIP thread to call a function. Caller thread blocks on 426 * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, 427 * this has to be done by the user. 428 * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way 429 * with least runtime overhead. 430 * 431 * @param fn function to be called from TCPIP thread 432 * @param apimsg argument to API function 433 * @param sem semaphore to wait on 434 * @return ERR_OK if the function was called, another err_t if not 435 */ 436err_t 437tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) 438{ 439#if LWIP_TCPIP_CORE_LOCKING 440 LWIP_UNUSED_ARG(sem); 441 LOCK_TCPIP_CORE(); 442 fn(apimsg); 443 UNLOCK_TCPIP_CORE(); 444 return ERR_OK; 445#else /* LWIP_TCPIP_CORE_LOCKING */ 446 TCPIP_MSG_VAR_DECLARE(msg); 447 448 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); 449 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 450 451 TCPIP_MSG_VAR_ALLOC(msg); 452 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; 453 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; 454 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; 455 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 456 sys_arch_sem_wait(sem, 0); 457 TCPIP_MSG_VAR_FREE(msg); 458 return ERR_OK; 459#endif /* LWIP_TCPIP_CORE_LOCKING */ 460} 461 462/** 463 * Synchronously calls function in TCPIP thread and waits for its completion. 464 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 465 * LWIP_NETCONN_SEM_PER_THREAD. 466 * If not, a semaphore is created and destroyed on every call which is usually 467 * an expensive/slow operation. 468 * @param fn Function to call 469 * @param call Call parameters 470 * @return Return value from tcpip_api_call_fn 471 */ 472err_t 473tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) 474{ 475#if LWIP_TCPIP_CORE_LOCKING 476 err_t err; 477 LOCK_TCPIP_CORE(); 478 err = fn(call); 479 UNLOCK_TCPIP_CORE(); 480 return err; 481#else /* LWIP_TCPIP_CORE_LOCKING */ 482 TCPIP_MSG_VAR_DECLARE(msg); 483 484#if !LWIP_NETCONN_SEM_PER_THREAD 485 err_t err = sys_sem_new(&call->sem, 0); 486 if (err != ERR_OK) { 487 return err; 488 } 489#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 490 491 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 492 493 TCPIP_MSG_VAR_ALLOC(msg); 494 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; 495 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; 496 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; 497#if LWIP_NETCONN_SEM_PER_THREAD 498 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); 499#else /* LWIP_NETCONN_SEM_PER_THREAD */ 500 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; 501#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 502 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 503 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); 504 TCPIP_MSG_VAR_FREE(msg); 505 506#if !LWIP_NETCONN_SEM_PER_THREAD 507 sys_sem_free(&call->sem); 508#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 509 510 return call->err; 511#endif /* LWIP_TCPIP_CORE_LOCKING */ 512} 513 514/** 515 * @ingroup lwip_os 516 * Allocate a structure for a static callback message and initialize it. 517 * The message has a special type such that lwIP never frees it. 518 * This is intended to be used to send "static" messages from interrupt context, 519 * e.g. the message is allocated once and posted several times from an IRQ 520 * using tcpip_callbackmsg_trycallback(). 521 * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context. 522 * 523 * @param function the function to call 524 * @param ctx parameter passed to function 525 * @return a struct pointer to pass to tcpip_callbackmsg_trycallback(). 526 * 527 * @see tcpip_callbackmsg_trycallback() 528 * @see tcpip_callbackmsg_delete() 529 */ 530struct tcpip_callback_msg * 531tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 532{ 533 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 534 if (msg == NULL) { 535 return NULL; 536 } 537 msg->type = TCPIP_MSG_CALLBACK_STATIC; 538 msg->msg.cb.function = function; 539 msg->msg.cb.ctx = ctx; 540 return (struct tcpip_callback_msg *)msg; 541} 542 543/** 544 * @ingroup lwip_os 545 * Free a callback message allocated by tcpip_callbackmsg_new(). 546 * 547 * @param msg the message to free 548 * 549 * @see tcpip_callbackmsg_new() 550 */ 551void 552tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg) 553{ 554 memp_free(MEMP_TCPIP_MSG_API, msg); 555} 556 557/** 558 * @ingroup lwip_os 559 * Try to post a callback-message to the tcpip_thread tcpip_mbox. 560 * 561 * @param msg pointer to the message to post 562 * @return sys_mbox_trypost() return code 563 * 564 * @see tcpip_callbackmsg_new() 565 */ 566err_t 567tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg) 568{ 569 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 570 return sys_mbox_trypost(&tcpip_mbox, msg); 571} 572 573/** 574 * @ingroup lwip_os 575 * Try to post a callback-message to the tcpip_thread mbox. 576 * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(), 577 * mainly to help FreeRTOS, where calls differ between task level and ISR level. 578 * 579 * @param msg pointer to the message to post 580 * @return sys_mbox_trypost_fromisr() return code (without change, so this 581 * knowledge can be used to e.g. propagate "bool needs_scheduling") 582 * 583 * @see tcpip_callbackmsg_new() 584 */ 585err_t 586tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg) 587{ 588 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 589 return sys_mbox_trypost_fromisr(&tcpip_mbox, msg); 590} 591 592/** 593 * @ingroup lwip_os 594 * Initialize this module: 595 * - initialize all sub modules 596 * - start the tcpip_thread 597 * 598 * @param initfunc a function to call when tcpip_thread is running and finished initializing 599 * @param arg argument to pass to initfunc 600 */ 601void 602tcpip_init(tcpip_init_done_fn initfunc, void *arg) 603{ 604 lwip_init(); 605 606 tcpip_init_done = initfunc; 607 tcpip_init_done_arg = arg; 608 if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 609 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 610 } 611#if LWIP_TCPIP_CORE_LOCKING 612 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 613 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 614 } 615#endif /* LWIP_TCPIP_CORE_LOCKING */ 616 617 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 618} 619 620/** 621 * Simple callback function used with tcpip_callback to free a pbuf 622 * (pbuf_free has a wrong signature for tcpip_callback) 623 * 624 * @param p The pbuf (chain) to be dereferenced. 625 */ 626static void 627pbuf_free_int(void *p) 628{ 629 struct pbuf *q = (struct pbuf *)p; 630 pbuf_free(q); 631} 632 633/** 634 * A simple wrapper function that allows you to free a pbuf from interrupt context. 635 * 636 * @param p The pbuf (chain) to be dereferenced. 637 * @return ERR_OK if callback could be enqueued, an err_t if not 638 */ 639err_t 640pbuf_free_callback(struct pbuf *p) 641{ 642 return tcpip_try_callback(pbuf_free_int, p); 643} 644 645/** 646 * A simple wrapper function that allows you to free heap memory from 647 * interrupt context. 648 * 649 * @param m the heap memory to free 650 * @return ERR_OK if callback could be enqueued, an err_t if not 651 */ 652err_t 653mem_free_callback(void *m) 654{ 655 return tcpip_try_callback(mem_free, m); 656} 657 658#endif /* !NO_SYS */ 659