Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
coap_connection_handler.c
00001 /* 00002 * Copyright (c) 2015-2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include <string.h> 00019 #include "coap_connection_handler.h" 00020 #include "coap_security_handler.h" 00021 #include "ns_list.h" 00022 #include "ns_trace.h" 00023 #include "nsdynmemLIB.h" 00024 #include "socket_api.h" 00025 #include "net_interface.h" 00026 #include "eventOS_event_timer.h" 00027 #include "coap_service_api_internal.h" 00028 00029 #define TRACE_GROUP "ThCH" 00030 00031 typedef enum session_state_e { 00032 SECURE_SESSION_HANDSHAKE_ONGOING = 0, 00033 SECURE_SESSION_OK, 00034 SECURE_SESSION_CLOSED 00035 } session_state_t; 00036 00037 typedef struct internal_socket_s { 00038 coap_conn_handler_t *parent; 00039 cch_func_cb *cch_function_callback; // callback function 00040 00041 uint32_t timeout_min; 00042 uint32_t timeout_max; 00043 00044 uint16_t listen_port; // 0 for ephemeral-port sockets 00045 00046 int16_t data_len; 00047 uint8_t *data; 00048 int8_t recv_if_id; // interface ID where data is coming from 00049 00050 int8_t socket; //positive value = socket id, negative value virtual socket id 00051 bool real_socket; 00052 uint8_t usage_counter; 00053 bool is_secure; 00054 00055 bool bypass_link_sec; 00056 00057 ns_list_link_t link; 00058 } internal_socket_t; 00059 00060 const uint8_t COAP_MULTICAST_ADDR_LINK_LOCAL[16] = { 0xff, 0x02, [15] = 0xfd }; // ff02::fd, COAP link-local multicast (rfc7390) 00061 const uint8_t COAP_MULTICAST_ADDR_ADMIN_LOCAL[16] = { 0xff, 0x03, [15] = 0xfd }; // ff02::fd, COAP admin-local multicast (rfc7390) 00062 const uint8_t COAP_MULTICAST_ADDR_SITE_LOCAL[16] = { 0xff, 0x05, [15] = 0xfd }; // ff05::fd, COAP site-local multicast (rfc7390) 00063 00064 static NS_LIST_DEFINE(socket_list, internal_socket_t, link); 00065 00066 static uint8_t max_handshakes = MAX_ONGOING_HANDSHAKES; 00067 static uint8_t max_sessions = MAX_SECURE_SESSION_COUNT; 00068 00069 static void timer_cb(void *param); 00070 00071 static void recv_sckt_msg(void *cb_res); 00072 #ifdef COAP_SECURITY_AVAILABLE 00073 static void secure_recv_sckt_msg(void *cb_res); 00074 #endif 00075 00076 #define TIMER_STATE_CANCELLED -1 /* cancelled */ 00077 #define TIMER_STATE_NO_EXPIRY 0 /* none of the delays is expired */ 00078 #define TIMER_STATE_INT_EXPIRY 1 /* the intermediate delay only is expired */ 00079 #define TIMER_STATE_FIN_EXPIRY 2 /* the final delay is expired */ 00080 00081 typedef struct secure_timer_s { 00082 uint8_t id; 00083 timeout_t *timer; 00084 int8_t state; 00085 uint32_t fin_ms; 00086 uint32_t int_ms; 00087 } secure_timer_t; 00088 00089 typedef struct secure_session { 00090 coap_security_t *sec_handler; //owned 00091 internal_socket_t *parent; //not owned 00092 00093 ns_address_t remote_host; 00094 uint8_t local_address[16]; 00095 // local port is fixed by socket 00096 00097 secure_timer_t timer; 00098 00099 session_state_t session_state; 00100 uint32_t last_contact_time; 00101 ns_list_link_t link; 00102 } secure_session_t; 00103 00104 static NS_LIST_DEFINE(secure_session_list, secure_session_t, link); 00105 static int secure_session_sendto(int8_t socket_id, void *handle, const void *buf, size_t len); 00106 static int secure_session_recvfrom(int8_t socket_id, unsigned char *buf, size_t len); 00107 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms); 00108 static int timer_status(int8_t timer_id); 00109 00110 static secure_session_t *secure_session_find_by_timer_id(int8_t timer_id) 00111 { 00112 secure_session_t *this = NULL; 00113 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00114 if (cur_ptr->timer.id == timer_id) { 00115 this = cur_ptr; 00116 break; 00117 } 00118 } 00119 return this; 00120 } 00121 00122 static bool is_secure_session_valid(secure_session_t *session) 00123 { 00124 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00125 if (cur_ptr == session) { 00126 return true; 00127 } 00128 } 00129 return false; 00130 } 00131 00132 static void secure_session_delete(secure_session_t *this) 00133 { 00134 if (this) { 00135 ns_list_remove(&secure_session_list, this); 00136 transactions_delete_all(this->remote_host.address, this->remote_host.identifier); 00137 if (this->sec_handler) { 00138 coap_security_destroy(this->sec_handler); 00139 this->sec_handler = NULL; 00140 } 00141 if (this->timer.timer) { 00142 eventOS_timeout_cancel(this->timer.timer); 00143 } 00144 ns_dyn_mem_free(this); 00145 this = NULL; 00146 } 00147 00148 return; 00149 } 00150 00151 static int8_t virtual_socket_id_allocate() 00152 { 00153 int8_t new_virtual_socket_id = -1; // must not overlap with real socket id's 00154 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 00155 if (cur_ptr->socket <= new_virtual_socket_id) { 00156 new_virtual_socket_id = cur_ptr->socket - 1; 00157 } 00158 } 00159 return new_virtual_socket_id; 00160 } 00161 00162 static secure_session_t *secure_session_create(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port, SecureConnectionMode secure_mode) 00163 { 00164 uint8_t handshakes = 0; 00165 if (!address_ptr) { 00166 return NULL; 00167 } 00168 00169 if (max_sessions <= ns_list_count(&secure_session_list)) { 00170 // Seek & destroy oldest session where close notify have been sent 00171 secure_session_t *to_be_removed = NULL; 00172 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00173 if (cur_ptr->session_state == SECURE_SESSION_CLOSED) { 00174 if (!to_be_removed || cur_ptr->last_contact_time < to_be_removed->last_contact_time) { 00175 to_be_removed = cur_ptr; 00176 } 00177 } 00178 } 00179 if (!to_be_removed) { 00180 tr_err("max session count exceeded"); 00181 return NULL; 00182 } 00183 00184 secure_session_delete(to_be_removed); 00185 } 00186 00187 // Count for ongoing handshakes 00188 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00189 if (cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 00190 handshakes++; 00191 } 00192 } 00193 if (handshakes >= max_handshakes) { 00194 tr_err("ongoing handshakes exceeded"); 00195 return NULL; 00196 } 00197 00198 secure_session_t *this = ns_dyn_mem_alloc(sizeof(secure_session_t)); 00199 if (!this) { 00200 return NULL; 00201 } 00202 memset(this, 0, sizeof(secure_session_t)); 00203 00204 uint8_t timer_id = 1; 00205 00206 while (secure_session_find_by_timer_id(timer_id)) { 00207 if (timer_id == 0xff) { 00208 ns_dyn_mem_free(this); 00209 return NULL; 00210 } 00211 timer_id++; 00212 } 00213 this->last_contact_time = coap_service_get_internal_timer_ticks(); 00214 this->timer.id = timer_id; 00215 this->remote_host.type = ADDRESS_IPV6; 00216 memcpy(this->remote_host.address, address_ptr, 16); 00217 this->remote_host.identifier = port; 00218 00219 this->sec_handler = coap_security_create(parent->socket, this->timer.id, this, secure_mode, 00220 &secure_session_sendto, &secure_session_recvfrom, &start_timer, &timer_status); 00221 if (!this->sec_handler) { 00222 tr_err("security create failed"); 00223 ns_dyn_mem_free(this); 00224 return NULL; 00225 } 00226 this->parent = parent; 00227 00228 this->session_state = SECURE_SESSION_HANDSHAKE_ONGOING; 00229 ns_list_add_to_start(&secure_session_list, this); 00230 00231 return this; 00232 } 00233 00234 00235 static void clear_secure_sessions(internal_socket_t *this) 00236 { 00237 if (this) { 00238 ns_list_foreach_safe(secure_session_t, cur_ptr, &secure_session_list) { 00239 if (cur_ptr->parent == this) { 00240 coap_security_send_close_alert(cur_ptr->sec_handler); 00241 secure_session_delete(cur_ptr); 00242 } 00243 } 00244 } 00245 } 00246 00247 static secure_session_t *secure_session_find(internal_socket_t *parent, const uint8_t *address_ptr, uint16_t port) 00248 { 00249 secure_session_t *this = NULL; 00250 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00251 if (cur_ptr->sec_handler) { 00252 if (cur_ptr->parent == parent && cur_ptr->remote_host.identifier == port && 00253 memcmp(cur_ptr->remote_host.address, address_ptr, 16) == 0) { 00254 this = cur_ptr; 00255 break; 00256 } 00257 } 00258 } 00259 return this; 00260 } 00261 00262 static void coap_multicast_group_join_or_leave(int8_t socket_id, uint8_t opt_name, int8_t interface_id) 00263 { 00264 ns_ipv6_mreq_t ns_ipv6_mreq; 00265 int8_t ret_val; 00266 00267 // Join or leave COAP multicast groups 00268 ns_ipv6_mreq.ipv6mr_interface = interface_id; 00269 00270 memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_LINK_LOCAL, 16); 00271 ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq)); 00272 00273 memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_ADMIN_LOCAL, 16); 00274 ret_val |= socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq)); 00275 00276 memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_SITE_LOCAL, 16); 00277 ret_val |= socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq)); 00278 00279 if (ret_val) { 00280 tr_error("Multicast group access failed, err=%d, name=%d", ret_val, opt_name); 00281 } 00282 } 00283 00284 static internal_socket_t *int_socket_create(uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec, int8_t socket_interface_selection, bool multicast_registration) 00285 { 00286 internal_socket_t *this = ns_dyn_mem_alloc(sizeof(internal_socket_t)); 00287 00288 if (!this) { 00289 return NULL; 00290 } 00291 memset(this, 0, sizeof(internal_socket_t)); 00292 00293 this->data_len = 0; 00294 this->data = NULL; 00295 00296 this->is_secure = is_secure; 00297 this->usage_counter = 1; 00298 00299 this->listen_port = listen_port; 00300 this->real_socket = real_socket; 00301 this->bypass_link_sec = bypassSec; 00302 this->socket = -1; 00303 if (real_socket) { 00304 if (use_ephemeral_port) { //socket_api creates ephemeral port if the one provided is 0 00305 listen_port = 0; 00306 } 00307 if (!is_secure) { 00308 this->socket = socket_open(SOCKET_UDP, listen_port, recv_sckt_msg); 00309 } else { 00310 #ifdef COAP_SECURITY_AVAILABLE 00311 this->socket = socket_open(SOCKET_UDP, listen_port, secure_recv_sckt_msg); 00312 #else 00313 tr_err("Secure CoAP unavailable - SSL library not configured, possibly due to lack of entropy source"); 00314 #endif 00315 } 00316 // Socket create failed 00317 if (this->socket < 0) { 00318 ns_dyn_mem_free(this); 00319 return NULL; 00320 } 00321 00322 socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &(const int8_t) { 00323 bypassSec ? 0 : 1 00324 }, sizeof(int8_t)); 00325 00326 // XXX API for this? May want to get clever to do recommended first query = 1 hop, retries = whole PAN 00327 socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &(const int16_t) { 00328 16 00329 }, sizeof(int16_t)); 00330 00331 // Set socket option to receive packet info 00332 socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_RECVPKTINFO, &(const bool) { 00333 1 00334 }, sizeof(bool)); 00335 if (socket_interface_selection > 0) { 00336 // Interface selection requested as socket_interface_selection set 00337 socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_INTERFACE_SELECT, &socket_interface_selection, sizeof(socket_interface_selection)); 00338 } 00339 00340 if (multicast_registration) { 00341 coap_multicast_group_join_or_leave(this->socket, SOCKET_IPV6_JOIN_GROUP, socket_interface_selection); 00342 } 00343 } else { 00344 this->socket = virtual_socket_id_allocate(); 00345 } 00346 00347 ns_list_add_to_start(&socket_list, this); 00348 return this; 00349 } 00350 00351 static void int_socket_delete(internal_socket_t *this) 00352 { 00353 if (this) { 00354 this->usage_counter--; 00355 if (this->usage_counter == 0) { 00356 clear_secure_sessions(this); 00357 socket_close(this->socket); 00358 ns_list_remove(&socket_list, this); 00359 if (this->data) { 00360 ns_dyn_mem_free(this->data); 00361 this->data = NULL; 00362 } 00363 if (this->parent) { 00364 ns_dyn_mem_free(this->parent); 00365 } 00366 ns_dyn_mem_free(this); 00367 } 00368 } 00369 } 00370 00371 static internal_socket_t *int_socket_find_by_socket_id(int8_t id) 00372 { 00373 internal_socket_t *this = NULL; 00374 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 00375 if (cur_ptr->socket == id) { 00376 this = cur_ptr; 00377 break; 00378 } 00379 } 00380 return this; 00381 } 00382 00383 static internal_socket_t *int_socket_find(uint16_t port, bool is_secure, bool is_real_socket, bool bypassSec) 00384 { 00385 (void) bypassSec; 00386 00387 internal_socket_t *this = NULL; 00388 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 00389 if (cur_ptr->listen_port == port && cur_ptr->real_socket == is_real_socket && 00390 is_secure == cur_ptr->is_secure /*&& bypass_link_sec == bypassSec*/) { 00391 this = cur_ptr; 00392 break; 00393 } 00394 } 00395 return this; 00396 } 00397 00398 static int send_to_real_socket(int8_t socket_id, const ns_address_t *address, const uint8_t source_address[static 16], const void *buffer, uint16_t length) 00399 { 00400 ns_iovec_t msg_iov = { 00401 .iov_base = (void *) buffer, 00402 .iov_len = length 00403 }; 00404 ns_msghdr_t msghdr = { 00405 .msg_name = (void *) address, 00406 .msg_namelen = sizeof(ns_address_t), 00407 .msg_iov = &msg_iov, 00408 .msg_iovlen = 1 00409 }; 00410 00411 uint8_t ancillary_databuffer[NS_CMSG_SPACE(sizeof(ns_in6_pktinfo_t))]; 00412 00413 if (memcmp(source_address, ns_in6addr_any, 16)) { 00414 ns_cmsghdr_t *cmsg; 00415 ns_in6_pktinfo_t *pktinfo; 00416 00417 msghdr.msg_control = ancillary_databuffer; 00418 msghdr.msg_controllen = sizeof(ancillary_databuffer); 00419 00420 cmsg = NS_CMSG_FIRSTHDR(&msghdr); 00421 cmsg->cmsg_type = SOCKET_IPV6_PKTINFO; 00422 cmsg->cmsg_level = SOCKET_IPPROTO_IPV6; 00423 cmsg->cmsg_len = NS_CMSG_LEN(sizeof(ns_in6_pktinfo_t)); 00424 00425 pktinfo = (ns_in6_pktinfo_t *)NS_CMSG_DATA(cmsg); 00426 pktinfo->ipi6_ifindex = 0; 00427 memcpy(pktinfo->ipi6_addr, source_address, 16); 00428 } 00429 00430 return socket_sendmsg(socket_id, &msghdr, 0); 00431 } 00432 00433 static int secure_session_sendto(int8_t socket_id, void *handle, const void *buf, size_t len) 00434 { 00435 secure_session_t *session = handle; 00436 internal_socket_t *sock = int_socket_find_by_socket_id(socket_id); 00437 if (!sock) { 00438 return -1; 00439 } 00440 if (!sock->real_socket) { 00441 // Send to virtual socket cb 00442 int ret = sock->parent->_send_cb(sock->socket, session->remote_host.address, session->remote_host.identifier, buf, len); 00443 if (ret < 0) { 00444 return ret; 00445 } 00446 return len; 00447 } 00448 00449 int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00450 int8_t securityLinkLayer = 1; 00451 if (sock->bypass_link_sec) { 00452 securityLinkLayer = 0; 00453 } 00454 socket_setsockopt(sock->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); 00455 socket_setsockopt(sock->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); 00456 //For some reason socket_sendto returns 0 in success, while other socket impls return number of bytes sent!!! 00457 //TODO: check if address_ptr is valid and use that instead if it is 00458 00459 int ret = send_to_real_socket(sock->socket, &session->remote_host, session->local_address, buf, len); 00460 if (ret < 0) { 00461 return ret; 00462 } 00463 return len; 00464 } 00465 00466 static int secure_session_recvfrom(int8_t socket_id, unsigned char *buf, size_t len) 00467 { 00468 (void)len; 00469 internal_socket_t *sock = int_socket_find_by_socket_id(socket_id); 00470 if (sock->data && sock->data_len > 0) { 00471 memcpy(buf, sock->data, sock->data_len); 00472 int l = sock->data_len; 00473 ns_dyn_mem_free(sock->data); 00474 sock->data = NULL; 00475 sock->data_len = 0; 00476 return l; 00477 } 00478 return MBEDTLS_ERR_SSL_WANT_READ; 00479 } 00480 00481 /** 00482 * Callback timer. Maybe called in interrupt context 00483 * so keep it simple. 00484 * TODO - might be better to use an event timer in conjunction with 00485 * CoAP tasklet 00486 */ 00487 static void timer_cb(void *param) 00488 { 00489 secure_session_t *sec = param; 00490 00491 if (sec && is_secure_session_valid(sec)) { 00492 if (sec->timer.fin_ms > sec->timer.int_ms) { 00493 /* Intermediate expiry */ 00494 sec->timer.fin_ms -= sec->timer.int_ms; 00495 sec->timer.state = TIMER_STATE_INT_EXPIRY; 00496 int error = coap_security_handler_continue_connecting(sec->sec_handler); 00497 if (MBEDTLS_ERR_SSL_TIMEOUT == error) { 00498 //TODO: How do we handle timeouts? 00499 secure_session_delete(sec); 00500 } else { 00501 sec->timer.timer = eventOS_timeout_ms(timer_cb, sec->timer.int_ms, (void *)sec); 00502 } 00503 } else { 00504 /* We have counted the number of cycles - finish */ 00505 eventOS_timeout_cancel(sec->timer.timer); 00506 sec->timer.fin_ms = 0; 00507 sec->timer.int_ms = 0; 00508 sec->timer.timer = NULL; 00509 sec->timer.state = TIMER_STATE_FIN_EXPIRY; 00510 int error = coap_security_handler_continue_connecting(sec->sec_handler); 00511 if (MBEDTLS_ERR_SSL_TIMEOUT == error) { 00512 //TODO: How do we handle timeouts? 00513 secure_session_delete(sec); 00514 } 00515 } 00516 } 00517 } 00518 00519 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms) 00520 { 00521 secure_session_t *sec = secure_session_find_by_timer_id(timer_id); 00522 if (sec) { 00523 if ((int_ms > 0) && (fin_ms > 0)) { 00524 sec->timer.int_ms = int_ms; 00525 sec->timer.fin_ms = fin_ms; 00526 sec->timer.state = TIMER_STATE_NO_EXPIRY; 00527 if (sec->timer.timer) { 00528 eventOS_timeout_cancel(sec->timer.timer); 00529 } 00530 sec->timer.timer = eventOS_timeout_ms(timer_cb, int_ms, sec); 00531 } else if (fin_ms == 0) { 00532 /* fin_ms == 0 means cancel the timer */ 00533 sec->timer.state = TIMER_STATE_CANCELLED; 00534 eventOS_timeout_cancel(sec->timer.timer); 00535 sec->timer.fin_ms = 0; 00536 sec->timer.int_ms = 0; 00537 sec->timer.timer = NULL; 00538 } 00539 } 00540 } 00541 00542 static int timer_status(int8_t timer_id) 00543 { 00544 secure_session_t *sec = secure_session_find_by_timer_id(timer_id); 00545 if (sec) { 00546 return (int)sec->timer.state; 00547 } 00548 return TIMER_STATE_CANCELLED; 00549 } 00550 00551 static int read_data(socket_callback_t *sckt_data, internal_socket_t *sock, ns_address_t *src_address, uint8_t dst_address[static 16]) 00552 { 00553 sock->data_len = 0; 00554 sock->recv_if_id = -1; 00555 if (sckt_data->event_type == SOCKET_DATA && sckt_data->d_len > 0) { 00556 uint8_t ancillary_databuffer[NS_CMSG_SPACE(sizeof(ns_in6_pktinfo_t))]; 00557 ns_iovec_t msg_iov; 00558 ns_msghdr_t msghdr; 00559 ns_in6_pktinfo_t *pkt = NULL; 00560 00561 if (sock->data) { 00562 ns_dyn_mem_free(sock->data); 00563 sock->data = NULL; 00564 } 00565 00566 sock->data = ns_dyn_mem_temporary_alloc(sckt_data->d_len); 00567 if (!sock->data) { 00568 sock->data = NULL; 00569 return -1; 00570 } 00571 00572 msghdr.msg_name = src_address; 00573 msghdr.msg_namelen = sizeof(ns_address_t); 00574 msghdr.msg_iov = &msg_iov; 00575 msghdr.msg_iovlen = 1; 00576 msghdr.msg_control = ancillary_databuffer; 00577 msghdr.msg_controllen = sizeof(ancillary_databuffer); 00578 00579 msg_iov.iov_base = sock->data; 00580 msg_iov.iov_len = sckt_data->d_len; 00581 00582 sock->data_len = socket_recvmsg(sckt_data->socket_id, &msghdr, 0); 00583 00584 if (sock->data_len > 0) { 00585 ns_cmsghdr_t *cmsg = NS_CMSG_FIRSTHDR(&msghdr); 00586 00587 while (cmsg) { 00588 switch (cmsg->cmsg_type) { 00589 case SOCKET_IPV6_PKTINFO: 00590 pkt = (ns_in6_pktinfo_t *)NS_CMSG_DATA(cmsg); 00591 break; 00592 default: 00593 break; 00594 } 00595 cmsg = NS_CMSG_NXTHDR(&msghdr, cmsg); 00596 } 00597 if (pkt) { 00598 memcpy(dst_address, pkt->ipi6_addr, 16); 00599 sock->recv_if_id = pkt->ipi6_ifindex; 00600 } else { 00601 goto return_failure; 00602 } 00603 } else { 00604 goto return_failure; 00605 } 00606 } else { 00607 goto return_failure; 00608 } 00609 00610 return 0; 00611 00612 return_failure: 00613 ns_dyn_mem_free(sock->data); 00614 sock->data = NULL; 00615 sock->data_len = 0; 00616 return -1; 00617 00618 00619 } 00620 00621 #ifdef COAP_SECURITY_AVAILABLE 00622 static void secure_recv_sckt_msg(void *cb_res) 00623 { 00624 socket_callback_t *sckt_data = cb_res; 00625 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00626 ns_address_t src_address; 00627 uint8_t dst_address[16] = {0}; 00628 memset(&src_address, 0, sizeof(ns_address_t)); 00629 00630 if (sock && read_data(sckt_data, sock, &src_address, dst_address) == 0) { 00631 /* If received from multicast address, reject */ 00632 if (*(dst_address) == 0xFF) { 00633 return; 00634 } 00635 secure_session_t *session = secure_session_find(sock, src_address.address, src_address.identifier); 00636 00637 // Create session 00638 if (!session) { 00639 coap_security_keys_t keys; 00640 memset(&keys, 0, sizeof(coap_security_keys_t)); 00641 00642 if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, src_address.address, src_address.identifier, &keys)) { 00643 session = secure_session_create(sock, src_address.address, src_address.identifier, keys.mode); 00644 if (!session) { 00645 tr_err("secure_recv_sckt_msg session creation failed - OOM"); 00646 ns_dyn_mem_free(keys._key); 00647 return; 00648 } 00649 //TODO: error handling 00650 } else { 00651 return; 00652 } 00653 00654 // Record the destination. We are not strict on local address - all 00655 // session_find calls match only on remote address and port. But we 00656 // record the last-used destination address to use it as the source of 00657 // outgoing packets. 00658 memcpy(session->local_address, dst_address, 16); 00659 00660 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00661 // Start handshake 00662 if (!coap_security_handler_is_started(session->sec_handler)) { 00663 if (-1 == coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max)) { 00664 tr_err("Connection start failed"); 00665 secure_session_delete(session); 00666 } 00667 ns_dyn_mem_free(keys._key); 00668 } 00669 } else { 00670 //Continue handshake 00671 if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 00672 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00673 // Handshake done 00674 if (ret == 0) { 00675 eventOS_timeout_cancel(session->timer.timer); 00676 session->timer.timer = NULL; 00677 session->session_state = SECURE_SESSION_OK; 00678 if (sock->parent->_security_done_cb) { 00679 sock->parent->_security_done_cb(sock->socket, src_address.address, 00680 src_address.identifier, 00681 (void *)coap_security_handler_keyblock(session->sec_handler)); 00682 } 00683 } else if (ret < 0) { 00684 // error handling 00685 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00686 secure_session_delete(session); 00687 } 00688 //Session valid 00689 } else { 00690 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00691 int len = 0; 00692 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00693 if (len < 0) { 00694 if (len != MBEDTLS_ERR_SSL_WANT_READ && len != MBEDTLS_ERR_SSL_WANT_WRITE && 00695 len != MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { 00696 secure_session_delete(session); 00697 } 00698 ns_dyn_mem_free(data); 00699 } else { 00700 if (sock->parent->_recv_cb) { 00701 sock->parent->_recv_cb(sock->socket, sock->recv_if_id, src_address.address, src_address.identifier, dst_address, data, len); 00702 } 00703 ns_dyn_mem_free(data); 00704 } 00705 } 00706 } 00707 } 00708 } 00709 #endif 00710 00711 static void recv_sckt_msg(void *cb_res) 00712 { 00713 socket_callback_t *sckt_data = cb_res; 00714 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00715 ns_address_t src_address; 00716 uint8_t dst_address[16]; 00717 00718 if (sock && read_data(sckt_data, sock, &src_address, dst_address) == 0) { 00719 if (sock->parent && sock->parent->_recv_cb) { 00720 sock->parent->_recv_cb(sock->socket, sock->recv_if_id, src_address.address, src_address.identifier, dst_address, sock->data, sock->data_len); 00721 } 00722 ns_dyn_mem_free(sock->data); 00723 sock->data = NULL; 00724 } 00725 } 00726 00727 int coap_connection_handler_virtual_recv(coap_conn_handler_t *handler, uint8_t address[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len) 00728 { 00729 if (!handler || !handler->socket) { 00730 return -1; 00731 } 00732 internal_socket_t *sock = handler->socket; 00733 sock->data_len = data_len; 00734 if (sock->data) { 00735 ns_dyn_mem_free(sock->data); 00736 sock->data = NULL; 00737 } 00738 sock->data = ns_dyn_mem_temporary_alloc(data_len); 00739 if (data_len > 0 && !sock->data) { 00740 return -1; 00741 } 00742 if (data_ptr) { 00743 memcpy(sock->data, data_ptr, data_len); 00744 } else { 00745 if (sock->data) { 00746 ns_dyn_mem_free(sock->data); 00747 sock->data = NULL; 00748 } 00749 } 00750 00751 if (handler->socket->is_secure) { 00752 coap_security_keys_t keys; 00753 memset(&keys, 0, sizeof(coap_security_keys_t)); 00754 00755 secure_session_t *session = secure_session_find(sock, address, port); 00756 if (!session) { 00757 if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, &keys)) { 00758 session = secure_session_create(sock, address, port, keys.mode); 00759 if (!session) { 00760 tr_err("coap_connection_handler_virtual_recv session creation failed"); 00761 ns_dyn_mem_free(keys._key); 00762 return -1; 00763 } 00764 if (-1 == coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max)) { 00765 tr_err("Connection start failed"); 00766 ns_dyn_mem_free(keys._key); 00767 secure_session_delete(session); 00768 return -1; 00769 } 00770 ns_dyn_mem_free(keys._key); 00771 return 0; 00772 } else { 00773 return -1; 00774 } 00775 } 00776 00777 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00778 00779 if (coap_security_handler_is_started(session->sec_handler)) { 00780 if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 00781 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00782 if (ret == 0) { 00783 session->session_state = SECURE_SESSION_OK; 00784 if (handler->_security_done_cb) { 00785 handler->_security_done_cb(sock->socket, 00786 address, port, 00787 (void *)coap_security_handler_keyblock(session->sec_handler)); 00788 } 00789 return 0; 00790 } else if (ret < 0) { 00791 // error handling 00792 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00793 secure_session_delete(session); 00794 } 00795 //TODO: error handling 00796 } else { 00797 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00798 int len = 0; 00799 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00800 if (len < 0) { 00801 if (len != MBEDTLS_ERR_SSL_WANT_READ && len != MBEDTLS_ERR_SSL_WANT_WRITE && 00802 len != MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { 00803 secure_session_delete(session); 00804 } 00805 ns_dyn_mem_free(data); 00806 return 0; 00807 } else { 00808 if (sock->parent->_recv_cb) { 00809 sock->parent->_recv_cb(sock->socket, sock->recv_if_id, address, port, ns_in6addr_any, data, len); 00810 } 00811 ns_dyn_mem_free(data); 00812 data = NULL; 00813 } 00814 return 0; 00815 } 00816 } 00817 } else { 00818 /* unsecure*/ 00819 if (sock->parent->_recv_cb) { 00820 sock->parent->_recv_cb(sock->socket, sock->recv_if_id, address, port, ns_in6addr_any, sock->data, sock->data_len); 00821 } 00822 if (sock->data) { 00823 ns_dyn_mem_free(sock->data); 00824 sock->data = NULL; 00825 } 00826 return 0; 00827 } 00828 return -1; 00829 } 00830 00831 coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb, 00832 send_to_socket_cb *send_to_cb, 00833 get_pw_cb *pw_cb, 00834 security_done_cb *done_cb) 00835 { 00836 if (recv_from_cb == NULL) { 00837 return NULL; 00838 } 00839 00840 coap_conn_handler_t *handler = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00841 if (!handler) { 00842 return NULL; 00843 } 00844 memset(handler, 0, sizeof(coap_conn_handler_t)); 00845 handler->socket = NULL; 00846 handler->_recv_cb = recv_from_cb; 00847 handler->_send_cb = send_to_cb; 00848 00849 handler->_get_password_cb = pw_cb; 00850 handler->_security_done_cb = done_cb; 00851 00852 return handler; 00853 } 00854 00855 void connection_handler_destroy(coap_conn_handler_t *handler, bool multicast_group_leave) 00856 { 00857 if (handler) { 00858 if (multicast_group_leave) { 00859 coap_multicast_group_join_or_leave(handler->socket->socket, SOCKET_IPV6_LEAVE_GROUP, handler->socket_interface_selection); 00860 } 00861 if (handler->security_keys) { 00862 ns_dyn_mem_free(handler->security_keys); 00863 } 00864 int_socket_delete(handler->socket); 00865 ns_dyn_mem_free(handler); 00866 } 00867 } 00868 00869 void connection_handler_close_secure_connection(coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port) 00870 { 00871 if (handler) { 00872 if (handler->socket && handler->socket->is_secure) { 00873 secure_session_t *session = secure_session_find(handler->socket, destination_addr_ptr, port); 00874 if (session) { 00875 coap_security_send_close_alert(session->sec_handler); 00876 session->session_state = SECURE_SESSION_CLOSED; 00877 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00878 } 00879 } 00880 } 00881 } 00882 00883 int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool is_real_socket, bool bypassSec) 00884 { 00885 if (!handler) { 00886 return -1; 00887 } 00888 //virtual socket must have send callback 00889 if (!is_real_socket && !handler->_send_cb) { 00890 return -1; 00891 } 00892 if (handler->socket) { 00893 int_socket_delete(handler->socket); 00894 } 00895 00896 internal_socket_t *current = !use_ephemeral_port ? int_socket_find(listen_port, is_secure, is_real_socket, bypassSec) : NULL; 00897 if (!current) { 00898 handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec, handler->socket_interface_selection, handler->registered_to_multicast); 00899 if (!handler->socket) { 00900 return -1; 00901 } 00902 handler->socket->parent = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00903 if (!handler->socket->parent) { 00904 int_socket_delete(handler->socket); 00905 return -1; 00906 } 00907 *handler->socket->parent = *handler; 00908 } else { 00909 current->usage_counter++; 00910 handler->socket = current; 00911 } 00912 return 0; 00913 } 00914 00915 int coap_connection_handler_send_data(coap_conn_handler_t *handler, const ns_address_t *dest_addr, const uint8_t src_address[static 16], uint8_t *data_ptr, uint16_t data_len, bool bypass_link_sec) 00916 { 00917 if (!handler || !handler->socket || !dest_addr) { 00918 return -1; 00919 } 00920 00921 /* Secure send */ 00922 if (handler->socket->is_secure) { 00923 handler->socket->bypass_link_sec = bypass_link_sec; 00924 secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier); 00925 if (!session) { 00926 coap_security_keys_t security_material; 00927 int ret_val = 0; 00928 00929 memset(&security_material, 0, sizeof(coap_security_keys_t)); 00930 00931 if (!handler->_get_password_cb || 0 != handler->_get_password_cb(handler->socket->socket, (uint8_t *)dest_addr->address, dest_addr->identifier, &security_material)) { 00932 return -1; 00933 } 00934 00935 session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier, security_material.mode); 00936 if (!session || (0 > coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, security_material, handler->socket->timeout_min, handler->socket->timeout_max))) { 00937 ret_val = -1; 00938 } 00939 00940 ns_dyn_mem_free(security_material._key); 00941 return ret_val; 00942 00943 } else if (session->session_state == SECURE_SESSION_OK) { 00944 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00945 if (0 > coap_security_handler_send_message(session->sec_handler, data_ptr, data_len)) { 00946 return -1; 00947 } 00948 } 00949 /* Unsecure */ 00950 } else { 00951 /* Virtual socket */ 00952 if (!handler->socket->real_socket && handler->_send_cb) { 00953 if (handler->_send_cb((int8_t)handler->socket->socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len) < 0) { 00954 return -1; 00955 } 00956 } else { 00957 int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00958 int8_t securityLinkLayer = 1; 00959 if (bypass_link_sec) { 00960 securityLinkLayer = 0; 00961 } 00962 00963 socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); 00964 socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); 00965 00966 if (0 > send_to_real_socket(handler->socket->socket, dest_addr, src_address, data_ptr, data_len)) { 00967 return -1; 00968 } 00969 } 00970 } 00971 00972 return 1; 00973 } 00974 00975 bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id) 00976 { 00977 if (!handler || !handler->socket) { 00978 return false; 00979 } 00980 00981 if (handler->socket->socket == socket_id) { 00982 return true; 00983 } 00984 return false; 00985 } 00986 00987 int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max) 00988 { 00989 if (!handler || !handler->socket) { 00990 return -1; 00991 } 00992 handler->socket->timeout_max = max; 00993 handler->socket->timeout_min = min; 00994 00995 return 0; 00996 } 00997 00998 int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, uint8_t connections_limit) 00999 { 01000 if (!handshakes_limit || !connections_limit) { 01001 return -1; 01002 } 01003 max_handshakes = handshakes_limit; 01004 max_sessions = connections_limit; 01005 01006 return 0; 01007 } 01008 01009 /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */ 01010 void coap_connection_handler_exec(uint32_t time) 01011 { 01012 if (ns_list_count(&secure_session_list)) { 01013 // Seek & destroy old sessions where close notify have been sent 01014 ns_list_foreach_safe(secure_session_t, cur_ptr, &secure_session_list) { 01015 if (cur_ptr->session_state == SECURE_SESSION_CLOSED) { 01016 if ((cur_ptr->last_contact_time + CLOSED_SECURE_SESSION_TIMEOUT) <= time) { 01017 secure_session_delete(cur_ptr); 01018 } 01019 } else if (cur_ptr->session_state == SECURE_SESSION_OK) { 01020 if ((cur_ptr->last_contact_time + OPEN_SECURE_SESSION_TIMEOUT) <= time) { 01021 secure_session_delete(cur_ptr); 01022 } 01023 } else if (cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 01024 if ((cur_ptr->last_contact_time + ONGOING_HANDSHAKE_TIMEOUT) <= time) { 01025 secure_session_delete(cur_ptr); 01026 } 01027 } 01028 } 01029 } 01030 } 01031 01032 int coap_connection_handler_msg_prevalidate_callback_set(coap_conn_handler_t *handler, cch_func_cb *function_callback) 01033 { 01034 if (!handler) { 01035 return -1; 01036 } 01037 handler->socket->cch_function_callback = function_callback; 01038 return 0; 01039 } 01040 01041 coap_conn_handler_t *coap_connection_handler_find_by_socket_port(uint16_t listen_port) 01042 { 01043 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 01044 if (cur_ptr->listen_port == listen_port) { 01045 return cur_ptr->parent; 01046 } 01047 } 01048 return NULL; 01049 } 01050 01051 cch_func_cb *coap_connection_handler_msg_prevalidate_callback_get(coap_conn_handler_t *handler, uint16_t *listen_socket_port) 01052 { 01053 if (!handler || !listen_socket_port) { 01054 return NULL; 01055 } 01056 01057 *listen_socket_port = handler->socket->listen_port; 01058 return handler->socket->cch_function_callback; 01059 }
Generated on Tue Jul 12 2022 13:54:10 by
