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