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.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo 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 // XXX API for this? May want to get clever to do recommended first query = 1 hop, retries = whole PAN 00230 socket_setsockopt(this->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &(const int16_t) { 00231 16 00232 }, sizeof(int16_t)); 00233 }else{ 00234 this->listen_socket = -1; 00235 } 00236 00237 ns_list_add_to_start(&socket_list, this); 00238 return this; 00239 } 00240 00241 static void int_socket_delete(internal_socket_t *this) 00242 { 00243 if (this) { 00244 this->usage_counter--; 00245 if(this->usage_counter == 0){ 00246 clear_secure_sessions(this); 00247 socket_free(this->listen_socket); 00248 ns_list_remove(&socket_list, this); 00249 if( this->data ){ 00250 ns_dyn_mem_free(this->data); 00251 this->data = NULL; 00252 } 00253 if(this->parent){ 00254 ns_dyn_mem_free(this->parent); 00255 } 00256 ns_dyn_mem_free(this); 00257 } 00258 } 00259 } 00260 00261 static internal_socket_t *int_socket_find_by_socket_id(int8_t id) 00262 { 00263 internal_socket_t *this = NULL; 00264 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 00265 if( cur_ptr->listen_socket == id ) { 00266 this = cur_ptr; 00267 break; 00268 } 00269 } 00270 return this; 00271 } 00272 00273 static internal_socket_t *int_socket_find(uint16_t port, bool is_secure, bool is_real_socket, bool bypassSec) 00274 { 00275 (void) bypassSec; 00276 00277 internal_socket_t *this = NULL; 00278 ns_list_foreach(internal_socket_t, cur_ptr, &socket_list) { 00279 if( cur_ptr->listen_port == port && cur_ptr->real_socket == is_real_socket && 00280 is_secure == cur_ptr->is_secure /*&& bypass_link_sec == bypassSec*/) { 00281 this = cur_ptr; 00282 break; 00283 } 00284 } 00285 return this; 00286 } 00287 00288 static int send_to_socket(int8_t socket_id, uint8_t *address_ptr, uint16_t port, const unsigned char *buf, size_t len) 00289 { 00290 internal_socket_t *sock = int_socket_find_by_socket_id(socket_id); 00291 if(!sock){ 00292 return -1; 00293 } 00294 if(!sock->real_socket){ 00295 //In this case all clients will have socket_id -1 and socket will not have a real address 00296 //so sock->dest_addr cannot be used here 00297 int ret = sock->parent->_send_cb(sock->listen_socket, address_ptr, port, buf, len); 00298 if( ret < 0 ) 00299 return ret; 00300 return len; 00301 } 00302 00303 int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00304 int8_t securityLinkLayer = 1; 00305 if( sock->bypass_link_sec ){ 00306 securityLinkLayer = 0; 00307 } 00308 socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); 00309 socket_setsockopt(sock->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); 00310 //For some reason socket_sendto returns 0 in success, while other socket impls return number of bytes sent!!! 00311 //TODO: check if address_ptr is valid and use that instead if it is 00312 int ret = socket_sendto(sock->listen_socket, &sock->dest_addr, (unsigned char*)buf, len); 00313 if( ret < 0 ) 00314 return ret; 00315 return len; 00316 } 00317 00318 static int receive_from_socket(int8_t socket_id, unsigned char *buf, size_t len) 00319 { 00320 (void)len; 00321 internal_socket_t *sock = int_socket_find_by_socket_id(socket_id); 00322 if( sock->data && sock->data_len > 0 ){ 00323 memcpy( buf, sock->data, sock->data_len ); 00324 int l = sock->data_len; 00325 ns_dyn_mem_free(sock->data); 00326 sock->data = NULL; 00327 sock->data_len = 0; 00328 return l; 00329 } 00330 return MBEDTLS_ERR_SSL_WANT_READ; 00331 } 00332 00333 /** 00334 * Callback timer. Maybe called in interrupt context 00335 * so keep it simple. 00336 * TODO - might be better to use an event timer in conjunction with 00337 * CoAP tasklet 00338 */ 00339 static void timer_cb(void *param) 00340 { 00341 secure_session_t *sec = param; 00342 if( sec ){ 00343 if(sec->timer.fin_ms > sec->timer.int_ms){ 00344 /* Intermediate expiry */ 00345 sec->timer.fin_ms -= sec->timer.int_ms; 00346 sec->timer.state = TIMER_STATE_INT_EXPIRY; 00347 int error = coap_security_handler_continue_connecting(sec->sec_handler); 00348 if(MBEDTLS_ERR_SSL_TIMEOUT == error) { 00349 //TODO: How do we handle timeouts? 00350 secure_session_delete(sec); 00351 } 00352 else{ 00353 sec->timer.timer = eventOS_timeout_ms(timer_cb, sec->timer.int_ms, (void*)sec); 00354 } 00355 } 00356 else{ 00357 /* We have counted the number of cycles - finish */ 00358 eventOS_timeout_cancel(sec->timer.timer); 00359 sec->timer.fin_ms = 0; 00360 sec->timer.int_ms = 0; 00361 sec->timer.timer = NULL; 00362 sec->timer.state = TIMER_STATE_FIN_EXPIRY; 00363 int error = coap_security_handler_continue_connecting(sec->sec_handler); 00364 if(MBEDTLS_ERR_SSL_TIMEOUT == error) { 00365 //TODO: How do we handle timeouts? 00366 secure_session_delete(sec); 00367 } 00368 } 00369 } 00370 } 00371 00372 static void start_timer(int8_t timer_id, uint32_t int_ms, uint32_t fin_ms) 00373 { 00374 secure_session_t *sec = secure_session_find_by_timer_id(timer_id); 00375 if( sec ){ 00376 if ((int_ms > 0) && (fin_ms > 0)) { 00377 sec->timer.int_ms = int_ms; 00378 sec->timer.fin_ms = fin_ms; 00379 sec->timer.state = TIMER_STATE_NO_EXPIRY; 00380 if(sec->timer.timer){ 00381 eventOS_timeout_cancel(sec->timer.timer); 00382 } 00383 sec->timer.timer = eventOS_timeout_ms(timer_cb, int_ms, sec); 00384 } else if (fin_ms == 0) { 00385 /* fin_ms == 0 means cancel the timer */ 00386 sec->timer.state = TIMER_STATE_CANCELLED; 00387 eventOS_timeout_cancel(sec->timer.timer); 00388 sec->timer.fin_ms = 0; 00389 sec->timer.int_ms = 0; 00390 sec->timer.timer = NULL; 00391 } 00392 } 00393 } 00394 00395 static int timer_status(int8_t timer_id) 00396 { 00397 secure_session_t *sec = secure_session_find_by_timer_id(timer_id); 00398 if( sec ){ 00399 return (int)sec->timer.state; 00400 } 00401 return TIMER_STATE_CANCELLED; 00402 } 00403 00404 static int read_data(socket_callback_t *sckt_data, internal_socket_t *sock, ns_address_t *src_address) 00405 { 00406 sock->data_len = 0; 00407 if (sckt_data->event_type == SOCKET_DATA && sckt_data->d_len > 0) { 00408 if( sock->data ){ 00409 ns_dyn_mem_free(sock->data); 00410 sock->data = NULL; 00411 } 00412 sock->data = ns_dyn_mem_temporary_alloc(sckt_data->d_len); 00413 if( !sock->data ){ 00414 sock->data = NULL; 00415 return -1; 00416 } 00417 sock->data_len = socket_read(sckt_data->socket_id, src_address, sock->data, sckt_data->d_len); 00418 } 00419 if( sock->data_len < 1){ 00420 ns_dyn_mem_free(sock->data); 00421 sock->data = NULL; 00422 sock->data_len = 0; 00423 return -1; 00424 } 00425 return 0; 00426 } 00427 00428 static void secure_recv_sckt_msg(void *cb_res) 00429 { 00430 socket_callback_t *sckt_data = cb_res; 00431 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00432 ns_address_t src_address; 00433 00434 if( sock && read_data(sckt_data, sock, &src_address) == 0 ){ 00435 secure_session_t *session = secure_session_find(sock, src_address.address, src_address.identifier); 00436 00437 // Create session 00438 if( !session ){ 00439 memcpy( sock->dest_addr.address, src_address.address, 16 ); 00440 sock->dest_addr.identifier = src_address.identifier; 00441 sock->dest_addr.type = src_address.type; 00442 session = secure_session_create(sock, src_address.address, src_address.identifier); 00443 } 00444 if( !session ){ 00445 tr_err("secure_recv_sckt_msg session creation failed - OOM"); 00446 return; 00447 } 00448 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00449 // Start handshake 00450 if( !session->sec_handler->_is_started ){ 00451 uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64); 00452 uint8_t pw_len; 00453 if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, src_address.address, src_address.identifier, pw, &pw_len)){ 00454 //TODO: get_password_cb should support certs and PSK also 00455 coap_security_keys_t keys; 00456 keys._priv = pw; 00457 keys._priv_len = pw_len; 00458 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max); 00459 //TODO: error handling 00460 } 00461 ns_dyn_mem_free(pw); 00462 }else{ 00463 //Continue handshake 00464 if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ 00465 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00466 // Handshake done 00467 if(ret == 0){ 00468 eventOS_timeout_cancel(session->timer.timer); 00469 session->timer.timer = NULL; 00470 session->session_state = SECURE_SESSION_OK; 00471 if( sock->parent->_security_done_cb ){ 00472 sock->parent->_security_done_cb(sock->listen_socket, src_address.address, 00473 src_address.identifier, 00474 session->sec_handler->_keyblk.value); 00475 } 00476 } 00477 else if (ret < 0){ 00478 // error handling 00479 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00480 secure_session_delete(session); 00481 } 00482 //Session valid 00483 }else{ 00484 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00485 int len = 0; 00486 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00487 if( len < 0 ){ 00488 ns_dyn_mem_free(data); 00489 secure_session_delete( session ); 00490 }else{ 00491 if( sock->parent->_recv_cb ){ 00492 sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, data, len); 00493 } 00494 ns_dyn_mem_free(data); 00495 } 00496 } 00497 } 00498 } 00499 } 00500 00501 static void recv_sckt_msg(void *cb_res) 00502 { 00503 socket_callback_t *sckt_data = cb_res; 00504 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00505 ns_address_t src_address; 00506 if( sock && read_data(sckt_data, sock, &src_address) == 0 ){ 00507 if(sock->parent && sock->parent->_recv_cb){ 00508 sock->parent->_recv_cb(sock->listen_socket, src_address.address, src_address.identifier, sock->data, sock->data_len); 00509 } 00510 ns_dyn_mem_free(sock->data); 00511 sock->data = NULL; 00512 } 00513 } 00514 00515 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) 00516 { 00517 if( !handler || !handler->socket ){ 00518 return -1; 00519 } 00520 internal_socket_t *sock = handler->socket; 00521 sock->data_len = data_len; 00522 if( sock->data ){ 00523 ns_dyn_mem_free(sock->data); 00524 sock->data = NULL; 00525 } 00526 sock->data = ns_dyn_mem_temporary_alloc(data_len); 00527 if( data_len > 0 && !sock->data ){ 00528 return -1; 00529 } 00530 if( data_ptr ){ 00531 memcpy(sock->data, data_ptr, data_len); 00532 }else{ 00533 if( sock->data ){ 00534 ns_dyn_mem_free(sock->data); 00535 sock->data = NULL; 00536 } 00537 } 00538 00539 if( handler->socket->is_secure ){ 00540 secure_session_t *session = secure_session_find(sock, address, port); 00541 if( !session ){ 00542 session = secure_session_create(sock, address, port); 00543 } 00544 if( !session ){ 00545 tr_err("coap_connection_handler_virtual_recv session creation failed - OOM"); 00546 return -1; 00547 } 00548 00549 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00550 00551 if( !session->sec_handler->_is_started ){ 00552 uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64); 00553 uint8_t pw_len; 00554 if( sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->listen_socket, address, port, pw, &pw_len)){ 00555 //TODO: get_password_cb should support certs and PSK also 00556 coap_security_keys_t keys; 00557 keys._priv = pw; 00558 keys._priv_len = pw_len; 00559 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); 00560 //TODO: error handling 00561 ns_dyn_mem_free(pw); 00562 return 0; 00563 }else{ 00564 ns_dyn_mem_free(pw); 00565 return -1; 00566 } 00567 }else{ 00568 if(session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ 00569 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00570 if(ret == 0){ 00571 session->session_state = SECURE_SESSION_OK; 00572 if( handler->_security_done_cb ){ 00573 handler->_security_done_cb(sock->listen_socket, 00574 address, port, 00575 session->sec_handler->_keyblk.value); 00576 } 00577 return 0; 00578 } 00579 else if(ret < 0) 00580 { 00581 // error handling 00582 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00583 secure_session_delete(session); 00584 } 00585 //TODO: error handling 00586 }else{ 00587 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00588 int len = 0; 00589 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00590 if( len < 0 ){ 00591 ns_dyn_mem_free(data); 00592 secure_session_delete( session ); 00593 return 0; 00594 }else{ 00595 if( sock->parent->_recv_cb ){ 00596 sock->parent->_recv_cb(sock->listen_socket, address, port, data, len); 00597 } 00598 ns_dyn_mem_free(data); 00599 data = NULL; 00600 } 00601 return 0; 00602 } 00603 } 00604 }else{ 00605 if( sock->parent->_recv_cb ){ 00606 sock->parent->_recv_cb(sock->listen_socket, address, port, sock->data, sock->data_len); 00607 } 00608 if( sock->data ){ 00609 ns_dyn_mem_free(sock->data); 00610 sock->data = NULL; 00611 } 00612 return 0; 00613 } 00614 return -1; 00615 } 00616 00617 coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb, 00618 send_to_socket_cb *send_to_cb, 00619 get_pw_cb *pw_cb, 00620 security_done_cb *done_cb ) 00621 { 00622 if( recv_from_cb == NULL ){ 00623 return NULL; 00624 } 00625 00626 coap_conn_handler_t *handler = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00627 if(!handler){ 00628 return NULL; 00629 } 00630 memset(handler, 0, sizeof(coap_conn_handler_t)); 00631 handler->socket = NULL; 00632 handler->_recv_cb = recv_from_cb; 00633 handler->_send_cb = send_to_cb; 00634 00635 handler->_get_password_cb = pw_cb; 00636 handler->_security_done_cb = done_cb; 00637 00638 return handler; 00639 } 00640 void connection_handler_destroy(coap_conn_handler_t *handler) 00641 { 00642 if(handler){ 00643 int_socket_delete(handler->socket); 00644 ns_dyn_mem_free(handler); 00645 } 00646 } 00647 00648 void connection_handler_close_secure_connection( coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port ) 00649 { 00650 if(handler){ 00651 if( handler->socket && handler->socket->is_secure){ 00652 secure_session_t *session = secure_session_find( handler->socket, destination_addr_ptr, port); 00653 if( session ){ 00654 coap_security_send_close_alert( session->sec_handler ); 00655 session->session_state = SECURE_SESSION_CLOSED; 00656 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00657 } 00658 } 00659 } 00660 } 00661 00662 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) 00663 { 00664 if( !handler ){ 00665 return -1; 00666 } 00667 //virtual socket must have send callback 00668 if( !is_real_socket && !handler->_send_cb ){ 00669 return -1; 00670 } 00671 if( handler->socket ){ 00672 int_socket_delete(handler->socket); 00673 } 00674 00675 internal_socket_t *current = !use_ephemeral_port?int_socket_find(listen_port, is_secure, is_real_socket, bypassSec):NULL; 00676 if(!current){ 00677 handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec); 00678 if(!handler->socket){ 00679 return -1; 00680 } 00681 handler->socket->parent = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00682 if(!handler->socket->parent){ 00683 int_socket_delete(handler->socket); 00684 return -1; 00685 } 00686 *handler->socket->parent = *handler; 00687 }else{ 00688 current->usage_counter++; 00689 handler->socket = current; 00690 } 00691 return 0; 00692 } 00693 00694 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) 00695 { 00696 if( !handler || !handler->socket || !dest_addr){ 00697 return -1; 00698 } 00699 if(handler->socket->is_secure){ 00700 handler->socket->bypass_link_sec = bypass_link_sec; 00701 memcpy(handler->socket->dest_addr.address, dest_addr->address, 16); 00702 handler->socket->dest_addr.identifier = dest_addr->identifier; 00703 handler->socket->dest_addr.type = dest_addr->type; 00704 secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier); 00705 if( !session ){ 00706 session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier); 00707 if( !session ){ 00708 return -1; 00709 } 00710 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00711 memcpy( handler->socket->dest_addr.address, dest_addr->address, 16 ); 00712 handler->socket->dest_addr.identifier = dest_addr->identifier; 00713 handler->socket->dest_addr.type = dest_addr->type; 00714 uint8_t *pw = (uint8_t *)ns_dyn_mem_alloc(64); 00715 if(!pw){ 00716 //todo: free secure session? 00717 return -1; 00718 } 00719 uint8_t pw_len; 00720 if( handler->_get_password_cb && 0 == handler->_get_password_cb(handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, 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, false, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); 00726 ns_dyn_mem_free(pw); 00727 return -2; 00728 }else{ 00729 //free secure session? 00730 ns_dyn_mem_free(pw); 00731 return -1; 00732 } 00733 }else if( session->session_state == SECURE_SESSION_OK ){ 00734 if( coap_security_handler_send_message(session->sec_handler, data_ptr, data_len ) > 0 ){ 00735 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00736 return 0; 00737 } 00738 } 00739 return -1; 00740 }else{ 00741 if( !handler->socket->real_socket && handler->_send_cb){ 00742 return handler->_send_cb((int8_t)handler->socket->listen_socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len); 00743 } 00744 int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00745 int8_t securityLinkLayer = 1; 00746 if( bypass_link_sec ){ 00747 securityLinkLayer = 0; 00748 } 00749 socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); 00750 socket_setsockopt(handler->socket->listen_socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); 00751 return socket_sendto(handler->socket->listen_socket, dest_addr, data_ptr, data_len); 00752 } 00753 } 00754 00755 bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id) 00756 { 00757 if( !handler || !handler->socket){ 00758 return false; 00759 } 00760 00761 if( handler->socket->listen_socket == socket_id){ 00762 return true; 00763 } 00764 return false; 00765 } 00766 00767 int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max) 00768 { 00769 if(!handler || !handler->socket){ 00770 return -1; 00771 } 00772 handler->socket->timeout_max = max; 00773 handler->socket->timeout_min = min; 00774 00775 return 0; 00776 } 00777 00778 /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */ 00779 void coap_connection_handler_exec(uint32_t time) 00780 { 00781 if(ns_list_count(&secure_session_list)){ 00782 // Seek & destroy old sessions where close notify have been sent 00783 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 00784 if(cur_ptr->session_state == SECURE_SESSION_CLOSED || 00785 cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ 00786 if((cur_ptr->last_contact_time + CLOSED_SECURE_SESSION_TIMEOUT) <= time){ 00787 secure_session_delete(cur_ptr); 00788 } 00789 } 00790 if(cur_ptr->session_state == SECURE_SESSION_OK){ 00791 if((cur_ptr->last_contact_time + OPEN_SECURE_SESSION_TIMEOUT) <= time){ 00792 secure_session_delete(cur_ptr); 00793 } 00794 } 00795 } 00796 } 00797 }
Generated on Tue Jul 12 2022 12:28:28 by
