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