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