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