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 <[email protected]> 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/sys.h" 44 #include "lwip/memp.h" 45 #include "lwip/mem.h" 46 #include "lwip/pbuf.h" 47 #include "lwip/tcpip.h" 48 #include "lwip/init.h" 49 #include "netif/etharp.h" 50 #include "netif/ppp_oe.h" 51 52 /* global variables */ 53 static tcpip_init_done_fn tcpip_init_done; 54 static void *tcpip_init_done_arg; 55 static sys_mbox_t mbox; 56 57 #if LWIP_TCPIP_CORE_LOCKING 58 /** The global semaphore to lock the stack. */ 59 sys_mutex_t lock_tcpip_core; 60 #endif /* LWIP_TCPIP_CORE_LOCKING */ 61 62 63 /** 64 * The main lwIP thread. This thread has exclusive access to lwIP core functions 65 * (unless access to them is not locked). Other threads communicate with this 66 * thread using message boxes. 67 * 68 * It also starts all the timers to make sure they are running in the right 69 * thread context. 70 * 71 * @param arg unused argument 72 */ 73 static void 74 tcpip_thread(void *arg) 75 { 76 struct tcpip_msg *msg; 77 LWIP_UNUSED_ARG(arg); 78 79 if (tcpip_init_done != NULL) { 80 tcpip_init_done(tcpip_init_done_arg); 81 } 82 83 LOCK_TCPIP_CORE(); 84 while (1) { /* MAIN Loop */ 85 UNLOCK_TCPIP_CORE(); 86 LWIP_TCPIP_THREAD_ALIVE(); 87 /* wait for a message, timeouts are processed while waiting */ 88 sys_timeouts_mbox_fetch(&mbox, (void **)&msg); 89 LOCK_TCPIP_CORE(); 90 switch (msg->type) { 91 #if LWIP_NETCONN 92 case TCPIP_MSG_API: 93 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 94 msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); 95 break; 96 #endif /* LWIP_NETCONN */ 97 98 #if !LWIP_TCPIP_CORE_LOCKING_INPUT 99 case TCPIP_MSG_INPKT: 100 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 101 #if LWIP_ETHERNET 102 if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 103 ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); 104 } else 105 #endif /* LWIP_ETHERNET */ 106 { 107 ip_input(msg->msg.inp.p, msg->msg.inp.netif); 108 } 109 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 110 break; 111 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 112 113 #if LWIP_NETIF_API 114 case TCPIP_MSG_NETIFAPI: 115 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); 116 msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); 117 break; 118 #endif /* LWIP_NETIF_API */ 119 120 #if LWIP_TCPIP_TIMEOUT 121 case TCPIP_MSG_TIMEOUT: 122 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 123 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 124 memp_free(MEMP_TCPIP_MSG_API, msg); 125 break; 126 case TCPIP_MSG_UNTIMEOUT: 127 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 128 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 129 memp_free(MEMP_TCPIP_MSG_API, msg); 130 break; 131 #endif /* LWIP_TCPIP_TIMEOUT */ 132 133 case TCPIP_MSG_CALLBACK: 134 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 135 msg->msg.cb.function(msg->msg.cb.ctx); 136 memp_free(MEMP_TCPIP_MSG_API, msg); 137 break; 138 139 case TCPIP_MSG_CALLBACK_STATIC: 140 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); 141 msg->msg.cb.function(msg->msg.cb.ctx); 142 break; 143 144 default: 145 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 146 LWIP_ASSERT("tcpip_thread: invalid message", 0); 147 break; 148 } 149 } 150 } 151 152 /** 153 * Pass a received packet to tcpip_thread for input processing 154 * 155 * @param p the received packet, p->payload pointing to the Ethernet header or 156 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 157 * NETIF_FLAG_ETHERNET flags) 158 * @param inp the network interface on which the packet was received 159 */ 160 err_t 161 tcpip_input(struct pbuf *p, struct netif *inp) 162 { 163 #if LWIP_TCPIP_CORE_LOCKING_INPUT 164 err_t ret; 165 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); 166 LOCK_TCPIP_CORE(); 167 #if LWIP_ETHERNET 168 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 169 ret = ethernet_input(p, inp); 170 } else 171 #endif /* LWIP_ETHERNET */ 172 { 173 ret = ip_input(p, inp); 174 } 175 UNLOCK_TCPIP_CORE(); 176 return ret; 177 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 178 struct tcpip_msg *msg; 179 180 if (!sys_mbox_valid(&mbox)) { 181 return ERR_VAL; 182 } 183 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 184 if (msg == NULL) { 185 return ERR_MEM; 186 } 187 188 msg->type = TCPIP_MSG_INPKT; 189 msg->msg.inp.p = p; 190 msg->msg.inp.netif = inp; 191 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 192 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 193 return ERR_MEM; 194 } 195 return ERR_OK; 196 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 197 } 198 199 /** 200 * Call a specific function in the thread context of 201 * tcpip_thread for easy access synchronization. 202 * A function called in that way may access lwIP core code 203 * without fearing concurrent access. 204 * 205 * @param f the function to call 206 * @param ctx parameter passed to f 207 * @param block 1 to block until the request is posted, 0 to non-blocking mode 208 * @return ERR_OK if the function was called, another err_t if not 209 */ 210 err_t 211 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) 212 { 213 struct tcpip_msg *msg; 214 215 if (sys_mbox_valid(&mbox)) { 216 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 217 if (msg == NULL) { 218 return ERR_MEM; 219 } 220 221 msg->type = TCPIP_MSG_CALLBACK; 222 msg->msg.cb.function = function; 223 msg->msg.cb.ctx = ctx; 224 if (block) { 225 sys_mbox_post(&mbox, msg); 226 } else { 227 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 228 memp_free(MEMP_TCPIP_MSG_API, msg); 229 return ERR_MEM; 230 } 231 } 232 return ERR_OK; 233 } 234 return ERR_VAL; 235 } 236 237 #if LWIP_TCPIP_TIMEOUT 238 /** 239 * call sys_timeout in tcpip_thread 240 * 241 * @param msec time in milliseconds for timeout 242 * @param h function to be called on timeout 243 * @param arg argument to pass to timeout function h 244 * @return ERR_MEM on memory error, ERR_OK otherwise 245 */ 246 err_t 247 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 248 { 249 struct tcpip_msg *msg; 250 251 if (sys_mbox_valid(&mbox)) { 252 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 253 if (msg == NULL) { 254 return ERR_MEM; 255 } 256 257 msg->type = TCPIP_MSG_TIMEOUT; 258 msg->msg.tmo.msecs = msecs; 259 msg->msg.tmo.h = h; 260 msg->msg.tmo.arg = arg; 261 sys_mbox_post(&mbox, msg); 262 return ERR_OK; 263 } 264 return ERR_VAL; 265 } 266 267 /** 268 * call sys_untimeout in tcpip_thread 269 * 270 * @param msec time in milliseconds for timeout 271 * @param h function to be called on timeout 272 * @param arg argument to pass to timeout function h 273 * @return ERR_MEM on memory error, ERR_OK otherwise 274 */ 275 err_t 276 tcpip_untimeout(sys_timeout_handler h, void *arg) 277 { 278 struct tcpip_msg *msg; 279 280 if (sys_mbox_valid(&mbox)) { 281 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 282 if (msg == NULL) { 283 return ERR_MEM; 284 } 285 286 msg->type = TCPIP_MSG_UNTIMEOUT; 287 msg->msg.tmo.h = h; 288 msg->msg.tmo.arg = arg; 289 sys_mbox_post(&mbox, msg); 290 return ERR_OK; 291 } 292 return ERR_VAL; 293 } 294 #endif /* LWIP_TCPIP_TIMEOUT */ 295 296 #if LWIP_NETCONN 297 /** 298 * Call the lower part of a netconn_* function 299 * This function is then running in the thread context 300 * of tcpip_thread and has exclusive access to lwIP core code. 301 * 302 * @param apimsg a struct containing the function to call and its parameters 303 * @return ERR_OK if the function was called, another err_t if not 304 */ 305 err_t 306 tcpip_apimsg(struct api_msg *apimsg) 307 { 308 struct tcpip_msg msg; 309 #ifdef LWIP_DEBUG 310 /* catch functions that don't set err */ 311 apimsg->msg.err = ERR_VAL; 312 #endif 313 314 if (sys_mbox_valid(&mbox)) { 315 msg.type = TCPIP_MSG_API; 316 msg.msg.apimsg = apimsg; 317 sys_mbox_post(&mbox, &msg); 318 sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); 319 return apimsg->msg.err; 320 } 321 return ERR_VAL; 322 } 323 324 #if LWIP_TCPIP_CORE_LOCKING 325 /** 326 * Call the lower part of a netconn_* function 327 * This function has exclusive access to lwIP core code by locking it 328 * before the function is called. 329 * 330 * @param apimsg a struct containing the function to call and its parameters 331 * @return ERR_OK (only for compatibility fo tcpip_apimsg()) 332 */ 333 err_t 334 tcpip_apimsg_lock(struct api_msg *apimsg) 335 { 336 #ifdef LWIP_DEBUG 337 /* catch functions that don't set err */ 338 apimsg->msg.err = ERR_VAL; 339 #endif 340 341 LOCK_TCPIP_CORE(); 342 apimsg->function(&(apimsg->msg)); 343 UNLOCK_TCPIP_CORE(); 344 return apimsg->msg.err; 345 346 } 347 #endif /* LWIP_TCPIP_CORE_LOCKING */ 348 #endif /* LWIP_NETCONN */ 349 350 #if LWIP_NETIF_API 351 #if !LWIP_TCPIP_CORE_LOCKING 352 /** 353 * Much like tcpip_apimsg, but calls the lower part of a netifapi_* 354 * function. 355 * 356 * @param netifapimsg a struct containing the function to call and its parameters 357 * @return error code given back by the function that was called 358 */ 359 err_t 360 tcpip_netifapi(struct netifapi_msg* netifapimsg) 361 { 362 struct tcpip_msg msg; 363 364 if (sys_mbox_valid(&mbox)) { 365 err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); 366 if (err != ERR_OK) { 367 netifapimsg->msg.err = err; 368 return err; 369 } 370 371 msg.type = TCPIP_MSG_NETIFAPI; 372 msg.msg.netifapimsg = netifapimsg; 373 sys_mbox_post(&mbox, &msg); 374 sys_sem_wait(&netifapimsg->msg.sem); 375 sys_sem_free(&netifapimsg->msg.sem); 376 return netifapimsg->msg.err; 377 } 378 return ERR_VAL; 379 } 380 #else /* !LWIP_TCPIP_CORE_LOCKING */ 381 /** 382 * Call the lower part of a netifapi_* function 383 * This function has exclusive access to lwIP core code by locking it 384 * before the function is called. 385 * 386 * @param netifapimsg a struct containing the function to call and its parameters 387 * @return ERR_OK (only for compatibility fo tcpip_netifapi()) 388 */ 389 err_t 390 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) 391 { 392 LOCK_TCPIP_CORE(); 393 netifapimsg->function(&(netifapimsg->msg)); 394 UNLOCK_TCPIP_CORE(); 395 return netifapimsg->msg.err; 396 } 397 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 398 #endif /* LWIP_NETIF_API */ 399 400 /** 401 * Allocate a structure for a static callback message and initialize it. 402 * This is intended to be used to send "static" messages from interrupt context. 403 * 404 * @param function the function to call 405 * @param ctx parameter passed to function 406 * @return a struct pointer to pass to tcpip_trycallback(). 407 */ 408 struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 409 { 410 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 411 if (msg == NULL) { 412 return NULL; 413 } 414 msg->type = TCPIP_MSG_CALLBACK_STATIC; 415 msg->msg.cb.function = function; 416 msg->msg.cb.ctx = ctx; 417 return (struct tcpip_callback_msg*)msg; 418 } 419 420 /** 421 * Free a callback message allocated by tcpip_callbackmsg_new(). 422 * 423 * @param msg the message to free 424 */ 425 void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) 426 { 427 memp_free(MEMP_TCPIP_MSG_API, msg); 428 } 429 430 /** 431 * Try to post a callback-message to the tcpip_thread mbox 432 * This is intended to be used to send "static" messages from interrupt context. 433 * 434 * @param msg pointer to the message to post 435 * @return sys_mbox_trypost() return code 436 */ 437 err_t 438 tcpip_trycallback(struct tcpip_callback_msg* msg) 439 { 440 if (!sys_mbox_valid(&mbox)) { 441 return ERR_VAL; 442 } 443 return sys_mbox_trypost(&mbox, msg); 444 } 445 446 /** 447 * Initialize this module: 448 * - initialize all sub modules 449 * - start the tcpip_thread 450 * 451 * @param initfunc a function to call when tcpip_thread is running and finished initializing 452 * @param arg argument to pass to initfunc 453 */ 454 void 455 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 456 { 457 lwip_init(); 458 459 tcpip_init_done = initfunc; 460 tcpip_init_done_arg = arg; 461 if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 462 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 463 } 464 #if LWIP_TCPIP_CORE_LOCKING 465 if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 466 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 467 } 468 #endif /* LWIP_TCPIP_CORE_LOCKING */ 469 470 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 471 } 472 473 /** 474 * Simple callback function used with tcpip_callback to free a pbuf 475 * (pbuf_free has a wrong signature for tcpip_callback) 476 * 477 * @param p The pbuf (chain) to be dereferenced. 478 */ 479 static void 480 pbuf_free_int(void *p) 481 { 482 struct pbuf *q = (struct pbuf *)p; 483 pbuf_free(q); 484 } 485 486 /** 487 * A simple wrapper function that allows you to free a pbuf from interrupt context. 488 * 489 * @param p The pbuf (chain) to be dereferenced. 490 * @return ERR_OK if callback could be enqueued, an err_t if not 491 */ 492 err_t 493 pbuf_free_callback(struct pbuf *p) 494 { 495 return tcpip_callback_with_block(pbuf_free_int, p, 0); 496 } 497 498 /** 499 * A simple wrapper function that allows you to free heap memory from 500 * interrupt context. 501 * 502 * @param m the heap memory to free 503 * @return ERR_OK if callback could be enqueued, an err_t if not 504 */ 505 err_t 506 mem_free_callback(void *m) 507 { 508 return tcpip_callback_with_block(mem_free, m, 0); 509 } 510 511 #endif /* !NO_SYS */ 512