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 mbed-os 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 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 13:15:55 by
