takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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