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], int8_t *interface) 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 *interface = pkt->ipi6_ifindex; 00588 } else { 00589 goto return_failure; 00590 } 00591 } else { 00592 goto return_failure; 00593 } 00594 } else { 00595 goto return_failure; 00596 } 00597 00598 return 0; 00599 00600 return_failure: 00601 ns_dyn_mem_free(sock->data); 00602 sock->data = NULL; 00603 sock->data_len = 0; 00604 return -1; 00605 00606 00607 } 00608 00609 #ifdef COAP_SECURITY_AVAILABLE 00610 static void secure_recv_sckt_msg(void *cb_res) 00611 { 00612 socket_callback_t *sckt_data = cb_res; 00613 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00614 ns_address_t src_address; 00615 uint8_t dst_address[16] = {0}; 00616 memset(&src_address, 0, sizeof(ns_address_t)); 00617 int8_t interface_id = -1; 00618 00619 if (sock && read_data(sckt_data, sock, &src_address, dst_address, &interface_id) == 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 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, sock->timeout_min, sock->timeout_max); 00653 ns_dyn_mem_free(keys._key); 00654 00655 } 00656 } else { 00657 //Continue handshake 00658 if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 00659 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00660 // Handshake done 00661 if (ret == 0) { 00662 eventOS_timeout_cancel(session->timer.timer); 00663 session->timer.timer = NULL; 00664 session->session_state = SECURE_SESSION_OK; 00665 if( sock->parent->_security_done_cb ){ 00666 sock->parent->_security_done_cb(sock->socket, src_address.address, 00667 src_address.identifier, 00668 (void *)coap_security_handler_keyblock(session->sec_handler)); 00669 } 00670 } else if (ret < 0){ 00671 // error handling 00672 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00673 secure_session_delete(session); 00674 } 00675 //Session valid 00676 } else { 00677 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00678 int len = 0; 00679 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00680 if( len < 0 ){ 00681 if (len != MBEDTLS_ERR_SSL_WANT_READ && len != MBEDTLS_ERR_SSL_WANT_WRITE && 00682 len != MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { 00683 secure_session_delete(session); 00684 } 00685 ns_dyn_mem_free(data); 00686 } else { 00687 if (sock->parent->_recv_cb) { 00688 sock->parent->_recv_cb(sock->socket, interface_id, src_address.address, src_address.identifier, dst_address, data, len); 00689 } 00690 ns_dyn_mem_free(data); 00691 } 00692 } 00693 } 00694 } 00695 } 00696 #endif 00697 00698 static void recv_sckt_msg(void *cb_res) 00699 { 00700 socket_callback_t *sckt_data = cb_res; 00701 internal_socket_t *sock = int_socket_find_by_socket_id(sckt_data->socket_id); 00702 ns_address_t src_address; 00703 uint8_t dst_address[16]; 00704 int8_t interface_id = -1; 00705 00706 if (sock && read_data(sckt_data, sock, &src_address, dst_address, &interface_id) == 0) { 00707 if (sock->parent && sock->parent->_recv_cb) { 00708 sock->parent->_recv_cb(sock->socket, interface_id, src_address.address, src_address.identifier, dst_address, sock->data, sock->data_len); 00709 } 00710 ns_dyn_mem_free(sock->data); 00711 sock->data = NULL; 00712 } 00713 } 00714 00715 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) 00716 { 00717 int8_t interface_id = -1; 00718 00719 if(!handler || !handler->socket) { 00720 return -1; 00721 } 00722 internal_socket_t *sock = handler->socket; 00723 sock->data_len = data_len; 00724 if (sock->data) { 00725 ns_dyn_mem_free(sock->data); 00726 sock->data = NULL; 00727 } 00728 sock->data = ns_dyn_mem_temporary_alloc(data_len); 00729 if (data_len > 0 && !sock->data) { 00730 return -1; 00731 } 00732 if (data_ptr) { 00733 memcpy(sock->data, data_ptr, data_len); 00734 } else { 00735 if (sock->data) { 00736 ns_dyn_mem_free(sock->data); 00737 sock->data = NULL; 00738 } 00739 } 00740 00741 if (handler->socket->is_secure) { 00742 coap_security_keys_t keys; 00743 memset(&keys, 0, sizeof(coap_security_keys_t)); 00744 00745 secure_session_t *session = secure_session_find(sock, address, port); 00746 if (!session) { 00747 if (sock->parent->_get_password_cb && 0 == sock->parent->_get_password_cb(sock->socket, address, port, &keys)) { 00748 session = secure_session_create(sock, address, port, keys.mode); 00749 if (!session) { 00750 tr_err("coap_connection_handler_virtual_recv session creation failed - OOM"); 00751 ns_dyn_mem_free(keys._key); 00752 return -1; 00753 } 00754 coap_security_handler_connect_non_blocking(session->sec_handler, true, DTLS, keys, handler->socket->timeout_min, handler->socket->timeout_max); 00755 ns_dyn_mem_free(keys._key); 00756 return 0; 00757 } else { 00758 return -1; 00759 } 00760 } 00761 00762 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00763 00764 if (coap_security_handler_is_started(session->sec_handler)) { 00765 if (session->session_state == SECURE_SESSION_HANDSHAKE_ONGOING) { 00766 int ret = coap_security_handler_continue_connecting(session->sec_handler); 00767 if(ret == 0){ 00768 session->session_state = SECURE_SESSION_OK; 00769 if( handler->_security_done_cb ){ 00770 handler->_security_done_cb(sock->socket, 00771 address, port, 00772 (void *)coap_security_handler_keyblock(session->sec_handler)); 00773 } 00774 return 0; 00775 } 00776 else if (ret < 0) { 00777 // error handling 00778 // TODO: here we also should clear CoAP retransmission buffer and inform that CoAP request sending is failed. 00779 secure_session_delete(session); 00780 } 00781 //TODO: error handling 00782 } else { 00783 unsigned char *data = ns_dyn_mem_temporary_alloc(sock->data_len); 00784 int len = 0; 00785 len = coap_security_handler_read(session->sec_handler, data, sock->data_len); 00786 if (len < 0) { 00787 if (len != MBEDTLS_ERR_SSL_WANT_READ && len != MBEDTLS_ERR_SSL_WANT_WRITE && 00788 len != MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) { 00789 secure_session_delete(session); 00790 } 00791 ns_dyn_mem_free(data); 00792 return 0; 00793 } else { 00794 if (sock->parent->_recv_cb) { 00795 sock->parent->_recv_cb(sock->socket, interface_id, address, port, ns_in6addr_any, data, len); 00796 } 00797 ns_dyn_mem_free(data); 00798 data = NULL; 00799 } 00800 return 0; 00801 } 00802 } 00803 } else { 00804 /* unsecure*/ 00805 if (sock->parent->_recv_cb) { 00806 sock->parent->_recv_cb(sock->socket, interface_id, address, port, ns_in6addr_any, sock->data, sock->data_len); 00807 } 00808 if (sock->data) { 00809 ns_dyn_mem_free(sock->data); 00810 sock->data = NULL; 00811 } 00812 return 0; 00813 } 00814 return -1; 00815 } 00816 00817 coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb, 00818 send_to_socket_cb *send_to_cb, 00819 get_pw_cb *pw_cb, 00820 security_done_cb *done_cb ) 00821 { 00822 if(recv_from_cb == NULL) { 00823 return NULL; 00824 } 00825 00826 coap_conn_handler_t *handler = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00827 if(!handler){ 00828 return NULL; 00829 } 00830 memset(handler, 0, sizeof(coap_conn_handler_t)); 00831 handler->socket = NULL; 00832 handler->_recv_cb = recv_from_cb; 00833 handler->_send_cb = send_to_cb; 00834 00835 handler->_get_password_cb = pw_cb; 00836 handler->_security_done_cb = done_cb; 00837 00838 return handler; 00839 } 00840 00841 void connection_handler_destroy(coap_conn_handler_t *handler, bool multicast_group_leave) 00842 { 00843 if(handler){ 00844 if (multicast_group_leave) { 00845 coap_multicast_group_join_or_leave(handler->socket->socket, SOCKET_IPV6_LEAVE_GROUP, handler->socket_interface_selection); 00846 } 00847 if (handler->security_keys) { 00848 ns_dyn_mem_free(handler->security_keys); 00849 } 00850 int_socket_delete(handler->socket); 00851 ns_dyn_mem_free(handler); 00852 } 00853 } 00854 00855 void connection_handler_close_secure_connection( coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port ) 00856 { 00857 if (handler) { 00858 if (handler->socket && handler->socket->is_secure) { 00859 secure_session_t *session = secure_session_find( handler->socket, destination_addr_ptr, port ); 00860 if (session) { 00861 coap_security_send_close_alert( session->sec_handler ); 00862 session->session_state = SECURE_SESSION_CLOSED; 00863 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00864 } 00865 } 00866 } 00867 } 00868 00869 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) 00870 { 00871 if (!handler) { 00872 return -1; 00873 } 00874 //virtual socket must have send callback 00875 if (!is_real_socket && !handler->_send_cb) { 00876 return -1; 00877 } 00878 if (handler->socket) { 00879 int_socket_delete(handler->socket); 00880 } 00881 00882 internal_socket_t *current = !use_ephemeral_port?int_socket_find(listen_port, is_secure, is_real_socket, bypassSec):NULL; 00883 if (!current) { 00884 handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec, handler->socket_interface_selection, handler->registered_to_multicast); 00885 if (!handler->socket) { 00886 return -1; 00887 } 00888 handler->socket->parent = ns_dyn_mem_alloc(sizeof(coap_conn_handler_t)); 00889 if (!handler->socket->parent) { 00890 int_socket_delete(handler->socket); 00891 return -1; 00892 } 00893 *handler->socket->parent = *handler; 00894 } else { 00895 current->usage_counter++; 00896 handler->socket = current; 00897 } 00898 return 0; 00899 } 00900 00901 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) 00902 { 00903 if (!handler || !handler->socket || !dest_addr) { 00904 return -1; 00905 } 00906 00907 /* Secure send */ 00908 if (handler->socket->is_secure) { 00909 handler->socket->bypass_link_sec = bypass_link_sec; 00910 secure_session_t *session = secure_session_find(handler->socket, dest_addr->address, dest_addr->identifier); 00911 if (!session) { 00912 coap_security_keys_t security_material; 00913 int ret_val = 0; 00914 00915 memset(&security_material, 0, sizeof(coap_security_keys_t)); 00916 00917 if (!handler->_get_password_cb || 0 != handler->_get_password_cb(handler->socket->socket, (uint8_t*)dest_addr->address, dest_addr->identifier, &security_material)) { 00918 return -1; 00919 } 00920 00921 session = secure_session_create(handler->socket, dest_addr->address, dest_addr->identifier, security_material.mode); 00922 if (!session || (0 > coap_security_handler_connect_non_blocking(session->sec_handler, false, DTLS, security_material, handler->socket->timeout_min, handler->socket->timeout_max))) { 00923 ret_val = -1; 00924 } 00925 00926 ns_dyn_mem_free(security_material._key); 00927 return ret_val; 00928 00929 } else if (session->session_state == SECURE_SESSION_OK) { 00930 session->last_contact_time = coap_service_get_internal_timer_ticks(); 00931 if (0 > coap_security_handler_send_message(session->sec_handler, data_ptr, data_len )) { 00932 return -1; 00933 } 00934 } 00935 /* Unsecure */ 00936 } else { 00937 /* Virtual socket */ 00938 if (!handler->socket->real_socket && handler->_send_cb) { 00939 if (handler->_send_cb((int8_t)handler->socket->socket, dest_addr->address, dest_addr->identifier, data_ptr, data_len) < 0) { 00940 return -1; 00941 } 00942 } else { 00943 int opt_name = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00944 int8_t securityLinkLayer = 1; 00945 if (bypass_link_sec) { 00946 securityLinkLayer = 0; 00947 } 00948 00949 socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &opt_name, sizeof(int)); 00950 socket_setsockopt(handler->socket->socket, SOCKET_IPPROTO_IPV6, SOCKET_LINK_LAYER_SECURITY, &securityLinkLayer, sizeof(int8_t)); 00951 00952 if (0 > send_to_real_socket(handler->socket->socket, dest_addr, src_address, data_ptr, data_len)) { 00953 return -1; 00954 } 00955 } 00956 } 00957 00958 return 1; 00959 } 00960 00961 bool coap_connection_handler_socket_belongs_to(coap_conn_handler_t *handler, int8_t socket_id) 00962 { 00963 if( !handler || !handler->socket){ 00964 return false; 00965 } 00966 00967 if( handler->socket->socket == socket_id){ 00968 return true; 00969 } 00970 return false; 00971 } 00972 00973 int8_t coap_connection_handler_set_timeout(coap_conn_handler_t *handler, uint32_t min, uint32_t max) 00974 { 00975 if(!handler || !handler->socket){ 00976 return -1; 00977 } 00978 handler->socket->timeout_max = max; 00979 handler->socket->timeout_min = min; 00980 00981 return 0; 00982 } 00983 00984 int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, uint8_t connections_limit) 00985 { 00986 if (!handshakes_limit || !connections_limit) { 00987 return -1; 00988 } 00989 max_handshakes = handshakes_limit; 00990 max_sessions = connections_limit; 00991 00992 return 0; 00993 } 00994 00995 /* No need to call every second - call rather like every minute (SECURE_SESSION_CLEAN_INTERVAL sets this) */ 00996 void coap_connection_handler_exec(uint32_t time) 00997 { 00998 if(ns_list_count(&secure_session_list)){ 00999 // Seek & destroy old sessions where close notify have been sent 01000 ns_list_foreach(secure_session_t, cur_ptr, &secure_session_list) { 01001 if(cur_ptr->session_state == SECURE_SESSION_CLOSED) { 01002 if((cur_ptr->last_contact_time + CLOSED_SECURE_SESSION_TIMEOUT) <= time){ 01003 secure_session_delete(cur_ptr); 01004 } 01005 } else if(cur_ptr->session_state == SECURE_SESSION_OK){ 01006 if((cur_ptr->last_contact_time + OPEN_SECURE_SESSION_TIMEOUT) <= time){ 01007 secure_session_delete(cur_ptr); 01008 } 01009 } else if(cur_ptr->session_state == SECURE_SESSION_HANDSHAKE_ONGOING){ 01010 if((cur_ptr->last_contact_time + ONGOING_HANDSHAKE_TIMEOUT) <= time){ 01011 secure_session_delete(cur_ptr); 01012 } 01013 } 01014 } 01015 } 01016 }
Generated on Tue Jul 12 2022 13:24:35 by
1.7.2