1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * Sequential API Internal module
4195972f6Sopenharmony_ci *
5195972f6Sopenharmony_ci */
6195972f6Sopenharmony_ci
7195972f6Sopenharmony_ci/*
8195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9195972f6Sopenharmony_ci * All rights reserved.
10195972f6Sopenharmony_ci *
11195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
12195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
13195972f6Sopenharmony_ci *
14195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
15195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
16195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
17195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
18195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
19195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
20195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
21195972f6Sopenharmony_ci *
22195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31195972f6Sopenharmony_ci * OF SUCH DAMAGE.
32195972f6Sopenharmony_ci *
33195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack.
34195972f6Sopenharmony_ci *
35195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se>
36195972f6Sopenharmony_ci *
37195972f6Sopenharmony_ci */
38195972f6Sopenharmony_ci
39195972f6Sopenharmony_ci#include "lwip/opt.h"
40195972f6Sopenharmony_ci
41195972f6Sopenharmony_ci#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
42195972f6Sopenharmony_ci
43195972f6Sopenharmony_ci#include "lwip/priv/api_msg.h"
44195972f6Sopenharmony_ci
45195972f6Sopenharmony_ci#include "lwip/ip.h"
46195972f6Sopenharmony_ci#include "lwip/ip_addr.h"
47195972f6Sopenharmony_ci#include "lwip/udp.h"
48195972f6Sopenharmony_ci#include "lwip/tcp.h"
49195972f6Sopenharmony_ci#include "lwip/raw.h"
50195972f6Sopenharmony_ci
51195972f6Sopenharmony_ci#include "lwip/memp.h"
52195972f6Sopenharmony_ci#include "lwip/igmp.h"
53195972f6Sopenharmony_ci#include "lwip/dns.h"
54195972f6Sopenharmony_ci#include "lwip/mld6.h"
55195972f6Sopenharmony_ci#include "lwip/priv/tcpip_priv.h"
56195972f6Sopenharmony_ci
57195972f6Sopenharmony_ci#include <string.h>
58195972f6Sopenharmony_ci
59195972f6Sopenharmony_ci/* netconns are polled once per second (e.g. continue write on memory error) */
60195972f6Sopenharmony_ci#define NETCONN_TCP_POLL_INTERVAL 2
61195972f6Sopenharmony_ci
62195972f6Sopenharmony_ci#define SET_NONBLOCKING_CONNECT(conn, val)  do { if (val) { \
63195972f6Sopenharmony_ci  netconn_set_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); \
64195972f6Sopenharmony_ci} else { \
65195972f6Sopenharmony_ci  netconn_clear_flags(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT); }} while(0)
66195972f6Sopenharmony_ci#define IN_NONBLOCKING_CONNECT(conn) netconn_is_flag_set(conn, NETCONN_FLAG_IN_NONBLOCKING_CONNECT)
67195972f6Sopenharmony_ci
68195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
69195972f6Sopenharmony_ci#define NETCONN_MBOX_VALID(conn, mbox) (sys_mbox_valid(mbox) && ((conn->flags & NETCONN_FLAG_MBOXINVALID) == 0))
70195972f6Sopenharmony_ci#else
71195972f6Sopenharmony_ci#define NETCONN_MBOX_VALID(conn, mbox) sys_mbox_valid(mbox)
72195972f6Sopenharmony_ci#endif
73195972f6Sopenharmony_ci
74195972f6Sopenharmony_ci/* forward declarations */
75195972f6Sopenharmony_ci#if LWIP_TCP
76195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
77195972f6Sopenharmony_ci#define WRITE_DELAYED         , 1
78195972f6Sopenharmony_ci#define WRITE_DELAYED_PARAM   , u8_t delayed
79195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
80195972f6Sopenharmony_ci#define WRITE_DELAYED
81195972f6Sopenharmony_ci#define WRITE_DELAYED_PARAM
82195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
83195972f6Sopenharmony_cistatic err_t lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM);
84195972f6Sopenharmony_cistatic err_t lwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM);
85195972f6Sopenharmony_ci#endif
86195972f6Sopenharmony_ci
87195972f6Sopenharmony_cistatic void netconn_drain(struct netconn *conn);
88195972f6Sopenharmony_ci
89195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
90195972f6Sopenharmony_ci#define TCPIP_APIMSG_ACK(m)
91195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
92195972f6Sopenharmony_ci#define TCPIP_APIMSG_ACK(m)   do { sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
93195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
94195972f6Sopenharmony_ci
95195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
96195972f6Sopenharmony_ciconst u8_t netconn_deleted = 0;
97195972f6Sopenharmony_ci
98195972f6Sopenharmony_ciint
99195972f6Sopenharmony_cilwip_netconn_is_deallocated_msg(void *msg)
100195972f6Sopenharmony_ci{
101195972f6Sopenharmony_ci  if (msg == &netconn_deleted) {
102195972f6Sopenharmony_ci    return 1;
103195972f6Sopenharmony_ci  }
104195972f6Sopenharmony_ci  return 0;
105195972f6Sopenharmony_ci}
106195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
107195972f6Sopenharmony_ci
108195972f6Sopenharmony_ci#if LWIP_TCP
109195972f6Sopenharmony_ciconst u8_t netconn_aborted = 0;
110195972f6Sopenharmony_ciconst u8_t netconn_reset = 0;
111195972f6Sopenharmony_ciconst u8_t netconn_closed = 0;
112195972f6Sopenharmony_ci
113195972f6Sopenharmony_ci/** Translate an error to a unique void* passed via an mbox */
114195972f6Sopenharmony_cistatic void *
115195972f6Sopenharmony_cilwip_netconn_err_to_msg(err_t err)
116195972f6Sopenharmony_ci{
117195972f6Sopenharmony_ci  switch (err) {
118195972f6Sopenharmony_ci    case ERR_ABRT:
119195972f6Sopenharmony_ci      return LWIP_CONST_CAST(void *, &netconn_aborted);
120195972f6Sopenharmony_ci    case ERR_RST:
121195972f6Sopenharmony_ci      return LWIP_CONST_CAST(void *, &netconn_reset);
122195972f6Sopenharmony_ci    case ERR_CLSD:
123195972f6Sopenharmony_ci      return LWIP_CONST_CAST(void *, &netconn_closed);
124195972f6Sopenharmony_ci    default:
125195972f6Sopenharmony_ci      LWIP_ASSERT("unhandled error", err == ERR_OK);
126195972f6Sopenharmony_ci      return NULL;
127195972f6Sopenharmony_ci  }
128195972f6Sopenharmony_ci}
129195972f6Sopenharmony_ci
130195972f6Sopenharmony_ciint
131195972f6Sopenharmony_cilwip_netconn_is_err_msg(void *msg, err_t *err)
132195972f6Sopenharmony_ci{
133195972f6Sopenharmony_ci  LWIP_ASSERT("err != NULL", err != NULL);
134195972f6Sopenharmony_ci
135195972f6Sopenharmony_ci  if (msg == &netconn_aborted) {
136195972f6Sopenharmony_ci    *err = ERR_ABRT;
137195972f6Sopenharmony_ci    return 1;
138195972f6Sopenharmony_ci  } else if (msg == &netconn_reset) {
139195972f6Sopenharmony_ci    *err = ERR_RST;
140195972f6Sopenharmony_ci    return 1;
141195972f6Sopenharmony_ci  } else if (msg == &netconn_closed) {
142195972f6Sopenharmony_ci    *err = ERR_CLSD;
143195972f6Sopenharmony_ci    return 1;
144195972f6Sopenharmony_ci  }
145195972f6Sopenharmony_ci  return 0;
146195972f6Sopenharmony_ci}
147195972f6Sopenharmony_ci#endif /* LWIP_TCP */
148195972f6Sopenharmony_ci
149195972f6Sopenharmony_ci
150195972f6Sopenharmony_ci#if LWIP_RAW
151195972f6Sopenharmony_ci/**
152195972f6Sopenharmony_ci * Receive callback function for RAW netconns.
153195972f6Sopenharmony_ci * Doesn't 'eat' the packet, only copies it and sends it to
154195972f6Sopenharmony_ci * conn->recvmbox
155195972f6Sopenharmony_ci *
156195972f6Sopenharmony_ci * @see raw.h (struct raw_pcb.recv) for parameters and return value
157195972f6Sopenharmony_ci */
158195972f6Sopenharmony_cistatic u8_t
159195972f6Sopenharmony_cirecv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
160195972f6Sopenharmony_ci         const ip_addr_t *addr)
161195972f6Sopenharmony_ci{
162195972f6Sopenharmony_ci  struct pbuf *q;
163195972f6Sopenharmony_ci  struct netbuf *buf;
164195972f6Sopenharmony_ci  struct netconn *conn;
165195972f6Sopenharmony_ci
166195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(addr);
167195972f6Sopenharmony_ci  conn = (struct netconn *)arg;
168195972f6Sopenharmony_ci
169195972f6Sopenharmony_ci  if ((conn != NULL) && NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
170195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
171195972f6Sopenharmony_ci    int recv_avail;
172195972f6Sopenharmony_ci    SYS_ARCH_GET(conn->recv_avail, recv_avail);
173195972f6Sopenharmony_ci    if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
174195972f6Sopenharmony_ci      return 0;
175195972f6Sopenharmony_ci    }
176195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
177195972f6Sopenharmony_ci    /* copy the whole packet into new pbufs */
178195972f6Sopenharmony_ci    q = pbuf_clone(PBUF_RAW, PBUF_RAM, p);
179195972f6Sopenharmony_ci    if (q != NULL) {
180195972f6Sopenharmony_ci      u16_t len;
181195972f6Sopenharmony_ci      buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
182195972f6Sopenharmony_ci      if (buf == NULL) {
183195972f6Sopenharmony_ci        pbuf_free(q);
184195972f6Sopenharmony_ci        return 0;
185195972f6Sopenharmony_ci      }
186195972f6Sopenharmony_ci
187195972f6Sopenharmony_ci      buf->p = q;
188195972f6Sopenharmony_ci      buf->ptr = q;
189195972f6Sopenharmony_ci      ip_addr_copy(buf->addr, *ip_current_src_addr());
190195972f6Sopenharmony_ci      buf->port = pcb->protocol;
191195972f6Sopenharmony_ci
192195972f6Sopenharmony_ci      len = q->tot_len;
193195972f6Sopenharmony_ci      if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
194195972f6Sopenharmony_ci        netbuf_delete(buf);
195195972f6Sopenharmony_ci        return 0;
196195972f6Sopenharmony_ci      } else {
197195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
198195972f6Sopenharmony_ci        SYS_ARCH_INC(conn->recv_avail, len);
199195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
200195972f6Sopenharmony_ci        /* Register event with callback */
201195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
202195972f6Sopenharmony_ci      }
203195972f6Sopenharmony_ci    }
204195972f6Sopenharmony_ci  }
205195972f6Sopenharmony_ci
206195972f6Sopenharmony_ci  return 0; /* do not eat the packet */
207195972f6Sopenharmony_ci}
208195972f6Sopenharmony_ci#endif /* LWIP_RAW*/
209195972f6Sopenharmony_ci
210195972f6Sopenharmony_ci#if LWIP_UDP
211195972f6Sopenharmony_ci/**
212195972f6Sopenharmony_ci * Receive callback function for UDP netconns.
213195972f6Sopenharmony_ci * Posts the packet to conn->recvmbox or deletes it on memory error.
214195972f6Sopenharmony_ci *
215195972f6Sopenharmony_ci * @see udp.h (struct udp_pcb.recv) for parameters
216195972f6Sopenharmony_ci */
217195972f6Sopenharmony_cistatic void
218195972f6Sopenharmony_cirecv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
219195972f6Sopenharmony_ci         const ip_addr_t *addr, u16_t port)
220195972f6Sopenharmony_ci{
221195972f6Sopenharmony_ci  struct netbuf *buf;
222195972f6Sopenharmony_ci  struct netconn *conn;
223195972f6Sopenharmony_ci  u16_t len;
224195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
225195972f6Sopenharmony_ci  int recv_avail;
226195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
227195972f6Sopenharmony_ci
228195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
229195972f6Sopenharmony_ci  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
230195972f6Sopenharmony_ci  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
231195972f6Sopenharmony_ci  conn = (struct netconn *)arg;
232195972f6Sopenharmony_ci
233195972f6Sopenharmony_ci  if (conn == NULL) {
234195972f6Sopenharmony_ci    pbuf_free(p);
235195972f6Sopenharmony_ci    return;
236195972f6Sopenharmony_ci  }
237195972f6Sopenharmony_ci
238195972f6Sopenharmony_ci  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
239195972f6Sopenharmony_ci
240195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
241195972f6Sopenharmony_ci  SYS_ARCH_GET(conn->recv_avail, recv_avail);
242195972f6Sopenharmony_ci  if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox) ||
243195972f6Sopenharmony_ci      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
244195972f6Sopenharmony_ci#else  /* LWIP_SO_RCVBUF */
245195972f6Sopenharmony_ci  if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
246195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
247195972f6Sopenharmony_ci    pbuf_free(p);
248195972f6Sopenharmony_ci    return;
249195972f6Sopenharmony_ci  }
250195972f6Sopenharmony_ci
251195972f6Sopenharmony_ci  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
252195972f6Sopenharmony_ci  if (buf == NULL) {
253195972f6Sopenharmony_ci    pbuf_free(p);
254195972f6Sopenharmony_ci    return;
255195972f6Sopenharmony_ci  } else {
256195972f6Sopenharmony_ci    buf->p = p;
257195972f6Sopenharmony_ci    buf->ptr = p;
258195972f6Sopenharmony_ci    ip_addr_set(&buf->addr, addr);
259195972f6Sopenharmony_ci    buf->port = port;
260195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO
261195972f6Sopenharmony_ci    if (conn->flags & NETCONN_FLAG_PKTINFO) {
262195972f6Sopenharmony_ci      /* get the UDP header - always in the first pbuf, ensured by udp_input */
263195972f6Sopenharmony_ci      const struct udp_hdr *udphdr = (const struct udp_hdr *)ip_next_header_ptr();
264195972f6Sopenharmony_ci      buf->flags = NETBUF_FLAG_DESTADDR;
265195972f6Sopenharmony_ci      ip_addr_set(&buf->toaddr, ip_current_dest_addr());
266195972f6Sopenharmony_ci      buf->toport_chksum = udphdr->dest;
267195972f6Sopenharmony_ci    }
268195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */
269195972f6Sopenharmony_ci  }
270195972f6Sopenharmony_ci
271195972f6Sopenharmony_ci  len = p->tot_len;
272195972f6Sopenharmony_ci  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
273195972f6Sopenharmony_ci    netbuf_delete(buf);
274195972f6Sopenharmony_ci    return;
275195972f6Sopenharmony_ci  } else {
276195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
277195972f6Sopenharmony_ci    SYS_ARCH_INC(conn->recv_avail, len);
278195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
279195972f6Sopenharmony_ci    /* Register event with callback */
280195972f6Sopenharmony_ci    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
281195972f6Sopenharmony_ci  }
282195972f6Sopenharmony_ci}
283195972f6Sopenharmony_ci#endif /* LWIP_UDP */
284195972f6Sopenharmony_ci
285195972f6Sopenharmony_ci#if LWIP_TCP
286195972f6Sopenharmony_ci/**
287195972f6Sopenharmony_ci * Receive callback function for TCP netconns.
288195972f6Sopenharmony_ci * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
289195972f6Sopenharmony_ci *
290195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
291195972f6Sopenharmony_ci */
292195972f6Sopenharmony_cistatic err_t
293195972f6Sopenharmony_cirecv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
294195972f6Sopenharmony_ci{
295195972f6Sopenharmony_ci  struct netconn *conn;
296195972f6Sopenharmony_ci  u16_t len;
297195972f6Sopenharmony_ci  void *msg;
298195972f6Sopenharmony_ci
299195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb);
300195972f6Sopenharmony_ci  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
301195972f6Sopenharmony_ci  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
302195972f6Sopenharmony_ci  LWIP_ASSERT("err != ERR_OK unhandled", err == ERR_OK);
303195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
304195972f6Sopenharmony_ci  conn = (struct netconn *)arg;
305195972f6Sopenharmony_ci
306195972f6Sopenharmony_ci  if (conn == NULL) {
307195972f6Sopenharmony_ci    return ERR_VAL;
308195972f6Sopenharmony_ci  }
309195972f6Sopenharmony_ci  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
310195972f6Sopenharmony_ci
311195972f6Sopenharmony_ci  if (!NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
312195972f6Sopenharmony_ci    /* recvmbox already deleted */
313195972f6Sopenharmony_ci    if (p != NULL) {
314195972f6Sopenharmony_ci      tcp_recved(pcb, p->tot_len);
315195972f6Sopenharmony_ci      pbuf_free(p);
316195972f6Sopenharmony_ci    }
317195972f6Sopenharmony_ci    return ERR_OK;
318195972f6Sopenharmony_ci  }
319195972f6Sopenharmony_ci  /* Unlike for UDP or RAW pcbs, don't check for available space
320195972f6Sopenharmony_ci     using recv_avail since that could break the connection
321195972f6Sopenharmony_ci     (data is already ACKed) */
322195972f6Sopenharmony_ci
323195972f6Sopenharmony_ci  if (p != NULL) {
324195972f6Sopenharmony_ci    msg = p;
325195972f6Sopenharmony_ci    len = p->tot_len;
326195972f6Sopenharmony_ci  } else {
327195972f6Sopenharmony_ci    msg = LWIP_CONST_CAST(void *, &netconn_closed);
328195972f6Sopenharmony_ci    len = 0;
329195972f6Sopenharmony_ci  }
330195972f6Sopenharmony_ci
331195972f6Sopenharmony_ci  if (sys_mbox_trypost(&conn->recvmbox, msg) != ERR_OK) {
332195972f6Sopenharmony_ci    /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
333195972f6Sopenharmony_ci    return ERR_MEM;
334195972f6Sopenharmony_ci  } else {
335195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
336195972f6Sopenharmony_ci    SYS_ARCH_INC(conn->recv_avail, len);
337195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
338195972f6Sopenharmony_ci    /* Register event with callback */
339195972f6Sopenharmony_ci    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
340195972f6Sopenharmony_ci  }
341195972f6Sopenharmony_ci
342195972f6Sopenharmony_ci  return ERR_OK;
343195972f6Sopenharmony_ci}
344195972f6Sopenharmony_ci
345195972f6Sopenharmony_ci/**
346195972f6Sopenharmony_ci * Poll callback function for TCP netconns.
347195972f6Sopenharmony_ci * Wakes up an application thread that waits for a connection to close
348195972f6Sopenharmony_ci * or data to be sent. The application thread then takes the
349195972f6Sopenharmony_ci * appropriate action to go on.
350195972f6Sopenharmony_ci *
351195972f6Sopenharmony_ci * Signals the conn->sem.
352195972f6Sopenharmony_ci * netconn_close waits for conn->sem if closing failed.
353195972f6Sopenharmony_ci *
354195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
355195972f6Sopenharmony_ci */
356195972f6Sopenharmony_cistatic err_t
357195972f6Sopenharmony_cipoll_tcp(void *arg, struct tcp_pcb *pcb)
358195972f6Sopenharmony_ci{
359195972f6Sopenharmony_ci  struct netconn *conn = (struct netconn *)arg;
360195972f6Sopenharmony_ci
361195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb);
362195972f6Sopenharmony_ci  LWIP_ASSERT("conn != NULL", (conn != NULL));
363195972f6Sopenharmony_ci
364195972f6Sopenharmony_ci  if (conn->state == NETCONN_WRITE) {
365195972f6Sopenharmony_ci    lwip_netconn_do_writemore(conn  WRITE_DELAYED);
366195972f6Sopenharmony_ci  } else if (conn->state == NETCONN_CLOSE) {
367195972f6Sopenharmony_ci#if !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER
368195972f6Sopenharmony_ci    if (conn->current_msg && conn->current_msg->msg.sd.polls_left) {
369195972f6Sopenharmony_ci      conn->current_msg->msg.sd.polls_left--;
370195972f6Sopenharmony_ci    }
371195972f6Sopenharmony_ci#endif /* !LWIP_SO_SNDTIMEO && !LWIP_SO_LINGER */
372195972f6Sopenharmony_ci    lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
373195972f6Sopenharmony_ci  }
374195972f6Sopenharmony_ci  /* @todo: implement connect timeout here? */
375195972f6Sopenharmony_ci
376195972f6Sopenharmony_ci  /* Did a nonblocking write fail before? Then check available write-space. */
377195972f6Sopenharmony_ci  if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
378195972f6Sopenharmony_ci    /* If the queued byte- or pbuf-count drops below the configured low-water limit,
379195972f6Sopenharmony_ci       let select mark this pcb as writable again. */
380195972f6Sopenharmony_ci    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
381195972f6Sopenharmony_ci        (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
382195972f6Sopenharmony_ci      netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
383195972f6Sopenharmony_ci      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
384195972f6Sopenharmony_ci    }
385195972f6Sopenharmony_ci  }
386195972f6Sopenharmony_ci
387195972f6Sopenharmony_ci  return ERR_OK;
388195972f6Sopenharmony_ci}
389195972f6Sopenharmony_ci
390195972f6Sopenharmony_ci#if LWIP_LOWPOWER
391195972f6Sopenharmony_ci/* check wether need to poll tcp */
392195972f6Sopenharmony_ciu8_t
393195972f6Sopenharmony_cipoll_tcp_needed(void *arg, struct tcp_pcb *pcb)
394195972f6Sopenharmony_ci{
395195972f6Sopenharmony_ci  struct netconn *conn = (struct netconn *)arg;
396195972f6Sopenharmony_ci  u8_t ret = 0;
397195972f6Sopenharmony_ci
398195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb);
399195972f6Sopenharmony_ci  if (conn == NULL) {
400195972f6Sopenharmony_ci    return 0;
401195972f6Sopenharmony_ci  }
402195972f6Sopenharmony_ci  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
403195972f6Sopenharmony_ci    ret = 1;
404195972f6Sopenharmony_ci  }
405195972f6Sopenharmony_ci
406195972f6Sopenharmony_ci  /* Did a nonblocking write fail before? Then check available write-space. */
407195972f6Sopenharmony_ci  if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) {
408195972f6Sopenharmony_ci    /* If the queued byte- or pbuf-count drops below the configured low-water limit,
409195972f6Sopenharmony_ci       let select mark this pcb as writable again. */
410195972f6Sopenharmony_ci    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
411195972f6Sopenharmony_ci        (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
412195972f6Sopenharmony_ci      ret = 1;
413195972f6Sopenharmony_ci    }
414195972f6Sopenharmony_ci  }
415195972f6Sopenharmony_ci  return ret;
416195972f6Sopenharmony_ci}
417195972f6Sopenharmony_ci#endif /* LWIP_LOWPOWER */
418195972f6Sopenharmony_ci
419195972f6Sopenharmony_ci/**
420195972f6Sopenharmony_ci * Sent callback function for TCP netconns.
421195972f6Sopenharmony_ci * Signals the conn->sem and calls API_EVENT.
422195972f6Sopenharmony_ci * netconn_write waits for conn->sem if send buffer is low.
423195972f6Sopenharmony_ci *
424195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
425195972f6Sopenharmony_ci */
426195972f6Sopenharmony_cistatic err_t
427195972f6Sopenharmony_cisent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
428195972f6Sopenharmony_ci{
429195972f6Sopenharmony_ci  struct netconn *conn = (struct netconn *)arg;
430195972f6Sopenharmony_ci
431195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb);
432195972f6Sopenharmony_ci  LWIP_ASSERT("conn != NULL", (conn != NULL));
433195972f6Sopenharmony_ci
434195972f6Sopenharmony_ci  if (conn) {
435195972f6Sopenharmony_ci    if (conn->state == NETCONN_WRITE) {
436195972f6Sopenharmony_ci      lwip_netconn_do_writemore(conn  WRITE_DELAYED);
437195972f6Sopenharmony_ci    } else if (conn->state == NETCONN_CLOSE) {
438195972f6Sopenharmony_ci      lwip_netconn_do_close_internal(conn  WRITE_DELAYED);
439195972f6Sopenharmony_ci    }
440195972f6Sopenharmony_ci
441195972f6Sopenharmony_ci    /* If the queued byte- or pbuf-count drops below the configured low-water limit,
442195972f6Sopenharmony_ci       let select mark this pcb as writable again. */
443195972f6Sopenharmony_ci    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
444195972f6Sopenharmony_ci        (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
445195972f6Sopenharmony_ci      netconn_clear_flags(conn, NETCONN_FLAG_CHECK_WRITESPACE);
446195972f6Sopenharmony_ci      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
447195972f6Sopenharmony_ci    }
448195972f6Sopenharmony_ci  }
449195972f6Sopenharmony_ci
450195972f6Sopenharmony_ci  return ERR_OK;
451195972f6Sopenharmony_ci}
452195972f6Sopenharmony_ci
453195972f6Sopenharmony_ci/**
454195972f6Sopenharmony_ci * Error callback function for TCP netconns.
455195972f6Sopenharmony_ci * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
456195972f6Sopenharmony_ci * The application thread has then to decide what to do.
457195972f6Sopenharmony_ci *
458195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.err) for parameters
459195972f6Sopenharmony_ci */
460195972f6Sopenharmony_cistatic void
461195972f6Sopenharmony_cierr_tcp(void *arg, err_t err)
462195972f6Sopenharmony_ci{
463195972f6Sopenharmony_ci  struct netconn *conn;
464195972f6Sopenharmony_ci  enum netconn_state old_state;
465195972f6Sopenharmony_ci  void *mbox_msg;
466195972f6Sopenharmony_ci  SYS_ARCH_DECL_PROTECT(lev);
467195972f6Sopenharmony_ci
468195972f6Sopenharmony_ci  conn = (struct netconn *)arg;
469195972f6Sopenharmony_ci  LWIP_ASSERT("conn != NULL", (conn != NULL));
470195972f6Sopenharmony_ci
471195972f6Sopenharmony_ci  SYS_ARCH_PROTECT(lev);
472195972f6Sopenharmony_ci
473195972f6Sopenharmony_ci  /* when err is called, the pcb is deallocated, so delete the reference */
474195972f6Sopenharmony_ci  conn->pcb.tcp = NULL;
475195972f6Sopenharmony_ci  /* store pending error */
476195972f6Sopenharmony_ci  conn->pending_err = err;
477195972f6Sopenharmony_ci  /* prevent application threads from blocking on 'recvmbox'/'acceptmbox' */
478195972f6Sopenharmony_ci  conn->flags |= NETCONN_FLAG_MBOXCLOSED;
479195972f6Sopenharmony_ci
480195972f6Sopenharmony_ci  /* reset conn->state now before waking up other threads */
481195972f6Sopenharmony_ci  old_state = conn->state;
482195972f6Sopenharmony_ci  conn->state = NETCONN_NONE;
483195972f6Sopenharmony_ci
484195972f6Sopenharmony_ci  SYS_ARCH_UNPROTECT(lev);
485195972f6Sopenharmony_ci
486195972f6Sopenharmony_ci  /* Notify the user layer about a connection error. Used to signal select. */
487195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_ERROR, 0);
488195972f6Sopenharmony_ci  /* Try to release selects pending on 'read' or 'write', too.
489195972f6Sopenharmony_ci     They will get an error if they actually try to read or write. */
490195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
491195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
492195972f6Sopenharmony_ci
493195972f6Sopenharmony_ci  mbox_msg = lwip_netconn_err_to_msg(err);
494195972f6Sopenharmony_ci  /* pass error message to recvmbox to wake up pending recv */
495195972f6Sopenharmony_ci  if (NETCONN_MBOX_VALID(conn, &conn->recvmbox)) {
496195972f6Sopenharmony_ci    /* use trypost to prevent deadlock */
497195972f6Sopenharmony_ci    sys_mbox_trypost(&conn->recvmbox, mbox_msg);
498195972f6Sopenharmony_ci  }
499195972f6Sopenharmony_ci  /* pass error message to acceptmbox to wake up pending accept */
500195972f6Sopenharmony_ci  if (NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
501195972f6Sopenharmony_ci    /* use trypost to preven deadlock */
502195972f6Sopenharmony_ci    sys_mbox_trypost(&conn->acceptmbox, mbox_msg);
503195972f6Sopenharmony_ci  }
504195972f6Sopenharmony_ci
505195972f6Sopenharmony_ci  if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
506195972f6Sopenharmony_ci      (old_state == NETCONN_CONNECT)) {
507195972f6Sopenharmony_ci    /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary
508195972f6Sopenharmony_ci       since the pcb has already been deleted! */
509195972f6Sopenharmony_ci    int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
510195972f6Sopenharmony_ci    SET_NONBLOCKING_CONNECT(conn, 0);
511195972f6Sopenharmony_ci
512195972f6Sopenharmony_ci    if (!was_nonblocking_connect) {
513195972f6Sopenharmony_ci      sys_sem_t *op_completed_sem;
514195972f6Sopenharmony_ci      /* set error return code */
515195972f6Sopenharmony_ci      LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
516195972f6Sopenharmony_ci      if (old_state == NETCONN_CLOSE) {
517195972f6Sopenharmony_ci        /* let close succeed: the connection is closed after all... */
518195972f6Sopenharmony_ci        conn->current_msg->err = ERR_OK;
519195972f6Sopenharmony_ci      } else {
520195972f6Sopenharmony_ci        /* Write and connect fail */
521195972f6Sopenharmony_ci        conn->current_msg->err = err;
522195972f6Sopenharmony_ci      }
523195972f6Sopenharmony_ci      op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
524195972f6Sopenharmony_ci      LWIP_ASSERT("inavlid op_completed_sem", sys_sem_valid(op_completed_sem));
525195972f6Sopenharmony_ci      conn->current_msg = NULL;
526195972f6Sopenharmony_ci      /* wake up the waiting task */
527195972f6Sopenharmony_ci      sys_sem_signal(op_completed_sem);
528195972f6Sopenharmony_ci    } else {
529195972f6Sopenharmony_ci      /* @todo: test what happens for error on nonblocking connect */
530195972f6Sopenharmony_ci    }
531195972f6Sopenharmony_ci  } else {
532195972f6Sopenharmony_ci    LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
533195972f6Sopenharmony_ci  }
534195972f6Sopenharmony_ci}
535195972f6Sopenharmony_ci
536195972f6Sopenharmony_ci/**
537195972f6Sopenharmony_ci * Setup a tcp_pcb with the correct callback function pointers
538195972f6Sopenharmony_ci * and their arguments.
539195972f6Sopenharmony_ci *
540195972f6Sopenharmony_ci * @param conn the TCP netconn to setup
541195972f6Sopenharmony_ci */
542195972f6Sopenharmony_cistatic void
543195972f6Sopenharmony_cisetup_tcp(struct netconn *conn)
544195972f6Sopenharmony_ci{
545195972f6Sopenharmony_ci  struct tcp_pcb *pcb;
546195972f6Sopenharmony_ci
547195972f6Sopenharmony_ci  pcb = conn->pcb.tcp;
548195972f6Sopenharmony_ci  tcp_arg(pcb, conn);
549195972f6Sopenharmony_ci  tcp_recv(pcb, recv_tcp);
550195972f6Sopenharmony_ci  tcp_sent(pcb, sent_tcp);
551195972f6Sopenharmony_ci  tcp_poll(pcb, poll_tcp, NETCONN_TCP_POLL_INTERVAL);
552195972f6Sopenharmony_ci  tcp_err(pcb, err_tcp);
553195972f6Sopenharmony_ci}
554195972f6Sopenharmony_ci
555195972f6Sopenharmony_ci/**
556195972f6Sopenharmony_ci * Accept callback function for TCP netconns.
557195972f6Sopenharmony_ci * Allocates a new netconn and posts that to conn->acceptmbox.
558195972f6Sopenharmony_ci *
559195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
560195972f6Sopenharmony_ci */
561195972f6Sopenharmony_cistatic err_t
562195972f6Sopenharmony_ciaccept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
563195972f6Sopenharmony_ci{
564195972f6Sopenharmony_ci  struct netconn *newconn;
565195972f6Sopenharmony_ci  struct netconn *conn = (struct netconn *)arg;
566195972f6Sopenharmony_ci
567195972f6Sopenharmony_ci  if (conn == NULL) {
568195972f6Sopenharmony_ci    return ERR_VAL;
569195972f6Sopenharmony_ci  }
570195972f6Sopenharmony_ci  if (!NETCONN_MBOX_VALID(conn, &conn->acceptmbox)) {
571195972f6Sopenharmony_ci    LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
572195972f6Sopenharmony_ci    return ERR_VAL;
573195972f6Sopenharmony_ci  }
574195972f6Sopenharmony_ci
575195972f6Sopenharmony_ci  if (newpcb == NULL) {
576195972f6Sopenharmony_ci    /* out-of-pcbs during connect: pass on this error to the application */
577195972f6Sopenharmony_ci    if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
578195972f6Sopenharmony_ci      /* Register event with callback */
579195972f6Sopenharmony_ci      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
580195972f6Sopenharmony_ci    }
581195972f6Sopenharmony_ci    return ERR_VAL;
582195972f6Sopenharmony_ci  }
583195972f6Sopenharmony_ci  LWIP_ASSERT("expect newpcb == NULL or err == ERR_OK", err == ERR_OK);
584195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */
585195972f6Sopenharmony_ci
586195972f6Sopenharmony_ci  LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->state: %s\n", tcp_debug_state_str(newpcb->state)));
587195972f6Sopenharmony_ci
588195972f6Sopenharmony_ci  /* We have to set the callback here even though
589195972f6Sopenharmony_ci   * the new socket is unknown. newconn->socket is marked as -1. */
590195972f6Sopenharmony_ci  newconn = netconn_alloc(conn->type, conn->callback);
591195972f6Sopenharmony_ci  if (newconn == NULL) {
592195972f6Sopenharmony_ci    /* outof netconns: pass on this error to the application */
593195972f6Sopenharmony_ci    if (sys_mbox_trypost(&conn->acceptmbox, lwip_netconn_err_to_msg(ERR_ABRT)) == ERR_OK) {
594195972f6Sopenharmony_ci      /* Register event with callback */
595195972f6Sopenharmony_ci      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
596195972f6Sopenharmony_ci    }
597195972f6Sopenharmony_ci    return ERR_MEM;
598195972f6Sopenharmony_ci  }
599195972f6Sopenharmony_ci  newconn->pcb.tcp = newpcb;
600195972f6Sopenharmony_ci  setup_tcp(newconn);
601195972f6Sopenharmony_ci
602195972f6Sopenharmony_ci  /* handle backlog counter */
603195972f6Sopenharmony_ci  tcp_backlog_delayed(newpcb);
604195972f6Sopenharmony_ci
605195972f6Sopenharmony_ci  if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
606195972f6Sopenharmony_ci    /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
607195972f6Sopenharmony_ci       so do nothing here! */
608195972f6Sopenharmony_ci    /* remove all references to this netconn from the pcb */
609195972f6Sopenharmony_ci    struct tcp_pcb *pcb = newconn->pcb.tcp;
610195972f6Sopenharmony_ci    tcp_arg(pcb, NULL);
611195972f6Sopenharmony_ci    tcp_recv(pcb, NULL);
612195972f6Sopenharmony_ci    tcp_sent(pcb, NULL);
613195972f6Sopenharmony_ci    tcp_poll(pcb, NULL, 0);
614195972f6Sopenharmony_ci    tcp_err(pcb, NULL);
615195972f6Sopenharmony_ci    /* remove reference from to the pcb from this netconn */
616195972f6Sopenharmony_ci    newconn->pcb.tcp = NULL;
617195972f6Sopenharmony_ci    /* no need to drain since we know the recvmbox is empty. */
618195972f6Sopenharmony_ci    sys_mbox_free(&newconn->recvmbox);
619195972f6Sopenharmony_ci    sys_mbox_set_invalid(&newconn->recvmbox);
620195972f6Sopenharmony_ci    netconn_free(newconn);
621195972f6Sopenharmony_ci    return ERR_MEM;
622195972f6Sopenharmony_ci  } else {
623195972f6Sopenharmony_ci    /* Register event with callback */
624195972f6Sopenharmony_ci    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
625195972f6Sopenharmony_ci  }
626195972f6Sopenharmony_ci
627195972f6Sopenharmony_ci  return ERR_OK;
628195972f6Sopenharmony_ci}
629195972f6Sopenharmony_ci#endif /* LWIP_TCP */
630195972f6Sopenharmony_ci
631195972f6Sopenharmony_ci/**
632195972f6Sopenharmony_ci * Create a new pcb of a specific type.
633195972f6Sopenharmony_ci * Called from lwip_netconn_do_newconn().
634195972f6Sopenharmony_ci *
635195972f6Sopenharmony_ci * @param msg the api_msg describing the connection type
636195972f6Sopenharmony_ci */
637195972f6Sopenharmony_cistatic void
638195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
639195972f6Sopenharmony_cipcb_new(struct api_msg *msg, struct net_group *group)
640195972f6Sopenharmony_ci#else
641195972f6Sopenharmony_cipcb_new(struct api_msg *msg)
642195972f6Sopenharmony_ci#endif
643195972f6Sopenharmony_ci{
644195972f6Sopenharmony_ci  enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4;
645195972f6Sopenharmony_ci
646195972f6Sopenharmony_ci  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
647195972f6Sopenharmony_ci
648195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV4
649195972f6Sopenharmony_ci  /* IPv6: Dual-stack by default, unless netconn_set_ipv6only() is called */
650195972f6Sopenharmony_ci  if (NETCONNTYPE_ISIPV6(netconn_type(msg->conn))) {
651195972f6Sopenharmony_ci    iptype = IPADDR_TYPE_ANY;
652195972f6Sopenharmony_ci  }
653195972f6Sopenharmony_ci#endif
654195972f6Sopenharmony_ci
655195972f6Sopenharmony_ci  /* Allocate a PCB for this connection */
656195972f6Sopenharmony_ci  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
657195972f6Sopenharmony_ci#if LWIP_RAW
658195972f6Sopenharmony_ci    case NETCONN_RAW:
659195972f6Sopenharmony_ci      msg->conn->pcb.raw = raw_new_ip_type(iptype, msg->msg.n.proto);
660195972f6Sopenharmony_ci      if (msg->conn->pcb.raw != NULL) {
661195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
662195972f6Sopenharmony_ci        set_raw_pcb_net_group(msg->conn->pcb.raw, group);
663195972f6Sopenharmony_ci#endif
664195972f6Sopenharmony_ci#if LWIP_IPV6
665195972f6Sopenharmony_ci        /* ICMPv6 packets should always have checksum calculated by the stack as per RFC 3542 chapter 3.1 */
666195972f6Sopenharmony_ci        if (NETCONNTYPE_ISIPV6(msg->conn->type) && msg->conn->pcb.raw->protocol == IP6_NEXTH_ICMP6) {
667195972f6Sopenharmony_ci          msg->conn->pcb.raw->chksum_reqd = 1;
668195972f6Sopenharmony_ci          msg->conn->pcb.raw->chksum_offset = 2;
669195972f6Sopenharmony_ci        }
670195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */
671195972f6Sopenharmony_ci        raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
672195972f6Sopenharmony_ci      }
673195972f6Sopenharmony_ci      break;
674195972f6Sopenharmony_ci#endif /* LWIP_RAW */
675195972f6Sopenharmony_ci#if LWIP_UDP
676195972f6Sopenharmony_ci    case NETCONN_UDP:
677195972f6Sopenharmony_ci      msg->conn->pcb.udp = udp_new_ip_type(iptype);
678195972f6Sopenharmony_ci      if (msg->conn->pcb.udp != NULL) {
679195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
680195972f6Sopenharmony_ci        set_udp_pcb_net_group(msg->conn->pcb.udp, group);
681195972f6Sopenharmony_ci#endif
682195972f6Sopenharmony_ci#if LWIP_UDPLITE
683195972f6Sopenharmony_ci        if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
684195972f6Sopenharmony_ci          udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
685195972f6Sopenharmony_ci        }
686195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */
687195972f6Sopenharmony_ci        if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
688195972f6Sopenharmony_ci          udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
689195972f6Sopenharmony_ci        }
690195972f6Sopenharmony_ci        udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
691195972f6Sopenharmony_ci      }
692195972f6Sopenharmony_ci      break;
693195972f6Sopenharmony_ci#endif /* LWIP_UDP */
694195972f6Sopenharmony_ci#if LWIP_TCP
695195972f6Sopenharmony_ci    case NETCONN_TCP:
696195972f6Sopenharmony_ci      msg->conn->pcb.tcp = tcp_new_ip_type(iptype);
697195972f6Sopenharmony_ci      if (msg->conn->pcb.tcp != NULL) {
698195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
699195972f6Sopenharmony_ci        set_tcp_pcb_net_group(msg->conn->pcb.tcp, group);
700195972f6Sopenharmony_ci#endif
701195972f6Sopenharmony_ci        setup_tcp(msg->conn);
702195972f6Sopenharmony_ci      }
703195972f6Sopenharmony_ci      break;
704195972f6Sopenharmony_ci#endif /* LWIP_TCP */
705195972f6Sopenharmony_ci    default:
706195972f6Sopenharmony_ci      /* Unsupported netconn type, e.g. protocol disabled */
707195972f6Sopenharmony_ci      msg->err = ERR_VAL;
708195972f6Sopenharmony_ci      return;
709195972f6Sopenharmony_ci  }
710195972f6Sopenharmony_ci  if (msg->conn->pcb.ip == NULL) {
711195972f6Sopenharmony_ci    msg->err = ERR_MEM;
712195972f6Sopenharmony_ci  }
713195972f6Sopenharmony_ci}
714195972f6Sopenharmony_ci
715195972f6Sopenharmony_ci/**
716195972f6Sopenharmony_ci * Create a new pcb of a specific type inside a netconn.
717195972f6Sopenharmony_ci * Called from netconn_new_with_proto_and_callback.
718195972f6Sopenharmony_ci *
719195972f6Sopenharmony_ci * @param m the api_msg describing the connection type
720195972f6Sopenharmony_ci */
721195972f6Sopenharmony_civoid
722195972f6Sopenharmony_cilwip_netconn_do_newconn(void *m)
723195972f6Sopenharmony_ci{
724195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
725195972f6Sopenharmony_ci
726195972f6Sopenharmony_ci  msg->err = ERR_OK;
727195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp == NULL) {
728195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
729195972f6Sopenharmony_ci    pcb_new(msg, get_curr_process_net_group());
730195972f6Sopenharmony_ci#else
731195972f6Sopenharmony_ci    pcb_new(msg);
732195972f6Sopenharmony_ci#endif
733195972f6Sopenharmony_ci  }
734195972f6Sopenharmony_ci  /* Else? This "new" connection already has a PCB allocated. */
735195972f6Sopenharmony_ci  /* Is this an error condition? Should it be deleted? */
736195972f6Sopenharmony_ci  /* We currently just are happy and return. */
737195972f6Sopenharmony_ci
738195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
739195972f6Sopenharmony_ci}
740195972f6Sopenharmony_ci
741195972f6Sopenharmony_ci/**
742195972f6Sopenharmony_ci * Create a new netconn (of a specific type) that has a callback function.
743195972f6Sopenharmony_ci * The corresponding pcb is NOT created!
744195972f6Sopenharmony_ci *
745195972f6Sopenharmony_ci * @param t the type of 'connection' to create (@see enum netconn_type)
746195972f6Sopenharmony_ci * @param callback a function to call on status changes (RX available, TX'ed)
747195972f6Sopenharmony_ci * @return a newly allocated struct netconn or
748195972f6Sopenharmony_ci *         NULL on memory error
749195972f6Sopenharmony_ci */
750195972f6Sopenharmony_cistruct netconn *
751195972f6Sopenharmony_cinetconn_alloc(enum netconn_type t, netconn_callback callback)
752195972f6Sopenharmony_ci{
753195972f6Sopenharmony_ci  struct netconn *conn;
754195972f6Sopenharmony_ci  int size;
755195972f6Sopenharmony_ci  u8_t init_flags = 0;
756195972f6Sopenharmony_ci
757195972f6Sopenharmony_ci  conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
758195972f6Sopenharmony_ci  if (conn == NULL) {
759195972f6Sopenharmony_ci    return NULL;
760195972f6Sopenharmony_ci  }
761195972f6Sopenharmony_ci
762195972f6Sopenharmony_ci  conn->pending_err = ERR_OK;
763195972f6Sopenharmony_ci  conn->type = t;
764195972f6Sopenharmony_ci  conn->pcb.tcp = NULL;
765195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
766195972f6Sopenharmony_ci  conn->mbox_threads_waiting = 0;
767195972f6Sopenharmony_ci#endif
768195972f6Sopenharmony_ci
769195972f6Sopenharmony_ci  /* If all sizes are the same, every compiler should optimize this switch to nothing */
770195972f6Sopenharmony_ci  switch (NETCONNTYPE_GROUP(t)) {
771195972f6Sopenharmony_ci#if LWIP_RAW
772195972f6Sopenharmony_ci    case NETCONN_RAW:
773195972f6Sopenharmony_ci      size = DEFAULT_RAW_RECVMBOX_SIZE;
774195972f6Sopenharmony_ci      break;
775195972f6Sopenharmony_ci#endif /* LWIP_RAW */
776195972f6Sopenharmony_ci#if LWIP_UDP
777195972f6Sopenharmony_ci    case NETCONN_UDP:
778195972f6Sopenharmony_ci      size = DEFAULT_UDP_RECVMBOX_SIZE;
779195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO
780195972f6Sopenharmony_ci      init_flags |= NETCONN_FLAG_PKTINFO;
781195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */
782195972f6Sopenharmony_ci      break;
783195972f6Sopenharmony_ci#endif /* LWIP_UDP */
784195972f6Sopenharmony_ci#if LWIP_TCP
785195972f6Sopenharmony_ci    case NETCONN_TCP:
786195972f6Sopenharmony_ci      size = DEFAULT_TCP_RECVMBOX_SIZE;
787195972f6Sopenharmony_ci      break;
788195972f6Sopenharmony_ci#endif /* LWIP_TCP */
789195972f6Sopenharmony_ci    default:
790195972f6Sopenharmony_ci      LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
791195972f6Sopenharmony_ci      goto free_and_return;
792195972f6Sopenharmony_ci  }
793195972f6Sopenharmony_ci
794195972f6Sopenharmony_ci  if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
795195972f6Sopenharmony_ci    goto free_and_return;
796195972f6Sopenharmony_ci  }
797195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD
798195972f6Sopenharmony_ci  if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
799195972f6Sopenharmony_ci    sys_mbox_free(&conn->recvmbox);
800195972f6Sopenharmony_ci    goto free_and_return;
801195972f6Sopenharmony_ci  }
802195972f6Sopenharmony_ci#endif
803195972f6Sopenharmony_ci
804195972f6Sopenharmony_ci#if LWIP_TCP
805195972f6Sopenharmony_ci  sys_mbox_set_invalid(&conn->acceptmbox);
806195972f6Sopenharmony_ci#endif
807195972f6Sopenharmony_ci  conn->state        = NETCONN_NONE;
808195972f6Sopenharmony_ci#if LWIP_SOCKET
809195972f6Sopenharmony_ci  /* initialize socket to -1 since 0 is a valid socket */
810195972f6Sopenharmony_ci  conn->socket       = -1;
811195972f6Sopenharmony_ci#endif /* LWIP_SOCKET */
812195972f6Sopenharmony_ci  conn->callback     = callback;
813195972f6Sopenharmony_ci#if LWIP_TCP
814195972f6Sopenharmony_ci  conn->current_msg  = NULL;
815195972f6Sopenharmony_ci#endif /* LWIP_TCP */
816195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO
817195972f6Sopenharmony_ci  conn->send_timeout = 0;
818195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */
819195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO
820195972f6Sopenharmony_ci  conn->recv_timeout = 0;
821195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO */
822195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
823195972f6Sopenharmony_ci  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
824195972f6Sopenharmony_ci  conn->recv_avail   = 0;
825195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
826195972f6Sopenharmony_ci#if LWIP_SO_LINGER
827195972f6Sopenharmony_ci  conn->linger = -1;
828195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */
829195972f6Sopenharmony_ci  conn->flags = init_flags;
830195972f6Sopenharmony_ci  return conn;
831195972f6Sopenharmony_cifree_and_return:
832195972f6Sopenharmony_ci  memp_free(MEMP_NETCONN, conn);
833195972f6Sopenharmony_ci  return NULL;
834195972f6Sopenharmony_ci}
835195972f6Sopenharmony_ci
836195972f6Sopenharmony_ci/**
837195972f6Sopenharmony_ci * Delete a netconn and all its resources.
838195972f6Sopenharmony_ci * The pcb is NOT freed (since we might not be in the right thread context do this).
839195972f6Sopenharmony_ci *
840195972f6Sopenharmony_ci * @param conn the netconn to free
841195972f6Sopenharmony_ci */
842195972f6Sopenharmony_civoid
843195972f6Sopenharmony_cinetconn_free(struct netconn *conn)
844195972f6Sopenharmony_ci{
845195972f6Sopenharmony_ci  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
846195972f6Sopenharmony_ci
847195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
848195972f6Sopenharmony_ci  /* in fullduplex, netconn is drained here */
849195972f6Sopenharmony_ci  netconn_drain(conn);
850195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
851195972f6Sopenharmony_ci
852195972f6Sopenharmony_ci  LWIP_ASSERT("recvmbox must be deallocated before calling this function",
853195972f6Sopenharmony_ci              !sys_mbox_valid(&conn->recvmbox));
854195972f6Sopenharmony_ci#if LWIP_TCP
855195972f6Sopenharmony_ci  LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
856195972f6Sopenharmony_ci              !sys_mbox_valid(&conn->acceptmbox));
857195972f6Sopenharmony_ci#endif /* LWIP_TCP */
858195972f6Sopenharmony_ci
859195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD
860195972f6Sopenharmony_ci  sys_sem_free(&conn->op_completed);
861195972f6Sopenharmony_ci  sys_sem_set_invalid(&conn->op_completed);
862195972f6Sopenharmony_ci#endif
863195972f6Sopenharmony_ci
864195972f6Sopenharmony_ci  memp_free(MEMP_NETCONN, conn);
865195972f6Sopenharmony_ci}
866195972f6Sopenharmony_ci
867195972f6Sopenharmony_ci/**
868195972f6Sopenharmony_ci * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
869195972f6Sopenharmony_ci * these mboxes
870195972f6Sopenharmony_ci *
871195972f6Sopenharmony_ci * @param conn the netconn to free
872195972f6Sopenharmony_ci * @bytes_drained bytes drained from recvmbox
873195972f6Sopenharmony_ci * @accepts_drained pending connections drained from acceptmbox
874195972f6Sopenharmony_ci */
875195972f6Sopenharmony_cistatic void
876195972f6Sopenharmony_cinetconn_drain(struct netconn *conn)
877195972f6Sopenharmony_ci{
878195972f6Sopenharmony_ci  void *mem;
879195972f6Sopenharmony_ci
880195972f6Sopenharmony_ci  /* This runs when mbox and netconn are marked as closed,
881195972f6Sopenharmony_ci     so we don't need to lock against rx packets */
882195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
883195972f6Sopenharmony_ci  LWIP_ASSERT("netconn marked closed", conn->flags & NETCONN_FLAG_MBOXINVALID);
884195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
885195972f6Sopenharmony_ci
886195972f6Sopenharmony_ci  /* Delete and drain the recvmbox. */
887195972f6Sopenharmony_ci  if (sys_mbox_valid(&conn->recvmbox)) {
888195972f6Sopenharmony_ci    while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
889195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
890195972f6Sopenharmony_ci      if (!lwip_netconn_is_deallocated_msg(mem))
891195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
892195972f6Sopenharmony_ci      {
893195972f6Sopenharmony_ci#if LWIP_TCP
894195972f6Sopenharmony_ci        if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
895195972f6Sopenharmony_ci          err_t err;
896195972f6Sopenharmony_ci          if (!lwip_netconn_is_err_msg(mem, &err)) {
897195972f6Sopenharmony_ci            pbuf_free((struct pbuf *)mem);
898195972f6Sopenharmony_ci          }
899195972f6Sopenharmony_ci        } else
900195972f6Sopenharmony_ci#endif /* LWIP_TCP */
901195972f6Sopenharmony_ci        {
902195972f6Sopenharmony_ci          netbuf_delete((struct netbuf *)mem);
903195972f6Sopenharmony_ci        }
904195972f6Sopenharmony_ci      }
905195972f6Sopenharmony_ci    }
906195972f6Sopenharmony_ci    sys_mbox_free(&conn->recvmbox);
907195972f6Sopenharmony_ci    sys_mbox_set_invalid(&conn->recvmbox);
908195972f6Sopenharmony_ci  }
909195972f6Sopenharmony_ci
910195972f6Sopenharmony_ci  /* Delete and drain the acceptmbox. */
911195972f6Sopenharmony_ci#if LWIP_TCP
912195972f6Sopenharmony_ci  if (sys_mbox_valid(&conn->acceptmbox)) {
913195972f6Sopenharmony_ci    while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
914195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
915195972f6Sopenharmony_ci      if (!lwip_netconn_is_deallocated_msg(mem))
916195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
917195972f6Sopenharmony_ci      {
918195972f6Sopenharmony_ci        err_t err;
919195972f6Sopenharmony_ci        if (!lwip_netconn_is_err_msg(mem, &err)) {
920195972f6Sopenharmony_ci          struct netconn *newconn = (struct netconn *)mem;
921195972f6Sopenharmony_ci          /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
922195972f6Sopenharmony_ci          /* pcb might be set to NULL already by err_tcp() */
923195972f6Sopenharmony_ci          /* drain recvmbox */
924195972f6Sopenharmony_ci          netconn_drain(newconn);
925195972f6Sopenharmony_ci          if (newconn->pcb.tcp != NULL) {
926195972f6Sopenharmony_ci            tcp_abort(newconn->pcb.tcp);
927195972f6Sopenharmony_ci            newconn->pcb.tcp = NULL;
928195972f6Sopenharmony_ci          }
929195972f6Sopenharmony_ci          netconn_free(newconn);
930195972f6Sopenharmony_ci        }
931195972f6Sopenharmony_ci      }
932195972f6Sopenharmony_ci    }
933195972f6Sopenharmony_ci    sys_mbox_free(&conn->acceptmbox);
934195972f6Sopenharmony_ci    sys_mbox_set_invalid(&conn->acceptmbox);
935195972f6Sopenharmony_ci  }
936195972f6Sopenharmony_ci#endif /* LWIP_TCP */
937195972f6Sopenharmony_ci}
938195972f6Sopenharmony_ci
939195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
940195972f6Sopenharmony_cistatic void
941195972f6Sopenharmony_cinetconn_mark_mbox_invalid(struct netconn *conn)
942195972f6Sopenharmony_ci{
943195972f6Sopenharmony_ci  int i, num_waiting;
944195972f6Sopenharmony_ci  void *msg = LWIP_CONST_CAST(void *, &netconn_deleted);
945195972f6Sopenharmony_ci
946195972f6Sopenharmony_ci  /* Prevent new calls/threads from reading from the mbox */
947195972f6Sopenharmony_ci  conn->flags |= NETCONN_FLAG_MBOXINVALID;
948195972f6Sopenharmony_ci
949195972f6Sopenharmony_ci  SYS_ARCH_LOCKED(num_waiting = conn->mbox_threads_waiting);
950195972f6Sopenharmony_ci  for (i = 0; i < num_waiting; i++) {
951195972f6Sopenharmony_ci    if (sys_mbox_valid_val(conn->recvmbox)) {
952195972f6Sopenharmony_ci      sys_mbox_trypost(&conn->recvmbox, msg);
953195972f6Sopenharmony_ci    } else {
954195972f6Sopenharmony_ci      sys_mbox_trypost(&conn->acceptmbox, msg);
955195972f6Sopenharmony_ci    }
956195972f6Sopenharmony_ci  }
957195972f6Sopenharmony_ci}
958195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
959195972f6Sopenharmony_ci
960195972f6Sopenharmony_ci#if LWIP_TCP
961195972f6Sopenharmony_ci/**
962195972f6Sopenharmony_ci * Internal helper function to close a TCP netconn: since this sometimes
963195972f6Sopenharmony_ci * doesn't work at the first attempt, this function is called from multiple
964195972f6Sopenharmony_ci * places.
965195972f6Sopenharmony_ci *
966195972f6Sopenharmony_ci * @param conn the TCP netconn to close
967195972f6Sopenharmony_ci */
968195972f6Sopenharmony_cistatic err_t
969195972f6Sopenharmony_cilwip_netconn_do_close_internal(struct netconn *conn  WRITE_DELAYED_PARAM)
970195972f6Sopenharmony_ci{
971195972f6Sopenharmony_ci  err_t err;
972195972f6Sopenharmony_ci  u8_t shut, shut_rx, shut_tx, shut_close;
973195972f6Sopenharmony_ci  u8_t close_finished = 0;
974195972f6Sopenharmony_ci  struct tcp_pcb *tpcb;
975195972f6Sopenharmony_ci#if LWIP_SO_LINGER
976195972f6Sopenharmony_ci  u8_t linger_wait_required = 0;
977195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */
978195972f6Sopenharmony_ci
979195972f6Sopenharmony_ci  LWIP_ASSERT("invalid conn", (conn != NULL));
980195972f6Sopenharmony_ci  LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
981195972f6Sopenharmony_ci  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
982195972f6Sopenharmony_ci  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
983195972f6Sopenharmony_ci  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
984195972f6Sopenharmony_ci
985195972f6Sopenharmony_ci  tpcb = conn->pcb.tcp;
986195972f6Sopenharmony_ci  shut = conn->current_msg->msg.sd.shut;
987195972f6Sopenharmony_ci  shut_rx = shut & NETCONN_SHUT_RD;
988195972f6Sopenharmony_ci  shut_tx = shut & NETCONN_SHUT_WR;
989195972f6Sopenharmony_ci  /* shutting down both ends is the same as closing
990195972f6Sopenharmony_ci     (also if RD or WR side was shut down before already) */
991195972f6Sopenharmony_ci  if (shut == NETCONN_SHUT_RDWR) {
992195972f6Sopenharmony_ci    shut_close = 1;
993195972f6Sopenharmony_ci  } else if (shut_rx &&
994195972f6Sopenharmony_ci             ((tpcb->state == FIN_WAIT_1) ||
995195972f6Sopenharmony_ci              (tpcb->state == FIN_WAIT_2) ||
996195972f6Sopenharmony_ci              (tpcb->state == CLOSING))) {
997195972f6Sopenharmony_ci    shut_close = 1;
998195972f6Sopenharmony_ci  } else if (shut_tx && ((tpcb->flags & TF_RXCLOSED) != 0)) {
999195972f6Sopenharmony_ci    shut_close = 1;
1000195972f6Sopenharmony_ci  } else {
1001195972f6Sopenharmony_ci    shut_close = 0;
1002195972f6Sopenharmony_ci  }
1003195972f6Sopenharmony_ci
1004195972f6Sopenharmony_ci  /* Set back some callback pointers */
1005195972f6Sopenharmony_ci  if (shut_close) {
1006195972f6Sopenharmony_ci    tcp_arg(tpcb, NULL);
1007195972f6Sopenharmony_ci  }
1008195972f6Sopenharmony_ci  if (tpcb->state == LISTEN) {
1009195972f6Sopenharmony_ci    tcp_accept(tpcb, NULL);
1010195972f6Sopenharmony_ci  } else {
1011195972f6Sopenharmony_ci    /* some callbacks have to be reset if tcp_close is not successful */
1012195972f6Sopenharmony_ci    if (shut_rx) {
1013195972f6Sopenharmony_ci      tcp_recv(tpcb, NULL);
1014195972f6Sopenharmony_ci      tcp_accept(tpcb, NULL);
1015195972f6Sopenharmony_ci    }
1016195972f6Sopenharmony_ci    if (shut_tx) {
1017195972f6Sopenharmony_ci      tcp_sent(tpcb, NULL);
1018195972f6Sopenharmony_ci    }
1019195972f6Sopenharmony_ci    if (shut_close) {
1020195972f6Sopenharmony_ci      tcp_poll(tpcb, NULL, 0);
1021195972f6Sopenharmony_ci      tcp_err(tpcb, NULL);
1022195972f6Sopenharmony_ci    }
1023195972f6Sopenharmony_ci  }
1024195972f6Sopenharmony_ci  /* Try to close the connection */
1025195972f6Sopenharmony_ci  if (shut_close) {
1026195972f6Sopenharmony_ci#if LWIP_SO_LINGER
1027195972f6Sopenharmony_ci    /* check linger possibilites before calling tcp_close */
1028195972f6Sopenharmony_ci    err = ERR_OK;
1029195972f6Sopenharmony_ci    /* linger enabled/required at all? (i.e. is there untransmitted data left?) */
1030195972f6Sopenharmony_ci    if ((conn->linger >= 0) && (conn->pcb.tcp->unsent || conn->pcb.tcp->unacked)) {
1031195972f6Sopenharmony_ci      if ((conn->linger == 0)) {
1032195972f6Sopenharmony_ci        /* data left but linger prevents waiting */
1033195972f6Sopenharmony_ci        tcp_abort(tpcb);
1034195972f6Sopenharmony_ci        tpcb = NULL;
1035195972f6Sopenharmony_ci      } else if (conn->linger > 0) {
1036195972f6Sopenharmony_ci        /* data left and linger says we should wait */
1037195972f6Sopenharmony_ci        if (netconn_is_nonblocking(conn)) {
1038195972f6Sopenharmony_ci          /* data left on a nonblocking netconn -> cannot linger */
1039195972f6Sopenharmony_ci          err = ERR_WOULDBLOCK;
1040195972f6Sopenharmony_ci        } else if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >=
1041195972f6Sopenharmony_ci                   (conn->linger * 1000)) {
1042195972f6Sopenharmony_ci          /* data left but linger timeout has expired (this happens on further
1043195972f6Sopenharmony_ci             calls to this function through poll_tcp */
1044195972f6Sopenharmony_ci          tcp_abort(tpcb);
1045195972f6Sopenharmony_ci          tpcb = NULL;
1046195972f6Sopenharmony_ci        } else {
1047195972f6Sopenharmony_ci          /* data left -> need to wait for ACK after successful close */
1048195972f6Sopenharmony_ci          linger_wait_required = 1;
1049195972f6Sopenharmony_ci        }
1050195972f6Sopenharmony_ci      }
1051195972f6Sopenharmony_ci    }
1052195972f6Sopenharmony_ci    if ((err == ERR_OK) && (tpcb != NULL))
1053195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */
1054195972f6Sopenharmony_ci    {
1055195972f6Sopenharmony_ci      err = tcp_close(tpcb);
1056195972f6Sopenharmony_ci    }
1057195972f6Sopenharmony_ci  } else {
1058195972f6Sopenharmony_ci    err = tcp_shutdown(tpcb, shut_rx, shut_tx);
1059195972f6Sopenharmony_ci  }
1060195972f6Sopenharmony_ci  if (err == ERR_OK) {
1061195972f6Sopenharmony_ci    close_finished = 1;
1062195972f6Sopenharmony_ci#if LWIP_SO_LINGER
1063195972f6Sopenharmony_ci    if (linger_wait_required) {
1064195972f6Sopenharmony_ci      /* wait for ACK of all unsent/unacked data by just getting called again */
1065195972f6Sopenharmony_ci      close_finished = 0;
1066195972f6Sopenharmony_ci      err = ERR_INPROGRESS;
1067195972f6Sopenharmony_ci    }
1068195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */
1069195972f6Sopenharmony_ci  } else {
1070195972f6Sopenharmony_ci    if (err == ERR_MEM) {
1071195972f6Sopenharmony_ci      /* Closing failed because of memory shortage, try again later. Even for
1072195972f6Sopenharmony_ci         nonblocking netconns, we have to wait since no standard socket application
1073195972f6Sopenharmony_ci         is prepared for close failing because of resource shortage.
1074195972f6Sopenharmony_ci         Check the timeout: this is kind of an lwip addition to the standard sockets:
1075195972f6Sopenharmony_ci         we wait for some time when failing to allocate a segment for the FIN */
1076195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1077195972f6Sopenharmony_ci      s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
1078195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO
1079195972f6Sopenharmony_ci      if (conn->send_timeout > 0) {
1080195972f6Sopenharmony_ci        close_timeout = conn->send_timeout;
1081195972f6Sopenharmony_ci      }
1082195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */
1083195972f6Sopenharmony_ci#if LWIP_SO_LINGER
1084195972f6Sopenharmony_ci      if (conn->linger >= 0) {
1085195972f6Sopenharmony_ci        /* use linger timeout (seconds) */
1086195972f6Sopenharmony_ci        close_timeout = conn->linger * 1000U;
1087195972f6Sopenharmony_ci      }
1088195972f6Sopenharmony_ci#endif
1089195972f6Sopenharmony_ci      if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
1090195972f6Sopenharmony_ci#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1091195972f6Sopenharmony_ci      if (conn->current_msg->msg.sd.polls_left == 0) {
1092195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1093195972f6Sopenharmony_ci        close_finished = 1;
1094195972f6Sopenharmony_ci        if (shut_close) {
1095195972f6Sopenharmony_ci          /* in this case, we want to RST the connection */
1096195972f6Sopenharmony_ci          tcp_abort(tpcb);
1097195972f6Sopenharmony_ci          err = ERR_OK;
1098195972f6Sopenharmony_ci        }
1099195972f6Sopenharmony_ci      }
1100195972f6Sopenharmony_ci    } else {
1101195972f6Sopenharmony_ci      /* Closing failed for a non-memory error: give up */
1102195972f6Sopenharmony_ci      close_finished = 1;
1103195972f6Sopenharmony_ci    }
1104195972f6Sopenharmony_ci  }
1105195972f6Sopenharmony_ci  if (close_finished) {
1106195972f6Sopenharmony_ci    /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */
1107195972f6Sopenharmony_ci    sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1108195972f6Sopenharmony_ci    conn->current_msg->err = err;
1109195972f6Sopenharmony_ci    conn->current_msg = NULL;
1110195972f6Sopenharmony_ci    conn->state = NETCONN_NONE;
1111195972f6Sopenharmony_ci    if (err == ERR_OK) {
1112195972f6Sopenharmony_ci      if (shut_close) {
1113195972f6Sopenharmony_ci        /* Set back some callback pointers as conn is going away */
1114195972f6Sopenharmony_ci        conn->pcb.tcp = NULL;
1115195972f6Sopenharmony_ci        /* Trigger select() in socket layer. Make sure everybody notices activity
1116195972f6Sopenharmony_ci         on the connection, error first! */
1117195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_ERROR, 0);
1118195972f6Sopenharmony_ci      }
1119195972f6Sopenharmony_ci      if (shut_rx) {
1120195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
1121195972f6Sopenharmony_ci      }
1122195972f6Sopenharmony_ci      if (shut_tx) {
1123195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1124195972f6Sopenharmony_ci      }
1125195972f6Sopenharmony_ci    }
1126195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1127195972f6Sopenharmony_ci    if (delayed)
1128195972f6Sopenharmony_ci#endif
1129195972f6Sopenharmony_ci    {
1130195972f6Sopenharmony_ci      /* wake up the application task */
1131195972f6Sopenharmony_ci      sys_sem_signal(op_completed_sem);
1132195972f6Sopenharmony_ci    }
1133195972f6Sopenharmony_ci    return ERR_OK;
1134195972f6Sopenharmony_ci  }
1135195972f6Sopenharmony_ci  if (!close_finished) {
1136195972f6Sopenharmony_ci    /* Closing failed and we want to wait: restore some of the callbacks */
1137195972f6Sopenharmony_ci    /* Closing of listen pcb will never fail! */
1138195972f6Sopenharmony_ci    LWIP_ASSERT("Closing a listen pcb may not fail!", (tpcb->state != LISTEN));
1139195972f6Sopenharmony_ci    if (shut_tx) {
1140195972f6Sopenharmony_ci      tcp_sent(tpcb, sent_tcp);
1141195972f6Sopenharmony_ci    }
1142195972f6Sopenharmony_ci    /* when waiting for close, set up poll interval to 500ms */
1143195972f6Sopenharmony_ci    tcp_poll(tpcb, poll_tcp, 1);
1144195972f6Sopenharmony_ci    tcp_err(tpcb, err_tcp);
1145195972f6Sopenharmony_ci    tcp_arg(tpcb, conn);
1146195972f6Sopenharmony_ci    /* don't restore recv callback: we don't want to receive any more data */
1147195972f6Sopenharmony_ci  }
1148195972f6Sopenharmony_ci  /* If closing didn't succeed, we get called again either
1149195972f6Sopenharmony_ci     from poll_tcp or from sent_tcp */
1150195972f6Sopenharmony_ci  LWIP_ASSERT("err != ERR_OK", err != ERR_OK);
1151195972f6Sopenharmony_ci  return err;
1152195972f6Sopenharmony_ci}
1153195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1154195972f6Sopenharmony_ci
1155195972f6Sopenharmony_ci/**
1156195972f6Sopenharmony_ci * Delete the pcb inside a netconn.
1157195972f6Sopenharmony_ci * Called from netconn_delete.
1158195972f6Sopenharmony_ci *
1159195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1160195972f6Sopenharmony_ci */
1161195972f6Sopenharmony_civoid
1162195972f6Sopenharmony_cilwip_netconn_do_delconn(void *m)
1163195972f6Sopenharmony_ci{
1164195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1165195972f6Sopenharmony_ci
1166195972f6Sopenharmony_ci  enum netconn_state state = msg->conn->state;
1167195972f6Sopenharmony_ci  LWIP_ASSERT("netconn state error", /* this only happens for TCP netconns */
1168195972f6Sopenharmony_ci              (state == NETCONN_NONE) || (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP));
1169195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
1170195972f6Sopenharmony_ci  /* In full duplex mode, blocking write/connect is aborted with ERR_CLSD */
1171195972f6Sopenharmony_ci  if (state != NETCONN_NONE) {
1172195972f6Sopenharmony_ci    if ((state == NETCONN_WRITE) ||
1173195972f6Sopenharmony_ci        ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1174195972f6Sopenharmony_ci      /* close requested, abort running write/connect */
1175195972f6Sopenharmony_ci      sys_sem_t *op_completed_sem;
1176195972f6Sopenharmony_ci      LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
1177195972f6Sopenharmony_ci      op_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
1178195972f6Sopenharmony_ci      msg->conn->current_msg->err = ERR_CLSD;
1179195972f6Sopenharmony_ci      msg->conn->current_msg = NULL;
1180195972f6Sopenharmony_ci      msg->conn->state = NETCONN_NONE;
1181195972f6Sopenharmony_ci      sys_sem_signal(op_completed_sem);
1182195972f6Sopenharmony_ci    }
1183195972f6Sopenharmony_ci  }
1184195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */
1185195972f6Sopenharmony_ci  if (((state != NETCONN_NONE) &&
1186195972f6Sopenharmony_ci       (state != NETCONN_LISTEN) &&
1187195972f6Sopenharmony_ci       (state != NETCONN_CONNECT)) ||
1188195972f6Sopenharmony_ci      ((state == NETCONN_CONNECT) && !IN_NONBLOCKING_CONNECT(msg->conn))) {
1189195972f6Sopenharmony_ci    /* This means either a blocking write or blocking connect is running
1190195972f6Sopenharmony_ci       (nonblocking write returns and sets state to NONE) */
1191195972f6Sopenharmony_ci    msg->err = ERR_INPROGRESS;
1192195972f6Sopenharmony_ci  } else
1193195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
1194195972f6Sopenharmony_ci  {
1195195972f6Sopenharmony_ci    LWIP_ASSERT("blocking connect in progress",
1196195972f6Sopenharmony_ci                (state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
1197195972f6Sopenharmony_ci    msg->err = ERR_OK;
1198195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
1199195972f6Sopenharmony_ci    /* Mark mboxes invalid */
1200195972f6Sopenharmony_ci    netconn_mark_mbox_invalid(msg->conn);
1201195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */
1202195972f6Sopenharmony_ci    netconn_drain(msg->conn);
1203195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
1204195972f6Sopenharmony_ci
1205195972f6Sopenharmony_ci    if (msg->conn->pcb.tcp != NULL) {
1206195972f6Sopenharmony_ci
1207195972f6Sopenharmony_ci      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1208195972f6Sopenharmony_ci#if LWIP_RAW
1209195972f6Sopenharmony_ci        case NETCONN_RAW:
1210195972f6Sopenharmony_ci          raw_remove(msg->conn->pcb.raw);
1211195972f6Sopenharmony_ci          break;
1212195972f6Sopenharmony_ci#endif /* LWIP_RAW */
1213195972f6Sopenharmony_ci#if LWIP_UDP
1214195972f6Sopenharmony_ci        case NETCONN_UDP:
1215195972f6Sopenharmony_ci          msg->conn->pcb.udp->recv_arg = NULL;
1216195972f6Sopenharmony_ci          udp_remove(msg->conn->pcb.udp);
1217195972f6Sopenharmony_ci          break;
1218195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1219195972f6Sopenharmony_ci#if LWIP_TCP
1220195972f6Sopenharmony_ci        case NETCONN_TCP:
1221195972f6Sopenharmony_ci          LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1222195972f6Sopenharmony_ci          msg->conn->state = NETCONN_CLOSE;
1223195972f6Sopenharmony_ci          msg->msg.sd.shut = NETCONN_SHUT_RDWR;
1224195972f6Sopenharmony_ci          msg->conn->current_msg = msg;
1225195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1226195972f6Sopenharmony_ci          if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
1227195972f6Sopenharmony_ci            LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
1228195972f6Sopenharmony_ci            UNLOCK_TCPIP_CORE();
1229195972f6Sopenharmony_ci            sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1230195972f6Sopenharmony_ci            LOCK_TCPIP_CORE();
1231195972f6Sopenharmony_ci            LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
1232195972f6Sopenharmony_ci          }
1233195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
1234195972f6Sopenharmony_ci          lwip_netconn_do_close_internal(msg->conn);
1235195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
1236195972f6Sopenharmony_ci          /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing
1237195972f6Sopenharmony_ci             the application thread, so we can return at this point! */
1238195972f6Sopenharmony_ci          return;
1239195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1240195972f6Sopenharmony_ci        default:
1241195972f6Sopenharmony_ci          break;
1242195972f6Sopenharmony_ci      }
1243195972f6Sopenharmony_ci      msg->conn->pcb.tcp = NULL;
1244195972f6Sopenharmony_ci    }
1245195972f6Sopenharmony_ci    /* tcp netconns don't come here! */
1246195972f6Sopenharmony_ci
1247195972f6Sopenharmony_ci    /* @todo: this lets select make the socket readable and writable,
1248195972f6Sopenharmony_ci       which is wrong! errfd instead? */
1249195972f6Sopenharmony_ci    API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
1250195972f6Sopenharmony_ci    API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
1251195972f6Sopenharmony_ci  }
1252195972f6Sopenharmony_ci  if (sys_sem_valid(LWIP_API_MSG_SEM(msg))) {
1253195972f6Sopenharmony_ci    TCPIP_APIMSG_ACK(msg);
1254195972f6Sopenharmony_ci  }
1255195972f6Sopenharmony_ci}
1256195972f6Sopenharmony_ci
1257195972f6Sopenharmony_ci/**
1258195972f6Sopenharmony_ci * Bind a pcb contained in a netconn
1259195972f6Sopenharmony_ci * Called from netconn_bind.
1260195972f6Sopenharmony_ci *
1261195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing
1262195972f6Sopenharmony_ci *          the IP address and port to bind to
1263195972f6Sopenharmony_ci */
1264195972f6Sopenharmony_civoid
1265195972f6Sopenharmony_cilwip_netconn_do_bind(void *m)
1266195972f6Sopenharmony_ci{
1267195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1268195972f6Sopenharmony_ci  err_t err;
1269195972f6Sopenharmony_ci
1270195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
1271195972f6Sopenharmony_ci    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1272195972f6Sopenharmony_ci#if LWIP_RAW
1273195972f6Sopenharmony_ci      case NETCONN_RAW:
1274195972f6Sopenharmony_ci        err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1275195972f6Sopenharmony_ci        break;
1276195972f6Sopenharmony_ci#endif /* LWIP_RAW */
1277195972f6Sopenharmony_ci#if LWIP_UDP
1278195972f6Sopenharmony_ci      case NETCONN_UDP:
1279195972f6Sopenharmony_ci        err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1280195972f6Sopenharmony_ci        break;
1281195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1282195972f6Sopenharmony_ci#if LWIP_TCP
1283195972f6Sopenharmony_ci      case NETCONN_TCP:
1284195972f6Sopenharmony_ci        err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1285195972f6Sopenharmony_ci        break;
1286195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1287195972f6Sopenharmony_ci      default:
1288195972f6Sopenharmony_ci        err = ERR_VAL;
1289195972f6Sopenharmony_ci        break;
1290195972f6Sopenharmony_ci    }
1291195972f6Sopenharmony_ci  } else {
1292195972f6Sopenharmony_ci    err = ERR_VAL;
1293195972f6Sopenharmony_ci  }
1294195972f6Sopenharmony_ci  msg->err = err;
1295195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1296195972f6Sopenharmony_ci}
1297195972f6Sopenharmony_ci
1298195972f6Sopenharmony_ci/**
1299195972f6Sopenharmony_ci * Bind a pcb contained in a netconn to an interface
1300195972f6Sopenharmony_ci * Called from netconn_bind_if.
1301195972f6Sopenharmony_ci *
1302195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing
1303195972f6Sopenharmony_ci *          the IP address and port to bind to
1304195972f6Sopenharmony_ci */
1305195972f6Sopenharmony_civoid
1306195972f6Sopenharmony_cilwip_netconn_do_bind_if(void *m)
1307195972f6Sopenharmony_ci{
1308195972f6Sopenharmony_ci  struct netif *netif;
1309195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1310195972f6Sopenharmony_ci  err_t err;
1311195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
1312195972f6Sopenharmony_ci  struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip);
1313195972f6Sopenharmony_ci
1314195972f6Sopenharmony_ci  if (group != NULL) {
1315195972f6Sopenharmony_ci    netif = netif_get_by_index(msg->msg.bc.if_idx, group);
1316195972f6Sopenharmony_ci  } else {
1317195972f6Sopenharmony_ci    netif = NULL;
1318195972f6Sopenharmony_ci  }
1319195972f6Sopenharmony_ci#else
1320195972f6Sopenharmony_ci  netif = netif_get_by_index(msg->msg.bc.if_idx);
1321195972f6Sopenharmony_ci#endif
1322195972f6Sopenharmony_ci
1323195972f6Sopenharmony_ci  if ((netif != NULL) && (msg->conn->pcb.tcp != NULL)) {
1324195972f6Sopenharmony_ci    err = ERR_OK;
1325195972f6Sopenharmony_ci    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1326195972f6Sopenharmony_ci#if LWIP_RAW
1327195972f6Sopenharmony_ci      case NETCONN_RAW:
1328195972f6Sopenharmony_ci        raw_bind_netif(msg->conn->pcb.raw, netif);
1329195972f6Sopenharmony_ci        break;
1330195972f6Sopenharmony_ci#endif /* LWIP_RAW */
1331195972f6Sopenharmony_ci#if LWIP_UDP
1332195972f6Sopenharmony_ci      case NETCONN_UDP:
1333195972f6Sopenharmony_ci        udp_bind_netif(msg->conn->pcb.udp, netif);
1334195972f6Sopenharmony_ci        break;
1335195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1336195972f6Sopenharmony_ci#if LWIP_TCP
1337195972f6Sopenharmony_ci      case NETCONN_TCP:
1338195972f6Sopenharmony_ci        tcp_bind_netif(msg->conn->pcb.tcp, netif);
1339195972f6Sopenharmony_ci        break;
1340195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1341195972f6Sopenharmony_ci      default:
1342195972f6Sopenharmony_ci        err = ERR_VAL;
1343195972f6Sopenharmony_ci        break;
1344195972f6Sopenharmony_ci    }
1345195972f6Sopenharmony_ci  } else {
1346195972f6Sopenharmony_ci    err = ERR_VAL;
1347195972f6Sopenharmony_ci  }
1348195972f6Sopenharmony_ci  msg->err = err;
1349195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1350195972f6Sopenharmony_ci}
1351195972f6Sopenharmony_ci
1352195972f6Sopenharmony_ci#if LWIP_TCP
1353195972f6Sopenharmony_ci/**
1354195972f6Sopenharmony_ci * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has
1355195972f6Sopenharmony_ci * been established (or reset by the remote host).
1356195972f6Sopenharmony_ci *
1357195972f6Sopenharmony_ci * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
1358195972f6Sopenharmony_ci */
1359195972f6Sopenharmony_cistatic err_t
1360195972f6Sopenharmony_cilwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
1361195972f6Sopenharmony_ci{
1362195972f6Sopenharmony_ci  struct netconn *conn;
1363195972f6Sopenharmony_ci  int was_blocking;
1364195972f6Sopenharmony_ci  sys_sem_t *op_completed_sem = NULL;
1365195972f6Sopenharmony_ci
1366195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(pcb);
1367195972f6Sopenharmony_ci
1368195972f6Sopenharmony_ci  conn = (struct netconn *)arg;
1369195972f6Sopenharmony_ci
1370195972f6Sopenharmony_ci  if (conn == NULL) {
1371195972f6Sopenharmony_ci    return ERR_VAL;
1372195972f6Sopenharmony_ci  }
1373195972f6Sopenharmony_ci
1374195972f6Sopenharmony_ci  LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
1375195972f6Sopenharmony_ci  LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
1376195972f6Sopenharmony_ci              (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
1377195972f6Sopenharmony_ci
1378195972f6Sopenharmony_ci  if (conn->current_msg != NULL) {
1379195972f6Sopenharmony_ci    conn->current_msg->err = err;
1380195972f6Sopenharmony_ci    op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1381195972f6Sopenharmony_ci  }
1382195972f6Sopenharmony_ci  if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
1383195972f6Sopenharmony_ci    setup_tcp(conn);
1384195972f6Sopenharmony_ci  }
1385195972f6Sopenharmony_ci  was_blocking = !IN_NONBLOCKING_CONNECT(conn);
1386195972f6Sopenharmony_ci  SET_NONBLOCKING_CONNECT(conn, 0);
1387195972f6Sopenharmony_ci  LWIP_ASSERT("blocking connect state error",
1388195972f6Sopenharmony_ci              (was_blocking && op_completed_sem != NULL) ||
1389195972f6Sopenharmony_ci              (!was_blocking && op_completed_sem == NULL));
1390195972f6Sopenharmony_ci  conn->current_msg = NULL;
1391195972f6Sopenharmony_ci  conn->state = NETCONN_NONE;
1392195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
1393195972f6Sopenharmony_ci
1394195972f6Sopenharmony_ci  if (was_blocking) {
1395195972f6Sopenharmony_ci    sys_sem_signal(op_completed_sem);
1396195972f6Sopenharmony_ci  }
1397195972f6Sopenharmony_ci  return ERR_OK;
1398195972f6Sopenharmony_ci}
1399195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1400195972f6Sopenharmony_ci
1401195972f6Sopenharmony_ci/**
1402195972f6Sopenharmony_ci * Connect a pcb contained inside a netconn
1403195972f6Sopenharmony_ci * Called from netconn_connect.
1404195972f6Sopenharmony_ci *
1405195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection and containing
1406195972f6Sopenharmony_ci *          the IP address and port to connect to
1407195972f6Sopenharmony_ci */
1408195972f6Sopenharmony_civoid
1409195972f6Sopenharmony_cilwip_netconn_do_connect(void *m)
1410195972f6Sopenharmony_ci{
1411195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1412195972f6Sopenharmony_ci  err_t err;
1413195972f6Sopenharmony_ci
1414195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp == NULL) {
1415195972f6Sopenharmony_ci    /* This may happen when calling netconn_connect() a second time */
1416195972f6Sopenharmony_ci    err = ERR_CLSD;
1417195972f6Sopenharmony_ci  } else {
1418195972f6Sopenharmony_ci    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1419195972f6Sopenharmony_ci#if LWIP_RAW
1420195972f6Sopenharmony_ci      case NETCONN_RAW:
1421195972f6Sopenharmony_ci        err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr));
1422195972f6Sopenharmony_ci        break;
1423195972f6Sopenharmony_ci#endif /* LWIP_RAW */
1424195972f6Sopenharmony_ci#if LWIP_UDP
1425195972f6Sopenharmony_ci      case NETCONN_UDP:
1426195972f6Sopenharmony_ci        err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port);
1427195972f6Sopenharmony_ci        break;
1428195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1429195972f6Sopenharmony_ci#if LWIP_TCP
1430195972f6Sopenharmony_ci      case NETCONN_TCP:
1431195972f6Sopenharmony_ci        /* Prevent connect while doing any other action. */
1432195972f6Sopenharmony_ci        if (msg->conn->state == NETCONN_CONNECT) {
1433195972f6Sopenharmony_ci          err = ERR_ALREADY;
1434195972f6Sopenharmony_ci        } else if (msg->conn->state != NETCONN_NONE) {
1435195972f6Sopenharmony_ci          err = ERR_ISCONN;
1436195972f6Sopenharmony_ci        } else {
1437195972f6Sopenharmony_ci          setup_tcp(msg->conn);
1438195972f6Sopenharmony_ci          err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr),
1439195972f6Sopenharmony_ci                            msg->msg.bc.port, lwip_netconn_do_connected);
1440195972f6Sopenharmony_ci          if (err == ERR_OK) {
1441195972f6Sopenharmony_ci            u8_t non_blocking = netconn_is_nonblocking(msg->conn);
1442195972f6Sopenharmony_ci            msg->conn->state = NETCONN_CONNECT;
1443195972f6Sopenharmony_ci            SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
1444195972f6Sopenharmony_ci            if (non_blocking) {
1445195972f6Sopenharmony_ci              err = ERR_INPROGRESS;
1446195972f6Sopenharmony_ci            } else {
1447195972f6Sopenharmony_ci              msg->conn->current_msg = msg;
1448195972f6Sopenharmony_ci              /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()),
1449195972f6Sopenharmony_ci                 when the connection is established! */
1450195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1451195972f6Sopenharmony_ci              LWIP_ASSERT("state!", msg->conn->state == NETCONN_CONNECT);
1452195972f6Sopenharmony_ci              UNLOCK_TCPIP_CORE();
1453195972f6Sopenharmony_ci              sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1454195972f6Sopenharmony_ci              LOCK_TCPIP_CORE();
1455195972f6Sopenharmony_ci              LWIP_ASSERT("state!", msg->conn->state != NETCONN_CONNECT);
1456195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
1457195972f6Sopenharmony_ci              return;
1458195972f6Sopenharmony_ci            }
1459195972f6Sopenharmony_ci          }
1460195972f6Sopenharmony_ci        }
1461195972f6Sopenharmony_ci        break;
1462195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1463195972f6Sopenharmony_ci      default:
1464195972f6Sopenharmony_ci        LWIP_ERROR("Invalid netconn type", 0, do {
1465195972f6Sopenharmony_ci          err = ERR_VAL;
1466195972f6Sopenharmony_ci        } while (0));
1467195972f6Sopenharmony_ci        break;
1468195972f6Sopenharmony_ci    }
1469195972f6Sopenharmony_ci  }
1470195972f6Sopenharmony_ci  msg->err = err;
1471195972f6Sopenharmony_ci  /* For all other protocols, netconn_connect() calls netconn_apimsg(),
1472195972f6Sopenharmony_ci     so use TCPIP_APIMSG_ACK() here. */
1473195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1474195972f6Sopenharmony_ci}
1475195972f6Sopenharmony_ci
1476195972f6Sopenharmony_ci/**
1477195972f6Sopenharmony_ci * Disconnect a pcb contained inside a netconn
1478195972f6Sopenharmony_ci * Only used for UDP netconns.
1479195972f6Sopenharmony_ci * Called from netconn_disconnect.
1480195972f6Sopenharmony_ci *
1481195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection to disconnect
1482195972f6Sopenharmony_ci */
1483195972f6Sopenharmony_civoid
1484195972f6Sopenharmony_cilwip_netconn_do_disconnect(void *m)
1485195972f6Sopenharmony_ci{
1486195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1487195972f6Sopenharmony_ci
1488195972f6Sopenharmony_ci#if LWIP_UDP
1489195972f6Sopenharmony_ci  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
1490195972f6Sopenharmony_ci    udp_disconnect(msg->conn->pcb.udp);
1491195972f6Sopenharmony_ci    msg->err = ERR_OK;
1492195972f6Sopenharmony_ci  } else
1493195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1494195972f6Sopenharmony_ci  {
1495195972f6Sopenharmony_ci    msg->err = ERR_VAL;
1496195972f6Sopenharmony_ci  }
1497195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1498195972f6Sopenharmony_ci}
1499195972f6Sopenharmony_ci
1500195972f6Sopenharmony_ci#if LWIP_TCP
1501195972f6Sopenharmony_ci/**
1502195972f6Sopenharmony_ci * Set a TCP pcb contained in a netconn into listen mode
1503195972f6Sopenharmony_ci * Called from netconn_listen.
1504195972f6Sopenharmony_ci *
1505195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1506195972f6Sopenharmony_ci */
1507195972f6Sopenharmony_civoid
1508195972f6Sopenharmony_cilwip_netconn_do_listen(void *m)
1509195972f6Sopenharmony_ci{
1510195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1511195972f6Sopenharmony_ci  err_t err;
1512195972f6Sopenharmony_ci
1513195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
1514195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1515195972f6Sopenharmony_ci      if (msg->conn->state == NETCONN_NONE) {
1516195972f6Sopenharmony_ci        struct tcp_pcb *lpcb;
1517195972f6Sopenharmony_ci        if (msg->conn->pcb.tcp->state != CLOSED) {
1518195972f6Sopenharmony_ci          /* connection is not closed, cannot listen */
1519195972f6Sopenharmony_ci          err = ERR_VAL;
1520195972f6Sopenharmony_ci        } else {
1521195972f6Sopenharmony_ci          u8_t backlog;
1522195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
1523195972f6Sopenharmony_ci          backlog = msg->msg.lb.backlog;
1524195972f6Sopenharmony_ci#else  /* TCP_LISTEN_BACKLOG */
1525195972f6Sopenharmony_ci          backlog = TCP_DEFAULT_LISTEN_BACKLOG;
1526195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
1527195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
1528195972f6Sopenharmony_ci          /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
1529195972f6Sopenharmony_ci            * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
1530195972f6Sopenharmony_ci            */
1531195972f6Sopenharmony_ci          if (ip_addr_cmp(&msg->conn->pcb.ip->local_ip, IP6_ADDR_ANY) &&
1532195972f6Sopenharmony_ci              (netconn_get_ipv6only(msg->conn) == 0)) {
1533195972f6Sopenharmony_ci            /* change PCB type to IPADDR_TYPE_ANY */
1534195972f6Sopenharmony_ci            IP_SET_TYPE_VAL(msg->conn->pcb.tcp->local_ip,  IPADDR_TYPE_ANY);
1535195972f6Sopenharmony_ci            IP_SET_TYPE_VAL(msg->conn->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
1536195972f6Sopenharmony_ci          }
1537195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */
1538195972f6Sopenharmony_ci
1539195972f6Sopenharmony_ci          lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
1540195972f6Sopenharmony_ci
1541195972f6Sopenharmony_ci          if (lpcb == NULL) {
1542195972f6Sopenharmony_ci            /* in this case, the old pcb is still allocated */
1543195972f6Sopenharmony_ci          } else {
1544195972f6Sopenharmony_ci            /* delete the recvmbox and allocate the acceptmbox */
1545195972f6Sopenharmony_ci            if (sys_mbox_valid(&msg->conn->recvmbox)) {
1546195972f6Sopenharmony_ci              /** @todo: should we drain the recvmbox here? */
1547195972f6Sopenharmony_ci              sys_mbox_free(&msg->conn->recvmbox);
1548195972f6Sopenharmony_ci              sys_mbox_set_invalid(&msg->conn->recvmbox);
1549195972f6Sopenharmony_ci            }
1550195972f6Sopenharmony_ci            err = ERR_OK;
1551195972f6Sopenharmony_ci            if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
1552195972f6Sopenharmony_ci              err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
1553195972f6Sopenharmony_ci            }
1554195972f6Sopenharmony_ci            if (err == ERR_OK) {
1555195972f6Sopenharmony_ci              msg->conn->state = NETCONN_LISTEN;
1556195972f6Sopenharmony_ci              msg->conn->pcb.tcp = lpcb;
1557195972f6Sopenharmony_ci              tcp_arg(msg->conn->pcb.tcp, msg->conn);
1558195972f6Sopenharmony_ci              tcp_accept(msg->conn->pcb.tcp, accept_function);
1559195972f6Sopenharmony_ci            } else {
1560195972f6Sopenharmony_ci              /* since the old pcb is already deallocated, free lpcb now */
1561195972f6Sopenharmony_ci              tcp_close(lpcb);
1562195972f6Sopenharmony_ci              msg->conn->pcb.tcp = NULL;
1563195972f6Sopenharmony_ci            }
1564195972f6Sopenharmony_ci          }
1565195972f6Sopenharmony_ci        }
1566195972f6Sopenharmony_ci      } else if (msg->conn->state == NETCONN_LISTEN) {
1567195972f6Sopenharmony_ci        /* already listening, allow updating of the backlog */
1568195972f6Sopenharmony_ci        err = ERR_OK;
1569195972f6Sopenharmony_ci        tcp_backlog_set(msg->conn->pcb.tcp, msg->msg.lb.backlog);
1570195972f6Sopenharmony_ci      } else {
1571195972f6Sopenharmony_ci        err = ERR_CONN;
1572195972f6Sopenharmony_ci      }
1573195972f6Sopenharmony_ci    } else {
1574195972f6Sopenharmony_ci      err = ERR_ARG;
1575195972f6Sopenharmony_ci    }
1576195972f6Sopenharmony_ci  } else {
1577195972f6Sopenharmony_ci    err = ERR_CONN;
1578195972f6Sopenharmony_ci  }
1579195972f6Sopenharmony_ci  msg->err = err;
1580195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1581195972f6Sopenharmony_ci}
1582195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1583195972f6Sopenharmony_ci
1584195972f6Sopenharmony_ci/**
1585195972f6Sopenharmony_ci * Send some data on a RAW or UDP pcb contained in a netconn
1586195972f6Sopenharmony_ci * Called from netconn_send
1587195972f6Sopenharmony_ci *
1588195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1589195972f6Sopenharmony_ci */
1590195972f6Sopenharmony_civoid
1591195972f6Sopenharmony_cilwip_netconn_do_send(void *m)
1592195972f6Sopenharmony_ci{
1593195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1594195972f6Sopenharmony_ci
1595195972f6Sopenharmony_ci  err_t err = netconn_err(msg->conn);
1596195972f6Sopenharmony_ci  if (err == ERR_OK) {
1597195972f6Sopenharmony_ci    if (msg->conn->pcb.tcp != NULL) {
1598195972f6Sopenharmony_ci      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1599195972f6Sopenharmony_ci#if LWIP_RAW
1600195972f6Sopenharmony_ci        case NETCONN_RAW:
1601195972f6Sopenharmony_ci          if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1602195972f6Sopenharmony_ci            err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
1603195972f6Sopenharmony_ci          } else {
1604195972f6Sopenharmony_ci            err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
1605195972f6Sopenharmony_ci          }
1606195972f6Sopenharmony_ci          break;
1607195972f6Sopenharmony_ci#endif
1608195972f6Sopenharmony_ci#if LWIP_UDP
1609195972f6Sopenharmony_ci        case NETCONN_UDP:
1610195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY
1611195972f6Sopenharmony_ci          if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1612195972f6Sopenharmony_ci            err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1613195972f6Sopenharmony_ci                                  msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1614195972f6Sopenharmony_ci          } else {
1615195972f6Sopenharmony_ci            err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
1616195972f6Sopenharmony_ci                                    &msg->msg.b->addr, msg->msg.b->port,
1617195972f6Sopenharmony_ci                                    msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
1618195972f6Sopenharmony_ci          }
1619195972f6Sopenharmony_ci#else /* LWIP_CHECKSUM_ON_COPY */
1620195972f6Sopenharmony_ci          if (ip_addr_isany_val(msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
1621195972f6Sopenharmony_ci            err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
1622195972f6Sopenharmony_ci          } else {
1623195972f6Sopenharmony_ci            err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
1624195972f6Sopenharmony_ci          }
1625195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */
1626195972f6Sopenharmony_ci          break;
1627195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1628195972f6Sopenharmony_ci        default:
1629195972f6Sopenharmony_ci          err = ERR_CONN;
1630195972f6Sopenharmony_ci          break;
1631195972f6Sopenharmony_ci      }
1632195972f6Sopenharmony_ci    } else {
1633195972f6Sopenharmony_ci      err = ERR_CONN;
1634195972f6Sopenharmony_ci    }
1635195972f6Sopenharmony_ci  }
1636195972f6Sopenharmony_ci  msg->err = err;
1637195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1638195972f6Sopenharmony_ci}
1639195972f6Sopenharmony_ci
1640195972f6Sopenharmony_ci#if LWIP_TCP
1641195972f6Sopenharmony_ci/**
1642195972f6Sopenharmony_ci * Indicate data has been received from a TCP pcb contained in a netconn
1643195972f6Sopenharmony_ci * Called from netconn_recv
1644195972f6Sopenharmony_ci *
1645195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1646195972f6Sopenharmony_ci */
1647195972f6Sopenharmony_civoid
1648195972f6Sopenharmony_cilwip_netconn_do_recv(void *m)
1649195972f6Sopenharmony_ci{
1650195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1651195972f6Sopenharmony_ci
1652195972f6Sopenharmony_ci  msg->err = ERR_OK;
1653195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
1654195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1655195972f6Sopenharmony_ci      size_t remaining = msg->msg.r.len;
1656195972f6Sopenharmony_ci      do {
1657195972f6Sopenharmony_ci        u16_t recved = (u16_t)((remaining > 0xffff) ? 0xffff : remaining);
1658195972f6Sopenharmony_ci        tcp_recved(msg->conn->pcb.tcp, recved);
1659195972f6Sopenharmony_ci        remaining -= recved;
1660195972f6Sopenharmony_ci      } while (remaining != 0);
1661195972f6Sopenharmony_ci    }
1662195972f6Sopenharmony_ci  }
1663195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1664195972f6Sopenharmony_ci}
1665195972f6Sopenharmony_ci
1666195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
1667195972f6Sopenharmony_ci/** Indicate that a TCP pcb has been accepted
1668195972f6Sopenharmony_ci * Called from netconn_accept
1669195972f6Sopenharmony_ci *
1670195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1671195972f6Sopenharmony_ci */
1672195972f6Sopenharmony_civoid
1673195972f6Sopenharmony_cilwip_netconn_do_accepted(void *m)
1674195972f6Sopenharmony_ci{
1675195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1676195972f6Sopenharmony_ci
1677195972f6Sopenharmony_ci  msg->err = ERR_OK;
1678195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
1679195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1680195972f6Sopenharmony_ci      tcp_backlog_accepted(msg->conn->pcb.tcp);
1681195972f6Sopenharmony_ci    }
1682195972f6Sopenharmony_ci  }
1683195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1684195972f6Sopenharmony_ci}
1685195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
1686195972f6Sopenharmony_ci
1687195972f6Sopenharmony_ci/**
1688195972f6Sopenharmony_ci * See if more data needs to be written from a previous call to netconn_write.
1689195972f6Sopenharmony_ci * Called initially from lwip_netconn_do_write. If the first call can't send all data
1690195972f6Sopenharmony_ci * (because of low memory or empty send-buffer), this function is called again
1691195972f6Sopenharmony_ci * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
1692195972f6Sopenharmony_ci * blocking application thread (waiting in netconn_write) is released.
1693195972f6Sopenharmony_ci *
1694195972f6Sopenharmony_ci * @param conn netconn (that is currently in state NETCONN_WRITE) to process
1695195972f6Sopenharmony_ci * @return ERR_OK
1696195972f6Sopenharmony_ci *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
1697195972f6Sopenharmony_ci */
1698195972f6Sopenharmony_cistatic err_t
1699195972f6Sopenharmony_cilwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
1700195972f6Sopenharmony_ci{
1701195972f6Sopenharmony_ci  err_t err;
1702195972f6Sopenharmony_ci  const void *dataptr;
1703195972f6Sopenharmony_ci  u16_t len, available;
1704195972f6Sopenharmony_ci  u8_t write_finished = 0;
1705195972f6Sopenharmony_ci  size_t diff;
1706195972f6Sopenharmony_ci  u8_t dontblock;
1707195972f6Sopenharmony_ci  u8_t apiflags;
1708195972f6Sopenharmony_ci  u8_t write_more;
1709195972f6Sopenharmony_ci
1710195972f6Sopenharmony_ci  LWIP_ASSERT("conn != NULL", conn != NULL);
1711195972f6Sopenharmony_ci  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
1712195972f6Sopenharmony_ci  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
1713195972f6Sopenharmony_ci  LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
1714195972f6Sopenharmony_ci  LWIP_ASSERT("conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len",
1715195972f6Sopenharmony_ci              conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len);
1716195972f6Sopenharmony_ci  LWIP_ASSERT("conn->current_msg->msg.w.vector_cnt > 0", conn->current_msg->msg.w.vector_cnt > 0);
1717195972f6Sopenharmony_ci
1718195972f6Sopenharmony_ci  apiflags = conn->current_msg->msg.w.apiflags;
1719195972f6Sopenharmony_ci  dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1720195972f6Sopenharmony_ci
1721195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO
1722195972f6Sopenharmony_ci  if ((conn->send_timeout != 0) &&
1723195972f6Sopenharmony_ci      ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
1724195972f6Sopenharmony_ci    write_finished = 1;
1725195972f6Sopenharmony_ci    if (conn->current_msg->msg.w.offset == 0) {
1726195972f6Sopenharmony_ci      /* nothing has been written */
1727195972f6Sopenharmony_ci      err = ERR_WOULDBLOCK;
1728195972f6Sopenharmony_ci    } else {
1729195972f6Sopenharmony_ci      /* partial write */
1730195972f6Sopenharmony_ci      err = ERR_OK;
1731195972f6Sopenharmony_ci    }
1732195972f6Sopenharmony_ci  } else
1733195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */
1734195972f6Sopenharmony_ci  {
1735195972f6Sopenharmony_ci    do {
1736195972f6Sopenharmony_ci      dataptr = (const u8_t *)conn->current_msg->msg.w.vector->ptr + conn->current_msg->msg.w.vector_off;
1737195972f6Sopenharmony_ci      diff = conn->current_msg->msg.w.vector->len - conn->current_msg->msg.w.vector_off;
1738195972f6Sopenharmony_ci      if (diff > 0xffffUL) { /* max_u16_t */
1739195972f6Sopenharmony_ci        len = 0xffff;
1740195972f6Sopenharmony_ci        apiflags |= TCP_WRITE_FLAG_MORE;
1741195972f6Sopenharmony_ci      } else {
1742195972f6Sopenharmony_ci        len = (u16_t)diff;
1743195972f6Sopenharmony_ci      }
1744195972f6Sopenharmony_ci      available = tcp_sndbuf(conn->pcb.tcp);
1745195972f6Sopenharmony_ci      if (available < len) {
1746195972f6Sopenharmony_ci        /* don't try to write more than sendbuf */
1747195972f6Sopenharmony_ci        len = available;
1748195972f6Sopenharmony_ci        if (dontblock) {
1749195972f6Sopenharmony_ci          if (!len) {
1750195972f6Sopenharmony_ci            /* set error according to partial write or not */
1751195972f6Sopenharmony_ci            err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1752195972f6Sopenharmony_ci            goto err_mem;
1753195972f6Sopenharmony_ci          }
1754195972f6Sopenharmony_ci        } else {
1755195972f6Sopenharmony_ci          apiflags |= TCP_WRITE_FLAG_MORE;
1756195972f6Sopenharmony_ci        }
1757195972f6Sopenharmony_ci      }
1758195972f6Sopenharmony_ci      LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!",
1759195972f6Sopenharmony_ci                  ((conn->current_msg->msg.w.vector_off + len) <= conn->current_msg->msg.w.vector->len));
1760195972f6Sopenharmony_ci      /* we should loop around for more sending in the following cases:
1761195972f6Sopenharmony_ci           1) We couldn't finish the current vector because of 16-bit size limitations.
1762195972f6Sopenharmony_ci              tcp_write() and tcp_sndbuf() both are limited to 16-bit sizes
1763195972f6Sopenharmony_ci           2) We are sending the remainder of the current vector and have more */
1764195972f6Sopenharmony_ci      if ((len == 0xffff && diff > 0xffffUL) ||
1765195972f6Sopenharmony_ci          (len == (u16_t)diff && conn->current_msg->msg.w.vector_cnt > 1)) {
1766195972f6Sopenharmony_ci        write_more = 1;
1767195972f6Sopenharmony_ci        apiflags |= TCP_WRITE_FLAG_MORE;
1768195972f6Sopenharmony_ci      } else {
1769195972f6Sopenharmony_ci        write_more = 0;
1770195972f6Sopenharmony_ci      }
1771195972f6Sopenharmony_ci      err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
1772195972f6Sopenharmony_ci      if (err == ERR_OK) {
1773195972f6Sopenharmony_ci        conn->current_msg->msg.w.offset += len;
1774195972f6Sopenharmony_ci        conn->current_msg->msg.w.vector_off += len;
1775195972f6Sopenharmony_ci        /* check if current vector is finished */
1776195972f6Sopenharmony_ci        if (conn->current_msg->msg.w.vector_off == conn->current_msg->msg.w.vector->len) {
1777195972f6Sopenharmony_ci          conn->current_msg->msg.w.vector_cnt--;
1778195972f6Sopenharmony_ci          /* if we have additional vectors, move on to them */
1779195972f6Sopenharmony_ci          if (conn->current_msg->msg.w.vector_cnt > 0) {
1780195972f6Sopenharmony_ci            conn->current_msg->msg.w.vector++;
1781195972f6Sopenharmony_ci            conn->current_msg->msg.w.vector_off = 0;
1782195972f6Sopenharmony_ci          }
1783195972f6Sopenharmony_ci        }
1784195972f6Sopenharmony_ci      }
1785195972f6Sopenharmony_ci    } while (write_more && err == ERR_OK);
1786195972f6Sopenharmony_ci    /* if OK or memory error, check available space */
1787195972f6Sopenharmony_ci    if ((err == ERR_OK) || (err == ERR_MEM)) {
1788195972f6Sopenharmony_cierr_mem:
1789195972f6Sopenharmony_ci      if (dontblock && (conn->current_msg->msg.w.offset < conn->current_msg->msg.w.len)) {
1790195972f6Sopenharmony_ci        /* non-blocking write did not write everything: mark the pcb non-writable
1791195972f6Sopenharmony_ci           and let poll_tcp check writable space to mark the pcb writable again */
1792195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1793195972f6Sopenharmony_ci        conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
1794195972f6Sopenharmony_ci      } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
1795195972f6Sopenharmony_ci                 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
1796195972f6Sopenharmony_ci        /* The queued byte- or pbuf-count exceeds the configured low-water limit,
1797195972f6Sopenharmony_ci           let select mark this pcb as non-writable. */
1798195972f6Sopenharmony_ci        API_EVENT(conn, NETCONN_EVT_SENDMINUS, 0);
1799195972f6Sopenharmony_ci      }
1800195972f6Sopenharmony_ci    }
1801195972f6Sopenharmony_ci
1802195972f6Sopenharmony_ci    if (err == ERR_OK) {
1803195972f6Sopenharmony_ci      err_t out_err;
1804195972f6Sopenharmony_ci      if ((conn->current_msg->msg.w.offset == conn->current_msg->msg.w.len) || dontblock) {
1805195972f6Sopenharmony_ci        /* return sent length (caller reads length from msg.w.offset) */
1806195972f6Sopenharmony_ci        write_finished = 1;
1807195972f6Sopenharmony_ci      }
1808195972f6Sopenharmony_ci      out_err = tcp_output(conn->pcb.tcp);
1809195972f6Sopenharmony_ci      if (out_err == ERR_RTE) {
1810195972f6Sopenharmony_ci        /* If tcp_output fails because no route is found,
1811195972f6Sopenharmony_ci           don't try writing any more but return the error
1812195972f6Sopenharmony_ci           to the application thread. */
1813195972f6Sopenharmony_ci        err = out_err;
1814195972f6Sopenharmony_ci        write_finished = 1;
1815195972f6Sopenharmony_ci      }
1816195972f6Sopenharmony_ci    } else if (err == ERR_MEM) {
1817195972f6Sopenharmony_ci      /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called.
1818195972f6Sopenharmony_ci         For blocking sockets, we do NOT return to the application
1819195972f6Sopenharmony_ci         thread, since ERR_MEM is only a temporary error! Non-blocking
1820195972f6Sopenharmony_ci         will remain non-writable until sent_tcp/poll_tcp is called */
1821195972f6Sopenharmony_ci
1822195972f6Sopenharmony_ci      /* tcp_write returned ERR_MEM, try tcp_output anyway */
1823195972f6Sopenharmony_ci      err_t out_err = tcp_output(conn->pcb.tcp);
1824195972f6Sopenharmony_ci      if (out_err == ERR_RTE) {
1825195972f6Sopenharmony_ci        /* If tcp_output fails because no route is found,
1826195972f6Sopenharmony_ci           don't try writing any more but return the error
1827195972f6Sopenharmony_ci           to the application thread. */
1828195972f6Sopenharmony_ci        err = out_err;
1829195972f6Sopenharmony_ci        write_finished = 1;
1830195972f6Sopenharmony_ci      } else if (dontblock) {
1831195972f6Sopenharmony_ci        /* non-blocking write is done on ERR_MEM, set error according
1832195972f6Sopenharmony_ci           to partial write or not */
1833195972f6Sopenharmony_ci        err = (conn->current_msg->msg.w.offset == 0) ? ERR_WOULDBLOCK : ERR_OK;
1834195972f6Sopenharmony_ci        write_finished = 1;
1835195972f6Sopenharmony_ci      }
1836195972f6Sopenharmony_ci    } else {
1837195972f6Sopenharmony_ci      /* On errors != ERR_MEM, we don't try writing any more but return
1838195972f6Sopenharmony_ci         the error to the application thread. */
1839195972f6Sopenharmony_ci      write_finished = 1;
1840195972f6Sopenharmony_ci    }
1841195972f6Sopenharmony_ci  }
1842195972f6Sopenharmony_ci  if (write_finished) {
1843195972f6Sopenharmony_ci    /* everything was written: set back connection state
1844195972f6Sopenharmony_ci       and back to application task */
1845195972f6Sopenharmony_ci    sys_sem_t *op_completed_sem = LWIP_API_MSG_SEM(conn->current_msg);
1846195972f6Sopenharmony_ci    conn->current_msg->err = err;
1847195972f6Sopenharmony_ci    conn->current_msg = NULL;
1848195972f6Sopenharmony_ci    conn->state = NETCONN_NONE;
1849195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1850195972f6Sopenharmony_ci    if (delayed)
1851195972f6Sopenharmony_ci#endif
1852195972f6Sopenharmony_ci    {
1853195972f6Sopenharmony_ci      sys_sem_signal(op_completed_sem);
1854195972f6Sopenharmony_ci    }
1855195972f6Sopenharmony_ci  }
1856195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1857195972f6Sopenharmony_ci  else {
1858195972f6Sopenharmony_ci    return ERR_MEM;
1859195972f6Sopenharmony_ci  }
1860195972f6Sopenharmony_ci#endif
1861195972f6Sopenharmony_ci  return ERR_OK;
1862195972f6Sopenharmony_ci}
1863195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1864195972f6Sopenharmony_ci
1865195972f6Sopenharmony_ci/**
1866195972f6Sopenharmony_ci * Send some data on a TCP pcb contained in a netconn
1867195972f6Sopenharmony_ci * Called from netconn_write
1868195972f6Sopenharmony_ci *
1869195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1870195972f6Sopenharmony_ci */
1871195972f6Sopenharmony_civoid
1872195972f6Sopenharmony_cilwip_netconn_do_write(void *m)
1873195972f6Sopenharmony_ci{
1874195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1875195972f6Sopenharmony_ci
1876195972f6Sopenharmony_ci  err_t err = netconn_err(msg->conn);
1877195972f6Sopenharmony_ci  if (err == ERR_OK) {
1878195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
1879195972f6Sopenharmony_ci#if LWIP_TCP
1880195972f6Sopenharmony_ci      if (msg->conn->state != NETCONN_NONE) {
1881195972f6Sopenharmony_ci        /* netconn is connecting, closing or in blocking write */
1882195972f6Sopenharmony_ci        err = ERR_INPROGRESS;
1883195972f6Sopenharmony_ci      } else if (msg->conn->pcb.tcp != NULL) {
1884195972f6Sopenharmony_ci        msg->conn->state = NETCONN_WRITE;
1885195972f6Sopenharmony_ci        /* set all the variables used by lwip_netconn_do_writemore */
1886195972f6Sopenharmony_ci        LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
1887195972f6Sopenharmony_ci        LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
1888195972f6Sopenharmony_ci        msg->conn->current_msg = msg;
1889195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
1890195972f6Sopenharmony_ci        if (lwip_netconn_do_writemore(msg->conn, 0) != ERR_OK) {
1891195972f6Sopenharmony_ci          LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
1892195972f6Sopenharmony_ci          UNLOCK_TCPIP_CORE();
1893195972f6Sopenharmony_ci          sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
1894195972f6Sopenharmony_ci          LOCK_TCPIP_CORE();
1895195972f6Sopenharmony_ci          LWIP_ASSERT("state!", msg->conn->state != NETCONN_WRITE);
1896195972f6Sopenharmony_ci        }
1897195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
1898195972f6Sopenharmony_ci        lwip_netconn_do_writemore(msg->conn);
1899195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
1900195972f6Sopenharmony_ci        /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG
1901195972f6Sopenharmony_ci           since lwip_netconn_do_writemore ACKs it! */
1902195972f6Sopenharmony_ci        return;
1903195972f6Sopenharmony_ci      } else {
1904195972f6Sopenharmony_ci        err = ERR_CONN;
1905195972f6Sopenharmony_ci      }
1906195972f6Sopenharmony_ci#else /* LWIP_TCP */
1907195972f6Sopenharmony_ci      err = ERR_VAL;
1908195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1909195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW)
1910195972f6Sopenharmony_ci    } else {
1911195972f6Sopenharmony_ci      err = ERR_VAL;
1912195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */
1913195972f6Sopenharmony_ci    }
1914195972f6Sopenharmony_ci  }
1915195972f6Sopenharmony_ci  msg->err = err;
1916195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1917195972f6Sopenharmony_ci}
1918195972f6Sopenharmony_ci
1919195972f6Sopenharmony_ci/**
1920195972f6Sopenharmony_ci * Return a connection's local or remote address
1921195972f6Sopenharmony_ci * Called from netconn_getaddr
1922195972f6Sopenharmony_ci *
1923195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1924195972f6Sopenharmony_ci */
1925195972f6Sopenharmony_civoid
1926195972f6Sopenharmony_cilwip_netconn_do_getaddr(void *m)
1927195972f6Sopenharmony_ci{
1928195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1929195972f6Sopenharmony_ci
1930195972f6Sopenharmony_ci  if (msg->conn->pcb.ip != NULL) {
1931195972f6Sopenharmony_ci    if (msg->msg.ad.local) {
1932195972f6Sopenharmony_ci      ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1933195972f6Sopenharmony_ci                   msg->conn->pcb.ip->local_ip);
1934195972f6Sopenharmony_ci    } else {
1935195972f6Sopenharmony_ci      ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr),
1936195972f6Sopenharmony_ci                   msg->conn->pcb.ip->remote_ip);
1937195972f6Sopenharmony_ci    }
1938195972f6Sopenharmony_ci
1939195972f6Sopenharmony_ci    msg->err = ERR_OK;
1940195972f6Sopenharmony_ci    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
1941195972f6Sopenharmony_ci#if LWIP_RAW
1942195972f6Sopenharmony_ci      case NETCONN_RAW:
1943195972f6Sopenharmony_ci        if (msg->msg.ad.local) {
1944195972f6Sopenharmony_ci          API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
1945195972f6Sopenharmony_ci        } else {
1946195972f6Sopenharmony_ci          /* return an error as connecting is only a helper for upper layers */
1947195972f6Sopenharmony_ci          msg->err = ERR_CONN;
1948195972f6Sopenharmony_ci        }
1949195972f6Sopenharmony_ci        break;
1950195972f6Sopenharmony_ci#endif /* LWIP_RAW */
1951195972f6Sopenharmony_ci#if LWIP_UDP
1952195972f6Sopenharmony_ci      case NETCONN_UDP:
1953195972f6Sopenharmony_ci        if (msg->msg.ad.local) {
1954195972f6Sopenharmony_ci          API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
1955195972f6Sopenharmony_ci        } else {
1956195972f6Sopenharmony_ci          if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
1957195972f6Sopenharmony_ci            msg->err = ERR_CONN;
1958195972f6Sopenharmony_ci          } else {
1959195972f6Sopenharmony_ci            API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
1960195972f6Sopenharmony_ci          }
1961195972f6Sopenharmony_ci        }
1962195972f6Sopenharmony_ci        break;
1963195972f6Sopenharmony_ci#endif /* LWIP_UDP */
1964195972f6Sopenharmony_ci#if LWIP_TCP
1965195972f6Sopenharmony_ci      case NETCONN_TCP:
1966195972f6Sopenharmony_ci        if ((msg->msg.ad.local == 0) &&
1967195972f6Sopenharmony_ci            ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) {
1968195972f6Sopenharmony_ci          /* pcb is not connected and remote name is requested */
1969195972f6Sopenharmony_ci          msg->err = ERR_CONN;
1970195972f6Sopenharmony_ci        } else {
1971195972f6Sopenharmony_ci          API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port);
1972195972f6Sopenharmony_ci        }
1973195972f6Sopenharmony_ci        break;
1974195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1975195972f6Sopenharmony_ci      default:
1976195972f6Sopenharmony_ci        LWIP_ASSERT("invalid netconn_type", 0);
1977195972f6Sopenharmony_ci        break;
1978195972f6Sopenharmony_ci    }
1979195972f6Sopenharmony_ci  } else {
1980195972f6Sopenharmony_ci    msg->err = ERR_CONN;
1981195972f6Sopenharmony_ci  }
1982195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
1983195972f6Sopenharmony_ci}
1984195972f6Sopenharmony_ci
1985195972f6Sopenharmony_ci/**
1986195972f6Sopenharmony_ci * Close or half-shutdown a TCP pcb contained in a netconn
1987195972f6Sopenharmony_ci * Called from netconn_close
1988195972f6Sopenharmony_ci * In contrast to closing sockets, the netconn is not deallocated.
1989195972f6Sopenharmony_ci *
1990195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
1991195972f6Sopenharmony_ci */
1992195972f6Sopenharmony_civoid
1993195972f6Sopenharmony_cilwip_netconn_do_close(void *m)
1994195972f6Sopenharmony_ci{
1995195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
1996195972f6Sopenharmony_ci
1997195972f6Sopenharmony_ci#if LWIP_TCP
1998195972f6Sopenharmony_ci  enum netconn_state state = msg->conn->state;
1999195972f6Sopenharmony_ci  /* First check if this is a TCP netconn and if it is in a correct state
2000195972f6Sopenharmony_ci      (LISTEN doesn't support half shutdown) */
2001195972f6Sopenharmony_ci  if ((msg->conn->pcb.tcp != NULL) &&
2002195972f6Sopenharmony_ci      (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) &&
2003195972f6Sopenharmony_ci      ((msg->msg.sd.shut == NETCONN_SHUT_RDWR) || (state != NETCONN_LISTEN))) {
2004195972f6Sopenharmony_ci    /* Check if we are in a connected state */
2005195972f6Sopenharmony_ci    if (state == NETCONN_CONNECT) {
2006195972f6Sopenharmony_ci      /* TCP connect in progress: cannot shutdown */
2007195972f6Sopenharmony_ci      msg->err = ERR_CONN;
2008195972f6Sopenharmony_ci    } else if (state == NETCONN_WRITE) {
2009195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
2010195972f6Sopenharmony_ci      if (msg->msg.sd.shut & NETCONN_SHUT_WR) {
2011195972f6Sopenharmony_ci        /* close requested, abort running write */
2012195972f6Sopenharmony_ci        sys_sem_t *write_completed_sem;
2013195972f6Sopenharmony_ci        LWIP_ASSERT("msg->conn->current_msg != NULL", msg->conn->current_msg != NULL);
2014195972f6Sopenharmony_ci        write_completed_sem = LWIP_API_MSG_SEM(msg->conn->current_msg);
2015195972f6Sopenharmony_ci        msg->conn->current_msg->err = ERR_CLSD;
2016195972f6Sopenharmony_ci        msg->conn->current_msg = NULL;
2017195972f6Sopenharmony_ci        msg->conn->state = NETCONN_NONE;
2018195972f6Sopenharmony_ci        state = NETCONN_NONE;
2019195972f6Sopenharmony_ci        sys_sem_signal(write_completed_sem);
2020195972f6Sopenharmony_ci      } else {
2021195972f6Sopenharmony_ci        LWIP_ASSERT("msg->msg.sd.shut == NETCONN_SHUT_RD", msg->msg.sd.shut == NETCONN_SHUT_RD);
2022195972f6Sopenharmony_ci        /* In this case, let the write continue and do not interfere with
2023195972f6Sopenharmony_ci           conn->current_msg or conn->state! */
2024195972f6Sopenharmony_ci        msg->err = tcp_shutdown(msg->conn->pcb.tcp, 1, 0);
2025195972f6Sopenharmony_ci      }
2026195972f6Sopenharmony_ci    }
2027195972f6Sopenharmony_ci    if (state == NETCONN_NONE) {
2028195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */
2029195972f6Sopenharmony_ci      msg->err = ERR_INPROGRESS;
2030195972f6Sopenharmony_ci    } else {
2031195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
2032195972f6Sopenharmony_ci      if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
2033195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
2034195972f6Sopenharmony_ci        /* Mark mboxes invalid */
2035195972f6Sopenharmony_ci        netconn_mark_mbox_invalid(msg->conn);
2036195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */
2037195972f6Sopenharmony_ci        netconn_drain(msg->conn);
2038195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
2039195972f6Sopenharmony_ci      }
2040195972f6Sopenharmony_ci      LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL);
2041195972f6Sopenharmony_ci      msg->conn->state = NETCONN_CLOSE;
2042195972f6Sopenharmony_ci      msg->conn->current_msg = msg;
2043195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
2044195972f6Sopenharmony_ci      if (lwip_netconn_do_close_internal(msg->conn, 0) != ERR_OK) {
2045195972f6Sopenharmony_ci        LWIP_ASSERT("state!", msg->conn->state == NETCONN_CLOSE);
2046195972f6Sopenharmony_ci        UNLOCK_TCPIP_CORE();
2047195972f6Sopenharmony_ci        sys_arch_sem_wait(LWIP_API_MSG_SEM(msg), 0);
2048195972f6Sopenharmony_ci        LOCK_TCPIP_CORE();
2049195972f6Sopenharmony_ci        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
2050195972f6Sopenharmony_ci      }
2051195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
2052195972f6Sopenharmony_ci      lwip_netconn_do_close_internal(msg->conn);
2053195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
2054195972f6Sopenharmony_ci      /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */
2055195972f6Sopenharmony_ci      return;
2056195972f6Sopenharmony_ci    }
2057195972f6Sopenharmony_ci  } else
2058195972f6Sopenharmony_ci#endif /* LWIP_TCP */
2059195972f6Sopenharmony_ci  {
2060195972f6Sopenharmony_ci    msg->err = ERR_CONN;
2061195972f6Sopenharmony_ci  }
2062195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
2063195972f6Sopenharmony_ci}
2064195972f6Sopenharmony_ci
2065195972f6Sopenharmony_ci#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
2066195972f6Sopenharmony_ci/**
2067195972f6Sopenharmony_ci * Join multicast groups for UDP netconns.
2068195972f6Sopenharmony_ci * Called from netconn_join_leave_group
2069195972f6Sopenharmony_ci *
2070195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
2071195972f6Sopenharmony_ci */
2072195972f6Sopenharmony_civoid
2073195972f6Sopenharmony_cilwip_netconn_do_join_leave_group(void *m)
2074195972f6Sopenharmony_ci{
2075195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
2076195972f6Sopenharmony_ci
2077195972f6Sopenharmony_ci  msg->err = ERR_CONN;
2078195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
2079195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2080195972f6Sopenharmony_ci#if LWIP_UDP
2081195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_MLD
2082195972f6Sopenharmony_ci      if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2083195972f6Sopenharmony_ci        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2084195972f6Sopenharmony_ci          msg->err = mld6_joingroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2085195972f6Sopenharmony_ci                                    ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2086195972f6Sopenharmony_ci        } else {
2087195972f6Sopenharmony_ci          msg->err = mld6_leavegroup(ip_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
2088195972f6Sopenharmony_ci                                     ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2089195972f6Sopenharmony_ci        }
2090195972f6Sopenharmony_ci      } else
2091195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2092195972f6Sopenharmony_ci      {
2093195972f6Sopenharmony_ci#if LWIP_IGMP
2094195972f6Sopenharmony_ci        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2095195972f6Sopenharmony_ci          msg->err = igmp_joingroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2096195972f6Sopenharmony_ci                                    ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2097195972f6Sopenharmony_ci        } else {
2098195972f6Sopenharmony_ci          msg->err = igmp_leavegroup(ip_2_ip4(API_EXPR_REF(msg->msg.jl.netif_addr)),
2099195972f6Sopenharmony_ci                                     ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2100195972f6Sopenharmony_ci        }
2101195972f6Sopenharmony_ci#endif /* LWIP_IGMP */
2102195972f6Sopenharmony_ci      }
2103195972f6Sopenharmony_ci#endif /* LWIP_UDP */
2104195972f6Sopenharmony_ci#if (LWIP_TCP || LWIP_RAW)
2105195972f6Sopenharmony_ci    } else {
2106195972f6Sopenharmony_ci      msg->err = ERR_VAL;
2107195972f6Sopenharmony_ci#endif /* (LWIP_TCP || LWIP_RAW) */
2108195972f6Sopenharmony_ci    }
2109195972f6Sopenharmony_ci  }
2110195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
2111195972f6Sopenharmony_ci}
2112195972f6Sopenharmony_ci/**
2113195972f6Sopenharmony_ci * Join multicast groups for UDP netconns.
2114195972f6Sopenharmony_ci * Called from netconn_join_leave_group_netif
2115195972f6Sopenharmony_ci *
2116195972f6Sopenharmony_ci * @param m the api_msg pointing to the connection
2117195972f6Sopenharmony_ci */
2118195972f6Sopenharmony_civoid
2119195972f6Sopenharmony_cilwip_netconn_do_join_leave_group_netif(void *m)
2120195972f6Sopenharmony_ci{
2121195972f6Sopenharmony_ci  struct api_msg *msg = (struct api_msg *)m;
2122195972f6Sopenharmony_ci  struct netif *netif;
2123195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER
2124195972f6Sopenharmony_ci  struct net_group *group = get_net_group_from_ippcb(msg->conn->pcb.ip);
2125195972f6Sopenharmony_ci
2126195972f6Sopenharmony_ci  if (group != NULL) {
2127195972f6Sopenharmony_ci    netif = netif_get_by_index(msg->msg.jl.if_idx, group);
2128195972f6Sopenharmony_ci  } else {
2129195972f6Sopenharmony_ci    netif = NULL;
2130195972f6Sopenharmony_ci  }
2131195972f6Sopenharmony_ci#else
2132195972f6Sopenharmony_ci  netif = netif_get_by_index(msg->msg.jl.if_idx);
2133195972f6Sopenharmony_ci#endif
2134195972f6Sopenharmony_ci
2135195972f6Sopenharmony_ci  if (netif == NULL) {
2136195972f6Sopenharmony_ci    msg->err = ERR_IF;
2137195972f6Sopenharmony_ci    goto done;
2138195972f6Sopenharmony_ci  }
2139195972f6Sopenharmony_ci
2140195972f6Sopenharmony_ci  msg->err = ERR_CONN;
2141195972f6Sopenharmony_ci  if (msg->conn->pcb.tcp != NULL) {
2142195972f6Sopenharmony_ci    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
2143195972f6Sopenharmony_ci#if LWIP_UDP
2144195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_MLD
2145195972f6Sopenharmony_ci      if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
2146195972f6Sopenharmony_ci        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2147195972f6Sopenharmony_ci          msg->err = mld6_joingroup_netif(netif,
2148195972f6Sopenharmony_ci                                          ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2149195972f6Sopenharmony_ci        } else {
2150195972f6Sopenharmony_ci          msg->err = mld6_leavegroup_netif(netif,
2151195972f6Sopenharmony_ci                                           ip_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
2152195972f6Sopenharmony_ci        }
2153195972f6Sopenharmony_ci      } else
2154195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
2155195972f6Sopenharmony_ci      {
2156195972f6Sopenharmony_ci#if LWIP_IGMP
2157195972f6Sopenharmony_ci        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
2158195972f6Sopenharmony_ci          msg->err = igmp_joingroup_netif(netif,
2159195972f6Sopenharmony_ci                                          ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2160195972f6Sopenharmony_ci        } else {
2161195972f6Sopenharmony_ci          msg->err = igmp_leavegroup_netif(netif,
2162195972f6Sopenharmony_ci                                           ip_2_ip4(API_EXPR_REF(msg->msg.jl.multiaddr)));
2163195972f6Sopenharmony_ci        }
2164195972f6Sopenharmony_ci#endif /* LWIP_IGMP */
2165195972f6Sopenharmony_ci      }
2166195972f6Sopenharmony_ci#endif /* LWIP_UDP */
2167195972f6Sopenharmony_ci#if (LWIP_TCP || LWIP_RAW)
2168195972f6Sopenharmony_ci    } else {
2169195972f6Sopenharmony_ci      msg->err = ERR_VAL;
2170195972f6Sopenharmony_ci#endif /* (LWIP_TCP || LWIP_RAW) */
2171195972f6Sopenharmony_ci    }
2172195972f6Sopenharmony_ci  }
2173195972f6Sopenharmony_ci
2174195972f6Sopenharmony_cidone:
2175195972f6Sopenharmony_ci  TCPIP_APIMSG_ACK(msg);
2176195972f6Sopenharmony_ci}
2177195972f6Sopenharmony_ci#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
2178195972f6Sopenharmony_ci
2179195972f6Sopenharmony_ci#if LWIP_DNS
2180195972f6Sopenharmony_ci/**
2181195972f6Sopenharmony_ci * Callback function that is called when DNS name is resolved
2182195972f6Sopenharmony_ci * (or on timeout). A waiting application thread is waked up by
2183195972f6Sopenharmony_ci * signaling the semaphore.
2184195972f6Sopenharmony_ci */
2185195972f6Sopenharmony_cistatic void
2186195972f6Sopenharmony_cilwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg)
2187195972f6Sopenharmony_ci{
2188195972f6Sopenharmony_ci  struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2189195972f6Sopenharmony_ci
2190195972f6Sopenharmony_ci  /* we trust the internal implementation to be correct :-) */
2191195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(name);
2192195972f6Sopenharmony_ci
2193195972f6Sopenharmony_ci  if (ipaddr == NULL) {
2194195972f6Sopenharmony_ci    /* timeout or memory error */
2195195972f6Sopenharmony_ci    API_EXPR_DEREF(msg->err) = ERR_VAL;
2196195972f6Sopenharmony_ci  } else {
2197195972f6Sopenharmony_ci    /* address was resolved */
2198195972f6Sopenharmony_ci    API_EXPR_DEREF(msg->err) = ERR_OK;
2199195972f6Sopenharmony_ci    API_EXPR_DEREF(msg->addr) = *ipaddr;
2200195972f6Sopenharmony_ci  }
2201195972f6Sopenharmony_ci  /* wake up the application task waiting in netconn_gethostbyname */
2202195972f6Sopenharmony_ci  sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2203195972f6Sopenharmony_ci}
2204195972f6Sopenharmony_ci
2205195972f6Sopenharmony_ci/**
2206195972f6Sopenharmony_ci * Execute a DNS query
2207195972f6Sopenharmony_ci * Called from netconn_gethostbyname
2208195972f6Sopenharmony_ci *
2209195972f6Sopenharmony_ci * @param arg the dns_api_msg pointing to the query
2210195972f6Sopenharmony_ci */
2211195972f6Sopenharmony_civoid
2212195972f6Sopenharmony_cilwip_netconn_do_gethostbyname(void *arg)
2213195972f6Sopenharmony_ci{
2214195972f6Sopenharmony_ci  struct dns_api_msg *msg = (struct dns_api_msg *)arg;
2215195972f6Sopenharmony_ci  u8_t addrtype =
2216195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
2217195972f6Sopenharmony_ci    msg->dns_addrtype;
2218195972f6Sopenharmony_ci#else
2219195972f6Sopenharmony_ci    LWIP_DNS_ADDRTYPE_DEFAULT;
2220195972f6Sopenharmony_ci#endif
2221195972f6Sopenharmony_ci
2222195972f6Sopenharmony_ci  API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name,
2223195972f6Sopenharmony_ci                             API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype);
2224195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING
2225195972f6Sopenharmony_ci  /* For core locking, only block if we need to wait for answer/timeout */
2226195972f6Sopenharmony_ci  if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) {
2227195972f6Sopenharmony_ci    UNLOCK_TCPIP_CORE();
2228195972f6Sopenharmony_ci    sys_sem_wait(API_EXPR_REF_SEM(msg->sem));
2229195972f6Sopenharmony_ci    LOCK_TCPIP_CORE();
2230195972f6Sopenharmony_ci    LWIP_ASSERT("do_gethostbyname still in progress!!", API_EXPR_DEREF(msg->err) != ERR_INPROGRESS);
2231195972f6Sopenharmony_ci  }
2232195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */
2233195972f6Sopenharmony_ci  if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) {
2234195972f6Sopenharmony_ci    /* on error or immediate success, wake up the application
2235195972f6Sopenharmony_ci     * task waiting in netconn_gethostbyname */
2236195972f6Sopenharmony_ci    sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
2237195972f6Sopenharmony_ci  }
2238195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */
2239195972f6Sopenharmony_ci}
2240195972f6Sopenharmony_ci#endif /* LWIP_DNS */
2241195972f6Sopenharmony_ci
2242195972f6Sopenharmony_ci#endif /* LWIP_NETCONN */
2243