1 /* coap_io_lwip.h -- Network I/O functions for libcoap on lwIP
2 *
3 * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
4 * 2014 chrysn <chrysn@fsfe.org>
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
12 #include "coap3/coap_internal.h"
13 #include <lwip/udp.h>
14
15 #if NO_SYS
16 pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER;
17 pthread_t lwprot_thread = (pthread_t)0xDEAD;
18 int lwprot_count = 0;
19 #endif
20
21 #if 0
22 void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
23 {
24 target->port = packet->srcport;
25 memcpy(&target->addr, ip_current_src_addr(), sizeof(ip_addr_t));
26 }
27 #endif
coap_packet_get_memmapped(coap_packet_t * packet,unsigned char ** address,size_t * length)28 void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
29 {
30 LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", packet->pbuf->tot_len == packet->pbuf->len);
31 *address = packet->pbuf->payload;
32 *length = packet->pbuf->tot_len;
33 }
coap_free_packet(coap_packet_t * packet)34 void coap_free_packet(coap_packet_t *packet)
35 {
36 if (packet->pbuf)
37 pbuf_free(packet->pbuf);
38 coap_free_type(COAP_PACKET, packet);
39 }
40
coap_packet_extract_pbuf(coap_packet_t * packet)41 struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet)
42 {
43 struct pbuf *ret = packet->pbuf;
44 packet->pbuf = NULL;
45 return ret;
46 }
47
48
49 /** Callback from lwIP when a package was received.
50 *
51 * The current implementation deals this to coap_dispatch immediately, but
52 * other mechanisms (as storing the package in a queue and later fetching it
53 * when coap_io_do_io is called) can be envisioned.
54 *
55 * It handles everything coap_io_do_io does on other implementations.
56 */
coap_recv(void * arg,struct udp_pcb * upcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)57 static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
58 {
59 coap_endpoint_t *ep = (coap_endpoint_t*)arg;
60 coap_pdu_t *pdu = NULL;
61 coap_session_t *session;
62 coap_tick_t now;
63 coap_packet_t *packet;
64
65 if (p->len < 4) {
66 /* Minimum size of CoAP header - ignore runt */
67 return;
68 }
69
70 packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t));
71
72 /* this is fatal because due to the short life of the packet, never should there be more than one coap_packet_t required */
73 LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL);
74 packet->pbuf = p;
75 /* Need to do this as there may be holes in addr_info */
76 memset(&packet->addr_info, 0, sizeof(packet->addr_info));
77 packet->addr_info.remote.port = port;
78 packet->addr_info.remote.addr = *addr;
79 packet->addr_info.local.port = upcb->local_port;
80 packet->addr_info.local.addr = *ip_current_dest_addr();
81 packet->ifindex = netif_get_index(ip_current_netif());
82
83 pdu = coap_pdu_from_pbuf(p);
84 if (!pdu)
85 goto error;
86
87 if (!coap_pdu_parse(ep->proto, p->payload, p->len, pdu)) {
88 goto error;
89 }
90
91 coap_ticks(&now);
92 session = coap_endpoint_get_session(ep, packet, now);
93 if (!session)
94 goto error;
95 LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
96 coap_dispatch(ep->context, session, pdu);
97
98 coap_delete_pdu(pdu);
99 packet->pbuf = NULL;
100 coap_free_packet(packet);
101 return;
102
103 error:
104 /*
105 * https://tools.ietf.org/html/rfc7252#section-4.2 MUST send RST
106 * https://tools.ietf.org/html/rfc7252#section-4.3 MAY send RST
107 */
108 coap_send_rst(session, pdu);
109 coap_delete_pdu(pdu);
110 if (packet) {
111 packet->pbuf = NULL;
112 coap_free_packet(packet);
113 }
114 return;
115 }
116
117 coap_endpoint_t *
coap_new_endpoint(coap_context_t * context,const coap_address_t * addr,coap_proto_t proto)118 coap_new_endpoint(coap_context_t *context, const coap_address_t *addr, coap_proto_t proto) {
119 coap_endpoint_t *result;
120 err_t err;
121
122 LWIP_ASSERT("Proto not supported for LWIP endpoints", proto == COAP_PROTO_UDP);
123
124 result = coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t));
125 if (!result) return NULL;
126
127 result->sock.pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
128 if (result->sock.pcb == NULL) goto error;
129
130 udp_recv(result->sock.pcb, coap_recv, (void*)result);
131 err = udp_bind(result->sock.pcb, &addr->addr, addr->port);
132 if (err) {
133 udp_remove(result->sock.pcb);
134 goto error;
135 }
136
137 result->default_mtu = COAP_DEFAULT_MTU;
138 result->context = context;
139 result->proto = proto;
140
141 return result;
142
143 error:
144 coap_free_type(COAP_ENDPOINT, result);
145 return NULL;
146 }
147
coap_free_endpoint(coap_endpoint_t * ep)148 void coap_free_endpoint(coap_endpoint_t *ep)
149 {
150 udp_remove(ep->sock.pcb);
151 coap_free_type(COAP_ENDPOINT, ep);
152 }
153
154 ssize_t
coap_socket_send_pdu(coap_socket_t * sock,coap_session_t * session,coap_pdu_t * pdu)155 coap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session,
156 coap_pdu_t *pdu) {
157 /* FIXME: we can't check this here with the existing infrastructure, but we
158 * should actually check that the pdu is not held by anyone but us. the
159 * respective pbuf is already exclusively owned by the pdu. */
160
161 pbuf_realloc(pdu->pbuf, pdu->used_size + coap_pdu_parse_header_size(session->proto, pdu->pbuf->payload));
162 udp_sendto(sock->pcb, pdu->pbuf, &session->addr_info.remote.addr,
163 session->addr_info.remote.port);
164 return pdu->used_size;
165 }
166
167 ssize_t
coap_socket_send(coap_socket_t * sock,coap_session_t * session,const uint8_t * data,size_t data_len)168 coap_socket_send(coap_socket_t *sock, coap_session_t *session,
169 const uint8_t *data, size_t data_len ) {
170 /* Not implemented, use coap_socket_send_pdu instead */
171 return -1;
172 }
173
174 int
coap_socket_bind_udp(coap_socket_t * sock,const coap_address_t * listen_addr,coap_address_t * bound_addr)175 coap_socket_bind_udp(coap_socket_t *sock,
176 const coap_address_t *listen_addr,
177 coap_address_t *bound_addr) {
178 return 0;
179 }
180
181 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)182 coap_socket_connect_udp(coap_socket_t *sock,
183 const coap_address_t *local_if,
184 const coap_address_t *server,
185 int default_port,
186 coap_address_t *local_addr,
187 coap_address_t *remote_addr) {
188 return 0;
189 }
190
191 int
coap_socket_connect_tcp1(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)192 coap_socket_connect_tcp1(coap_socket_t *sock,
193 const coap_address_t *local_if,
194 const coap_address_t *server,
195 int default_port,
196 coap_address_t *local_addr,
197 coap_address_t *remote_addr) {
198 return 0;
199 }
200
201 int
coap_socket_connect_tcp2(coap_socket_t * sock,coap_address_t * local_addr,coap_address_t * remote_addr)202 coap_socket_connect_tcp2(coap_socket_t *sock,
203 coap_address_t *local_addr,
204 coap_address_t *remote_addr) {
205 return 0;
206 }
207
208 int
coap_socket_bind_tcp(coap_socket_t * sock,const coap_address_t * listen_addr,coap_address_t * bound_addr)209 coap_socket_bind_tcp(coap_socket_t *sock,
210 const coap_address_t *listen_addr,
211 coap_address_t *bound_addr) {
212 return 0;
213 }
214
215 int
coap_socket_accept_tcp(coap_socket_t * server,coap_socket_t * new_client,coap_address_t * local_addr,coap_address_t * remote_addr)216 coap_socket_accept_tcp(coap_socket_t *server,
217 coap_socket_t *new_client,
218 coap_address_t *local_addr,
219 coap_address_t *remote_addr) {
220 return 0;
221 }
222
223 ssize_t
coap_socket_write(coap_socket_t * sock,const uint8_t * data,size_t data_len)224 coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
225 return -1;
226 }
227
228 ssize_t
coap_socket_read(coap_socket_t * sock,uint8_t * data,size_t data_len)229 coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
230 return -1;
231 }
232
coap_socket_close(coap_socket_t * sock)233 void coap_socket_close(coap_socket_t *sock) {
234 return;
235 }
236
237