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.
Fork of mbed-os by
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 13:15:37 by
