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.
Fork of OmniWheels by
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 Fri Jul 22 2022 04:53:46 by
1.7.2
