Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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