1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * Sequential API External module
4195972f6Sopenharmony_ci *
5195972f6Sopenharmony_ci * @defgroup netconn Netconn API
6195972f6Sopenharmony_ci * @ingroup sequential_api
7195972f6Sopenharmony_ci * Thread-safe, to be called from non-TCPIP threads only.
8195972f6Sopenharmony_ci * TX/RX handling based on @ref netbuf (containing @ref pbuf)
9195972f6Sopenharmony_ci * to avoid copying data around.
10195972f6Sopenharmony_ci *
11195972f6Sopenharmony_ci * @defgroup netconn_common Common functions
12195972f6Sopenharmony_ci * @ingroup netconn
13195972f6Sopenharmony_ci * For use with TCP and UDP
14195972f6Sopenharmony_ci *
15195972f6Sopenharmony_ci * @defgroup netconn_tcp TCP only
16195972f6Sopenharmony_ci * @ingroup netconn
17195972f6Sopenharmony_ci * TCP only functions
18195972f6Sopenharmony_ci *
19195972f6Sopenharmony_ci * @defgroup netconn_udp UDP only
20195972f6Sopenharmony_ci * @ingroup netconn
21195972f6Sopenharmony_ci * UDP only functions
22195972f6Sopenharmony_ci */
23195972f6Sopenharmony_ci
24195972f6Sopenharmony_ci/*
25195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
26195972f6Sopenharmony_ci * All rights reserved.
27195972f6Sopenharmony_ci *
28195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
29195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
30195972f6Sopenharmony_ci *
31195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
32195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
33195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
34195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
35195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
36195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
37195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
38195972f6Sopenharmony_ci *
39195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
40195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
41195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
42195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
43195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
44195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
46195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
47195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
48195972f6Sopenharmony_ci * OF SUCH DAMAGE.
49195972f6Sopenharmony_ci *
50195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack.
51195972f6Sopenharmony_ci *
52195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se>
53195972f6Sopenharmony_ci */
54195972f6Sopenharmony_ci
55195972f6Sopenharmony_ci/* This is the part of the API that is linked with
56195972f6Sopenharmony_ci   the application */
57195972f6Sopenharmony_ci
58195972f6Sopenharmony_ci#include "lwip/opt.h"
59195972f6Sopenharmony_ci
60195972f6Sopenharmony_ci#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
61195972f6Sopenharmony_ci
62195972f6Sopenharmony_ci#include "lwip/api.h"
63195972f6Sopenharmony_ci#include "lwip/memp.h"
64195972f6Sopenharmony_ci
65195972f6Sopenharmony_ci#include "lwip/ip.h"
66195972f6Sopenharmony_ci#include "lwip/raw.h"
67195972f6Sopenharmony_ci#include "lwip/udp.h"
68195972f6Sopenharmony_ci#include "lwip/priv/api_msg.h"
69195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h"
70195972f6Sopenharmony_ci#include "lwip/priv/tcpip_priv.h"
71195972f6Sopenharmony_ci
72195972f6Sopenharmony_ci#ifdef LWIP_HOOK_FILENAME
73195972f6Sopenharmony_ci#include LWIP_HOOK_FILENAME
74195972f6Sopenharmony_ci#endif
75195972f6Sopenharmony_ci
76195972f6Sopenharmony_ci#include <string.h>
77195972f6Sopenharmony_ci
78195972f6Sopenharmony_ci#define API_MSG_VAR_REF(name)               API_VAR_REF(name)
79195972f6Sopenharmony_ci#define API_MSG_VAR_DECLARE(name)           API_VAR_DECLARE(struct api_msg, name)
80195972f6Sopenharmony_ci#define API_MSG_VAR_ALLOC(name)             API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
81195972f6Sopenharmony_ci#define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
82195972f6Sopenharmony_ci#define API_MSG_VAR_FREE(name)              API_VAR_FREE(MEMP_API_MSG, name)
83195972f6Sopenharmony_ci
84195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
85195972f6Sopenharmony_ci/* need to allocate API message for accept so empty message pool does not result in event loss
86195972f6Sopenharmony_ci * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
87195972f6Sopenharmony_ci#define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg)
88195972f6Sopenharmony_ci#define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg)
89195972f6Sopenharmony_ci#else /* TCP_LISTEN_BACKLOG */
90195972f6Sopenharmony_ci#define API_MSG_VAR_ALLOC_ACCEPT(msg)
91195972f6Sopenharmony_ci#define API_MSG_VAR_FREE_ACCEPT(msg)
92195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
93195972f6Sopenharmony_ci
94195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
95195972f6Sopenharmony_ci#define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0))
96195972f6Sopenharmony_ci#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0))
97195972f6Sopenharmony_ci#define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1)
98195972f6Sopenharmony_ci#define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1)
99195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */
100195972f6Sopenharmony_ci#define NETCONN_RECVMBOX_WAITABLE(conn)   sys_mbox_valid(&(conn)->recvmbox)
101195972f6Sopenharmony_ci#define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0))
102195972f6Sopenharmony_ci#define NETCONN_MBOX_WAITING_INC(conn)
103195972f6Sopenharmony_ci#define NETCONN_MBOX_WAITING_DEC(conn)
104195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
105195972f6Sopenharmony_ci
106195972f6Sopenharmony_cistatic err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
107195972f6Sopenharmony_ci
108195972f6Sopenharmony_ci/**
109195972f6Sopenharmony_ci * Call the lower part of a netconn_* function
110195972f6Sopenharmony_ci * This function is then running in the thread context
111195972f6Sopenharmony_ci * of tcpip_thread and has exclusive access to lwIP core code.
112195972f6Sopenharmony_ci *
113195972f6Sopenharmony_ci * @param fn function to call
114195972f6Sopenharmony_ci * @param apimsg a struct containing the function to call and its parameters
115195972f6Sopenharmony_ci * @return ERR_OK if the function was called, another err_t if not
116195972f6Sopenharmony_ci */
117195972f6Sopenharmony_cistatic err_t
118195972f6Sopenharmony_cinetconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
119195972f6Sopenharmony_ci{
120195972f6Sopenharmony_ci  err_t err;
121195972f6Sopenharmony_ci
122195972f6Sopenharmony_ci#ifdef LWIP_DEBUG
123195972f6Sopenharmony_ci  /* catch functions that don't set err */
124195972f6Sopenharmony_ci  apimsg->err = ERR_VAL;
125195972f6Sopenharmony_ci#endif /* LWIP_DEBUG */
126195972f6Sopenharmony_ci
127195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD
128195972f6Sopenharmony_ci  apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
129195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */
130195972f6Sopenharmony_ci
131195972f6Sopenharmony_ci  err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
132195972f6Sopenharmony_ci  if (err == ERR_OK) {
133195972f6Sopenharmony_ci    return apimsg->err;
134195972f6Sopenharmony_ci  }
135195972f6Sopenharmony_ci  return err;
136195972f6Sopenharmony_ci}
137195972f6Sopenharmony_ci
138195972f6Sopenharmony_ci/**
139195972f6Sopenharmony_ci * Create a new netconn (of a specific type) that has a callback function.
140195972f6Sopenharmony_ci * The corresponding pcb is also created.
141195972f6Sopenharmony_ci *
142195972f6Sopenharmony_ci * @param t the type of 'connection' to create (@see enum netconn_type)
143195972f6Sopenharmony_ci * @param proto the IP protocol for RAW IP pcbs
144195972f6Sopenharmony_ci * @param callback a function to call on status changes (RX available, TX'ed)
145195972f6Sopenharmony_ci * @return a newly allocated struct netconn or
146195972f6Sopenharmony_ci *         NULL on memory error
147195972f6Sopenharmony_ci */
148195972f6Sopenharmony_cistruct netconn *
149195972f6Sopenharmony_cinetconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
150195972f6Sopenharmony_ci{
151195972f6Sopenharmony_ci  struct netconn *conn;
152195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
153195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC_RETURN_NULL(msg);
154195972f6Sopenharmony_ci
155195972f6Sopenharmony_ci  conn = netconn_alloc(t, callback);
156195972f6Sopenharmony_ci  if (conn != NULL) {
157195972f6Sopenharmony_ci    err_t err;
158195972f6Sopenharmony_ci
159195972f6Sopenharmony_ci    API_MSG_VAR_REF(msg).msg.n.proto = proto;
160195972f6Sopenharmony_ci    API_MSG_VAR_REF(msg).conn = conn;
161195972f6Sopenharmony_ci    err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
162195972f6Sopenharmony_ci    if (err != ERR_OK) {
163195972f6Sopenharmony_ci      LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
164195972f6Sopenharmony_ci      LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
165195972f6Sopenharmony_ci#if LWIP_TCP
166195972f6Sopenharmony_ci      LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
167195972f6Sopenharmony_ci#endif /* LWIP_TCP */
168195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD
169195972f6Sopenharmony_ci      LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
170195972f6Sopenharmony_ci      sys_sem_free(&conn->op_completed);
171195972f6Sopenharmony_ci#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
172195972f6Sopenharmony_ci      sys_mbox_free(&conn->recvmbox);
173195972f6Sopenharmony_ci      memp_free(MEMP_NETCONN, conn);
174195972f6Sopenharmony_ci      API_MSG_VAR_FREE(msg);
175195972f6Sopenharmony_ci      return NULL;
176195972f6Sopenharmony_ci    }
177195972f6Sopenharmony_ci  }
178195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
179195972f6Sopenharmony_ci  return conn;
180195972f6Sopenharmony_ci}
181195972f6Sopenharmony_ci
182195972f6Sopenharmony_ci/**
183195972f6Sopenharmony_ci * @ingroup netconn_common
184195972f6Sopenharmony_ci * Close a netconn 'connection' and free all its resources but not the netconn itself.
185195972f6Sopenharmony_ci * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
186195972f6Sopenharmony_ci * after this returns.
187195972f6Sopenharmony_ci *
188195972f6Sopenharmony_ci * @param conn the netconn to delete
189195972f6Sopenharmony_ci * @return ERR_OK if the connection was deleted
190195972f6Sopenharmony_ci */
191195972f6Sopenharmony_cierr_t
192195972f6Sopenharmony_cinetconn_prepare_delete(struct netconn *conn)
193195972f6Sopenharmony_ci{
194195972f6Sopenharmony_ci  err_t err;
195195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
196195972f6Sopenharmony_ci
197195972f6Sopenharmony_ci  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
198195972f6Sopenharmony_ci  if (conn == NULL) {
199195972f6Sopenharmony_ci    return ERR_OK;
200195972f6Sopenharmony_ci  }
201195972f6Sopenharmony_ci
202195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
203195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
204195972f6Sopenharmony_ci#if LWIP_TCP
205195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
206195972f6Sopenharmony_ci  /* get the time we started, which is later compared to
207195972f6Sopenharmony_ci     sys_now() + conn->send_timeout */
208195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
209195972f6Sopenharmony_ci#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
210195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.sd.polls_left =
211195972f6Sopenharmony_ci    ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
212195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
213195972f6Sopenharmony_ci#endif /* LWIP_TCP */
214195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
215195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
216195972f6Sopenharmony_ci
217195972f6Sopenharmony_ci  if (err != ERR_OK) {
218195972f6Sopenharmony_ci    return err;
219195972f6Sopenharmony_ci  }
220195972f6Sopenharmony_ci  return ERR_OK;
221195972f6Sopenharmony_ci}
222195972f6Sopenharmony_ci
223195972f6Sopenharmony_ci/**
224195972f6Sopenharmony_ci * @ingroup netconn_common
225195972f6Sopenharmony_ci * Close a netconn 'connection' and free its resources.
226195972f6Sopenharmony_ci * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
227195972f6Sopenharmony_ci * after this returns.
228195972f6Sopenharmony_ci *
229195972f6Sopenharmony_ci * @param conn the netconn to delete
230195972f6Sopenharmony_ci * @return ERR_OK if the connection was deleted
231195972f6Sopenharmony_ci */
232195972f6Sopenharmony_cierr_t
233195972f6Sopenharmony_cinetconn_delete(struct netconn *conn)
234195972f6Sopenharmony_ci{
235195972f6Sopenharmony_ci  err_t err;
236195972f6Sopenharmony_ci
237195972f6Sopenharmony_ci  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
238195972f6Sopenharmony_ci  if (conn == NULL) {
239195972f6Sopenharmony_ci    return ERR_OK;
240195972f6Sopenharmony_ci  }
241195972f6Sopenharmony_ci
242195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
243195972f6Sopenharmony_ci  if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
244195972f6Sopenharmony_ci    /* Already called netconn_prepare_delete() before */
245195972f6Sopenharmony_ci    err = ERR_OK;
246195972f6Sopenharmony_ci  } else
247195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */
248195972f6Sopenharmony_ci  {
249195972f6Sopenharmony_ci    err = netconn_prepare_delete(conn);
250195972f6Sopenharmony_ci  }
251195972f6Sopenharmony_ci  if (err == ERR_OK) {
252195972f6Sopenharmony_ci    netconn_free(conn);
253195972f6Sopenharmony_ci  }
254195972f6Sopenharmony_ci  return err;
255195972f6Sopenharmony_ci}
256195972f6Sopenharmony_ci
257195972f6Sopenharmony_ci/**
258195972f6Sopenharmony_ci * Get the local or remote IP address and port of a netconn.
259195972f6Sopenharmony_ci * For RAW netconns, this returns the protocol instead of a port!
260195972f6Sopenharmony_ci *
261195972f6Sopenharmony_ci * @param conn the netconn to query
262195972f6Sopenharmony_ci * @param addr a pointer to which to save the IP address
263195972f6Sopenharmony_ci * @param port a pointer to which to save the port (or protocol for RAW)
264195972f6Sopenharmony_ci * @param local 1 to get the local IP address, 0 to get the remote one
265195972f6Sopenharmony_ci * @return ERR_CONN for invalid connections
266195972f6Sopenharmony_ci *         ERR_OK if the information was retrieved
267195972f6Sopenharmony_ci */
268195972f6Sopenharmony_cierr_t
269195972f6Sopenharmony_cinetconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
270195972f6Sopenharmony_ci{
271195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
272195972f6Sopenharmony_ci  err_t err;
273195972f6Sopenharmony_ci
274195972f6Sopenharmony_ci  LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
275195972f6Sopenharmony_ci  LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
276195972f6Sopenharmony_ci  LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
277195972f6Sopenharmony_ci
278195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
279195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
280195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.ad.local = local;
281195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE
282195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
283195972f6Sopenharmony_ci  *addr = msg->msg.ad.ipaddr;
284195972f6Sopenharmony_ci  *port = msg->msg.ad.port;
285195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */
286195972f6Sopenharmony_ci  msg.msg.ad.ipaddr = addr;
287195972f6Sopenharmony_ci  msg.msg.ad.port = port;
288195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
289195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */
290195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
291195972f6Sopenharmony_ci
292195972f6Sopenharmony_ci  return err;
293195972f6Sopenharmony_ci}
294195972f6Sopenharmony_ci
295195972f6Sopenharmony_ci/**
296195972f6Sopenharmony_ci * @ingroup netconn_common
297195972f6Sopenharmony_ci * Bind a netconn to a specific local IP address and port.
298195972f6Sopenharmony_ci * Binding one netconn twice might not always be checked correctly!
299195972f6Sopenharmony_ci *
300195972f6Sopenharmony_ci * @param conn the netconn to bind
301195972f6Sopenharmony_ci * @param addr the local IP address to bind the netconn to
302195972f6Sopenharmony_ci *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
303195972f6Sopenharmony_ci * @param port the local port to bind the netconn to (not used for RAW)
304195972f6Sopenharmony_ci * @return ERR_OK if bound, any other err_t on failure
305195972f6Sopenharmony_ci */
306195972f6Sopenharmony_cierr_t
307195972f6Sopenharmony_cinetconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
308195972f6Sopenharmony_ci{
309195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
310195972f6Sopenharmony_ci  err_t err;
311195972f6Sopenharmony_ci
312195972f6Sopenharmony_ci  LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
313195972f6Sopenharmony_ci
314195972f6Sopenharmony_ci#if LWIP_IPV4
315195972f6Sopenharmony_ci  /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
316195972f6Sopenharmony_ci  if (addr == NULL) {
317195972f6Sopenharmony_ci    addr = IP4_ADDR_ANY;
318195972f6Sopenharmony_ci  }
319195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
320195972f6Sopenharmony_ci
321195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
322195972f6Sopenharmony_ci  /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
323195972f6Sopenharmony_ci   * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
324195972f6Sopenharmony_ci   */
325195972f6Sopenharmony_ci  if ((netconn_get_ipv6only(conn) == 0) &&
326195972f6Sopenharmony_ci      ip_addr_cmp(addr, IP6_ADDR_ANY)) {
327195972f6Sopenharmony_ci    addr = IP_ANY_TYPE;
328195972f6Sopenharmony_ci  }
329195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */
330195972f6Sopenharmony_ci
331195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
332195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
333195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
334195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.bc.port = port;
335195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
336195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
337195972f6Sopenharmony_ci
338195972f6Sopenharmony_ci  return err;
339195972f6Sopenharmony_ci}
340195972f6Sopenharmony_ci
341195972f6Sopenharmony_ci/**
342195972f6Sopenharmony_ci * @ingroup netconn_common
343195972f6Sopenharmony_ci * Bind a netconn to a specific interface and port.
344195972f6Sopenharmony_ci * Binding one netconn twice might not always be checked correctly!
345195972f6Sopenharmony_ci *
346195972f6Sopenharmony_ci * @param conn the netconn to bind
347195972f6Sopenharmony_ci * @param if_idx the local interface index to bind the netconn to
348195972f6Sopenharmony_ci * @return ERR_OK if bound, any other err_t on failure
349195972f6Sopenharmony_ci */
350195972f6Sopenharmony_cierr_t
351195972f6Sopenharmony_cinetconn_bind_if(struct netconn *conn, u8_t if_idx)
352195972f6Sopenharmony_ci{
353195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
354195972f6Sopenharmony_ci  err_t err;
355195972f6Sopenharmony_ci
356195972f6Sopenharmony_ci  LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;);
357195972f6Sopenharmony_ci
358195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
359195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
360195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx;
361195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg));
362195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
363195972f6Sopenharmony_ci
364195972f6Sopenharmony_ci  return err;
365195972f6Sopenharmony_ci}
366195972f6Sopenharmony_ci
367195972f6Sopenharmony_ci/**
368195972f6Sopenharmony_ci * @ingroup netconn_common
369195972f6Sopenharmony_ci * Connect a netconn to a specific remote IP address and port.
370195972f6Sopenharmony_ci *
371195972f6Sopenharmony_ci * @param conn the netconn to connect
372195972f6Sopenharmony_ci * @param addr the remote IP address to connect to
373195972f6Sopenharmony_ci * @param port the remote port to connect to (no used for RAW)
374195972f6Sopenharmony_ci * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
375195972f6Sopenharmony_ci */
376195972f6Sopenharmony_cierr_t
377195972f6Sopenharmony_cinetconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
378195972f6Sopenharmony_ci{
379195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
380195972f6Sopenharmony_ci  err_t err;
381195972f6Sopenharmony_ci
382195972f6Sopenharmony_ci  LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
383195972f6Sopenharmony_ci
384195972f6Sopenharmony_ci#if LWIP_IPV4
385195972f6Sopenharmony_ci  /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
386195972f6Sopenharmony_ci  if (addr == NULL) {
387195972f6Sopenharmony_ci    addr = IP4_ADDR_ANY;
388195972f6Sopenharmony_ci  }
389195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
390195972f6Sopenharmony_ci
391195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
392195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
393195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
394195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.bc.port = port;
395195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
396195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
397195972f6Sopenharmony_ci
398195972f6Sopenharmony_ci  return err;
399195972f6Sopenharmony_ci}
400195972f6Sopenharmony_ci
401195972f6Sopenharmony_ci/**
402195972f6Sopenharmony_ci * @ingroup netconn_udp
403195972f6Sopenharmony_ci * Disconnect a netconn from its current peer (only valid for UDP netconns).
404195972f6Sopenharmony_ci *
405195972f6Sopenharmony_ci * @param conn the netconn to disconnect
406195972f6Sopenharmony_ci * @return See @ref err_t
407195972f6Sopenharmony_ci */
408195972f6Sopenharmony_cierr_t
409195972f6Sopenharmony_cinetconn_disconnect(struct netconn *conn)
410195972f6Sopenharmony_ci{
411195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
412195972f6Sopenharmony_ci  err_t err;
413195972f6Sopenharmony_ci
414195972f6Sopenharmony_ci  LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
415195972f6Sopenharmony_ci
416195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
417195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
418195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
419195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
420195972f6Sopenharmony_ci
421195972f6Sopenharmony_ci  return err;
422195972f6Sopenharmony_ci}
423195972f6Sopenharmony_ci
424195972f6Sopenharmony_ci/**
425195972f6Sopenharmony_ci * @ingroup netconn_tcp
426195972f6Sopenharmony_ci * Set a TCP netconn into listen mode
427195972f6Sopenharmony_ci *
428195972f6Sopenharmony_ci * @param conn the tcp netconn to set to listen mode
429195972f6Sopenharmony_ci * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
430195972f6Sopenharmony_ci * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
431195972f6Sopenharmony_ci *         don't return any error (yet?))
432195972f6Sopenharmony_ci */
433195972f6Sopenharmony_cierr_t
434195972f6Sopenharmony_cinetconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
435195972f6Sopenharmony_ci{
436195972f6Sopenharmony_ci#if LWIP_TCP
437195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
438195972f6Sopenharmony_ci  err_t err;
439195972f6Sopenharmony_ci
440195972f6Sopenharmony_ci  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
441195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(backlog);
442195972f6Sopenharmony_ci
443195972f6Sopenharmony_ci  LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
444195972f6Sopenharmony_ci
445195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
446195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
447195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
448195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
449195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
450195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
451195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
452195972f6Sopenharmony_ci
453195972f6Sopenharmony_ci  return err;
454195972f6Sopenharmony_ci#else /* LWIP_TCP */
455195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(conn);
456195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(backlog);
457195972f6Sopenharmony_ci  return ERR_ARG;
458195972f6Sopenharmony_ci#endif /* LWIP_TCP */
459195972f6Sopenharmony_ci}
460195972f6Sopenharmony_ci
461195972f6Sopenharmony_ci/**
462195972f6Sopenharmony_ci * @ingroup netconn_tcp
463195972f6Sopenharmony_ci * Accept a new connection on a TCP listening netconn.
464195972f6Sopenharmony_ci *
465195972f6Sopenharmony_ci * @param conn the TCP listen netconn
466195972f6Sopenharmony_ci * @param new_conn pointer where the new connection is stored
467195972f6Sopenharmony_ci * @return ERR_OK if a new connection has been received or an error
468195972f6Sopenharmony_ci *                code otherwise
469195972f6Sopenharmony_ci */
470195972f6Sopenharmony_cierr_t
471195972f6Sopenharmony_cinetconn_accept(struct netconn *conn, struct netconn **new_conn)
472195972f6Sopenharmony_ci{
473195972f6Sopenharmony_ci#if LWIP_TCP
474195972f6Sopenharmony_ci  err_t err;
475195972f6Sopenharmony_ci  void *accept_ptr;
476195972f6Sopenharmony_ci  struct netconn *newconn;
477195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
478195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
479195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
480195972f6Sopenharmony_ci
481195972f6Sopenharmony_ci  LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_ARG;);
482195972f6Sopenharmony_ci  *new_conn = NULL;
483195972f6Sopenharmony_ci  LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_ARG;);
484195972f6Sopenharmony_ci
485195972f6Sopenharmony_ci  /* NOTE: Although the opengroup spec says a pending error shall be returned to
486195972f6Sopenharmony_ci           send/recv/getsockopt(SO_ERROR) only, we return it for listening
487195972f6Sopenharmony_ci           connections also, to handle embedded-system errors */
488195972f6Sopenharmony_ci  err = netconn_err(conn);
489195972f6Sopenharmony_ci  if (err != ERR_OK) {
490195972f6Sopenharmony_ci    /* return pending error */
491195972f6Sopenharmony_ci    return err;
492195972f6Sopenharmony_ci  }
493195972f6Sopenharmony_ci  if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
494195972f6Sopenharmony_ci    /* don't accept if closed: this might block the application task
495195972f6Sopenharmony_ci       waiting on acceptmbox forever! */
496195972f6Sopenharmony_ci    return ERR_CLSD;
497195972f6Sopenharmony_ci  }
498195972f6Sopenharmony_ci
499195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC_ACCEPT(msg);
500195972f6Sopenharmony_ci
501195972f6Sopenharmony_ci  NETCONN_MBOX_WAITING_INC(conn);
502195972f6Sopenharmony_ci  if (netconn_is_nonblocking(conn)) {
503195972f6Sopenharmony_ci    if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_MBOX_EMPTY) {
504195972f6Sopenharmony_ci      API_MSG_VAR_FREE_ACCEPT(msg);
505195972f6Sopenharmony_ci      NETCONN_MBOX_WAITING_DEC(conn);
506195972f6Sopenharmony_ci      return ERR_WOULDBLOCK;
507195972f6Sopenharmony_ci    }
508195972f6Sopenharmony_ci  } else {
509195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO
510195972f6Sopenharmony_ci    if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
511195972f6Sopenharmony_ci      API_MSG_VAR_FREE_ACCEPT(msg);
512195972f6Sopenharmony_ci      NETCONN_MBOX_WAITING_DEC(conn);
513195972f6Sopenharmony_ci      return ERR_TIMEOUT;
514195972f6Sopenharmony_ci    }
515195972f6Sopenharmony_ci#else
516195972f6Sopenharmony_ci    sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
517195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO*/
518195972f6Sopenharmony_ci  }
519195972f6Sopenharmony_ci  NETCONN_MBOX_WAITING_DEC(conn);
520195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
521195972f6Sopenharmony_ci  if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
522195972f6Sopenharmony_ci    if (lwip_netconn_is_deallocated_msg(accept_ptr)) {
523195972f6Sopenharmony_ci      /* the netconn has been closed from another thread */
524195972f6Sopenharmony_ci      API_MSG_VAR_FREE_ACCEPT(msg);
525195972f6Sopenharmony_ci      return ERR_CONN;
526195972f6Sopenharmony_ci    }
527195972f6Sopenharmony_ci  }
528195972f6Sopenharmony_ci#endif
529195972f6Sopenharmony_ci
530195972f6Sopenharmony_ci  /* Register event with callback */
531195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
532195972f6Sopenharmony_ci
533195972f6Sopenharmony_ci  if (lwip_netconn_is_err_msg(accept_ptr, &err)) {
534195972f6Sopenharmony_ci    /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */
535195972f6Sopenharmony_ci    API_MSG_VAR_FREE_ACCEPT(msg);
536195972f6Sopenharmony_ci    return err;
537195972f6Sopenharmony_ci  }
538195972f6Sopenharmony_ci  if (accept_ptr == NULL) {
539195972f6Sopenharmony_ci    /* connection has been aborted */
540195972f6Sopenharmony_ci    API_MSG_VAR_FREE_ACCEPT(msg);
541195972f6Sopenharmony_ci    return ERR_CLSD;
542195972f6Sopenharmony_ci  }
543195972f6Sopenharmony_ci  newconn = (struct netconn *)accept_ptr;
544195972f6Sopenharmony_ci#if TCP_LISTEN_BACKLOG
545195972f6Sopenharmony_ci  /* Let the stack know that we have accepted the connection. */
546195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = newconn;
547195972f6Sopenharmony_ci  /* don't care for the return value of lwip_netconn_do_recv */
548195972f6Sopenharmony_ci  netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
549195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
550195972f6Sopenharmony_ci#endif /* TCP_LISTEN_BACKLOG */
551195972f6Sopenharmony_ci
552195972f6Sopenharmony_ci  *new_conn = newconn;
553195972f6Sopenharmony_ci  /* don't set conn->last_err: it's only ERR_OK, anyway */
554195972f6Sopenharmony_ci  return ERR_OK;
555195972f6Sopenharmony_ci#else /* LWIP_TCP */
556195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(conn);
557195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(new_conn);
558195972f6Sopenharmony_ci  return ERR_ARG;
559195972f6Sopenharmony_ci#endif /* LWIP_TCP */
560195972f6Sopenharmony_ci}
561195972f6Sopenharmony_ci
562195972f6Sopenharmony_ci/**
563195972f6Sopenharmony_ci * @ingroup netconn_common
564195972f6Sopenharmony_ci * Receive data: actual implementation that doesn't care whether pbuf or netbuf
565195972f6Sopenharmony_ci * is received (this is internal, it's just here for describing common errors)
566195972f6Sopenharmony_ci *
567195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
568195972f6Sopenharmony_ci * @param new_buf pointer where a new pbuf/netbuf is stored when received data
569195972f6Sopenharmony_ci * @param apiflags flags that control function behaviour. For now only:
570195972f6Sopenharmony_ci * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
571195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
572195972f6Sopenharmony_ci *                memory error or another error)
573195972f6Sopenharmony_ci *         ERR_CONN if not connected
574195972f6Sopenharmony_ci *         ERR_CLSD if TCP connection has been closed
575195972f6Sopenharmony_ci *         ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data
576195972f6Sopenharmony_ci *         ERR_TIMEOUT if the netconn has a receive timeout and no data was received
577195972f6Sopenharmony_ci */
578195972f6Sopenharmony_cistatic err_t
579195972f6Sopenharmony_cinetconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
580195972f6Sopenharmony_ci{
581195972f6Sopenharmony_ci  void *buf = NULL;
582195972f6Sopenharmony_ci  u16_t len;
583195972f6Sopenharmony_ci
584195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
585195972f6Sopenharmony_ci  *new_buf = NULL;
586195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
587195972f6Sopenharmony_ci
588195972f6Sopenharmony_ci  if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
589195972f6Sopenharmony_ci    err_t err = netconn_err(conn);
590195972f6Sopenharmony_ci    if (err != ERR_OK) {
591195972f6Sopenharmony_ci      /* return pending error */
592195972f6Sopenharmony_ci      return err;
593195972f6Sopenharmony_ci    }
594195972f6Sopenharmony_ci    return ERR_CONN;
595195972f6Sopenharmony_ci  }
596195972f6Sopenharmony_ci
597195972f6Sopenharmony_ci  NETCONN_MBOX_WAITING_INC(conn);
598195972f6Sopenharmony_ci  if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
599195972f6Sopenharmony_ci      (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) {
600195972f6Sopenharmony_ci    if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_MBOX_EMPTY) {
601195972f6Sopenharmony_ci      err_t err;
602195972f6Sopenharmony_ci      NETCONN_MBOX_WAITING_DEC(conn);
603195972f6Sopenharmony_ci      err = netconn_err(conn);
604195972f6Sopenharmony_ci      if (err != ERR_OK) {
605195972f6Sopenharmony_ci        /* return pending error */
606195972f6Sopenharmony_ci        return err;
607195972f6Sopenharmony_ci      }
608195972f6Sopenharmony_ci      if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
609195972f6Sopenharmony_ci        return ERR_CONN;
610195972f6Sopenharmony_ci      }
611195972f6Sopenharmony_ci      return ERR_WOULDBLOCK;
612195972f6Sopenharmony_ci    }
613195972f6Sopenharmony_ci  } else {
614195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO
615195972f6Sopenharmony_ci    if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
616195972f6Sopenharmony_ci      NETCONN_MBOX_WAITING_DEC(conn);
617195972f6Sopenharmony_ci      return ERR_TIMEOUT;
618195972f6Sopenharmony_ci    }
619195972f6Sopenharmony_ci#else
620195972f6Sopenharmony_ci    sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
621195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO*/
622195972f6Sopenharmony_ci  }
623195972f6Sopenharmony_ci  NETCONN_MBOX_WAITING_DEC(conn);
624195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX
625195972f6Sopenharmony_ci  if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
626195972f6Sopenharmony_ci    if (lwip_netconn_is_deallocated_msg(buf)) {
627195972f6Sopenharmony_ci      /* the netconn has been closed from another thread */
628195972f6Sopenharmony_ci      API_MSG_VAR_FREE_ACCEPT(msg);
629195972f6Sopenharmony_ci      return ERR_CONN;
630195972f6Sopenharmony_ci    }
631195972f6Sopenharmony_ci  }
632195972f6Sopenharmony_ci#endif
633195972f6Sopenharmony_ci
634195972f6Sopenharmony_ci#if LWIP_TCP
635195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW)
636195972f6Sopenharmony_ci  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
637195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */
638195972f6Sopenharmony_ci  {
639195972f6Sopenharmony_ci    err_t err;
640195972f6Sopenharmony_ci    /* Check if this is an error message or a pbuf */
641195972f6Sopenharmony_ci    if (lwip_netconn_is_err_msg(buf, &err)) {
642195972f6Sopenharmony_ci      /* new_buf has been zeroed above already */
643195972f6Sopenharmony_ci      if (err == ERR_CLSD) {
644195972f6Sopenharmony_ci        /* connection closed translates to ERR_OK with *new_buf == NULL */
645195972f6Sopenharmony_ci        return ERR_OK;
646195972f6Sopenharmony_ci      }
647195972f6Sopenharmony_ci      return err;
648195972f6Sopenharmony_ci    }
649195972f6Sopenharmony_ci    len = ((struct pbuf *)buf)->tot_len;
650195972f6Sopenharmony_ci  }
651195972f6Sopenharmony_ci#endif /* LWIP_TCP */
652195972f6Sopenharmony_ci#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
653195972f6Sopenharmony_ci  else
654195972f6Sopenharmony_ci#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
655195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW)
656195972f6Sopenharmony_ci  {
657195972f6Sopenharmony_ci    LWIP_ASSERT("buf != NULL", buf != NULL);
658195972f6Sopenharmony_ci    len = netbuf_len((struct netbuf *)buf);
659195972f6Sopenharmony_ci  }
660195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */
661195972f6Sopenharmony_ci
662195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF
663195972f6Sopenharmony_ci  SYS_ARCH_DEC(conn->recv_avail, len);
664195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */
665195972f6Sopenharmony_ci  /* Register event with callback */
666195972f6Sopenharmony_ci  API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
667195972f6Sopenharmony_ci
668195972f6Sopenharmony_ci  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
669195972f6Sopenharmony_ci
670195972f6Sopenharmony_ci  *new_buf = buf;
671195972f6Sopenharmony_ci  /* don't set conn->last_err: it's only ERR_OK, anyway */
672195972f6Sopenharmony_ci  return ERR_OK;
673195972f6Sopenharmony_ci}
674195972f6Sopenharmony_ci
675195972f6Sopenharmony_ci#if LWIP_TCP
676195972f6Sopenharmony_cistatic err_t
677195972f6Sopenharmony_cinetconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg)
678195972f6Sopenharmony_ci{
679195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
680195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
681195972f6Sopenharmony_ci
682195972f6Sopenharmony_ci  msg->conn = conn;
683195972f6Sopenharmony_ci  msg->msg.r.len = len;
684195972f6Sopenharmony_ci
685195972f6Sopenharmony_ci  return netconn_apimsg(lwip_netconn_do_recv, msg);
686195972f6Sopenharmony_ci}
687195972f6Sopenharmony_ci
688195972f6Sopenharmony_cierr_t
689195972f6Sopenharmony_cinetconn_tcp_recvd(struct netconn *conn, size_t len)
690195972f6Sopenharmony_ci{
691195972f6Sopenharmony_ci  err_t err;
692195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
693195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
694195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
695195972f6Sopenharmony_ci
696195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
697195972f6Sopenharmony_ci  err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
698195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
699195972f6Sopenharmony_ci  return err;
700195972f6Sopenharmony_ci}
701195972f6Sopenharmony_ci
702195972f6Sopenharmony_cistatic err_t
703195972f6Sopenharmony_cinetconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
704195972f6Sopenharmony_ci{
705195972f6Sopenharmony_ci  err_t err;
706195972f6Sopenharmony_ci  struct pbuf *buf;
707195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
708195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE
709195972f6Sopenharmony_ci  msg = NULL;
710195972f6Sopenharmony_ci#endif
711195972f6Sopenharmony_ci
712195972f6Sopenharmony_ci  if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
713195972f6Sopenharmony_ci    /* This only happens when calling this function more than once *after* receiving FIN */
714195972f6Sopenharmony_ci    return ERR_CONN;
715195972f6Sopenharmony_ci  }
716195972f6Sopenharmony_ci  if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) {
717195972f6Sopenharmony_ci    netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING);
718195972f6Sopenharmony_ci    goto handle_fin;
719195972f6Sopenharmony_ci  }
720195972f6Sopenharmony_ci
721195972f6Sopenharmony_ci  if (!(apiflags & NETCONN_NOAUTORCVD)) {
722195972f6Sopenharmony_ci    /* need to allocate API message here so empty message pool does not result in event loss
723195972f6Sopenharmony_ci      * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
724195972f6Sopenharmony_ci    API_MSG_VAR_ALLOC(msg);
725195972f6Sopenharmony_ci  }
726195972f6Sopenharmony_ci
727195972f6Sopenharmony_ci  err = netconn_recv_data(conn, (void **)new_buf, apiflags);
728195972f6Sopenharmony_ci  if (err != ERR_OK) {
729195972f6Sopenharmony_ci    if (!(apiflags & NETCONN_NOAUTORCVD)) {
730195972f6Sopenharmony_ci      API_MSG_VAR_FREE(msg);
731195972f6Sopenharmony_ci    }
732195972f6Sopenharmony_ci    return err;
733195972f6Sopenharmony_ci  }
734195972f6Sopenharmony_ci  buf = *new_buf;
735195972f6Sopenharmony_ci  if (!(apiflags & NETCONN_NOAUTORCVD)) {
736195972f6Sopenharmony_ci    /* Let the stack know that we have taken the data. */
737195972f6Sopenharmony_ci    u16_t len = buf ? buf->tot_len : 1;
738195972f6Sopenharmony_ci    /* don't care for the return value of lwip_netconn_do_recv */
739195972f6Sopenharmony_ci    /* @todo: this should really be fixed, e.g. by retrying in poll on error */
740195972f6Sopenharmony_ci    netconn_tcp_recvd_msg(conn, len,  &API_VAR_REF(msg));
741195972f6Sopenharmony_ci    API_MSG_VAR_FREE(msg);
742195972f6Sopenharmony_ci  }
743195972f6Sopenharmony_ci
744195972f6Sopenharmony_ci  /* If we are closed, we indicate that we no longer wish to use the socket */
745195972f6Sopenharmony_ci  if (buf == NULL) {
746195972f6Sopenharmony_ci    if (apiflags & NETCONN_NOFIN) {
747195972f6Sopenharmony_ci      /* received a FIN but the caller cannot handle it right now:
748195972f6Sopenharmony_ci         re-enqueue it and return "no data" */
749195972f6Sopenharmony_ci      netconn_set_flags(conn, NETCONN_FIN_RX_PENDING);
750195972f6Sopenharmony_ci      return ERR_WOULDBLOCK;
751195972f6Sopenharmony_ci    } else {
752195972f6Sopenharmony_cihandle_fin:
753195972f6Sopenharmony_ci      API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
754195972f6Sopenharmony_ci      if (conn->pcb.ip == NULL) {
755195972f6Sopenharmony_ci        /* race condition: RST during recv */
756195972f6Sopenharmony_ci        err = netconn_err(conn);
757195972f6Sopenharmony_ci        if (err != ERR_OK) {
758195972f6Sopenharmony_ci          return err;
759195972f6Sopenharmony_ci        }
760195972f6Sopenharmony_ci        return ERR_RST;
761195972f6Sopenharmony_ci      }
762195972f6Sopenharmony_ci      /* RX side is closed, so deallocate the recvmbox */
763195972f6Sopenharmony_ci      netconn_close_shutdown(conn, NETCONN_SHUT_RD);
764195972f6Sopenharmony_ci      /* Don' store ERR_CLSD as conn->err since we are only half-closed */
765195972f6Sopenharmony_ci      return ERR_CLSD;
766195972f6Sopenharmony_ci    }
767195972f6Sopenharmony_ci  }
768195972f6Sopenharmony_ci  return err;
769195972f6Sopenharmony_ci}
770195972f6Sopenharmony_ci
771195972f6Sopenharmony_ci/**
772195972f6Sopenharmony_ci * @ingroup netconn_tcp
773195972f6Sopenharmony_ci * Receive data (in form of a pbuf) from a TCP netconn
774195972f6Sopenharmony_ci *
775195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
776195972f6Sopenharmony_ci * @param new_buf pointer where a new pbuf is stored when received data
777195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
778195972f6Sopenharmony_ci *                memory error or another error, @see netconn_recv_data)
779195972f6Sopenharmony_ci *         ERR_ARG if conn is not a TCP netconn
780195972f6Sopenharmony_ci */
781195972f6Sopenharmony_cierr_t
782195972f6Sopenharmony_cinetconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
783195972f6Sopenharmony_ci{
784195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
785195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
786195972f6Sopenharmony_ci
787195972f6Sopenharmony_ci  return netconn_recv_data_tcp(conn, new_buf, 0);
788195972f6Sopenharmony_ci}
789195972f6Sopenharmony_ci
790195972f6Sopenharmony_ci/**
791195972f6Sopenharmony_ci * @ingroup netconn_tcp
792195972f6Sopenharmony_ci * Receive data (in form of a pbuf) from a TCP netconn
793195972f6Sopenharmony_ci *
794195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
795195972f6Sopenharmony_ci * @param new_buf pointer where a new pbuf is stored when received data
796195972f6Sopenharmony_ci * @param apiflags flags that control function behaviour. For now only:
797195972f6Sopenharmony_ci * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
798195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
799195972f6Sopenharmony_ci *                memory error or another error, @see netconn_recv_data)
800195972f6Sopenharmony_ci *         ERR_ARG if conn is not a TCP netconn
801195972f6Sopenharmony_ci */
802195972f6Sopenharmony_cierr_t
803195972f6Sopenharmony_cinetconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
804195972f6Sopenharmony_ci{
805195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
806195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
807195972f6Sopenharmony_ci
808195972f6Sopenharmony_ci  return netconn_recv_data_tcp(conn, new_buf, apiflags);
809195972f6Sopenharmony_ci}
810195972f6Sopenharmony_ci#endif /* LWIP_TCP */
811195972f6Sopenharmony_ci
812195972f6Sopenharmony_ci/**
813195972f6Sopenharmony_ci * Receive data (in form of a netbuf) from a UDP or RAW netconn
814195972f6Sopenharmony_ci *
815195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
816195972f6Sopenharmony_ci * @param new_buf pointer where a new netbuf is stored when received data
817195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
818195972f6Sopenharmony_ci *                memory error or another error)
819195972f6Sopenharmony_ci *         ERR_ARG if conn is not a UDP/RAW netconn
820195972f6Sopenharmony_ci */
821195972f6Sopenharmony_cierr_t
822195972f6Sopenharmony_cinetconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf)
823195972f6Sopenharmony_ci{
824195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
825195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
826195972f6Sopenharmony_ci
827195972f6Sopenharmony_ci  return netconn_recv_data(conn, (void **)new_buf, 0);
828195972f6Sopenharmony_ci}
829195972f6Sopenharmony_ci
830195972f6Sopenharmony_ci/**
831195972f6Sopenharmony_ci * Receive data (in form of a netbuf) from a UDP or RAW netconn
832195972f6Sopenharmony_ci *
833195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
834195972f6Sopenharmony_ci * @param new_buf pointer where a new netbuf is stored when received data
835195972f6Sopenharmony_ci * @param apiflags flags that control function behaviour. For now only:
836195972f6Sopenharmony_ci * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
837195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
838195972f6Sopenharmony_ci *                memory error or another error)
839195972f6Sopenharmony_ci *         ERR_ARG if conn is not a UDP/RAW netconn
840195972f6Sopenharmony_ci */
841195972f6Sopenharmony_cierr_t
842195972f6Sopenharmony_cinetconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags)
843195972f6Sopenharmony_ci{
844195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
845195972f6Sopenharmony_ci             NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
846195972f6Sopenharmony_ci
847195972f6Sopenharmony_ci  return netconn_recv_data(conn, (void **)new_buf, apiflags);
848195972f6Sopenharmony_ci}
849195972f6Sopenharmony_ci
850195972f6Sopenharmony_ci/**
851195972f6Sopenharmony_ci * @ingroup netconn_common
852195972f6Sopenharmony_ci * Receive data (in form of a netbuf containing a packet buffer) from a netconn
853195972f6Sopenharmony_ci *
854195972f6Sopenharmony_ci * @param conn the netconn from which to receive data
855195972f6Sopenharmony_ci * @param new_buf pointer where a new netbuf is stored when received data
856195972f6Sopenharmony_ci * @return ERR_OK if data has been received, an error code otherwise (timeout,
857195972f6Sopenharmony_ci *                memory error or another error)
858195972f6Sopenharmony_ci */
859195972f6Sopenharmony_cierr_t
860195972f6Sopenharmony_cinetconn_recv(struct netconn *conn, struct netbuf **new_buf)
861195972f6Sopenharmony_ci{
862195972f6Sopenharmony_ci#if LWIP_TCP
863195972f6Sopenharmony_ci  struct netbuf *buf = NULL;
864195972f6Sopenharmony_ci  err_t err;
865195972f6Sopenharmony_ci#endif /* LWIP_TCP */
866195972f6Sopenharmony_ci
867195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
868195972f6Sopenharmony_ci  *new_buf = NULL;
869195972f6Sopenharmony_ci  LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
870195972f6Sopenharmony_ci
871195972f6Sopenharmony_ci#if LWIP_TCP
872195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW)
873195972f6Sopenharmony_ci  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
874195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */
875195972f6Sopenharmony_ci  {
876195972f6Sopenharmony_ci    struct pbuf *p = NULL;
877195972f6Sopenharmony_ci    /* This is not a listening netconn, since recvmbox is set */
878195972f6Sopenharmony_ci
879195972f6Sopenharmony_ci    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
880195972f6Sopenharmony_ci    if (buf == NULL) {
881195972f6Sopenharmony_ci      return ERR_MEM;
882195972f6Sopenharmony_ci    }
883195972f6Sopenharmony_ci
884195972f6Sopenharmony_ci    err = netconn_recv_data_tcp(conn, &p, 0);
885195972f6Sopenharmony_ci    if (err != ERR_OK) {
886195972f6Sopenharmony_ci      memp_free(MEMP_NETBUF, buf);
887195972f6Sopenharmony_ci      return err;
888195972f6Sopenharmony_ci    }
889195972f6Sopenharmony_ci    LWIP_ASSERT("p != NULL", p != NULL);
890195972f6Sopenharmony_ci
891195972f6Sopenharmony_ci    buf->p = p;
892195972f6Sopenharmony_ci    buf->ptr = p;
893195972f6Sopenharmony_ci    buf->port = 0;
894195972f6Sopenharmony_ci    ip_addr_set_zero(&buf->addr);
895195972f6Sopenharmony_ci    *new_buf = buf;
896195972f6Sopenharmony_ci    /* don't set conn->last_err: it's only ERR_OK, anyway */
897195972f6Sopenharmony_ci    return ERR_OK;
898195972f6Sopenharmony_ci  }
899195972f6Sopenharmony_ci#endif /* LWIP_TCP */
900195972f6Sopenharmony_ci#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
901195972f6Sopenharmony_ci  else
902195972f6Sopenharmony_ci#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
903195972f6Sopenharmony_ci  {
904195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW)
905195972f6Sopenharmony_ci    return netconn_recv_data(conn, (void **)new_buf, 0);
906195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */
907195972f6Sopenharmony_ci  }
908195972f6Sopenharmony_ci}
909195972f6Sopenharmony_ci
910195972f6Sopenharmony_ci/**
911195972f6Sopenharmony_ci * @ingroup netconn_udp
912195972f6Sopenharmony_ci * Send data (in form of a netbuf) to a specific remote IP address and port.
913195972f6Sopenharmony_ci * Only to be used for UDP and RAW netconns (not TCP).
914195972f6Sopenharmony_ci *
915195972f6Sopenharmony_ci * @param conn the netconn over which to send data
916195972f6Sopenharmony_ci * @param buf a netbuf containing the data to send
917195972f6Sopenharmony_ci * @param addr the remote IP address to which to send the data
918195972f6Sopenharmony_ci * @param port the remote port to which to send the data
919195972f6Sopenharmony_ci * @return ERR_OK if data was sent, any other err_t on error
920195972f6Sopenharmony_ci */
921195972f6Sopenharmony_cierr_t
922195972f6Sopenharmony_cinetconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
923195972f6Sopenharmony_ci{
924195972f6Sopenharmony_ci  if (buf != NULL) {
925195972f6Sopenharmony_ci    ip_addr_set(&buf->addr, addr);
926195972f6Sopenharmony_ci    buf->port = port;
927195972f6Sopenharmony_ci    return netconn_send(conn, buf);
928195972f6Sopenharmony_ci  }
929195972f6Sopenharmony_ci  return ERR_VAL;
930195972f6Sopenharmony_ci}
931195972f6Sopenharmony_ci
932195972f6Sopenharmony_ci/**
933195972f6Sopenharmony_ci * @ingroup netconn_udp
934195972f6Sopenharmony_ci * Send data over a UDP or RAW netconn (that is already connected).
935195972f6Sopenharmony_ci *
936195972f6Sopenharmony_ci * @param conn the UDP or RAW netconn over which to send data
937195972f6Sopenharmony_ci * @param buf a netbuf containing the data to send
938195972f6Sopenharmony_ci * @return ERR_OK if data was sent, any other err_t on error
939195972f6Sopenharmony_ci */
940195972f6Sopenharmony_cierr_t
941195972f6Sopenharmony_cinetconn_send(struct netconn *conn, struct netbuf *buf)
942195972f6Sopenharmony_ci{
943195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
944195972f6Sopenharmony_ci  err_t err;
945195972f6Sopenharmony_ci
946195972f6Sopenharmony_ci  LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
947195972f6Sopenharmony_ci
948195972f6Sopenharmony_ci  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
949195972f6Sopenharmony_ci
950195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
951195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
952195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.b = buf;
953195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
954195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
955195972f6Sopenharmony_ci
956195972f6Sopenharmony_ci  return err;
957195972f6Sopenharmony_ci}
958195972f6Sopenharmony_ci
959195972f6Sopenharmony_ci/**
960195972f6Sopenharmony_ci * @ingroup netconn_tcp
961195972f6Sopenharmony_ci * Send data over a TCP netconn.
962195972f6Sopenharmony_ci *
963195972f6Sopenharmony_ci * @param conn the TCP netconn over which to send data
964195972f6Sopenharmony_ci * @param dataptr pointer to the application buffer that contains the data to send
965195972f6Sopenharmony_ci * @param size size of the application data to send
966195972f6Sopenharmony_ci * @param apiflags combination of following flags :
967195972f6Sopenharmony_ci * - NETCONN_COPY: data will be copied into memory belonging to the stack
968195972f6Sopenharmony_ci * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
969195972f6Sopenharmony_ci * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
970195972f6Sopenharmony_ci * @param bytes_written pointer to a location that receives the number of written bytes
971195972f6Sopenharmony_ci * @return ERR_OK if data was sent, any other err_t on error
972195972f6Sopenharmony_ci */
973195972f6Sopenharmony_cierr_t
974195972f6Sopenharmony_cinetconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
975195972f6Sopenharmony_ci                     u8_t apiflags, size_t *bytes_written)
976195972f6Sopenharmony_ci{
977195972f6Sopenharmony_ci  struct netvector vector;
978195972f6Sopenharmony_ci  vector.ptr = dataptr;
979195972f6Sopenharmony_ci  vector.len = size;
980195972f6Sopenharmony_ci  return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written);
981195972f6Sopenharmony_ci}
982195972f6Sopenharmony_ci
983195972f6Sopenharmony_ci/**
984195972f6Sopenharmony_ci * Send vectorized data atomically over a TCP netconn.
985195972f6Sopenharmony_ci *
986195972f6Sopenharmony_ci * @param conn the TCP netconn over which to send data
987195972f6Sopenharmony_ci * @param vectors array of vectors containing data to send
988195972f6Sopenharmony_ci * @param vectorcnt number of vectors in the array
989195972f6Sopenharmony_ci * @param apiflags combination of following flags :
990195972f6Sopenharmony_ci * - NETCONN_COPY: data will be copied into memory belonging to the stack
991195972f6Sopenharmony_ci * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
992195972f6Sopenharmony_ci * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
993195972f6Sopenharmony_ci * @param bytes_written pointer to a location that receives the number of written bytes
994195972f6Sopenharmony_ci * @return ERR_OK if data was sent, any other err_t on error
995195972f6Sopenharmony_ci */
996195972f6Sopenharmony_cierr_t
997195972f6Sopenharmony_cinetconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt,
998195972f6Sopenharmony_ci                             u8_t apiflags, size_t *bytes_written)
999195972f6Sopenharmony_ci{
1000195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
1001195972f6Sopenharmony_ci  err_t err;
1002195972f6Sopenharmony_ci  u8_t dontblock;
1003195972f6Sopenharmony_ci  size_t size;
1004195972f6Sopenharmony_ci  int i;
1005195972f6Sopenharmony_ci
1006195972f6Sopenharmony_ci  LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
1007195972f6Sopenharmony_ci  LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;);
1008195972f6Sopenharmony_ci  dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
1009195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO
1010195972f6Sopenharmony_ci  if (conn->send_timeout != 0) {
1011195972f6Sopenharmony_ci    dontblock = 1;
1012195972f6Sopenharmony_ci  }
1013195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */
1014195972f6Sopenharmony_ci  if (dontblock && !bytes_written) {
1015195972f6Sopenharmony_ci    /* This implies netconn_write() cannot be used for non-blocking send, since
1016195972f6Sopenharmony_ci       it has no way to return the number of bytes written. */
1017195972f6Sopenharmony_ci    return ERR_VAL;
1018195972f6Sopenharmony_ci  }
1019195972f6Sopenharmony_ci
1020195972f6Sopenharmony_ci  /* sum up the total size */
1021195972f6Sopenharmony_ci  size = 0;
1022195972f6Sopenharmony_ci  for (i = 0; i < vectorcnt; i++) {
1023195972f6Sopenharmony_ci    size += vectors[i].len;
1024195972f6Sopenharmony_ci    if (size < vectors[i].len) {
1025195972f6Sopenharmony_ci      /* overflow */
1026195972f6Sopenharmony_ci      return ERR_VAL;
1027195972f6Sopenharmony_ci    }
1028195972f6Sopenharmony_ci  }
1029195972f6Sopenharmony_ci  if (size == 0) {
1030195972f6Sopenharmony_ci    return ERR_OK;
1031195972f6Sopenharmony_ci  } else if (size > SSIZE_MAX) {
1032195972f6Sopenharmony_ci    ssize_t limited;
1033195972f6Sopenharmony_ci    /* this is required by the socket layer (cannot send full size_t range) */
1034195972f6Sopenharmony_ci    if (!bytes_written) {
1035195972f6Sopenharmony_ci      return ERR_VAL;
1036195972f6Sopenharmony_ci    }
1037195972f6Sopenharmony_ci    /* limit the amount of data to send */
1038195972f6Sopenharmony_ci    limited = SSIZE_MAX;
1039195972f6Sopenharmony_ci    size = (size_t)limited;
1040195972f6Sopenharmony_ci  }
1041195972f6Sopenharmony_ci
1042195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
1043195972f6Sopenharmony_ci  /* non-blocking write sends as much  */
1044195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
1045195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.vector = vectors;
1046195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt;
1047195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.vector_off = 0;
1048195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
1049195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.len = size;
1050195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.w.offset = 0;
1051195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO
1052195972f6Sopenharmony_ci  if (conn->send_timeout != 0) {
1053195972f6Sopenharmony_ci    /* get the time we started, which is later compared to
1054195972f6Sopenharmony_ci        sys_now() + conn->send_timeout */
1055195972f6Sopenharmony_ci    API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
1056195972f6Sopenharmony_ci  } else {
1057195972f6Sopenharmony_ci    API_MSG_VAR_REF(msg).msg.w.time_started = 0;
1058195972f6Sopenharmony_ci  }
1059195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */
1060195972f6Sopenharmony_ci
1061195972f6Sopenharmony_ci  /* For locking the core: this _can_ be delayed on low memory/low send buffer,
1062195972f6Sopenharmony_ci     but if it is, this is done inside api_msg.c:do_write(), so we can use the
1063195972f6Sopenharmony_ci     non-blocking version here. */
1064195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
1065195972f6Sopenharmony_ci  if (err == ERR_OK) {
1066195972f6Sopenharmony_ci    if (bytes_written != NULL) {
1067195972f6Sopenharmony_ci      *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset;
1068195972f6Sopenharmony_ci    }
1069195972f6Sopenharmony_ci    /* for blocking, check all requested bytes were written, NOTE: send_timeout is
1070195972f6Sopenharmony_ci       treated as dontblock (see dontblock assignment above) */
1071195972f6Sopenharmony_ci    if (!dontblock) {
1072195972f6Sopenharmony_ci      LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size);
1073195972f6Sopenharmony_ci    }
1074195972f6Sopenharmony_ci  }
1075195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
1076195972f6Sopenharmony_ci
1077195972f6Sopenharmony_ci  return err;
1078195972f6Sopenharmony_ci}
1079195972f6Sopenharmony_ci
1080195972f6Sopenharmony_ci/**
1081195972f6Sopenharmony_ci * @ingroup netconn_tcp
1082195972f6Sopenharmony_ci * Close or shutdown a TCP netconn (doesn't delete it).
1083195972f6Sopenharmony_ci *
1084195972f6Sopenharmony_ci * @param conn the TCP netconn to close or shutdown
1085195972f6Sopenharmony_ci * @param how fully close or only shutdown one side?
1086195972f6Sopenharmony_ci * @return ERR_OK if the netconn was closed, any other err_t on error
1087195972f6Sopenharmony_ci */
1088195972f6Sopenharmony_cistatic err_t
1089195972f6Sopenharmony_cinetconn_close_shutdown(struct netconn *conn, u8_t how)
1090195972f6Sopenharmony_ci{
1091195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
1092195972f6Sopenharmony_ci  err_t err;
1093195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(how);
1094195972f6Sopenharmony_ci
1095195972f6Sopenharmony_ci  LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
1096195972f6Sopenharmony_ci
1097195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
1098195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
1099195972f6Sopenharmony_ci#if LWIP_TCP
1100195972f6Sopenharmony_ci  /* shutting down both ends is the same as closing */
1101195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.sd.shut = how;
1102195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
1103195972f6Sopenharmony_ci  /* get the time we started, which is later compared to
1104195972f6Sopenharmony_ci     sys_now() + conn->send_timeout */
1105195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
1106195972f6Sopenharmony_ci#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1107195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.sd.polls_left =
1108195972f6Sopenharmony_ci    ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
1109195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
1110195972f6Sopenharmony_ci#endif /* LWIP_TCP */
1111195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
1112195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
1113195972f6Sopenharmony_ci
1114195972f6Sopenharmony_ci  return err;
1115195972f6Sopenharmony_ci}
1116195972f6Sopenharmony_ci
1117195972f6Sopenharmony_ci/**
1118195972f6Sopenharmony_ci * @ingroup netconn_tcp
1119195972f6Sopenharmony_ci * Close a TCP netconn (doesn't delete it).
1120195972f6Sopenharmony_ci *
1121195972f6Sopenharmony_ci * @param conn the TCP netconn to close
1122195972f6Sopenharmony_ci * @return ERR_OK if the netconn was closed, any other err_t on error
1123195972f6Sopenharmony_ci */
1124195972f6Sopenharmony_cierr_t
1125195972f6Sopenharmony_cinetconn_close(struct netconn *conn)
1126195972f6Sopenharmony_ci{
1127195972f6Sopenharmony_ci  /* shutting down both ends is the same as closing */
1128195972f6Sopenharmony_ci  return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
1129195972f6Sopenharmony_ci}
1130195972f6Sopenharmony_ci
1131195972f6Sopenharmony_ci/**
1132195972f6Sopenharmony_ci * @ingroup netconn_common
1133195972f6Sopenharmony_ci * Get and reset pending error on a netconn
1134195972f6Sopenharmony_ci *
1135195972f6Sopenharmony_ci * @param conn the netconn to get the error from
1136195972f6Sopenharmony_ci * @return and pending error or ERR_OK if no error was pending
1137195972f6Sopenharmony_ci */
1138195972f6Sopenharmony_cierr_t
1139195972f6Sopenharmony_cinetconn_err(struct netconn *conn)
1140195972f6Sopenharmony_ci{
1141195972f6Sopenharmony_ci  err_t err;
1142195972f6Sopenharmony_ci  SYS_ARCH_DECL_PROTECT(lev);
1143195972f6Sopenharmony_ci  if (conn == NULL) {
1144195972f6Sopenharmony_ci    return ERR_OK;
1145195972f6Sopenharmony_ci  }
1146195972f6Sopenharmony_ci  SYS_ARCH_PROTECT(lev);
1147195972f6Sopenharmony_ci  err = conn->pending_err;
1148195972f6Sopenharmony_ci  conn->pending_err = ERR_OK;
1149195972f6Sopenharmony_ci  SYS_ARCH_UNPROTECT(lev);
1150195972f6Sopenharmony_ci  return err;
1151195972f6Sopenharmony_ci}
1152195972f6Sopenharmony_ci
1153195972f6Sopenharmony_ci/**
1154195972f6Sopenharmony_ci * @ingroup netconn_tcp
1155195972f6Sopenharmony_ci * Shut down one or both sides of a TCP netconn (doesn't delete it).
1156195972f6Sopenharmony_ci *
1157195972f6Sopenharmony_ci * @param conn the TCP netconn to shut down
1158195972f6Sopenharmony_ci * @param shut_rx shut down the RX side (no more read possible after this)
1159195972f6Sopenharmony_ci * @param shut_tx shut down the TX side (no more write possible after this)
1160195972f6Sopenharmony_ci * @return ERR_OK if the netconn was closed, any other err_t on error
1161195972f6Sopenharmony_ci */
1162195972f6Sopenharmony_cierr_t
1163195972f6Sopenharmony_cinetconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
1164195972f6Sopenharmony_ci{
1165195972f6Sopenharmony_ci  return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)));
1166195972f6Sopenharmony_ci}
1167195972f6Sopenharmony_ci
1168195972f6Sopenharmony_ci#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
1169195972f6Sopenharmony_ci/**
1170195972f6Sopenharmony_ci * @ingroup netconn_udp
1171195972f6Sopenharmony_ci * Join multicast groups for UDP netconns.
1172195972f6Sopenharmony_ci *
1173195972f6Sopenharmony_ci * @param conn the UDP netconn for which to change multicast addresses
1174195972f6Sopenharmony_ci * @param multiaddr IP address of the multicast group to join or leave
1175195972f6Sopenharmony_ci * @param netif_addr the IP address of the network interface on which to send
1176195972f6Sopenharmony_ci *                  the igmp message
1177195972f6Sopenharmony_ci * @param join_or_leave flag whether to send a join- or leave-message
1178195972f6Sopenharmony_ci * @return ERR_OK if the action was taken, any err_t on error
1179195972f6Sopenharmony_ci */
1180195972f6Sopenharmony_cierr_t
1181195972f6Sopenharmony_cinetconn_join_leave_group(struct netconn *conn,
1182195972f6Sopenharmony_ci                         const ip_addr_t *multiaddr,
1183195972f6Sopenharmony_ci                         const ip_addr_t *netif_addr,
1184195972f6Sopenharmony_ci                         enum netconn_igmp join_or_leave)
1185195972f6Sopenharmony_ci{
1186195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
1187195972f6Sopenharmony_ci  err_t err;
1188195972f6Sopenharmony_ci
1189195972f6Sopenharmony_ci  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
1190195972f6Sopenharmony_ci
1191195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
1192195972f6Sopenharmony_ci
1193195972f6Sopenharmony_ci#if LWIP_IPV4
1194195972f6Sopenharmony_ci  /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1195195972f6Sopenharmony_ci  if (multiaddr == NULL) {
1196195972f6Sopenharmony_ci    multiaddr = IP4_ADDR_ANY;
1197195972f6Sopenharmony_ci  }
1198195972f6Sopenharmony_ci  if (netif_addr == NULL) {
1199195972f6Sopenharmony_ci    netif_addr = IP4_ADDR_ANY;
1200195972f6Sopenharmony_ci  }
1201195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
1202195972f6Sopenharmony_ci
1203195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
1204195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1205195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
1206195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1207195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
1208195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
1209195972f6Sopenharmony_ci
1210195972f6Sopenharmony_ci  return err;
1211195972f6Sopenharmony_ci}
1212195972f6Sopenharmony_ci/**
1213195972f6Sopenharmony_ci * @ingroup netconn_udp
1214195972f6Sopenharmony_ci * Join multicast groups for UDP netconns.
1215195972f6Sopenharmony_ci *
1216195972f6Sopenharmony_ci * @param conn the UDP netconn for which to change multicast addresses
1217195972f6Sopenharmony_ci * @param multiaddr IP address of the multicast group to join or leave
1218195972f6Sopenharmony_ci * @param if_idx the index of the netif
1219195972f6Sopenharmony_ci * @param join_or_leave flag whether to send a join- or leave-message
1220195972f6Sopenharmony_ci * @return ERR_OK if the action was taken, any err_t on error
1221195972f6Sopenharmony_ci */
1222195972f6Sopenharmony_cierr_t
1223195972f6Sopenharmony_cinetconn_join_leave_group_netif(struct netconn *conn,
1224195972f6Sopenharmony_ci                               const ip_addr_t *multiaddr,
1225195972f6Sopenharmony_ci                               u8_t if_idx,
1226195972f6Sopenharmony_ci                               enum netconn_igmp join_or_leave)
1227195972f6Sopenharmony_ci{
1228195972f6Sopenharmony_ci  API_MSG_VAR_DECLARE(msg);
1229195972f6Sopenharmony_ci  err_t err;
1230195972f6Sopenharmony_ci
1231195972f6Sopenharmony_ci  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
1232195972f6Sopenharmony_ci
1233195972f6Sopenharmony_ci  API_MSG_VAR_ALLOC(msg);
1234195972f6Sopenharmony_ci
1235195972f6Sopenharmony_ci#if LWIP_IPV4
1236195972f6Sopenharmony_ci  /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
1237195972f6Sopenharmony_ci  if (multiaddr == NULL) {
1238195972f6Sopenharmony_ci    multiaddr = IP4_ADDR_ANY;
1239195972f6Sopenharmony_ci  }
1240195972f6Sopenharmony_ci  if (if_idx == NETIF_NO_INDEX) {
1241195972f6Sopenharmony_ci    return ERR_IF;
1242195972f6Sopenharmony_ci  }
1243195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
1244195972f6Sopenharmony_ci
1245195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).conn = conn;
1246195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
1247195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx;
1248195972f6Sopenharmony_ci  API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
1249195972f6Sopenharmony_ci  err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg));
1250195972f6Sopenharmony_ci  API_MSG_VAR_FREE(msg);
1251195972f6Sopenharmony_ci
1252195972f6Sopenharmony_ci  return err;
1253195972f6Sopenharmony_ci}
1254195972f6Sopenharmony_ci#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
1255195972f6Sopenharmony_ci
1256195972f6Sopenharmony_ci#if LWIP_DNS
1257195972f6Sopenharmony_ci/**
1258195972f6Sopenharmony_ci * @ingroup netconn_common
1259195972f6Sopenharmony_ci * Execute a DNS query, only one IP address is returned
1260195972f6Sopenharmony_ci *
1261195972f6Sopenharmony_ci * @param name a string representation of the DNS host name to query
1262195972f6Sopenharmony_ci * @param addr a preallocated ip_addr_t where to store the resolved IP address
1263195972f6Sopenharmony_ci * @param dns_addrtype IP address type (IPv4 / IPv6)
1264195972f6Sopenharmony_ci * @return ERR_OK: resolving succeeded
1265195972f6Sopenharmony_ci *         ERR_MEM: memory error, try again later
1266195972f6Sopenharmony_ci *         ERR_ARG: dns client not initialized or invalid hostname
1267195972f6Sopenharmony_ci *         ERR_VAL: dns server response was invalid
1268195972f6Sopenharmony_ci */
1269195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
1270195972f6Sopenharmony_cierr_t
1271195972f6Sopenharmony_cinetconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
1272195972f6Sopenharmony_ci#else
1273195972f6Sopenharmony_cierr_t
1274195972f6Sopenharmony_cinetconn_gethostbyname(const char *name, ip_addr_t *addr)
1275195972f6Sopenharmony_ci#endif
1276195972f6Sopenharmony_ci{
1277195972f6Sopenharmony_ci  API_VAR_DECLARE(struct dns_api_msg, msg);
1278195972f6Sopenharmony_ci#if !LWIP_MPU_COMPATIBLE
1279195972f6Sopenharmony_ci  sys_sem_t sem;
1280195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */
1281195972f6Sopenharmony_ci  err_t err;
1282195972f6Sopenharmony_ci  err_t cberr;
1283195972f6Sopenharmony_ci
1284195972f6Sopenharmony_ci  LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
1285195972f6Sopenharmony_ci  LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
1286195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE
1287195972f6Sopenharmony_ci  if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
1288195972f6Sopenharmony_ci    return ERR_ARG;
1289195972f6Sopenharmony_ci  }
1290195972f6Sopenharmony_ci#endif
1291195972f6Sopenharmony_ci
1292195972f6Sopenharmony_ci#ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
1293195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
1294195972f6Sopenharmony_ci  if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) {
1295195972f6Sopenharmony_ci#else
1296195972f6Sopenharmony_ci  if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) {
1297195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */
1298195972f6Sopenharmony_ci    return err;
1299195972f6Sopenharmony_ci  }
1300195972f6Sopenharmony_ci#endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */
1301195972f6Sopenharmony_ci
1302195972f6Sopenharmony_ci  API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
1303195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE
1304195972f6Sopenharmony_ci  strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1);
1305195972f6Sopenharmony_ci  API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0;
1306195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */
1307195972f6Sopenharmony_ci  msg.err = &err;
1308195972f6Sopenharmony_ci  msg.sem = &sem;
1309195972f6Sopenharmony_ci  API_VAR_REF(msg).addr = API_VAR_REF(addr);
1310195972f6Sopenharmony_ci  API_VAR_REF(msg).name = name;
1311195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */
1312195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6
1313195972f6Sopenharmony_ci  API_VAR_REF(msg).dns_addrtype = dns_addrtype;
1314195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */
1315195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD
1316195972f6Sopenharmony_ci  API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
1317195972f6Sopenharmony_ci#else /* LWIP_NETCONN_SEM_PER_THREAD*/
1318195972f6Sopenharmony_ci  err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
1319195972f6Sopenharmony_ci  if (err != ERR_OK) {
1320195972f6Sopenharmony_ci    API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1321195972f6Sopenharmony_ci    return err;
1322195972f6Sopenharmony_ci  }
1323195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */
1324195972f6Sopenharmony_ci
1325195972f6Sopenharmony_ci  cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem));
1326195972f6Sopenharmony_ci#if !LWIP_NETCONN_SEM_PER_THREAD
1327195972f6Sopenharmony_ci  sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
1328195972f6Sopenharmony_ci#endif /* !LWIP_NETCONN_SEM_PER_THREAD */
1329195972f6Sopenharmony_ci  if (cberr != ERR_OK) {
1330195972f6Sopenharmony_ci    API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1331195972f6Sopenharmony_ci    return cberr;
1332195972f6Sopenharmony_ci  }
1333195972f6Sopenharmony_ci
1334195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE
1335195972f6Sopenharmony_ci  *addr = msg->addr;
1336195972f6Sopenharmony_ci  err = msg->err;
1337195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */
1338195972f6Sopenharmony_ci
1339195972f6Sopenharmony_ci  API_VAR_FREE(MEMP_DNS_API_MSG, msg);
1340195972f6Sopenharmony_ci  return err;
1341195972f6Sopenharmony_ci}
1342195972f6Sopenharmony_ci#endif /* LWIP_DNS*/
1343195972f6Sopenharmony_ci
1344195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD
1345195972f6Sopenharmony_civoid
1346195972f6Sopenharmony_cinetconn_thread_init(void)
1347195972f6Sopenharmony_ci{
1348195972f6Sopenharmony_ci  sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1349195972f6Sopenharmony_ci  if (!sys_sem_valid(sem)) {
1350195972f6Sopenharmony_ci    /* call alloc only once */
1351195972f6Sopenharmony_ci    LWIP_NETCONN_THREAD_SEM_ALLOC();
1352195972f6Sopenharmony_ci    LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
1353195972f6Sopenharmony_ci  }
1354195972f6Sopenharmony_ci}
1355195972f6Sopenharmony_ci
1356195972f6Sopenharmony_civoid
1357195972f6Sopenharmony_cinetconn_thread_cleanup(void)
1358195972f6Sopenharmony_ci{
1359195972f6Sopenharmony_ci  sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
1360195972f6Sopenharmony_ci  if (sys_sem_valid(sem)) {
1361195972f6Sopenharmony_ci    /* call free only once */
1362195972f6Sopenharmony_ci    LWIP_NETCONN_THREAD_SEM_FREE();
1363195972f6Sopenharmony_ci  }
1364195972f6Sopenharmony_ci}
1365195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */
1366195972f6Sopenharmony_ci
1367195972f6Sopenharmony_ci#endif /* LWIP_NETCONN */
1368