ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_connection_handler.c Source File

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 }