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