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 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 }
Generated on Tue Aug 9 2022 00:37:04 by
1.7.2