• 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 #include "netif/etharp.h"
57 
58 #include <string.h>
59 
60 /* netconns are polled once per second (e.g. continue write on memory error) */
61 #define NETCONN_TCP_POLL_INTERVAL 2
62 
63 #define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
64   netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
65 } else { \
66   netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
67 #define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
68 
69 #if LWIP_NETCONN_FULLDUPLEX
70 #define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
71 #else
72 #define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
73 #endif
74 
75 /* forward declarations */
76 #if LWIP_TCP
77 #if LWIP_TCPIP_CORE_LOCKING
78 #define WRITE_DELAYED         , 1
79 #define WRITE_DELAYED_PARAM   , u8_t delayed
80 #else /* LWIP_TCPIP_CORE_LOCKING */
81 #define WRITE_DELAYED
82 #define WRITE_DELAYED_PARAM
83 #endif /* LWIP_TCPIP_CORE_LOCKING */
84 static err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
85 static err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
86 #endif
87 
88 static void netconn_drain(struct netconn *conn);
89 
90 #if LWIP_TCPIP_CORE_LOCKING
91 #define TCPIP_APIMSG_ACK(m)   NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
92 #else /* LWIP_TCPIP_CORE_LOCKING */
93 #define TCPIP_APIMSG_ACK(m)   do { \
94   NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); \
95   sys_sem_signal(LWIP_API_MSG_SEM(m)); \
96 } while (0)
97 #endif /* LWIP_TCPIP_CORE_LOCKING */
98 
99 #if LWIP_NETCONN_FULLDUPLEX
100 const u8_t netconn_deleted = 0;
101 
102 int
lwip_netconn_is_deallocated_msg(void * msg)103 lwip_netconn_is_deallocated_msg(void *msg)
104 {
105   if (msg == &netconn_deleted) {
106     return 1;
107   }
108   return 0;
109 }
110 #endif /* LWIP_NETCONN_FULLDUPLEX */
111 
112 #if LWIP_TCP
113 const u8_t netconn_aborted = 0;
114 const u8_t netconn_reset = 0;
115 const u8_t netconn_closed = 0;
116 
117 /** Translate an error to a unique void* passed via an mbox */
118 static void *
lwip_netconn_err_to_msg(err_t err)119 lwip_netconn_err_to_msg(err_t err)
120 {
121   switch (err) {
122     case ERR_ABRT:
123       return LWIP_CONST_CAST(void *, &netconn_aborted);
124     case ERR_RST:
125       return LWIP_CONST_CAST(void *, &netconn_reset);
126     case ERR_CLSD:
127       return LWIP_CONST_CAST(void *, &netconn_closed);
128     default:
129       LWIP_ASSERT("unhandled error", err == ERR_OK);
130       return NULL;
131   }
132 }
133 
134 int
lwip_netconn_is_err_msg(void * msg,err_t * err)135 lwip_netconn_is_err_msg(void *msg, err_t *err)
136 {
137   LWIP_ASSERT("err != NULL", err != NULL);
138 
139   if (msg == &netconn_aborted) {
140     *err = ERR_ABRT;
141     return 1;
142   } else if (msg == &netconn_reset) {
143     *err = ERR_RST;
144     return 1;
145   } else if (msg == &netconn_closed) {
146     *err = ERR_CLSD;
147     return 1;
148   }
149   return 0;
150 }
151 #endif /* LWIP_TCP */
152 
153 
154 #if LWIP_RAW
155 
156 #ifndef IPPROTO_RAW
157 #define IPPROTO_RAW     255
158 #endif
159 
160 /**
161  * Receive callback function for RAW netconns.
162  * Doesn't 'eat' the packet, only copies it and sends it to
163  * conn->recvmbox
164  *
165  * @see raw.h (struct raw_pcb.recv) for parameters and return value
166  */
167 static u8_t
recv_raw(void * arg,struct raw_pcb * pcb,struct pbuf * p,const ip_addr_t * addr)168 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
169          const ip_addr_t *addr)
170 {
171   struct pbuf *q;
172   struct netbuf *buf;
173   struct netconn *conn;
174 #if LWIP_SO_RCVBUF
175   int recv_avail;
176 #endif
177 #if LWIP_SOCK_FILTER && PF_PKT_SUPPORT
178   s32_t ret_filter;
179 #endif /* LWIP_SOCK_FILTER && PF_PKT_SUPPORT */
180 
181   LWIP_UNUSED_ARG(addr);
182   conn = (struct netconn *)arg;
183 
184   if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
185 #if LWIP_SOCK_FILTER && PF_PKT_SUPPORT
186     /* do filter at the very beginning to make decision to accept or drop packets */
187     if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_PKT_RAW) && (conn->sk_filter.filter) &&
188         (pbuf_header(p, -ETH_PAD_SIZE) == 0)) {
189       /* drop the PAD size bytes */
190       ret_filter = sock_filter(conn, p);
191       (void)pbuf_header(p, ETH_PAD_SIZE);
192       if (ret_filter == EPERM) {
193         return 0;
194       }
195     }
196 #endif /* LWIP_SOCK_FILTER && PF_PKT_SUPPORT */
197 #if LWIP_SO_RCVBUF
198     SYS_ARCH_GET(conn->recv_avail, recv_avail);
199     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
200       return 0;
201     }
202 #endif /* LWIP_SO_RCVBUF */
203     /* copy the whole packet into new pbufs */
204     q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
205     if (q != NULL) {
206       u16_t len;
207       buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
208       if (buf == NULL) {
209         pbuf_free(q);
210         return 0;
211       }
212 
213 #if PF_PKT_SUPPORT
214       /* To get the pkt type filtered in ethernet_input */
215       q->flags = p->flags;
216 #if ETH_PAD_SIZE
217       /* exclude the begining two padding bytes in struct eth_hdr */
218       if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_PKT_RAW) && (pbuf_header(q, -ETH_PAD_SIZE))) {
219         (void)pbuf_free(q);
220         memp_free(MEMP_NETBUF, buf);
221         return 0;
222       }
223 #endif
224 #endif
225 
226       buf->p = q;
227       buf->ptr = q;
228 #if PF_PKT_SUPPORT
229       /* IP addr is NULL only when RAW packets are received for PF_PACKET sockets */
230       if (addr == NULL) {
231         ip_addr_set_any(IP_IS_V6_VAL(buf->addr), &buf->addr);
232         buf->port = eth_current_hdr()->type;
233         buf->hatype = eth_current_netif()->link_layer_type;
234         buf->netifindex = eth_current_netif()->ifindex;
235       } else {
236         ip_addr_copy(buf->addr, *ip_current_src_addr());
237         buf->port = pcb->raw_proto;
238       }
239 #else
240       ip_addr_copy(buf->addr, *ip_current_src_addr());
241       buf->port = pcb->protocol;
242 #endif
243 
244       len = q->tot_len;
245       if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
246         netbuf_delete(buf);
247         return 0;
248       } else {
249 #if LWIP_SO_RCVBUF
250         SYS_ARCH_INC(conn->recv_avail, len);
251 #endif /* LWIP_SO_RCVBUF */
252         /* Register event with callback */
253         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
254         return 1;
255       }
256     }
257   }
258 
259   return 0; /* do not eat the packet */
260 }
261 #endif /* LWIP_RAW*/
262 
263 #if LWIP_UDP
264 /**
265  * Receive callback function for UDP netconns.
266  * Posts the packet to conn->recvmbox or deletes it on memory error.
267  *
268  * @see udp.h (struct udp_pcb.recv) for parameters
269  */
270 void
recv_udp(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)271 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
272          const ip_addr_t *addr, u16_t port)
273 {
274   struct netbuf *buf;
275   struct netconn *conn;
276   u16_t len;
277 #if LWIP_SO_RCVBUF
278   int recv_avail;
279 #endif /* LWIP_SO_RCVBUF */
280 
281   LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
282   LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
283   LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
284   conn = (struct netconn *)arg;
285 
286   if (conn == NULL) {
287     pbuf_free(p);
288     return;
289   }
290 
291   LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
292 
293 #if LWIP_SO_RCVBUF
294   SYS_ARCH_GET(conn->recv_avail, recv_avail);
295   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
296       ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
297 #else  /* LWIP_SO_RCVBUF */
298   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
299 #endif /* LWIP_SO_RCVBUF */
300     pbuf_free(p);
301     return;
302   }
303 
304   buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
305   if (buf == NULL) {
306     pbuf_free(p);
307     return;
308   } else {
309     buf->p = p;
310     buf->ptr = p;
311     ip_addr_set(&buf->addr, addr);
312     buf->port = port;
313 #if LWIP_NETBUF_RECVINFO
314     if (conn->flags & NETCONN_FLAG_PKTINFO) {
315       /* get the UDP header - always in the first pbuf, ensured by udp_input */
316       const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
317       buf->flags = NETBUF_FLAG_DESTADDR;
318       ip_addr_set(&buf->toaddr, ip_current_dest_addr());
319       buf->toport_chksum = udphdr->dest;
320     }
321 #endif /* LWIP_NETBUF_RECVINFO */
322   }
323 
324   len = p->tot_len;
325   if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
326     netbuf_delete(buf);
327     return;
328   } else {
329 #if LWIP_SO_RCVBUF
330     SYS_ARCH_INC(conn->recv_avail, len);
331 #endif /* LWIP_SO_RCVBUF */
332     /* Register event with callback */
333     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
334   }
335 }
336 #endif /* LWIP_UDP */
337 
338 #if LWIP_TCP
339 /**
340  * Receive callback function for TCP netconns.
341  * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
342  *
343  * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
344  */
345 static err_t
346 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
347 {
348   struct netconn *conn;
349   u16_t len;
350   void *msg;
351 
352   LWIP_UNUSED_ARG(pcb);
353   LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
354   LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
355   LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
356   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
357   conn = (struct netconn *)arg;
358 
359   if (conn == NULL) {
360     return ERR_VAL;
361   }
362   LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
363 
364   if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
365     /* recvmbox already deleted */
366     if (p != NULL) {
367       tcp_recved(pcb, p->tot_len);
368       pbuf_free(p);
369     }
370     return ERR_OK;
371   }
372   /* Unlike for UDP or RAW pcbs, don't check for available space
373      using recv_avail since that could break the connection
374      (data is already ACKed) */
375 
376   if (p != NULL) {
377     msg = p;
378     len = p->tot_len;
379   } else {
380     conn->shutdown = RCV_SHUTDOWN;
381     msg = LWIP_CONST_CAST(void *, &netconn_closed);
382     len = 0;
383   }
384 
385   if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
386     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
387     return ERR_MEM;
388   } else {
389 #if LWIP_SO_RCVBUF
390     SYS_ARCH_INC(conn->recv_avail, len);
391 #endif /* LWIP_SO_RCVBUF */
392     /* Register event with callback */
393     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
394   }
395 
396   return ERR_OK;
397 }
398 
399 /**
400  * Poll callback function for TCP netconns.
401  * Wakes up an application thread that waits for a connection to close
402  * or data to be sent. The application thread then takes the
403  * appropriate action to go on.
404  *
405  * Signals the conn->sem.
406  * netconn_close waits for conn->sem if closing failed.
407  *
408  * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
409  */
410 static err_t
411 poll_tcp(void *arg, struct tcp_pcb *pcb)
412 {
413   struct netconn *conn = (struct netconn *)arg;
414 
415   LWIP_UNUSED_ARG(pcb);
416   LWIP_ASSERT("conn != NULL", (conn != NULL));
417 
418   if (conn->state == NETCONN_WRITE) {
419     lwip_netconn_do_writemore(conn  WRITE_DELAYED);
420   } else if (conn->state == NETCONN_CLOSE) {
421 #if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
422     if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
423       conn->current_msg->msg.sd.polls_left--;
424     }
425 #endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
426     lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
427   }
428   /* @todo: implement connect timeout here? */
429 
430   /* Did a nonblocking write fail before? Then check available write-space. */
431   if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
432     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
433        let select mark this pcb as writable again. */
434     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
435         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
436       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
437       API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
438     }
439   }
440 
441   return ERR_OK;
442 }
443 
444 #if LWIP_LOWPOWER
445 /* check wether need to poll tcp */
446 u8_t
447 poll_tcp_needed(void *arg, struct tcp_pcb *pcb)
448 {
449   struct netconn *conn = (struct netconn *)arg;
450   u8_t ret = 0;
451 
452   LWIP_UNUSED_ARG(pcb);
453   if (conn == NULL) {
454     return 0;
455   }
456   if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
457     ret = 1;
458   }
459 
460   /* Did a nonblocking write fail before? Then check available write-space. */
461   if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) {
462     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
463        let select mark this pcb as writable again. */
464     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > conn->pcb.tcp->snd_buf_lowat) &&
465         (tcp_sndqueuelen(conn->pcb.tcp) < conn->pcb.tcp->snd_queuelen_lowat)) {
466       ret = 1;
467     }
468   }
469   return ret;
470 }
471 #endif /* LWIP_LOWPOWER */
472 
473 /**
474  * Sent callback function for TCP netconns.
475  * Signals the conn->sem and calls API_EVENT.
476  * netconn_write waits for conn->sem if send buffer is low.
477  *
478  * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
479  */
480 static err_t
481 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
482 {
483   struct netconn *conn = (struct netconn *)arg;
484 
485   LWIP_UNUSED_ARG(pcb);
486   LWIP_ASSERT("conn != NULL", (conn != NULL));
487 
488   if (conn) {
489     if (conn->state == NETCONN_WRITE) {
490       lwip_netconn_do_writemore(conn  WRITE_DELAYED);
491     } else if (conn->state == NETCONN_CLOSE) {
492       lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
493     }
494 
495     /* If the queued byte- or pbuf-count drops below the configured low-water limit,
496        let select mark this pcb as writable again. */
497     if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
498         (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
499       netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
500       API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
501     }
502   }
503 
504   return ERR_OK;
505 }
506 
507 /**
508  * Error callback function for TCP netconns.
509  * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
510  * The application thread has then to decide what to do.
511  *
512  * @see tcp.h (struct tcp_pcb.err) for parameters
513  */
514 static void
515 err_tcp(void *arg, err_t err)
516 {
517   struct netconn *conn;
518   enum netconn_state old_state;
519   void *mbox_msg;
520   SYS_ARCH_DECL_PROTECT(lev);
521 
522   conn = (struct netconn *)arg;
523   LWIP_ASSERT("conn != NULL", (conn != NULL));
524 
525   SYS_ARCH_PROTECT(lev);
526 
527   if (err == ERR_RST) {
528     conn->refused_data = conn->pcb.tcp->refused_data;
529     conn->pcb.tcp->refused_data = NULL;
530     conn->pending_err = NETCONN_PENDING_ERR_RST;
531   }
532 
533   if (conn->pcb.tcp->tcp_pcb_flag & TCP_PBUF_FLAG_TCP_FIN_RECV_SYSPOST_FAIL) {
534     conn->pending_err = NETCONN_PENDING_ERR_FIN_RST;
535   }
536 
537   /* when err is called, the pcb is deallocated, so delete the reference */
538   conn->pcb.tcp = NULL;
539   /* store pending error */
540   conn->last_err = err;
541   /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
542   conn->flags |= NETCONN_FLAG_MBOXCLOSED;
543 
544   /* reset conn->state now before waking up other threads */
545   old_state = conn->state;
546   conn->state = NETCONN_NONE;
547 
548   /* close both direction for tcp connection in err state */
549   conn->shutdown = SHUTDOWN_MASK;
550 
551   if (old_state == NETCONN_CLOSE) {
552     /* RST during close: let close return success & dealloc the netconn */
553     err = ERR_OK;
554     NETCONN_SET_SAFE_ERR_VAL(conn, ERR_OK);
555   } else {
556     /* no check since this is always fatal! */
557     SYS_ARCH_SET(conn->last_err, err);
558   }
559 
560   SYS_ARCH_UNPROTECT(lev);
561 
562   /* Notify the user layer about a connection error. Used to signal select. */
563   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
564   /* Try to release selects pending on 'read' or 'write', too.
565      They will get an error if they actually try to read or write. */
566   API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
567   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
568 
569   mbox_msg = lwip_netconn_err_to_msg(err);
570   /* pass error message to recvmbox to wake up pending recv */
571   if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
572     /* use trypost to prevent deadlock */
573     /* [Bug: 50912] No need to worry about whether post is success or not here.
574      * Scenario 1) When DATA is already made the recvmbox full and RST is received.
575      * ----Flag pending_error is marked NETCONN_PENDING_ERR_RST which upon user calling
576      *     recv() will ensure that the refused data will be given to user and the final recv() will
577      *     return with -1 and errno -104
578      *   Scenario 2) When DATA is already made the recvmbox full and FIN and RST is received (Both FIN post
579      *     and RST post has failed)
580      *   ---- Flag pending_error is marked NETCONN_PENDING_ERR_FIN_RST which upon user calling
581      *          recv() will ensure that the refused data will be given to user and the subsequent first
582      *          recv() will return 0 to user for FIN and mnest subsequent recv() will return with -1
583      *          and errno -104
584      */
585     sys_mbox_trypost(&conn->recvmbox, mbox_msg);
586   }
587   /* pass error message to acceptmbox to wake up pending accept */
588   if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
589     /* use trypost to preven deadlock */
590     sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
591   }
592 
593   if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
594       (old_state == NETCONN_CONNECT)) {
595     /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
596        since the pcb has already been deleted! */
597     int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
598     SET_NONBLOCKING_CONNECT(conn, 0);
599 
600     if (!was_nonblocking_connect) {
601       sys_sem_t *op_completed_sem;
602       /* set error return code */
603       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
604       if (old_state == NETCONN_CLOSE) {
605         /* let close succeed: the connection is closed after all... */
606         conn->current_msg->err = ERR_OK;
607       } else {
608         /* Write and connect fail */
609         conn->current_msg->err = err;
610       }
611       op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
612       LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
613       conn->current_msg = NULL;
614       /* wake up the waiting task */
615       sys_sem_signal(op_completed_sem);
616     } else {
617       /* @todo: test what happens for error on nonblocking connect */
618     }
619   } else {
620     LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
621   }
622 }
623 
624 #if DRIVER_STATUS_CHECK
625 void update_tcp_sndplus_event(void *arg, const struct tcp_pcb *pcb)
626 {
627   struct netconn *conn = (struct netconn *)arg;
628 
629   LWIP_UNUSED_ARG(pcb);
630   LWIP_ASSERT("conn != NULL", (conn != NULL));
631 
632   if (netconn_is_nonblocking(conn)) {
633     API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
634   }
635   return;
636 }
637 #endif
638 
639 /**
640  * Setup a tcp_pcb with the correct callback function pointers
641  * and their arguments.
642  *
643  * @param conn the TCP netconn to setup
644  */
645 static void
646 setup_tcp(struct netconn *conn)
647 {
648   struct tcp_pcb *pcb;
649 
650   pcb = conn->pcb.tcp;
651   tcp_arg(pcb, conn);
652   tcp_recv(pcb, recv_tcp);
653   tcp_sent(pcb, sent_tcp);
654   tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
655   tcp_err(pcb, err_tcp);
656 #if DRIVER_STATUS_CHECK
657   pcb->sndplus =  update_tcp_sndplus_event;
658 #endif
659 }
660 
661 /**
662  * Accept callback function for TCP netconns.
663  * Allocates a new netconn and posts that to conn->acceptmbox.
664  *
665  * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
666  */
667 static err_t
668 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
669 {
670   struct netconn *newconn;
671   struct netconn *conn = (struct netconn *)arg;
672 
673   if (conn == NULL) {
674     return ERR_VAL;
675   }
676 
677   if (NETCONNTYPE_GROUP(NETCONN_TYPE(conn)) != NETCONN_TCP) {
678     return ERR_VAL;
679   }
680 
681   if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
682     LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
683     return ERR_VAL;
684   }
685 
686   if (newpcb == NULL) {
687     /* out-of-pcbs during connect: pass on this error to the application */
688     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
689       /* Register event with callback */
690       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
691     }
692     /* connection will be aborted here */
693     tcp_err(newpcb, NULL);
694     tcp_arg(newpcb, NULL);
695     return ERR_VAL;
696   }
697   LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
698   LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
699 
700   LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
701 
702   /* We have to set the callback here even though
703    * the new socket is unknown. newconn->socket is marked as -1. */
704   newconn = netconn_alloc(conn->type, conn->callback);
705   if (newconn == NULL) {
706     /* outof netconns: pass on this error to the application */
707     if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
708       /* Register event with callback */
709       API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
710     }
711     return ERR_MEM;
712   }
713   newconn->pcb.tcp = newpcb;
714   setup_tcp(newconn);
715   (void)atomic_set(&newconn->tcp_connected, 1);
716   /* no protection: when creating the pcb, the netconn is not yet known
717      to the application thread */
718   newconn->last_err = err;
719 
720   ip_addr_copy(newconn->remote_ip, newpcb->remote_ip);
721   newconn->remote_port = newpcb->remote_port;
722 
723   /* handle backlog counter */
724   tcp_backlog_delayed(newpcb);
725 
726   if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
727     /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
728        so do nothing here! */
729     /* remove all references to this netconn from the pcb */
730     struct tcp_pcb *pcb = newconn->pcb.tcp;
731     tcp_arg(pcb, NULL);
732     tcp_recv(pcb, NULL);
733     tcp_sent(pcb, NULL);
734     tcp_poll(pcb, NULL, 0);
735     tcp_err(pcb, NULL);
736     /* remove reference from to the pcb from this netconn */
737     newconn->pcb.tcp = NULL;
738     /* no need to drain since we know the recvmbox is empty. */
739     sys_mbox_free(&newconn->recvmbox);
740     sys_mbox_set_invalid(&newconn->recvmbox);
741     netconn_free(newconn);
742     return ERR_MEM;
743   } else {
744 #if LWIP_SO_RCVBUF
745     SYS_ARCH_INC(conn->recv_avail, 1);
746 #endif /* LWIP_SO_RCVBUF */
747     /* Register event with callback */
748     API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
749   }
750 
751   return ERR_OK;
752 }
753 #endif /* LWIP_TCP */
754 
755 /**
756  * Create a new pcb of a specific type.
757  * Called from lwip_netconn_do_newconn().
758  *
759  * @param msg the api_msg describing the connection type
760  */
761 static void
762 pcb_new(struct api_msg *msg)
763 {
764   enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
765 
766   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
767 
768 #if LWIP_IPV6 && LWIP_IPV4
769   /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
770   if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(msg->conn))) {
771     iptype = IPADDR_TYPE_ANY;
772   }
773 #endif
774 
775   /* Allocate a PCB for this connection */
776   switch (NETCONNTYPE_GROUP(msg->conn->type)) {
777 #if LWIP_RAW
778     case NETCONN_RAW:
779       msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
780       if (msg->conn->pcb.raw != NULL) {
781 #if LWIP_IPV6
782 #if LWIP_SOCK_OPT_ICMP6_FILTER
783       /* rfc3542.  Section: 3.2.  ICMPv6 Type Filtering */
784         u32_t i;
785         for (i = 0; i < ICMP_FILTER_LENGTH; i++) {
786           msg->conn->pcb.raw->icmp6_filter.icmp6_filt[i] = 0x00;
787         }
788 #endif
789         /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
790         if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->raw_proto == IP6_NEXTH_ICMP6) {
791           msg->conn->pcb.raw->chksum_reqd = 1;
792           msg->conn->pcb.raw->chksum_offset = RAW_CHKSUM_OFFSET;
793         }
794 #endif /* LWIP_IPV6 */
795 
796 #if LWIP_IPV4
797         /* IP_HDRINCL is enabled by default */
798         if (!(NETCONNTYPE_ISIPV6(msg->conn->type)) && (msg->msg.n.proto == IPPROTO_RAW)) {
799           raw_set_flags(msg->conn->pcb.raw, RAW_FLAGS_HDRINCL);
800         }
801 #endif
802 #if LWIP_SO_PRIORITY
803         msg->conn->pcb.raw->priority = LWIP_PKT_PRIORITY_DEFAULT;
804 #endif /* LWIP_SO_PRIORITY */
805         raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
806       }
807       break;
808 
809 #if PF_PKT_SUPPORT
810   case NETCONN_PKT_RAW:
811     msg->conn->pcb.pkt_raw = raw_pkt_new(msg->msg.n.proto);
812     if (msg->conn->pcb.pkt_raw == NULL) {
813       msg->err = ERR_MEM;
814       break;
815     }
816     raw_recv(msg->conn->pcb.pkt_raw, recv_raw, msg->conn);
817     break;
818 #endif
819 #endif /* LWIP_RAW */
820 #if LWIP_UDP
821     case NETCONN_UDP:
822       msg->conn->pcb.udp = udp_new_ip_type(iptype);
823       if (msg->conn->pcb.udp != NULL) {
824 #if LWIP_UDPLITE
825         if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
826           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
827         }
828 #endif /* LWIP_UDPLITE */
829         if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
830           udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
831         }
832 #if LWIP_SO_PRIORITY
833         msg->conn->pcb.udp->priority = LWIP_PKT_PRIORITY_DEFAULT;
834 #endif /* LWIP_SO_PRIORITY */
835 
836         udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
837       }
838       break;
839 #endif /* LWIP_UDP */
840 #if LWIP_TCP
841     case NETCONN_TCP:
842       msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
843       if (msg->conn->pcb.tcp != NULL) {
844 #if LWIP_SO_PRIORITY
845         msg->conn->pcb.tcp->priority = LWIP_PKT_PRIORITY_DEFAULT;
846 #endif /* LWIP_SO_PRIORITY */
847 
848         setup_tcp(msg->conn);
849       }
850       break;
851 #endif /* LWIP_TCP */
852     default:
853       /* Unsupported netconn type, e.g. protocol disabled */
854       msg->err = ERR_VAL;
855       return;
856   }
857   if (msg->conn->pcb.ip == NULL) {
858     msg->err = ERR_MEM;
859   }
860 }
861 
862 /**
863  * Create a new pcb of a specific type inside a netconn.
864  * Called from netconn_new_with_proto_and_callback.
865  *
866  * @param m the api_msg describing the connection type
867  */
868 void
869 lwip_netconn_do_newconn(void *m)
870 {
871   struct api_msg *msg = (struct api_msg *)m;
872 
873   msg->err = ERR_OK;
874   if (msg->conn->pcb.tcp == NULL) {
875     pcb_new(msg);
876   }
877   /* Else? This "new" connection already has a PCB allocated. */
878   /* Is this an error condition? Should it be deleted? */
879   /* We currently just are happy and return. */
880 
881   TCPIP_APIMSG_ACK(msg);
882 }
883 
884 /**
885  * Create a new netconn (of a specific type) that has a callback function.
886  * The corresponding pcb is NOT created!
887  *
888  * @param t the type of 'connection' to create (@see enum netconn_type)
889  * @param callback a function to call on status changes (RX available, TX'ed)
890  * @return a newly allocated struct netconn or
891  *         NULL on memory error
892  */
893 struct netconn *
894 netconn_alloc(enum netconn_type t, netconn_callback callback)
895 {
896   struct netconn *conn;
897   int size;
898   u8_t init_flags = 0;
899 
900   conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
901   if (conn == NULL) {
902     return NULL;
903   }
904 
905   conn->last_err = ERR_OK;
906   conn->type = t;
907   conn->pcb.tcp = NULL;
908 #if LWIP_NETCONN_FULLDUPLEX
909   conn->mbox_threads_waiting = 0;
910 #endif
911 
912   /* If all sizes are the same, every compiler should optimize this switch to nothing */
913   switch (NETCONNTYPE_GROUP(t)) {
914 #if LWIP_RAW
915 #if PF_PKT_SUPPORT
916     case NETCONN_PKT_RAW:
917 #endif
918     case NETCONN_RAW:
919       size = DEFAULT_RAW_RECVMBOX_SIZE;
920       break;
921 #endif /* LWIP_RAW */
922 #if LWIP_UDP
923     case NETCONN_UDP:
924       size = DEFAULT_UDP_RECVMBOX_SIZE;
925 #if LWIP_NETBUF_RECVINFO
926       init_flags |= NETCONN_FLAG_PKTINFO;
927 #endif /* LWIP_NETBUF_RECVINFO */
928       break;
929 #endif /* LWIP_UDP */
930 #if LWIP_TCP
931     case NETCONN_TCP:
932       size = DEFAULT_TCP_RECVMBOX_SIZE;
933       break;
934 #endif /* LWIP_TCP */
935     default:
936       LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
937       goto free_and_return;
938   }
939 
940   if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
941     goto free_and_return;
942   }
943 #if !LWIP_NETCONN_SEM_PER_THREAD
944   if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
945     sys_mbox_free(&conn->recvmbox);
946     goto free_and_return;
947   }
948 #endif
949 
950 #if LWIP_TCP
951   sys_mbox_set_invalid(&conn->acceptmbox);
952 #endif
953   conn->state        = NETCONN_NONE;
954 #if LWIP_SOCKET
955   /* initialize socket to -1 since 0 is a valid socket */
956   conn->socket       = -1;
957 #endif /* LWIP_SOCKET */
958   conn->callback     = callback;
959 #if LWIP_TCP
960   conn->current_msg  = NULL;
961   conn->write_offset = 0;
962   (void)atomic_set(&conn->tcp_connected, 0);
963 #endif /* LWIP_TCP */
964 #if LWIP_SO_SNDTIMEO
965   conn->send_timeout = 0;
966 #endif /* LWIP_SO_SNDTIMEO */
967 #if LWIP_SO_RCVTIMEO
968   conn->recv_timeout = 0;
969 #endif /* LWIP_SO_RCVTIMEO */
970 #if LWIP_SO_RCVBUF
971   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
972   conn->recv_avail   = 0;
973 #endif /* LWIP_SO_RCVBUF */
974 #if LWIP_SO_LINGER
975   conn->linger = -1;
976 #endif /* LWIP_SO_LINGER */
977   conn->flags = init_flags;
978   conn->shutdown = NON_SHUTDOWN;
979 
980 #if LWIP_SOCK_FILTER
981   conn->sk_filter.len = 0;
982   conn->sk_filter.filter = NULL;
983 #endif
984 #if LWIP_TCP
985   conn->pending_err = 0;
986   conn->refused_data = NULL;
987   ip_addr_set_zero(&conn->remote_ip);
988   conn->remote_port  = 0;
989 #endif
990 
991   return conn;
992 free_and_return:
993   memp_free(MEMP_NETCONN, conn);
994   return NULL;
995 }
996 
997 /**
998  * Delete a netconn and all its resources.
999  * The pcb is NOT freed (since we might not be in the right thread context do this).
1000  *
1001  * @param conn the netconn to free
1002  */
1003 void
1004 netconn_free(struct netconn *conn)
1005 {
1006   LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
1007 
1008 #if LWIP_NETCONN_FULLDUPLEX
1009   /* in fullduplex, netconn is drained here */
1010   netconn_drain(conn);
1011 #endif /* LWIP_NETCONN_FULLDUPLEX */
1012 
1013   LWIP_ASSERT("recvmbox must be deallocated before calling this function",
1014               !sys_mbox_valid(&conn->recvmbox));
1015 #if LWIP_TCP
1016   LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
1017               !sys_mbox_valid(&conn->acceptmbox));
1018 #endif /* LWIP_TCP */
1019 
1020 #if LWIP_TCP
1021   if (conn->refused_data != NULL) {
1022     (void)pbuf_free(conn->refused_data);
1023     conn->refused_data = NULL;
1024   }
1025 #endif
1026 
1027 #if !LWIP_NETCONN_SEM_PER_THREAD
1028   sys_sem_free(&conn->op_completed);
1029   sys_sem_set_invalid(&conn->op_completed);
1030 #endif
1031 #if LWIP_SOCK_FILTER
1032   if (conn->sk_filter.filter != NULL) {
1033     mem_free(conn->sk_filter.filter);
1034     conn->sk_filter.filter = NULL;
1035     conn->sk_filter.len = 0;
1036   }
1037 #endif
1038 
1039   memp_free(MEMP_NETCONN, conn);
1040 }
1041 
1042 /**
1043  * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
1044  * these mboxes
1045  *
1046  * @param conn the netconn to free
1047  * @bytes_drained bytes drained from recvmbox
1048  * @accepts_drained pending connections drained from acceptmbox
1049  */
1050 static void
1051 netconn_drain(struct netconn *conn)
1052 {
1053   void *mem;
1054 
1055   /* This runs when mbox and netconn are marked as closed,
1056      so we don't need to lock against rx packets */
1057 #if LWIP_NETCONN_FULLDUPLEX
1058   LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
1059 #endif /* LWIP_NETCONN_FULLDUPLEX */
1060 
1061   /* Delete and drain the recvmbox. */
1062   if (sys_mbox_valid(&conn->recvmbox)) {
1063     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
1064 #if LWIP_NETCONN_FULLDUPLEX
1065       if (!lwip_netconn_is_deallocated_msg(mem))
1066 #endif /* LWIP_NETCONN_FULLDUPLEX */
1067       {
1068 #if LWIP_TCP
1069         if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
1070           err_t err;
1071           if (!lwip_netconn_is_err_msg(mem, &err)) {
1072             pbuf_free((struct pbuf *)mem);
1073           }
1074         } else
1075 #endif /* LWIP_TCP */
1076         {
1077           netbuf_delete((struct netbuf *)mem);
1078         }
1079       }
1080     }
1081     sys_mbox_free(&conn->recvmbox);
1082     sys_mbox_set_invalid(&conn->recvmbox);
1083   }
1084 
1085   /* Delete and drain the acceptmbox. */
1086 #if LWIP_TCP
1087   if (sys_mbox_valid(&conn->acceptmbox)) {
1088     while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
1089 #if LWIP_NETCONN_FULLDUPLEX
1090       if (!lwip_netconn_is_deallocated_msg(mem))
1091 #endif /* LWIP_NETCONN_FULLDUPLEX */
1092       {
1093         err_t err;
1094         if (!lwip_netconn_is_err_msg(mem, &err)) {
1095           struct netconn *newconn = (struct netconn *)mem;
1096           /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
1097           /* pcb might be set to NULL already by err_tcp() */
1098           /* drain recvmbox */
1099           netconn_drain(newconn);
1100           if (newconn->pcb.tcp != NULL) {
1101             tcp_abort(newconn->pcb.tcp);
1102             newconn->pcb.tcp = NULL;
1103           }
1104           netconn_free(newconn);
1105         }
1106       }
1107     }
1108     sys_mbox_free(&conn->acceptmbox);
1109     sys_mbox_set_invalid(&conn->acceptmbox);
1110   }
1111 #endif /* LWIP_TCP */
1112 }
1113 
1114 #if LWIP_NETCONN_FULLDUPLEX
1115 static void
1116 netconn_mark_mbox_invalid(struct netconn *conn)
1117 {
1118   int i, num_waiting;
1119   void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
1120 
1121   /* Prevent new calls/threads from reading from the mbox */
1122   conn->flags |= NETCONN_FLAG_MBOXINVALID;
1123 
1124   SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
1125   for (i = 0; i < num_waiting; i++) {
1126     if (sys_mbox_valid_val(conn->recvmbox)) {
1127       sys_mbox_trypost(&conn->recvmbox, msg);
1128 #if LWIP_TCP
1129     } else if (sys_mbox_valid_val(conn->acceptmbox)) {
1130       sys_mbox_trypost(&conn->acceptmbox, msg);
1131 #endif
1132     } else {
1133       LWIP_DEBUGF(API_MSG_DEBUG, ("warning: mbox already marked invalid\n"));
1134     }
1135   }
1136 }
1137 #endif /* LWIP_NETCONN_FULLDUPLEX */
1138 
1139 #if LWIP_TCP
1140 /**
1141  * Internal helper function to close a TCP netconn: since this sometimes
1142  * doesn't work at the first attempt, this function is called from multiple
1143  * places.
1144  *
1145  * @param conn the TCP netconn to close
1146  */
1147 static err_t
1148 lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
1149 {
1150   err_t err;
1151   u8_t shut, shut_rx, shut_tx, shut_close;
1152   u8_t close_finished = 0;
1153   struct tcp_pcb *tpcb;
1154 #if LWIP_SO_LINGER
1155   u8_t linger_wait_required = 0;
1156 #endif /* LWIP_SO_LINGER */
1157 
1158   LWIP_ASSERT("invalid conn", (conn != NULL));
1159   LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
1160   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
1161   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
1162   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1163 
1164   tpcb = conn->pcb.tcp;
1165   shut = conn->current_msg->msg.sd.shut;
1166   shut_rx = shut & NETCONN_SHUT_RD;
1167   shut_tx = shut & NETCONN_SHUT_WR;
1168   /* shutting down both ends is the same as closing
1169      (also if RD or WR side was shut down before already) */
1170   if (shut == NETCONN_SHUT_RDWR) {
1171     shut_close = 1;
1172   } else if (shut_rx &&
1173              ((tpcb->state == FIN_WAIT_1) ||
1174               (tpcb->state == FIN_WAIT_2) ||
1175               (tpcb->state == CLOSING) ||
1176               (tpcb->state == LAST_ACK) ||
1177               (((tpcb->state == SYN_RCVD) ||
1178                 (tpcb->state == ESTABLISHED) ||
1179                 (tpcb->state == CLOSE_WAIT)) &&
1180                (tpcb->flags & TF_CLOSEPEND)))) {
1181     shut_close = 1;
1182   } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
1183     shut_close = 1;
1184   } else {
1185     shut_close = 0;
1186   }
1187 
1188   /* Set back some callback pointers */
1189   if (shut_close) {
1190     tcp_arg(tpcb, NULL);
1191   }
1192   if (tpcb->state == LISTEN) {
1193     tcp_accept(tpcb, NULL);
1194   } else {
1195     /* some callbacks have to be reset if tcp_close is not successful */
1196     if (shut_rx) {
1197       tcp_recv(tpcb, NULL);
1198       tcp_accept(tpcb, NULL);
1199     }
1200     if (shut_tx) {
1201       tcp_sent(tpcb, NULL);
1202     }
1203     if (shut_close) {
1204       tcp_poll(tpcb, NULL, 0);
1205       tcp_err(tpcb, NULL);
1206     }
1207   }
1208   /* Try to close the connection */
1209   if (shut_close) {
1210 #if LWIP_SO_LINGER
1211     /* check linger possibilites before calling tcp_close */
1212     err = ERR_OK;
1213     /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
1214     if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
1215       if ((conn->linger == 0)) {
1216         /* data left but linger prevents waiting */
1217         tcp_abort(tpcb);
1218         tpcb = NULL;
1219       } else if (conn->linger > 0) {
1220         /* data left and linger says we should wait */
1221         if (netconn_is_nonblocking(conn)) {
1222           /* data left on a nonblocking netconn -> cannot linger */
1223           err = ERR_WOULDBLOCK;
1224         } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
1225                    (conn->linger * 1000)) {
1226           /* data left but linger timeout has expired (this happens on further
1227              calls to this function through poll_tcp */
1228           tcp_abort(tpcb);
1229           tpcb = NULL;
1230         } else {
1231           /* data left -> need to wait for ACK after successful close */
1232           linger_wait_required = 1;
1233         }
1234       }
1235     }
1236     if ((err == ERR_OK) && (tpcb != NULL))
1237 #endif /* LWIP_SO_LINGER */
1238     {
1239       err = tcp_close(tpcb);
1240     }
1241   } else {
1242     err = tcp_shutdown(tpcb, shut_rx, shut_tx);
1243   }
1244   if (err == ERR_OK) {
1245     close_finished = 1;
1246 #if LWIP_SO_LINGER
1247     if (linger_wait_required) {
1248       /* wait for ACK of all unsent/unacked data by just getting called again */
1249       close_finished = 0;
1250       err = ERR_INPROGRESS;
1251     }
1252 #endif /* LWIP_SO_LINGER */
1253   } else {
1254     if (err == ERR_MEM) {
1255       /* Closing failed because of memory shortage, try again later. Even for
1256          nonblocking netconns, we have to wait since no standard socket application
1257          is prepared for close failing because of resource shortage.
1258          Check the timeout: this is kind of an lwip addition to the standard sockets:
1259          we wait for some time when failing to allocate a segment for the FIN */
1260 #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1261       s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
1262 #if LWIP_SO_SNDTIMEO
1263       if (conn->send_timeout > 0) {
1264         close_timeout = conn->send_timeout;
1265       }
1266 #endif /* LWIP_SO_SNDTIMEO */
1267 #if LWIP_SO_LINGER
1268       if (conn->linger >= 0) {
1269         /* use linger timeout (seconds) */
1270         close_timeout = conn->linger * 1000U;
1271       }
1272 #endif
1273       if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
1274 #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1275       if (conn->current_msg->msg.sd.polls_left == 0) {
1276 #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1277         close_finished = 1;
1278         if (shut_close) {
1279           /* in this case, we want to RST the connection */
1280           tcp_abort(tpcb);
1281           err = ERR_OK;
1282         }
1283       }
1284     } else {
1285       /* Closing failed for a non-memory error: give up */
1286       close_finished = 1;
1287     }
1288   }
1289   if (close_finished) {
1290     /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
1291     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1292     conn->current_msg->err = err;
1293     conn->current_msg = NULL;
1294     conn->state = NETCONN_NONE;
1295     if (err == ERR_OK) {
1296       if (shut_close) {
1297         /* Set back some callback pointers as conn is going away */
1298         conn->pcb.tcp = NULL;
1299         /* Trigger select() in socket layer. Make sure everybody notices activity
1300          on the connection, error first! */
1301         API_EVENT(conn, NETCONN_EVT_ERROR, 0);
1302       }
1303       if (shut_rx) {
1304         API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
1305       }
1306       if (shut_tx) {
1307         API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1308       }
1309     }
1310 #if LWIP_TCPIP_CORE_LOCKING
1311     if (delayed)
1312 #endif
1313     {
1314       /* wake up the application task */
1315       sys_sem_signal(op_completed_sem);
1316     }
1317     return ERR_OK;
1318   }
1319   if (!close_finished) {
1320     /* Closing failed and we want to wait: restore some of the callbacks */
1321     /* Closing of listen pcb will never fail! */
1322     LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
1323     if (shut_tx) {
1324       tcp_sent(tpcb, sent_tcp);
1325     }
1326     /* when waiting for close, set up poll interval to 500ms */
1327     tcp_poll(tpcb, poll_tcp, 1);
1328     tcp_err(tpcb, err_tcp);
1329     tcp_arg(tpcb, conn);
1330     /* don't restore recv callback: we don't want to receive any more data */
1331   }
1332   /* If closing didn't succeed, we get called again either
1333      from poll_tcp or from sent_tcp */
1334   LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1335   return err;
1336 }
1337 #endif /* LWIP_TCP */
1338 
1339 /**
1340  * Delete the pcb inside a netconn.
1341  * Called from netconn_delete.
1342  *
1343  * @param m the api_msg pointing to the connection
1344  */
1345 void
1346 lwip_netconn_do_delconn(void *m)
1347 {
1348   struct api_msg *msg = (struct api_msg *)m;
1349 
1350   enum netconn_state state = msg->conn->state;
1351   LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1352               (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1353 #if LWIP_NETCONN_FULLDUPLEX
1354 #if LWIP_TCP
1355   /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1356   if (state != NETCONN_NONE) {
1357     if ((state == NETCONN_WRITE) ||
1358         ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1359       /* close requested, abort running write/connect */
1360       if (msg->conn->current_msg != NULL) {
1361         sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1362         msg->conn->current_msg->err = ERR_CLSD;
1363         msg->conn->current_msg = NULL;
1364         msg->conn->write_offset = 0;
1365         msg->conn->state = NETCONN_NONE;
1366         sys_sem_signal(op_completed_sem);
1367       }
1368     }
1369   }
1370 #endif /* LWIP_TCP */
1371 #else /* LWIP_NETCONN_FULLDUPLEX */
1372   if (((state != NETCONN_NONE) &&
1373        (state != NETCONN_LISTEN) &&
1374        (state != NETCONN_CONNECT)) ||
1375       ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1376     /* This means either a blocking write or blocking connect is running
1377        (nonblocking write returns and sets state to NONE) */
1378     msg->err = ERR_INPROGRESS;
1379   } else
1380 #endif /* LWIP_NETCONN_FULLDUPLEX */
1381   {
1382     LWIP_ASSERT("blocking connect in progress",
1383                 (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1384     msg->err = ERR_OK;
1385 #if LWIP_NETCONN_FULLDUPLEX
1386     /* Mark mboxes invalid */
1387     netconn_mark_mbox_invalid(msg->conn);
1388 #else /* LWIP_NETCONN_FULLDUPLEX */
1389     netconn_drain(msg->conn);
1390 #endif /* LWIP_NETCONN_FULLDUPLEX */
1391 
1392     if (msg->conn->pcb.tcp != NULL) {
1393 
1394       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1395 #if LWIP_RAW
1396         case NETCONN_RAW:
1397           raw_remove(msg->conn->pcb.raw);
1398           break;
1399 #if PF_PKT_SUPPORT
1400         case NETCONN_PKT_RAW:
1401           raw_pkt_remove(msg->conn->pcb.pkt_raw);
1402           break;
1403 #endif
1404 #endif /* LWIP_RAW */
1405 #if LWIP_UDP
1406         case NETCONN_UDP:
1407           msg->conn->pcb.udp->recv_arg = NULL;
1408           udp_remove(msg->conn->pcb.udp);
1409           break;
1410 #endif /* LWIP_UDP */
1411 #if LWIP_TCP
1412         case NETCONN_TCP:
1413           LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
1414             msg->conn->write_offset == 0);
1415           msg->conn->state = NETCONN_CLOSE;
1416           msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1417           msg->conn->current_msg = msg;
1418 #if LWIP_TCPIP_CORE_LOCKING
1419           if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1420             LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1421             UNLOCK_TCPIP_CORE();
1422             sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1423             LOCK_TCPIP_CORE();
1424             LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1425           }
1426 #else /* LWIP_TCPIP_CORE_LOCKING */
1427           lwip_netconn_do_close_internal(msg->conn);
1428 #endif /* LWIP_TCPIP_CORE_LOCKING */
1429           /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1430              the application thread, so we can return at this point! */
1431           return;
1432 #endif /* LWIP_TCP */
1433         default:
1434           break;
1435       }
1436       msg->conn->pcb.tcp = NULL;
1437     }
1438     /* tcp netconns don't come here! */
1439 
1440     /* @todo: this lets select make the socket readable and writable,
1441        which is wrong! errfd instead? */
1442     API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1443     API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1444   }
1445   if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1446     TCPIP_APIMSG_ACK(msg);
1447   }
1448 }
1449 
1450 /**
1451  * Bind a pcb contained in a netconn
1452  * Called from netconn_bind.
1453  *
1454  * @param m the api_msg pointing to the connection and containing
1455  *          the IP address and port to bind to
1456  */
1457 void
1458 lwip_netconn_do_bind(void *m)
1459 {
1460   struct api_msg *msg = (struct api_msg *)m;
1461   struct netif *netif = NULL;
1462   netif = netif_find_by_ipaddr(API_EXPR_REF(msg->msg.bc.ipaddr));
1463 
1464   if (ERR_IS_FATAL(msg->conn->last_err)) {
1465     msg->err = (err_t)((msg->conn->state == NETCONN_CLOSED) ? ERR_VAL : msg->conn->last_err);
1466   } else if (!(ip_addr_isany(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1467              ip_addr_ismulticast(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1468              netif_ipaddr_isbrdcast(API_EXPR_REF(msg->msg.bc.ipaddr)) ||
1469              ((netif != NULL) && netif_is_up(netif)))) {
1470     msg->err = ERR_NOADDR;
1471   } else {
1472     msg->err = ERR_VAL;
1473     if (msg->conn->pcb.tcp != NULL) {
1474       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1475 #if LWIP_RAW
1476       case NETCONN_RAW:
1477         msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1478         break;
1479 #if PF_PKT_SUPPORT
1480       case NETCONN_PKT_RAW:
1481         msg->err = raw_pkt_bind(msg->conn->pcb.pkt_raw, msg->msg.bc.if_idx, msg->msg.bc.port);
1482         break;
1483 #endif
1484 #endif /* LWIP_RAW */
1485 #if LWIP_UDP
1486       case NETCONN_UDP:
1487         msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1488         break;
1489 #endif /* LWIP_UDP */
1490 #if LWIP_TCP
1491       case NETCONN_TCP:
1492         if (msg->conn->pcb.tcp->local_port == 0) {
1493           msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1494         } else {
1495           msg->err = ERR_VAL;
1496         }
1497 
1498         break;
1499 #endif /* LWIP_TCP */
1500       default:
1501         msg->err = ERR_OPNOTSUPP;
1502         break;
1503       }
1504     }
1505   }
1506   TCPIP_APIMSG_ACK(msg);
1507 }
1508 /**
1509  * Bind a pcb contained in a netconn to an interface
1510  * Called from netconn_bind_if.
1511  *
1512  * @param m the api_msg pointing to the connection and containing
1513  *          the IP address and port to bind to
1514  */
1515 void
1516 lwip_netconn_do_bind_if(void *m)
1517 {
1518   struct netif *netif;
1519   struct api_msg *msg = (struct api_msg *)m;
1520   err_t err;
1521 
1522   netif = netif_get_by_index(msg->msg.bc.if_idx);
1523 
1524   if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
1525     err = ERR_OK;
1526     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1527 #if LWIP_RAW
1528       case NETCONN_RAW:
1529         raw_bind_netif(msg->conn->pcb.raw, netif);
1530         break;
1531 #endif /* LWIP_RAW */
1532 #if LWIP_UDP
1533       case NETCONN_UDP:
1534         udp_bind_netif(msg->conn->pcb.udp, netif);
1535         break;
1536 #endif /* LWIP_UDP */
1537 #if LWIP_TCP
1538       case NETCONN_TCP:
1539         tcp_bind_netif(msg->conn->pcb.tcp, netif);
1540         break;
1541 #endif /* LWIP_TCP */
1542       default:
1543         err = ERR_VAL;
1544         break;
1545     }
1546   } else {
1547     err = ERR_VAL;
1548   }
1549   msg->err = err;
1550   TCPIP_APIMSG_ACK(msg);
1551 }
1552 
1553 #if LWIP_TCP
1554 /**
1555  * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1556  * been established (or reset by the remote host).
1557  *
1558  * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1559  */
1560 static err_t
1561 lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1562 {
1563   struct netconn *conn;
1564   int was_blocking;
1565   sys_sem_t *op_completed_sem = NULL;
1566 
1567   LWIP_UNUSED_ARG(pcb);
1568 
1569   conn = (struct netconn *)arg;
1570 
1571   if (conn == NULL) {
1572     return ERR_VAL;
1573   }
1574 
1575   LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1576   LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1577               (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1578 
1579   if (conn->current_msg != NULL) {
1580     conn->current_msg->err = err;
1581     op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1582   }
1583   if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1584     setup_tcp(conn);
1585 #if LWIP_SO_SNDBUF
1586     tcp_sndbuf_init(pcb);
1587 #endif
1588     ip_addr_copy(conn->remote_ip, pcb->remote_ip);
1589     conn->remote_port = pcb->remote_port;
1590     (void)atomic_set(&conn->tcp_connected, 1);
1591   }
1592   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1593   SET_NONBLOCKING_CONNECT(conn, 0);
1594   LWIP_ASSERT("blocking connect state error",
1595               (was_blocking && op_completed_sem != NULL) ||
1596               (!was_blocking && op_completed_sem == NULL));
1597   conn->current_msg = NULL;
1598   conn->state = NETCONN_NONE;
1599   NETCONN_SET_SAFE_ERR_VAL(conn, err);
1600   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1601 
1602   if (was_blocking && (op_completed_sem != NULL)) {
1603     sys_sem_signal(op_completed_sem);
1604   }
1605   return ERR_OK;
1606 }
1607 #endif /* LWIP_TCP */
1608 
1609 /**
1610  * Connect a pcb contained inside a netconn
1611  * Called from netconn_connect.
1612  *
1613  * @param m the api_msg pointing to the connection and containing
1614  *          the IP address and port to connect to
1615  */
1616 void
1617 lwip_netconn_do_connect(void *m)
1618 {
1619   struct api_msg *msg = (struct api_msg *)m;
1620   err_t err;
1621   if (ERR_IS_FATAL(msg->conn->last_err)) {
1622     msg->err =  msg->conn->last_err;
1623     TCPIP_APIMSG_ACK(msg);
1624     return;
1625   }
1626 
1627   if (msg->conn->pcb.tcp == NULL) {
1628     /* This may happen when calling netconn_connect() a second time */
1629     err = ERR_CLSD;
1630   } else {
1631     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1632 #if LWIP_RAW
1633       case NETCONN_RAW:
1634         err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1635         break;
1636 #endif /* LWIP_RAW */
1637 #if LWIP_UDP
1638       case NETCONN_UDP:
1639         err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1640         break;
1641 #endif /* LWIP_UDP */
1642 #if LWIP_TCP
1643       case NETCONN_TCP:
1644         /* Prevent connect while doing any other action. */
1645         if (msg->conn->state == NETCONN_CONNECT) {
1646           err = ERR_ALREADY;
1647         } else if (msg->conn->state == NETCONN_LISTEN) {
1648           err = ERR_OPNOTSUPP;
1649         } else if (msg->conn->state != NETCONN_NONE) {
1650           err = ERR_ISCONN;
1651         } else {
1652           setup_tcp(msg->conn);
1653           err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1654                             msg->msg.bc.port, lwip_netconn_do_connected);
1655           if (err == ERR_OK) {
1656             u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1657             msg->conn->state = NETCONN_CONNECT;
1658             SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1659             if (non_blocking) {
1660               err = ERR_INPROGRESS;
1661             } else {
1662               msg->conn->current_msg = msg;
1663               /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1664                  when the connection is established! */
1665 #if LWIP_TCPIP_CORE_LOCKING
1666               LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1667               UNLOCK_TCPIP_CORE();
1668               sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1669               LOCK_TCPIP_CORE();
1670               LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1671 #endif /* LWIP_TCPIP_CORE_LOCKING */
1672               return;
1673             }
1674           }
1675         }
1676         break;
1677 #endif /* LWIP_TCP */
1678       default:
1679         LWIP_ERROR("Invalid netconn type", 0, do {
1680           err = ERR_VAL;
1681         } while (0));
1682         break;
1683     }
1684   }
1685   msg->err = err;
1686   /* For all other protocols, netconn_connect() calls netconn_apimsg(),
1687      so use TCPIP_APIMSG_ACK() here. */
1688   TCPIP_APIMSG_ACK(msg);
1689 }
1690 
1691 /**
1692  * Disconnect a pcb contained inside a netconn
1693  * Only used for UDP netconns.
1694  * Called from netconn_disconnect.
1695  *
1696  * @param m the api_msg pointing to the connection to disconnect
1697  */
1698 void
1699 lwip_netconn_do_disconnect(void *m)
1700 {
1701   struct api_msg *msg = (struct api_msg *)m;
1702 
1703 #if LWIP_UDP
1704   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1705     udp_disconnect(msg->conn->pcb.udp);
1706     msg->err = ERR_OK;
1707   } else
1708 #endif /* LWIP_UDP */
1709   {
1710     msg->err = ERR_VAL;
1711   }
1712   TCPIP_APIMSG_ACK(msg);
1713 }
1714 
1715 #if LWIP_TCP
1716 /**
1717  * Set a TCP pcb contained in a netconn into listen mode
1718  * Called from netconn_listen.
1719  *
1720  * @param m the api_msg pointing to the connection
1721  */
1722 void
1723 lwip_netconn_do_listen(void *m)
1724 {
1725   struct api_msg *msg = (struct api_msg *)m;
1726   err_t err;
1727 
1728   if (ERR_IS_FATAL(msg->conn->last_err)) {
1729     err = msg->conn->last_err;
1730     goto SEND_ERROR;
1731   }
1732 
1733   if (msg->conn->pcb.tcp != NULL) {
1734     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1735       if (msg->conn->pcb.tcp->local_port == 0) {
1736         err = ERR_NODEST;
1737         goto SEND_ERROR;
1738       }
1739       if (msg->conn->state == NETCONN_NONE) {
1740         struct tcp_pcb *lpcb;
1741         if (msg->conn->pcb.tcp->state != CLOSED) {
1742           /* connection is not closed, cannot listen */
1743           err = ERR_VAL;
1744         } else {
1745           u8_t backlog;
1746           u32_t added;
1747 #if TCP_LISTEN_BACKLOG
1748           backlog = msg->msg.lb.backlog;
1749 #else  /* TCP_LISTEN_BACKLOG */
1750           backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1751 #endif /* TCP_LISTEN_BACKLOG */
1752 
1753           err = ERR_OK;
1754           added = 0;
1755           if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1756             err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1757             if (err != ERR_OK) {
1758               err = ERR_BUF;
1759               goto SEND_ERROR;
1760             }
1761             added = 1;
1762           }
1763 
1764           lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1765 
1766           if (lpcb == NULL) {
1767             /* in this case, the old pcb is still allocated */
1768             if (added) {
1769               sys_mbox_free(&msg->conn->acceptmbox);
1770               sys_mbox_set_invalid(&msg->conn->acceptmbox);
1771             }
1772           } else {
1773             /* delete the recvmbox and allocate the acceptmbox */
1774             if (sys_mbox_valid(&msg->conn->recvmbox)) {
1775               /** @todo: should we drain the recvmbox here? */
1776               sys_mbox_free(&msg->conn->recvmbox);
1777               sys_mbox_set_invalid(&msg->conn->recvmbox);
1778             }
1779 
1780             msg->conn->state = NETCONN_LISTEN;
1781             msg->conn->pcb.tcp = lpcb;
1782             tcp_arg(msg->conn->pcb.tcp, msg->conn);
1783             tcp_accept(msg->conn->pcb.tcp, accept_function);
1784           }
1785 
1786 #if LWIP_IPV4 && LWIP_IPV6
1787           /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1788             * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1789             */
1790           if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1791               (netconn_get_ipv6only(msg->conn) == 0)) {
1792             /* change PCB type to IPADDR_TYPE_ANY */
1793             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
1794             IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1795           }
1796 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1797         }
1798       } else if (msg->conn->state == NETCONN_LISTEN) {
1799         /* already listening, allow updating of the backlog */
1800         err = ERR_OK;
1801         tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1802       } else {
1803         err = ERR_CONN;
1804       }
1805     } else {
1806       err = ERR_OPNOTSUPP;
1807     }
1808   } else {
1809     err = ERR_CONN;
1810   }
1811 
1812 SEND_ERROR:
1813   msg->err = err;
1814   TCPIP_APIMSG_ACK(msg);
1815 }
1816 #endif /* LWIP_TCP */
1817 
1818 /**
1819  * Send some data on a RAW or UDP pcb contained in a netconn
1820  * Called from netconn_send
1821  *
1822  * @param m the api_msg pointing to the connection
1823  */
1824 void
1825 lwip_netconn_do_send(void *m)
1826 {
1827   struct api_msg *msg = (struct api_msg *)m;
1828 
1829   err_t err = netconn_err(msg->conn);
1830   if (!ERR_IS_FATAL(err)) {
1831     err = ERR_CLSD;
1832     if (msg->conn->pcb.tcp != NULL) {
1833       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1834 #if LWIP_RAW
1835         case NETCONN_RAW:
1836           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1837             struct ip_hdr *iphdr = NULL;
1838             ip_addr_t dest_addr;
1839 
1840             if (!(msg->conn->pcb.raw->flags & RAW_FLAGS_CONNECTED) ||
1841                 ip_addr_isany(&msg->conn->pcb.raw->remote_ip)) {
1842               if (raw_is_flag_set(msg->conn->pcb.raw, RAW_FLAGS_HDRINCL)) {
1843                 if (msg->msg.b->p->len < IP_HLEN) {
1844                   err = ERR_MSGSIZE;
1845                   break;
1846                 }
1847 
1848                 /* IP header already included in p */
1849                 iphdr = (struct ip_hdr *)msg->msg.b->p->payload;
1850                 ip_addr_copy_from_ip4(dest_addr, iphdr->dest);
1851                 err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &dest_addr);
1852                 break;
1853               }
1854 
1855               err = ERR_NODEST;
1856               break;
1857             }
1858 
1859             err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1860           } else {
1861             err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1862           }
1863           break;
1864 #if PF_PKT_SUPPORT
1865       case NETCONN_PKT_RAW:
1866         /* Check if its for sending RAW packets for PF_PACKET family */
1867         if (msg->msg.b->flags & NETBUF_FLAG_IFINDEX) {
1868           err = raw_pkt_sendto(msg->conn->pcb.pkt_raw, msg->msg.b->p, msg->msg.b->netifindex);
1869         } else {
1870           err = raw_pkt_sendto(msg->conn->pcb.pkt_raw, msg->msg.b->p, 0);
1871         }
1872         break;
1873 #endif
1874 #endif
1875 #if LWIP_UDP
1876         case NETCONN_UDP:
1877 #if LWIP_CHECKSUM_ON_COPY
1878           if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1879             if (!udp_is_flag_set(msg->conn->pcb.udp, UDP_FLAGS_CONNECTED)) {
1880               err = ERR_NODEST;
1881               break;
1882             }
1883             err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1884                                   msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1885           } else {
1886             err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1887                                     &msg->msg.b->addr, msg->msg.b->port,
1888                                     msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1889           }
1890 #else /* LWIP_CHECKSUM_ON_COPY */
1891           if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1892             if (!udp_is_flag_set(msg->conn->pcb.udp, UDP_FLAGS_CONNECTED)) {
1893               err = ERR_NODEST;
1894               break;
1895             }
1896             err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1897           } else {
1898             err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1899           }
1900 #endif /* LWIP_CHECKSUM_ON_COPY */
1901           break;
1902 #endif /* LWIP_UDP */
1903         default:
1904           err = ERR_CONN;
1905           break;
1906       }
1907     } else {
1908       err = ERR_CONN;
1909     }
1910   }
1911   msg->err = err;
1912   TCPIP_APIMSG_ACK(msg);
1913 }
1914 
1915 #if LWIP_TCP
1916 /**
1917  * Indicate data has been received from a TCP pcb contained in a netconn
1918  * Called from netconn_recv
1919  *
1920  * @param m the api_msg pointing to the connection
1921  */
1922 void
1923 lwip_netconn_do_recv(void *m)
1924 {
1925   struct api_msg *msg = (struct api_msg *)m;
1926 
1927   msg->err = ERR_OK;
1928   if (ERR_IS_FATAL(msg->conn->last_err)) {
1929     msg->err = msg->conn->last_err;
1930   } else if (msg->conn->pcb.tcp != NULL) {
1931     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1932       size_t remaining = msg->msg.r.len;
1933       do {
1934         u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
1935         tcp_recved(msg->conn->pcb.tcp, recved);
1936         remaining -= recved;
1937       } while (remaining != 0);
1938     }
1939   }
1940   TCPIP_APIMSG_ACK(msg);
1941 }
1942 
1943 #if TCP_LISTEN_BACKLOG
1944 /** Indicate that a TCP pcb has been accepted
1945  * Called from netconn_accept
1946  *
1947  * @param m the api_msg pointing to the connection
1948  */
1949 void
1950 lwip_netconn_do_accepted(void *m)
1951 {
1952   struct api_msg *msg = (struct api_msg *)m;
1953 
1954   msg->err = ERR_OK;
1955   if (msg->conn->pcb.tcp != NULL) {
1956     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1957       tcp_backlog_accepted(msg->conn->pcb.tcp);
1958     }
1959   }
1960   TCPIP_APIMSG_ACK(msg);
1961 }
1962 #endif /* TCP_LISTEN_BACKLOG */
1963 
1964 /**
1965  * See if more data needs to be written from a previous call to netconn_write.
1966  * Called initially from lwip_netconn_do_write. If the first call can't send all data
1967  * (because of low memory or empty send-buffer), this function is called again
1968  * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1969  * blocking application thread (waiting in netconn_write) is released.
1970  *
1971  * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1972  * @return ERR_OK
1973  *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1974  */
1975 static err_t
1976 lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
1977 {
1978   err_t err;
1979   const void *dataptr;
1980   u32_t len, available;
1981   u8_t write_finished = 0;
1982   size_t diff;
1983   u8_t dontblock;
1984   u8_t apiflags;
1985   u8_t write_more;
1986 
1987   LWIP_ASSERT("conn != NULL", conn != NULL);
1988   LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1989   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1990   LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1991   LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1992               conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1993   LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1994 
1995   apiflags = conn->current_msg->msg.w.apiflags;
1996   dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1997 
1998 #if DRIVER_STATUS_CHECK
1999   if (dontblock && (conn->pcb.tcp->drv_status == DRV_NOT_READY)) {
2000     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2001     u8_t dontblock_sock = netconn_is_nonblocking(conn);
2002 
2003     if (dontblock_sock) {
2004       LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. So sending SENDMINUS event\n"));
2005       API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2006     }
2007 
2008     /* check for state, and ensure correct errno is set while returning ... */
2009     if (!atomic_read(&conn->tcp_connected)) {
2010       err = ERR_CONN;
2011       LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. But connection is also not established, So returning ERR_CONN\n"));
2012     } else {
2013       LWIP_DEBUGF(DRV_STS_DEBUG, ("Driver Not Ready. So returning ERR_WOULDBLOCK\n"));
2014       err = ERR_WOULDBLOCK;
2015     }
2016 
2017     conn->current_msg->err = err;
2018     conn->current_msg = NULL;
2019     conn->state = NETCONN_NONE;
2020 
2021     sys_sem_signal(op_completed_sem);
2022     return err;
2023   }
2024 #else
2025   if (!atomic_read(&conn->tcp_connected)) {
2026     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2027     /* check for state, and ensure correct errno is set while returning ... */
2028     err = ERR_CONN;
2029     LWIP_DEBUGF(DRV_STS_DEBUG, ("Connection is also not established, So returning ERR_CONN\n"));
2030 
2031     conn->current_msg->err = err;
2032     conn->current_msg = NULL;
2033     conn->state = NETCONN_NONE;
2034 
2035     sys_sem_signal(op_completed_sem);
2036     return err;
2037   }
2038 #endif
2039 
2040 #if LWIP_SO_SNDTIMEO
2041   if ((conn->send_timeout != 0) &&
2042       ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
2043     write_finished = 1;
2044     if (conn->current_msg->msg.w.offset == 0) {
2045       /* nothing has been written */
2046       err = ERR_WOULDBLOCK;
2047     } else {
2048       /* partial write */
2049       err = ERR_OK;
2050     }
2051   } else
2052 #endif /* LWIP_SO_SNDTIMEO */
2053   {
2054     do {
2055       dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
2056       diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
2057       if (diff > 0xffffUL) { /* max_u16_t */
2058         len = 0xffff;
2059         apiflags |= TCP_WRITE_FLAG_MORE;
2060       } else {
2061         len = (u16_t)diff;
2062       }
2063       available = tcp_sndbuf(conn->pcb.tcp);
2064       if (available < len) {
2065         /* don't try to write more than sendbuf */
2066         len = available;
2067         if (dontblock) {
2068           if (!len) {
2069             /* set error according to partial write or not */
2070             err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
2071             goto err_mem;
2072           }
2073         } else {
2074           apiflags |= TCP_WRITE_FLAG_MORE;
2075         }
2076       }
2077       LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
2078                   ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
2079       /* we should loop around for more sending in the following cases:
2080            1) We couldn't finish the current vector because of 16-bit size limitations.
2081               tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
2082            2) We are sending the remainder of the current vector and have more */
2083       if ((len == 0xffff && diff > 0xffffUL) ||
2084           (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
2085         write_more = 1;
2086         apiflags |= TCP_WRITE_FLAG_MORE;
2087       } else {
2088         write_more = 0;
2089       }
2090       err = tcp_write(conn->pcb.tcp, dataptr, (u16_t)len, apiflags);
2091       if (err == ERR_OK) {
2092         conn->current_msg->msg.w.offset += len;
2093         conn->current_msg->msg.w.vector_off += len;
2094         /* check if current vector is finished */
2095         if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
2096           conn->current_msg->msg.w.vector_cnt--;
2097           /* if we have additional vectors, move on to them */
2098           if (conn->current_msg->msg.w.vector_cnt > 0) {
2099             conn->current_msg->msg.w.vector++;
2100             conn->current_msg->msg.w.vector_off = 0;
2101           }
2102         }
2103       }
2104     } while (write_more && err == ERR_OK);
2105     /* if OK or memory error, check available space */
2106     if ((err == ERR_OK) || (err == ERR_MEM)) {
2107 err_mem:
2108       if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
2109         /* non-blocking write did not write everything: mark the pcb non-writable
2110            and let poll_tcp check writable space to mark the pcb writable again */
2111         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2112         conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
2113       } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
2114                  (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
2115         /* The queued byte- or pbuf-count exceeds the configured low-water limit,
2116            let select mark this pcb as non-writable. */
2117         API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
2118       }
2119     }
2120 
2121     if (err == ERR_OK) {
2122       err_t out_err;
2123       if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
2124         /* return sent length (caller reads length from msg.w.offset) */
2125         write_finished = 1;
2126       }
2127       out_err = tcp_output(conn->pcb.tcp);
2128       if (ERR_IS_FATAL(out_err) || out_err == ERR_RTE) {
2129         /* If tcp_output fails with fatal error or no route is found,
2130            don't try writing any more but return the error
2131            to the application thread. */
2132         err = out_err;
2133         write_finished = 1;
2134       }
2135     } else if (err == ERR_MEM) {
2136       /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
2137          For blocking sockets, we do NOT return to the application
2138          thread, since ERR_MEM is only a temporary error! Non-blocking
2139          will remain non-writable until sent_tcp/poll_tcp is called */
2140 
2141       /* tcp_write returned ERR_MEM, try tcp_output anyway */
2142       err_t out_err = tcp_output(conn->pcb.tcp);
2143       if (ERR_IS_FATAL(out_err) || out_err == ERR_RTE) {
2144         /* If tcp_output fails with fatal error or no route is found,
2145            don't try writing any more but return the error
2146            to the application thread. */
2147         err = out_err;
2148         write_finished = 1;
2149       } else if (dontblock) {
2150         /* non-blocking write is done on ERR_MEM, set error according
2151            to partial write or not */
2152         err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
2153         write_finished = 1;
2154       }
2155     } else {
2156       /* On errors != ERR_MEM, we don't try writing any more but return
2157          the error to the application thread. */
2158       write_finished = 1;
2159     }
2160   }
2161   if (write_finished) {
2162     /* everything was written: set back connection state
2163        and back to application task */
2164     sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
2165     conn->current_msg->err = err;
2166     conn->current_msg = NULL;
2167     conn->state = NETCONN_NONE;
2168 #if LWIP_TCPIP_CORE_LOCKING
2169     if (delayed)
2170 #endif
2171     {
2172       sys_sem_signal(op_completed_sem);
2173     }
2174   }
2175 #if LWIP_TCPIP_CORE_LOCKING
2176   else {
2177     return ERR_MEM;
2178   }
2179 #endif
2180   return ERR_OK;
2181 }
2182 #endif /* LWIP_TCP */
2183 
2184 /**
2185  * Send some data on a TCP pcb contained in a netconn
2186  * Called from netconn_write
2187  *
2188  * @param m the api_msg pointing to the connection
2189  */
2190 void
2191 lwip_netconn_do_write(void *m)
2192 {
2193   struct api_msg *msg = (struct api_msg *)m;
2194   err_t err;
2195   if (ERR_IS_FATAL(msg->conn->last_err)) {
2196     err = (err_t)((msg->conn->last_err == ERR_CLSD) ? ERR_PIPE : msg->conn->last_err);
2197   } else {
2198     if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
2199 #if LWIP_TCP
2200       if (msg->conn->state != NETCONN_NONE) {
2201         /* netconn is connecting, closing or in blocking write */
2202         err = ((msg->conn->state == NETCONN_LISTEN) ? ERR_PIPE : ERR_INPROGRESS);
2203         err = (err_t)((msg->conn->state == NETCONN_CONNECT) ? ERR_CONN : err);
2204       } else if (msg->conn->pcb.tcp != NULL) {
2205         msg->conn->state = NETCONN_WRITE;
2206         /* set all the variables used by lwip_netconn_do_writemore */
2207         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
2208           msg->conn->write_offset == 0);
2209         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
2210         msg->conn->current_msg = msg;
2211         msg->conn->write_offset = 0;
2212 #if LWIP_TCPIP_CORE_LOCKING
2213         if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
2214           LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
2215           UNLOCK_TCPIP_CORE();
2216           sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2217           LOCK_TCPIP_CORE();
2218           LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
2219         }
2220 #else /* LWIP_TCPIP_CORE_LOCKING */
2221         lwip_netconn_do_writemore(msg->conn);
2222 #endif /* LWIP_TCPIP_CORE_LOCKING */
2223         /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
2224            since lwip_netconn_do_writemore ACKs it! */
2225         return;
2226       } else {
2227         err = ERR_PIPE;
2228       }
2229 #else /* LWIP_TCP */
2230       err = ERR_VAL;
2231 #endif /* LWIP_TCP */
2232 #if (LWIP_UDP || LWIP_RAW)
2233     } else {
2234       err = ERR_VAL;
2235 #endif /* (LWIP_UDP || LWIP_RAW) */
2236     }
2237   }
2238   msg->err = err;
2239   TCPIP_APIMSG_ACK(msg);
2240 }
2241 
2242 /**
2243  * Return a connection's local or remote address
2244  * Called from netconn_getaddr
2245  *
2246  * @param m the api_msg pointing to the connection
2247  */
2248 void
2249 lwip_netconn_do_getaddr(void *m)
2250 {
2251   struct api_msg *msg = (struct api_msg *)m;
2252 
2253   if ((msg->conn == NULL) || (msg->conn->pcb.tcp == NULL)) {
2254     msg->err = ERR_CONN;
2255     TCPIP_APIMSG_ACK(msg);
2256     return;
2257   }
2258   if (msg->conn->pcb.ip != NULL) {
2259     if (msg->msg.ad.local) {
2260       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2261                    msg->conn->pcb.ip->local_ip);
2262     } else {
2263       ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2264                    msg->conn->pcb.ip->remote_ip);
2265     }
2266 
2267     msg->err = ERR_OK;
2268     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
2269 #if LWIP_RAW
2270       case NETCONN_RAW:
2271         if (msg->msg.ad.local) {
2272           ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2273                        msg->conn->pcb.raw->local_ip);
2274           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->raw_proto;
2275         } else {
2276           if (raw_is_flag_set(msg->conn->pcb.raw, RAW_FLAGS_CONNECTED)) {
2277             ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
2278                          msg->conn->pcb.raw->remote_ip);
2279             API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->raw_proto;
2280           } else {
2281             /* return an error as connecting is only a helper for upper layers */
2282             msg->err = ERR_CONN;
2283           }
2284         }
2285         break;
2286 #endif /* LWIP_RAW */
2287 #if LWIP_UDP
2288       case NETCONN_UDP:
2289         if (msg->msg.ad.local) {
2290           API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
2291         } else {
2292           if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
2293             msg->err = ERR_CONN;
2294           } else {
2295             API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
2296           }
2297         }
2298         break;
2299 #endif /* LWIP_UDP */
2300 #if LWIP_TCP
2301       case NETCONN_TCP:
2302         if ((msg->msg.ad.local == 0) &&
2303             ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
2304           /* pcb is not connected and remote name is requested */
2305           msg->err = ERR_CONN;
2306         } else {
2307           API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
2308         }
2309         break;
2310 #endif /* LWIP_TCP */
2311       default:
2312         msg->err = ERR_OPNOTSUPP;
2313         LWIP_ASSERT("invalid netconn_type", 0);
2314         break;
2315     }
2316   } else {
2317     msg->err = ERR_CLSD;
2318   }
2319   TCPIP_APIMSG_ACK(msg);
2320 }
2321 
2322 #if PF_PKT_SUPPORT
2323 /**
2324  * Return a pf pkt socket's local address
2325  * Called from netconn_getaddr
2326  *
2327  * @param m the api_msg pointing to the connection
2328  */
2329 void
2330 lwip_netconn_do_getaddr_pfpkt(void *m)
2331 {
2332   struct api_msg *msg = (struct api_msg *)m;
2333   struct pf_pkt_ll ll;
2334   msg->err = ERR_OK;
2335   if (msg->conn->pcb.ip != NULL) {
2336     /* Non standard way of do it, but doing it :( */
2337     if (msg->msg.adpkt.local) {
2338       ll.sll_protocol = msg->conn->pcb.pkt_raw->proto.eth_proto;
2339       ll.if_idx = msg->conn->pcb.pkt_raw->netifindex;
2340       struct netif *netif = netif_find_by_ifindex(msg->conn->pcb.pkt_raw->netifindex);
2341       if (netif == NULL) {
2342         LWIP_DEBUGF(SOCKETS_DEBUG,
2343                     ("lwip_getaddrname:netif not found for given ifindex (%u)\n",
2344                      msg->conn->pcb.pkt_raw->netifindex));
2345         ll.sll_halen = 0;
2346         ll.sll_hatype = 0;
2347       } else {
2348         ll.sll_hatype = netif->link_layer_type;
2349         ll.sll_halen = NETIF_MAX_HWADDR_LEN;
2350         (void)memcpy_s(ll.sll_addr, ll.sll_halen, netif->hwaddr, NETIF_MAX_HWADDR_LEN);
2351       }
2352       API_EXPR_DEREF(msg->msg.adpkt.ll) = ll;
2353     } else {
2354       msg->err = ERR_OPNOTSUPP;
2355     }
2356   } else {
2357     msg->err = ERR_CONN;
2358   }
2359   TCPIP_APIMSG_ACK(msg);
2360 }
2361 #endif
2362 
2363 /**
2364  * Close or half-shutdown a TCP pcb contained in a netconn
2365  * Called from netconn_close
2366  * In contrast to closing sockets, the netconn is not deallocated.
2367  *
2368  * @param m the api_msg pointing to the connection
2369  */
2370 void
2371 lwip_netconn_do_close(void *m)
2372 {
2373   struct api_msg *msg = (struct api_msg *)m;
2374 
2375 #if LWIP_TCP
2376   enum netconn_state state = msg->conn->state;
2377   /* First check if this is a TCP netconn and if it is in a correct state
2378       (LISTEN doesn't support half shutdown) */
2379   if ((msg->conn->pcb.tcp != NULL) &&
2380       (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
2381       ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
2382 
2383       LWIP_ERROR("lwip_netconn_do_close: shutdown can not be done when in CLOSED state",
2384                   msg->conn->net_tcp_state != CLOSED,
2385                   msg->err = ERR_CONN; TCPIP_APIMSG_ACK(msg); return);
2386     /* Check if we are in a connected state */
2387     if (state == NETCONN_CONNECT) {
2388       /* TCP connect in progress: cannot shutdown */
2389       int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(msg->conn);
2390       SET_NONBLOCKING_CONNECT(msg->conn, 0);
2391 
2392       if ((msg->msg.sd.shut & NETCONN_SHUT_WR) && !was_nonblocking_connect && (msg->conn->current_msg != NULL)) {
2393         sys_sem_t *op_completed_sem = NULL;
2394         msg->conn->current_msg->err = ERR_ABRT;
2395         op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2396         LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
2397         msg->conn->current_msg = NULL;
2398         /* wake up the waiting task */
2399         sys_sem_signal(op_completed_sem);
2400       }
2401       msg->err = ERR_CONN;
2402     } else if (state == NETCONN_WRITE) {
2403 #if LWIP_NETCONN_FULLDUPLEX
2404       if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
2405         /* close requested, abort running write */
2406         sys_sem_t *write_completed_sem;
2407         LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
2408         write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2409         msg->conn->current_msg->err = ERR_CLSD;
2410         msg->conn->current_msg = NULL;
2411         msg->conn->write_offset = 0;
2412         msg->conn->state = NETCONN_NONE;
2413         state = NETCONN_NONE;
2414         sys_sem_signal(write_completed_sem);
2415       } else {
2416         LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
2417         /* In this case, let the write continue and do not interfere with
2418            conn->current_msg or conn->state! */
2419         msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
2420       }
2421     }
2422     if ((state == NETCONN_NONE) || (state == NETCONN_LISTEN)) {
2423 #else /* LWIP_NETCONN_FULLDUPLEX */
2424       msg->err = ERR_INPROGRESS;
2425     } else {
2426 #endif /* LWIP_NETCONN_FULLDUPLEX */
2427       if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
2428         msg->conn->shutdown = RCV_SHUTDOWN;
2429 #if LWIP_NETCONN_FULLDUPLEX
2430         /* Mark mboxes invalid */
2431         netconn_mark_mbox_invalid(msg->conn);
2432 #else /* LWIP_NETCONN_FULLDUPLEX */
2433         netconn_drain(msg->conn);
2434 #endif /* LWIP_NETCONN_FULLDUPLEX */
2435       }
2436       LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
2437         msg->conn->write_offset == 0);
2438       msg->conn->state = NETCONN_CLOSE;
2439       msg->conn->current_msg = msg;
2440 #if LWIP_TCPIP_CORE_LOCKING
2441       if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
2442         LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
2443         UNLOCK_TCPIP_CORE();
2444         sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2445         LOCK_TCPIP_CORE();
2446         LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
2447       }
2448 #else /* LWIP_TCPIP_CORE_LOCKING */
2449       lwip_netconn_do_close_internal(msg->conn);
2450 #endif /* LWIP_TCPIP_CORE_LOCKING */
2451       /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
2452       return;
2453     }
2454   } else
2455 #endif /* LWIP_TCP */
2456   {
2457     msg->err = ERR_CLSD;
2458     if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
2459         /* LISTEN doesn't support half shutdown */
2460         msg->err = ERR_CONN;
2461     }
2462   }
2463   TCPIP_APIMSG_ACK(msg);
2464 }
2465 
2466 #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
2467 /*
2468  * Leave multicast groups for UDP netconns.
2469  * Called from netconn_leave_group and netconn_leave_group_netif
2470  *
2471  * @param m the api_msg_msg pointing to the connection
2472  */
2473 void
2474 lwip_netconn_do_leave_group(void *m)
2475 {
2476   struct api_msg *msg = (struct api_msg*)m;
2477 
2478 
2479   msg->err = ERR_CONN;
2480   if (ERR_IS_FATAL(msg->conn->last_err)) {
2481     msg->err = msg->conn->last_err;
2482   } else {
2483     if (msg->conn->pcb.udp != NULL) {
2484       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2485 #if LWIP_UDP
2486 #if LWIP_IPV6 && LWIP_IPV6_MLD
2487         if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2488           struct netif *netif = NULL;
2489 
2490           netif = netif_get_by_index(msg->msg.jl.if_idx);
2491           if (netif == NULL) {
2492             msg->err = ERR_IF;
2493             TCPIP_APIMSG_ACK(msg);
2494             return;
2495           }
2496 
2497           if (msg->msg.jl.join_or_leave == NETCONN_LEAVE) {
2498             msg->err = mld6_leavegroup_netif(netif,
2499                                              ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2500           }
2501         }
2502         else
2503 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2504         {
2505 #if LWIP_IGMP
2506           if (msg->msg.jl.join_or_leave == NETCONN_LEAVE) {
2507             msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2508                                        ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2509           }
2510 #endif /* LWIP_IGMP */
2511         }
2512 #endif /* LWIP_UDP */
2513 #if (LWIP_TCP || LWIP_RAW)
2514       } else {
2515         msg->err = ERR_VAL;
2516 #endif /* (LWIP_TCP || LWIP_RAW) */
2517       }
2518     } else {
2519       msg->err = ERR_CONN;
2520     }
2521   }
2522   TCPIP_APIMSG_ACK(msg);
2523 }
2524 #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2525 
2526 #if LWIP_DNS
2527 /**
2528  * Callback function that is called when DNS name is resolved
2529  * (or on timeout). A waiting application thread is waked up by
2530  * signaling the semaphore.
2531  */
2532 static void
2533 lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, u32_t count, void *arg)
2534 {
2535   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2536   u32_t i;
2537 
2538   /* we trust the internal implementation to be correct :-) */
2539   LWIP_UNUSED_ARG(name);
2540 
2541   if (ipaddr == NULL) {
2542     /* If ipaddr = NULL, then count will contain the reason of error
2543      * that will be eventually set to h_errno or h_errnop */
2544     if (count != 0) {
2545       /* Incase of known errors */
2546       API_EXPR_DEREF(msg->err) = (err_t)(count);
2547     } else {
2548       /* Incase of unknown errors */
2549       API_EXPR_DEREF(msg->err) = EINVAL;
2550     }
2551   } else {
2552     /* address was resolved */
2553     API_EXPR_DEREF(msg->err) = ERR_OK;
2554     for (i = 0; i < count; i++) {
2555       msg->addr[i] = ipaddr[i];
2556     }
2557   }
2558   API_EXPR_DEREF(msg->count) = API_EXPR_DEREF(&count);
2559   /* wake up the application task waiting in netconn_gethostbyname */
2560   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2561 }
2562 
2563 /**
2564  * Execute a DNS query
2565  * Called from netconn_gethostbyname
2566  *
2567  * @param arg the dns_api_msg pointing to the query
2568  */
2569 void
2570 lwip_netconn_do_gethostbyname(void *arg)
2571 {
2572   struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2573   u8_t addrtype =
2574 #if LWIP_IPV4 && LWIP_IPV6
2575     msg->dns_addrtype;
2576 #else
2577     LWIP_DNS_ADDRTYPE_DEFAULT;
2578 #endif
2579 
2580   API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, API_EXPR_REF(msg->addr), msg->count,
2581                                                         lwip_netconn_do_dns_found, msg, addrtype);
2582 #if LWIP_TCPIP_CORE_LOCKING
2583   /* For core locking, only block if we need to wait for answer/timeout */
2584   if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
2585     UNLOCK_TCPIP_CORE();
2586     sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
2587     LOCK_TCPIP_CORE();
2588     LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
2589   }
2590 #else /* LWIP_TCPIP_CORE_LOCKING */
2591   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2592     /* on error or immediate success, wake up the application
2593      * task waiting in netconn_gethostbyname */
2594     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2595   }
2596 #endif /* LWIP_TCPIP_CORE_LOCKING */
2597 }
2598 
2599 void
2600 lwip_netconn_do_reverse_dns_found(const char *hostname, u32_t count, void *arg)
2601 {
2602   struct reverse_dns_api_msg *msg = (struct reverse_dns_api_msg*)arg;
2603 
2604   if (hostname != NULL) {
2605     size_t namelen = strlen(hostname);
2606     if (namelen < NI_MAXHOST) {
2607       if (strncpy_s(msg->hostname, NI_MAXHOST, hostname, namelen) != EOK) {
2608         API_EXPR_DEREF(msg->err) = EINVAL;
2609       } else {
2610         API_EXPR_DEREF(msg->err) = ERR_OK;
2611       }
2612     } else {
2613 
2614       API_EXPR_DEREF(msg->err) = EINVAL;
2615     }
2616   } else {
2617     /* If hostname is NULL, then count will contain the error code (because h_errno is not implemented yet) */
2618     if (count != 0) {
2619       /* Incase of known errors */
2620       API_EXPR_DEREF(msg->err) = (err_t)(count);
2621     } else {
2622       /* Incase of unknown errors */
2623       API_EXPR_DEREF(msg->err) = EINVAL;
2624     }
2625   }
2626 
2627   sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2628 }
2629 
2630 #if LWIP_DNS_REVERSE
2631 void
2632 lwip_netconn_do_getnamebyhost(void *arg)
2633 {
2634   struct reverse_dns_api_msg *msg = (struct reverse_dns_api_msg*)arg;
2635 
2636   API_EXPR_DEREF(msg->err) = reverse_dns_getnamebyhost(API_EXPR_REF(msg->addr), msg->hostname,
2637                                                        lwip_netconn_do_reverse_dns_found, msg);
2638   if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2639     /* on error or immediate success, wake up the application
2640      * task waiting in netconn_gethostbyname */
2641     sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2642   }
2643 }
2644 #endif /* LWIP_DNS_REVERSE */
2645 #endif /* LWIP_DNS */
2646 
2647 static err_t
2648 do_get_tcpconninfo(struct api_msg *msg)
2649 {
2650   struct tcp_pcb *tcp = msg->conn->pcb.tcp;
2651   struct tcpip_conn *conn_info = msg->msg.conn_info;
2652   if (tcp == NULL) {
2653     msg->err = ERR_CLSD;
2654     return msg->err;
2655   }
2656   if (tcp->state == LISTEN) {
2657     msg->err = ERR_VAL;
2658     return msg->err;
2659   }
2660 
2661   if ((msg->conn->pcb.tcp->state == CLOSED) ||
2662      (msg->conn->pcb.tcp->state == TIME_WAIT)) {
2663     msg->err = ERR_CONN;
2664     return msg->err;
2665   }
2666   ip_addr_copy(conn_info->dst_ip, tcp->remote_ip);
2667   ip_addr_copy(conn_info->src_ip, tcp->local_ip);
2668   conn_info->srcport = tcp->local_port;
2669   conn_info->dstport = tcp->remote_port;
2670   if (tcp->state == SYN_SENT) {
2671     conn_info->seqnum  = tcp->lastack; /* seqnum of last ACKED byte */
2672   } else {
2673     conn_info->seqnum  = (u32_t)(tcp->lastack - 1);
2674   }
2675   conn_info->acknum  = tcp->rcv_nxt; /* Last acknowledged number sent */
2676   conn_info->tcpwin  = tcp->snd_wnd;
2677   conn_info->last_payload_len = tcp->last_payload_len;
2678   conn_info->tsval   = 0 ;
2679   conn_info->tsecr = 0;
2680   conn_info->ipid = ip4_last_ip_id();
2681   return ERR_OK;
2682 }
2683 
2684 static err_t
2685 do_get_udpconninfo(struct api_msg *msg)
2686 {
2687   struct udp_pcb *udp = msg->conn->pcb.udp;
2688   struct tcpip_conn *conn_info = msg->msg.conn_info;
2689   if (udp == NULL) {
2690     msg->err = ERR_CLSD;
2691     return msg->err;
2692   }
2693   ip_addr_copy(conn_info->dst_ip, udp->remote_ip);
2694   ip_addr_copy(conn_info->src_ip, udp->local_ip);
2695   conn_info->srcport = udp->local_port;
2696   conn_info->dstport = udp->remote_port;
2697   conn_info->seqnum = 0; /* Last sent Sequence number */
2698   conn_info->acknum = 0; /* Last acknowledged number sent */
2699   conn_info->tcpwin = 0;
2700   conn_info->last_payload_len = udp->last_payload_len;
2701   conn_info->tsval = 0;
2702   conn_info->tsecr = 0;
2703   conn_info->ipid = ip4_last_ip_id();
2704   return ERR_OK;
2705 }
2706 
2707 void
2708 do_getconninfo(void *m)
2709 {
2710   struct api_msg *msg = (struct api_msg*)m;
2711   ip_addr_t *dst_addr = NULL;
2712   ip_addr_t *src_addr = NULL;
2713 
2714   const ip4_addr_t *ip_add = NULL;
2715   struct tcpip_conn *conn_info = NULL;
2716   struct eth_addr *tdst_mac = NULL;
2717   struct eth_addr invalid_mac = {{0, 0, 0, 0, 0, 0}};
2718   s8_t ret;
2719   err_t err;
2720   conn_info = msg->msg.conn_info;
2721   tdst_mac = &conn_info->dst_mac;
2722   if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2723     err = do_get_udpconninfo(msg);
2724     dst_addr = &(msg->conn->pcb.udp->remote_ip);
2725     src_addr = &(msg->conn->pcb.udp->local_ip);
2726     if (err != ERR_OK) {
2727       goto RETURN;
2728     }
2729 
2730   } else if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
2731     err = do_get_tcpconninfo(msg);
2732     dst_addr = &(msg->conn->pcb.tcp->remote_ip);
2733     src_addr = &(msg->conn->pcb.tcp->local_ip);
2734     if (err != ERR_OK) {
2735       goto RETURN;
2736     }
2737   } else {
2738     msg->err = ERR_VAL;
2739     goto RETURN;
2740   }
2741 
2742   if (ip_addr_isany(dst_addr)) {
2743     tdst_mac = &invalid_mac;
2744     (void)memcpy_s(&conn_info->dst_mac, sizeof(struct eth_addr), tdst_mac, sizeof(struct eth_addr));
2745     msg->err = ERR_OK;
2746     goto RETURN;
2747   }
2748 
2749   if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(msg->conn))) {
2750     ret = netif_find_dst_ip6addr_mac_addr(src_addr, &dst_addr, &tdst_mac);
2751   } else {
2752     ret  = netif_find_dst_ipaddr(src_addr, &dst_addr);
2753     if (ret == 0) {
2754       ret = (s8_t)etharp_find_addr(NULL, ip_2_ip4(dst_addr), &tdst_mac, &ip_add);
2755     }
2756   }
2757 
2758   if (ret == -1) {
2759     tdst_mac = &invalid_mac;
2760   }
2761 
2762   (void)memcpy_s(&conn_info->dst_mac, sizeof(struct eth_addr), tdst_mac, sizeof(struct eth_addr));
2763   msg->err = ERR_OK;
2764 
2765 RETURN:
2766   TCPIP_APIMSG_ACK(msg);
2767 }
2768 
2769 #endif /* LWIP_NETCONN */
2770