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