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