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 */ 59 static tcpip_init_done_fn tcpip_init_done; 60 static void *tcpip_init_done_arg; 61 static sys_mbox_t tcpip_mbox; 62 63 #if LWIP_TCPIP_CORE_LOCKING 64 /** The global semaphore to lock the stack. */ 65 sys_mutex_t lock_tcpip_core; 66 #endif /* LWIP_TCPIP_CORE_LOCKING */ 67 68 static 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 */ 83 static void 84 tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 85 { 86 u32_t sleeptime, res; 87 88 again: 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 */ 126 static void 127 tcpip_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 */ 155 static void 156 tcpip_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 case TCPIP_MSG_CALLBACK_STATIC_WAIT: 170 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK WAIT message %p\n", (void *)msg)); 171 msg->msg.cb_wait.function(msg->msg.cb_wait.ctx); 172 sys_sem_signal(msg->msg.cb_wait.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 210 default: 211 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 212 LWIP_ASSERT("tcpip_thread: invalid message", 0); 213 break; 214 } 215 } 216 217 #ifdef TCPIP_THREAD_TEST 218 /** Work on queued items in single-threaded test mode */ 219 int 220 tcpip_thread_poll_one(void) 221 { 222 int ret = 0; 223 struct tcpip_msg *msg; 224 225 if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_MBOX_EMPTY) { 226 LOCK_TCPIP_CORE(); 227 if (msg != NULL) { 228 tcpip_thread_handle_msg(msg); 229 ret = 1; 230 } 231 UNLOCK_TCPIP_CORE(); 232 } 233 return ret; 234 } 235 #endif 236 237 /** 238 * Pass a received packet to tcpip_thread for input processing 239 * 240 * @param p the received packet 241 * @param inp the network interface on which the packet was received 242 * @param input_fn input function to call 243 */ 244 err_t 245 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 246 { 247 #if LWIP_TCPIP_CORE_LOCKING_INPUT 248 err_t ret; 249 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); 250 LOCK_TCPIP_CORE(); 251 ret = input_fn(p, inp); 252 UNLOCK_TCPIP_CORE(); 253 return ret; 254 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 255 struct tcpip_msg *msg; 256 257 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 258 259 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 260 if (msg == NULL) { 261 return ERR_MEM; 262 } 263 264 msg->type = TCPIP_MSG_INPKT; 265 msg->msg.inp.p = p; 266 msg->msg.inp.netif = inp; 267 msg->msg.inp.input_fn = input_fn; 268 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 269 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 270 return ERR_MEM; 271 } 272 return ERR_OK; 273 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 274 } 275 276 /** 277 * @ingroup lwip_os 278 * Pass a received packet to tcpip_thread for input processing with 279 * ethernet_input or ip_input. Don't call directly, pass to netif_add() 280 * and call netif->input(). 281 * 282 * @param p the received packet, p->payload pointing to the Ethernet header or 283 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 284 * NETIF_FLAG_ETHERNET flags) 285 * @param inp the network interface on which the packet was received 286 */ 287 err_t 288 tcpip_input(struct pbuf *p, struct netif *inp) 289 { 290 #if LWIP_ETHERNET 291 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 292 return tcpip_inpkt(p, inp, ethernet_input); 293 } else 294 #endif /* LWIP_ETHERNET */ 295 return tcpip_inpkt(p, inp, ip_input); 296 } 297 298 /** 299 * @ingroup lwip_os 300 * Call a specific function in the thread context of 301 * tcpip_thread for easy access synchronization. 302 * A function called in that way may access lwIP core code 303 * without fearing concurrent access. 304 * Blocks until the request is posted. 305 * Must not be called from interrupt context! 306 * 307 * @param function the function to call 308 * @param ctx parameter passed to f 309 * @return ERR_OK if the function was called, another err_t if not 310 * 311 * @see tcpip_try_callback 312 */ 313 err_t 314 tcpip_callback(tcpip_callback_fn function, void *ctx) 315 { 316 struct tcpip_msg *msg; 317 318 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 319 320 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 321 if (msg == NULL) { 322 return ERR_MEM; 323 } 324 325 msg->type = TCPIP_MSG_CALLBACK; 326 msg->msg.cb.function = function; 327 msg->msg.cb.ctx = ctx; 328 329 sys_mbox_post(&tcpip_mbox, msg); 330 return ERR_OK; 331 } 332 333 /** 334 * @ingroup lwip_os 335 * Call a specific function in the thread context of 336 * tcpip_thread for easy access synchronization. 337 * A function called in that way may access lwIP core code 338 * without fearing concurrent access. 339 * Does NOT block when the request cannot be posted because the 340 * tcpip_mbox is full, but returns ERR_MEM instead. 341 * Can be called from interrupt context. 342 * 343 * @param function the function to call 344 * @param ctx parameter passed to f 345 * @return ERR_OK if the function was called, another err_t if not 346 * 347 * @see tcpip_callback 348 */ 349 err_t 350 tcpip_try_callback(tcpip_callback_fn function, void *ctx) 351 { 352 struct tcpip_msg *msg; 353 354 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 355 356 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 357 if (msg == NULL) { 358 return ERR_MEM; 359 } 360 361 msg->type = TCPIP_MSG_CALLBACK; 362 msg->msg.cb.function = function; 363 msg->msg.cb.ctx = ctx; 364 365 if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) { 366 memp_free(MEMP_TCPIP_MSG_API, msg); 367 return ERR_MEM; 368 } 369 return ERR_OK; 370 } 371 372 #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 373 /** 374 * call sys_timeout in tcpip_thread 375 * 376 * @param msecs time in milliseconds for timeout 377 * @param h function to be called on timeout 378 * @param arg argument to pass to timeout function h 379 * @return ERR_MEM on memory error, ERR_OK otherwise 380 */ 381 err_t 382 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 383 { 384 struct tcpip_msg *msg; 385 386 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 387 388 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 389 if (msg == NULL) { 390 return ERR_MEM; 391 } 392 393 msg->type = TCPIP_MSG_TIMEOUT; 394 msg->msg.tmo.msecs = msecs; 395 msg->msg.tmo.h = h; 396 msg->msg.tmo.arg = arg; 397 sys_mbox_post(&tcpip_mbox, msg); 398 return ERR_OK; 399 } 400 401 /** 402 * call sys_untimeout in tcpip_thread 403 * 404 * @param h function to be called on timeout 405 * @param arg argument to pass to timeout function h 406 * @return ERR_MEM on memory error, ERR_OK otherwise 407 */ 408 err_t 409 tcpip_untimeout(sys_timeout_handler h, void *arg) 410 { 411 struct tcpip_msg *msg; 412 413 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 414 415 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 416 if (msg == NULL) { 417 return ERR_MEM; 418 } 419 420 msg->type = TCPIP_MSG_UNTIMEOUT; 421 msg->msg.tmo.h = h; 422 msg->msg.tmo.arg = arg; 423 sys_mbox_post(&tcpip_mbox, msg); 424 return ERR_OK; 425 } 426 #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 427 428 429 /** 430 * Sends a message to TCPIP thread to call a function. Caller thread blocks on 431 * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, 432 * this has to be done by the user. 433 * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way 434 * with least runtime overhead. 435 * 436 * @param fn function to be called from TCPIP thread 437 * @param apimsg argument to API function 438 * @param sem semaphore to wait on 439 * @return ERR_OK if the function was called, another err_t if not 440 */ 441 err_t 442 tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem) 443 { 444 #if LWIP_TCPIP_CORE_LOCKING 445 LWIP_UNUSED_ARG(sem); 446 LOCK_TCPIP_CORE(); 447 fn(apimsg); 448 UNLOCK_TCPIP_CORE(); 449 return ERR_OK; 450 #else /* LWIP_TCPIP_CORE_LOCKING */ 451 TCPIP_MSG_VAR_DECLARE(msg); 452 453 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); 454 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 455 456 TCPIP_MSG_VAR_ALLOC(msg); 457 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; 458 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; 459 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; 460 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 461 sys_arch_sem_wait(sem, 0); 462 TCPIP_MSG_VAR_FREE(msg); 463 return ERR_OK; 464 #endif /* LWIP_TCPIP_CORE_LOCKING */ 465 } 466 467 /** 468 * Synchronously calls function in TCPIP thread and waits for its completion. 469 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 470 * LWIP_NETCONN_SEM_PER_THREAD. 471 * If not, a semaphore is created and destroyed on every call which is usually 472 * an expensive/slow operation. 473 * @param fn Function to call 474 * @param call Call parameters 475 * @return Return value from tcpip_api_call_fn 476 */ 477 err_t 478 tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) 479 { 480 #if LWIP_TCPIP_CORE_LOCKING 481 err_t err; 482 LOCK_TCPIP_CORE(); 483 err = fn(call); 484 UNLOCK_TCPIP_CORE(); 485 return err; 486 #else /* LWIP_TCPIP_CORE_LOCKING */ 487 TCPIP_MSG_VAR_DECLARE(msg); 488 489 #if !LWIP_NETCONN_SEM_PER_THREAD 490 err_t err = sys_sem_new(&call->sem, 0); 491 if (err != ERR_OK) { 492 return err; 493 } 494 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 495 496 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 497 498 TCPIP_MSG_VAR_ALLOC(msg); 499 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; 500 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; 501 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; 502 #if LWIP_NETCONN_SEM_PER_THREAD 503 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); 504 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 505 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; 506 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 507 sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg)); 508 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); 509 TCPIP_MSG_VAR_FREE(msg); 510 511 #if !LWIP_NETCONN_SEM_PER_THREAD 512 sys_sem_free(&call->sem); 513 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 514 515 return call->err; 516 #endif /* LWIP_TCPIP_CORE_LOCKING */ 517 } 518 519 /** 520 * @ingroup lwip_os 521 * Allocate a structure for a static callback message and initialize it. 522 * The message has a special type such that lwIP never frees it. 523 * This is intended to be used to send "static" messages from interrupt context, 524 * e.g. the message is allocated once and posted several times from an IRQ 525 * using tcpip_callbackmsg_trycallback(). 526 * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context. 527 * 528 * @param function the function to call 529 * @param ctx parameter passed to function 530 * @return a struct pointer to pass to tcpip_callbackmsg_trycallback(). 531 * 532 * @see tcpip_callbackmsg_trycallback() 533 * @see tcpip_callbackmsg_delete() 534 */ 535 struct tcpip_callback_msg * 536 tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 537 { 538 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 539 if (msg == NULL) { 540 return NULL; 541 } 542 msg->type = TCPIP_MSG_CALLBACK_STATIC; 543 msg->msg.cb.function = function; 544 msg->msg.cb.ctx = ctx; 545 return (struct tcpip_callback_msg *)msg; 546 } 547 548 /** 549 * @ingroup lwip_os 550 * Free a callback message allocated by tcpip_callbackmsg_new(). 551 * 552 * @param msg the message to free 553 * 554 * @see tcpip_callbackmsg_new() 555 */ 556 void 557 tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg) 558 { 559 memp_free(MEMP_TCPIP_MSG_API, msg); 560 } 561 562 /** 563 * @ingroup lwip_os 564 * Try to post a callback-message to the tcpip_thread tcpip_mbox. 565 * 566 * @param msg pointer to the message to post 567 * @return sys_mbox_trypost() return code 568 * 569 * @see tcpip_callbackmsg_new() 570 */ 571 err_t 572 tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg) 573 { 574 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 575 return sys_mbox_trypost(&tcpip_mbox, msg); 576 } 577 578 /** 579 * @ingroup lwip_os 580 * Try to post a callback-message to the tcpip_thread mbox. 581 * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(), 582 * mainly to help FreeRTOS, where calls differ between task level and ISR level. 583 * 584 * @param msg pointer to the message to post 585 * @return sys_mbox_trypost_fromisr() return code (without change, so this 586 * knowledge can be used to e.g. propagate "bool needs_scheduling") 587 * 588 * @see tcpip_callbackmsg_new() 589 */ 590 err_t 591 tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg) 592 { 593 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 594 return sys_mbox_trypost_fromisr(&tcpip_mbox, msg); 595 } 596 597 /** 598 * Sends a message to TCPIP thread to call a function. Caller thread blocks 599 * until the function returns. 600 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 601 * LWIP_NETCONN_SEM_PER_THREAD. 602 * If not, a semaphore is created and destroyed on every call which is usually 603 * an expensive/slow operation. 604 * 605 * @param function the function to call 606 * @param ctx parameter passed to f 607 * @return ERR_OK if the function was called, another err_t if not 608 */ 609 err_t 610 tcpip_callback_wait(tcpip_callback_fn function, void *ctx) 611 { 612 #if LWIP_TCPIP_CORE_LOCKING 613 LOCK_TCPIP_CORE(); 614 function(ctx); 615 UNLOCK_TCPIP_CORE(); 616 return ERR_OK; 617 #else /* LWIP_TCPIP_CORE_LOCKING */ 618 err_t err; 619 sys_sem_t sem; 620 struct tcpip_msg msg; 621 622 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox)); 623 624 err = sys_sem_new(&sem, 0); 625 if (err != ERR_OK) { 626 return err; 627 } 628 629 msg.type = TCPIP_MSG_CALLBACK_STATIC_WAIT; 630 msg.msg.cb_wait.function = function; 631 msg.msg.cb_wait.ctx = ctx; 632 msg.msg.cb_wait.sem = &sem; 633 sys_mbox_post(&tcpip_mbox, &msg); 634 sys_arch_sem_wait(&sem, 0); 635 sys_sem_free(&sem); 636 return ERR_OK; 637 #endif /* LWIP_TCPIP_CORE_LOCKING */ 638 } 639 640 /** 641 * @ingroup lwip_os 642 * Initialize this module: 643 * - initialize all sub modules 644 * - start the tcpip_thread 645 * 646 * @param initfunc a function to call when tcpip_thread is running and finished initializing 647 * @param arg argument to pass to initfunc 648 */ 649 void 650 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 651 { 652 lwip_init(); 653 654 tcpip_init_done = initfunc; 655 tcpip_init_done_arg = arg; 656 if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 657 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 658 } 659 #if LWIP_TCPIP_CORE_LOCKING 660 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 661 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 662 } 663 #endif /* LWIP_TCPIP_CORE_LOCKING */ 664 665 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 666 } 667 668 /** 669 * Simple callback function used with tcpip_callback to free a pbuf 670 * (pbuf_free has a wrong signature for tcpip_callback) 671 * 672 * @param p The pbuf (chain) to be dereferenced. 673 */ 674 static void 675 pbuf_free_int(void *p) 676 { 677 struct pbuf *q = (struct pbuf *)p; 678 pbuf_free(q); 679 } 680 681 /** 682 * A simple wrapper function that allows you to free a pbuf from interrupt context. 683 * 684 * @param p The pbuf (chain) to be dereferenced. 685 * @return ERR_OK if callback could be enqueued, an err_t if not 686 */ 687 err_t 688 pbuf_free_callback(struct pbuf *p) 689 { 690 return tcpip_try_callback(pbuf_free_int, p); 691 } 692 693 /** 694 * A simple wrapper function that allows you to free heap memory from 695 * interrupt context. 696 * 697 * @param m the heap memory to free 698 * @return ERR_OK if callback could be enqueued, an err_t if not 699 */ 700 err_t 701 mem_free_callback(void *m) 702 { 703 return tcpip_try_callback(mem_free, m); 704 } 705 706 #endif /* !NO_SYS */ 707