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