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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 00052 #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) 00053 #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) 00054 #define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM) 00055 #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) 00056 00057 /* global variables */ 00058 static tcpip_init_done_fn tcpip_init_done; 00059 static void *tcpip_init_done_arg; 00060 static sys_mbox_t mbox; 00061 00062 #if LWIP_TCPIP_CORE_LOCKING 00063 /** The global semaphore to lock the stack. */ 00064 sys_mutex_t lock_tcpip_core; 00065 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00066 00067 00068 /** 00069 * The main lwIP thread. This thread has exclusive access to lwIP core functions 00070 * (unless access to them is not locked). Other threads communicate with this 00071 * thread using message boxes. 00072 * 00073 * It also starts all the timers to make sure they are running in the right 00074 * thread context. 00075 * 00076 * @param arg unused argument 00077 */ 00078 static void 00079 tcpip_thread(void *arg) 00080 { 00081 struct tcpip_msg *msg; 00082 LWIP_UNUSED_ARG(arg); 00083 00084 if (tcpip_init_done != NULL) { 00085 tcpip_init_done(tcpip_init_done_arg); 00086 } 00087 00088 LOCK_TCPIP_CORE(); 00089 while (1) { /* MAIN Loop */ 00090 UNLOCK_TCPIP_CORE(); 00091 LWIP_TCPIP_THREAD_ALIVE(); 00092 /* wait for a message, timeouts are processed while waiting */ 00093 sys_timeouts_mbox_fetch(&mbox, (void **)&msg); 00094 LOCK_TCPIP_CORE(); 00095 if (msg == NULL) { 00096 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); 00097 LWIP_ASSERT("tcpip_thread: invalid message", 0); 00098 continue; 00099 } 00100 switch (msg->type) { 00101 #if !LWIP_TCPIP_CORE_LOCKING 00102 case TCPIP_MSG_API: 00103 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 00104 msg->msg.api_msg.function(msg->msg.api_msg.msg); 00105 break; 00106 case TCPIP_MSG_API_CALL: 00107 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg)); 00108 msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg); 00109 sys_sem_signal(msg->msg.api_call.sem); 00110 break; 00111 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 00112 00113 #if !LWIP_TCPIP_CORE_LOCKING_INPUT 00114 case TCPIP_MSG_INPKT: 00115 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 00116 msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif); 00117 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 00118 break; 00119 #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ 00120 00121 #if LWIP_TCPIP_TIMEOUT 00122 case TCPIP_MSG_TIMEOUT: 00123 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); 00124 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); 00125 memp_free(MEMP_TCPIP_MSG_API, msg); 00126 break; 00127 case TCPIP_MSG_UNTIMEOUT: 00128 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); 00129 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); 00130 memp_free(MEMP_TCPIP_MSG_API, msg); 00131 break; 00132 #endif /* LWIP_TCPIP_TIMEOUT */ 00133 00134 case TCPIP_MSG_CALLBACK: 00135 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); 00136 msg->msg.cb.function(msg->msg.cb.ctx); 00137 memp_free(MEMP_TCPIP_MSG_API, msg); 00138 break; 00139 00140 case TCPIP_MSG_CALLBACK_STATIC: 00141 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); 00142 msg->msg.cb.function(msg->msg.cb.ctx); 00143 break; 00144 00145 default: 00146 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); 00147 LWIP_ASSERT("tcpip_thread: invalid message", 0); 00148 break; 00149 } 00150 } 00151 } 00152 00153 /** 00154 * Pass a received packet to tcpip_thread for input processing 00155 * 00156 * @param p the received packet 00157 * @param inp the network interface on which the packet was received 00158 * @param input_fn input function to call 00159 */ 00160 err_t 00161 tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn) 00162 { 00163 #if LWIP_TCPIP_CORE_LOCKING_INPUT 00164 err_t ret; 00165 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp)); 00166 LOCK_TCPIP_CORE(); 00167 ret = input_fn(p, inp); 00168 UNLOCK_TCPIP_CORE(); 00169 return ret; 00170 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00171 struct tcpip_msg *msg; 00172 00173 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00174 00175 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 00176 if (msg == NULL) { 00177 return ERR_MEM; 00178 } 00179 00180 msg->type = TCPIP_MSG_INPKT; 00181 msg->msg.inp.p = p; 00182 msg->msg.inp.netif = inp; 00183 msg->msg.inp.input_fn = input_fn; 00184 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 00185 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 00186 return ERR_MEM; 00187 } 00188 return ERR_OK; 00189 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00190 } 00191 00192 /** 00193 * @ingroup lwip_os 00194 * Pass a received packet to tcpip_thread for input processing with 00195 * ethernet_input or ip_input. Don't call directly, pass to netif_add() 00196 * and call netif->input(). 00197 * 00198 * @param p the received packet, p->payload pointing to the Ethernet header or 00199 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 00200 * NETIF_FLAG_ETHERNET flags) 00201 * @param inp the network interface on which the packet was received 00202 */ 00203 err_t 00204 tcpip_input(struct pbuf *p, struct netif *inp) 00205 { 00206 #if LWIP_ETHERNET 00207 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 00208 return tcpip_inpkt(p, inp, ethernet_input); 00209 } else 00210 #endif /* LWIP_ETHERNET */ 00211 return tcpip_inpkt(p, inp, ip_input); 00212 } 00213 00214 /** 00215 * Call a specific function in the thread context of 00216 * tcpip_thread for easy access synchronization. 00217 * A function called in that way may access lwIP core code 00218 * without fearing concurrent access. 00219 * 00220 * @param function the function to call 00221 * @param ctx parameter passed to f 00222 * @param block 1 to block until the request is posted, 0 to non-blocking mode 00223 * @return ERR_OK if the function was called, another err_t if not 00224 */ 00225 err_t 00226 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) 00227 { 00228 struct tcpip_msg *msg; 00229 00230 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00231 00232 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00233 if (msg == NULL) { 00234 return ERR_MEM; 00235 } 00236 00237 msg->type = TCPIP_MSG_CALLBACK; 00238 msg->msg.cb.function = function; 00239 msg->msg.cb.ctx = ctx; 00240 if (block) { 00241 sys_mbox_post(&mbox, msg); 00242 } else { 00243 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 00244 memp_free(MEMP_TCPIP_MSG_API, msg); 00245 return ERR_MEM; 00246 } 00247 } 00248 return ERR_OK; 00249 } 00250 00251 #if LWIP_TCPIP_TIMEOUT 00252 /** 00253 * call sys_timeout in tcpip_thread 00254 * 00255 * @param msec time in milliseconds for timeout 00256 * @param h function to be called on timeout 00257 * @param arg argument to pass to timeout function h 00258 * @return ERR_MEM on memory error, ERR_OK otherwise 00259 */ 00260 err_t 00261 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 00262 { 00263 struct tcpip_msg *msg; 00264 00265 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00266 00267 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00268 if (msg == NULL) { 00269 return ERR_MEM; 00270 } 00271 00272 msg->type = TCPIP_MSG_TIMEOUT; 00273 msg->msg.tmo.msecs = msecs; 00274 msg->msg.tmo.h = h; 00275 msg->msg.tmo.arg = arg; 00276 sys_mbox_post(&mbox, msg); 00277 return ERR_OK; 00278 } 00279 00280 /** 00281 * call sys_untimeout in tcpip_thread 00282 * 00283 * @param msec time in milliseconds for timeout 00284 * @param h function to be called on timeout 00285 * @param arg argument to pass to timeout function h 00286 * @return ERR_MEM on memory error, ERR_OK otherwise 00287 */ 00288 err_t 00289 tcpip_untimeout(sys_timeout_handler h, void *arg) 00290 { 00291 struct tcpip_msg *msg; 00292 00293 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00294 00295 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00296 if (msg == NULL) { 00297 return ERR_MEM; 00298 } 00299 00300 msg->type = TCPIP_MSG_UNTIMEOUT; 00301 msg->msg.tmo.h = h; 00302 msg->msg.tmo.arg = arg; 00303 sys_mbox_post(&mbox, msg); 00304 return ERR_OK; 00305 } 00306 #endif /* LWIP_TCPIP_TIMEOUT */ 00307 00308 00309 /** 00310 * Sends a message to TCPIP thread to call a function. Caller thread blocks on 00311 * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, 00312 * this has to be done by the user. 00313 * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way 00314 * with least runtime overhead. 00315 * 00316 * @param fn function to be called from TCPIP thread 00317 * @param apimsg argument to API function 00318 * @param sem semaphore to wait on 00319 * @return ERR_OK if the function was called, another err_t if not 00320 */ 00321 err_t 00322 tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem) 00323 { 00324 #if LWIP_TCPIP_CORE_LOCKING 00325 LWIP_UNUSED_ARG(sem); 00326 LOCK_TCPIP_CORE(); 00327 fn(apimsg); 00328 UNLOCK_TCPIP_CORE(); 00329 return ERR_OK; 00330 #else /* LWIP_TCPIP_CORE_LOCKING */ 00331 TCPIP_MSG_VAR_DECLARE(msg); 00332 00333 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); 00334 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00335 00336 TCPIP_MSG_VAR_ALLOC(msg); 00337 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; 00338 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; 00339 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; 00340 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); 00341 sys_arch_sem_wait(sem, 0); 00342 TCPIP_MSG_VAR_FREE(msg); 00343 return ERR_OK; 00344 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00345 } 00346 00347 /** 00348 * Synchronously calls function in TCPIP thread and waits for its completion. 00349 * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or 00350 * LWIP_NETCONN_SEM_PER_THREAD. 00351 * If not, a semaphore is created and destroyed on every call which is usually 00352 * an expensive/slow operation. 00353 * @param fn Function to call 00354 * @param call Call parameters 00355 * @return Return value from tcpip_api_call_fn 00356 */ 00357 err_t 00358 tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call) 00359 { 00360 #if LWIP_TCPIP_CORE_LOCKING 00361 err_t err; 00362 LOCK_TCPIP_CORE(); 00363 err = fn(call); 00364 UNLOCK_TCPIP_CORE(); 00365 return err; 00366 #else /* LWIP_TCPIP_CORE_LOCKING */ 00367 TCPIP_MSG_VAR_DECLARE(msg); 00368 00369 #if !LWIP_NETCONN_SEM_PER_THREAD 00370 err_t err = sys_sem_new(&call->sem, 0); 00371 if (err != ERR_OK) { 00372 return err; 00373 } 00374 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00375 00376 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00377 00378 TCPIP_MSG_VAR_ALLOC(msg); 00379 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL; 00380 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call; 00381 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn; 00382 #if LWIP_NETCONN_SEM_PER_THREAD 00383 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET(); 00384 #else /* LWIP_NETCONN_SEM_PER_THREAD */ 00385 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem; 00386 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00387 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); 00388 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0); 00389 TCPIP_MSG_VAR_FREE(msg); 00390 00391 #if !LWIP_NETCONN_SEM_PER_THREAD 00392 sys_sem_free(&call->sem); 00393 #endif /* LWIP_NETCONN_SEM_PER_THREAD */ 00394 00395 return call->err; 00396 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00397 } 00398 00399 /** 00400 * Allocate a structure for a static callback message and initialize it. 00401 * This is intended to be used to send "static" messages from interrupt context. 00402 * 00403 * @param function the function to call 00404 * @param ctx parameter passed to function 00405 * @return a struct pointer to pass to tcpip_trycallback(). 00406 */ 00407 struct tcpip_callback_msg* 00408 tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 00409 { 00410 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00411 if (msg == NULL) { 00412 return NULL; 00413 } 00414 msg->type = TCPIP_MSG_CALLBACK_STATIC; 00415 msg->msg.cb.function = function; 00416 msg->msg.cb.ctx = ctx; 00417 return (struct tcpip_callback_msg*)msg; 00418 } 00419 00420 /** 00421 * Free a callback message allocated by tcpip_callbackmsg_new(). 00422 * 00423 * @param msg the message to free 00424 */ 00425 void 00426 tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) 00427 { 00428 memp_free(MEMP_TCPIP_MSG_API, msg); 00429 } 00430 00431 /** 00432 * Try to post a callback-message to the tcpip_thread mbox 00433 * This is intended to be used to send "static" messages from interrupt context. 00434 * 00435 * @param msg pointer to the message to post 00436 * @return sys_mbox_trypost() return code 00437 */ 00438 err_t 00439 tcpip_trycallback(struct tcpip_callback_msg* msg) 00440 { 00441 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); 00442 return sys_mbox_trypost(&mbox, msg); 00443 } 00444 00445 /** 00446 * @ingroup lwip_os 00447 * Initialize this module: 00448 * - initialize all sub modules 00449 * - start the tcpip_thread 00450 * 00451 * @param initfunc a function to call when tcpip_thread is running and finished initializing 00452 * @param arg argument to pass to initfunc 00453 */ 00454 void 00455 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 00456 { 00457 lwip_init(); 00458 00459 tcpip_init_done = initfunc; 00460 tcpip_init_done_arg = arg; 00461 if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 00462 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 00463 } 00464 #if LWIP_TCPIP_CORE_LOCKING 00465 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 00466 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 00467 } 00468 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00469 00470 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 00471 } 00472 00473 /** 00474 * Simple callback function used with tcpip_callback to free a pbuf 00475 * (pbuf_free has a wrong signature for tcpip_callback) 00476 * 00477 * @param p The pbuf (chain) to be dereferenced. 00478 */ 00479 static void 00480 pbuf_free_int(void *p) 00481 { 00482 struct pbuf *q = (struct pbuf *)p; 00483 pbuf_free(q); 00484 } 00485 00486 /** 00487 * A simple wrapper function that allows you to free a pbuf from interrupt context. 00488 * 00489 * @param p The pbuf (chain) to be dereferenced. 00490 * @return ERR_OK if callback could be enqueued, an err_t if not 00491 */ 00492 err_t 00493 pbuf_free_callback(struct pbuf *p) 00494 { 00495 return tcpip_callback_with_block(pbuf_free_int, p, 0); 00496 } 00497 00498 /** 00499 * A simple wrapper function that allows you to free heap memory from 00500 * interrupt context. 00501 * 00502 * @param m the heap memory to free 00503 * @return ERR_OK if callback could be enqueued, an err_t if not 00504 */ 00505 err_t 00506 mem_free_callback(void *m) 00507 { 00508 return tcpip_callback_with_block(mem_free, m, 0); 00509 } 00510 00511 #endif /* !NO_SYS */
Generated on Tue Jul 12 2022 11:02:42 by
