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#if LWIP_LOWPOWER 53#include "lwip/lowpower.h" 54#endif 55 56#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) 57#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) 58#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) 59#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) 60 61/* global variables */ 62static tcpip_init_done_fn tcpip_init_done; 63static void *tcpip_init_done_arg; 64static sys_mbox_t tcpip_mbox; 65 66#if LWIP_TCPIP_CORE_LOCKING 67/** The global semaphore to lock the stack. */ 68sys_mutex_t lock_tcpip_core; 69#endif /* LWIP_TCPIP_CORE_LOCKING */ 70 71static void tcpip_thread_handle_msg(struct tcpip_msg *msg); 72 73#if !LWIP_TIMERS 74/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ 75#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) 76#else /* !LWIP_TIMERS */ 77/* wait for a message, timeouts are processed while waiting */ 78#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg) 79#if !LWIP_LOWPOWER 80/** 81 * Wait (forever) for a message to arrive in an mbox. 82 * While waiting, timeouts are processed. 83 * 84 * @param mbox the mbox to fetch the message from 85 * @param msg the place to store the message 86 */ 87static void 88tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 89{ 90 u32_t sleeptime, res; 91 92again: 93 LWIP_ASSERT_CORE_LOCKED(); 94 95 sleeptime = sys_timeouts_sleeptime(); 96 if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) { 97 UNLOCK_TCPIP_CORE(); 98 sys_arch_mbox_fetch(mbox, msg, 0); 99 LOCK_TCPIP_CORE(); 100 return; 101 } else if (sleeptime == 0) { 102 sys_check_timeouts(); 103 /* We try again to fetch a message from the mbox. */ 104 goto again; 105 } 106 107 UNLOCK_TCPIP_CORE(); 108 res = sys_arch_mbox_fetch(mbox, msg, sleeptime); 109 LOCK_TCPIP_CORE(); 110 if (res == SYS_ARCH_TIMEOUT) { 111 /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred 112 before a message could be fetched. */ 113 sys_check_timeouts(); 114 /* We try again to fetch a message from the mbox. */ 115 goto again; 116 } 117} 118#endif /* !LWIP_LOWPOWER */ 119#endif /* !LWIP_TIMERS */ 120 121/** 122 * The main lwIP thread. This thread has exclusive access to lwIP core functions 123 * (unless access to them is not locked). Other threads communicate with this 124 * thread using message boxes. 125 * 126 * It also starts all the timers to make sure they are running in the right 127 * thread context. 128 * 129 * @param arg unused argument 130 */ 131static void 132tcpip_thread(void *arg) 133{ 134 struct tcpip_msg *msg; 135 LWIP_UNUSED_ARG(arg); 136 137 LWIP_MARK_TCPIP_THREAD(); 138 139 LOCK_TCPIP_CORE(); 140 if (tcpip_init_done != NULL) { 141 tcpip_init_done(tcpip_init_done_arg); 142 } 143 144 while (1) { /* MAIN Loop */ 145 LWIP_TCPIP_THREAD_ALIVE(); 146 /* wait for a message, timeouts are processed while waiting */ 147 TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg); 148 if (msg == NULL) { 149 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); 150 LWIP_ASSERT("tcpip_thread: invalid message", 0); 151 continue; 152 } 153 tcpip_thread_handle_msg(msg); 154 } 155} 156 157/* Handle a single tcpip_msg 158 * This is in its own function for access by tests only. 159 */ 160static void 161tcpip_thread_handle_msg(struct tcpip_msg *msg) 162{ 163 switch (msg->type) { 164#if !LWIP_TCPIP_CORE_LOCKING 165 case TCPIP_MSG_API: 166 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 167 msg->msg.api_msg.function(msg->msg.api_msg.msg); 168 break; 169 case TCPIP_MSG_API_CALL: 170 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); 171 msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); 172 sys_sem_signal(msg->msg.api_call.sem); 173 break; 174#endif /* !LWIP_TCPIP_CORE_LOCKING */ 175 176#if !LWIP_TCPIP_CORE_LOCKING_INPUT 177 case TCPIP_MSG_INPKT: 178 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 179 if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) { 180 pbuf_free(msg->msg.inp.p); 181 } 182 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 183 break; 184#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ 185 186#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 187 case TCPIP_MSG_TIMEOUT: 188 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 189 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 190 memp_free(MEMP_TCPIP_MSG_API, msg); 191 break; 192 case TCPIP_MSG_UNTIMEOUT: 193 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 194 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 195 memp_free(MEMP_TCPIP_MSG_API, msg); 196 break; 197#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 198 199 case TCPIP_MSG_CALLBACK: 200 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 201 msg->msg.cb.function(msg->msg.cb.ctx); 202 memp_free(MEMP_TCPIP_MSG_API, msg); 203 break; 204 205 case TCPIP_MSG_CALLBACK_STATIC: 206 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); 207 msg->msg.cb.function(msg->msg.cb.ctx); 208 break; 209#if LWIP_LOWPOWER 210 /* just wake up thread do nothing */ 211 case TCPIP_MSG_NA: 212 if (msg->msg.lowpower.type == LOW_BLOCK) { 213 LOWPOWER_SIGNAL(msg->msg.lowpower.wait_up); 214 } else { 215 memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); 216 } 217 sys_timeout_set_wake_time(LOW_TMR_DELAY); 218 break; 219#endif 220 default: 221 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 222 LWIP_ASSERT("tcpip_thread: invalid message", 0); 223 break; 224 } 225} 226 227#if LWIP_LOWPOWER 228/* send a na msg to wake up tcpip_thread */ 229void 230tcpip_send_msg_na(enum lowpower_msg_type type) 231{ 232 struct tcpip_msg *msg = NULL; 233 err_t val; 234 235 /* is not used lowpower mode */ 236 if ((type != LOW_FORCE_NON_BLOCK) && (get_lowpowper_mod() == LOW_TMR_NORMAL_MOD)) { 237 return; 238 } 239 if (sys_timeout_waiting_long() == 0) { 240 return; 241 } 242 243 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_LOWPOWER); 244 if (msg == NULL) { 245 LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na alloc faild\n")); 246 return; 247 } 248 249 /* just wake up thread if nonblock */ 250 msg->type = TCPIP_MSG_NA; 251 msg->msg.lowpower.type = type; 252 253 if (type == LOW_BLOCK) { 254 LOWPOWER_SEM_NEW(msg->msg.lowpower.wait_up, val); 255 if (val != ERR_OK) { 256 LWIP_DEBUGF(LOWPOWER_DEBUG, ("alloc sem faild\n")); 257 memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); 258 return; 259 } 260 } 261 262 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 263 if (type == LOW_BLOCK) { 264 LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); 265 } 266 memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); 267 LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na post faild\n")); 268 return; 269 } 270 271 if (type == LOW_BLOCK) { 272 LOWPOWER_SEM_WAIT(msg->msg.lowpower.wait_up); 273 LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up); 274 memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg); 275 } 276} 277#endif /* LWIP_LOWPOWER */ 278 279#ifdef TCPIP_THREAD_TEST 280/** Work on queued items in single-threaded test mode */ 281int 282tcpip_thread_poll_one(void) 283{ 284 int ret = 0; 285 struct tcpip_msg *msg; 286 287 if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_MBOX_EMPTY) { 288 LOCK_TCPIP_CORE(); 289 if (msg != NULL) { 290 tcpip_thread_handle_msg(msg); 291 ret = 1; 292 } 293 UNLOCK_TCPIP_CORE(); 294 } 295 return ret; 296} 297#endif 298 299/** 300 * Pass a received packet to tcpip_thread for input processing 301 * 302 * @param p the received packet 303 * @param inp the network interface on which the packet was received 304 * @param input_fn input function to call 305 */ 306err_t 307tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 308{ 309#if LWIP_TCPIP_CORE_LOCKING_INPUT 310 err_t ret; 311 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); 312#if LWIP_LOWPOWER 313 tcpip_send_msg_na(LOW_BLOCK); 314#endif 315 LOCK_TCPIP_CORE(); 316 ret = input_fn(p, inp); 317 UNLOCK_TCPIP_CORE(); 318 return ret; 319#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 320 struct tcpip_msg *msg; 321 322 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 323 324 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 325 if (msg == NULL) { 326 return ERR_MEM; 327 } 328 329 msg->type = TCPIP_MSG_INPKT; 330 msg->msg.inp.p = p; 331 msg->msg.inp.netif = inp; 332 msg->msg.inp.input_fn = input_fn; 333 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 334 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 335 return ERR_MEM; 336 } 337 return ERR_OK; 338#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 339} 340 341/** 342 * @ingroup lwip_os 343 * Pass a received packet to tcpip_thread for input processing with 344 * ethernet_input or ip_input. Don't call directly, pass to netif_add() 345 * and call netif->input(). 346 * 347 * @param p the received packet, p->payload pointing to the Ethernet header or 348 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 349 * NETIF_FLAG_ETHERNET flags) 350 * @param inp the network interface on which the packet was received 351 */ 352err_t 353tcpip_input(struct pbuf *p, struct netif *inp) 354{ 355#if LWIP_ETHERNET 356 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 357 return tcpip_inpkt(p, inp, ethernet_input); 358 } else 359#endif /* LWIP_ETHERNET */ 360 return tcpip_inpkt(p, inp, ip_input); 361} 362 363/** 364 * @ingroup lwip_os 365 * Call a specific function in the thread context of 366 * tcpip_thread for easy access synchronization. 367 * A function called in that way may access lwIP core code 368 * without fearing concurrent access. 369 * Blocks until the request is posted. 370 * Must not be called from interrupt context! 371 * 372 * @param function the function to call 373 * @param ctx parameter passed to f 374 * @return ERR_OK if the function was called, another err_t if not 375 * 376 * @see tcpip_try_callback 377 */ 378err_t 379tcpip_callback(tcpip_callback_fn function, void *ctx) 380{ 381 struct tcpip_msg *msg; 382 383 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 384 385 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 386 if (msg == NULL) { 387 return ERR_MEM; 388 } 389 390 msg->type = TCPIP_MSG_CALLBACK; 391 msg->msg.cb.function = function; 392 msg->msg.cb.ctx = ctx; 393 394 sys_mbox_post(&tcpip_mbox, msg); 395 return ERR_OK; 396} 397 398/** 399 * @ingroup lwip_os 400 * Call a specific function in the thread context of 401 * tcpip_thread for easy access synchronization. 402 * A function called in that way may access lwIP core code 403 * without fearing concurrent access. 404 * Does NOT block when the request cannot be posted because the 405 * tcpip_mbox is full, but returns ERR_MEM instead. 406 * Can be called from interrupt context. 407 * 408 * @param function the function to call 409 * @param ctx parameter passed to f 410 * @return ERR_OK if the function was called, another err_t if not 411 * 412 * @see tcpip_callback 413 */ 414err_t 415tcpip_try_callback(tcpip_callback_fn function, void *ctx) 416{ 417 struct tcpip_msg *msg; 418 419 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 420 421 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 422 if (msg == NULL) { 423 return ERR_MEM; 424 } 425 426 msg->type = TCPIP_MSG_CALLBACK; 427 msg->msg.cb.function = function; 428 msg->msg.cb.ctx = ctx; 429 430 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 431 memp_free(MEMP_TCPIP_MSG_API, msg); 432 return ERR_MEM; 433 } 434 return ERR_OK; 435} 436 437#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 438/** 439 * call sys_timeout in tcpip_thread 440 * 441 * @param msecs time in milliseconds for timeout 442 * @param h function to be called on timeout 443 * @param arg argument to pass to timeout function h 444 * @return ERR_MEM on memory error, ERR_OK otherwise 445 */ 446err_t 447tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 448{ 449 struct tcpip_msg *msg; 450 451 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 452 453 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 454 if (msg == NULL) { 455 return ERR_MEM; 456 } 457 458 msg->type = TCPIP_MSG_TIMEOUT; 459 msg->msg.tmo.msecs = msecs; 460 msg->msg.tmo.h = h; 461 msg->msg.tmo.arg = arg; 462 sys_mbox_post(&tcpip_mbox, msg); 463 return ERR_OK; 464} 465 466/** 467 * call sys_untimeout in tcpip_thread 468 * 469 * @param h function to be called on timeout 470 * @param arg argument to pass to timeout function h 471 * @return ERR_MEM on memory error, ERR_OK otherwise 472 */ 473err_t 474tcpip_untimeout(sys_timeout_handler h, void *arg) 475{ 476 struct tcpip_msg *msg; 477 478 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 479 480 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 481 if (msg == NULL) { 482 return ERR_MEM; 483 } 484 485 msg->type = TCPIP_MSG_UNTIMEOUT; 486 msg->msg.tmo.h = h; 487 msg->msg.tmo.arg = arg; 488 sys_mbox_post(&tcpip_mbox, msg); 489 return ERR_OK; 490} 491#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 492 493 494/** 495 * Sends a message to TCPIP thread to call a function. Caller thread blocks on 496 * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, 497 * this has to be done by the user. 498 * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way 499 * with least runtime overhead. 500 * 501 * @param fn function to be called from TCPIP thread 502 * @param apimsg argument to API function 503 * @param sem semaphore to wait on 504 * @return ERR_OK if the function was called, another err_t if not 505 */ 506err_t 507tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) 508{ 509#if LWIP_TCPIP_CORE_LOCKING 510 LWIP_UNUSED_ARG(sem); 511#if LWIP_LOWPOWER 512 tcpip_send_msg_na(LOW_BLOCK); 513#endif 514 LOCK_TCPIP_CORE(); 515 fn(apimsg); 516 UNLOCK_TCPIP_CORE(); 517 return ERR_OK; 518#else /* LWIP_TCPIP_CORE_LOCKING */ 519 TCPIP_MSG_VAR_DECLARE(msg); 520 521 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); 522 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 523 524 TCPIP_MSG_VAR_ALLOC(msg); 525 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; 526 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; 527 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; 528 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 529 sys_arch_sem_wait(sem, 0); 530 TCPIP_MSG_VAR_FREE(msg); 531 return ERR_OK; 532#endif /* LWIP_TCPIP_CORE_LOCKING */ 533} 534 535/** 536 * Synchronously calls function in TCPIP thread and waits for its completion. 537 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 538 * LWIP_NETCONN_SEM_PER_THREAD. 539 * If not, a semaphore is created and destroyed on every call which is usually 540 * an expensive/slow operation. 541 * @param fn Function to call 542 * @param call Call parameters 543 * @return Return value from tcpip_api_call_fn 544 */ 545err_t 546tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) 547{ 548#if LWIP_TCPIP_CORE_LOCKING 549 err_t err; 550#if LWIP_LOWPOWER 551 tcpip_send_msg_na(LOW_BLOCK); 552#endif 553 LOCK_TCPIP_CORE(); 554 err = fn(call); 555 UNLOCK_TCPIP_CORE(); 556 return err; 557#else /* LWIP_TCPIP_CORE_LOCKING */ 558 TCPIP_MSG_VAR_DECLARE(msg); 559 560#if !LWIP_NETCONN_SEM_PER_THREAD 561 err_t err = sys_sem_new(&call->sem, 0); 562 if (err != ERR_OK) { 563 return err; 564 } 565#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 566 567 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 568 569 TCPIP_MSG_VAR_ALLOC(msg); 570 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; 571 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; 572 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; 573#if LWIP_NETCONN_SEM_PER_THREAD 574 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); 575#else /* LWIP_NETCONN_SEM_PER_THREAD */ 576 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; 577#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 578 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 579 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); 580 TCPIP_MSG_VAR_FREE(msg); 581 582#if !LWIP_NETCONN_SEM_PER_THREAD 583 sys_sem_free(&call->sem); 584#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 585 586 return call->err; 587#endif /* LWIP_TCPIP_CORE_LOCKING */ 588} 589 590/** 591 * @ingroup lwip_os 592 * Allocate a structure for a static callback message and initialize it. 593 * The message has a special type such that lwIP never frees it. 594 * This is intended to be used to send "static" messages from interrupt context, 595 * e.g. the message is allocated once and posted several times from an IRQ 596 * using tcpip_callbackmsg_trycallback(). 597 * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context. 598 * 599 * @param function the function to call 600 * @param ctx parameter passed to function 601 * @return a struct pointer to pass to tcpip_callbackmsg_trycallback(). 602 * 603 * @see tcpip_callbackmsg_trycallback() 604 * @see tcpip_callbackmsg_delete() 605 */ 606struct tcpip_callback_msg * 607tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 608{ 609 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 610 if (msg == NULL) { 611 return NULL; 612 } 613 msg->type = TCPIP_MSG_CALLBACK_STATIC; 614 msg->msg.cb.function = function; 615 msg->msg.cb.ctx = ctx; 616 return (struct tcpip_callback_msg *)msg; 617} 618 619/** 620 * @ingroup lwip_os 621 * Free a callback message allocated by tcpip_callbackmsg_new(). 622 * 623 * @param msg the message to free 624 * 625 * @see tcpip_callbackmsg_new() 626 */ 627void 628tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg) 629{ 630 memp_free(MEMP_TCPIP_MSG_API, msg); 631} 632 633/** 634 * @ingroup lwip_os 635 * Try to post a callback-message to the tcpip_thread tcpip_mbox. 636 * 637 * @param msg pointer to the message to post 638 * @return sys_mbox_trypost() return code 639 * 640 * @see tcpip_callbackmsg_new() 641 */ 642err_t 643tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg) 644{ 645 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 646 return sys_mbox_trypost(&tcpip_mbox, msg); 647} 648 649/** 650 * @ingroup lwip_os 651 * Try to post a callback-message to the tcpip_thread mbox. 652 * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(), 653 * mainly to help FreeRTOS, where calls differ between task level and ISR level. 654 * 655 * @param msg pointer to the message to post 656 * @return sys_mbox_trypost_fromisr() return code (without change, so this 657 * knowledge can be used to e.g. propagate "bool needs_scheduling") 658 * 659 * @see tcpip_callbackmsg_new() 660 */ 661err_t 662tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg) 663{ 664 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 665 return sys_mbox_trypost_fromisr(&tcpip_mbox, msg); 666} 667 668/** 669 * @ingroup lwip_os 670 * Initialize this module: 671 * - initialize all sub modules 672 * - start the tcpip_thread 673 * 674 * @param initfunc a function to call when tcpip_thread is running and finished initializing 675 * @param arg argument to pass to initfunc 676 */ 677void 678tcpip_init(tcpip_init_done_fn initfunc, void *arg) 679{ 680 lwip_init(); 681 682 tcpip_init_done = initfunc; 683 tcpip_init_done_arg = arg; 684 if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 685 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 686 } 687#if LWIP_TCPIP_CORE_LOCKING 688 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 689 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 690 } 691#endif /* LWIP_TCPIP_CORE_LOCKING */ 692 693 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 694} 695 696/** 697 * Simple callback function used with tcpip_callback to free a pbuf 698 * (pbuf_free has a wrong signature for tcpip_callback) 699 * 700 * @param p The pbuf (chain) to be dereferenced. 701 */ 702static void 703pbuf_free_int(void *p) 704{ 705 struct pbuf *q = (struct pbuf *)p; 706 pbuf_free(q); 707} 708 709/** 710 * A simple wrapper function that allows you to free a pbuf from interrupt context. 711 * 712 * @param p The pbuf (chain) to be dereferenced. 713 * @return ERR_OK if callback could be enqueued, an err_t if not 714 */ 715err_t 716pbuf_free_callback(struct pbuf *p) 717{ 718 return tcpip_try_callback(pbuf_free_int, p); 719} 720 721/** 722 * A simple wrapper function that allows you to free heap memory from 723 * interrupt context. 724 * 725 * @param m the heap memory to free 726 * @return ERR_OK if callback could be enqueued, an err_t if not 727 */ 728err_t 729mem_free_callback(void *m) 730{ 731 return tcpip_try_callback(mem_free, m); 732} 733 734#endif /* !NO_SYS */ 735