1c87c5fbaSopenharmony_ci/*
2c87c5fbaSopenharmony_ci * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
3c87c5fbaSopenharmony_ci *               2014 chrysn <chrysn@fsfe.org>
4c87c5fbaSopenharmony_ci *               2022-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
5c87c5fbaSopenharmony_ci *
6c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
7c87c5fbaSopenharmony_ci *
8c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see
9c87c5fbaSopenharmony_ci * README for terms of use.
10c87c5fbaSopenharmony_ci */
11c87c5fbaSopenharmony_ci
12c87c5fbaSopenharmony_ci/**
13c87c5fbaSopenharmony_ci * @file coap_io_lwip.c
14c87c5fbaSopenharmony_ci * @brief LwIP specific functions
15c87c5fbaSopenharmony_ci */
16c87c5fbaSopenharmony_ci
17c87c5fbaSopenharmony_ci#include "coap3/coap_internal.h"
18c87c5fbaSopenharmony_ci#include <lwip/udp.h>
19c87c5fbaSopenharmony_ci#include <lwip/timeouts.h>
20c87c5fbaSopenharmony_ci#include <lwip/tcpip.h>
21c87c5fbaSopenharmony_ci
22c87c5fbaSopenharmony_civoid
23c87c5fbaSopenharmony_cicoap_lwip_dump_memory_pools(coap_log_t log_level) {
24c87c5fbaSopenharmony_ci#if MEMP_STATS && LWIP_STATS_DISPLAY
25c87c5fbaSopenharmony_ci  int i;
26c87c5fbaSopenharmony_ci
27c87c5fbaSopenharmony_ci  /* Save time if not needed */
28c87c5fbaSopenharmony_ci  if (log_level > coap_get_log_level())
29c87c5fbaSopenharmony_ci    return;
30c87c5fbaSopenharmony_ci
31c87c5fbaSopenharmony_ci  coap_log(log_level, "*   LwIP custom memory pools information\n");
32c87c5fbaSopenharmony_ci  /*
33c87c5fbaSopenharmony_ci   * Make sure LwIP and libcoap have been built with the same
34c87c5fbaSopenharmony_ci   * -DCOAP_CLIENT_ONLY or -DCOAP_SERVER_ONLY options for
35c87c5fbaSopenharmony_ci   * MEMP_MAX to be correct.
36c87c5fbaSopenharmony_ci   */
37c87c5fbaSopenharmony_ci  for (i = 0; i < MEMP_MAX; i++) {
38c87c5fbaSopenharmony_ci    coap_log(log_level, "*    %-17s avail %3d  in-use %3d  peak %3d failed %3d\n",
39c87c5fbaSopenharmony_ci             memp_pools[i]->stats->name, memp_pools[i]->stats->avail,
40c87c5fbaSopenharmony_ci             memp_pools[i]->stats->used, memp_pools[i]->stats->max,
41c87c5fbaSopenharmony_ci             memp_pools[i]->stats->err);
42c87c5fbaSopenharmony_ci  }
43c87c5fbaSopenharmony_ci#endif /* MEMP_STATS && LWIP_STATS_DISPLAY */
44c87c5fbaSopenharmony_ci}
45c87c5fbaSopenharmony_ci
46c87c5fbaSopenharmony_civoid
47c87c5fbaSopenharmony_cicoap_lwip_set_input_wait_handler(coap_context_t *context,
48c87c5fbaSopenharmony_ci                                 coap_lwip_input_wait_handler_t handler,
49c87c5fbaSopenharmony_ci                                 void *input_arg) {
50c87c5fbaSopenharmony_ci  context->input_wait = handler;
51c87c5fbaSopenharmony_ci  context->input_arg = input_arg;
52c87c5fbaSopenharmony_ci}
53c87c5fbaSopenharmony_ci
54c87c5fbaSopenharmony_civoid
55c87c5fbaSopenharmony_cicoap_io_process_timeout(void *arg) {
56c87c5fbaSopenharmony_ci  coap_context_t *context = (coap_context_t *)arg;
57c87c5fbaSopenharmony_ci  coap_tick_t before;
58c87c5fbaSopenharmony_ci  unsigned int num_sockets;
59c87c5fbaSopenharmony_ci  unsigned int timeout;
60c87c5fbaSopenharmony_ci
61c87c5fbaSopenharmony_ci  coap_ticks(&before);
62c87c5fbaSopenharmony_ci  timeout = coap_io_prepare_io(context, NULL, 0, &num_sockets, before);
63c87c5fbaSopenharmony_ci  if (context->timer_configured) {
64c87c5fbaSopenharmony_ci    sys_untimeout(coap_io_process_timeout, (void *)context);
65c87c5fbaSopenharmony_ci    context->timer_configured = 0;
66c87c5fbaSopenharmony_ci  }
67c87c5fbaSopenharmony_ci  if (timeout == 0) {
68c87c5fbaSopenharmony_ci    /* Garbage collect 1 sec hence */
69c87c5fbaSopenharmony_ci    timeout = 1000;
70c87c5fbaSopenharmony_ci  }
71c87c5fbaSopenharmony_ci#ifdef COAP_DEBUG_WAKEUP_TIMES
72c87c5fbaSopenharmony_ci  coap_log_info("****** Next wakeup msecs %u (1)\n",
73c87c5fbaSopenharmony_ci                timeout);
74c87c5fbaSopenharmony_ci#endif /* COAP_DEBUG_WAKEUP_TIMES */
75c87c5fbaSopenharmony_ci  sys_timeout(timeout, coap_io_process_timeout, context);
76c87c5fbaSopenharmony_ci  context->timer_configured = 1;
77c87c5fbaSopenharmony_ci}
78c87c5fbaSopenharmony_ci
79c87c5fbaSopenharmony_ciint
80c87c5fbaSopenharmony_cicoap_io_process(coap_context_t *context, uint32_t timeout_ms) {
81c87c5fbaSopenharmony_ci  coap_tick_t before;
82c87c5fbaSopenharmony_ci  coap_tick_t now;
83c87c5fbaSopenharmony_ci  unsigned int num_sockets;
84c87c5fbaSopenharmony_ci  unsigned int timeout;
85c87c5fbaSopenharmony_ci
86c87c5fbaSopenharmony_ci  coap_ticks(&before);
87c87c5fbaSopenharmony_ci  timeout = coap_io_prepare_io(context, NULL, 0, &num_sockets, before);
88c87c5fbaSopenharmony_ci  if (timeout_ms != 0 && timeout_ms != COAP_IO_NO_WAIT &&
89c87c5fbaSopenharmony_ci      timeout > timeout_ms) {
90c87c5fbaSopenharmony_ci    timeout = timeout_ms;
91c87c5fbaSopenharmony_ci  }
92c87c5fbaSopenharmony_ci
93c87c5fbaSopenharmony_ci  LOCK_TCPIP_CORE();
94c87c5fbaSopenharmony_ci
95c87c5fbaSopenharmony_ci  if (context->timer_configured) {
96c87c5fbaSopenharmony_ci    sys_untimeout(coap_io_process_timeout, (void *)context);
97c87c5fbaSopenharmony_ci    context->timer_configured = 0;
98c87c5fbaSopenharmony_ci  }
99c87c5fbaSopenharmony_ci  if (timeout == 0) {
100c87c5fbaSopenharmony_ci    /* Garbage collect 1 sec hence */
101c87c5fbaSopenharmony_ci    timeout = 1000;
102c87c5fbaSopenharmony_ci  }
103c87c5fbaSopenharmony_ci#ifdef COAP_DEBUG_WAKEUP_TIMES
104c87c5fbaSopenharmony_ci  coap_log_info("****** Next wakeup msecs %u (2)\n",
105c87c5fbaSopenharmony_ci                timeout);
106c87c5fbaSopenharmony_ci#endif /* COAP_DEBUG_WAKEUP_TIMES */
107c87c5fbaSopenharmony_ci  sys_timeout(timeout, coap_io_process_timeout, context);
108c87c5fbaSopenharmony_ci  context->timer_configured = 1;
109c87c5fbaSopenharmony_ci
110c87c5fbaSopenharmony_ci  UNLOCK_TCPIP_CORE();
111c87c5fbaSopenharmony_ci
112c87c5fbaSopenharmony_ci  if (context->input_wait) {
113c87c5fbaSopenharmony_ci    context->input_wait(context->input_arg, timeout);
114c87c5fbaSopenharmony_ci  }
115c87c5fbaSopenharmony_ci
116c87c5fbaSopenharmony_ci  LOCK_TCPIP_CORE();
117c87c5fbaSopenharmony_ci
118c87c5fbaSopenharmony_ci  sys_check_timeouts();
119c87c5fbaSopenharmony_ci
120c87c5fbaSopenharmony_ci  UNLOCK_TCPIP_CORE();
121c87c5fbaSopenharmony_ci
122c87c5fbaSopenharmony_ci  coap_ticks(&now);
123c87c5fbaSopenharmony_ci  return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
124c87c5fbaSopenharmony_ci}
125c87c5fbaSopenharmony_ci
126c87c5fbaSopenharmony_ci/*
127c87c5fbaSopenharmony_ci * Not used for LwIP (done with coap_recvc()), but need dummy function.
128c87c5fbaSopenharmony_ci */
129c87c5fbaSopenharmony_cissize_t
130c87c5fbaSopenharmony_cicoap_socket_recv(coap_socket_t *sock, coap_packet_t *packet) {
131c87c5fbaSopenharmony_ci  (void)sock;
132c87c5fbaSopenharmony_ci  (void)packet;
133c87c5fbaSopenharmony_ci  assert(0);
134c87c5fbaSopenharmony_ci  return -1;
135c87c5fbaSopenharmony_ci}
136c87c5fbaSopenharmony_ci
137c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
138c87c5fbaSopenharmony_ci/** Callback from lwIP when a package was received for a client.
139c87c5fbaSopenharmony_ci *
140c87c5fbaSopenharmony_ci * The current implementation deals this to coap_dispatch immediately, but
141c87c5fbaSopenharmony_ci * other mechanisms (as storing the package in a queue and later fetching it
142c87c5fbaSopenharmony_ci * when coap_io_do_io is called) can be envisioned.
143c87c5fbaSopenharmony_ci *
144c87c5fbaSopenharmony_ci * It handles everything coap_io_do_io does on other implementations.
145c87c5fbaSopenharmony_ci */
146c87c5fbaSopenharmony_cistatic void
147c87c5fbaSopenharmony_cicoap_recvc(void *arg, struct udp_pcb *upcb, struct pbuf *p,
148c87c5fbaSopenharmony_ci           const ip_addr_t *addr, u16_t port) {
149c87c5fbaSopenharmony_ci  coap_pdu_t *pdu = NULL;
150c87c5fbaSopenharmony_ci  coap_session_t *session = (coap_session_t *)arg;
151c87c5fbaSopenharmony_ci  int result = -1;
152c87c5fbaSopenharmony_ci  (void)upcb;
153c87c5fbaSopenharmony_ci  (void)addr;
154c87c5fbaSopenharmony_ci  (void)port;
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_ci  assert(session);
157c87c5fbaSopenharmony_ci  LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
158c87c5fbaSopenharmony_ci
159c87c5fbaSopenharmony_ci  if (p->len < 4) {
160c87c5fbaSopenharmony_ci    /* Minimum size of CoAP header - ignore runt */
161c87c5fbaSopenharmony_ci    return;
162c87c5fbaSopenharmony_ci  }
163c87c5fbaSopenharmony_ci
164c87c5fbaSopenharmony_ci  coap_log_debug("*  %s: lwip:  recv %4d bytes\n",
165c87c5fbaSopenharmony_ci                 coap_session_str(session), p->len);
166c87c5fbaSopenharmony_ci  if (session->proto == COAP_PROTO_DTLS) {
167c87c5fbaSopenharmony_ci    if (session->tls) {
168c87c5fbaSopenharmony_ci      result = coap_dtls_receive(session, p->payload, p->len);
169c87c5fbaSopenharmony_ci      if (result < 0)
170c87c5fbaSopenharmony_ci        goto error;
171c87c5fbaSopenharmony_ci    }
172c87c5fbaSopenharmony_ci    pbuf_free(p);
173c87c5fbaSopenharmony_ci  } else {
174c87c5fbaSopenharmony_ci    pdu = coap_pdu_from_pbuf(p);
175c87c5fbaSopenharmony_ci    if (!pdu)
176c87c5fbaSopenharmony_ci      goto error;
177c87c5fbaSopenharmony_ci
178c87c5fbaSopenharmony_ci    if (!coap_pdu_parse(session->proto, p->payload, p->len, pdu)) {
179c87c5fbaSopenharmony_ci      goto error;
180c87c5fbaSopenharmony_ci    }
181c87c5fbaSopenharmony_ci    coap_dispatch(session->context, session, pdu);
182c87c5fbaSopenharmony_ci  }
183c87c5fbaSopenharmony_ci  coap_delete_pdu(pdu);
184c87c5fbaSopenharmony_ci  return;
185c87c5fbaSopenharmony_ci
186c87c5fbaSopenharmony_cierror:
187c87c5fbaSopenharmony_ci  /*
188c87c5fbaSopenharmony_ci   * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST
189c87c5fbaSopenharmony_ci   * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST
190c87c5fbaSopenharmony_ci   */
191c87c5fbaSopenharmony_ci  if (session)
192c87c5fbaSopenharmony_ci    coap_send_rst(session, pdu);
193c87c5fbaSopenharmony_ci  coap_delete_pdu(pdu);
194c87c5fbaSopenharmony_ci  return;
195c87c5fbaSopenharmony_ci}
196c87c5fbaSopenharmony_ci#endif /* ! COAP_CLIENT_SUPPORT */
197c87c5fbaSopenharmony_ci
198c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
199c87c5fbaSopenharmony_ci
200c87c5fbaSopenharmony_cistatic void
201c87c5fbaSopenharmony_cicoap_free_packet(coap_packet_t *packet) {
202c87c5fbaSopenharmony_ci  coap_free_type(COAP_PACKET, packet);
203c87c5fbaSopenharmony_ci}
204c87c5fbaSopenharmony_ci
205c87c5fbaSopenharmony_ci/** Callback from lwIP when a package was received for a server.
206c87c5fbaSopenharmony_ci *
207c87c5fbaSopenharmony_ci * The current implementation deals this to coap_dispatch immediately, but
208c87c5fbaSopenharmony_ci * other mechanisms (as storing the package in a queue and later fetching it
209c87c5fbaSopenharmony_ci * when coap_io_do_io is called) can be envisioned.
210c87c5fbaSopenharmony_ci *
211c87c5fbaSopenharmony_ci * It handles everything coap_io_do_io does on other implementations.
212c87c5fbaSopenharmony_ci */
213c87c5fbaSopenharmony_cistatic void
214c87c5fbaSopenharmony_cicoap_recvs(void *arg, struct udp_pcb *upcb, struct pbuf *p,
215c87c5fbaSopenharmony_ci           const ip_addr_t *addr, u16_t port) {
216c87c5fbaSopenharmony_ci  coap_endpoint_t *ep = (coap_endpoint_t *)arg;
217c87c5fbaSopenharmony_ci  coap_pdu_t *pdu = NULL;
218c87c5fbaSopenharmony_ci  coap_session_t *session = NULL;
219c87c5fbaSopenharmony_ci  coap_tick_t now;
220c87c5fbaSopenharmony_ci  coap_packet_t *packet;
221c87c5fbaSopenharmony_ci  int result = -1;
222c87c5fbaSopenharmony_ci
223c87c5fbaSopenharmony_ci  if (p->len < 4) {
224c87c5fbaSopenharmony_ci    /* Minimum size of CoAP header - ignore runt */
225c87c5fbaSopenharmony_ci    return;
226c87c5fbaSopenharmony_ci  }
227c87c5fbaSopenharmony_ci
228c87c5fbaSopenharmony_ci  packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t));
229c87c5fbaSopenharmony_ci
230c87c5fbaSopenharmony_ci  /* this is fatal because due to the short life of the packet, never should
231c87c5fbaSopenharmony_ci     there be more than one coap_packet_t required */
232c87c5fbaSopenharmony_ci  LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL);
233c87c5fbaSopenharmony_ci  /* Need to do this as there may be holes in addr_info */
234c87c5fbaSopenharmony_ci  memset(&packet->addr_info, 0, sizeof(packet->addr_info));
235c87c5fbaSopenharmony_ci  packet->length = p->len;
236c87c5fbaSopenharmony_ci  packet->payload = p->payload;
237c87c5fbaSopenharmony_ci  packet->addr_info.remote.port = port;
238c87c5fbaSopenharmony_ci  packet->addr_info.remote.addr = *addr;
239c87c5fbaSopenharmony_ci  packet->addr_info.local.port = upcb->local_port;
240c87c5fbaSopenharmony_ci  packet->addr_info.local.addr = *ip_current_dest_addr();
241c87c5fbaSopenharmony_ci  packet->ifindex = netif_get_index(ip_current_netif());
242c87c5fbaSopenharmony_ci
243c87c5fbaSopenharmony_ci  coap_ticks(&now);
244c87c5fbaSopenharmony_ci
245c87c5fbaSopenharmony_ci  session = coap_endpoint_get_session(ep, packet, now);
246c87c5fbaSopenharmony_ci  if (!session)
247c87c5fbaSopenharmony_ci    goto error;
248c87c5fbaSopenharmony_ci  LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
249c87c5fbaSopenharmony_ci
250c87c5fbaSopenharmony_ci  coap_log_debug("*  %s: lwip:  recv %4d bytes\n",
251c87c5fbaSopenharmony_ci                 coap_session_str(session), p->len);
252c87c5fbaSopenharmony_ci
253c87c5fbaSopenharmony_ci  if (session->proto == COAP_PROTO_DTLS) {
254c87c5fbaSopenharmony_ci    if (session->type == COAP_SESSION_TYPE_HELLO)
255c87c5fbaSopenharmony_ci      result = coap_dtls_hello(session, p->payload, p->len);
256c87c5fbaSopenharmony_ci    else if (session->tls)
257c87c5fbaSopenharmony_ci      result = coap_dtls_receive(session, p->payload, p->len);
258c87c5fbaSopenharmony_ci    if (session->type == COAP_SESSION_TYPE_HELLO && result == 1)
259c87c5fbaSopenharmony_ci      coap_session_new_dtls_session(session, now);
260c87c5fbaSopenharmony_ci    pbuf_free(p);
261c87c5fbaSopenharmony_ci  } else {
262c87c5fbaSopenharmony_ci    pdu = coap_pdu_from_pbuf(p);
263c87c5fbaSopenharmony_ci    if (!pdu)
264c87c5fbaSopenharmony_ci      goto error;
265c87c5fbaSopenharmony_ci
266c87c5fbaSopenharmony_ci    if (!coap_pdu_parse(ep->proto, p->payload, p->len, pdu)) {
267c87c5fbaSopenharmony_ci      goto error;
268c87c5fbaSopenharmony_ci    }
269c87c5fbaSopenharmony_ci    coap_dispatch(ep->context, session, pdu);
270c87c5fbaSopenharmony_ci  }
271c87c5fbaSopenharmony_ci
272c87c5fbaSopenharmony_ci  coap_delete_pdu(pdu);
273c87c5fbaSopenharmony_ci  coap_free_packet(packet);
274c87c5fbaSopenharmony_ci  return;
275c87c5fbaSopenharmony_ci
276c87c5fbaSopenharmony_cierror:
277c87c5fbaSopenharmony_ci  /*
278c87c5fbaSopenharmony_ci   * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST
279c87c5fbaSopenharmony_ci   * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST
280c87c5fbaSopenharmony_ci   */
281c87c5fbaSopenharmony_ci  if (session)
282c87c5fbaSopenharmony_ci    coap_send_rst(session, pdu);
283c87c5fbaSopenharmony_ci  coap_delete_pdu(pdu);
284c87c5fbaSopenharmony_ci  coap_free_packet(packet);
285c87c5fbaSopenharmony_ci  return;
286c87c5fbaSopenharmony_ci}
287c87c5fbaSopenharmony_ci
288c87c5fbaSopenharmony_ci#endif /* ! COAP_SERVER_SUPPORT */
289c87c5fbaSopenharmony_ci
290c87c5fbaSopenharmony_cissize_t
291c87c5fbaSopenharmony_cicoap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session,
292c87c5fbaSopenharmony_ci                     coap_pdu_t *pdu) {
293c87c5fbaSopenharmony_ci  /* FIXME: we can't check this here with the existing infrastructure, but we
294c87c5fbaSopenharmony_ci  * should actually check that the pdu is not held by anyone but us. the
295c87c5fbaSopenharmony_ci  * respective pbuf is already exclusively owned by the pdu. */
296c87c5fbaSopenharmony_ci  struct pbuf *pbuf;
297c87c5fbaSopenharmony_ci  int err;
298c87c5fbaSopenharmony_ci
299c87c5fbaSopenharmony_ci  pbuf_realloc(pdu->pbuf, pdu->used_size + coap_pdu_parse_header_size(session->proto,
300c87c5fbaSopenharmony_ci               pdu->pbuf->payload));
301c87c5fbaSopenharmony_ci
302c87c5fbaSopenharmony_ci  if (coap_debug_send_packet()) {
303c87c5fbaSopenharmony_ci    /* Need to take a copy as we may be re-using the origin in a retransmit */
304c87c5fbaSopenharmony_ci    pbuf = pbuf_clone(PBUF_TRANSPORT, PBUF_RAM, pdu->pbuf);
305c87c5fbaSopenharmony_ci    if (pbuf == NULL)
306c87c5fbaSopenharmony_ci      return -1;
307c87c5fbaSopenharmony_ci    err = udp_sendto(sock->pcb, pbuf, &session->addr_info.remote.addr,
308c87c5fbaSopenharmony_ci                     session->addr_info.remote.port);
309c87c5fbaSopenharmony_ci    pbuf_free(pbuf);
310c87c5fbaSopenharmony_ci    if (err < 0)
311c87c5fbaSopenharmony_ci      return -1;
312c87c5fbaSopenharmony_ci  }
313c87c5fbaSopenharmony_ci  return pdu->used_size;
314c87c5fbaSopenharmony_ci}
315c87c5fbaSopenharmony_ci
316c87c5fbaSopenharmony_ci/*
317c87c5fbaSopenharmony_ci * dgram
318c87c5fbaSopenharmony_ci * return +ve Number of bytes written.
319c87c5fbaSopenharmony_ci *         -1 Error error in errno).
320c87c5fbaSopenharmony_ci */
321c87c5fbaSopenharmony_cissize_t
322c87c5fbaSopenharmony_cicoap_socket_send(coap_socket_t *sock, const coap_session_t *session,
323c87c5fbaSopenharmony_ci                 const uint8_t *data, size_t data_len) {
324c87c5fbaSopenharmony_ci  struct pbuf *pbuf;
325c87c5fbaSopenharmony_ci  int err;
326c87c5fbaSopenharmony_ci
327c87c5fbaSopenharmony_ci  if (coap_debug_send_packet()) {
328c87c5fbaSopenharmony_ci    pbuf = pbuf_alloc(PBUF_TRANSPORT, data_len, PBUF_RAM);
329c87c5fbaSopenharmony_ci    if (pbuf == NULL)
330c87c5fbaSopenharmony_ci      return -1;
331c87c5fbaSopenharmony_ci    memcpy(pbuf->payload, data, data_len);
332c87c5fbaSopenharmony_ci
333c87c5fbaSopenharmony_ci    LOCK_TCPIP_CORE();
334c87c5fbaSopenharmony_ci
335c87c5fbaSopenharmony_ci    err = udp_sendto(sock->pcb, pbuf, &session->addr_info.remote.addr,
336c87c5fbaSopenharmony_ci                     session->addr_info.remote.port);
337c87c5fbaSopenharmony_ci
338c87c5fbaSopenharmony_ci    UNLOCK_TCPIP_CORE();
339c87c5fbaSopenharmony_ci
340c87c5fbaSopenharmony_ci    pbuf_free(pbuf);
341c87c5fbaSopenharmony_ci    if (err < 0)
342c87c5fbaSopenharmony_ci      return -1;
343c87c5fbaSopenharmony_ci  }
344c87c5fbaSopenharmony_ci  return data_len;
345c87c5fbaSopenharmony_ci}
346c87c5fbaSopenharmony_ci
347c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
348c87c5fbaSopenharmony_ciint
349c87c5fbaSopenharmony_cicoap_socket_bind_udp(coap_socket_t *sock,
350c87c5fbaSopenharmony_ci                     const coap_address_t *listen_addr,
351c87c5fbaSopenharmony_ci                     coap_address_t *bound_addr) {
352c87c5fbaSopenharmony_ci  int err;
353c87c5fbaSopenharmony_ci  coap_address_t l_listen = *listen_addr;
354c87c5fbaSopenharmony_ci
355c87c5fbaSopenharmony_ci  sock->pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
356c87c5fbaSopenharmony_ci  if (sock->pcb == NULL)
357c87c5fbaSopenharmony_ci    return 0;
358c87c5fbaSopenharmony_ci
359c87c5fbaSopenharmony_ci#if LWIP_IPV6 && LWIP_IPV4
360c87c5fbaSopenharmony_ci  if (l_listen.addr.type == IPADDR_TYPE_V6)
361c87c5fbaSopenharmony_ci    l_listen.addr.type = IPADDR_TYPE_ANY;
362c87c5fbaSopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV4 */
363c87c5fbaSopenharmony_ci  udp_recv(sock->pcb, coap_recvs, (void *)sock->endpoint);
364c87c5fbaSopenharmony_ci  err = udp_bind(sock->pcb, &l_listen.addr, l_listen.port);
365c87c5fbaSopenharmony_ci  if (err) {
366c87c5fbaSopenharmony_ci    udp_remove(sock->pcb);
367c87c5fbaSopenharmony_ci    sock->pcb = NULL;
368c87c5fbaSopenharmony_ci  }
369c87c5fbaSopenharmony_ci  *bound_addr = l_listen;
370c87c5fbaSopenharmony_ci  return err ? 0 : 1;
371c87c5fbaSopenharmony_ci}
372c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
373c87c5fbaSopenharmony_ci
374c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
375c87c5fbaSopenharmony_ciint
376c87c5fbaSopenharmony_cicoap_socket_connect_udp(coap_socket_t *sock,
377c87c5fbaSopenharmony_ci                        const coap_address_t *local_if,
378c87c5fbaSopenharmony_ci                        const coap_address_t *server,
379c87c5fbaSopenharmony_ci                        int default_port,
380c87c5fbaSopenharmony_ci                        coap_address_t *local_addr,
381c87c5fbaSopenharmony_ci                        coap_address_t *remote_addr) {
382c87c5fbaSopenharmony_ci  err_t err;
383c87c5fbaSopenharmony_ci  struct udp_pcb *pcb;
384c87c5fbaSopenharmony_ci
385c87c5fbaSopenharmony_ci  (void)local_if;
386c87c5fbaSopenharmony_ci  (void)default_port;
387c87c5fbaSopenharmony_ci  (void)local_addr;
388c87c5fbaSopenharmony_ci  (void)remote_addr;
389c87c5fbaSopenharmony_ci
390c87c5fbaSopenharmony_ci  LOCK_TCPIP_CORE();
391c87c5fbaSopenharmony_ci
392c87c5fbaSopenharmony_ci  pcb = udp_new();
393c87c5fbaSopenharmony_ci
394c87c5fbaSopenharmony_ci  if (!pcb) {
395c87c5fbaSopenharmony_ci    goto err_unlock;
396c87c5fbaSopenharmony_ci  }
397c87c5fbaSopenharmony_ci
398c87c5fbaSopenharmony_ci  err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
399c87c5fbaSopenharmony_ci  if (err) {
400c87c5fbaSopenharmony_ci    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
401c87c5fbaSopenharmony_ci                ("coap_socket_connect_udp: port bind failed\n"));
402c87c5fbaSopenharmony_ci    goto err_udp_remove;
403c87c5fbaSopenharmony_ci  }
404c87c5fbaSopenharmony_ci
405c87c5fbaSopenharmony_ci  sock->session->addr_info.local.port = pcb->local_port;
406c87c5fbaSopenharmony_ci
407c87c5fbaSopenharmony_ci  err = udp_connect(pcb, &server->addr, server->port);
408c87c5fbaSopenharmony_ci  if (err) {
409c87c5fbaSopenharmony_ci    goto err_udp_unbind;
410c87c5fbaSopenharmony_ci  }
411c87c5fbaSopenharmony_ci
412c87c5fbaSopenharmony_ci#if LWIP_IPV6 && LWIP_IPV4
413c87c5fbaSopenharmony_ci  pcb->local_ip.type = pcb->remote_ip.type;
414c87c5fbaSopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV4 */
415c87c5fbaSopenharmony_ci
416c87c5fbaSopenharmony_ci  sock->pcb = pcb;
417c87c5fbaSopenharmony_ci
418c87c5fbaSopenharmony_ci  udp_recv(sock->pcb, coap_recvc, (void *)sock->session);
419c87c5fbaSopenharmony_ci
420c87c5fbaSopenharmony_ci  UNLOCK_TCPIP_CORE();
421c87c5fbaSopenharmony_ci
422c87c5fbaSopenharmony_ci  return 1;
423c87c5fbaSopenharmony_ci
424c87c5fbaSopenharmony_cierr_udp_unbind:
425c87c5fbaSopenharmony_cierr_udp_remove:
426c87c5fbaSopenharmony_ci  udp_remove(pcb);
427c87c5fbaSopenharmony_cierr_unlock:
428c87c5fbaSopenharmony_ci  UNLOCK_TCPIP_CORE();
429c87c5fbaSopenharmony_ci  return 0;
430c87c5fbaSopenharmony_ci}
431c87c5fbaSopenharmony_ci#endif /* ! COAP_CLIENT_SUPPORT */
432c87c5fbaSopenharmony_ci
433c87c5fbaSopenharmony_ci#if ! COAP_DISABLE_TCP
434c87c5fbaSopenharmony_ciint
435c87c5fbaSopenharmony_cicoap_socket_connect_tcp1(coap_socket_t *sock,
436c87c5fbaSopenharmony_ci                         const coap_address_t *local_if,
437c87c5fbaSopenharmony_ci                         const coap_address_t *server,
438c87c5fbaSopenharmony_ci                         int default_port,
439c87c5fbaSopenharmony_ci                         coap_address_t *local_addr,
440c87c5fbaSopenharmony_ci                         coap_address_t *remote_addr) {
441c87c5fbaSopenharmony_ci  (void)sock;
442c87c5fbaSopenharmony_ci  (void)local_if;
443c87c5fbaSopenharmony_ci  (void)server;
444c87c5fbaSopenharmony_ci  (void)default_port;
445c87c5fbaSopenharmony_ci  (void)local_addr;
446c87c5fbaSopenharmony_ci  (void)remote_addr;
447c87c5fbaSopenharmony_ci  return 0;
448c87c5fbaSopenharmony_ci}
449c87c5fbaSopenharmony_ci
450c87c5fbaSopenharmony_ciint
451c87c5fbaSopenharmony_cicoap_socket_connect_tcp2(coap_socket_t *sock,
452c87c5fbaSopenharmony_ci                         coap_address_t *local_addr,
453c87c5fbaSopenharmony_ci                         coap_address_t *remote_addr) {
454c87c5fbaSopenharmony_ci  (void)sock;
455c87c5fbaSopenharmony_ci  (void)local_addr;
456c87c5fbaSopenharmony_ci  (void)remote_addr;
457c87c5fbaSopenharmony_ci  return 0;
458c87c5fbaSopenharmony_ci}
459c87c5fbaSopenharmony_ci
460c87c5fbaSopenharmony_ciint
461c87c5fbaSopenharmony_cicoap_socket_bind_tcp(coap_socket_t *sock,
462c87c5fbaSopenharmony_ci                     const coap_address_t *listen_addr,
463c87c5fbaSopenharmony_ci                     coap_address_t *bound_addr) {
464c87c5fbaSopenharmony_ci  (void)sock;
465c87c5fbaSopenharmony_ci  (void)listen_addr;
466c87c5fbaSopenharmony_ci  (void)bound_addr;
467c87c5fbaSopenharmony_ci  return 0;
468c87c5fbaSopenharmony_ci}
469c87c5fbaSopenharmony_ci
470c87c5fbaSopenharmony_ciint
471c87c5fbaSopenharmony_cicoap_socket_accept_tcp(coap_socket_t *server,
472c87c5fbaSopenharmony_ci                       coap_socket_t *new_client,
473c87c5fbaSopenharmony_ci                       coap_address_t *local_addr,
474c87c5fbaSopenharmony_ci                       coap_address_t *remote_addr) {
475c87c5fbaSopenharmony_ci  (void)server;
476c87c5fbaSopenharmony_ci  (void)new_client;
477c87c5fbaSopenharmony_ci  (void)local_addr;
478c87c5fbaSopenharmony_ci  (void)remote_addr;
479c87c5fbaSopenharmony_ci  return 0;
480c87c5fbaSopenharmony_ci}
481c87c5fbaSopenharmony_ci#endif /* !COAP_DISABLE_TCP */
482c87c5fbaSopenharmony_ci
483c87c5fbaSopenharmony_cissize_t
484c87c5fbaSopenharmony_cicoap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
485c87c5fbaSopenharmony_ci  (void)sock;
486c87c5fbaSopenharmony_ci  (void)data;
487c87c5fbaSopenharmony_ci  (void)data_len;
488c87c5fbaSopenharmony_ci  return -1;
489c87c5fbaSopenharmony_ci}
490c87c5fbaSopenharmony_ci
491c87c5fbaSopenharmony_cissize_t
492c87c5fbaSopenharmony_cicoap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
493c87c5fbaSopenharmony_ci  (void)sock;
494c87c5fbaSopenharmony_ci  (void)data;
495c87c5fbaSopenharmony_ci  (void)data_len;
496c87c5fbaSopenharmony_ci  return -1;
497c87c5fbaSopenharmony_ci}
498c87c5fbaSopenharmony_ci
499c87c5fbaSopenharmony_civoid
500c87c5fbaSopenharmony_cicoap_socket_close(coap_socket_t *sock) {
501c87c5fbaSopenharmony_ci  if (sock->pcb) {
502c87c5fbaSopenharmony_ci    LOCK_TCPIP_CORE();
503c87c5fbaSopenharmony_ci    udp_remove(sock->pcb);
504c87c5fbaSopenharmony_ci    UNLOCK_TCPIP_CORE();
505c87c5fbaSopenharmony_ci  }
506c87c5fbaSopenharmony_ci  sock->pcb = NULL;
507c87c5fbaSopenharmony_ci  return;
508c87c5fbaSopenharmony_ci}
509