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 (at) 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 "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 case TCPIP_MSG_CALLBACK: 121 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 122 msg->msg.cb.function(msg->msg.cb.ctx); 123 memp_free(MEMP_TCPIP_MSG_API, msg); 124 break; 125 126 #if LWIP_TCPIP_TIMEOUT 127 case TCPIP_MSG_TIMEOUT: 128 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 129 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 130 memp_free(MEMP_TCPIP_MSG_API, msg); 131 break; 132 case TCPIP_MSG_UNTIMEOUT: 133 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 134 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 135 memp_free(MEMP_TCPIP_MSG_API, msg); 136 break; 137 #endif /* LWIP_TCPIP_TIMEOUT */ 138 139 default: 140 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 141 LWIP_ASSERT("tcpip_thread: invalid message", 0); 142 break; 143 } 144 } 145 } 146 147 /** 148 * Pass a received packet to tcpip_thread for input processing 149 * 150 * @param p the received packet, p->payload pointing to the Ethernet header or 151 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 152 * NETIF_FLAG_ETHERNET flags) 153 * @param inp the network interface on which the packet was received 154 */ 155 err_t 156 tcpip_input(struct pbuf *p, struct netif *inp) 157 { 158 #if LWIP_TCPIP_CORE_LOCKING_INPUT 159 err_t ret; 160 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); 161 LOCK_TCPIP_CORE(); 162 #if LWIP_ETHERNET 163 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 164 ret = ethernet_input(p, inp); 165 } else 166 #endif /* LWIP_ETHERNET */ 167 { 168 ret = ip_input(p, inp); 169 } 170 UNLOCK_TCPIP_CORE(); 171 return ret; 172 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 173 struct tcpip_msg *msg; 174 175 if (sys_mbox_valid(&mbox)) { 176 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 177 if (msg == NULL) { 178 return ERR_MEM; 179 } 180 181 msg->type = TCPIP_MSG_INPKT; 182 msg->msg.inp.p = p; 183 msg->msg.inp.netif = inp; 184 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 185 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 186 return ERR_MEM; 187 } 188 return ERR_OK; 189 } 190 return ERR_VAL; 191 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 192 } 193 194 /** 195 * Call a specific function in the thread context of 196 * tcpip_thread for easy access synchronization. 197 * A function called in that way may access lwIP core code 198 * without fearing concurrent access. 199 * 200 * @param f the function to call 201 * @param ctx parameter passed to f 202 * @param block 1 to block until the request is posted, 0 to non-blocking mode 203 * @return ERR_OK if the function was called, another err_t if not 204 */ 205 err_t 206 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) 207 { 208 struct tcpip_msg *msg; 209 210 if (sys_mbox_valid(&mbox)) { 211 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 212 if (msg == NULL) { 213 return ERR_MEM; 214 } 215 216 msg->type = TCPIP_MSG_CALLBACK; 217 msg->msg.cb.function = function; 218 msg->msg.cb.ctx = ctx; 219 if (block) { 220 sys_mbox_post(&mbox, msg); 221 } else { 222 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 223 memp_free(MEMP_TCPIP_MSG_API, msg); 224 return ERR_MEM; 225 } 226 } 227 return ERR_OK; 228 } 229 return ERR_VAL; 230 } 231 232 #if LWIP_TCPIP_TIMEOUT 233 /** 234 * call sys_timeout in tcpip_thread 235 * 236 * @param msec time in milliseconds for timeout 237 * @param h function to be called on timeout 238 * @param arg argument to pass to timeout function h 239 * @return ERR_MEM on memory error, ERR_OK otherwise 240 */ 241 err_t 242 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 243 { 244 struct tcpip_msg *msg; 245 246 if (sys_mbox_valid(&mbox)) { 247 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 248 if (msg == NULL) { 249 return ERR_MEM; 250 } 251 252 msg->type = TCPIP_MSG_TIMEOUT; 253 msg->msg.tmo.msecs = msecs; 254 msg->msg.tmo.h = h; 255 msg->msg.tmo.arg = arg; 256 sys_mbox_post(&mbox, msg); 257 return ERR_OK; 258 } 259 return ERR_VAL; 260 } 261 262 /** 263 * call sys_untimeout in tcpip_thread 264 * 265 * @param msec time in milliseconds for timeout 266 * @param h function to be called on timeout 267 * @param arg argument to pass to timeout function h 268 * @return ERR_MEM on memory error, ERR_OK otherwise 269 */ 270 err_t 271 tcpip_untimeout(sys_timeout_handler h, void *arg) 272 { 273 struct tcpip_msg *msg; 274 275 if (sys_mbox_valid(&mbox)) { 276 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 277 if (msg == NULL) { 278 return ERR_MEM; 279 } 280 281 msg->type = TCPIP_MSG_UNTIMEOUT; 282 msg->msg.tmo.h = h; 283 msg->msg.tmo.arg = arg; 284 sys_mbox_post(&mbox, msg); 285 return ERR_OK; 286 } 287 return ERR_VAL; 288 } 289 #endif /* LWIP_TCPIP_TIMEOUT */ 290 291 #if LWIP_NETCONN 292 /** 293 * Call the lower part of a netconn_* function 294 * This function is then running in the thread context 295 * of tcpip_thread and has exclusive access to lwIP core code. 296 * 297 * @param apimsg a struct containing the function to call and its parameters 298 * @return ERR_OK if the function was called, another err_t if not 299 */ 300 err_t 301 tcpip_apimsg(struct api_msg *apimsg) 302 { 303 struct tcpip_msg msg; 304 #ifdef LWIP_DEBUG 305 /* catch functions that don't set err */ 306 apimsg->msg.err = ERR_VAL; 307 #endif 308 309 if (sys_mbox_valid(&mbox)) { 310 msg.type = TCPIP_MSG_API; 311 msg.msg.apimsg = apimsg; 312 sys_mbox_post(&mbox, &msg); 313 sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); 314 return apimsg->msg.err; 315 } 316 return ERR_VAL; 317 } 318 319 #if LWIP_TCPIP_CORE_LOCKING 320 /** 321 * Call the lower part of a netconn_* function 322 * This function has exclusive access to lwIP core code by locking it 323 * before the function is called. 324 * 325 * @param apimsg a struct containing the function to call and its parameters 326 * @return ERR_OK (only for compatibility fo tcpip_apimsg()) 327 */ 328 err_t 329 tcpip_apimsg_lock(struct api_msg *apimsg) 330 { 331 #ifdef LWIP_DEBUG 332 /* catch functions that don't set err */ 333 apimsg->msg.err = ERR_VAL; 334 #endif 335 336 LOCK_TCPIP_CORE(); 337 apimsg->function(&(apimsg->msg)); 338 UNLOCK_TCPIP_CORE(); 339 return apimsg->msg.err; 340 341 } 342 #endif /* LWIP_TCPIP_CORE_LOCKING */ 343 #endif /* LWIP_NETCONN */ 344 345 #if LWIP_NETIF_API 346 #if !LWIP_TCPIP_CORE_LOCKING 347 /** 348 * Much like tcpip_apimsg, but calls the lower part of a netifapi_* 349 * function. 350 * 351 * @param netifapimsg a struct containing the function to call and its parameters 352 * @return error code given back by the function that was called 353 */ 354 err_t 355 tcpip_netifapi(struct netifapi_msg* netifapimsg) 356 { 357 struct tcpip_msg msg; 358 359 if (sys_mbox_valid(&mbox)) { 360 err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); 361 if (err != ERR_OK) { 362 netifapimsg->msg.err = err; 363 return err; 364 } 365 366 msg.type = TCPIP_MSG_NETIFAPI; 367 msg.msg.netifapimsg = netifapimsg; 368 sys_mbox_post(&mbox, &msg); 369 sys_sem_wait(&netifapimsg->msg.sem); 370 sys_sem_free(&netifapimsg->msg.sem); 371 return netifapimsg->msg.err; 372 } 373 return ERR_VAL; 374 } 375 #else /* !LWIP_TCPIP_CORE_LOCKING */ 376 /** 377 * Call the lower part of a netifapi_* function 378 * This function has exclusive access to lwIP core code by locking it 379 * before the function is called. 380 * 381 * @param netifapimsg a struct containing the function to call and its parameters 382 * @return ERR_OK (only for compatibility fo tcpip_netifapi()) 383 */ 384 err_t 385 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) 386 { 387 LOCK_TCPIP_CORE(); 388 netifapimsg->function(&(netifapimsg->msg)); 389 UNLOCK_TCPIP_CORE(); 390 return netifapimsg->msg.err; 391 } 392 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 393 #endif /* LWIP_NETIF_API */ 394 395 /** 396 * Initialize this module: 397 * - initialize all sub modules 398 * - start the tcpip_thread 399 * 400 * @param initfunc a function to call when tcpip_thread is running and finished initializing 401 * @param arg argument to pass to initfunc 402 */ 403 void 404 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 405 { 406 lwip_init(); 407 408 tcpip_init_done = initfunc; 409 tcpip_init_done_arg = arg; 410 if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 411 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 412 } 413 #if LWIP_TCPIP_CORE_LOCKING 414 if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 415 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 416 } 417 #endif /* LWIP_TCPIP_CORE_LOCKING */ 418 419 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 420 } 421 422 /** 423 * Simple callback function used with tcpip_callback to free a pbuf 424 * (pbuf_free has a wrong signature for tcpip_callback) 425 * 426 * @param p The pbuf (chain) to be dereferenced. 427 */ 428 static void 429 pbuf_free_int(void *p) 430 { 431 struct pbuf *q = (struct pbuf *)p; 432 pbuf_free(q); 433 } 434 435 /** 436 * A simple wrapper function that allows you to free a pbuf from interrupt context. 437 * 438 * @param p The pbuf (chain) to be dereferenced. 439 * @return ERR_OK if callback could be enqueued, an err_t if not 440 */ 441 err_t 442 pbuf_free_callback(struct pbuf *p) 443 { 444 return tcpip_callback_with_block(pbuf_free_int, p, 0); 445 } 446 447 /** 448 * A simple wrapper function that allows you to free heap memory from 449 * interrupt context. 450 * 451 * @param m the heap memory to free 452 * @return ERR_OK if callback could be enqueued, an err_t if not 453 */ 454 err_t 455 mem_free_callback(void *m) 456 { 457 return tcpip_callback_with_block(mem_free, m, 0); 458 } 459 460 #endif /* !NO_SYS */ 461