• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * Sequential API Internal module
4  *
5  */
6 
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  *
35  * Author: Adam Dunkels <adam@sics.se>
36  *
37  */
38 
39 #include "lwip/opt.h"
40 
41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42 
43 #include "lwip/priv/api_msg.h"
44 
45 #include "lwip/ip.h"
46 #include "lwip/ip_addr.h"
47 #include "lwip/udp.h"
48 #include "lwip/tcp.h"
49 #include "lwip/raw.h"
50 
51 #include "lwip/memp.h"
52 #include "lwip/igmp.h"
53 #include "lwip/dns.h"
54 #include "lwip/mld6.h"
55 #include "lwip/priv/tcpip_priv.h"
56 
57 #include <string.h>
58 
59 /* netconns are polled once per second (e.g. continue write on memory error) */
60 #define NETCONN_TCP_POLL_INTERVAL 2
61 
62 #define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
63   netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
64 } else { \
65   netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
66 #define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
67 
68 #if LWIP_NETCONN_FULLDUPLEX
69 #define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
70 #else
71 #define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
72 #endif
73 
74 /* forward declarations */
75 #if LWIP_TCP
76 #if LWIP_TCPIP_CORE_LOCKING
77 #define WRITE_DELAYED         , 1
78 #define WRITE_DELAYED_PARAM   , u8_t delayed
79 #else /* LWIP_TCPIP_CORE_LOCKING */
80 #define WRITE_DELAYED
81 #define WRITE_DELAYED_PARAM
82 #endif /* LWIP_TCPIP_CORE_LOCKING */
83 static err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
84 static err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
85 #endif
86 
87 static void netconn_drain(struct netconn *conn);
88 
89 #if LWIP_TCPIP_CORE_LOCKING
90 #define TCPIP_APIMSG_ACK(m)
91 #else /* LWIP_TCPIP_CORE_LOCKING */
92 #define TCPIP_APIMSG_ACK(m)   do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
93 #endif /* LWIP_TCPIP_CORE_LOCKING */
94 
95 #if LWIP_NETCONN_FULLDUPLEX
96 const u8_t netconn_deleted = 0;
97 
98 int
lwip_netconn_is_deallocated_msg(void * msg)99 lwip_netconn_is_deallocated_msg(void *msg)
100 {
101   if (msg == &netconn_deleted) {
102     return 1;
103   }
104   return 0;
105 }
106 #endif /* LWIP_NETCONN_FULLDUPLEX */
107 
108 #if LWIP_TCP
109 const u8_t netconn_aborted = 0;
110 const u8_t netconn_reset = 0;
111 const u8_t netconn_closed = 0;
112 
113 /** Translate an error to a unique void* passed via an mbox */
114 static void *
lwip_netconn_err_to_msg(err_t err)115 lwip_netconn_err_to_msg(err_t err)
116 {
117   switch (err) {
118     case ERR_ABRT:
119       return LWIP_CONST_CAST(void *, &netconn_aborted);
120     case ERR_RST:
121       return LWIP_CONST_CAST(void *, &netconn_reset);
122     case ERR_CLSD:
123       return LWIP_CONST_CAST(void *, &netconn_closed);
124     default:
125       LWIP_ASSERT("unhandled error", err == ERR_OK);
126       return NULL;
127   }
128 }
129 
130 int
lwip_netconn_is_err_msg(void * msg,err_t * err)131 lwip_netconn_is_err_msg(void *msg, err_t *err)
132 {
133   LWIP_ASSERT("err != NULL", err != NULL);
134 
135   if (msg == &netconn_aborted) {
136     *err = ERR_ABRT;
137     return 1;
138   } else if (msg == &netconn_reset) {
139     *err = ERR_RST;
140     return 1;
141   } else if (msg == &netconn_closed) {
142     *err = ERR_CLSD;
143     return 1;
144   }
145   return 0;
146 }
147 #endif /* LWIP_TCP */
148 
149 
150 #if LWIP_RAW
151 /**
152  * Receive callback function for RAW netconns.
153  * Doesn't 'eat' the packet, only copies it and sends it to
154  * conn->recvmbox
155  *
156  * @see raw.h (struct raw_pcb.recv) for parameters and return value
157  */
158 static u8_t
recv_raw(void * arg,struct raw_pcb * pcb,struct pbuf * p,const ip_addr_t * addr)159 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
160          const ip_addr_t *addr)
161 {
162   struct pbuf *q;
163   struct netbuf *buf;
164   struct netconn *conn;
165 
166   LWIP_UNUSED_ARG(addr);
167   conn = (struct netconn *)arg;
168 
169   if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
170 #if LWIP_SO_RCVBUF
171     int recv_avail;
172     SYS_ARCH_GET(conn->recv_avail, recv_avail);
173     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
174       return 0;
175     }
176 #endif /* LWIP_SO_RCVBUF */
177     /* copy the whole packet into new pbufs */
178     q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
179     if (q != NULL) {
180       u16_t len;
181       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
182       if (buf == NULL) {
183         pbuf_free(q);
184         return 0;
185       }
186 
187       buf->p = q;
188       buf->ptr = q;
189       ip_addr_copy(buf->addr, *ip_current_src_addr());
190       buf->port = pcb->protocol;
191 
192       len = q->tot_len;
193       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
194         netbuf_delete(buf);
195         return 0;
196       } else {
197 #if LWIP_SO_RCVBUF
198         SYS_ARCH_INC(conn->recv_avail, len);
199 #endif /* LWIP_SO_RCVBUF */
200         /* Register event with callback */
201         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
202       }
203     }
204   }
205 
206   return 0; /* do not eat the packet */
207 }
208 #endif /* LWIP_RAW*/
209 
210 #if LWIP_UDP
211 /**
212  * Receive callback function for UDP netconns.
213  * Posts the packet to conn->recvmbox or deletes it on memory error.
214  *
215  * @see udp.h (struct udp_pcb.recv) for parameters
216  */
217 static void
recv_udp(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)218 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
219          const ip_addr_t *addr, u16_t port)
220 {
221   struct netbuf *buf;
222   struct netconn *conn;
223   u16_t len;
224 #if LWIP_SO_RCVBUF
225   int recv_avail;
226 #endif /* LWIP_SO_RCVBUF */
227 
228   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
229   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
230   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
231   conn = (struct netconn *)arg;
232 
233   if (conn == NULL) {
234     pbuf_free(p);
235     return;
236   }
237 
238   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
239 
240 #if LWIP_SO_RCVBUF
241   SYS_ARCH_GET(conn->recv_avail, recv_avail);
242   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
243       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
244 #else  /* LWIP_SO_RCVBUF */
245   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
246 #endif /* LWIP_SO_RCVBUF */
247     pbuf_free(p);
248     return;
249   }
250 
251   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
252   if (buf == NULL) {
253     pbuf_free(p);
254     return;
255   } else {
256     buf->p = p;
257     buf->ptr = p;
258     ip_addr_set(&buf->addr, addr);
259     buf->port = port;
260 #if LWIP_NETBUF_RECVINFO
261     if (conn->flags & NETCONN_FLAG_PKTINFO) {
262       /* get the UDP header - always in the first pbuf, ensured by udp_input */
263       const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
264       buf->flags = NETBUF_FLAG_DESTADDR;
265       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
266       buf->toport_chksum = udphdr->dest;
267     }
268 #endif /* LWIP_NETBUF_RECVINFO */
269   }
270 
271   len = p->tot_len;
272   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
273     netbuf_delete(buf);
274     return;
275   } else {
276 #if LWIP_SO_RCVBUF
277     SYS_ARCH_INC(conn->recv_avail, len);
278 #endif /* LWIP_SO_RCVBUF */
279     /* Register event with callback */
280     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
281   }
282 }
283 #endif /* LWIP_UDP */
284 
285 #if LWIP_TCP
286 /**
287  * Receive callback function for TCP netconns.
288  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
289  *
290  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
291  */
292 static err_t
293 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
294 {
295   struct netconn *conn;
296   u16_t len;
297   void *msg;
298 
299   LWIP_UNUSED_ARG(pcb);
300   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
301   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
302   LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
303   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
304   conn = (struct netconn *)arg;
305 
306   if (conn == NULL) {
307     return ERR_VAL;
308   }
309   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
310 
311   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
312     /* recvmbox already deleted */
313     if (p != NULL) {
314       tcp_recved(pcb, p->tot_len);
315       pbuf_free(p);
316     }
317     return ERR_OK;
318   }
319   /* Unlike for UDP or RAW pcbs, don't check for available space
320      using recv_avail since that could break the connection
321      (data is already ACKed) */
322 
323   if (p != NULL) {
324     msg = p;
325     len = p->tot_len;
326   } else {
327     msg = LWIP_CONST_CAST(void *, &netconn_closed);
328     len = 0;
329   }
330 
331   if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
332     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
333     return ERR_MEM;
334   } else {
335 #if LWIP_SO_RCVBUF
336     SYS_ARCH_INC(conn->recv_avail, len);
337 #endif /* LWIP_SO_RCVBUF */
338     /* Register event with callback */
339     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
340   }
341 
342   return ERR_OK;
343 }
344 
345 /**
346  * Poll callback function for TCP netconns.
347  * Wakes up an application thread that waits for a connection to close
348  * or data to be sent. The application thread then takes the
349  * appropriate action to go on.
350  *
351  * Signals the conn->sem.
352  * netconn_close waits for conn->sem if closing failed.
353  *
354  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
355  */
356 static err_t
357 poll_tcp(void *arg, struct tcp_pcb *pcb)
358 {
359   struct netconn *conn = (struct netconn *)arg;
360 
361   LWIP_UNUSED_ARG(pcb);
362   LWIP_ASSERT("conn != NULL", (conn != NULL));
363 
364   if (conn->state == NETCONN_WRITE) {
365     lwip_netconn_do_writemore(conn  WRITE_DELAYED);
366   } else if (conn->state == NETCONN_CLOSE) {
367 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
368     if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
369       conn->current_msg->msg.sd.polls_left--;
370     }
371 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
372     lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
373   }
374   /* @todo: implement connect timeout here? */
375 
376   /* Did a nonblocking write fail before? Then check available write-space. */
377   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
378     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
379        let select mark this pcb as writable again. */
380     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
381         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
382       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
383       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
384     }
385   }
386 
387   return ERR_OK;
388 }
389 
390 #if LWIP_LOWPOWER
391 /* check wether need to poll tcp */
392 u8_t
393 poll_tcp_needed(void *arg, struct tcp_pcb *pcb)
394 {
395   struct netconn *conn = (struct netconn *)arg;
396   u8_t ret = 0;
397 
398   LWIP_UNUSED_ARG(pcb);
399   if (conn == NULL) {
400     return 0;
401   }
402   if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
403     ret = 1;
404   }
405 
406   /* Did a nonblocking write fail before? Then check available write-space. */
407   if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) {
408     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
409        let select mark this pcb as writable again. */
410     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
411         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
412       ret = 1;
413     }
414   }
415   return ret;
416 }
417 #endif /* LWIP_LOWPOWER */
418 
419 /**
420  * Sent callback function for TCP netconns.
421  * Signals the conn->sem and calls API_EVENT.
422  * netconn_write waits for conn->sem if send buffer is low.
423  *
424  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
425  */
426 static err_t
427 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
428 {
429   struct netconn *conn = (struct netconn *)arg;
430 
431   LWIP_UNUSED_ARG(pcb);
432   LWIP_ASSERT("conn != NULL", (conn != NULL));
433 
434   if (conn) {
435     if (conn->state == NETCONN_WRITE) {
436       lwip_netconn_do_writemore(conn  WRITE_DELAYED);
437     } else if (conn->state == NETCONN_CLOSE) {
438       lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
439     }
440 
441     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
442        let select mark this pcb as writable again. */
443     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
444         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
445       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
446       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
447     }
448   }
449 
450   return ERR_OK;
451 }
452 
453 /**
454  * Error callback function for TCP netconns.
455  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
456  * The application thread has then to decide what to do.
457  *
458  * @see tcp.h (struct tcp_pcb.err) for parameters
459  */
460 static void
461 err_tcp(void *arg, err_t err)
462 {
463   struct netconn *conn;
464   enum netconn_state old_state;
465   void *mbox_msg;
466   SYS_ARCH_DECL_PROTECT(lev);
467 
468   conn = (struct netconn *)arg;
469   LWIP_ASSERT("conn != NULL", (conn != NULL));
470 
471   SYS_ARCH_PROTECT(lev);
472 
473   /* when err is called, the pcb is deallocated, so delete the reference */
474   conn->pcb.tcp = NULL;
475   /* store pending error */
476   conn->pending_err = err;
477   /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
478   conn->flags |= NETCONN_FLAG_MBOXCLOSED;
479 
480   /* reset conn->state now before waking up other threads */
481   old_state = conn->state;
482   conn->state = NETCONN_NONE;
483 
484   SYS_ARCH_UNPROTECT(lev);
485 
486   /* Notify the user layer about a connection error. Used to signal select. */
487   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
488   /* Try to release selects pending on 'read' or 'write', too.
489      They will get an error if they actually try to read or write. */
490   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
491   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
492 
493   mbox_msg = lwip_netconn_err_to_msg(err);
494   /* pass error message to recvmbox to wake up pending recv */
495   if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
496     /* use trypost to prevent deadlock */
497     sys_mbox_trypost(&conn->recvmbox, mbox_msg);
498   }
499   /* pass error message to acceptmbox to wake up pending accept */
500   if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
501     /* use trypost to preven deadlock */
502     sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
503   }
504 
505   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
506       (old_state == NETCONN_CONNECT)) {
507     /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
508        since the pcb has already been deleted! */
509     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
510     SET_NONBLOCKING_CONNECT(conn, 0);
511 
512     if (!was_nonblocking_connect) {
513       sys_sem_t *op_completed_sem;
514       /* set error return code */
515       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
516       if (old_state == NETCONN_CLOSE) {
517         /* let close succeed: the connection is closed after all... */
518         conn->current_msg->err = ERR_OK;
519       } else {
520         /* Write and connect fail */
521         conn->current_msg->err = err;
522       }
523       op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
524       LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
525       conn->current_msg = NULL;
526       /* wake up the waiting task */
527       sys_sem_signal(op_completed_sem);
528     } else {
529       /* @todo: test what happens for error on nonblocking connect */
530     }
531   } else {
532     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
533   }
534 }
535 
536 /**
537  * Setup a tcp_pcb with the correct callback function pointers
538  * and their arguments.
539  *
540  * @param conn the TCP netconn to setup
541  */
542 static void
543 setup_tcp(struct netconn *conn)
544 {
545   struct tcp_pcb *pcb;
546 
547   pcb = conn->pcb.tcp;
548   tcp_arg(pcb, conn);
549   tcp_recv(pcb, recv_tcp);
550   tcp_sent(pcb, sent_tcp);
551   tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
552   tcp_err(pcb, err_tcp);
553 }
554 
555 /**
556  * Accept callback function for TCP netconns.
557  * Allocates a new netconn and posts that to conn->acceptmbox.
558  *
559  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
560  */
561 static err_t
562 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
563 {
564   struct netconn *newconn;
565   struct netconn *conn = (struct netconn *)arg;
566 
567   if (conn == NULL) {
568     return ERR_VAL;
569   }
570   if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
571     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
572     return ERR_VAL;
573   }
574 
575   if (newpcb == NULL) {
576     /* out-of-pcbs during connect: pass on this error to the application */
577     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
578       /* Register event with callback */
579       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
580     }
581     return ERR_VAL;
582   }
583   LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
584   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
585 
586   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
587 
588   /* We have to set the callback here even though
589    * the new socket is unknown. newconn->socket is marked as -1. */
590   newconn = netconn_alloc(conn->type, conn->callback);
591   if (newconn == NULL) {
592     /* outof netconns: pass on this error to the application */
593     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
594       /* Register event with callback */
595       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
596     }
597     return ERR_MEM;
598   }
599   newconn->pcb.tcp = newpcb;
600   setup_tcp(newconn);
601 
602   /* handle backlog counter */
603   tcp_backlog_delayed(newpcb);
604 
605   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
606     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
607        so do nothing here! */
608     /* remove all references to this netconn from the pcb */
609     struct tcp_pcb *pcb = newconn->pcb.tcp;
610     tcp_arg(pcb, NULL);
611     tcp_recv(pcb, NULL);
612     tcp_sent(pcb, NULL);
613     tcp_poll(pcb, NULL, 0);
614     tcp_err(pcb, NULL);
615     /* remove reference from to the pcb from this netconn */
616     newconn->pcb.tcp = NULL;
617     /* no need to drain since we know the recvmbox is empty. */
618     sys_mbox_free(&newconn->recvmbox);
619     sys_mbox_set_invalid(&newconn->recvmbox);
620     netconn_free(newconn);
621     return ERR_MEM;
622   } else {
623     /* Register event with callback */
624     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
625   }
626 
627   return ERR_OK;
628 }
629 #endif /* LWIP_TCP */
630 
631 /**
632  * Create a new pcb of a specific type.
633  * Called from lwip_netconn_do_newconn().
634  *
635  * @param msg the api_msg describing the connection type
636  */
637 static void
638 #ifdef LOSCFG_NET_CONTAINER
639 pcb_new(struct api_msg *msg, struct net_group *group)
640 #else
641 pcb_new(struct api_msg *msg)
642 #endif
643 {
644   enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
645 
646   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
647 
648 #if LWIP_IPV6 && LWIP_IPV4
649   /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
650   if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
651     iptype = IPADDR_TYPE_ANY;
652   }
653 #endif
654 
655   /* Allocate a PCB for this connection */
656   switch (NETCONNTYPE_GROUP(msg->conn->type)) {
657 #if LWIP_RAW
658     case NETCONN_RAW:
659       msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
660       if (msg->conn->pcb.raw != NULL) {
661 #ifdef LOSCFG_NET_CONTAINER
662         set_raw_pcb_net_group(msg->conn->pcb.raw, group);
663 #endif
664 #if LWIP_IPV6
665         /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
666         if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
667           msg->conn->pcb.raw->chksum_reqd = 1;
668           msg->conn->pcb.raw->chksum_offset = 2;
669         }
670 #endif /* LWIP_IPV6 */
671         raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
672       }
673       break;
674 #endif /* LWIP_RAW */
675 #if LWIP_UDP
676     case NETCONN_UDP:
677       msg->conn->pcb.udp = udp_new_ip_type(iptype);
678       if (msg->conn->pcb.udp != NULL) {
679 #ifdef LOSCFG_NET_CONTAINER
680         set_udp_pcb_net_group(msg->conn->pcb.udp, group);
681 #endif
682 #if LWIP_UDPLITE
683         if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
684           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
685         }
686 #endif /* LWIP_UDPLITE */
687         if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
688           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
689         }
690         udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
691       }
692       break;
693 #endif /* LWIP_UDP */
694 #if LWIP_TCP
695     case NETCONN_TCP:
696       msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
697       if (msg->conn->pcb.tcp != NULL) {
698 #ifdef LOSCFG_NET_CONTAINER
699         set_tcp_pcb_net_group(msg->conn->pcb.tcp, group);
700 #endif
701         setup_tcp(msg->conn);
702       }
703       break;
704 #endif /* LWIP_TCP */
705     default:
706       /* Unsupported netconn type, e.g. protocol disabled */
707       msg->err = ERR_VAL;
708       return;
709   }
710   if (msg->conn->pcb.ip == NULL) {
711     msg->err = ERR_MEM;
712   }
713 }
714 
715 /**
716  * Create a new pcb of a specific type inside a netconn.
717  * Called from netconn_new_with_proto_and_callback.
718  *
719  * @param m the api_msg describing the connection type
720  */
721 void
722 lwip_netconn_do_newconn(void *m)
723 {
724   struct api_msg *msg = (struct api_msg *)m;
725 
726   msg->err = ERR_OK;
727   if (msg->conn->pcb.tcp == NULL) {
728 #ifdef LOSCFG_NET_CONTAINER
729     pcb_new(msg, get_curr_process_net_group());
730 #else
731     pcb_new(msg);
732 #endif
733   }
734   /* Else? This "new" connection already has a PCB allocated. */
735   /* Is this an error condition? Should it be deleted? */
736   /* We currently just are happy and return. */
737 
738   TCPIP_APIMSG_ACK(msg);
739 }
740 
741 /**
742  * Create a new netconn (of a specific type) that has a callback function.
743  * The corresponding pcb is NOT created!
744  *
745  * @param t the type of 'connection' to create (@see enum netconn_type)
746  * @param callback a function to call on status changes (RX available, TX'ed)
747  * @return a newly allocated struct netconn or
748  *         NULL on memory error
749  */
750 struct netconn *
751 netconn_alloc(enum netconn_type t, netconn_callback callback)
752 {
753   struct netconn *conn;
754   int size;
755   u8_t init_flags = 0;
756 
757   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
758   if (conn == NULL) {
759     return NULL;
760   }
761 
762   conn->pending_err = ERR_OK;
763   conn->type = t;
764   conn->pcb.tcp = NULL;
765 #if LWIP_NETCONN_FULLDUPLEX
766   conn->mbox_threads_waiting = 0;
767 #endif
768 
769   /* If all sizes are the same, every compiler should optimize this switch to nothing */
770   switch (NETCONNTYPE_GROUP(t)) {
771 #if LWIP_RAW
772     case NETCONN_RAW:
773       size = DEFAULT_RAW_RECVMBOX_SIZE;
774       break;
775 #endif /* LWIP_RAW */
776 #if LWIP_UDP
777     case NETCONN_UDP:
778       size = DEFAULT_UDP_RECVMBOX_SIZE;
779 #if LWIP_NETBUF_RECVINFO
780       init_flags |= NETCONN_FLAG_PKTINFO;
781 #endif /* LWIP_NETBUF_RECVINFO */
782       break;
783 #endif /* LWIP_UDP */
784 #if LWIP_TCP
785     case NETCONN_TCP:
786       size = DEFAULT_TCP_RECVMBOX_SIZE;
787       break;
788 #endif /* LWIP_TCP */
789     default:
790       LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
791       goto free_and_return;
792   }
793 
794   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
795     goto free_and_return;
796   }
797 #if !LWIP_NETCONN_SEM_PER_THREAD
798   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
799     sys_mbox_free(&conn->recvmbox);
800     goto free_and_return;
801   }
802 #endif
803 
804 #if LWIP_TCP
805   sys_mbox_set_invalid(&conn->acceptmbox);
806 #endif
807   conn->state        = NETCONN_NONE;
808 #if LWIP_SOCKET
809   /* initialize socket to -1 since 0 is a valid socket */
810   conn->socket       = -1;
811 #endif /* LWIP_SOCKET */
812   conn->callback     = callback;
813 #if LWIP_TCP
814   conn->current_msg  = NULL;
815 #endif /* LWIP_TCP */
816 #if LWIP_SO_SNDTIMEO
817   conn->send_timeout = 0;
818 #endif /* LWIP_SO_SNDTIMEO */
819 #if LWIP_SO_RCVTIMEO
820   conn->recv_timeout = 0;
821 #endif /* LWIP_SO_RCVTIMEO */
822 #if LWIP_SO_RCVBUF
823   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
824   conn->recv_avail   = 0;
825 #endif /* LWIP_SO_RCVBUF */
826 #if LWIP_SO_LINGER
827   conn->linger = -1;
828 #endif /* LWIP_SO_LINGER */
829   conn->flags = init_flags;
830   return conn;
831 free_and_return:
832   memp_free(MEMP_NETCONN, conn);
833   return NULL;
834 }
835 
836 /**
837  * Delete a netconn and all its resources.
838  * The pcb is NOT freed (since we might not be in the right thread context do this).
839  *
840  * @param conn the netconn to free
841  */
842 void
843 netconn_free(struct netconn *conn)
844 {
845   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
846 
847 #if LWIP_NETCONN_FULLDUPLEX
848   /* in fullduplex, netconn is drained here */
849   netconn_drain(conn);
850 #endif /* LWIP_NETCONN_FULLDUPLEX */
851 
852   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
853               !sys_mbox_valid(&conn->recvmbox));
854 #if LWIP_TCP
855   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
856               !sys_mbox_valid(&conn->acceptmbox));
857 #endif /* LWIP_TCP */
858 
859 #if !LWIP_NETCONN_SEM_PER_THREAD
860   sys_sem_free(&conn->op_completed);
861   sys_sem_set_invalid(&conn->op_completed);
862 #endif
863 
864   memp_free(MEMP_NETCONN, conn);
865 }
866 
867 /**
868  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
869  * these mboxes
870  *
871  * @param conn the netconn to free
872  * @bytes_drained bytes drained from recvmbox
873  * @accepts_drained pending connections drained from acceptmbox
874  */
875 static void
876 netconn_drain(struct netconn *conn)
877 {
878   void *mem;
879 
880   /* This runs when mbox and netconn are marked as closed,
881      so we don't need to lock against rx packets */
882 #if LWIP_NETCONN_FULLDUPLEX
883   LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
884 #endif /* LWIP_NETCONN_FULLDUPLEX */
885 
886   /* Delete and drain the recvmbox. */
887   if (sys_mbox_valid(&conn->recvmbox)) {
888     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
889 #if LWIP_NETCONN_FULLDUPLEX
890       if (!lwip_netconn_is_deallocated_msg(mem))
891 #endif /* LWIP_NETCONN_FULLDUPLEX */
892       {
893 #if LWIP_TCP
894         if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
895           err_t err;
896           if (!lwip_netconn_is_err_msg(mem, &err)) {
897             pbuf_free((struct pbuf *)mem);
898           }
899         } else
900 #endif /* LWIP_TCP */
901         {
902           netbuf_delete((struct netbuf *)mem);
903         }
904       }
905     }
906     sys_mbox_free(&conn->recvmbox);
907     sys_mbox_set_invalid(&conn->recvmbox);
908   }
909 
910   /* Delete and drain the acceptmbox. */
911 #if LWIP_TCP
912   if (sys_mbox_valid(&conn->acceptmbox)) {
913     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
914 #if LWIP_NETCONN_FULLDUPLEX
915       if (!lwip_netconn_is_deallocated_msg(mem))
916 #endif /* LWIP_NETCONN_FULLDUPLEX */
917       {
918         err_t err;
919         if (!lwip_netconn_is_err_msg(mem, &err)) {
920           struct netconn *newconn = (struct netconn *)mem;
921           /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
922           /* pcb might be set to NULL already by err_tcp() */
923           /* drain recvmbox */
924           netconn_drain(newconn);
925           if (newconn->pcb.tcp != NULL) {
926             tcp_abort(newconn->pcb.tcp);
927             newconn->pcb.tcp = NULL;
928           }
929           netconn_free(newconn);
930         }
931       }
932     }
933     sys_mbox_free(&conn->acceptmbox);
934     sys_mbox_set_invalid(&conn->acceptmbox);
935   }
936 #endif /* LWIP_TCP */
937 }
938 
939 #if LWIP_NETCONN_FULLDUPLEX
940 static void
941 netconn_mark_mbox_invalid(struct netconn *conn)
942 {
943   int i, num_waiting;
944   void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
945 
946   /* Prevent new calls/threads from reading from the mbox */
947   conn->flags |= NETCONN_FLAG_MBOXINVALID;
948 
949   SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
950   for (i = 0; i < num_waiting; i++) {
951     if (sys_mbox_valid_val(conn->recvmbox)) {
952       sys_mbox_trypost(&conn->recvmbox, msg);
953     } else {
954       sys_mbox_trypost(&conn->acceptmbox, msg);
955     }
956   }
957 }
958 #endif /* LWIP_NETCONN_FULLDUPLEX */
959 
960 #if LWIP_TCP
961 /**
962  * Internal helper function to close a TCP netconn: since this sometimes
963  * doesn't work at the first attempt, this function is called from multiple
964  * places.
965  *
966  * @param conn the TCP netconn to close
967  */
968 static err_t
969 lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
970 {
971   err_t err;
972   u8_t shut, shut_rx, shut_tx, shut_close;
973   u8_t close_finished = 0;
974   struct tcp_pcb *tpcb;
975 #if LWIP_SO_LINGER
976   u8_t linger_wait_required = 0;
977 #endif /* LWIP_SO_LINGER */
978 
979   LWIP_ASSERT("invalid conn", (conn != NULL));
980   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
981   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
982   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
983   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
984 
985   tpcb = conn->pcb.tcp;
986   shut = conn->current_msg->msg.sd.shut;
987   shut_rx = shut & NETCONN_SHUT_RD;
988   shut_tx = shut & NETCONN_SHUT_WR;
989   /* shutting down both ends is the same as closing
990      (also if RD or WR side was shut down before already) */
991   if (shut == NETCONN_SHUT_RDWR) {
992     shut_close = 1;
993   } else if (shut_rx &&
994              ((tpcb->state == FIN_WAIT_1) ||
995               (tpcb->state == FIN_WAIT_2) ||
996               (tpcb->state == CLOSING))) {
997     shut_close = 1;
998   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
999     shut_close = 1;
1000   } else {
1001     shut_close = 0;
1002   }
1003 
1004   /* Set back some callback pointers */
1005   if (shut_close) {
1006     tcp_arg(tpcb, NULL);
1007   }
1008   if (tpcb->state == LISTEN) {
1009     tcp_accept(tpcb, NULL);
1010   } else {
1011     /* some callbacks have to be reset if tcp_close is not successful */
1012     if (shut_rx) {
1013       tcp_recv(tpcb, NULL);
1014       tcp_accept(tpcb, NULL);
1015     }
1016     if (shut_tx) {
1017       tcp_sent(tpcb, NULL);
1018     }
1019     if (shut_close) {
1020       tcp_poll(tpcb, NULL, 0);
1021       tcp_err(tpcb, NULL);
1022     }
1023   }
1024   /* Try to close the connection */
1025   if (shut_close) {
1026 #if LWIP_SO_LINGER
1027     /* check linger possibilites before calling tcp_close */
1028     err = ERR_OK;
1029     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
1030     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
1031       if ((conn->linger == 0)) {
1032         /* data left but linger prevents waiting */
1033         tcp_abort(tpcb);
1034         tpcb = NULL;
1035       } else if (conn->linger > 0) {
1036         /* data left and linger says we should wait */
1037         if (netconn_is_nonblocking(conn)) {
1038           /* data left on a nonblocking netconn -> cannot linger */
1039           err = ERR_WOULDBLOCK;
1040         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
1041                    (conn->linger * 1000)) {
1042           /* data left but linger timeout has expired (this happens on further
1043              calls to this function through poll_tcp */
1044           tcp_abort(tpcb);
1045           tpcb = NULL;
1046         } else {
1047           /* data left -> need to wait for ACK after successful close */
1048           linger_wait_required = 1;
1049         }
1050       }
1051     }
1052     if ((err == ERR_OK) && (tpcb != NULL))
1053 #endif /* LWIP_SO_LINGER */
1054     {
1055       err = tcp_close(tpcb);
1056     }
1057   } else {
1058     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
1059   }
1060   if (err == ERR_OK) {
1061     close_finished = 1;
1062 #if LWIP_SO_LINGER
1063     if (linger_wait_required) {
1064       /* wait for ACK of all unsent/unacked data by just getting called again */
1065       close_finished = 0;
1066       err = ERR_INPROGRESS;
1067     }
1068 #endif /* LWIP_SO_LINGER */
1069   } else {
1070     if (err == ERR_MEM) {
1071       /* Closing failed because of memory shortage, try again later. Even for
1072          nonblocking netconns, we have to wait since no standard socket application
1073          is prepared for close failing because of resource shortage.
1074          Check the timeout: this is kind of an lwip addition to the standard sockets:
1075          we wait for some time when failing to allocate a segment for the FIN */
1076 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1077       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
1078 #if LWIP_SO_SNDTIMEO
1079       if (conn->send_timeout > 0) {
1080         close_timeout = conn->send_timeout;
1081       }
1082 #endif /* LWIP_SO_SNDTIMEO */
1083 #if LWIP_SO_LINGER
1084       if (conn->linger >= 0) {
1085         /* use linger timeout (seconds) */
1086         close_timeout = conn->linger * 1000U;
1087       }
1088 #endif
1089       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
1090 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1091       if (conn->current_msg->msg.sd.polls_left == 0) {
1092 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1093         close_finished = 1;
1094         if (shut_close) {
1095           /* in this case, we want to RST the connection */
1096           tcp_abort(tpcb);
1097           err = ERR_OK;
1098         }
1099       }
1100     } else {
1101       /* Closing failed for a non-memory error: give up */
1102       close_finished = 1;
1103     }
1104   }
1105   if (close_finished) {
1106     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
1107     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1108     conn->current_msg->err = err;
1109     conn->current_msg = NULL;
1110     conn->state = NETCONN_NONE;
1111     if (err == ERR_OK) {
1112       if (shut_close) {
1113         /* Set back some callback pointers as conn is going away */
1114         conn->pcb.tcp = NULL;
1115         /* Trigger select() in socket layer. Make sure everybody notices activity
1116          on the connection, error first! */
1117         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
1118       }
1119       if (shut_rx) {
1120         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
1121       }
1122       if (shut_tx) {
1123         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1124       }
1125     }
1126 #if LWIP_TCPIP_CORE_LOCKING
1127     if (delayed)
1128 #endif
1129     {
1130       /* wake up the application task */
1131       sys_sem_signal(op_completed_sem);
1132     }
1133     return ERR_OK;
1134   }
1135   if (!close_finished) {
1136     /* Closing failed and we want to wait: restore some of the callbacks */
1137     /* Closing of listen pcb will never fail! */
1138     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
1139     if (shut_tx) {
1140       tcp_sent(tpcb, sent_tcp);
1141     }
1142     /* when waiting for close, set up poll interval to 500ms */
1143     tcp_poll(tpcb, poll_tcp, 1);
1144     tcp_err(tpcb, err_tcp);
1145     tcp_arg(tpcb, conn);
1146     /* don't restore recv callback: we don't want to receive any more data */
1147   }
1148   /* If closing didn't succeed, we get called again either
1149      from poll_tcp or from sent_tcp */
1150   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1151   return err;
1152 }
1153 #endif /* LWIP_TCP */
1154 
1155 /**
1156  * Delete the pcb inside a netconn.
1157  * Called from netconn_delete.
1158  *
1159  * @param m the api_msg pointing to the connection
1160  */
1161 void
1162 lwip_netconn_do_delconn(void *m)
1163 {
1164   struct api_msg *msg = (struct api_msg *)m;
1165 
1166   enum netconn_state state = msg->conn->state;
1167   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1168               (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1169 #if LWIP_NETCONN_FULLDUPLEX
1170   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1171   if (state != NETCONN_NONE) {
1172     if ((state == NETCONN_WRITE) ||
1173         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1174       /* close requested, abort running write/connect */
1175       sys_sem_t *op_completed_sem;
1176       LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1177       op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1178       msg->conn->current_msg->err = ERR_CLSD;
1179       msg->conn->current_msg = NULL;
1180       msg->conn->state = NETCONN_NONE;
1181       sys_sem_signal(op_completed_sem);
1182     }
1183   }
1184 #else /* LWIP_NETCONN_FULLDUPLEX */
1185   if (((state != NETCONN_NONE) &&
1186        (state != NETCONN_LISTEN) &&
1187        (state != NETCONN_CONNECT)) ||
1188       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1189     /* This means either a blocking write or blocking connect is running
1190        (nonblocking write returns and sets state to NONE) */
1191     msg->err = ERR_INPROGRESS;
1192   } else
1193 #endif /* LWIP_NETCONN_FULLDUPLEX */
1194   {
1195     LWIP_ASSERT("blocking connect in progress",
1196                 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1197     msg->err = ERR_OK;
1198 #if LWIP_NETCONN_FULLDUPLEX
1199     /* Mark mboxes invalid */
1200     netconn_mark_mbox_invalid(msg->conn);
1201 #else /* LWIP_NETCONN_FULLDUPLEX */
1202     netconn_drain(msg->conn);
1203 #endif /* LWIP_NETCONN_FULLDUPLEX */
1204 
1205     if (msg->conn->pcb.tcp != NULL) {
1206 
1207       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1208 #if LWIP_RAW
1209         case NETCONN_RAW:
1210           raw_remove(msg->conn->pcb.raw);
1211           break;
1212 #endif /* LWIP_RAW */
1213 #if LWIP_UDP
1214         case NETCONN_UDP:
1215           msg->conn->pcb.udp->recv_arg = NULL;
1216           udp_remove(msg->conn->pcb.udp);
1217           break;
1218 #endif /* LWIP_UDP */
1219 #if LWIP_TCP
1220         case NETCONN_TCP:
1221           LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1222           msg->conn->state = NETCONN_CLOSE;
1223           msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1224           msg->conn->current_msg = msg;
1225 #if LWIP_TCPIP_CORE_LOCKING
1226           if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1227             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1228             UNLOCK_TCPIP_CORE();
1229             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1230             LOCK_TCPIP_CORE();
1231             LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1232           }
1233 #else /* LWIP_TCPIP_CORE_LOCKING */
1234           lwip_netconn_do_close_internal(msg->conn);
1235 #endif /* LWIP_TCPIP_CORE_LOCKING */
1236           /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1237              the application thread, so we can return at this point! */
1238           return;
1239 #endif /* LWIP_TCP */
1240         default:
1241           break;
1242       }
1243       msg->conn->pcb.tcp = NULL;
1244     }
1245     /* tcp netconns don't come here! */
1246 
1247     /* @todo: this lets select make the socket readable and writable,
1248        which is wrong! errfd instead? */
1249     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1250     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1251   }
1252   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1253     TCPIP_APIMSG_ACK(msg);
1254   }
1255 }
1256 
1257 /**
1258  * Bind a pcb contained in a netconn
1259  * Called from netconn_bind.
1260  *
1261  * @param m the api_msg pointing to the connection and containing
1262  *          the IP address and port to bind to
1263  */
1264 void
1265 lwip_netconn_do_bind(void *m)
1266 {
1267   struct api_msg *msg = (struct api_msg *)m;
1268   err_t err;
1269 
1270   if (msg->conn->pcb.tcp != NULL) {
1271     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1272 #if LWIP_RAW
1273       case NETCONN_RAW:
1274         err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1275         break;
1276 #endif /* LWIP_RAW */
1277 #if LWIP_UDP
1278       case NETCONN_UDP:
1279         err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1280         break;
1281 #endif /* LWIP_UDP */
1282 #if LWIP_TCP
1283       case NETCONN_TCP:
1284         err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1285         break;
1286 #endif /* LWIP_TCP */
1287       default:
1288         err = ERR_VAL;
1289         break;
1290     }
1291   } else {
1292     err = ERR_VAL;
1293   }
1294   msg->err = err;
1295   TCPIP_APIMSG_ACK(msg);
1296 }
1297 
1298 /**
1299  * Bind a pcb contained in a netconn to an interface
1300  * Called from netconn_bind_if.
1301  *
1302  * @param m the api_msg pointing to the connection and containing
1303  *          the IP address and port to bind to
1304  */
1305 void
1306 lwip_netconn_do_bind_if(void *m)
1307 {
1308   struct netif *netif;
1309   struct api_msg *msg = (struct api_msg *)m;
1310   err_t err;
1311 #ifdef LOSCFG_NET_CONTAINER
1312   struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip);
1313 
1314   if (group != NULL) {
1315     netif = netif_get_by_index(msg->msg.bc.if_idx, group);
1316   } else {
1317     netif = NULL;
1318   }
1319 #else
1320   netif = netif_get_by_index(msg->msg.bc.if_idx);
1321 #endif
1322 
1323   if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
1324     err = ERR_OK;
1325     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1326 #if LWIP_RAW
1327       case NETCONN_RAW:
1328         raw_bind_netif(msg->conn->pcb.raw, netif);
1329         break;
1330 #endif /* LWIP_RAW */
1331 #if LWIP_UDP
1332       case NETCONN_UDP:
1333         udp_bind_netif(msg->conn->pcb.udp, netif);
1334         break;
1335 #endif /* LWIP_UDP */
1336 #if LWIP_TCP
1337       case NETCONN_TCP:
1338         tcp_bind_netif(msg->conn->pcb.tcp, netif);
1339         break;
1340 #endif /* LWIP_TCP */
1341       default:
1342         err = ERR_VAL;
1343         break;
1344     }
1345   } else {
1346     err = ERR_VAL;
1347   }
1348   msg->err = err;
1349   TCPIP_APIMSG_ACK(msg);
1350 }
1351 
1352 #if LWIP_TCP
1353 /**
1354  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1355  * been established (or reset by the remote host).
1356  *
1357  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1358  */
1359 static err_t
1360 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1361 {
1362   struct netconn *conn;
1363   int was_blocking;
1364   sys_sem_t *op_completed_sem = NULL;
1365 
1366   LWIP_UNUSED_ARG(pcb);
1367 
1368   conn = (struct netconn *)arg;
1369 
1370   if (conn == NULL) {
1371     return ERR_VAL;
1372   }
1373 
1374   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1375   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1376               (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1377 
1378   if (conn->current_msg != NULL) {
1379     conn->current_msg->err = err;
1380     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1381   }
1382   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1383     setup_tcp(conn);
1384   }
1385   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1386   SET_NONBLOCKING_CONNECT(conn, 0);
1387   LWIP_ASSERT("blocking connect state error",
1388               (was_blocking && op_completed_sem != NULL) ||
1389               (!was_blocking && op_completed_sem == NULL));
1390   conn->current_msg = NULL;
1391   conn->state = NETCONN_NONE;
1392   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1393 
1394   if (was_blocking) {
1395     sys_sem_signal(op_completed_sem);
1396   }
1397   return ERR_OK;
1398 }
1399 #endif /* LWIP_TCP */
1400 
1401 /**
1402  * Connect a pcb contained inside a netconn
1403  * Called from netconn_connect.
1404  *
1405  * @param m the api_msg pointing to the connection and containing
1406  *          the IP address and port to connect to
1407  */
1408 void
1409 lwip_netconn_do_connect(void *m)
1410 {
1411   struct api_msg *msg = (struct api_msg *)m;
1412   err_t err;
1413 
1414   if (msg->conn->pcb.tcp == NULL) {
1415     /* This may happen when calling netconn_connect() a second time */
1416     err = ERR_CLSD;
1417   } else {
1418     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1419 #if LWIP_RAW
1420       case NETCONN_RAW:
1421         err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1422         break;
1423 #endif /* LWIP_RAW */
1424 #if LWIP_UDP
1425       case NETCONN_UDP:
1426         err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1427         break;
1428 #endif /* LWIP_UDP */
1429 #if LWIP_TCP
1430       case NETCONN_TCP:
1431         /* Prevent connect while doing any other action. */
1432         if (msg->conn->state == NETCONN_CONNECT) {
1433           err = ERR_ALREADY;
1434         } else if (msg->conn->state != NETCONN_NONE) {
1435           err = ERR_ISCONN;
1436         } else {
1437           setup_tcp(msg->conn);
1438           err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1439                             msg->msg.bc.port, lwip_netconn_do_connected);
1440           if (err == ERR_OK) {
1441             u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1442             msg->conn->state = NETCONN_CONNECT;
1443             SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1444             if (non_blocking) {
1445               err = ERR_INPROGRESS;
1446             } else {
1447               msg->conn->current_msg = msg;
1448               /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1449                  when the connection is established! */
1450 #if LWIP_TCPIP_CORE_LOCKING
1451               LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1452               UNLOCK_TCPIP_CORE();
1453               sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1454               LOCK_TCPIP_CORE();
1455               LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1456 #endif /* LWIP_TCPIP_CORE_LOCKING */
1457               return;
1458             }
1459           }
1460         }
1461         break;
1462 #endif /* LWIP_TCP */
1463       default:
1464         LWIP_ERROR("Invalid netconn type", 0, do {
1465           err = ERR_VAL;
1466         } while (0));
1467         break;
1468     }
1469   }
1470   msg->err = err;
1471   /* For all other protocols, netconn_connect() calls netconn_apimsg(),
1472      so use TCPIP_APIMSG_ACK() here. */
1473   TCPIP_APIMSG_ACK(msg);
1474 }
1475 
1476 /**
1477  * Disconnect a pcb contained inside a netconn
1478  * Only used for UDP netconns.
1479  * Called from netconn_disconnect.
1480  *
1481  * @param m the api_msg pointing to the connection to disconnect
1482  */
1483 void
1484 lwip_netconn_do_disconnect(void *m)
1485 {
1486   struct api_msg *msg = (struct api_msg *)m;
1487 
1488 #if LWIP_UDP
1489   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1490     udp_disconnect(msg->conn->pcb.udp);
1491     msg->err = ERR_OK;
1492   } else
1493 #endif /* LWIP_UDP */
1494   {
1495     msg->err = ERR_VAL;
1496   }
1497   TCPIP_APIMSG_ACK(msg);
1498 }
1499 
1500 #if LWIP_TCP
1501 /**
1502  * Set a TCP pcb contained in a netconn into listen mode
1503  * Called from netconn_listen.
1504  *
1505  * @param m the api_msg pointing to the connection
1506  */
1507 void
1508 lwip_netconn_do_listen(void *m)
1509 {
1510   struct api_msg *msg = (struct api_msg *)m;
1511   err_t err;
1512 
1513   if (msg->conn->pcb.tcp != NULL) {
1514     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1515       if (msg->conn->state == NETCONN_NONE) {
1516         struct tcp_pcb *lpcb;
1517         if (msg->conn->pcb.tcp->state != CLOSED) {
1518           /* connection is not closed, cannot listen */
1519           err = ERR_VAL;
1520         } else {
1521           u8_t backlog;
1522 #if TCP_LISTEN_BACKLOG
1523           backlog = msg->msg.lb.backlog;
1524 #else  /* TCP_LISTEN_BACKLOG */
1525           backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1526 #endif /* TCP_LISTEN_BACKLOG */
1527 #if LWIP_IPV4 && LWIP_IPV6
1528           /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1529             * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1530             */
1531           if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1532               (netconn_get_ipv6only(msg->conn) == 0)) {
1533             /* change PCB type to IPADDR_TYPE_ANY */
1534             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
1535             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1536           }
1537 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1538 
1539           lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1540 
1541           if (lpcb == NULL) {
1542             /* in this case, the old pcb is still allocated */
1543           } else {
1544             /* delete the recvmbox and allocate the acceptmbox */
1545             if (sys_mbox_valid(&msg->conn->recvmbox)) {
1546               /** @todo: should we drain the recvmbox here? */
1547               sys_mbox_free(&msg->conn->recvmbox);
1548               sys_mbox_set_invalid(&msg->conn->recvmbox);
1549             }
1550             err = ERR_OK;
1551             if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1552               err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1553             }
1554             if (err == ERR_OK) {
1555               msg->conn->state = NETCONN_LISTEN;
1556               msg->conn->pcb.tcp = lpcb;
1557               tcp_arg(msg->conn->pcb.tcp, msg->conn);
1558               tcp_accept(msg->conn->pcb.tcp, accept_function);
1559             } else {
1560               /* since the old pcb is already deallocated, free lpcb now */
1561               tcp_close(lpcb);
1562               msg->conn->pcb.tcp = NULL;
1563             }
1564           }
1565         }
1566       } else if (msg->conn->state == NETCONN_LISTEN) {
1567         /* already listening, allow updating of the backlog */
1568         err = ERR_OK;
1569         tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1570       } else {
1571         err = ERR_CONN;
1572       }
1573     } else {
1574       err = ERR_ARG;
1575     }
1576   } else {
1577     err = ERR_CONN;
1578   }
1579   msg->err = err;
1580   TCPIP_APIMSG_ACK(msg);
1581 }
1582 #endif /* LWIP_TCP */
1583 
1584 /**
1585  * Send some data on a RAW or UDP pcb contained in a netconn
1586  * Called from netconn_send
1587  *
1588  * @param m the api_msg pointing to the connection
1589  */
1590 void
1591 lwip_netconn_do_send(void *m)
1592 {
1593   struct api_msg *msg = (struct api_msg *)m;
1594 
1595   err_t err = netconn_err(msg->conn);
1596   if (err == ERR_OK) {
1597     if (msg->conn->pcb.tcp != NULL) {
1598       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1599 #if LWIP_RAW
1600         case NETCONN_RAW:
1601           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1602             err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1603           } else {
1604             err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1605           }
1606           break;
1607 #endif
1608 #if LWIP_UDP
1609         case NETCONN_UDP:
1610 #if LWIP_CHECKSUM_ON_COPY
1611           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1612             err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1613                                   msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1614           } else {
1615             err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1616                                     &msg->msg.b->addr, msg->msg.b->port,
1617                                     msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1618           }
1619 #else /* LWIP_CHECKSUM_ON_COPY */
1620           if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1621             err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1622           } else {
1623             err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1624           }
1625 #endif /* LWIP_CHECKSUM_ON_COPY */
1626           break;
1627 #endif /* LWIP_UDP */
1628         default:
1629           err = ERR_CONN;
1630           break;
1631       }
1632     } else {
1633       err = ERR_CONN;
1634     }
1635   }
1636   msg->err = err;
1637   TCPIP_APIMSG_ACK(msg);
1638 }
1639 
1640 #if LWIP_TCP
1641 /**
1642  * Indicate data has been received from a TCP pcb contained in a netconn
1643  * Called from netconn_recv
1644  *
1645  * @param m the api_msg pointing to the connection
1646  */
1647 void
1648 lwip_netconn_do_recv(void *m)
1649 {
1650   struct api_msg *msg = (struct api_msg *)m;
1651 
1652   msg->err = ERR_OK;
1653   if (msg->conn->pcb.tcp != NULL) {
1654     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1655       size_t remaining = msg->msg.r.len;
1656       do {
1657         u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
1658         tcp_recved(msg->conn->pcb.tcp, recved);
1659         remaining -= recved;
1660       } while (remaining != 0);
1661     }
1662   }
1663   TCPIP_APIMSG_ACK(msg);
1664 }
1665 
1666 #if TCP_LISTEN_BACKLOG
1667 /** Indicate that a TCP pcb has been accepted
1668  * Called from netconn_accept
1669  *
1670  * @param m the api_msg pointing to the connection
1671  */
1672 void
1673 lwip_netconn_do_accepted(void *m)
1674 {
1675   struct api_msg *msg = (struct api_msg *)m;
1676 
1677   msg->err = ERR_OK;
1678   if (msg->conn->pcb.tcp != NULL) {
1679     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1680       tcp_backlog_accepted(msg->conn->pcb.tcp);
1681     }
1682   }
1683   TCPIP_APIMSG_ACK(msg);
1684 }
1685 #endif /* TCP_LISTEN_BACKLOG */
1686 
1687 /**
1688  * See if more data needs to be written from a previous call to netconn_write.
1689  * Called initially from lwip_netconn_do_write. If the first call can't send all data
1690  * (because of low memory or empty send-buffer), this function is called again
1691  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1692  * blocking application thread (waiting in netconn_write) is released.
1693  *
1694  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1695  * @return ERR_OK
1696  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1697  */
1698 static err_t
1699 lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
1700 {
1701   err_t err;
1702   const void *dataptr;
1703   u16_t len, available;
1704   u8_t write_finished = 0;
1705   size_t diff;
1706   u8_t dontblock;
1707   u8_t apiflags;
1708   u8_t write_more;
1709 
1710   LWIP_ASSERT("conn != NULL", conn != NULL);
1711   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1712   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1713   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1714   LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1715               conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1716   LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1717 
1718   apiflags = conn->current_msg->msg.w.apiflags;
1719   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1720 
1721 #if LWIP_SO_SNDTIMEO
1722   if ((conn->send_timeout != 0) &&
1723       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1724     write_finished = 1;
1725     if (conn->current_msg->msg.w.offset == 0) {
1726       /* nothing has been written */
1727       err = ERR_WOULDBLOCK;
1728     } else {
1729       /* partial write */
1730       err = ERR_OK;
1731     }
1732   } else
1733 #endif /* LWIP_SO_SNDTIMEO */
1734   {
1735     do {
1736       dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
1737       diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
1738       if (diff > 0xffffUL) { /* max_u16_t */
1739         len = 0xffff;
1740         apiflags |= TCP_WRITE_FLAG_MORE;
1741       } else {
1742         len = (u16_t)diff;
1743       }
1744       available = tcp_sndbuf(conn->pcb.tcp);
1745       if (available < len) {
1746         /* don't try to write more than sendbuf */
1747         len = available;
1748         if (dontblock) {
1749           if (!len) {
1750             /* set error according to partial write or not */
1751             err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1752             goto err_mem;
1753           }
1754         } else {
1755           apiflags |= TCP_WRITE_FLAG_MORE;
1756         }
1757       }
1758       LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
1759                   ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
1760       /* we should loop around for more sending in the following cases:
1761            1) We couldn't finish the current vector because of 16-bit size limitations.
1762               tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
1763            2) We are sending the remainder of the current vector and have more */
1764       if ((len == 0xffff && diff > 0xffffUL) ||
1765           (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
1766         write_more = 1;
1767         apiflags |= TCP_WRITE_FLAG_MORE;
1768       } else {
1769         write_more = 0;
1770       }
1771       err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1772       if (err == ERR_OK) {
1773         conn->current_msg->msg.w.offset += len;
1774         conn->current_msg->msg.w.vector_off += len;
1775         /* check if current vector is finished */
1776         if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
1777           conn->current_msg->msg.w.vector_cnt--;
1778           /* if we have additional vectors, move on to them */
1779           if (conn->current_msg->msg.w.vector_cnt > 0) {
1780             conn->current_msg->msg.w.vector++;
1781             conn->current_msg->msg.w.vector_off = 0;
1782           }
1783         }
1784       }
1785     } while (write_more && err == ERR_OK);
1786     /* if OK or memory error, check available space */
1787     if ((err == ERR_OK) || (err == ERR_MEM)) {
1788 err_mem:
1789       if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
1790         /* non-blocking write did not write everything: mark the pcb non-writable
1791            and let poll_tcp check writable space to mark the pcb writable again */
1792         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1793         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1794       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1795                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1796         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1797            let select mark this pcb as non-writable. */
1798         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1799       }
1800     }
1801 
1802     if (err == ERR_OK) {
1803       err_t out_err;
1804       if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
1805         /* return sent length (caller reads length from msg.w.offset) */
1806         write_finished = 1;
1807       }
1808       out_err = tcp_output(conn->pcb.tcp);
1809       if (out_err == ERR_RTE) {
1810         /* If tcp_output fails because no route is found,
1811            don't try writing any more but return the error
1812            to the application thread. */
1813         err = out_err;
1814         write_finished = 1;
1815       }
1816     } else if (err == ERR_MEM) {
1817       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1818          For blocking sockets, we do NOT return to the application
1819          thread, since ERR_MEM is only a temporary error! Non-blocking
1820          will remain non-writable until sent_tcp/poll_tcp is called */
1821 
1822       /* tcp_write returned ERR_MEM, try tcp_output anyway */
1823       err_t out_err = tcp_output(conn->pcb.tcp);
1824       if (out_err == ERR_RTE) {
1825         /* If tcp_output fails because no route is found,
1826            don't try writing any more but return the error
1827            to the application thread. */
1828         err = out_err;
1829         write_finished = 1;
1830       } else if (dontblock) {
1831         /* non-blocking write is done on ERR_MEM, set error according
1832            to partial write or not */
1833         err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1834         write_finished = 1;
1835       }
1836     } else {
1837       /* On errors != ERR_MEM, we don't try writing any more but return
1838          the error to the application thread. */
1839       write_finished = 1;
1840     }
1841   }
1842   if (write_finished) {
1843     /* everything was written: set back connection state
1844        and back to application task */
1845     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1846     conn->current_msg->err = err;
1847     conn->current_msg = NULL;
1848     conn->state = NETCONN_NONE;
1849 #if LWIP_TCPIP_CORE_LOCKING
1850     if (delayed)
1851 #endif
1852     {
1853       sys_sem_signal(op_completed_sem);
1854     }
1855   }
1856 #if LWIP_TCPIP_CORE_LOCKING
1857   else {
1858     return ERR_MEM;
1859   }
1860 #endif
1861   return ERR_OK;
1862 }
1863 #endif /* LWIP_TCP */
1864 
1865 /**
1866  * Send some data on a TCP pcb contained in a netconn
1867  * Called from netconn_write
1868  *
1869  * @param m the api_msg pointing to the connection
1870  */
1871 void
1872 lwip_netconn_do_write(void *m)
1873 {
1874   struct api_msg *msg = (struct api_msg *)m;
1875 
1876   err_t err = netconn_err(msg->conn);
1877   if (err == ERR_OK) {
1878     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1879 #if LWIP_TCP
1880       if (msg->conn->state != NETCONN_NONE) {
1881         /* netconn is connecting, closing or in blocking write */
1882         err = ERR_INPROGRESS;
1883       } else if (msg->conn->pcb.tcp != NULL) {
1884         msg->conn->state = NETCONN_WRITE;
1885         /* set all the variables used by lwip_netconn_do_writemore */
1886         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1887         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1888         msg->conn->current_msg = msg;
1889 #if LWIP_TCPIP_CORE_LOCKING
1890         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1891           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1892           UNLOCK_TCPIP_CORE();
1893           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1894           LOCK_TCPIP_CORE();
1895           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1896         }
1897 #else /* LWIP_TCPIP_CORE_LOCKING */
1898         lwip_netconn_do_writemore(msg->conn);
1899 #endif /* LWIP_TCPIP_CORE_LOCKING */
1900         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1901            since lwip_netconn_do_writemore ACKs it! */
1902         return;
1903       } else {
1904         err = ERR_CONN;
1905       }
1906 #else /* LWIP_TCP */
1907       err = ERR_VAL;
1908 #endif /* LWIP_TCP */
1909 #if (LWIP_UDP || LWIP_RAW)
1910     } else {
1911       err = ERR_VAL;
1912 #endif /* (LWIP_UDP || LWIP_RAW) */
1913     }
1914   }
1915   msg->err = err;
1916   TCPIP_APIMSG_ACK(msg);
1917 }
1918 
1919 /**
1920  * Return a connection's local or remote address
1921  * Called from netconn_getaddr
1922  *
1923  * @param m the api_msg pointing to the connection
1924  */
1925 void
1926 lwip_netconn_do_getaddr(void *m)
1927 {
1928   struct api_msg *msg = (struct api_msg *)m;
1929 
1930   if (msg->conn->pcb.ip != NULL) {
1931     if (msg->msg.ad.local) {
1932       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1933                    msg->conn->pcb.ip->local_ip);
1934     } else {
1935       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1936                    msg->conn->pcb.ip->remote_ip);
1937     }
1938 
1939     msg->err = ERR_OK;
1940     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1941 #if LWIP_RAW
1942       case NETCONN_RAW:
1943         if (msg->msg.ad.local) {
1944           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1945         } else {
1946           /* return an error as connecting is only a helper for upper layers */
1947           msg->err = ERR_CONN;
1948         }
1949         break;
1950 #endif /* LWIP_RAW */
1951 #if LWIP_UDP
1952       case NETCONN_UDP:
1953         if (msg->msg.ad.local) {
1954           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1955         } else {
1956           if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1957             msg->err = ERR_CONN;
1958           } else {
1959             API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1960           }
1961         }
1962         break;
1963 #endif /* LWIP_UDP */
1964 #if LWIP_TCP
1965       case NETCONN_TCP:
1966         if ((msg->msg.ad.local == 0) &&
1967             ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1968           /* pcb is not connected and remote name is requested */
1969           msg->err = ERR_CONN;
1970         } else {
1971           API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1972         }
1973         break;
1974 #endif /* LWIP_TCP */
1975       default:
1976         LWIP_ASSERT("invalid netconn_type", 0);
1977         break;
1978     }
1979   } else {
1980     msg->err = ERR_CONN;
1981   }
1982   TCPIP_APIMSG_ACK(msg);
1983 }
1984 
1985 /**
1986  * Close or half-shutdown a TCP pcb contained in a netconn
1987  * Called from netconn_close
1988  * In contrast to closing sockets, the netconn is not deallocated.
1989  *
1990  * @param m the api_msg pointing to the connection
1991  */
1992 void
1993 lwip_netconn_do_close(void *m)
1994 {
1995   struct api_msg *msg = (struct api_msg *)m;
1996 
1997 #if LWIP_TCP
1998   enum netconn_state state = msg->conn->state;
1999   /* First check if this is a TCP netconn and if it is in a correct state
2000       (LISTEN doesn't support half shutdown) */
2001   if ((msg->conn->pcb.tcp != NULL) &&
2002       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
2003       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
2004     /* Check if we are in a connected state */
2005     if (state == NETCONN_CONNECT) {
2006       /* TCP connect in progress: cannot shutdown */
2007       msg->err = ERR_CONN;
2008     } else if (state == NETCONN_WRITE) {
2009 #if LWIP_NETCONN_FULLDUPLEX
2010       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
2011         /* close requested, abort running write */
2012         sys_sem_t *write_completed_sem;
2013         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
2014         write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2015         msg->conn->current_msg->err = ERR_CLSD;
2016         msg->conn->current_msg = NULL;
2017         msg->conn->state = NETCONN_NONE;
2018         state = NETCONN_NONE;
2019         sys_sem_signal(write_completed_sem);
2020       } else {
2021         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
2022         /* In this case, let the write continue and do not interfere with
2023            conn->current_msg or conn->state! */
2024         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
2025       }
2026     }
2027     if (state == NETCONN_NONE) {
2028 #else /* LWIP_NETCONN_FULLDUPLEX */
2029       msg->err = ERR_INPROGRESS;
2030     } else {
2031 #endif /* LWIP_NETCONN_FULLDUPLEX */
2032       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
2033 #if LWIP_NETCONN_FULLDUPLEX
2034         /* Mark mboxes invalid */
2035         netconn_mark_mbox_invalid(msg->conn);
2036 #else /* LWIP_NETCONN_FULLDUPLEX */
2037         netconn_drain(msg->conn);
2038 #endif /* LWIP_NETCONN_FULLDUPLEX */
2039       }
2040       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
2041       msg->conn->state = NETCONN_CLOSE;
2042       msg->conn->current_msg = msg;
2043 #if LWIP_TCPIP_CORE_LOCKING
2044       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
2045         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
2046         UNLOCK_TCPIP_CORE();
2047         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2048         LOCK_TCPIP_CORE();
2049         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
2050       }
2051 #else /* LWIP_TCPIP_CORE_LOCKING */
2052       lwip_netconn_do_close_internal(msg->conn);
2053 #endif /* LWIP_TCPIP_CORE_LOCKING */
2054       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
2055       return;
2056     }
2057   } else
2058 #endif /* LWIP_TCP */
2059   {
2060     msg->err = ERR_CONN;
2061   }
2062   TCPIP_APIMSG_ACK(msg);
2063 }
2064 
2065 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
2066 /**
2067  * Join multicast groups for UDP netconns.
2068  * Called from netconn_join_leave_group
2069  *
2070  * @param m the api_msg pointing to the connection
2071  */
2072 void
2073 lwip_netconn_do_join_leave_group(void *m)
2074 {
2075   struct api_msg *msg = (struct api_msg *)m;
2076 
2077   msg->err = ERR_CONN;
2078   if (msg->conn->pcb.tcp != NULL) {
2079     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2080 #if LWIP_UDP
2081 #if LWIP_IPV6 && LWIP_IPV6_MLD
2082       if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2083         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2084           msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2085                                     ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2086         } else {
2087           msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2088                                      ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2089         }
2090       } else
2091 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2092       {
2093 #if LWIP_IGMP
2094         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2095           msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2096                                     ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2097         } else {
2098           msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2099                                      ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2100         }
2101 #endif /* LWIP_IGMP */
2102       }
2103 #endif /* LWIP_UDP */
2104 #if (LWIP_TCP || LWIP_RAW)
2105     } else {
2106       msg->err = ERR_VAL;
2107 #endif /* (LWIP_TCP || LWIP_RAW) */
2108     }
2109   }
2110   TCPIP_APIMSG_ACK(msg);
2111 }
2112 /**
2113  * Join multicast groups for UDP netconns.
2114  * Called from netconn_join_leave_group_netif
2115  *
2116  * @param m the api_msg pointing to the connection
2117  */
2118 void
2119 lwip_netconn_do_join_leave_group_netif(void *m)
2120 {
2121   struct api_msg *msg = (struct api_msg *)m;
2122   struct netif *netif;
2123 #ifdef LOSCFG_NET_CONTAINER
2124   struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip);
2125 
2126   if (group != NULL) {
2127     netif = netif_get_by_index(msg->msg.jl.if_idx, group);
2128   } else {
2129     netif = NULL;
2130   }
2131 #else
2132   netif = netif_get_by_index(msg->msg.jl.if_idx);
2133 #endif
2134 
2135   if (netif == NULL) {
2136     msg->err = ERR_IF;
2137     goto done;
2138   }
2139 
2140   msg->err = ERR_CONN;
2141   if (msg->conn->pcb.tcp != NULL) {
2142     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2143 #if LWIP_UDP
2144 #if LWIP_IPV6 && LWIP_IPV6_MLD
2145       if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2146         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2147           msg->err = mld6_joingroup_netif(netif,
2148                                           ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2149         } else {
2150           msg->err = mld6_leavegroup_netif(netif,
2151                                            ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2152         }
2153       } else
2154 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2155       {
2156 #if LWIP_IGMP
2157         if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2158           msg->err = igmp_joingroup_netif(netif,
2159                                           ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2160         } else {
2161           msg->err = igmp_leavegroup_netif(netif,
2162                                            ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2163         }
2164 #endif /* LWIP_IGMP */
2165       }
2166 #endif /* LWIP_UDP */
2167 #if (LWIP_TCP || LWIP_RAW)
2168     } else {
2169       msg->err = ERR_VAL;
2170 #endif /* (LWIP_TCP || LWIP_RAW) */
2171     }
2172   }
2173 
2174 done:
2175   TCPIP_APIMSG_ACK(msg);
2176 }
2177 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2178 
2179 #if LWIP_DNS
2180 /**
2181  * Callback function that is called when DNS name is resolved
2182  * (or on timeout). A waiting application thread is waked up by
2183  * signaling the semaphore.
2184  */
2185 static void
2186 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
2187 {
2188   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2189 
2190   /* we trust the internal implementation to be correct :-) */
2191   LWIP_UNUSED_ARG(name);
2192 
2193   if (ipaddr == NULL) {
2194     /* timeout or memory error */
2195     API_EXPR_DEREF(msg->err) = ERR_VAL;
2196   } else {
2197     /* address was resolved */
2198     API_EXPR_DEREF(msg->err) = ERR_OK;
2199     API_EXPR_DEREF(msg->addr) = *ipaddr;
2200   }
2201   /* wake up the application task waiting in netconn_gethostbyname */
2202   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2203 }
2204 
2205 /**
2206  * Execute a DNS query
2207  * Called from netconn_gethostbyname
2208  *
2209  * @param arg the dns_api_msg pointing to the query
2210  */
2211 void
2212 lwip_netconn_do_gethostbyname(void *arg)
2213 {
2214   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2215   u8_t addrtype =
2216 #if LWIP_IPV4 && LWIP_IPV6
2217     msg->dns_addrtype;
2218 #else
2219     LWIP_DNS_ADDRTYPE_DEFAULT;
2220 #endif
2221 
2222   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
2223                              API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
2224 #if LWIP_TCPIP_CORE_LOCKING
2225   /* For core locking, only block if we need to wait for answer/timeout */
2226   if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
2227     UNLOCK_TCPIP_CORE();
2228     sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
2229     LOCK_TCPIP_CORE();
2230     LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
2231   }
2232 #else /* LWIP_TCPIP_CORE_LOCKING */
2233   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2234     /* on error or immediate success, wake up the application
2235      * task waiting in netconn_gethostbyname */
2236     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2237   }
2238 #endif /* LWIP_TCPIP_CORE_LOCKING */
2239 }
2240 #endif /* LWIP_DNS */
2241 
2242 #endif /* LWIP_NETCONN */
2243