libcoap 4.3.5-develop-490e4e0
Loading...
Searching...
No Matches
coap_dgrm_lwip.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
3 * 2014 chrysn <chrysn@fsfe.org>
4 * 2022-2025 Jon Shallow <supjps-libcoap@jpshallow.com>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * This file is part of the CoAP library libcoap. Please see
9 * README for terms of use.
10 */
11
18
19#if defined(WITH_LWIP)
20
21#include <lwip/udp.h>
22#include <lwip/timeouts.h>
23#include <lwip/tcpip.h>
24
25#if ! COAP_DISABLE_TCP
26#include <lwip/tcp.h>
27#endif /* !COAP_DISABLE_TCP */
28
29#if NO_SYS == 0
30extern sys_sem_t coap_io_timeout_sem;
31#endif /* NO_SYS == 0 */
32
33/*
34 * Not used for LwIP (done with coap_recvc()), but need dummy function.
35 */
36ssize_t
38 (void)sock;
39 (void)packet;
40 assert(0);
41 return -1;
42}
43
44#if COAP_CLIENT_SUPPORT
53static void
54coap_recvc(void *arg, struct udp_pcb *upcb, struct pbuf *p,
55 const ip_addr_t *addr, u16_t port) {
56 coap_pdu_t *pdu = NULL;
57 coap_session_t *session = (coap_session_t *)arg;
58 int result = -1;
59 (void)upcb;
60
61 assert(session);
62 LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
63
64 if (p->len < 4) {
65 /* Minimum size of CoAP header - ignore runt */
66 return;
67 }
68 coap_lock_lock(return);
69 memcpy(&session->addr_info.remote.addr, addr, sizeof(session->addr_info.remote.addr));
70 coap_address_set_port(&session->addr_info.remote, port);
71
72 coap_log_debug("* %s: lwip: recv %4d bytes\n",
73 coap_session_str(session), p->len);
74 if (session->proto == COAP_PROTO_DTLS) {
75 if (session->tls) {
76 result = coap_dtls_receive(session, p->payload, p->len);
77 if (result < 0)
78 goto error;
79 }
80 pbuf_free(p);
81 } else {
82 coap_opt_filter_t error_opts;
83
84 pdu = coap_pdu_from_pbuf(p);
85 if (!pdu)
86 goto error;
87
88 coap_option_filter_clear(&error_opts);
89 if (!coap_pdu_parse2(session->proto, p->payload, p->len, pdu, &error_opts)) {
91 coap_log_warn("discard malformed PDU\n");
92 if (error_opts.mask && COAP_PDU_IS_REQUEST(pdu)) {
93 coap_pdu_t *response =
95 COAP_RESPONSE_CODE(402), &error_opts);
96 if (!response) {
97 coap_log_warn("coap_handle_dgram: cannot create error response\n");
98 } else {
99 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
100 coap_log_warn("coap_handle_dgram: error sending response\n");
101 }
104#if NO_SYS == 0
105 sys_sem_signal(&coap_io_timeout_sem);
106#endif /* NO_SYS == 0 */
107 return;
108 } else {
109 goto error;
110 }
111 }
112 coap_dispatch(session->context, session, pdu);
113 }
114#if NO_SYS == 0
115 sys_sem_signal(&coap_io_timeout_sem);
116#endif /* NO_SYS == 0 */
119 return;
120
121error:
122 /*
123 * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST
124 * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST
125 */
126 if (session)
127 coap_send_rst_lkd(session, pdu);
130#if NO_SYS == 0
131 sys_sem_signal(&coap_io_timeout_sem);
132#endif /* NO_SYS == 0 */
133 return;
134}
135#endif /* ! COAP_CLIENT_SUPPORT */
136
137#if COAP_SERVER_SUPPORT
138
139static void
140coap_free_packet(coap_packet_t *packet) {
142}
143
152static void
153coap_udp_recvs(void *arg, struct udp_pcb *upcb, struct pbuf *p,
154 const ip_addr_t *addr, u16_t port) {
155 coap_endpoint_t *ep = (coap_endpoint_t *)arg;
156 coap_pdu_t *pdu = NULL;
157 coap_session_t *session = NULL;
158 coap_tick_t now;
159 coap_packet_t *packet = NULL;
160 int result = -1;
161
162 if (p->len < 4) {
163 /* Minimum size of CoAP header - ignore runt */
164 goto error_free_pbuf;
165 }
166
167 packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t));
168
169 /* this is fatal because due to the short life of the packet, never should
170 there be more than one coap_packet_t required */
171 LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL);
172 /* Need to do this as there may be holes in addr_info */
173 memset(&packet->addr_info, 0, sizeof(packet->addr_info));
174 packet->length = p->len;
175 packet->payload = p->payload;
176 packet->addr_info.remote.port = port;
177 packet->addr_info.remote.addr = *addr;
178 packet->addr_info.local.port = upcb->local_port;
179 packet->addr_info.local.addr = *ip_current_dest_addr();
180 packet->ifindex = netif_get_index(ip_current_netif());
181
182 coap_ticks(&now);
183
184 coap_lock_lock(goto error_free_pbuf);
185 session = coap_endpoint_get_session(ep, packet, now);
186 if (!session)
187 goto error_free_pbuf;
188 LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
189
190 coap_log_debug("* %s: lwip: recv %4d bytes\n",
191 coap_session_str(session), p->len);
192
193 if (session->proto == COAP_PROTO_DTLS) {
194 if (session->type == COAP_SESSION_TYPE_HELLO)
195 result = coap_dtls_hello(session, p->payload, p->len);
196 else if (session->tls)
197 result = coap_dtls_receive(session, p->payload, p->len);
198 if (session->type == COAP_SESSION_TYPE_HELLO && result == 1)
199 coap_session_new_dtls_session(session, now);
200 pbuf_free(p);
201 } else {
202 coap_opt_filter_t error_opts;
203
204 pdu = coap_pdu_from_pbuf(p);
205 if (!pdu)
206 goto error;
207
208 coap_option_filter_clear(&error_opts);
209 if (!coap_pdu_parse2(ep->proto, p->payload, p->len, pdu, &error_opts)) {
211 coap_log_warn("discard malformed PDU\n");
212 if (error_opts.mask && COAP_PDU_IS_REQUEST(pdu)) {
213 coap_pdu_t *response =
215 COAP_RESPONSE_CODE(402), &error_opts);
216 if (!response) {
217 coap_log_warn("coap_handle_dgram: cannot create error response\n");
218 } else {
219 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
220 coap_log_warn("coap_handle_dgram: error sending response\n");
221 }
222 goto cleanup;
223 } else {
224 goto error;
225 }
226 }
227 coap_dispatch(ep->context, session, pdu);
228 }
229
231 coap_free_packet(packet);
233#if NO_SYS == 0
234 sys_sem_signal(&coap_io_timeout_sem);
235#endif /* NO_SYS == 0 */
236 return;
237
238error_free_pbuf:
239 pbuf_free(p);
240
241error:
242 /*
243 * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST
244 * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST
245 */
246 if (session && pdu)
247 coap_send_rst_lkd(session, pdu);
248cleanup:
250 coap_free_packet(packet);
252#if NO_SYS == 0
253 sys_sem_signal(&coap_io_timeout_sem);
254#endif /* NO_SYS == 0 */
255 return;
256}
257
258#endif /* ! COAP_SERVER_SUPPORT */
259
260ssize_t
261coap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session,
262 coap_pdu_t *pdu) {
263 /* FIXME: we can't check this here with the existing infrastructure, but we
264 * should actually check that the pdu is not held by anyone but us. the
265 * respective pbuf is already exclusively owned by the pdu. */
266 struct pbuf *pbuf;
267 int err;
268
269 pbuf_realloc(pdu->pbuf, pdu->used_size + coap_pdu_parse_header_size(session->proto,
270 pdu->pbuf->payload));
271
273 /* Need to take a copy as we may be re-using the origin in a retransmit */
274 pbuf = pbuf_clone(PBUF_TRANSPORT, PBUF_RAM, pdu->pbuf);
275 if (pbuf == NULL)
276 return -1;
277 err = udp_sendto(sock->udp_pcb, pbuf, &session->addr_info.remote.addr,
278 session->addr_info.remote.port);
279 pbuf_free(pbuf);
280 if (err < 0)
281 return -1;
282 }
283 return pdu->used_size;
284}
285
286/*
287 * dgram
288 * return +ve Number of bytes written.
289 * -1 Error error in errno).
290 */
291ssize_t
293 const uint8_t *data, size_t data_len) {
294 struct pbuf *pbuf;
295 int err;
296
298 pbuf = pbuf_alloc(PBUF_TRANSPORT, data_len, PBUF_RAM);
299 if (pbuf == NULL)
300 return -1;
301 memcpy(pbuf->payload, data, data_len);
302
303 coap_lock_invert(LOCK_TCPIP_CORE(),
304 UNLOCK_TCPIP_CORE(); return -1);
305
306 err = udp_sendto(sock->udp_pcb, pbuf, &session->addr_info.remote.addr,
307 session->addr_info.remote.port);
308
309 UNLOCK_TCPIP_CORE();
310
311 pbuf_free(pbuf);
312 if (err < 0) {
313 if (err == ERR_RTE) {
314 coap_log_warn("** %s: udp_sendto: Packet not routable\n",
315 coap_session_str(session));
316 } else {
317 coap_log_warn("** %s: udp_sendto: error %d\n",
318 coap_session_str(session), err);
319 }
320 return -1;
321 }
322 }
323 return data_len;
324}
325
326#if COAP_SERVER_SUPPORT
327int
329 const coap_address_t *listen_addr,
330 coap_address_t *bound_addr) {
331 int err;
332 coap_address_t l_listen = *listen_addr;
333
334 sock->udp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
335 if (sock->udp_pcb == NULL)
336 return 0;
337
338#if LWIP_IPV6 && LWIP_IPV4
339 if (l_listen.addr.type == IPADDR_TYPE_V6)
340 l_listen.addr.type = IPADDR_TYPE_ANY;
341#endif /* LWIP_IPV6 && LWIP_IPV4 */
342 udp_recv(sock->udp_pcb, coap_udp_recvs, (void *)sock->endpoint);
343 err = udp_bind(sock->udp_pcb, &l_listen.addr, l_listen.port);
344 if (err) {
345 udp_remove(sock->udp_pcb);
346 sock->udp_pcb = NULL;
347 }
348 *bound_addr = l_listen;
349 return err ? 0 : 1;
350}
351#endif /* COAP_SERVER_SUPPORT */
352
353#if COAP_CLIENT_SUPPORT
354int
356 const coap_address_t *local_if,
357 const coap_address_t *server,
358 int default_port,
359 coap_address_t *local_addr,
360 coap_address_t *remote_addr) {
361 err_t err;
362 struct udp_pcb *pcb;
363 int is_mcast = coap_is_mcast(server);
364 coap_address_t connect_addr;
365
366 coap_address_copy(&connect_addr, server);
367 if (connect_addr.port == 0)
368 connect_addr.port = default_port;
369
370 coap_lock_invert(LOCK_TCPIP_CORE(),
371 goto err_unlock);
372
373 pcb = udp_new();
374
375 if (!pcb) {
376 goto err_unlock;
377 }
378
379 if (local_if) {
380 pcb->local_ip = local_if->addr;
381 pcb->local_port = local_if->port;
382 }
383 err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
384 if (err) {
385 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
386 ("coap_socket_connect_udp: port bind failed\n"));
387 goto err_udp_remove;
388 }
389
390 if (local_addr) {
391 local_addr->addr = pcb->local_ip;
392 local_addr->port = pcb->local_port;
393 }
394 sock->session->addr_info.local.port = pcb->local_port;
395
396 if (remote_addr) {
397 coap_address_copy(remote_addr, &connect_addr);
398 }
399
400 if (is_mcast) {
401 coap_address_copy(&sock->mcast_addr, &connect_addr);
403 } else {
404 err = udp_connect(pcb, &connect_addr.addr, connect_addr.port);
405 if (err) {
406 goto err_udp_unbind;
407 }
408 }
409
410#if LWIP_IPV6 && LWIP_IPV4
411 pcb->local_ip.type = pcb->remote_ip.type;
412#endif /* LWIP_IPV6 && LWIP_IPV4 */
413
414 sock->udp_pcb = pcb;
415
416 udp_recv(sock->udp_pcb, coap_recvc, (void *)sock->session);
417
418 UNLOCK_TCPIP_CORE();
419
420 return 1;
421
422err_udp_unbind:
423err_udp_remove:
424 udp_remove(pcb);
425err_unlock:
426 UNLOCK_TCPIP_CORE();
427 return 0;
428}
429#endif /* ! COAP_CLIENT_SUPPORT */
430void
432 if (sock->udp_pcb) {
433 if (sock->session) {
434 coap_lock_invert(LOCK_TCPIP_CORE(),
435 UNLOCK_TCPIP_CORE(); return);
436 } else {
437 LOCK_TCPIP_CORE();
438 }
439 udp_remove(sock->udp_pcb);
440 UNLOCK_TCPIP_CORE();
441 sock->udp_pcb = NULL;
442 }
443 return;
444}
445
446#else /* ! WITH_LWIP */
447
448#ifdef __clang__
449/* Make compilers happy that do not like empty modules. As this function is
450 * never used, we ignore -Wunused-function at the end of compiling this file
451 */
452#pragma GCC diagnostic ignored "-Wunused-function"
453#endif
454static inline void
455dummy(void) {
456}
457
458#endif /* ! WITH_LWIP */
void coap_address_set_port(coap_address_t *addr, uint16_t port)
Set the port field of addr to port (in host byte order).
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
static void dummy(void)
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
Library specific build wrapper for coap_internal.h.
@ COAP_PACKET
Definition coap_mem.h:37
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
int coap_dtls_receive(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition coap_notls.c:243
coap_mid_t coap_send_rst_lkd(coap_session_t *session, const coap_pdu_t *request)
Sends an RST message with code 0 for the specified request to dst.
Definition coap_net.c:1067
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:151
int coap_handle_event_lkd(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:4904
void coap_dispatch(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu)
Dispatches the PDUs from the receive queue in given context.
Definition coap_net.c:4376
coap_mid_t coap_send_internal(coap_session_t *session, coap_pdu_t *pdu, coap_pdu_t *request_pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:1836
coap_pdu_t * coap_new_error_response(const coap_pdu_t *request, coap_pdu_code_t code, coap_opt_filter_t *opts)
Creates a new ACK PDU with specified error code.
Definition coap_net.c:3110
void coap_ticks(coap_tick_t *t)
Returns the current value of an internal tick counter.
Definition coap_time.c:90
int coap_socket_connect_udp(coap_socket_t *sock, const coap_address_t *local_if, const coap_address_t *server, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr)
Create a new UDP socket and 'connect' it to the address tuple.
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for data transmission.
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Create a new UDP socket and then listen for new incoming UDP sessions to the specified IP address and...
void coap_socket_dgrm_close(coap_socket_t *sock)
Function interface to close off a datagram socket.
coap_session_t * coap_session_new_dtls_session(coap_session_t *session, coap_tick_t now)
Create a new DTLS session for the session.
int coap_dtls_hello(coap_session_t *coap_session, const uint8_t *data, size_t data_len)
Handling client HELLO messages from a new candiate peer.
@ COAP_EVENT_BAD_PACKET
Triggered when badly formatted packet received.
Definition coap_event.h:110
#define coap_lock_invert(alt_lock, failed)
Dummy for no thread-safe code.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_warn(...)
Definition coap_debug.h:108
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:194
size_t coap_pdu_parse_header_size(coap_proto_t proto, const uint8_t *data)
Interprets data to determine the number of bytes in the header.
Definition coap_pdu.c:994
int coap_pdu_parse2(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu, coap_opt_filter_t *error_opts)
Parses data into the CoAP PDU structure given in result.
Definition coap_pdu.c:1493
#define COAP_PDU_IS_REQUEST(pdu)
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:165
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:271
@ COAP_PROTO_DTLS
Definition coap_pdu.h:320
coap_session_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Lookup the server session for the packet received on an endpoint, or create a new one.
#define COAP_PROTO_NOT_RELIABLE(p)
@ COAP_SESSION_TYPE_HELLO
server-side ephemeral session for responding to a client hello
coap_address_t remote
remote address and port
Definition coap_io.h:60
coap_address_t local
local address and port
Definition coap_io.h:61
Multi-purpose address abstraction.
union coap_address_t::@0 addr
Abstraction of virtual endpoint that can be attached to coap_context_t.
coap_context_t * context
endpoint's context
coap_proto_t proto
protocol used on this interface
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
int ifindex
the interface index
structure for CoAP PDUs
size_t used_size
used bytes of storage for token, options and payload
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
void * tls
security parameters
coap_session_type_t type
client or server side socket
coap_context_t * context
session's context
coap_session_t * session
Used to determine session owner.
coap_endpoint_t * endpoint
Used by the epoll logic for a listening endpoint.
coap_address_t mcast_addr
remote address and port (multicast track)
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values