tcpip.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /**
  2. * @file
  3. * Sequential API Main thread module
  4. *
  5. */
  6. /*
  7. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without modification,
  11. * are permitted provided that the following conditions are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * 3. The name of the author may not be used to endorse or promote products
  19. * derived from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  22. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  23. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  24. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  26. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  29. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  30. * OF SUCH DAMAGE.
  31. *
  32. * This file is part of the lwIP TCP/IP stack.
  33. *
  34. * Author: Adam Dunkels <adam@sics.se>
  35. *
  36. */
  37. #include "lwip/opt.h"
  38. #if !NO_SYS /* don't build if not configured for use in lwipopts.h */
  39. #include "lwip/priv/tcpip_priv.h"
  40. #include "lwip/sys.h"
  41. #include "lwip/memp.h"
  42. #include "lwip/mem.h"
  43. #include "lwip/init.h"
  44. #include "lwip/ip.h"
  45. #include "lwip/pbuf.h"
  46. #include "lwip/etharp.h"
  47. #include "netif/ethernet.h"
  48. #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
  49. #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
  50. #define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
  51. #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
  52. /* global variables */
  53. static tcpip_init_done_fn tcpip_init_done;
  54. static void *tcpip_init_done_arg;
  55. static sys_mbox_t tcpip_mbox;
  56. #if LWIP_TCPIP_CORE_LOCKING
  57. /** The global semaphore to lock the stack. */
  58. sys_mutex_t lock_tcpip_core;
  59. #endif /* LWIP_TCPIP_CORE_LOCKING */
  60. static void tcpip_thread_handle_msg(struct tcpip_msg *msg);
  61. #if !LWIP_TIMERS
  62. /* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
  63. #define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
  64. #else /* !LWIP_TIMERS */
  65. /* wait for a message, timeouts are processed while waiting */
  66. #define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg)
  67. /**
  68. * Wait (forever) for a message to arrive in an mbox.
  69. * While waiting, timeouts are processed.
  70. *
  71. * @param mbox the mbox to fetch the message from
  72. * @param msg the place to store the message
  73. */
  74. static void
  75. tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
  76. {
  77. u32_t sleeptime, res;
  78. again:
  79. LWIP_ASSERT_CORE_LOCKED();
  80. sleeptime = sys_timeouts_sleeptime();
  81. if (sleeptime == SYS_TIMEOUTS_SLEEPTIME_INFINITE) {
  82. UNLOCK_TCPIP_CORE();
  83. sys_arch_mbox_fetch(mbox, msg, 0);
  84. LOCK_TCPIP_CORE();
  85. return;
  86. } else if (sleeptime == 0) {
  87. sys_check_timeouts();
  88. /* We try again to fetch a message from the mbox. */
  89. goto again;
  90. }
  91. UNLOCK_TCPIP_CORE();
  92. res = sys_arch_mbox_fetch(mbox, msg, sleeptime);
  93. LOCK_TCPIP_CORE();
  94. if (res == SYS_ARCH_TIMEOUT) {
  95. /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
  96. before a message could be fetched. */
  97. sys_check_timeouts();
  98. /* We try again to fetch a message from the mbox. */
  99. goto again;
  100. }
  101. }
  102. #endif /* !LWIP_TIMERS */
  103. /**
  104. * The main lwIP thread. This thread has exclusive access to lwIP core functions
  105. * (unless access to them is not locked). Other threads communicate with this
  106. * thread using message boxes.
  107. *
  108. * It also starts all the timers to make sure they are running in the right
  109. * thread context.
  110. *
  111. * @param arg unused argument
  112. */
  113. static void
  114. tcpip_thread(void *arg)
  115. {
  116. struct tcpip_msg *msg;
  117. LWIP_UNUSED_ARG(arg);
  118. LWIP_MARK_TCPIP_THREAD();
  119. LOCK_TCPIP_CORE();
  120. if (tcpip_init_done != NULL) {
  121. tcpip_init_done(tcpip_init_done_arg);
  122. }
  123. while (1) { /* MAIN Loop */
  124. LWIP_TCPIP_THREAD_ALIVE();
  125. /* wait for a message, timeouts are processed while waiting */
  126. TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
  127. if (msg == NULL) {
  128. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
  129. LWIP_ASSERT("tcpip_thread: invalid message", 0);
  130. continue;
  131. }
  132. tcpip_thread_handle_msg(msg);
  133. }
  134. }
  135. /* Handle a single tcpip_msg
  136. * This is in its own function for access by tests only.
  137. */
  138. static void
  139. tcpip_thread_handle_msg(struct tcpip_msg *msg)
  140. {
  141. switch (msg->type) {
  142. #if !LWIP_TCPIP_CORE_LOCKING
  143. case TCPIP_MSG_API:
  144. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
  145. msg->msg.api_msg.function(msg->msg.api_msg.msg);
  146. break;
  147. case TCPIP_MSG_API_CALL:
  148. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
  149. msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
  150. sys_sem_signal(msg->msg.api_call.sem);
  151. break;
  152. case TCPIP_MSG_CALLBACK_STATIC_WAIT:
  153. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK WAIT message %p\n", (void *)msg));
  154. msg->msg.cb_wait.function(msg->msg.cb_wait.ctx);
  155. sys_sem_signal(msg->msg.cb_wait.sem);
  156. break;
  157. #endif /* !LWIP_TCPIP_CORE_LOCKING */
  158. #if !LWIP_TCPIP_CORE_LOCKING_INPUT
  159. case TCPIP_MSG_INPKT:
  160. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
  161. if (msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif) != ERR_OK) {
  162. pbuf_free(msg->msg.inp.p);
  163. }
  164. memp_free(MEMP_TCPIP_MSG_INPKT, msg);
  165. break;
  166. #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
  167. #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
  168. case TCPIP_MSG_TIMEOUT:
  169. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
  170. sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
  171. memp_free(MEMP_TCPIP_MSG_API, msg);
  172. break;
  173. case TCPIP_MSG_UNTIMEOUT:
  174. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
  175. sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
  176. memp_free(MEMP_TCPIP_MSG_API, msg);
  177. break;
  178. #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
  179. case TCPIP_MSG_CALLBACK:
  180. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
  181. msg->msg.cb.function(msg->msg.cb.ctx);
  182. memp_free(MEMP_TCPIP_MSG_API, msg);
  183. break;
  184. case TCPIP_MSG_CALLBACK_STATIC:
  185. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
  186. msg->msg.cb.function(msg->msg.cb.ctx);
  187. break;
  188. default:
  189. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
  190. LWIP_ASSERT("tcpip_thread: invalid message", 0);
  191. break;
  192. }
  193. }
  194. #ifdef TCPIP_THREAD_TEST
  195. /** Work on queued items in single-threaded test mode */
  196. int
  197. tcpip_thread_poll_one(void)
  198. {
  199. int ret = 0;
  200. struct tcpip_msg *msg;
  201. if (sys_arch_mbox_tryfetch(&tcpip_mbox, (void **)&msg) != SYS_MBOX_EMPTY) {
  202. LOCK_TCPIP_CORE();
  203. if (msg != NULL) {
  204. tcpip_thread_handle_msg(msg);
  205. ret = 1;
  206. }
  207. UNLOCK_TCPIP_CORE();
  208. }
  209. return ret;
  210. }
  211. #endif
  212. /**
  213. * Pass a received packet to tcpip_thread for input processing
  214. *
  215. * @param p the received packet
  216. * @param inp the network interface on which the packet was received
  217. * @param input_fn input function to call
  218. */
  219. err_t
  220. tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
  221. {
  222. #if LWIP_TCPIP_CORE_LOCKING_INPUT
  223. err_t ret;
  224. LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
  225. LOCK_TCPIP_CORE();
  226. ret = input_fn(p, inp);
  227. UNLOCK_TCPIP_CORE();
  228. return ret;
  229. #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
  230. struct tcpip_msg *msg;
  231. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  232. msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
  233. if (msg == NULL) {
  234. return ERR_MEM;
  235. }
  236. msg->type = TCPIP_MSG_INPKT;
  237. msg->msg.inp.p = p;
  238. msg->msg.inp.netif = inp;
  239. msg->msg.inp.input_fn = input_fn;
  240. if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
  241. memp_free(MEMP_TCPIP_MSG_INPKT, msg);
  242. return ERR_MEM;
  243. }
  244. return ERR_OK;
  245. #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
  246. }
  247. /**
  248. * @ingroup lwip_os
  249. * Pass a received packet to tcpip_thread for input processing with
  250. * ethernet_input or ip_input. Don't call directly, pass to netif_add()
  251. * and call netif->input().
  252. *
  253. * @param p the received packet, p->payload pointing to the Ethernet header or
  254. * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
  255. * NETIF_FLAG_ETHERNET flags)
  256. * @param inp the network interface on which the packet was received
  257. */
  258. err_t
  259. tcpip_input(struct pbuf *p, struct netif *inp)
  260. {
  261. #if LWIP_ETHERNET
  262. if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
  263. return tcpip_inpkt(p, inp, ethernet_input);
  264. } else
  265. #endif /* LWIP_ETHERNET */
  266. return tcpip_inpkt(p, inp, ip_input);
  267. }
  268. /**
  269. * @ingroup lwip_os
  270. * Call a specific function in the thread context of
  271. * tcpip_thread for easy access synchronization.
  272. * A function called in that way may access lwIP core code
  273. * without fearing concurrent access.
  274. * Blocks until the request is posted.
  275. * Must not be called from interrupt context!
  276. *
  277. * @param function the function to call
  278. * @param ctx parameter passed to f
  279. * @return ERR_OK if the function was called, another err_t if not
  280. *
  281. * @see tcpip_try_callback
  282. */
  283. err_t
  284. tcpip_callback(tcpip_callback_fn function, void *ctx)
  285. {
  286. struct tcpip_msg *msg;
  287. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  288. msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  289. if (msg == NULL) {
  290. return ERR_MEM;
  291. }
  292. msg->type = TCPIP_MSG_CALLBACK;
  293. msg->msg.cb.function = function;
  294. msg->msg.cb.ctx = ctx;
  295. sys_mbox_post(&tcpip_mbox, msg);
  296. return ERR_OK;
  297. }
  298. /**
  299. * @ingroup lwip_os
  300. * Call a specific function in the thread context of
  301. * tcpip_thread for easy access synchronization.
  302. * A function called in that way may access lwIP core code
  303. * without fearing concurrent access.
  304. * Does NOT block when the request cannot be posted because the
  305. * tcpip_mbox is full, but returns ERR_MEM instead.
  306. * Can be called from interrupt context.
  307. *
  308. * @param function the function to call
  309. * @param ctx parameter passed to f
  310. * @return ERR_OK if the function was called, another err_t if not
  311. *
  312. * @see tcpip_callback
  313. */
  314. err_t
  315. tcpip_try_callback(tcpip_callback_fn function, void *ctx)
  316. {
  317. struct tcpip_msg *msg;
  318. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  319. msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  320. if (msg == NULL) {
  321. return ERR_MEM;
  322. }
  323. msg->type = TCPIP_MSG_CALLBACK;
  324. msg->msg.cb.function = function;
  325. msg->msg.cb.ctx = ctx;
  326. if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
  327. memp_free(MEMP_TCPIP_MSG_API, msg);
  328. return ERR_MEM;
  329. }
  330. return ERR_OK;
  331. }
  332. #if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
  333. /**
  334. * call sys_timeout in tcpip_thread
  335. *
  336. * @param msecs time in milliseconds for timeout
  337. * @param h function to be called on timeout
  338. * @param arg argument to pass to timeout function h
  339. * @return ERR_MEM on memory error, ERR_OK otherwise
  340. */
  341. err_t
  342. tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
  343. {
  344. struct tcpip_msg *msg;
  345. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  346. msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  347. if (msg == NULL) {
  348. return ERR_MEM;
  349. }
  350. msg->type = TCPIP_MSG_TIMEOUT;
  351. msg->msg.tmo.msecs = msecs;
  352. msg->msg.tmo.h = h;
  353. msg->msg.tmo.arg = arg;
  354. sys_mbox_post(&tcpip_mbox, msg);
  355. return ERR_OK;
  356. }
  357. /**
  358. * call sys_untimeout in tcpip_thread
  359. *
  360. * @param h function to be called on timeout
  361. * @param arg argument to pass to timeout function h
  362. * @return ERR_MEM on memory error, ERR_OK otherwise
  363. */
  364. err_t
  365. tcpip_untimeout(sys_timeout_handler h, void *arg)
  366. {
  367. struct tcpip_msg *msg;
  368. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  369. msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  370. if (msg == NULL) {
  371. return ERR_MEM;
  372. }
  373. msg->type = TCPIP_MSG_UNTIMEOUT;
  374. msg->msg.tmo.h = h;
  375. msg->msg.tmo.arg = arg;
  376. sys_mbox_post(&tcpip_mbox, msg);
  377. return ERR_OK;
  378. }
  379. #endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
  380. /**
  381. * Sends a message to TCPIP thread to call a function. Caller thread blocks on
  382. * on a provided semaphore, which is NOT automatically signalled by TCPIP thread,
  383. * this has to be done by the user.
  384. * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way
  385. * with least runtime overhead.
  386. *
  387. * @param fn function to be called from TCPIP thread
  388. * @param apimsg argument to API function
  389. * @param sem semaphore to wait on
  390. * @return ERR_OK if the function was called, another err_t if not
  391. */
  392. err_t
  393. tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
  394. {
  395. #if LWIP_TCPIP_CORE_LOCKING
  396. LWIP_UNUSED_ARG(sem);
  397. LOCK_TCPIP_CORE();
  398. fn(apimsg);
  399. UNLOCK_TCPIP_CORE();
  400. return ERR_OK;
  401. #else /* LWIP_TCPIP_CORE_LOCKING */
  402. TCPIP_MSG_VAR_DECLARE(msg);
  403. LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
  404. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  405. TCPIP_MSG_VAR_ALLOC(msg);
  406. TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
  407. TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
  408. TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
  409. sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
  410. sys_arch_sem_wait(sem, 0);
  411. TCPIP_MSG_VAR_FREE(msg);
  412. return ERR_OK;
  413. #endif /* LWIP_TCPIP_CORE_LOCKING */
  414. }
  415. /**
  416. * Synchronously calls function in TCPIP thread and waits for its completion.
  417. * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
  418. * LWIP_NETCONN_SEM_PER_THREAD.
  419. * If not, a semaphore is created and destroyed on every call which is usually
  420. * an expensive/slow operation.
  421. * @param fn Function to call
  422. * @param call Call parameters
  423. * @return Return value from tcpip_api_call_fn
  424. */
  425. err_t
  426. tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
  427. {
  428. #if LWIP_TCPIP_CORE_LOCKING
  429. err_t err;
  430. LOCK_TCPIP_CORE();
  431. err = fn(call);
  432. UNLOCK_TCPIP_CORE();
  433. return err;
  434. #else /* LWIP_TCPIP_CORE_LOCKING */
  435. TCPIP_MSG_VAR_DECLARE(msg);
  436. #if !LWIP_NETCONN_SEM_PER_THREAD
  437. err_t err = sys_sem_new(&call->sem, 0);
  438. if (err != ERR_OK) {
  439. return err;
  440. }
  441. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  442. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  443. TCPIP_MSG_VAR_ALLOC(msg);
  444. TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
  445. TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
  446. TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
  447. #if LWIP_NETCONN_SEM_PER_THREAD
  448. TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
  449. #else /* LWIP_NETCONN_SEM_PER_THREAD */
  450. TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
  451. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  452. sys_mbox_post(&tcpip_mbox, &TCPIP_MSG_VAR_REF(msg));
  453. sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
  454. TCPIP_MSG_VAR_FREE(msg);
  455. #if !LWIP_NETCONN_SEM_PER_THREAD
  456. sys_sem_free(&call->sem);
  457. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  458. return call->err;
  459. #endif /* LWIP_TCPIP_CORE_LOCKING */
  460. }
  461. /**
  462. * @ingroup lwip_os
  463. * Allocate a structure for a static callback message and initialize it.
  464. * The message has a special type such that lwIP never frees it.
  465. * This is intended to be used to send "static" messages from interrupt context,
  466. * e.g. the message is allocated once and posted several times from an IRQ
  467. * using tcpip_callbackmsg_trycallback().
  468. * Example usage: Trigger execution of an ethernet IRQ DPC routine in lwIP thread context.
  469. *
  470. * @param function the function to call
  471. * @param ctx parameter passed to function
  472. * @return a struct pointer to pass to tcpip_callbackmsg_trycallback().
  473. *
  474. * @see tcpip_callbackmsg_trycallback()
  475. * @see tcpip_callbackmsg_delete()
  476. */
  477. struct tcpip_callback_msg *
  478. tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
  479. {
  480. struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
  481. if (msg == NULL) {
  482. return NULL;
  483. }
  484. msg->type = TCPIP_MSG_CALLBACK_STATIC;
  485. msg->msg.cb.function = function;
  486. msg->msg.cb.ctx = ctx;
  487. return (struct tcpip_callback_msg *)msg;
  488. }
  489. /**
  490. * @ingroup lwip_os
  491. * Free a callback message allocated by tcpip_callbackmsg_new().
  492. *
  493. * @param msg the message to free
  494. *
  495. * @see tcpip_callbackmsg_new()
  496. */
  497. void
  498. tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg)
  499. {
  500. memp_free(MEMP_TCPIP_MSG_API, msg);
  501. }
  502. /**
  503. * @ingroup lwip_os
  504. * Try to post a callback-message to the tcpip_thread tcpip_mbox.
  505. *
  506. * @param msg pointer to the message to post
  507. * @return sys_mbox_trypost() return code
  508. *
  509. * @see tcpip_callbackmsg_new()
  510. */
  511. err_t
  512. tcpip_callbackmsg_trycallback(struct tcpip_callback_msg *msg)
  513. {
  514. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  515. return sys_mbox_trypost(&tcpip_mbox, msg);
  516. }
  517. /**
  518. * @ingroup lwip_os
  519. * Try to post a callback-message to the tcpip_thread mbox.
  520. * Same as @ref tcpip_callbackmsg_trycallback but calls sys_mbox_trypost_fromisr(),
  521. * mainly to help FreeRTOS, where calls differ between task level and ISR level.
  522. *
  523. * @param msg pointer to the message to post
  524. * @return sys_mbox_trypost_fromisr() return code (without change, so this
  525. * knowledge can be used to e.g. propagate "bool needs_scheduling")
  526. *
  527. * @see tcpip_callbackmsg_new()
  528. */
  529. err_t
  530. tcpip_callbackmsg_trycallback_fromisr(struct tcpip_callback_msg *msg)
  531. {
  532. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  533. return sys_mbox_trypost_fromisr(&tcpip_mbox, msg);
  534. }
  535. /**
  536. * Sends a message to TCPIP thread to call a function. Caller thread blocks
  537. * until the function returns.
  538. * It is recommended to use LWIP_TCPIP_CORE_LOCKING (preferred) or
  539. * LWIP_NETCONN_SEM_PER_THREAD.
  540. * If not, a semaphore is created and destroyed on every call which is usually
  541. * an expensive/slow operation.
  542. *
  543. * @param function the function to call
  544. * @param ctx parameter passed to f
  545. * @return ERR_OK if the function was called, another err_t if not
  546. */
  547. err_t
  548. tcpip_callback_wait(tcpip_callback_fn function, void *ctx)
  549. {
  550. #if LWIP_TCPIP_CORE_LOCKING
  551. LOCK_TCPIP_CORE();
  552. function(ctx);
  553. UNLOCK_TCPIP_CORE();
  554. return ERR_OK;
  555. #else /* LWIP_TCPIP_CORE_LOCKING */
  556. err_t err;
  557. sys_sem_t sem;
  558. struct tcpip_msg msg;
  559. LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(tcpip_mbox));
  560. err = sys_sem_new(&sem, 0);
  561. if (err != ERR_OK) {
  562. return err;
  563. }
  564. msg.type = TCPIP_MSG_CALLBACK_STATIC_WAIT;
  565. msg.msg.cb_wait.function = function;
  566. msg.msg.cb_wait.ctx = ctx;
  567. msg.msg.cb_wait.sem = &sem;
  568. sys_mbox_post(&tcpip_mbox, &msg);
  569. sys_arch_sem_wait(&sem, 0);
  570. sys_sem_free(&sem);
  571. return ERR_OK;
  572. #endif /* LWIP_TCPIP_CORE_LOCKING */
  573. }
  574. /**
  575. * @ingroup lwip_os
  576. * Initialize this module:
  577. * - initialize all sub modules
  578. * - start the tcpip_thread
  579. *
  580. * @param initfunc a function to call when tcpip_thread is running and finished initializing
  581. * @param arg argument to pass to initfunc
  582. */
  583. void
  584. tcpip_init(tcpip_init_done_fn initfunc, void *arg)
  585. {
  586. lwip_init();
  587. tcpip_init_done = initfunc;
  588. tcpip_init_done_arg = arg;
  589. if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
  590. LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
  591. }
  592. #if LWIP_TCPIP_CORE_LOCKING
  593. if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
  594. LWIP_ASSERT("failed to create lock_tcpip_core", 0);
  595. }
  596. #endif /* LWIP_TCPIP_CORE_LOCKING */
  597. sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
  598. }
  599. /**
  600. * Simple callback function used with tcpip_callback to free a pbuf
  601. * (pbuf_free has a wrong signature for tcpip_callback)
  602. *
  603. * @param p The pbuf (chain) to be dereferenced.
  604. */
  605. static void
  606. pbuf_free_int(void *p)
  607. {
  608. struct pbuf *q = (struct pbuf *)p;
  609. pbuf_free(q);
  610. }
  611. /**
  612. * A simple wrapper function that allows you to free a pbuf from interrupt context.
  613. *
  614. * @param p The pbuf (chain) to be dereferenced.
  615. * @return ERR_OK if callback could be enqueued, an err_t if not
  616. */
  617. err_t
  618. pbuf_free_callback(struct pbuf *p)
  619. {
  620. return tcpip_try_callback(pbuf_free_int, p);
  621. }
  622. /**
  623. * A simple wrapper function that allows you to free heap memory from
  624. * interrupt context.
  625. *
  626. * @param m the heap memory to free
  627. * @return ERR_OK if callback could be enqueued, an err_t if not
  628. */
  629. err_t
  630. mem_free_callback(void *m)
  631. {
  632. return tcpip_try_callback(mem_free, m);
  633. }
  634. #endif /* !NO_SYS */