The Pedigree Project 0.1
tcpip.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
26/*
27 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without modification,
31 * are permitted provided that the following conditions are met:
32 *
33 * 1. Redistributions of source code must retain the above copyright notice,
34 * this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright notice,
36 * this list of conditions and the following disclaimer in the documentation
37 * and/or other materials provided with the distribution.
38 * 3. The name of the author may not be used to endorse or promote products
39 * derived from this software without specific prior written permission.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
43 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
44 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
46 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
49 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
50 * OF SUCH DAMAGE.
51 *
52 * This file is part of the lwIP TCP/IP stack.
53 *
54 * Author: Adam Dunkels <adam@sics.se>
55 *
56 */
57
58#include "lwip/opt.h"
59
60#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
61
63#include "lwip/sys.h"
64#include "lwip/memp.h"
65#include "lwip/mem.h"
66#include "lwip/init.h"
67#include "lwip/ip.h"
68#include "lwip/pbuf.h"
69#include "lwip/etharp.h"
70#include "netif/ethernet.h"
71
72#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
73#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
74#define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name, ERR_MEM)
75#define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name)
76
77/* global variables */
78static tcpip_init_done_fn tcpip_init_done;
79static void *tcpip_init_done_arg;
80static sys_mbox_t mbox;
81static sys_thread_t tcpip_thread_handle;
82static struct tcpip_msg tcpip_shutdown_msg;
83enum tcpip_lifecycle_state {
84 TCPIP_STATE_RUNNING = 0,
85 TCPIP_STATE_STOPPING = 1,
86 TCPIP_STATE_STOPPED = 2,
87 TCPIP_STATE_FAILED = 3,
88 TCPIP_STATE_INITIALIZING = 4
89};
90static u8_t tcpip_shutdown_state = TCPIP_STATE_STOPPED;
91static u32_t tcpip_active_producers;
92
93static int
94tcpip_producer_enter(void)
95{
96 if (__atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE) !=
97 TCPIP_STATE_RUNNING) {
98 return 0;
99 }
100
101 __atomic_add_fetch(&tcpip_active_producers, 1, __ATOMIC_ACQ_REL);
102 if (__atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE) !=
103 TCPIP_STATE_RUNNING) {
104 __atomic_sub_fetch(&tcpip_active_producers, 1, __ATOMIC_RELEASE);
105 return 0;
106 }
107 return 1;
108}
109
110static void
111tcpip_producer_leave(void)
112{
113 LWIP_ASSERT("tcpip producer admission underflow",
114 __atomic_load_n(&tcpip_active_producers, __ATOMIC_RELAXED) != 0);
115 __atomic_sub_fetch(&tcpip_active_producers, 1, __ATOMIC_RELEASE);
116}
117
118#if LWIP_TCPIP_CORE_LOCKING
120sys_mutex_t lock_tcpip_core;
121#endif /* LWIP_TCPIP_CORE_LOCKING */
122
123#if LWIP_TIMERS
124/* wait for a message, timeouts are processed while waiting */
125#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
126#else /* LWIP_TIMERS */
127/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
128#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
129#endif /* LWIP_TIMERS */
130
141static void
142tcpip_thread(void *arg)
143{
144 struct tcpip_msg *msg;
145 LWIP_UNUSED_ARG(arg);
146
147 while (__atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE) ==
148 TCPIP_STATE_INITIALIZING) {
149 sys_msleep(1);
150 }
151 LWIP_ASSERT("tcpip_thread started outside running state",
152 __atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE) ==
153 TCPIP_STATE_RUNNING);
154
155 if (tcpip_init_done != NULL) {
156 tcpip_init_done(tcpip_init_done_arg);
157 }
158
159 LOCK_TCPIP_CORE();
160 while (1) { /* MAIN Loop */
161 UNLOCK_TCPIP_CORE();
163 /* wait for a message, timeouts are processed while waiting */
164 TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
165 LOCK_TCPIP_CORE();
166 if (msg == NULL) {
167 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
168 LWIP_ASSERT("tcpip_thread: invalid message", 0);
169 continue;
170 }
171 switch (msg->type) {
172#if !LWIP_TCPIP_CORE_LOCKING
173 case TCPIP_MSG_API:
174 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
175 msg->msg.api_msg.function(msg->msg.api_msg.msg);
176 break;
177 case TCPIP_MSG_API_CALL:
178 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API CALL message %p\n", (void *)msg));
179 msg->msg.api_call.arg->err = msg->msg.api_call.function(msg->msg.api_call.arg);
180 sys_sem_signal(msg->msg.api_call.sem);
181 break;
182#endif /* !LWIP_TCPIP_CORE_LOCKING */
183
184#if !LWIP_TCPIP_CORE_LOCKING_INPUT
185 case TCPIP_MSG_INPKT:
186 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
187 msg->msg.inp.input_fn(msg->msg.inp.p, msg->msg.inp.netif);
188 memp_free(MEMP_TCPIP_MSG_INPKT, msg);
189 break;
190#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
191
192#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
193 case TCPIP_MSG_TIMEOUT:
194 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
195 sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
196 memp_free(MEMP_TCPIP_MSG_API, msg);
197 break;
198 case TCPIP_MSG_UNTIMEOUT:
199 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
200 sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
201 memp_free(MEMP_TCPIP_MSG_API, msg);
202 break;
203#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
204
205 case TCPIP_MSG_CALLBACK:
206 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
207 msg->msg.cb.function(msg->msg.cb.ctx);
208 memp_free(MEMP_TCPIP_MSG_API, msg);
209 break;
210
211 case TCPIP_MSG_CALLBACK_STATIC:
212 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
213 msg->msg.cb.function(msg->msg.cb.ctx);
214 break;
215
216 case TCPIP_MSG_SHUTDOWN:
217 UNLOCK_TCPIP_CORE();
218 return;
219
220 default:
221 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
222 LWIP_ASSERT("tcpip_thread: invalid message", 0);
223 break;
224 }
225 }
226}
227
235err_t
236tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
237{
238 if (!tcpip_producer_enter()) {
239 return ERR_CLSD;
240 }
241#if LWIP_TCPIP_CORE_LOCKING_INPUT
242 err_t ret;
243 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
244 LOCK_TCPIP_CORE();
245 ret = input_fn(p, inp);
246 UNLOCK_TCPIP_CORE();
247 tcpip_producer_leave();
248 return ret;
249#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
250 struct tcpip_msg *msg;
251
252 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
253
254 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
255 if (msg == NULL) {
256 tcpip_producer_leave();
257 return ERR_MEM;
258 }
259
260 msg->type = TCPIP_MSG_INPKT;
261 msg->msg.inp.p = p;
262 msg->msg.inp.netif = inp;
263 msg->msg.inp.input_fn = input_fn;
264 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
265 memp_free(MEMP_TCPIP_MSG_INPKT, msg);
266 tcpip_producer_leave();
267 return ERR_MEM;
268 }
269 tcpip_producer_leave();
270 return ERR_OK;
271#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
272}
273
285err_t
286tcpip_input(struct pbuf *p, struct netif *inp)
287{
288#if LWIP_ETHERNET
290 return tcpip_inpkt(p, inp, ethernet_input);
291 } else
292#endif /* LWIP_ETHERNET */
293 return tcpip_inpkt(p, inp, ip_input);
294}
295
307static err_t
308tcpip_callback_with_block_admitted(tcpip_callback_fn function, void *ctx, u8_t block)
309{
310 struct tcpip_msg *msg;
311
312 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
313
314 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
315 if (msg == NULL) {
316 return ERR_MEM;
317 }
318
319 msg->type = TCPIP_MSG_CALLBACK;
320 msg->msg.cb.function = function;
321 msg->msg.cb.ctx = ctx;
322 if (block) {
323 sys_mbox_post(&mbox, msg);
324 } else {
325 if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
326 memp_free(MEMP_TCPIP_MSG_API, msg);
327 return ERR_MEM;
328 }
329 }
330 return ERR_OK;
331}
332
333err_t
334tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
335{
336 err_t err;
337
338 if (!tcpip_producer_enter()) {
339 return ERR_CLSD;
340 }
341 err = tcpip_callback_with_block_admitted(function, ctx, block);
342 tcpip_producer_leave();
343 return err;
344}
345
347 tcpip_callback_fn function;
348 void *ctx;
349 sys_sem_t completion;
350 u8_t retired;
351};
352
353static void
354tcpip_callback_wait_shim(void *arg)
355{
356 struct tcpip_callback_wait_context *context =
357 (struct tcpip_callback_wait_context *)arg;
358 context->function(context->ctx);
359 sys_sem_signal(&context->completion);
360 /* The caller may release callback text and context after this store. */
361 __atomic_store_n(&context->retired, 1, __ATOMIC_RELEASE);
362}
363
364err_t
366{
367 struct tcpip_callback_wait_context context;
368 err_t err;
369
370 if (function == NULL) {
371 return ERR_ARG;
372 }
373 if (!tcpip_producer_enter()) {
374 return ERR_CLSD;
375 }
377 __atomic_load_n(&tcpip_thread_handle, __ATOMIC_ACQUIRE))) {
378 function(ctx);
379 tcpip_producer_leave();
380 return ERR_OK;
381 }
382 context.function = function;
383 context.ctx = ctx;
384 context.retired = 0;
385 err = sys_sem_new(&context.completion, 0);
386 if (err != ERR_OK) {
387 tcpip_producer_leave();
388 return err;
389 }
390
391 err = tcpip_callback_with_block_admitted(tcpip_callback_wait_shim, &context, 1);
392 if (err == ERR_OK) {
393 sys_arch_sem_wait(&context.completion, 0);
394 while (!__atomic_load_n(&context.retired, __ATOMIC_ACQUIRE)) {
395 }
396 }
397 sys_sem_free(&context.completion);
398 tcpip_producer_leave();
399 return err;
400}
401
402#if LWIP_TCPIP_TIMEOUT && LWIP_TIMERS
411err_t
412tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
413{
414 struct tcpip_msg *msg;
415
416 if (!tcpip_producer_enter()) {
417 return ERR_CLSD;
418 }
419 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
420
421 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
422 if (msg == NULL) {
423 tcpip_producer_leave();
424 return ERR_MEM;
425 }
426
427 msg->type = TCPIP_MSG_TIMEOUT;
428 msg->msg.tmo.msecs = msecs;
429 msg->msg.tmo.h = h;
430 msg->msg.tmo.arg = arg;
431 sys_mbox_post(&mbox, msg);
432 tcpip_producer_leave();
433 return ERR_OK;
434}
435
443err_t
444tcpip_untimeout(sys_timeout_handler h, void *arg)
445{
446 struct tcpip_msg *msg;
447
448 if (!tcpip_producer_enter()) {
449 return ERR_CLSD;
450 }
451 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
452
453 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
454 if (msg == NULL) {
455 tcpip_producer_leave();
456 return ERR_MEM;
457 }
458
459 msg->type = TCPIP_MSG_UNTIMEOUT;
460 msg->msg.tmo.h = h;
461 msg->msg.tmo.arg = arg;
462 sys_mbox_post(&mbox, msg);
463 tcpip_producer_leave();
464 return ERR_OK;
465}
466#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
467
468
481err_t
482tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem)
483{
484 if (!tcpip_producer_enter()) {
485 return ERR_CLSD;
486 }
487#if LWIP_TCPIP_CORE_LOCKING
488 LWIP_UNUSED_ARG(sem);
489 LOCK_TCPIP_CORE();
490 fn(apimsg);
491 UNLOCK_TCPIP_CORE();
492 tcpip_producer_leave();
493 return ERR_OK;
494#else /* LWIP_TCPIP_CORE_LOCKING */
495 TCPIP_MSG_VAR_DECLARE(msg);
496
497 LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem));
498 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
499
500#if LWIP_MPU_COMPATIBLE
501 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
502 if (msg == NULL) {
503 tcpip_producer_leave();
504 return ERR_MEM;
505 }
506#endif /* LWIP_MPU_COMPATIBLE */
507 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API;
508 TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn;
509 TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg;
510 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
511 sys_arch_sem_wait(sem, 0);
512 TCPIP_MSG_VAR_FREE(msg);
513 tcpip_producer_leave();
514 return ERR_OK;
515#endif /* LWIP_TCPIP_CORE_LOCKING */
516}
517
528err_t
529tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
530{
531 if (!tcpip_producer_enter()) {
532 return ERR_CLSD;
533 }
534#if LWIP_TCPIP_CORE_LOCKING
535 err_t err;
536 LOCK_TCPIP_CORE();
537 err = fn(call);
538 UNLOCK_TCPIP_CORE();
539 tcpip_producer_leave();
540 return err;
541#else /* LWIP_TCPIP_CORE_LOCKING */
542 TCPIP_MSG_VAR_DECLARE(msg);
543
544#if !LWIP_NETCONN_SEM_PER_THREAD
545 err_t err = sys_sem_new(&call->sem, 0);
546 if (err != ERR_OK) {
547 tcpip_producer_leave();
548 return err;
549 }
550#endif /* LWIP_NETCONN_SEM_PER_THREAD */
551
552 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
553
554#if LWIP_MPU_COMPATIBLE
555 msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
556 if (msg == NULL) {
557#if !LWIP_NETCONN_SEM_PER_THREAD
558 sys_sem_free(&call->sem);
559#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
560 tcpip_producer_leave();
561 return ERR_MEM;
562 }
563#endif /* LWIP_MPU_COMPATIBLE */
564 TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API_CALL;
565 TCPIP_MSG_VAR_REF(msg).msg.api_call.arg = call;
566 TCPIP_MSG_VAR_REF(msg).msg.api_call.function = fn;
567#if LWIP_NETCONN_SEM_PER_THREAD
568 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = LWIP_NETCONN_THREAD_SEM_GET();
569#else /* LWIP_NETCONN_SEM_PER_THREAD */
570 TCPIP_MSG_VAR_REF(msg).msg.api_call.sem = &call->sem;
571#endif /* LWIP_NETCONN_SEM_PER_THREAD */
572 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg));
573 sys_arch_sem_wait(TCPIP_MSG_VAR_REF(msg).msg.api_call.sem, 0);
574 TCPIP_MSG_VAR_FREE(msg);
575
576#if !LWIP_NETCONN_SEM_PER_THREAD
577 sys_sem_free(&call->sem);
578#endif /* LWIP_NETCONN_SEM_PER_THREAD */
579
580 tcpip_producer_leave();
581 return call->err;
582#endif /* LWIP_TCPIP_CORE_LOCKING */
583}
584
593struct tcpip_callback_msg*
595{
596 struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
597 if (msg == NULL) {
598 return NULL;
599 }
600 msg->type = TCPIP_MSG_CALLBACK_STATIC;
601 msg->msg.cb.function = function;
602 msg->msg.cb.ctx = ctx;
603 return (struct tcpip_callback_msg*)msg;
604}
605
611void
612tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
613{
614 memp_free(MEMP_TCPIP_MSG_API, msg);
615}
616
624err_t
625tcpip_trycallback(struct tcpip_callback_msg* msg)
626{
627 err_t err;
628
629 if (!tcpip_producer_enter()) {
630 return ERR_CLSD;
631 }
632 LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
633 err = sys_mbox_trypost(&mbox, msg);
634 tcpip_producer_leave();
635 return err;
636}
637
647void
648tcpip_init(tcpip_init_done_fn initfunc, void *arg)
649{
650 u8_t state = TCPIP_STATE_STOPPED;
651 if (!__atomic_compare_exchange_n(
652 &tcpip_shutdown_state, &state, TCPIP_STATE_INITIALIZING, 0,
653 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
654 LWIP_ASSERT("tcpip_init called outside stopped state", 0);
655 return;
656 }
657 LWIP_ASSERT("tcpip_init with active producers",
658 __atomic_load_n(&tcpip_active_producers, __ATOMIC_ACQUIRE) == 0);
659 lwip_init();
660
661 tcpip_init_done = initfunc;
662 tcpip_init_done_arg = arg;
663 if (sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
664 LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
665 }
666#if LWIP_TCPIP_CORE_LOCKING
667 if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
668 LWIP_ASSERT("failed to create lock_tcpip_core", 0);
669 }
670#endif /* LWIP_TCPIP_CORE_LOCKING */
671
672 sys_thread_t thread = sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL,
674 LWIP_ASSERT("failed to create tcpip_thread", thread != NULL);
675 __atomic_store_n(&tcpip_thread_handle, thread, __ATOMIC_RELEASE);
676 __atomic_store_n(&tcpip_shutdown_state, TCPIP_STATE_RUNNING, __ATOMIC_RELEASE);
677}
678
679err_t
681{
682 u8_t state = __atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE);
683
684 if (state == TCPIP_STATE_STOPPED) {
685 return ERR_OK;
686 }
687 if (state == TCPIP_STATE_FAILED) {
688 return ERR_IF;
689 }
690 if (state == TCPIP_STATE_STOPPING || state == TCPIP_STATE_INITIALIZING) {
691 return ERR_INPROGRESS;
692 }
693
694 if (!tcpip_producer_enter()) {
695 state = __atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE);
696 return state == TCPIP_STATE_STOPPED
697 ? ERR_OK
698 : (state == TCPIP_STATE_FAILED ? ERR_IF : ERR_INPROGRESS);
699 }
700
701 sys_thread_t thread =
702 __atomic_load_n(&tcpip_thread_handle, __ATOMIC_ACQUIRE);
703 const int current = sys_thread_is_current(thread);
704 tcpip_producer_leave();
705 if (current) {
706 return ERR_USE;
707 }
708
709 state = __atomic_load_n(&tcpip_shutdown_state, __ATOMIC_ACQUIRE);
710 if (state != TCPIP_STATE_RUNNING) {
711 return state == TCPIP_STATE_STOPPED
712 ? ERR_OK
713 : (state == TCPIP_STATE_FAILED ? ERR_IF : ERR_INPROGRESS);
714 }
715
716 state = TCPIP_STATE_RUNNING;
717 if (!__atomic_compare_exchange_n(
718 &tcpip_shutdown_state, &state, TCPIP_STATE_STOPPING, 0,
719 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
720 return state == TCPIP_STATE_STOPPED
721 ? ERR_OK
722 : (state == TCPIP_STATE_FAILED ? ERR_IF : ERR_INPROGRESS);
723 }
724
725 while (__atomic_load_n(&tcpip_active_producers, __ATOMIC_ACQUIRE) != 0) {
726 sys_msleep(1);
727 }
728
729 tcpip_shutdown_msg.type = TCPIP_MSG_SHUTDOWN;
730 if (sys_mbox_post_and_close(&mbox, &tcpip_shutdown_msg) != ERR_OK) {
731 __atomic_store_n(&tcpip_shutdown_state, TCPIP_STATE_FAILED, __ATOMIC_RELEASE);
732 return ERR_CLSD;
733 }
734 thread = __atomic_load_n(&tcpip_thread_handle, __ATOMIC_ACQUIRE);
735 if (!sys_thread_join(thread)) {
736 __atomic_store_n(&tcpip_shutdown_state, TCPIP_STATE_FAILED, __ATOMIC_RELEASE);
737 return ERR_IF;
738 }
739 __atomic_store_n(&tcpip_thread_handle, NULL, __ATOMIC_RELEASE);
740
741#if LWIP_TCPIP_CORE_LOCKING
742 if (sys_mutex_valid(&lock_tcpip_core)) {
743 sys_mutex_free(&lock_tcpip_core);
744 sys_mutex_set_invalid(&lock_tcpip_core);
745 }
746#endif /* LWIP_TCPIP_CORE_LOCKING */
747 if (sys_mbox_valid_val(mbox)) {
748 sys_mbox_free(&mbox);
750 }
751 tcpip_init_done = NULL;
752 tcpip_init_done_arg = NULL;
753 __atomic_store_n(&tcpip_shutdown_state, TCPIP_STATE_STOPPED, __ATOMIC_RELEASE);
754 return ERR_OK;
755}
756
763static void
764pbuf_free_int(void *p)
765{
766 struct pbuf *q = (struct pbuf *)p;
767 pbuf_free(q);
768}
769
776err_t
778{
779 return tcpip_callback_with_block(pbuf_free_int, p, 0);
780}
781
789err_t
791{
792 return tcpip_callback_with_block(mem_free, m, 0);
793}
794
795#endif /* !NO_SYS */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
#define LWIP_UNUSED_ARG(x)
Definition arch.h:327
s8_t err_t
Definition err.h:76
@ ERR_INPROGRESS
Definition err.h:92
@ ERR_USE
Definition err.h:98
@ ERR_IF
Definition err.h:106
@ ERR_OK
Definition err.h:82
@ ERR_CLSD
Definition err.h:113
@ ERR_MEM
Definition err.h:84
@ ERR_ARG
Definition err.h:115
#define TCPIP_DEBUG
Definition opt.h:2833
#define TCPIP_THREAD_NAME
Definition opt.h:1558
#define TCPIP_THREAD_PRIO
Definition opt.h:1576
#define LWIP_TCPIP_THREAD_ALIVE()
Definition opt.h:1593
#define TCPIP_MBOX_SIZE
Definition opt.h:1585
#define TCPIP_THREAD_STACKSIZE
Definition opt.h:1567
#define NETIF_FLAG_ETHERNET
Definition netif.h:114
#define NETIF_FLAG_ETHARP
Definition netif.h:110
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:266
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:313
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Definition sys_arch.cc:250
void sys_mbox_free(sys_mbox_t *mbox)
Definition sys_arch.cc:255
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
Definition sys_arch.cc:104
void sys_msleep(u32_t ms)
Definition sys.c:112
void sys_mutex_free(sys_mutex_t *mutex)
Definition sys_arch.cc:355
err_t sys_mutex_new(sys_mutex_t *mutex)
Definition sys_arch.cc:338
void sys_mutex_set_invalid(sys_mutex_t *mutex)
Definition sys_arch.cc:365
int sys_mutex_valid(sys_mutex_t *mutex)
Definition sys_arch.cc:361
int sys_sem_valid(sys_sem_t *sem)
Definition sys_arch.cc:162
void sys_sem_free(sys_sem_t *sem)
Definition sys_arch.cc:152
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Definition sys_arch.cc:189
void sys_sem_signal(sys_sem_t *sem)
Definition sys_arch.cc:180
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition sys_arch.cc:138
void mem_free(void *rmem)
Definition mem.c:438
void * memp_malloc(memp_t type)
Definition memp.c:404
void memp_free(memp_t type, void *mem)
Definition memp.c:488
void lwip_init(void)
err_t(* netif_input_fn)(struct pbuf *p, struct netif *inp)
Definition netif.h:181
Definition netif.h:244
u8_t flags
Definition netif.h:324
Definition pbuf.h:161
int sys_thread_is_current(sys_thread_t thread)
Definition sys_arch.cc:126
int sys_thread_join(sys_thread_t thread)
Definition sys_arch.cc:114
#define sys_mbox_valid_val(mbox)
Definition sys.h:332
#define sys_mbox_set_invalid_val(mbox)
Definition sys.h:338
err_t sys_mbox_post_and_close(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:272
struct tcpip_callback_msg * tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
Definition tcpip.c:594
err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
Definition tcpip.c:482
void tcpip_init(tcpip_init_done_fn initfunc, void *arg)
Definition tcpip.c:648
err_t tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
Definition tcpip.c:529
err_t mem_free_callback(void *m)
Definition tcpip.c:790
err_t pbuf_free_callback(struct pbuf *p)
Definition tcpip.c:777
err_t tcpip_callback_wait(tcpip_callback_fn function, void *ctx)
Definition tcpip.c:365
err_t tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
Definition tcpip.c:236
err_t tcpip_shutdown(void)
Definition tcpip.c:680
void tcpip_callbackmsg_delete(struct tcpip_callback_msg *msg)
Definition tcpip.c:612
err_t tcpip_trycallback(struct tcpip_callback_msg *msg)
Definition tcpip.c:625
err_t tcpip_input(struct pbuf *p, struct netif *inp)
Definition tcpip.c:286
void(* tcpip_callback_fn)(void *ctx)
Definition tcpip.h:89
void(* tcpip_init_done_fn)(void *arg)
Definition tcpip.h:87