#include #include "CppUTest/TestHarness.h" #include "CppUTest/CommandLineTestRunner.h" #include "btstack_debug.h" #include "btstack_memory.h" #include "btstack_util.h" #include "mesh/adv_bearer.h" #include "mesh/gatt_bearer.h" #include "mesh/mesh_access.h" #include "mesh/mesh_crypto.h" #include "mesh/mesh_foundation.h" #include "mesh/mesh_iv_index_seq_number.h" #include "mesh/mesh_lower_transport.h" #include "mesh/mesh_network.h" #include "mesh/mesh_upper_transport.h" #include "mesh/provisioning.h" #include "mesh/mesh_peer.h" #include "mock.h" static mesh_network_pdu_t * received_network_pdu; static mesh_network_pdu_t * received_proxy_pdu; static uint8_t outgoing_gatt_network_pdu_data[29]; static uint8_t outgoing_gatt_network_pdu_len; static uint8_t outgoing_adv_network_pdu_data[29]; static uint8_t outgoing_adv_network_pdu_len; static uint8_t recv_upper_transport_pdu_data[100]; static uint16_t recv_upper_transport_pdu_len; #ifdef ENABLE_MESH_ADV_BEARER static btstack_packet_handler_t adv_packet_handler; void adv_bearer_register_for_network_pdu(btstack_packet_handler_t packet_handler){ adv_packet_handler = packet_handler; } void adv_bearer_request_can_send_now_for_network_pdu(void){ // simulate can send now uint8_t event[3]; event[0] = HCI_EVENT_MESH_META; event[1] = 1; event[2] = MESH_SUBEVENT_CAN_SEND_NOW; (*adv_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); } void adv_bearer_send_network_pdu(const uint8_t * network_pdu, uint16_t size, uint8_t count, uint16_t interval){ (void) count; (void) interval; // printf("ADV Network PDU: "); // printf_hexdump(network_pdu, size); memcpy(outgoing_adv_network_pdu_data, network_pdu, size); outgoing_adv_network_pdu_len = size; } static void adv_bearer_emit_sent(void){ uint8_t event[3]; event[0] = HCI_EVENT_MESH_META; event[1] = 1; event[2] = MESH_SUBEVENT_MESSAGE_SENT; (*adv_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); } #endif #ifdef ENABLE_MESH_GATT_BEARER static btstack_packet_handler_t gatt_packet_handler; void gatt_bearer_register_for_network_pdu(btstack_packet_handler_t packet_handler){ gatt_packet_handler = packet_handler; } void gatt_bearer_register_for_mesh_proxy_configuration(btstack_packet_handler_t packet_handler){ UNUSED(packet_handler); } void gatt_bearer_request_can_send_now_for_network_pdu(void){ // simulate can send now uint8_t event[3]; event[0] = HCI_EVENT_MESH_META; event[1] = 1; event[2] = MESH_SUBEVENT_CAN_SEND_NOW; (*gatt_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); } void gatt_bearer_send_network_pdu(const uint8_t * network_pdu, uint16_t size){ // printf("ADV Network PDU: "); // printf_hexdump(network_pdu, size); memcpy(outgoing_gatt_network_pdu_data, network_pdu, size); outgoing_gatt_network_pdu_len = size; } static void gatt_bearer_emit_sent(void){ uint8_t event[3]; event[0] = HCI_EVENT_MESH_META; event[1] = 1; event[2] = MESH_SUBEVENT_MESSAGE_SENT; (*gatt_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); } static void gatt_bearer_emit_connected(void){ uint8_t event[5]; event[0] = HCI_EVENT_MESH_META; event[1] = 1; event[2] = MESH_SUBEVENT_PROXY_CONNECTED; little_endian_store_16(event, 3, 0x1234); (*gatt_packet_handler)(HCI_EVENT_PACKET, 0, &event[0], sizeof(event)); } #endif // copy from mesh_message.c for now uint16_t mesh_pdu_dst(mesh_pdu_t * pdu){ switch (pdu->pdu_type){ case MESH_PDU_TYPE_UNSEGMENTED: case MESH_PDU_TYPE_NETWORK: case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL: return mesh_network_dst((mesh_network_pdu_t *) pdu); case MESH_PDU_TYPE_ACCESS: { return ((mesh_access_pdu_t *) pdu)->dst; } case MESH_PDU_TYPE_UPPER_SEGMENTED_ACCESS: case MESH_PDU_TYPE_UPPER_UNSEGMENTED_ACCESS: return ((mesh_upper_transport_pdu_t *) pdu)->dst; default: btstack_assert(false); return MESH_ADDRESS_UNSASSIGNED; } } uint16_t mesh_pdu_ctl(mesh_pdu_t * pdu){ switch (pdu->pdu_type){ case MESH_PDU_TYPE_NETWORK: case MESH_PDU_TYPE_UPPER_UNSEGMENTED_CONTROL: return mesh_network_control((mesh_network_pdu_t *) pdu); case MESH_PDU_TYPE_ACCESS: { return ((mesh_access_pdu_t *) pdu)->ctl_ttl >> 7; } default: btstack_assert(false); return 0; } } static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){ int i; for (i=0; inid = 0x68; btstack_parse_hex("0953fa93e7caac9638f58820220a398e", 16, network_key->encryption_key); btstack_parse_hex("8b84eedec100067d670971dd2aa700cf", 16, network_key->privacy_key); mesh_network_key_add(network_key); mesh_subnet_setup_for_netkey_index(network_key->netkey_index); } static void load_network_key_nid_5e(void){ mesh_network_key_t * network_key = btstack_memory_mesh_network_key_get(); network_key->nid = 0x5e; btstack_parse_hex("be635105434859f484fc798e043ce40e", 16, network_key->encryption_key); btstack_parse_hex("5d396d4b54d3cbafe943e051fe9a4eb8", 16, network_key->privacy_key); mesh_network_key_add(network_key); mesh_subnet_setup_for_netkey_index(network_key->netkey_index); } static void load_network_key_nid_10(void){ mesh_network_key_t * network_key = btstack_memory_mesh_network_key_get(); network_key->nid = 0x10; btstack_parse_hex("3a4fe84a6cc2c6a766ea93f1084d4039", 16, network_key->encryption_key); btstack_parse_hex("f695fcce709ccface4d8b7a1e6e39d25", 16, network_key->privacy_key); mesh_network_key_add(network_key); mesh_subnet_setup_for_netkey_index(network_key->netkey_index); } static void load_provisioning_data_test_message(void){ uint8_t application_key[16]; btstack_parse_hex("63964771734fbd76e3b40519d1d94a48", 16, application_key); mesh_application_key_set( 0, 0, 0x26, application_key); uint8_t device_key[16]; btstack_parse_hex("9d6dd0e96eb25dc19a40ed9914f8f03f", 16, device_key); mesh_transport_set_device_key(device_key); } static void test_lower_transport_callback_handler(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu){ switch (callback_type){ case MESH_NETWORK_PDU_RECEIVED: printf("test MESH_NETWORK_PDU_RECEIVED\n"); received_network_pdu = network_pdu; break; case MESH_NETWORK_PDU_SENT: printf("test MESH_NETWORK_PDU_SENT\n"); mesh_lower_transport_received_message(MESH_NETWORK_PDU_SENT, network_pdu); break; default: break; } } static void test_proxy_server_callback_handler(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * network_pdu){ switch (callback_type){ case MESH_NETWORK_PDU_RECEIVED: printf("test MESH_PROXY_PDU_RECEIVED\n"); received_proxy_pdu = network_pdu; break; case MESH_NETWORK_PDU_SENT: // printf("test MESH_PROXY_PDU_SENT\n"); // mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu); break; case MESH_NETWORK_PDU_ENCRYPTED: printf("test MESH_NETWORK_PDU_ENCRYPTED\n"); received_proxy_pdu = network_pdu; break; default: break; } } static void test_upper_transport_access_message_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){ UNUSED(status); // free sent pdus if (callback_type == MESH_TRANSPORT_PDU_SENT) { mesh_upper_transport_pdu_free(pdu); return; } // process pdu received mesh_access_pdu_t * access_pdu; mesh_network_pdu_t * network_pdu; mesh_segmented_pdu_t * message_pdu; switch(pdu->pdu_type){ case MESH_PDU_TYPE_ACCESS: access_pdu = (mesh_access_pdu_t *) pdu; printf("test access handler MESH_PDU_TYPE_ACCESS received\n"); recv_upper_transport_pdu_len = access_pdu->len; memcpy(recv_upper_transport_pdu_data, access_pdu->data, recv_upper_transport_pdu_len); mesh_upper_transport_message_processed_by_higher_layer(pdu); break; case MESH_PDU_TYPE_SEGMENTED: message_pdu = (mesh_segmented_pdu_t *) pdu; printf("test access handler MESH_PDU_TYPE_SEGMENTED received\n"); network_pdu = (mesh_network_pdu_t *) btstack_linked_list_get_first_item(&message_pdu->segments); recv_upper_transport_pdu_len = mesh_network_pdu_len(network_pdu) - 1; memcpy(recv_upper_transport_pdu_data, mesh_network_pdu_data(network_pdu) + 1, recv_upper_transport_pdu_len); mesh_upper_transport_message_processed_by_higher_layer(pdu); break; default: btstack_assert(0); break; } } static void test_upper_transport_control_message_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu){ UNUSED(status); // ignore pdu sent if (callback_type == MESH_TRANSPORT_PDU_SENT) return; // process pdu received mesh_control_pdu_t * control_pdu; switch(pdu->pdu_type){ case MESH_PDU_TYPE_CONTROL: control_pdu = (mesh_control_pdu_t *) pdu; printf("test MESH_PDU_TYPE_CONTROL\n"); recv_upper_transport_pdu_len = control_pdu->len + 1; recv_upper_transport_pdu_data[0] = control_pdu->akf_aid_control; memcpy(&recv_upper_transport_pdu_data[1], control_pdu->data, control_pdu->len); mesh_upper_transport_message_processed_by_higher_layer(pdu); break; default: btstack_assert(0); break; } } TEST_GROUP(MessageTest){ void setup(void){ btstack_memory_init(); btstack_crypto_init(); load_provisioning_data_test_message(); mesh_network_init(); mesh_lower_transport_init(); mesh_upper_transport_init(); mesh_network_key_init(); // intercept messages between network and lower layer mesh_network_set_higher_layer_handler(&test_lower_transport_callback_handler); mesh_network_set_proxy_message_handler(&test_proxy_server_callback_handler); // register to receive upper transport messages mesh_upper_transport_register_access_message_handler(&test_upper_transport_access_message_handler); mesh_upper_transport_register_control_message_handler(&test_upper_transport_control_message_handler); mesh_seq_auth_reset(); #ifdef ENABLE_MESH_GATT_BEARER mesh_foundation_gatt_proxy_set(1); gatt_bearer_emit_connected(); #endif outgoing_gatt_network_pdu_len = 0; outgoing_adv_network_pdu_len = 0; received_network_pdu = NULL; recv_upper_transport_pdu_len =0; } void teardown(void){ // printf("-- teardown start --\n\n"); btstack_crypto_reset(); mesh_network_reset(); mesh_lower_transport_reset(); mesh_upper_transport_dump(); mesh_upper_transport_reset(); // mesh_network_dump(); // mesh_transport_dump(); printf("-- teardown complete --\n\n"); } }; static uint8_t transport_pdu_data[64]; static uint16_t transport_pdu_len; static uint8_t test_network_pdu_len; static uint8_t test_network_pdu_data[29]; static void test_receive_network_pdus(int count, char ** network_pdus, char ** lower_transport_pdus, char * access_pdu){ int i; for (i=0;ipseudo_dst; test_send_access_message(netkey_index, appkey_index, ttl, src, pseudo_dst, szmic, message22_upper_transport_pdu, 1, message22_lower_transport_pdus, message22_network_pdus); } // Message 23 char * message23_network_pdus[] = { (char *) "e877a48dd5fe2d7a9d696d3dd16a75489696f0b70c711b881385", }; char * message23_lower_transport_pdus[] = { (char *) "662456db5e3100eef65daa7a38", }; char * message23_upper_transport_pdu = (char *) "d50a0048656c6c6f"; char * message23_label_string = (char *) "f4a002c7fb1e4ca0a469a021de0db875"; TEST(MessageTest, Message23Receive){ load_network_key_nid_68(); mesh_set_iv_index(0x12345677); uint8_t label_uuid[16]; btstack_parse_hex(message23_label_string, 16, label_uuid); mesh_virtual_address_register(label_uuid, 0x9736); test_receive_network_pdus(1, message23_network_pdus, message23_lower_transport_pdus, message23_upper_transport_pdu); } TEST(MessageTest, Message23Send){ uint16_t netkey_index = 0; uint16_t appkey_index = 0; uint8_t ttl = 3; uint16_t src = 0x1234; uint32_t seq = 0x07080c; uint8_t szmic = 0; load_network_key_nid_68(); mesh_set_iv_index(0x12345677); mesh_sequence_number_set(seq); uint8_t label_uuid[16]; btstack_parse_hex(message23_label_string, 16, label_uuid); mesh_virtual_address_t * virtual_address = mesh_virtual_address_register(label_uuid, 0x9736); uint16_t pseudo_dst = virtual_address->pseudo_dst; test_send_access_message(netkey_index, appkey_index, ttl, src, pseudo_dst, szmic, message23_upper_transport_pdu, 1, message23_lower_transport_pdus, message23_network_pdus); } #endif // Message 24 char * message24_network_pdus[] = { (char *) "e8624e65bb8c1794e998b4081f47a35251fdd3896d99e4db489b918599", (char *) "e8a7d0f0a2ea42dc2f4dd6fb4db33a6c088d023b47", }; char * message24_lower_transport_pdus[] = { (char *) "e6a03401c3c51d8e476b28e3aa5001f3", (char *) "e6a034211c01cea6", }; char * message24_upper_transport_pdu = (char *) "ea0a00576f726c64"; char * message24_label_string = (char *) "f4a002c7fb1e4ca0a469a021de0db875"; TEST(MessageTest, Message24Receive){ load_network_key_nid_68(); mesh_set_iv_index(0x12345677); uint8_t label_uuid[16]; btstack_parse_hex(message24_label_string, 16, label_uuid); mesh_virtual_address_register(label_uuid, 0x9736); test_receive_network_pdus(2, message24_network_pdus, message24_lower_transport_pdus, message24_upper_transport_pdu); } TEST(MessageTest, Message24Send){ uint16_t netkey_index = 0; uint16_t appkey_index = 0; uint8_t ttl = 3; uint16_t src = 0x1234; uint32_t seq = 0x07080d; uint8_t szmic = 1; load_network_key_nid_68(); mesh_set_iv_index(0x12345677); mesh_sequence_number_set(seq); uint8_t label_uuid[16]; btstack_parse_hex(message24_label_string, 16, label_uuid); mesh_virtual_address_t * virtual_address = mesh_virtual_address_register(label_uuid, 0x9736); uint16_t pseudo_dst = virtual_address->pseudo_dst; test_send_access_message(netkey_index, appkey_index, ttl, src, pseudo_dst, szmic, message24_upper_transport_pdu, 2, message24_lower_transport_pdus, message24_network_pdus); } // Proxy Configuration Test char * proxy_config_pdus[] = { (char *) "0210386bd60efbbb8b8c28512e792d3711f4b526", }; char * proxy_config_lower_transport_pdus[] = { (char *) "0000", }; char * proxy_config_upper_transport_pdu = (char *) "ea0a00576f726c64"; TEST(MessageTest, ProxyConfigReceive){ mesh_set_iv_index(0x12345678); load_network_key_nid_10(); int i = 0; char ** network_pdus = proxy_config_pdus; test_network_pdu_len = strlen(network_pdus[i]) / 2; btstack_parse_hex(network_pdus[i], test_network_pdu_len, test_network_pdu_data); mesh_network_process_proxy_configuration_message(&test_network_pdu_data[1], test_network_pdu_len-1); while (received_proxy_pdu == NULL) { mock_process_hci_cmd(); } char ** lower_transport_pdus = proxy_config_lower_transport_pdus; transport_pdu_len = strlen(lower_transport_pdus[i]) / 2; btstack_parse_hex(lower_transport_pdus[i], transport_pdu_len, transport_pdu_data); uint8_t * lower_transport_pdu = mesh_network_pdu_data(received_proxy_pdu); uint8_t lower_transport_pdu_len = mesh_network_pdu_len(received_proxy_pdu); // printf_hexdump(lower_transport_pdu, lower_transport_pdu_len); CHECK_EQUAL( transport_pdu_len, lower_transport_pdu_len); CHECK_EQUAL_ARRAY(transport_pdu_data, lower_transport_pdu, transport_pdu_len); // done mesh_network_message_processed_by_higher_layer(received_proxy_pdu); received_proxy_pdu = NULL; } TEST(MessageTest, ProxyConfigSend){ uint16_t netkey_index = 0; uint8_t ctl = 1; uint8_t ttl = 0; uint16_t src = 1; uint16_t dest = 0; uint32_t seq = 1; uint8_t nid = 0x10; mesh_set_iv_index(0x12345678); load_network_key_nid_10(); mesh_network_pdu_t * network_pdu = mesh_network_pdu_get(); uint8_t data[] = { 0 , 0 }; mesh_network_setup_pdu(network_pdu, netkey_index, nid, ctl, ttl, seq, src, dest, data, sizeof(data)); mesh_network_encrypt_proxy_configuration_message(network_pdu); while (received_proxy_pdu == NULL) { mock_process_hci_cmd(); } uint8_t * proxy_pdu_data = received_proxy_pdu->data; uint8_t proxy_pdu_len = received_proxy_pdu->len; int i = 0; char ** network_pdus = proxy_config_pdus; transport_pdu_len = strlen(network_pdus[i]) / 2; btstack_parse_hex(network_pdus[i], transport_pdu_len, transport_pdu_data); CHECK_EQUAL( transport_pdu_len-1, proxy_pdu_len); CHECK_EQUAL_ARRAY(transport_pdu_data+1, proxy_pdu_data, transport_pdu_len-1); received_proxy_pdu = NULL; mesh_network_pdu_free(network_pdu); } static btstack_crypto_aes128_t crypto_request_aes128; static uint8_t plaintext[16]; static uint8_t identity_key[16]; static uint8_t hash[16]; static uint8_t random_value[8]; static void mesh_proxy_handle_get_aes128(void * arg){ UNUSED(arg); uint8_t expected_hash[8]; uint8_t expected_random_value[8]; btstack_parse_hex("00861765aefcc57b", 8, expected_hash); CHECK_EQUAL_ARRAY(&hash[8], expected_hash, 8); btstack_parse_hex("34ae608fbbc1f2c6", 8, expected_random_value); CHECK_EQUAL_ARRAY(random_value, expected_random_value, 8); } TEST(MessageTest, ServiceDataUsingNodeIdentityTest){ btstack_parse_hex("34ae608fbbc1f2c6", 8, random_value); memset(plaintext, 0, sizeof(plaintext)); memcpy(&plaintext[6] , random_value, 8); big_endian_store_16(plaintext, 14, 0x1201); // 84396c435ac48560b5965385253e210c btstack_parse_hex("84396c435ac48560b5965385253e210c", 16, identity_key); btstack_crypto_aes128_encrypt(&crypto_request_aes128, identity_key, plaintext, hash, mesh_proxy_handle_get_aes128, NULL); } // Mesh v1.0, 8.2.1 static btstack_crypto_aes128_cmac_t aes_cmac_request; static uint8_t k4_result[1]; static void handle_k4_result(void *arg){ UNUSED(arg); printf("ApplicationkeyIDTest: %02x\n", k4_result[0]); CHECK_EQUAL( 0x26, k4_result[0]); } TEST(MessageTest, ApplicationkeyIDTest){ static uint8_t application_key[16]; btstack_parse_hex("63964771734fbd76e3b40519d1d94a48", 16, application_key); mesh_k4(&aes_cmac_request, application_key, &k4_result[0], &handle_k4_result, NULL); } int main (int argc, const char * argv[]){ return CommandLineTestRunner::RunAllTests(argc, argv); }