Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested
Dependents: STM32F746_iothub_client_sample_mqtt DISCO-F746NG_Ethernet Nucleo_F746ZG_Ethernet thethingsiO-DISCO_F746NG-mqtt ... more
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/sys.h" 00044 #include "lwip/memp.h" 00045 #include "lwip/mem.h" 00046 #include "lwip/pbuf.h" 00047 #include "lwip/tcpip.h" 00048 #include "lwip/init.h" 00049 #include "netif/etharp.h" 00050 #include "netif/ppp_oe.h" 00051 00052 /* global variables */ 00053 static tcpip_init_done_fn tcpip_init_done; 00054 static void *tcpip_init_done_arg; 00055 static sys_mbox_t mbox; 00056 00057 #if LWIP_TCPIP_CORE_LOCKING 00058 /** The global semaphore to lock the stack. */ 00059 sys_mutex_t lock_tcpip_core; 00060 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00061 00062 00063 /** 00064 * The main lwIP thread. This thread has exclusive access to lwIP core functions 00065 * (unless access to them is not locked). Other threads communicate with this 00066 * thread using message boxes. 00067 * 00068 * It also starts all the timers to make sure they are running in the right 00069 * thread context. 00070 * 00071 * @param arg unused argument 00072 */ 00073 static void 00074 tcpip_thread(void *arg) 00075 { 00076 struct tcpip_msg *msg; 00077 LWIP_UNUSED_ARG(arg); 00078 00079 if (tcpip_init_done != NULL) { 00080 tcpip_init_done(tcpip_init_done_arg); 00081 } 00082 00083 LOCK_TCPIP_CORE(); 00084 while (1) { /* MAIN Loop */ 00085 UNLOCK_TCPIP_CORE(); 00086 LWIP_TCPIP_THREAD_ALIVE(); 00087 /* wait for a message, timeouts are processed while waiting */ 00088 sys_timeouts_mbox_fetch(&mbox, (void **)&msg); 00089 LOCK_TCPIP_CORE(); 00090 switch (msg->type) { 00091 00092 #if LWIP_NETCONN 00093 case TCPIP_MSG_API: 00094 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 00095 msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); 00096 break; 00097 #endif /* LWIP_NETCONN */ 00098 00099 #if !LWIP_TCPIP_CORE_LOCKING_INPUT 00100 case TCPIP_MSG_INPKT: 00101 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); 00102 #if LWIP_ETHERNET 00103 if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 00104 ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); 00105 } else 00106 #endif /* LWIP_ETHERNET */ 00107 { 00108 ip_input(msg->msg.inp.p, msg->msg.inp.netif); 00109 } 00110 memp_free(MEMP_TCPIP_MSG_INPKT, msg); 00111 break; 00112 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00113 00114 #if LWIP_NETIF_API 00115 case TCPIP_MSG_NETIFAPI: 00116 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); 00117 msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); 00118 break; 00119 #endif /* LWIP_NETIF_API */ 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, p->payload pointing to the Ethernet header or 00157 * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or 00158 * NETIF_FLAG_ETHERNET flags) 00159 * @param inp the network interface on which the packet was received 00160 */ 00161 err_t 00162 tcpip_input(struct pbuf *p, struct netif *inp) 00163 { 00164 #if LWIP_TCPIP_CORE_LOCKING_INPUT 00165 err_t ret; 00166 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); 00167 LOCK_TCPIP_CORE(); 00168 #if LWIP_ETHERNET 00169 if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { 00170 ret = ethernet_input(p, inp); 00171 } else 00172 #endif /* LWIP_ETHERNET */ 00173 { 00174 ret = ip_input(p, inp); 00175 } 00176 UNLOCK_TCPIP_CORE(); 00177 return ret; 00178 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ 00179 struct tcpip_msg *msg; 00180 00181 if (!sys_mbox_valid(&mbox)) { 00182 return ERR_VAL; 00183 } 00184 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); 00185 if (msg == NULL) { 00186 return ERR_MEM; 00187 } 00188 00189 msg->type = TCPIP_MSG_INPKT; 00190 msg->msg.inp.p = p; 00191 msg->msg.inp.netif = inp; 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 * Call a specific function in the thread context of 00202 * tcpip_thread for easy access synchronization. 00203 * A function called in that way may access lwIP core code 00204 * without fearing concurrent access. 00205 * 00206 * @param f the function to call 00207 * @param ctx parameter passed to f 00208 * @param block 1 to block until the request is posted, 0 to non-blocking mode 00209 * @return ERR_OK if the function was called, another err_t if not 00210 */ 00211 err_t 00212 tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) 00213 { 00214 struct tcpip_msg *msg; 00215 00216 if (sys_mbox_valid(&mbox)) { 00217 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00218 if (msg == NULL) { 00219 return ERR_MEM; 00220 } 00221 00222 msg->type = TCPIP_MSG_CALLBACK; 00223 msg->msg.cb.function = function; 00224 msg->msg.cb.ctx = ctx; 00225 if (block) { 00226 sys_mbox_post(&mbox, msg); 00227 } else { 00228 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { 00229 memp_free(MEMP_TCPIP_MSG_API, msg); 00230 return ERR_MEM; 00231 } 00232 } 00233 return ERR_OK; 00234 } 00235 return ERR_VAL; 00236 } 00237 00238 #if LWIP_TCPIP_TIMEOUT 00239 /** 00240 * call sys_timeout in tcpip_thread 00241 * 00242 * @param msec time in milliseconds for timeout 00243 * @param h function to be called on timeout 00244 * @param arg argument to pass to timeout function h 00245 * @return ERR_MEM on memory error, ERR_OK otherwise 00246 */ 00247 err_t 00248 tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 00249 { 00250 struct tcpip_msg *msg; 00251 00252 if (sys_mbox_valid(&mbox)) { 00253 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00254 if (msg == NULL) { 00255 return ERR_MEM; 00256 } 00257 00258 msg->type = TCPIP_MSG_TIMEOUT; 00259 msg->msg.tmo.msecs = msecs; 00260 msg->msg.tmo.h = h; 00261 msg->msg.tmo.arg = arg; 00262 sys_mbox_post(&mbox, msg); 00263 return ERR_OK; 00264 } 00265 return ERR_VAL; 00266 } 00267 00268 /** 00269 * call sys_untimeout in tcpip_thread 00270 * 00271 * @param msec time in milliseconds for timeout 00272 * @param h function to be called on timeout 00273 * @param arg argument to pass to timeout function h 00274 * @return ERR_MEM on memory error, ERR_OK otherwise 00275 */ 00276 err_t 00277 tcpip_untimeout(sys_timeout_handler h, void *arg) 00278 { 00279 struct tcpip_msg *msg; 00280 00281 if (sys_mbox_valid(&mbox)) { 00282 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00283 if (msg == NULL) { 00284 return ERR_MEM; 00285 } 00286 00287 msg->type = TCPIP_MSG_UNTIMEOUT; 00288 msg->msg.tmo.h = h; 00289 msg->msg.tmo.arg = arg; 00290 sys_mbox_post(&mbox, msg); 00291 return ERR_OK; 00292 } 00293 return ERR_VAL; 00294 } 00295 #endif /* LWIP_TCPIP_TIMEOUT */ 00296 00297 #if LWIP_NETCONN 00298 /** 00299 * Call the lower part of a netconn_* function 00300 * This function is then running in the thread context 00301 * of tcpip_thread and has exclusive access to lwIP core code. 00302 * 00303 * @param apimsg a struct containing the function to call and its parameters 00304 * @return ERR_OK if the function was called, another err_t if not 00305 */ 00306 err_t 00307 tcpip_apimsg(struct api_msg *apimsg) 00308 { 00309 struct tcpip_msg msg; 00310 #ifdef LWIP_DEBUG 00311 /* catch functions that don't set err */ 00312 apimsg->msg.err = ERR_VAL; 00313 #endif 00314 00315 if (sys_mbox_valid(&mbox)) { 00316 msg.type = TCPIP_MSG_API; 00317 msg.msg.apimsg = apimsg; 00318 sys_mbox_post(&mbox, &msg); 00319 sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); 00320 return apimsg->msg.err; 00321 } 00322 return ERR_VAL; 00323 } 00324 00325 #if LWIP_TCPIP_CORE_LOCKING 00326 /** 00327 * Call the lower part of a netconn_* function 00328 * This function has exclusive access to lwIP core code by locking it 00329 * before the function is called. 00330 * 00331 * @param apimsg a struct containing the function to call and its parameters 00332 * @return ERR_OK (only for compatibility fo tcpip_apimsg()) 00333 */ 00334 err_t 00335 tcpip_apimsg_lock(struct api_msg *apimsg) 00336 { 00337 #ifdef LWIP_DEBUG 00338 /* catch functions that don't set err */ 00339 apimsg->msg.err = ERR_VAL; 00340 #endif 00341 00342 LOCK_TCPIP_CORE(); 00343 apimsg->function(&(apimsg->msg)); 00344 UNLOCK_TCPIP_CORE(); 00345 return apimsg->msg.err; 00346 00347 } 00348 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00349 #endif /* LWIP_NETCONN */ 00350 00351 #if LWIP_NETIF_API 00352 #if !LWIP_TCPIP_CORE_LOCKING 00353 /** 00354 * Much like tcpip_apimsg, but calls the lower part of a netifapi_* 00355 * function. 00356 * 00357 * @param netifapimsg a struct containing the function to call and its parameters 00358 * @return error code given back by the function that was called 00359 */ 00360 err_t 00361 tcpip_netifapi(struct netifapi_msg* netifapimsg) 00362 { 00363 struct tcpip_msg msg; 00364 00365 if (sys_mbox_valid(&mbox)) { 00366 err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); 00367 if (err != ERR_OK) { 00368 netifapimsg->msg.err = err; 00369 return err; 00370 } 00371 00372 msg.type = TCPIP_MSG_NETIFAPI; 00373 msg.msg.netifapimsg = netifapimsg; 00374 sys_mbox_post(&mbox, &msg); 00375 sys_sem_wait(&netifapimsg->msg.sem); 00376 sys_sem_free(&netifapimsg->msg.sem); 00377 return netifapimsg->msg.err; 00378 } 00379 return ERR_VAL; 00380 } 00381 #else /* !LWIP_TCPIP_CORE_LOCKING */ 00382 /** 00383 * Call the lower part of a netifapi_* function 00384 * This function has exclusive access to lwIP core code by locking it 00385 * before the function is called. 00386 * 00387 * @param netifapimsg a struct containing the function to call and its parameters 00388 * @return ERR_OK (only for compatibility fo tcpip_netifapi()) 00389 */ 00390 err_t 00391 tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) 00392 { 00393 LOCK_TCPIP_CORE(); 00394 netifapimsg->function(&(netifapimsg->msg)); 00395 UNLOCK_TCPIP_CORE(); 00396 return netifapimsg->msg.err; 00397 } 00398 #endif /* !LWIP_TCPIP_CORE_LOCKING */ 00399 #endif /* LWIP_NETIF_API */ 00400 00401 /** 00402 * Allocate a structure for a static callback message and initialize it. 00403 * This is intended to be used to send "static" messages from interrupt context. 00404 * 00405 * @param function the function to call 00406 * @param ctx parameter passed to function 00407 * @return a struct pointer to pass to tcpip_trycallback(). 00408 */ 00409 struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) 00410 { 00411 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); 00412 if (msg == NULL) { 00413 return NULL; 00414 } 00415 msg->type = TCPIP_MSG_CALLBACK_STATIC; 00416 msg->msg.cb.function = function; 00417 msg->msg.cb.ctx = ctx; 00418 return (struct tcpip_callback_msg*)msg; 00419 } 00420 00421 /** 00422 * Free a callback message allocated by tcpip_callbackmsg_new(). 00423 * 00424 * @param msg the message to free 00425 */ 00426 void 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 if (!sys_mbox_valid(&mbox)) { 00442 return ERR_VAL; 00443 } 00444 return sys_mbox_trypost(&mbox, msg); 00445 } 00446 00447 /** 00448 * Initialize this module: 00449 * - initialize all sub modules 00450 * - start the tcpip_thread 00451 * 00452 * @param initfunc a function to call when tcpip_thread is running and finished initializing 00453 * @param arg argument to pass to initfunc 00454 */ 00455 void 00456 tcpip_init(tcpip_init_done_fn initfunc, void *arg) 00457 { 00458 lwip_init(); 00459 00460 tcpip_init_done = initfunc; 00461 tcpip_init_done_arg = arg; 00462 if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { 00463 LWIP_ASSERT("failed to create tcpip_thread mbox", 0); 00464 } 00465 #if LWIP_TCPIP_CORE_LOCKING 00466 if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { 00467 LWIP_ASSERT("failed to create lock_tcpip_core", 0); 00468 } 00469 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00470 00471 sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); 00472 } 00473 00474 /** 00475 * Simple callback function used with tcpip_callback to free a pbuf 00476 * (pbuf_free has a wrong signature for tcpip_callback) 00477 * 00478 * @param p The pbuf (chain) to be dereferenced. 00479 */ 00480 static void 00481 pbuf_free_int(void *p) 00482 { 00483 struct pbuf *q = (struct pbuf *)p; 00484 pbuf_free(q); 00485 } 00486 00487 /** 00488 * A simple wrapper function that allows you to free a pbuf from interrupt context. 00489 * 00490 * @param p The pbuf (chain) to be dereferenced. 00491 * @return ERR_OK if callback could be enqueued, an err_t if not 00492 */ 00493 err_t 00494 pbuf_free_callback(struct pbuf *p) 00495 { 00496 return tcpip_callback_with_block(pbuf_free_int, p, 0); 00497 } 00498 00499 /** 00500 * A simple wrapper function that allows you to free heap memory from 00501 * interrupt context. 00502 * 00503 * @param m the heap memory to free 00504 * @return ERR_OK if callback could be enqueued, an err_t if not 00505 */ 00506 err_t 00507 mem_free_callback(void *m) 00508 { 00509 return tcpip_callback_with_block(mem_free, m, 0); 00510 } 00511 00512 //[MS_CHANGE] 00513 00514 err_t tcpip_shutdown() 00515 { 00516 struct tcpip_msg msg; 00517 sys_sem_t sem; 00518 msg.sem = &sem; 00519 if (sys_mbox_valid(&mbox)) 00520 { 00521 err_t err = sys_sem_new(msg.sem, 0); 00522 if (err != ERR_OK) 00523 return err; 00524 00525 msg.type = TCPIP_MSG_SHUTDOWN; 00526 sys_mbox_post(&mbox, &msg); 00527 sys_sem_wait(msg.sem); 00528 sys_sem_free(msg.sem); 00529 return ERR_OK; 00530 } 00531 return ERR_VAL; 00532 } 00533 //[END_MS_CHANGE] 00534 00535 #endif /* !NO_SYS */
Generated on Tue Jul 12 2022 18:14:55 by 1.7.2