Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
lwip_tcpip.c
00001 /** 00002 * @file 00003 * Sequential API Main thread module 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 */ 00038 00039 #include "lwip/opt.h" 00040 00041 #if !NO_SYS /* don't build if not configured for use in lwipopts.h */ 00042 00043 #include "lwip/priv/tcpip_priv.h" 00044 #include "lwip/sys.h" 00045 #include "lwip/memp.h" 00046 #include "lwip/mem.h" 00047 #include "lwip/init.h" 00048 #include "lwip/ip.h" 00049 #include "lwip/pbuf.h" 00050 #include "lwip/etharp.h" 00051 #include "netif/lwip_ethernet.h" 00052 00053 #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) 00054 #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) 00055 #define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) 00056 #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) 00057 00058 /* global variables */ 00059 static tcpip_init_done_fn tcpip_init_done; 00060 static void *tcpip_init_done_arg; 00061 static sys_mbox_t mbox; 00062 00063 #if LWIP_TCPIP_CORE_LOCKING 00064 /** The global semaphore to lock the stack. */ 00065 sys_mutex_t lock_tcpip_core; 00066 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00067 00068 #if LWIP_TIMERS 00069 /* wait for a message, timeouts are processed while waiting */ 00070 #define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg) 00071 #else /* LWIP_TIMERS */ 00072 /* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */ 00073 #define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg) 00074 #endif /* LWIP_TIMERS */ 00075 00076 /** 00077 * The main lwIP thread. This thread has exclusive access to lwIP core functions 00078 * (unless access to them is not locked). Other threads communicate with this 00079 * thread using message boxes. 00080 * 00081 * It also starts all the timers to make sure they are running in the right 00082 * thread context. 00083 * 00084 * @param arg unused argument 00085 */ 00086 static void 00087 tcpip_thread(void *arg) 00088 { 00089 struct tcpip_msg *msg; 00090 LWIP_UNUSED_ARG(arg); 00091 00092 if (tcpip_init_done != NULL) { 00093 tcpip_init_done(tcpip_init_done_arg); 00094 } 00095 00096 LOCK_TCPIP_CORE(); 00097 while (1) { /* MAIN Loop */ 00098 UNLOCK_TCPIP_CORE(); 00099 LWIP_TCPIP_THREAD_ALIVE(); 00100 /* wait for a message, timeouts are processed while waiting */ 00101 TCPIP_MBOX_FETCH(&mbox, (void **)&msg); 00102 LOCK_TCPIP_CORE(); 00103 if (msg == NULL) { 00104 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); 00105 LWIP_ASSERT("tcpip_thread: invalid message", 0); 00106 continue; 00107 } 00108 switch (msg->type) { 00109 #if !LWIP_TCPIP_CORE_LOCKING 00110 case TCPIP_MSG_API: 00111 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 00112 msg->msg.api_msg.function(msg->msg.api_msg.msg); 00113 break; 00114 case TCPIP_MSG_API_CALL: 00115 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); 00116 msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); 00117 sys_sem_signal(msg->msg.api_call.sem); 00118 break; 00119 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 00120 00121 #if !LWIP_TCPIP_CORE_LOCKING_INPUT 00122 case TCPIP_MSG_INPKT: 00123 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 00124 msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); 00125 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 00126 break; 00127 #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ 00128 00129 #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 00130 case TCPIP_MSG_TIMEOUT: 00131 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 00132 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 00133 memp_free(MEMP_TCPIP_MSG_API, msg); 00134 break; 00135 case TCPIP_MSG_UNTIMEOUT: 00136 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 00137 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 00138 memp_free(MEMP_TCPIP_MSG_API, msg); 00139 break; 00140 #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 00141 00142 case TCPIP_MSG_CALLBACK: 00143 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 00144 msg->msg.cb.function(msg->msg.cb.ctx); 00145 memp_free(MEMP_TCPIP_MSG_API, msg); 00146 break; 00147 00148 case TCPIP_MSG_CALLBACK_STATIC: 00149 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); 00150 msg->msg.cb.function(msg->msg.cb.ctx); 00151 break; 00152 00153 default: 00154 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 00155 LWIP_ASSERT("tcpip_thread: invalid message", 0); 00156 break; 00157 } 00158 } 00159 } 00160 00161 /** 00162 * Pass a received packet to tcpip_thread for input processing 00163 * 00164 * @param p the received packet 00165 * @param inp the network interface on which the packet was received 00166 * @param input_fn input function to call 00167 */ 00168 err_t 00169 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 00170 { 00171 #if LWIP_TCPIP_CORE_LOCKING_INPUT 00172 err_t ret; 00173 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); 00174 LOCK_TCPIP_CORE(); 00175 ret = input_fn(p, inp); 00176 UNLOCK_TCPIP_CORE(); 00177 return ret; 00178 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00179 struct tcpip_msg *msg; 00180 00181 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00182 00183 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 00184 if (msg == NULL) { 00185 return ERR_MEM; 00186 } 00187 00188 msg->type = TCPIP_MSG_INPKT; 00189 msg->msg.inp.p = p; 00190 msg->msg.inp.netif = inp; 00191 msg->msg.inp.input_fn = input_fn; 00192 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 00193 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 00194 return ERR_MEM; 00195 } 00196 return ERR_OK; 00197 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00198 } 00199 00200 /** 00201 * @ingroup lwip_os 00202 * Pass a received packet to tcpip_thread for input processing with 00203 * ethernet_input or ip_input. Don't call directly, pass to netif_add() 00204 * and call netif->input(). 00205 * 00206 * @param p the received packet, p->payload pointing to the Ethernet header or 00207 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 00208 * NETIF_FLAG_ETHERNET flags) 00209 * @param inp the network interface on which the packet was received 00210 */ 00211 err_t 00212 tcpip_input(struct pbuf *p, struct netif *inp) 00213 { 00214 #if LWIP_ETHERNET 00215 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 00216 return tcpip_inpkt(p, inp, ethernet_input); 00217 } else 00218 #endif /* LWIP_ETHERNET */ 00219 return tcpip_inpkt(p, inp, ip_input); 00220 } 00221 00222 /** 00223 * Call a specific function in the thread context of 00224 * tcpip_thread for easy access synchronization. 00225 * A function called in that way may access lwIP core code 00226 * without fearing concurrent access. 00227 * 00228 * @param function the function to call 00229 * @param ctx parameter passed to f 00230 * @param block 1 to block until the request is posted, 0 to non-blocking mode 00231 * @return ERR_OK if the function was called, another err_t if not 00232 */ 00233 err_t 00234 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) 00235 { 00236 struct tcpip_msg *msg; 00237 00238 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00239 00240 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00241 if (msg == NULL) { 00242 return ERR_MEM; 00243 } 00244 00245 msg->type = TCPIP_MSG_CALLBACK; 00246 msg->msg.cb.function = function; 00247 msg->msg.cb.ctx = ctx; 00248 if (block) { 00249 sys_mbox_post(&mbox, msg); 00250 } else { 00251 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 00252 memp_free(MEMP_TCPIP_MSG_API, msg); 00253 return ERR_MEM; 00254 } 00255 } 00256 return ERR_OK; 00257 } 00258 00259 #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS 00260 /** 00261 * call sys_timeout in tcpip_thread 00262 * 00263 * @param msecs time in milliseconds for timeout 00264 * @param h function to be called on timeout 00265 * @param arg argument to pass to timeout function h 00266 * @return ERR_MEM on memory error, ERR_OK otherwise 00267 */ 00268 err_t 00269 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 00270 { 00271 struct tcpip_msg *msg; 00272 00273 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00274 00275 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00276 if (msg == NULL) { 00277 return ERR_MEM; 00278 } 00279 00280 msg->type = TCPIP_MSG_TIMEOUT; 00281 msg->msg.tmo.msecs = msecs; 00282 msg->msg.tmo.h = h; 00283 msg->msg.tmo.arg = arg; 00284 sys_mbox_post(&mbox, msg); 00285 return ERR_OK; 00286 } 00287 00288 /** 00289 * call sys_untimeout in tcpip_thread 00290 * 00291 * @param h function to be called on timeout 00292 * @param arg argument to pass to timeout function h 00293 * @return ERR_MEM on memory error, ERR_OK otherwise 00294 */ 00295 err_t 00296 tcpip_untimeout(sys_timeout_handler h, void *arg) 00297 { 00298 struct tcpip_msg *msg; 00299 00300 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00301 00302 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00303 if (msg == NULL) { 00304 return ERR_MEM; 00305 } 00306 00307 msg->type = TCPIP_MSG_UNTIMEOUT; 00308 msg->msg.tmo.h = h; 00309 msg->msg.tmo.arg = arg; 00310 sys_mbox_post(&mbox, msg); 00311 return ERR_OK; 00312 } 00313 #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */ 00314 00315 00316 /** 00317 * Sends a message to TCPIP thread to call a function. Caller thread blocks on 00318 * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, 00319 * this has to be done by the user. 00320 * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way 00321 * with least runtime overhead. 00322 * 00323 * @param fn function to be called from TCPIP thread 00324 * @param apimsg argument to API function 00325 * @param sem semaphore to wait on 00326 * @return ERR_OK if the function was called, another err_t if not 00327 */ 00328 err_t 00329 tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem) 00330 { 00331 #if LWIP_TCPIP_CORE_LOCKING 00332 LWIP_UNUSED_ARG(sem); 00333 LOCK_TCPIP_CORE(); 00334 fn(apimsg); 00335 UNLOCK_TCPIP_CORE(); 00336 return ERR_OK; 00337 #else /* LWIP_TCPIP_CORE_LOCKING */ 00338 TCPIP_MSG_VAR_DECLARE(msg); 00339 00340 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); 00341 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00342 00343 TCPIP_MSG_VAR_ALLOC(msg); 00344 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; 00345 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; 00346 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; 00347 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); 00348 sys_arch_sem_wait(sem, 0); 00349 TCPIP_MSG_VAR_FREE(msg); 00350 return ERR_OK; 00351 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00352 } 00353 00354 /** 00355 * Synchronously calls function in TCPIP thread and waits for its completion. 00356 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 00357 * LWIP_NETCONN_SEM_PER_THREAD. 00358 * If not, a semaphore is created and destroyed on every call which is usually 00359 * an expensive/slow operation. 00360 * @param fn Function to call 00361 * @param call Call parameters 00362 * @return Return value from tcpip_api_call_fn 00363 */ 00364 err_t 00365 tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) 00366 { 00367 #if LWIP_TCPIP_CORE_LOCKING 00368 err_t err; 00369 LOCK_TCPIP_CORE(); 00370 err = fn(call); 00371 UNLOCK_TCPIP_CORE(); 00372 return err; 00373 #else /* LWIP_TCPIP_CORE_LOCKING */ 00374 TCPIP_MSG_VAR_DECLARE(msg); 00375 00376 #if !LWIP_NETCONN_SEM_PER_THREAD 00377 err_t err = sys_sem_new(&call->sem, 0); 00378 if (err != ERR_OK) { 00379 return err; 00380 } 00381 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00382 00383 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00384 00385 TCPIP_MSG_VAR_ALLOC(msg); 00386 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; 00387 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; 00388 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; 00389 #if LWIP_NETCONN_SEM_PER_THREAD 00390 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); 00391 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 00392 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; 00393 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00394 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); 00395 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); 00396 TCPIP_MSG_VAR_FREE(msg); 00397 00398 #if !LWIP_NETCONN_SEM_PER_THREAD 00399 sys_sem_free(&call->sem); 00400 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00401 00402 return call->err; 00403 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00404 } 00405 00406 /** 00407 * Allocate a structure for a static callback message and initialize it. 00408 * This is intended to be used to send "static" messages from interrupt context. 00409 * 00410 * @param function the function to call 00411 * @param ctx parameter passed to function 00412 * @return a struct pointer to pass to tcpip_trycallback(). 00413 */ 00414 struct tcpip_callback_msg* 00415 tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 00416 { 00417 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00418 if (msg == NULL) { 00419 return NULL; 00420 } 00421 msg->type = TCPIP_MSG_CALLBACK_STATIC; 00422 msg->msg.cb.function = function; 00423 msg->msg.cb.ctx = ctx; 00424 return (struct tcpip_callback_msg*)msg; 00425 } 00426 00427 /** 00428 * Free a callback message allocated by tcpip_callbackmsg_new(). 00429 * 00430 * @param msg the message to free 00431 */ 00432 void 00433 tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) 00434 { 00435 memp_free(MEMP_TCPIP_MSG_API, msg); 00436 } 00437 00438 /** 00439 * Try to post a callback-message to the tcpip_thread mbox 00440 * This is intended to be used to send "static" messages from interrupt context. 00441 * 00442 * @param msg pointer to the message to post 00443 * @return sys_mbox_trypost() return code 00444 */ 00445 err_t 00446 tcpip_trycallback(struct tcpip_callback_msg* msg) 00447 { 00448 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00449 return sys_mbox_trypost(&mbox, msg); 00450 } 00451 00452 /** 00453 * @ingroup lwip_os 00454 * Initialize this module: 00455 * - initialize all sub modules 00456 * - start the tcpip_thread 00457 * 00458 * @param initfunc a function to call when tcpip_thread is running and finished initializing 00459 * @param arg argument to pass to initfunc 00460 */ 00461 void 00462 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 00463 { 00464 lwip_init(); 00465 00466 tcpip_init_done = initfunc; 00467 tcpip_init_done_arg = arg; 00468 if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 00469 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 00470 } 00471 #if LWIP_TCPIP_CORE_LOCKING 00472 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 00473 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 00474 } 00475 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00476 00477 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 00478 } 00479 00480 /** 00481 * Simple callback function used with tcpip_callback to free a pbuf 00482 * (pbuf_free has a wrong signature for tcpip_callback) 00483 * 00484 * @param p The pbuf (chain) to be dereferenced. 00485 */ 00486 static void 00487 pbuf_free_int(void *p) 00488 { 00489 struct pbuf *q = (struct pbuf *)p; 00490 pbuf_free(q); 00491 } 00492 00493 /** 00494 * A simple wrapper function that allows you to free a pbuf from interrupt context. 00495 * 00496 * @param p The pbuf (chain) to be dereferenced. 00497 * @return ERR_OK if callback could be enqueued, an err_t if not 00498 */ 00499 err_t 00500 pbuf_free_callback(struct pbuf *p) 00501 { 00502 return tcpip_callback_with_block(pbuf_free_int, p, 0); 00503 } 00504 00505 /** 00506 * A simple wrapper function that allows you to free heap memory from 00507 * interrupt context. 00508 * 00509 * @param m the heap memory to free 00510 * @return ERR_OK if callback could be enqueued, an err_t if not 00511 */ 00512 err_t 00513 mem_free_callback(void *m) 00514 { 00515 return tcpip_callback_with_block(mem_free, m, 0); 00516 } 00517 00518 #endif /* !NO_SYS */
Generated on Fri Jul 22 2022 04:53:53 by
1.7.2
