diff --git a/applications/zpc/components/zwave/zwave_controller/src/zwave_controller_callbacks.c b/applications/zpc/components/zwave/zwave_controller/src/zwave_controller_callbacks.c index d92b3da52..e1f9dedd0 100644 --- a/applications/zpc/components/zwave/zwave_controller/src/zwave_controller_callbacks.c +++ b/applications/zpc/components/zwave/zwave_controller/src/zwave_controller_callbacks.c @@ -313,23 +313,11 @@ void zwave_controller_on_frame_received( frame_length); //If no transport plugins needs the frame parse it on to upper layers if (status == SL_STATUS_NOT_FOUND) { - // Check if the frame is a protocol CC - if (frame_data[0] == ZWAVE_CMD_CLASS_PROTOCOL || frame_data[0] == ZWAVE_CMD_CLASS_PROTOCOL_LR) - { - ZWAVE_CONTROLLER_DISPATCH_CALLBACKS(on_protocol_frame_received, - connection_info, - rx_options, - frame_data, - frame_length); - } - else - { - ZWAVE_CONTROLLER_DISPATCH_CALLBACKS(on_application_frame_received, - connection_info, - rx_options, - frame_data, - frame_length); - } + ZWAVE_CONTROLLER_DISPATCH_CALLBACKS(on_application_frame_received, + connection_info, + rx_options, + frame_data, + frame_length); } } diff --git a/applications/zpc/components/zwave/zwave_controller/test/zwave_controller_callbacks_test.c b/applications/zpc/components/zwave/zwave_controller/test/zwave_controller_callbacks_test.c index 98d5eb83e..81beafdd6 100644 --- a/applications/zpc/components/zwave/zwave_controller/test/zwave_controller_callbacks_test.c +++ b/applications/zpc/components/zwave/zwave_controller/test/zwave_controller_callbacks_test.c @@ -98,15 +98,6 @@ static void zwave_controller_on_protocol_cc_encryption_request( zwave_controller_on_protocol_cc_encryption_request_count += 1; } -static void zwave_controller_on_protocol_frame_received( - const zwave_controller_connection_info_t *connection_info, - const zwave_rx_receive_options_t *rx_options, - const uint8_t *frame_data, - uint16_t frame_length) -{ - zwave_controller_on_protocol_frame_received_count += 1; -} - static void zwave_controller_on_node_event_test(zwave_node_id_t node_id) { zwave_controller_on_node_event_test_call_count += 1; @@ -344,74 +335,6 @@ void test_zwave_controller_on_protocol_cc_encryption_request_received() callbacks.on_protocol_cc_encryption_request = NULL; } -void test_zwave_controller_on_controller_protocol_frames() -{ - // We need to inject a valid frame, as this will go through the transports - zwave_controller_on_frame_received(&info, - &rx_options, - protocol_frame_data, - sizeof(protocol_frame_data)); - TEST_ASSERT_EQUAL(0, zwave_controller_on_protocol_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_rx_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_application_frame_received_count); - - callbacks.on_rx_frame_received - = &zwave_controller_on_rx_frame_received_callback; - callbacks.on_application_frame_received - = &zwave_controller_on_application_frame_received; - callbacks.on_protocol_frame_received - = &zwave_controller_on_protocol_frame_received; - TEST_ASSERT_EQUAL(SL_STATUS_OK, - zwave_controller_register_callbacks(&callbacks)); - - zwave_controller_on_frame_received(&info, - &rx_options, - protocol_frame_data, - sizeof(protocol_frame_data)); - TEST_ASSERT_EQUAL(1, zwave_controller_on_protocol_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_application_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_rx_frame_received_count); - - // remove these callbacks: - callbacks.on_rx_frame_received = NULL; - callbacks.on_application_frame_received = NULL; - callbacks.on_protocol_frame_received = NULL; -} - -void test_zwave_controller_on_controller_protocol_lr_frames() -{ - // We need to inject a valid frame, as this will go through the transports - zwave_controller_on_frame_received(&info, - &rx_options, - protocol_lr_frame_data, - sizeof(protocol_lr_frame_data)); - TEST_ASSERT_EQUAL(0, zwave_controller_on_protocol_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_rx_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_application_frame_received_count); - - callbacks.on_rx_frame_received - = &zwave_controller_on_rx_frame_received_callback; - callbacks.on_application_frame_received - = &zwave_controller_on_application_frame_received; - callbacks.on_protocol_frame_received - = &zwave_controller_on_protocol_frame_received; - TEST_ASSERT_EQUAL(SL_STATUS_OK, - zwave_controller_register_callbacks(&callbacks)); - - zwave_controller_on_frame_received(&info, - &rx_options, - protocol_lr_frame_data, - sizeof(protocol_lr_frame_data)); - TEST_ASSERT_EQUAL(1, zwave_controller_on_protocol_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_application_frame_received_count); - TEST_ASSERT_EQUAL(0, zwave_controller_on_rx_frame_received_count); - - // remove these callbacks: - callbacks.on_rx_frame_received = NULL; - callbacks.on_application_frame_received = NULL; - callbacks.on_protocol_frame_received = NULL; -} - void test_zwave_controller_on_network_address_update() { // Nothing happens with no callback registered diff --git a/applications/zpc/components/zwave/zwave_transports/s2/CMakeLists.txt b/applications/zpc/components/zwave/zwave_transports/s2/CMakeLists.txt index a2e9a15df..120e81bd6 100644 --- a/applications/zpc/components/zwave/zwave_transports/s2/CMakeLists.txt +++ b/applications/zpc/components/zwave/zwave_transports/s2/CMakeLists.txt @@ -18,7 +18,7 @@ set(KEYSTORE_SOURCES "src/zwave_s2_keystore.c") add_library( zwave_s2 src/zwave_s2_fixt.c ${KEYSTORE_SOURCES} src/zwave_s2_network.c - src/zwave_s2_printf.c src/zwave_s2_process.c src/zwave_s2_transport.c src/zwave_s2_protocol_cc_encryption.c) + src/zwave_s2_printf.c src/zwave_s2_process.c src/zwave_s2_transport.c) set(DEFAULT_ZW-LIBS2_PATH libs/zw-libs2) if(EXISTS ${ZW-LIBS2_LOCATION}) @@ -40,13 +40,12 @@ target_include_directories( zwave_s2 PUBLIC include PRIVATE ${ZW-LIBS2_PATH}/include src) - install(TARGETS zwave_s2 LIBRARY DESTINATION lib) target_link_libraries( zwave_s2 PUBLIC zwave_s2_nonce_management unify - PRIVATE s2_controller zwave_controller zwave_s0 zpc_attribute_store) + PRIVATE s2_controller zwave_controller zwave_s0 zpc_attribute_store zpc_utils) target_compile_definitions(zwave_s2 PRIVATE ZIPGW ZW_CONTROLLER) diff --git a/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_process.c b/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_process.c index c5507c60e..96f710007 100644 --- a/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_process.c +++ b/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_process.c @@ -22,7 +22,6 @@ #include "zwave_s2_keystore_int.h" #include "zwave_s2_network.h" #include "zwave_s2_transport.h" -#include "zwave_s2_protocol_cc_encryption.h" #define LOG_TAG "zwave_s2_process" @@ -86,7 +85,6 @@ static void zwave_s2_init() .on_network_address_update = zwave_s2_on_network_address_update, .on_new_network_entered = zwave_s2_on_new_network_entered, .on_multicast_group_deleted = zwave_s2_on_on_multicast_group_deleted, - .on_protocol_cc_encryption_request = zwave_s2_on_protocol_cc_encryption_request, }; zwave_controller_register_callbacks(&callbacks); diff --git a/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_protocol_cc_encryption.c b/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_protocol_cc_encryption.c deleted file mode 100644 index 5dc7d34f7..000000000 --- a/applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_protocol_cc_encryption.c +++ /dev/null @@ -1,80 +0,0 @@ -/****************************************************************************** - * # License - * Copyright 2021 Silicon Laboratories Inc. www.silabs.com - ****************************************************************************** - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - *****************************************************************************/ -#include "zwave_controller_transport.h" -#include "zwave_controller_transport_internal.h" -#include "sl_log.h" -#include "zwave_controller.h" -#include "zwave_s2_internal.h" -#include "zwave_s2_transport.h" -#include "zwave_s2_protocol_cc_encryption.h" -#include "zwave_tx_scheme_selector.h" - -#define LOG_TAG "zwave_s2_protocol_cc_encryption" - -protocol_metadata_t metadata = {0}; - -static void on_send_protocol_data_callback_received(uint8_t status, const zwapi_tx_report_t *tx_info, void *user) -{ - protocol_metadata_t *metadata = (protocol_metadata_t *)user; - - if (status == TRANSMIT_COMPLETE_FAIL || status == TRANSMIT_COMPLETE_VERIFIED) { - zwave_controller_request_protocol_cc_encryption_callback(status, tx_info, metadata->session_id); - } else { - sl_log_debug(LOG_TAG, "Send Protocol Data callback, status: %d", status); - } -} - -void zwave_s2_on_protocol_cc_encryption_request( - const zwave_node_id_t destination_node_id, - const uint8_t payload_length, - const uint8_t *const payload, - const uint8_t protocol_metadata_length, - const uint8_t *const protocol_metadata, - const uint8_t use_supervision, - const uint8_t session_id) -{ - zwave_controller_connection_info_t connection_info = {0}; - zwave_tx_options_t tx_options = {0}; - uint8_t number_of_expected_responses = 1; - uint32_t discard_timeout_ms = 5000; - sl_status_t ret = SL_STATUS_OK; - zwave_tx_session_id_t tx_session_id = NULL; - - zwave_tx_scheme_get_node_connection_info(destination_node_id, 0, &connection_info); - zwave_tx_scheme_get_node_tx_options( - ZWAVE_TX_QOS_MAX_PRIORITY, - number_of_expected_responses, - discard_timeout_ms, - &tx_options); - - // Other TX options are set in the transport layer in `S2_send_frame` - tx_options.transport.is_protocol_frame = true; - - metadata.session_id = session_id; - metadata.data_length = protocol_metadata_length; - memcpy(metadata.data, protocol_metadata, protocol_metadata_length); - - // Following command will trigger a "Send Protocol Data" command and the callback - // provided to this function will be triggered when the callback data frame of - // the "Send Protocol Data" command is received. - ret = zwave_tx_send_data(&connection_info, - payload_length, - payload, - &tx_options, - on_send_protocol_data_callback_received, - (void *)&metadata, - &tx_session_id); - if (ret != SL_STATUS_OK) { - sl_log_error(LOG_TAG, "Unable to send S2 data. Error code %d.", ret); - } -} diff --git a/applications/zpc/components/zwave/zwave_transports/s2/test/CMakeLists.txt b/applications/zpc/components/zwave/zwave_transports/s2/test/CMakeLists.txt index 52abf038e..64e1107bc 100644 --- a/applications/zpc/components/zwave/zwave_transports/s2/test/CMakeLists.txt +++ b/applications/zpc/components/zwave/zwave_transports/s2/test/CMakeLists.txt @@ -65,21 +65,6 @@ target_add_unittest( zpc_attribute_store_test_helper zwave_network_management_mock) -# ####################### S2 Protocol CC Encryption test ################################## -target_add_unittest( - zwave_s2 - NAME - zwave_s2_protocol_cc_encryption_test - SOURCES - zwave_s2_protocol_cc_encryption_test.c - DEPENDS - zwave_controller ## Non-mock, we use the real thing here - libs2_mock - zwave_api_mock - uic_contiki_stub - zwave_tx_mock - zwave_network_management_mock) - # ####################### S2 Nonce Management test ################################## target_add_unittest( zwave_s2_nonce_management diff --git a/applications/zpc/components/zwave/zwave_transports/s2/test/zwave_s2_protocol_cc_encryption_test.c b/applications/zpc/components/zwave/zwave_transports/s2/test/zwave_s2_protocol_cc_encryption_test.c deleted file mode 100644 index b90d6f0d8..000000000 --- a/applications/zpc/components/zwave/zwave_transports/s2/test/zwave_s2_protocol_cc_encryption_test.c +++ /dev/null @@ -1,96 +0,0 @@ -/****************************************************************************** - * # License - * Copyright 2021 Silicon Laboratories Inc. www.silabs.com - ****************************************************************************** - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - *****************************************************************************/ -#include - -#include "contiki_test_helper.h" - -#include "zwave_s2_protocol_cc_encryption.h" - -#include "zwave_controller_connection_info.h" - -#include "zwave_tx_mock.h" - -#include "sl_log.h" -#include "sl_status.h" - -#include "unity.h" - -/// Setup the test suite (called once before all test_xxx functions are called) -void suiteSetUp() {} - -/// Teardown the test suite (called once after all test_xxx functions are called) -int suiteTearDown(int num_failures) -{ - return num_failures; -} - -void setUp() -{ - contiki_test_helper_init(); -} - -void tearDown() {} - -void test_zwave_s2_on_protocol_cc_encryption_request_happy_case() -{ - zwave_node_id_t destination_node_id = 2; - uint8_t payload[] = {0x01, 0x02, 0x03}; - uint8_t payload_length = sizeof(payload); - uint8_t protocol_metadata[] = {0xA1, 0xA2, 0xA3}; - uint8_t protocol_metadata_length = sizeof(protocol_metadata); - uint8_t use_supervision = 1; - uint8_t session_id = 1; - zwave_controller_connection_info_t connection_info = {0}; - zwave_tx_options_t tx_options = {0}; - zwave_tx_session_id_t tx_session_id = NULL; - protocol_metadata_t metadata = {0}; - - // Expected TX options - tx_options.transport.is_protocol_frame = true; - tx_options.number_of_responses = 1; - tx_options.discard_timeout_ms = 5000; - tx_options.qos_priority = ZWAVE_TX_QOS_MAX_PRIORITY; - - // Expected connection info - connection_info.encapsulation = ZWAVE_CONTROLLER_ENCAPSULATION_NONE; - connection_info.local.node_id = 0; - connection_info.remote.node_id = 2; - - // Expected protocol metadata - metadata.session_id = session_id; - metadata.data_length = protocol_metadata_length; - memcpy(metadata.data, protocol_metadata, protocol_metadata_length); - - zwave_tx_send_data_ExpectWithArrayAndReturn(&connection_info, - sizeof(connection_info), - payload_length, - payload, - sizeof(payload), - &tx_options, - sizeof(tx_options), - NULL, - (void *)&metadata, - sizeof(protocol_metadata_t), - &tx_session_id, - sizeof(zwave_tx_session_id_t), - SL_STATUS_OK); - zwave_tx_send_data_IgnoreArg_on_send_complete(); - - zwave_s2_on_protocol_cc_encryption_request(destination_node_id, - payload_length, - payload, - protocol_metadata_length, - protocol_metadata, - use_supervision, - session_id); -} diff --git a/applications/zpc/components/zwave_command_classes/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/CMakeLists.txt index c59c6587e..99c75db5f 100644 --- a/applications/zpc/components/zwave_command_classes/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/CMakeLists.txt @@ -62,7 +62,8 @@ add_library( src/zwave_command_classes_fixt.c src/zwave_command_classes_utils.c src/zwave_command_class_inclusion_controller.cpp - src/zwave_command_class_transport_service.c) + src/zwave_command_class_transport_service.c + src/zwave_command_class_protocol.c) install(TARGETS zwave_command_classes LIBRARY DESTINATION lib) target_include_directories( diff --git a/applications/zpc/components/zwave/zwave_transports/s2/include/zwave_s2_protocol_cc_encryption.h b/applications/zpc/components/zwave_command_classes/include/zwave_command_class_protocol.h similarity index 50% rename from applications/zpc/components/zwave/zwave_transports/s2/include/zwave_s2_protocol_cc_encryption.h rename to applications/zpc/components/zwave_command_classes/include/zwave_command_class_protocol.h index db257f59f..2dd8dd55b 100644 --- a/applications/zpc/components/zwave/zwave_transports/s2/include/zwave_s2_protocol_cc_encryption.h +++ b/applications/zpc/components/zwave_command_classes/include/zwave_command_class_protocol.h @@ -11,40 +11,34 @@ * *****************************************************************************/ -/** - * @defgroup zwave_s2_protocol_cc_encryption Security 2 Protocol Command Class Encryption - * @ingroup zwave_transports - * @brief Protocol Command Class Encryption implementation for Z-Wave S2 - * - * @{ - */ - -#ifndef ZWAVE_S2_PROTOCOL_CC_ENCRYPTION_H -#define ZWAVE_S2_PROTOCOL_CC_ENCRYPTION_H +#ifndef ZWAVE_COMMAND_CLASS_PROTOCOL_H +#define ZWAVE_COMMAND_CLASS_PROTOCOL_H -#include #include "sl_status.h" -#include "zwave_node_id_definitions.h" +#include "zwave_controller_connection_info.h" +#include "zwave_rx.h" +#include "zwave_tx.h" #ifdef __cplusplus extern "C" { #endif /** - * @brief Triggered when a Protocol CC Encryption Request is received. * - * This callback has to be registered to the Z-Wave Controller callbacks. + * @brief Setup fixture for the Protocol Command Class. * - * @param destination_node_id Destination node ID. - * @param payload_length Length of the payload to be encrypted. - * @param payload Payload to be encrypted. - * @param protocol_metadata_length Length of the protocol metadata. - * @param protocol_metadata Protocol metadata. - * @param use_supervision Whether to use supervision. - * @param session_id Session ID. + * This setup will register the Protocol command handler + * to the Z-Wave CC framework, * + * @returns SL_STATUS_OK if successful + * @returns SL_STATUS_FAIL if an error occurred */ -void zwave_s2_on_protocol_cc_encryption_request( +sl_status_t zwave_command_class_protocol_init(void); + +/** + * @brief + */ +void zwave_on_protocol_cc_encryption_request( const zwave_node_id_t destination_node_id, const uint8_t payload_length, const uint8_t *const payload, @@ -57,6 +51,4 @@ void zwave_s2_on_protocol_cc_encryption_request( } #endif -#endif //ZWAVE_S2_PROTOCOL_CC_ENCRYPTION_H -/** @} end zwave_s2_protocol_cc_encryption */ - +#endif //ZWAVE_COMMAND_CLASS_PROTOCOL_H \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_protocol.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_protocol.c new file mode 100644 index 000000000..4f8a64ef7 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_protocol.c @@ -0,0 +1,217 @@ +/****************************************************************************** + * # License + * Copyright 2021 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +// Attribute store helpers +#include "attribute_store_defined_attribute_types.h" +#include "attribute_store_helper.h" + +// Includes from other components +#include "sl_log.h" +#include "attribute_store.h" +#include "attribute_resolver.h" +#include "zwave_unid.h" +#include "ZW_classcmd.h" +#include "zwave_tx.h" +#include "zwave_controller_keyset.h" +#include "zwave_controller_utils.h" +#include "zwave_utils.h" +#include "zwave_command_handler.h" +#include "zwave_command_class_indices.h" +#include "zwapi_protocol_controller.h" +#include "zwave_command_class_protocol.h" +#include "zwave_command_class_supervision.h" +#include "zwave_tx_scheme_selector.h" + +// Generic includes +#include "assert.h" +#include "string.h" + +// Log tag +#define LOG_TAG "zwave_command_class_protocol" + +protocol_metadata_t metadata = {0}; + +static zwave_controller_callbacks_t zwave_command_class_protocol_callbacks = { + .on_protocol_cc_encryption_request = zwave_on_protocol_cc_encryption_request +}; + +static void on_send_protocol_data_callback_received(uint8_t status, const zwapi_tx_report_t *tx_info, void *user) +{ + protocol_metadata_t *metadata = (protocol_metadata_t *)user; + + if (status == TRANSMIT_COMPLETE_FAIL || status == TRANSMIT_COMPLETE_VERIFIED) { + zwave_controller_request_protocol_cc_encryption_callback(status, tx_info, metadata->session_id); + } else { + sl_log_debug(LOG_TAG, "Send Protocol Data callback, status: %d", status); + } +} + +void zwave_on_protocol_cc_encryption_request( + const zwave_node_id_t destination_node_id, + const uint8_t payload_length, + const uint8_t *const payload, + const uint8_t protocol_metadata_length, + const uint8_t *const protocol_metadata, + const uint8_t use_supervision, + const uint8_t session_id) +{ + zwave_controller_connection_info_t connection_info = {0}; + zwave_tx_options_t tx_options = {0}; + uint8_t number_of_expected_responses = 1; + uint32_t discard_timeout_ms = 5000; + // sl_status_t ret = SL_STATUS_OK; + zwave_tx_session_id_t tx_session_id = NULL; + + zwave_tx_scheme_get_node_connection_info(destination_node_id, 0, &connection_info); + zwave_tx_scheme_get_node_tx_options( + ZWAVE_TX_QOS_MAX_PRIORITY, + number_of_expected_responses, + discard_timeout_ms, + &tx_options); + + // Other TX options are set in the transport layer in `S2_send_frame` + tx_options.transport.is_protocol_frame = true; + + metadata.session_id = session_id; + metadata.data_length = protocol_metadata_length; + memcpy(metadata.data, protocol_metadata, protocol_metadata_length); + + if (use_supervision) + { + zwave_command_class_supervision_send_data( + &connection_info, + payload_length, + payload, + &tx_options, + &on_send_protocol_data_callback_received, + (void *)&metadata, + &tx_session_id); + } else { + zwave_tx_send_data( + &connection_info, + payload_length, + payload, + &tx_options, + &on_send_protocol_data_callback_received, + (void *)&metadata, + &tx_session_id); + } +} + +sl_status_t zwave_command_class_protocol_support_handler( + const zwave_controller_connection_info_t *connection, + const uint8_t *frame_data, + uint16_t frame_length) +{ + // Frame too short, it should have not come here. + if (frame_length <= COMMAND_INDEX) { + return SL_STATUS_NOT_SUPPORTED; + } + + sl_log_info(LOG_TAG, "Protocol command received from NodeID %d:%d", + connection->remote.node_id, connection->remote.endpoint_id); + + sl_status_t status = + zwapi_transfer_protocol_cc( + connection->remote.node_id, + zwave_controller_get_key_from_encapsulation(connection->encapsulation), + frame_length, + frame_data); + + switch (status) { + case SL_STATUS_OK: + sl_log_info(LOG_TAG, + "Command from NodeID %d:%d was handled successfully.", + connection->remote.node_id, + connection->remote.endpoint_id); + break; + + case SL_STATUS_FAIL: + sl_log_warning(LOG_TAG, + "Command from NodeID %d:%d had an error during handling. " + "Not all parameters were accepted", + connection->remote.node_id, + connection->remote.endpoint_id); + break; + + case SL_STATUS_BUSY: + // This should not happen, or if it happens, we should be able to return + // an application busy message or similar. + sl_log_warning(LOG_TAG, + "Frame handler is busy and could not handle frame from " + "NodeID %d:%d correctly.", + connection->remote.node_id, + connection->remote.endpoint_id); + break; + + case SL_STATUS_NOT_SUPPORTED: + sl_log_warning( + LOG_TAG, + "Command from NodeID %d:%d got rejected because it is not supported. " + "It was possibly also rejected due to security filtering", + connection->remote.node_id, + connection->remote.endpoint_id); + break; + + default: + sl_log_warning( + LOG_TAG, + "Command from NodeID %d:%d had an unexpected return status: 0x%04X\n", + connection->remote.node_id, + connection->remote.endpoint_id, + status); + break; + } + return status; +} + +sl_status_t zwave_command_class_protocol_init() +{ + zwave_command_handler_t handler_protocol = { 0 }; + handler_protocol.support_handler = &zwave_command_class_protocol_support_handler; + handler_protocol.control_handler = NULL; + handler_protocol.minimal_scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NONE; + handler_protocol.command_class = ZWAVE_CMD_CLASS_PROTOCOL; + handler_protocol.version = 1; + handler_protocol.command_class_name = "Protocol"; + handler_protocol.manual_security_validation = false; + + if(SL_STATUS_OK != zwave_controller_register_callbacks(&zwave_command_class_protocol_callbacks)) + { + sl_log_error(LOG_TAG, "Failed to register callbacks for Protocol Command Class"); + return SL_STATUS_FAIL; + } + + if(SL_STATUS_OK != zwave_command_handler_register_handler(handler_protocol)) + { + sl_log_error(LOG_TAG, "Failed to register Protocol Command Class"); + return SL_STATUS_FAIL; + } + + zwave_command_handler_t handler_protocol_lr = { 0 }; + handler_protocol_lr.support_handler = &zwave_command_class_protocol_support_handler; + handler_protocol_lr.control_handler = NULL; + handler_protocol_lr.minimal_scheme = ZWAVE_CONTROLLER_ENCAPSULATION_NONE; + handler_protocol_lr.command_class = ZWAVE_CMD_CLASS_PROTOCOL_LR; + handler_protocol_lr.version = 1; + handler_protocol_lr.command_class_name = "Protocol LR"; + handler_protocol_lr.manual_security_validation = false; + + if (SL_STATUS_OK != zwave_command_handler_register_handler(handler_protocol_lr)) + { + sl_log_error(LOG_TAG, "Failed to register Protocol Command Class"); + return SL_STATUS_FAIL; + } + + return SL_STATUS_OK; +} \ No newline at end of file diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_supervision.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_supervision.c index c7d716c60..f9ee011bb 100644 --- a/applications/zpc/components/zwave_command_classes/src/zwave_command_class_supervision.c +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_class_supervision.c @@ -503,10 +503,17 @@ sl_status_t zwave_command_class_supervision_send_data( supervision_tx_options.number_of_responses = tx_options->number_of_responses; supervision_tx_options.number_of_responses += 1; - intptr_t user_parameter = (intptr_t)INVALID_SUPERVISION_ID; - if (connection->remote.is_multicast == false) { - user_parameter = (intptr_t)supervision_id; + intptr_t user_parameter; + if (!tx_options->transport.is_protocol_frame) + { + user_parameter = (intptr_t)INVALID_SUPERVISION_ID; + if (connection->remote.is_multicast == false) { + user_parameter = (intptr_t)supervision_id; + } + } else { + user_parameter = (intptr_t) user; } + sl_status_t zwave_tx_status = zwave_tx_send_data( connection, supervision_frame_size, diff --git a/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c b/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c index 32d1c1522..a20c668f3 100644 --- a/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c +++ b/applications/zpc/components/zwave_command_classes/src/zwave_command_classes_fixt.c @@ -59,6 +59,7 @@ #include "zwave_command_class_indicator_control.h" #include "zwave_command_class_manufacturer_specific_control.h" #include "zwave_command_class_humidity_control_mode.h" +#include "zwave_command_class_protocol.h" // Generic includes #include @@ -129,6 +130,7 @@ sl_status_t zwave_command_classes_init() status |= zwave_command_class_version_init(); status |= zwave_command_class_wake_up_init(); status |= zwave_command_class_zwave_plus_info_init(); + status |= zwave_command_class_protocol_init(); // Auto-generated handlers with overrides status |= zwave_command_class_indicator_control_init(); diff --git a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt index 63b79e147..bfb7362ff 100644 --- a/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt +++ b/applications/zpc/components/zwave_command_classes/test/CMakeLists.txt @@ -884,3 +884,18 @@ target_add_unittest( uic_attribute_resolver_mock zpc_attribute_resolver_mock uic_dotdot_mqtt_mock) + +target_add_unittest( + zwave_command_classes + NAME + zwave_command_class_protocol_test + SOURCES + zwave_command_class_protocol_test.c + DEPENDS + zwave_command_class_test_helpers + zwave_controller_mock + zwave_command_handler_mock + zwave_api_mock + zwave_tx_mock + zwave_tx_scheme_selector_mock +) diff --git a/applications/zpc/components/zwave_command_classes/test/zwave_command_class_protocol_test.c b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_protocol_test.c new file mode 100644 index 000000000..fcdaf3388 --- /dev/null +++ b/applications/zpc/components/zwave_command_classes/test/zwave_command_class_protocol_test.c @@ -0,0 +1,220 @@ +/****************************************************************************** + * # License + * Copyright 2021 Silicon Laboratories Inc. www.silabs.com + ****************************************************************************** + * The licensor of this software is Silicon Laboratories Inc. Your use of this + * software is governed by the terms of Silicon Labs Master Software License + * Agreement (MSLA) available at + * www.silabs.com/about-us/legal/master-software-license-agreement. This + * software is distributed to you in Source Code format and is governed by the + * sections of the MSLA applicable to Source Code. + * + *****************************************************************************/ + +// Generic includes +#include + +// Test includes +#include "unity.h" + +// Interface includes +#include "attribute_store_defined_attribute_types.h" +#include "zwave_command_class_wake_up_types.h" +#include "ZW_classcmd.h" +#include "zwave_command_class_protocol.h" +#include "zwave_controller_utils.h" + +// Includes from other components +#include "sl_log.h" +#include "zwave_controller_connection_info.h" +#include "zwave_tx_groups.h" + +// Mock includes +#include "zwave_command_handler_mock.h" +#include "zwave_tx_scheme_selector_mock.h" +#include "attribute_store_mock.h" +#include "attribute_store_helper_mock.h" +#include "attribute_resolver_mock.h" +#include "zwapi_protocol_controller_mock.h" +#include "zwave_controller_keyset_mock.h" +#include "zwave_tx_mock.h" +#include "zwave_controller_callbacks_mock.h" + +#define LOG_TAG "zwave_command_class_protocol_test" + +static zwave_command_handler_t protocol_handler = {}; + +static sl_status_t zwave_command_handler_register_handler_stub( + zwave_command_handler_t new_command_class_handler, int cmock_num_calls) +{ + protocol_handler = new_command_class_handler; + + TEST_ASSERT_EQUAL(ZWAVE_CONTROLLER_ENCAPSULATION_NONE, + protocol_handler.minimal_scheme); + TEST_ASSERT_TRUE(ZWAVE_CMD_CLASS_PROTOCOL ==protocol_handler.command_class + || ZWAVE_CMD_CLASS_PROTOCOL_LR == protocol_handler.command_class); + TEST_ASSERT_EQUAL(1, protocol_handler.version); + TEST_ASSERT_NULL(protocol_handler.control_handler); + TEST_ASSERT_NOT_NULL(protocol_handler.support_handler); + TEST_ASSERT_FALSE(protocol_handler.manual_security_validation); + + return SL_STATUS_OK; +} + +static sl_status_t zwave_controller_register_callback_stub( + const zwave_controller_callbacks_t *callback, int cmock_num_calls) +{ + TEST_ASSERT_NOT_NULL(callback); + TEST_ASSERT_NOT_NULL(callback->on_protocol_cc_encryption_request); + + return SL_STATUS_OK; +} + +void suiteSetUp() {} + +int suiteTearDown(int num_failures) +{ + return num_failures; +} + +void setUp() +{ + // Handler registration + zwave_command_handler_register_handler_Stub( + &zwave_command_handler_register_handler_stub); + + zwave_controller_register_callbacks_Stub( + &zwave_controller_register_callback_stub); + + zwave_command_class_protocol_init(); +} + +void tearDown() {} + +void test_zwave_command_class_protocol_init() +{ + // Call the function + TEST_ASSERT_EQUAL(SL_STATUS_OK, zwave_command_class_protocol_init()); +} + +void test_zwave_command_class_protocol_handler(void) +{ + uint8_t test_frame_data[5] = { 0}; + + test_frame_data[0] = ZWAVE_CMD_CLASS_PROTOCOL; + + zwave_controller_connection_info_t connection = { 0 }; + connection.encapsulation = ZWAVE_CONTROLLER_ENCAPSULATION_SECURITY_2_AUTHENTICATED; + connection.remote.node_id = 2; + connection.local.node_id = 1; + + // Test with wrong command length + TEST_ASSERT_EQUAL( + SL_STATUS_NOT_SUPPORTED, + protocol_handler.support_handler(&connection, + test_frame_data, + 1)); // wrong length + + // Test with correct length + zwave_controller_get_key_from_encapsulation_ExpectAndReturn(ZWAVE_CONTROLLER_ENCAPSULATION_SECURITY_2_AUTHENTICATED, ZWAVE_CONTROLLER_S2_AUTHENTICATED_KEY); + + zwapi_transfer_protocol_cc_ExpectAndReturn(2, + ZWAVE_CONTROLLER_S2_AUTHENTICATED_KEY, + 5, + (uint8_t*) &test_frame_data, + SL_STATUS_OK); + + TEST_ASSERT_EQUAL( + SL_STATUS_OK, + protocol_handler.support_handler(&connection, + test_frame_data, + sizeof(test_frame_data))); +} + +void test_zwave_s2_on_protocol_cc_encryption_request_happy_case() +{ + zwave_node_id_t destination_node_id = 2; + uint8_t payload[] = {0x01, 0x02, 0x03}; + uint8_t payload_length = sizeof(payload) / sizeof(payload[0]); + uint8_t protocol_metadata[] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7}; + uint8_t protocol_metadata_length = sizeof(protocol_metadata) / sizeof(protocol_metadata[0]); + uint8_t use_supervision = 0; + uint8_t session_id = 1; + zwave_controller_connection_info_t connection_info = {0}; + zwave_tx_options_t tx_options = {0}; + zwave_tx_session_id_t tx_session_id = NULL; + protocol_metadata_t metadata = {0}; + + // Expected TX options + tx_options.transport.is_protocol_frame = true; + + // Expected protocol metadata + metadata.session_id = session_id; + metadata.data_length = protocol_metadata_length; + memcpy(metadata.data, protocol_metadata, protocol_metadata_length); + + zwave_tx_scheme_get_node_connection_info_Expect(destination_node_id, 0, NULL); + zwave_tx_scheme_get_node_connection_info_IgnoreArg_connection_info(); + zwave_tx_scheme_get_node_tx_options_Expect(ZWAVE_TX_QOS_MAX_PRIORITY, 1, 5000, NULL); + zwave_tx_scheme_get_node_tx_options_IgnoreArg_tx_options(); + + zwave_tx_send_data_ExpectWithArrayAndReturn(&connection_info, + sizeof(connection_info), + payload_length, + payload, + sizeof(payload), + &tx_options, + sizeof(tx_options), + NULL, + (void *)&metadata, + sizeof(protocol_metadata_t), + &tx_session_id, + sizeof(zwave_tx_session_id_t), + SL_STATUS_OK); + zwave_tx_send_data_IgnoreArg_on_send_complete(); + + zwave_on_protocol_cc_encryption_request(destination_node_id, + payload_length, + payload, + protocol_metadata_length, + protocol_metadata, + use_supervision, + session_id); + + // Test with supervision + use_supervision = 1; + + zwave_tx_scheme_get_node_connection_info_Expect(destination_node_id, 0, NULL); + zwave_tx_scheme_get_node_connection_info_IgnoreArg_connection_info(); + zwave_tx_scheme_get_node_tx_options_Expect(ZWAVE_TX_QOS_MAX_PRIORITY, 1, 5000, NULL); + zwave_tx_scheme_get_node_tx_options_IgnoreArg_tx_options(); + + uint16_t supervision_frame_size = 4 + payload_length; // sizeof(frame) - SUPERVISION_ENCAPSULATED_COMMAND_MAXIMUM_SIZE + tx_options.number_of_responses += 1; // supervision get expects 1 frame in response + + zwave_tx_send_data_ExpectWithArrayAndReturn(&connection_info, + sizeof(connection_info), + supervision_frame_size, + payload, + sizeof(payload), + &tx_options, + sizeof(tx_options), + NULL, + (void *)&metadata, + sizeof(protocol_metadata_t), + &tx_session_id, + sizeof(zwave_tx_session_id_t), + SL_STATUS_OK); + zwave_tx_send_data_IgnoreArg_on_send_complete(); + zwave_tx_send_data_IgnoreArg_data(); + zwave_tx_send_data_IgnoreArg_user(); + + zwave_on_protocol_cc_encryption_request(destination_node_id, + payload_length, + payload, + protocol_metadata_length, + protocol_metadata, + use_supervision, + session_id); +} + diff --git a/applications/zpc/components/zwave_command_handler/src/zwave_command_handler.cpp b/applications/zpc/components/zwave_command_handler/src/zwave_command_handler.cpp index 1717c1c04..a2f213b83 100644 --- a/applications/zpc/components/zwave_command_handler/src/zwave_command_handler.cpp +++ b/applications/zpc/components/zwave_command_handler/src/zwave_command_handler.cpp @@ -53,7 +53,7 @@ std::multiset static zwave_controller_callbacks_t zwave_command_handler_callbacks = { .on_new_network_entered = zwave_command_handler_on_new_network_entered, .on_application_frame_received = zwave_command_handler_on_frame_received, - .on_protocol_frame_received = zwave_command_handler_on_protocol_frame_received + .on_protocol_frame_received = zwave_command_handler_on_protocol_frame_received, }; /////////////////////////////////////////////////////////////////////////////// diff --git a/applications/zpc/main.c b/applications/zpc/main.c index 0c41e3e75..8ce055310 100644 --- a/applications/zpc/main.c +++ b/applications/zpc/main.c @@ -204,6 +204,7 @@ static uic_fixt_shutdown_step_t uic_fixt_shutdown_steps_list[] {&dotdot_mapper_teardown, "DotDot mapper"}, {NULL, "Terminator"}}; + int main(int argc, char **argv) { attribute_mapper_config_init(); //TODO how do we want to do this