Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_tcpip.c
Go to the documentation of this file.
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 Sun Jul 17 2022 08:25:25 by 1.7.2