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