From 698ac90b401885c04188dbdac4626b4539036497 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 8 Feb 2024 22:43:18 -0500 Subject: [PATCH 01/34] [TEST] Multicast packet filter --- src/zigbee_ncp/app.c | 67 ++++++++++++++++++++++++++++++++++ src/zigbee_ncp/zigbee_ncp.slcp | 3 ++ 2 files changed, 70 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 9e7f24f5..31e5ba61 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -17,6 +17,20 @@ #include PLATFORM_HEADER #include "ember.h" +#include "ember-types.h" +#include "ezsp-enum.h" + +#include "stack/include/message.h" + + +typedef enum { + XNCP_CMD_GET_SUPPORTED_FEATURES = 0x00, +} CUSTOM_EZSP_CMD; + + +#define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) +#define SUPPORTED_FEATURES (FEATURE_MEMBER_OF_ALL_GROUPS) + //---------------------- // Implemented Callbacks @@ -36,3 +50,56 @@ void emberAfRadioNeedsCalibratingCallback(void) void emberAfMainInitCallback(void) { } + +/** @brief Packet filter callback + * + * Filters and/or mutates incoming packets. Currently used only for wildcard multicast + * group membership. + */ +EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType packetType, + uint8_t* packetData, + uint8_t* size_p, + void* data) +{ + if ((packetType == EMBER_ZIGBEE_PACKET_TYPE_APS_COMMAND) && (*size_p >= 3)) { + uint8_t deliveryMode = (packetData[0] & 0b00001100) >> 2; + + // Ensure we automatically "join" every multicast group + if (deliveryMode == 0x03) { + // Take ownership over the first entry and continuously rewrite it + EmberMulticastTableEntry *tableEntry = &(sl_zigbee_get_multicast_table()[0]); + + tableEntry->endpoint = 1; + tableEntry->multicastId = (packetData[2] >> 8) | (packetData[1] >> 0); + tableEntry->networkIndex = 0; + } + } + + return EMBER_ACCEPT_PACKET; +} + + +EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, + uint8_t *messagePayload, + uint8_t *replyPayloadLength, + uint8_t *replyPayload) { + *replyPayloadLength = 0; + + if (messageLength < 1) { + return EMBER_BAD_ARGUMENT; + } + + switch (messagePayload[0]) { + case XNCP_CMD_GET_SUPPORTED_FEATURES: + *replyPayloadLength += 4; + replyPayload[0] = (uint8_t)((SUPPORTED_FEATURES >> 0) & 0xFF); + replyPayload[1] = (uint8_t)((SUPPORTED_FEATURES >> 8) & 0xFF); + replyPayload[2] = (uint8_t)((SUPPORTED_FEATURES >> 16) & 0xFF); + replyPayload[3] = (uint8_t)((SUPPORTED_FEATURES >> 24) & 0xFF); + break; + default: + return EMBER_BAD_ARGUMENT; + } + + return EMBER_SUCCESS; +} diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 8885e521..b494230d 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -25,6 +25,7 @@ component: - id: zigbee_ncp_uart_hardware - id: zigbee_debug_basic - id: zigbee_debug_extended + - id: zigbee_xncp - id: rail_util_rssi define: @@ -57,6 +58,8 @@ configuration: value: 0 - name: SL_PSA_ITS_SUPPORT_V3_DRIVER value: 1 + - name: EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ALL_PACKETS + value: 1 source: - path: main.c From 077a1f033fa3ddba689f7e451c839c2e70d31b22 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:14:38 -0500 Subject: [PATCH 02/34] Use the correct filter --- src/zigbee_ncp/app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 31e5ba61..cee150e6 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -61,7 +61,7 @@ EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType pack uint8_t* size_p, void* data) { - if ((packetType == EMBER_ZIGBEE_PACKET_TYPE_APS_COMMAND) && (*size_p >= 3)) { + if ((packetType == EMBER_ZIGBEE_PACKET_TYPE_APS_DATA) && (*size_p >= 3)) { uint8_t deliveryMode = (packetData[0] & 0b00001100) >> 2; // Ensure we automatically "join" every multicast group From 7d779e946b0ecd96830356ad8d49807aa353fbef Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 28 May 2024 15:20:41 -0400 Subject: [PATCH 03/34] Implement manual source routing --- src/zigbee_ncp/app.c | 103 +++++++++++++++++++++++++++++++-- src/zigbee_ncp/zigbee_ncp.slcp | 7 +++ 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index cee150e6..51234746 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -24,12 +24,20 @@ typedef enum { - XNCP_CMD_GET_SUPPORTED_FEATURES = 0x00, + XNCP_CMD_GET_SUPPORTED_FEATURES = 0x0000, + XNCP_CMD_SET_SOURCE_ROUTE = 0x0001 } CUSTOM_EZSP_CMD; #define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) -#define SUPPORTED_FEATURES (FEATURE_MEMBER_OF_ALL_GROUPS) +#define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) +#define SUPPORTED_FEATURES ( \ + FEATURE_MEMBER_OF_ALL_GROUPS \ + | FEATURE_MANUAL_SOURCE_ROUTE \ +) + +#define MAX_EPHEMERAL_SOURCE_ROUTES (20) +uint16_t manual_source_routes[MAX_EPHEMERAL_SOURCE_ROUTES][1 + EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1]; //---------------------- @@ -49,6 +57,11 @@ void emberAfRadioNeedsCalibratingCallback(void) */ void emberAfMainInitCallback(void) { + for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { + for (uint8_t j = 0; j < EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT; j++) { + manual_source_routes[i][j] = EMBER_NULL_NODE_ID; + } + } } /** @brief Packet filter callback @@ -79,17 +92,61 @@ EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType pack } +void nc_zigbee_override_append_source_route(EmberNodeId destination, + EmberMessageBuffer *header, + bool *consumed) +{ + uint8_t index = 0xFF; + + for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { + if (manual_source_routes[i][0] == destination) { + index = i; + break; + } + } + + if (index == 0xFF) { + *consumed = false; + return; + } + + uint16_t *routes = &manual_source_routes[index][1]; + + uint8_t relay_count = 0; + uint8_t relay_index = 0; + + while (routes[relay_count] != EMBER_NULL_NODE_ID) { + relay_count++; + } + + *consumed = true; + emberAppendToLinkedBuffers(*header, &relay_count, 1); + emberAppendToLinkedBuffers(*header, &relay_index, 1); + + //emberExtendLinkedBuffer(*header, relay_count * 2); + //memcpy(2 + emberMessageBufferContents(*header), routes, relay_count * 2); + + for (uint8_t i = 0; i < relay_count; i++) { + emberAppendToLinkedBuffers(*header, &routes[i], 2); + } + + return; +} + + EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, uint8_t *replyPayloadLength, uint8_t *replyPayload) { *replyPayloadLength = 0; - if (messageLength < 1) { + if (messageLength < 2) { return EMBER_BAD_ARGUMENT; } - switch (messagePayload[0]) { + uint16_t command_id = (messagePayload[0] << 0) | (messagePayload[1] << 8); + + switch (command_id) { case XNCP_CMD_GET_SUPPORTED_FEATURES: *replyPayloadLength += 4; replyPayload[0] = (uint8_t)((SUPPORTED_FEATURES >> 0) & 0xFF); @@ -97,6 +154,44 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, replyPayload[2] = (uint8_t)((SUPPORTED_FEATURES >> 16) & 0xFF); replyPayload[3] = (uint8_t)((SUPPORTED_FEATURES >> 24) & 0xFF); break; + + case XNCP_CMD_SET_SOURCE_ROUTE: + if ((messageLength < 4) || (messageLength % 2 != 0)) { + return EMBER_BAD_ARGUMENT; + } + + uint8_t num_relays = (messageLength - 4) / 2; + + if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1) { + return EMBER_BAD_ARGUMENT; + } + + // If we don't find a better index, pick one at random + uint8_t insertion_index = emberGetPseudoRandomNumber() % MAX_EPHEMERAL_SOURCE_ROUTES; + uint16_t node_id = (messagePayload[2] << 0) | (messagePayload[3] << 8); + + for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { + uint16_t current_node_id = manual_source_routes[i][0]; + + if (current_node_id == EMBER_NULL_NODE_ID) { + insertion_index = i; + } else if (current_node_id == node_id) { + insertion_index = i; + break; + } + } + + manual_source_routes[insertion_index][0] = node_id; + manual_source_routes[insertion_index][1 + num_relays] = EMBER_NULL_NODE_ID; + + for (uint8_t i = 0; i < num_relays; i++) { + manual_source_routes[insertion_index][1 + i] = ( + (messagePayload[4 + i * 2 + 0] << 0) + | (messagePayload[4 + i * 2 + 1] << 8) + ); + } + break; + default: return EMBER_BAD_ARGUMENT; } diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index b494230d..a5e3f30f 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -65,6 +65,13 @@ source: - path: main.c - path: app.c +template_contribution: +- name: zigbee_stack_callback + priority: -9999 + value: + callback_type: override_append_source_route + function_name: nc_zigbee_override_append_source_route + filter: - name: Wireless Technology value: [Zigbee] From ab6ba2557f01ffceb09a0d871e965b54fc46ebfc Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 28 May 2024 16:52:31 -0400 Subject: [PATCH 04/34] [no ci] Age out routes after a single use --- src/zigbee_ncp/app.c | 65 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 51234746..6a977876 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -36,9 +36,16 @@ typedef enum { | FEATURE_MANUAL_SOURCE_ROUTE \ ) -#define MAX_EPHEMERAL_SOURCE_ROUTES (20) -uint16_t manual_source_routes[MAX_EPHEMERAL_SOURCE_ROUTES][1 + EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1]; +#define MAX_MANUAL_SOURCE_ROUTES (20) +typedef struct ManualSourceRoute { + bool active; + uint16_t destination; + uint8_t num_relays; + uint16_t relays[EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT]; +} ManualSourceRoute; + +ManualSourceRoute manual_source_routes[MAX_MANUAL_SOURCE_ROUTES]; //---------------------- // Implemented Callbacks @@ -57,10 +64,8 @@ void emberAfRadioNeedsCalibratingCallback(void) */ void emberAfMainInitCallback(void) { - for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { - for (uint8_t j = 0; j < EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT; j++) { - manual_source_routes[i][j] = EMBER_NULL_NODE_ID; - } + for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + manual_source_routes[i].active = false; } } @@ -98,8 +103,8 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, { uint8_t index = 0xFF; - for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { - if (manual_source_routes[i][0] == destination) { + for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { index = i; break; } @@ -110,24 +115,18 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, return; } - uint16_t *routes = &manual_source_routes[index][1]; + ManualSourceRoute *route = &manual_source_routes[index]; - uint8_t relay_count = 0; uint8_t relay_index = 0; - while (routes[relay_count] != EMBER_NULL_NODE_ID) { - relay_count++; - } - *consumed = true; - emberAppendToLinkedBuffers(*header, &relay_count, 1); - emberAppendToLinkedBuffers(*header, &relay_index, 1); + route->active = false; // Disable the route after a single use - //emberExtendLinkedBuffer(*header, relay_count * 2); - //memcpy(2 + emberMessageBufferContents(*header), routes, relay_count * 2); + emberAppendToLinkedBuffers(*header, &route->num_relays, 1); + emberAppendToLinkedBuffers(*header, &relay_index, 1); - for (uint8_t i = 0; i < relay_count; i++) { - emberAppendToLinkedBuffers(*header, &routes[i], 2); + for (uint8_t i = 0; i < route->num_relays; i++) { + emberAppendToLinkedBuffers(*header, (uint8_t*)&route->relays[i], 2); } return; @@ -166,30 +165,32 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, return EMBER_BAD_ARGUMENT; } - // If we don't find a better index, pick one at random - uint8_t insertion_index = emberGetPseudoRandomNumber() % MAX_EPHEMERAL_SOURCE_ROUTES; + // If we don't find a better index, pick one at random to replace + uint8_t insertion_index = emberGetPseudoRandomNumber() % MAX_MANUAL_SOURCE_ROUTES; uint16_t node_id = (messagePayload[2] << 0) | (messagePayload[3] << 8); - for (uint8_t i = 0; i < MAX_EPHEMERAL_SOURCE_ROUTES; i++) { - uint16_t current_node_id = manual_source_routes[i][0]; + for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + ManualSourceRoute *route = &manual_source_routes[i]; - if (current_node_id == EMBER_NULL_NODE_ID) { + if (route->active == false) { insertion_index = i; - } else if (current_node_id == node_id) { + } else if (route->destination == node_id) { insertion_index = i; break; } } - manual_source_routes[insertion_index][0] = node_id; - manual_source_routes[insertion_index][1 + num_relays] = EMBER_NULL_NODE_ID; + ManualSourceRoute *route = &manual_source_routes[insertion_index]; for (uint8_t i = 0; i < num_relays; i++) { - manual_source_routes[insertion_index][1 + i] = ( - (messagePayload[4 + i * 2 + 0] << 0) - | (messagePayload[4 + i * 2 + 1] << 8) - ); + uint16_t relay = (messagePayload[4 + i * 2 + 0] << 0) | (messagePayload[4 + i * 2 + 1] << 8); + route->relays[i] = relay; } + + route->destination = node_id; + route->num_relays = num_relays; + route->active = true; + break; default: From a85da61d9cc6aa37b5ebad96d02ba70ed4af0878 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 11:57:19 -0400 Subject: [PATCH 05/34] Clean up naming and fix bitshifts --- src/zigbee_ncp/app.c | 25 +++++++++++++++---------- src/zigbee_ncp/zigbee_ncp.slcp | 4 +--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 6a977876..7b2b0ab3 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -19,9 +19,11 @@ #include "ember.h" #include "ember-types.h" #include "ezsp-enum.h" +#include "random.h" #include "stack/include/message.h" +#define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES = 0x0000, @@ -36,7 +38,8 @@ typedef enum { | FEATURE_MANUAL_SOURCE_ROUTE \ ) -#define MAX_MANUAL_SOURCE_ROUTES (20) +// Table entries are ephemeral and are expected to be populated before a request is sent +#define MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) typedef struct ManualSourceRoute { bool active; @@ -45,7 +48,7 @@ typedef struct ManualSourceRoute { uint16_t relays[EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT]; } ManualSourceRoute; -ManualSourceRoute manual_source_routes[MAX_MANUAL_SOURCE_ROUTES]; +ManualSourceRoute manual_source_routes[MANUAL_SOURCE_ROUTE_TABLE_SIZE]; //---------------------- // Implemented Callbacks @@ -64,7 +67,7 @@ void emberAfRadioNeedsCalibratingCallback(void) */ void emberAfMainInitCallback(void) { - for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { manual_source_routes[i].active = false; } } @@ -88,7 +91,7 @@ EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType pack EmberMulticastTableEntry *tableEntry = &(sl_zigbee_get_multicast_table()[0]); tableEntry->endpoint = 1; - tableEntry->multicastId = (packetData[2] >> 8) | (packetData[1] >> 0); + tableEntry->multicastId = BUILD_UINT16(packetData[1], packetData[2]); tableEntry->networkIndex = 0; } } @@ -103,7 +106,7 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, { uint8_t index = 0xFF; - for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { index = i; break; @@ -122,6 +125,8 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, *consumed = true; route->active = false; // Disable the route after a single use + emberExtendLinkedBuffer(*header, 1 + 1 + 2 * route->num_relays); + emberAppendToLinkedBuffers(*header, &route->num_relays, 1); emberAppendToLinkedBuffers(*header, &relay_index, 1); @@ -143,7 +148,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, return EMBER_BAD_ARGUMENT; } - uint16_t command_id = (messagePayload[0] << 0) | (messagePayload[1] << 8); + uint16_t command_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); switch (command_id) { case XNCP_CMD_GET_SUPPORTED_FEATURES: @@ -166,10 +171,10 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, } // If we don't find a better index, pick one at random to replace - uint8_t insertion_index = emberGetPseudoRandomNumber() % MAX_MANUAL_SOURCE_ROUTES; - uint16_t node_id = (messagePayload[2] << 0) | (messagePayload[3] << 8); + uint8_t insertion_index = emberGetPseudoRandomNumber() % MANUAL_SOURCE_ROUTE_TABLE_SIZE; + uint16_t node_id = BUILD_UINT16(messagePayload[2], messagePayload[3]); - for (uint8_t i = 0; i < MAX_MANUAL_SOURCE_ROUTES; i++) { + for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { ManualSourceRoute *route = &manual_source_routes[i]; if (route->active == false) { @@ -183,7 +188,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, ManualSourceRoute *route = &manual_source_routes[insertion_index]; for (uint8_t i = 0; i < num_relays; i++) { - uint16_t relay = (messagePayload[4 + i * 2 + 0] << 0) | (messagePayload[4 + i * 2 + 1] << 8); + uint16_t relay = BUILD_UINT16(messagePayload[4 + 2 * i + 0], messagePayload[4 + 2 * i + 1]); route->relays[i] = relay; } diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index a5e3f30f..856aa63c 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -68,9 +68,7 @@ source: template_contribution: - name: zigbee_stack_callback priority: -9999 - value: - callback_type: override_append_source_route - function_name: nc_zigbee_override_append_source_route + value: {callback_type: override_append_source_route, function_name: nc_zigbee_override_append_source_route} filter: - name: Wireless Technology From 4611b2b953df87faf33ea29b6ff33d5e12f9d9f6 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:35:34 -0400 Subject: [PATCH 06/34] Move XNCP configuration into its own file --- src/zigbee_ncp/app.c | 4 ++-- src/zigbee_ncp/config/xncp_config.h | 9 +++++++++ src/zigbee_ncp/zigbee_ncp.slcp | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/zigbee_ncp/config/xncp_config.h diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 7b2b0ab3..eedbcf8d 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -23,6 +23,8 @@ #include "stack/include/message.h" +#include "config/xncp_config.h" + #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) typedef enum { @@ -38,8 +40,6 @@ typedef enum { | FEATURE_MANUAL_SOURCE_ROUTE \ ) -// Table entries are ephemeral and are expected to be populated before a request is sent -#define MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) typedef struct ManualSourceRoute { bool active; diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h new file mode 100644 index 00000000..f2bce04d --- /dev/null +++ b/src/zigbee_ncp/config/xncp_config.h @@ -0,0 +1,9 @@ +#ifndef CONFIG_XNCP_CONFIG_H_ +#define CONFIG_XNCP_CONFIG_H_ + +// Table entries are ephemeral and are expected to be populated before a request is sent. +// This is not the size of any source route table! Rather, this controls how many unique +// destinations can be concurrently contacted with source routing enabled. +#define MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) + +#endif /* CONFIG_XNCP_CONFIG_H_ */ diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 856aa63c..5ac2ad92 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -65,6 +65,10 @@ source: - path: main.c - path: app.c +config_file: + - path: config/xncp_config.h + file_id: xncp_config + template_contribution: - name: zigbee_stack_callback priority: -9999 From 6dd24434efdad3ffbf47a7c4743796e1a651004a Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:37:26 -0400 Subject: [PATCH 07/34] Don't grow Ember buffer, the application crashes at runtime --- src/zigbee_ncp/app.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index eedbcf8d..bb9e3b1b 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -125,8 +125,6 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, *consumed = true; route->active = false; // Disable the route after a single use - emberExtendLinkedBuffer(*header, 1 + 1 + 2 * route->num_relays); - emberAppendToLinkedBuffers(*header, &route->num_relays, 1); emberAppendToLinkedBuffers(*header, &relay_index, 1); From 946740f2e3577519a94d3269c235b073a3b3fbaa Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:46:57 -0400 Subject: [PATCH 08/34] Prefix XNCP config --- src/zigbee_ncp/app.c | 10 +++++----- src/zigbee_ncp/config/xncp_config.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index bb9e3b1b..d6478653 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -48,7 +48,7 @@ typedef struct ManualSourceRoute { uint16_t relays[EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT]; } ManualSourceRoute; -ManualSourceRoute manual_source_routes[MANUAL_SOURCE_ROUTE_TABLE_SIZE]; +ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE]; //---------------------- // Implemented Callbacks @@ -67,7 +67,7 @@ void emberAfRadioNeedsCalibratingCallback(void) */ void emberAfMainInitCallback(void) { - for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { + for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { manual_source_routes[i].active = false; } } @@ -106,7 +106,7 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, { uint8_t index = 0xFF; - for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { + for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { index = i; break; @@ -169,10 +169,10 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, } // If we don't find a better index, pick one at random to replace - uint8_t insertion_index = emberGetPseudoRandomNumber() % MANUAL_SOURCE_ROUTE_TABLE_SIZE; + uint8_t insertion_index = emberGetPseudoRandomNumber() % XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; uint16_t node_id = BUILD_UINT16(messagePayload[2], messagePayload[3]); - for (uint8_t i = 0; i < MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { + for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { ManualSourceRoute *route = &manual_source_routes[i]; if (route->active == false) { diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index f2bce04d..8a4ca9f6 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -4,6 +4,6 @@ // Table entries are ephemeral and are expected to be populated before a request is sent. // This is not the size of any source route table! Rather, this controls how many unique // destinations can be concurrently contacted with source routing enabled. -#define MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) +#define XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) #endif /* CONFIG_XNCP_CONFIG_H_ */ From ffb5249ba1934b25d10b978d13337ce237fa30ba Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:48:22 -0400 Subject: [PATCH 09/34] Allow overriding the board and manufacturer name in-firmware --- src/zigbee_ncp/app.c | 28 +++++++++++++++++++++++++--- src/zigbee_ncp/config/xncp_config.h | 8 ++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index d6478653..7655de18 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -29,15 +29,19 @@ typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES = 0x0000, - XNCP_CMD_SET_SOURCE_ROUTE = 0x0001 + XNCP_CMD_SET_SOURCE_ROUTE = 0x0001, + XNCP_CMD_GET_BOARD_NAME_OVERRIDE = 0x0002, + XNCP_CMD_GET_MANUF_NAME_OVERRIDE = 0x0003 } CUSTOM_EZSP_CMD; -#define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) -#define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) +#define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) +#define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) +#define FEATURE_BOARD_MANUF_OVERRIDE (0b00000000000000000000000000000100) #define SUPPORTED_FEATURES ( \ FEATURE_MEMBER_OF_ALL_GROUPS \ | FEATURE_MANUAL_SOURCE_ROUTE \ + | FEATURE_BOARD_MANUF_OVERRIDE \ ) @@ -196,6 +200,24 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; + case XNCP_CMD_GET_BOARD_NAME_OVERRIDE: + if (!XNCP_BOARD_MANUF_OVERRIDE_ENABLED) { + break; + } + + *replyPayloadLength += strlen(XNCP_BOARD_NAME_OVERRIDE); + memcpy(replyPayload, XNCP_BOARD_NAME_OVERRIDE, *replyPayloadLength); + break; + + case XNCP_CMD_GET_MANUF_NAME_OVERRIDE: + if (!XNCP_BOARD_MANUF_OVERRIDE_ENABLED) { + break; + } + + *replyPayloadLength += strlen(XNCP_MANUF_NAME_OVERRIDE); + memcpy(replyPayload, XNCP_MANUF_NAME_OVERRIDE, *replyPayloadLength); + break; + default: return EMBER_BAD_ARGUMENT; } diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index 8a4ca9f6..02c506ad 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -6,4 +6,12 @@ // destinations can be concurrently contacted with source routing enabled. #define XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE (20) + +// Some manufacturers do not write a board or manufacturer name to the NCP. +// Rather than writing the manufacturing tokens within the application, you can instead +// supply overrides that will be preferred to the manufacturing token values. +#define XNCP_BOARD_MANUF_OVERRIDE_ENABLED (false) +#define XNCP_BOARD_NAME_OVERRIDE ("") +#define XNCP_MANUF_NAME_OVERRIDE ("") + #endif /* CONFIG_XNCP_CONFIG_H_ */ From 599eb2ba4dbcf62a405806705f968388c0a65f7f Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:51:41 -0400 Subject: [PATCH 10/34] Compute the length separately to isolate payload additions --- src/zigbee_ncp/app.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 7655de18..b2fae863 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -205,8 +205,9 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; } - *replyPayloadLength += strlen(XNCP_BOARD_NAME_OVERRIDE); - memcpy(replyPayload, XNCP_BOARD_NAME_OVERRIDE, *replyPayloadLength); + uint8_t length = strlen(XNCP_BOARD_NAME_OVERRIDE); + *replyPayloadLength += length; + memcpy(replyPayload, XNCP_BOARD_NAME_OVERRIDE, length); break; case XNCP_CMD_GET_MANUF_NAME_OVERRIDE: @@ -214,8 +215,9 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; } - *replyPayloadLength += strlen(XNCP_MANUF_NAME_OVERRIDE); - memcpy(replyPayload, XNCP_MANUF_NAME_OVERRIDE, *replyPayloadLength); + uint8_t length = strlen(XNCP_MANUF_NAME_OVERRIDE); + *replyPayloadLength += length; + memcpy(replyPayload, XNCP_MANUF_NAME_OVERRIDE, length); break; default: From ab302a39a9f31e8af192ec9fe7660c136a78f9a3 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:57:41 -0400 Subject: [PATCH 11/34] Don't require an enable flag --- src/zigbee_ncp/app.c | 8 -------- src/zigbee_ncp/config/xncp_config.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index b2fae863..027d192e 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -201,20 +201,12 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; case XNCP_CMD_GET_BOARD_NAME_OVERRIDE: - if (!XNCP_BOARD_MANUF_OVERRIDE_ENABLED) { - break; - } - uint8_t length = strlen(XNCP_BOARD_NAME_OVERRIDE); *replyPayloadLength += length; memcpy(replyPayload, XNCP_BOARD_NAME_OVERRIDE, length); break; case XNCP_CMD_GET_MANUF_NAME_OVERRIDE: - if (!XNCP_BOARD_MANUF_OVERRIDE_ENABLED) { - break; - } - uint8_t length = strlen(XNCP_MANUF_NAME_OVERRIDE); *replyPayloadLength += length; memcpy(replyPayload, XNCP_MANUF_NAME_OVERRIDE, length); diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index 02c506ad..3ef71994 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -10,7 +10,6 @@ // Some manufacturers do not write a board or manufacturer name to the NCP. // Rather than writing the manufacturing tokens within the application, you can instead // supply overrides that will be preferred to the manufacturing token values. -#define XNCP_BOARD_MANUF_OVERRIDE_ENABLED (false) #define XNCP_BOARD_NAME_OVERRIDE ("") #define XNCP_MANUF_NAME_OVERRIDE ("") From 4f3fa50ecbf32f8ba31390d7a03d9cdcc46320b2 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 12:59:13 -0400 Subject: [PATCH 12/34] Remove `_OVERRIDE` suffix from board and manuf name --- src/zigbee_ncp/app.c | 20 ++++++++++---------- src/zigbee_ncp/config/xncp_config.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 027d192e..ad3b949d 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -30,18 +30,18 @@ typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES = 0x0000, XNCP_CMD_SET_SOURCE_ROUTE = 0x0001, - XNCP_CMD_GET_BOARD_NAME_OVERRIDE = 0x0002, - XNCP_CMD_GET_MANUF_NAME_OVERRIDE = 0x0003 + XNCP_CMD_GET_BOARD_NAME = 0x0002, + XNCP_CMD_GET_MANUF_NAME = 0x0003 } CUSTOM_EZSP_CMD; #define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) #define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) -#define FEATURE_BOARD_MANUF_OVERRIDE (0b00000000000000000000000000000100) +#define FEATURE_BOARD_MANUF (0b00000000000000000000000000000100) #define SUPPORTED_FEATURES ( \ FEATURE_MEMBER_OF_ALL_GROUPS \ | FEATURE_MANUAL_SOURCE_ROUTE \ - | FEATURE_BOARD_MANUF_OVERRIDE \ + | FEATURE_BOARD_MANUF \ ) @@ -200,16 +200,16 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; - case XNCP_CMD_GET_BOARD_NAME_OVERRIDE: - uint8_t length = strlen(XNCP_BOARD_NAME_OVERRIDE); + case XNCP_CMD_GET_BOARD_NAME: + uint8_t length = strlen(XNCP_BOARD_NAME); *replyPayloadLength += length; - memcpy(replyPayload, XNCP_BOARD_NAME_OVERRIDE, length); + memcpy(replyPayload, XNCP_BOARD_NAME, length); break; - case XNCP_CMD_GET_MANUF_NAME_OVERRIDE: - uint8_t length = strlen(XNCP_MANUF_NAME_OVERRIDE); + case XNCP_CMD_GET_MANUF_NAME: + uint8_t length = strlen(XNCP_MANUF_NAME); *replyPayloadLength += length; - memcpy(replyPayload, XNCP_MANUF_NAME_OVERRIDE, length); + memcpy(replyPayload, XNCP_MANUF_NAME, length); break; default: diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index 3ef71994..b4a410bd 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -10,7 +10,7 @@ // Some manufacturers do not write a board or manufacturer name to the NCP. // Rather than writing the manufacturing tokens within the application, you can instead // supply overrides that will be preferred to the manufacturing token values. -#define XNCP_BOARD_NAME_OVERRIDE ("") -#define XNCP_MANUF_NAME_OVERRIDE ("") +#define XNCP_BOARD_NAME ("") +#define XNCP_MANUF_NAME ("") #endif /* CONFIG_XNCP_CONFIG_H_ */ From 311858951b108ec7862392a3cad174af48fc82b0 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 16:47:19 -0400 Subject: [PATCH 13/34] Use a status and a command ID for all responses --- src/zigbee_ncp/app.c | 90 +++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index ad3b949d..01f645e5 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -28,11 +28,18 @@ #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) typedef enum { - XNCP_CMD_GET_SUPPORTED_FEATURES = 0x0000, - XNCP_CMD_SET_SOURCE_ROUTE = 0x0001, - XNCP_CMD_GET_BOARD_NAME = 0x0002, - XNCP_CMD_GET_MANUF_NAME = 0x0003 -} CUSTOM_EZSP_CMD; + XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, + XNCP_CMD_SET_SOURCE_ROUTE_REQ = 0x0001, + XNCP_CMD_GET_BOARD_NAME_REQ = 0x0002, + XNCP_CMD_GET_MANUF_NAME_REQ = 0x0003, + + XNCP_CMD_GET_SUPPORTED_FEATURES_RSP = XNCP_CMD_GET_SUPPORTED_FEATURES_REQ | 0x8000, + XNCP_CMD_SET_SOURCE_ROUTE_RSP = XNCP_CMD_SET_SOURCE_ROUTE_REQ | 0x8000, + XNCP_CMD_GET_BOARD_NAME_RSP = XNCP_CMD_GET_BOARD_NAME_REQ | 0x8000, + XNCP_CMD_GET_MANUF_NAME_RSP = XNCP_CMD_GET_MANUF_NAME_REQ | 0x8000, + + XNCP_CMD_UNKNOWN = 0xFFFF +} XNCP_COMMAND; #define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) @@ -146,30 +153,48 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *replyPayload) { *replyPayloadLength = 0; - if (messageLength < 2) { - return EMBER_BAD_ARGUMENT; + uint8_t rsp_status = EMBER_ERR_FATAL; + uint16_t req_command_id = XNCP_CMD_UNKNOWN; + uint16_t rsp_command_id = XNCP_CMD_UNKNOWN; + + if (messageLength >= 3) { + rsp_status = EMBER_SUCCESS; + req_command_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); + + uint8_t req_status = messagePayload[2]; + (void)req_status; + + messagePayload += 3; } - uint16_t command_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); + *replyPayloadLength += 2; // Space for the response command ID + *replyPayloadLength += 1; // Space for the status + + switch (req_command_id) { + case XNCP_CMD_GET_SUPPORTED_FEATURES_REQ: + rsp_command_id = XNCP_CMD_GET_SUPPORTED_FEATURES_RSP; + rsp_status = EMBER_SUCCESS; - switch (command_id) { - case XNCP_CMD_GET_SUPPORTED_FEATURES: - *replyPayloadLength += 4; - replyPayload[0] = (uint8_t)((SUPPORTED_FEATURES >> 0) & 0xFF); - replyPayload[1] = (uint8_t)((SUPPORTED_FEATURES >> 8) & 0xFF); - replyPayload[2] = (uint8_t)((SUPPORTED_FEATURES >> 16) & 0xFF); - replyPayload[3] = (uint8_t)((SUPPORTED_FEATURES >> 24) & 0xFF); + replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 0) & 0xFF); + replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 8) & 0xFF); + replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 16) & 0xFF); + replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 24) & 0xFF); break; - case XNCP_CMD_SET_SOURCE_ROUTE: + case XNCP_CMD_SET_SOURCE_ROUTE_REQ: + rsp_command_id = XNCP_CMD_SET_SOURCE_ROUTE_RSP; + rsp_status = EMBER_SUCCESS; + if ((messageLength < 4) || (messageLength % 2 != 0)) { - return EMBER_BAD_ARGUMENT; + rsp_status = EMBER_BAD_ARGUMENT; + break; } uint8_t num_relays = (messageLength - 4) / 2; if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1) { - return EMBER_BAD_ARGUMENT; + rsp_status = EMBER_BAD_ARGUMENT; + break; } // If we don't find a better index, pick one at random to replace @@ -200,21 +225,32 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; - case XNCP_CMD_GET_BOARD_NAME: - uint8_t length = strlen(XNCP_BOARD_NAME); - *replyPayloadLength += length; - memcpy(replyPayload, XNCP_BOARD_NAME, length); + case XNCP_CMD_GET_BOARD_NAME_REQ: + rsp_command_id = XNCP_CMD_GET_BOARD_NAME_RSP; + rsp_status = EMBER_SUCCESS; + + uint8_t name_length = strlen(XNCP_BOARD_NAME); + *replyPayloadLength += name_length; + memcpy(replyPayload, XNCP_BOARD_NAME, name_length); break; - case XNCP_CMD_GET_MANUF_NAME: - uint8_t length = strlen(XNCP_MANUF_NAME); - *replyPayloadLength += length; - memcpy(replyPayload, XNCP_MANUF_NAME, length); + case XNCP_CMD_GET_MANUF_NAME_REQ: + rsp_command_id = XNCP_CMD_GET_MANUF_NAME_RSP; + rsp_status = EMBER_SUCCESS; + + uint8_t name_length = strlen(XNCP_MANUF_NAME); + *replyPayloadLength += name_length; + memcpy(replyPayload, XNCP_MANUF_NAME, name_length); break; default: - return EMBER_BAD_ARGUMENT; + rsp_status = EMBER_NOT_FOUND; + break; } + replyPayload[0] = (uint8_t)((rsp_command_id >> 0) & 0xFF); + replyPayload[1] = (uint8_t)((rsp_command_id >> 8) & 0xFF); + replyPayload[2] = rsp_status; + return EMBER_SUCCESS; } From f3a9a6a6dfce45ffaa4e447c2cb9faddfeb077b2 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 17:27:16 -0400 Subject: [PATCH 14/34] Avoid scope issues with curly braces --- src/zigbee_ncp/app.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 01f645e5..d058874a 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -171,7 +171,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, *replyPayloadLength += 1; // Space for the status switch (req_command_id) { - case XNCP_CMD_GET_SUPPORTED_FEATURES_REQ: + case XNCP_CMD_GET_SUPPORTED_FEATURES_REQ: { rsp_command_id = XNCP_CMD_GET_SUPPORTED_FEATURES_RSP; rsp_status = EMBER_SUCCESS; @@ -180,8 +180,9 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 16) & 0xFF); replyPayload[(*replyPayloadLength)++] = (uint8_t)((SUPPORTED_FEATURES >> 24) & 0xFF); break; + } - case XNCP_CMD_SET_SOURCE_ROUTE_REQ: + case XNCP_CMD_SET_SOURCE_ROUTE_REQ: { rsp_command_id = XNCP_CMD_SET_SOURCE_ROUTE_RSP; rsp_status = EMBER_SUCCESS; @@ -224,8 +225,9 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, route->active = true; break; + } - case XNCP_CMD_GET_BOARD_NAME_REQ: + case XNCP_CMD_GET_BOARD_NAME_REQ: { rsp_command_id = XNCP_CMD_GET_BOARD_NAME_RSP; rsp_status = EMBER_SUCCESS; @@ -233,8 +235,9 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, *replyPayloadLength += name_length; memcpy(replyPayload, XNCP_BOARD_NAME, name_length); break; + } - case XNCP_CMD_GET_MANUF_NAME_REQ: + case XNCP_CMD_GET_MANUF_NAME_REQ: { rsp_command_id = XNCP_CMD_GET_MANUF_NAME_RSP; rsp_status = EMBER_SUCCESS; @@ -242,10 +245,12 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, *replyPayloadLength += name_length; memcpy(replyPayload, XNCP_MANUF_NAME, name_length); break; + } - default: + default: { rsp_status = EMBER_NOT_FOUND; break; + } } replyPayload[0] = (uint8_t)((rsp_command_id >> 0) & 0xFF); From 0765193389faa904e4c97ccecec06bea64d58f49 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 17:58:31 -0400 Subject: [PATCH 15/34] Use a generic command for manufacturing token overrides --- src/zigbee_ncp/app.c | 88 ++++++++++++++++++----------- src/zigbee_ncp/config/xncp_config.h | 4 +- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index d058874a..fa203076 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -30,13 +30,11 @@ typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, XNCP_CMD_SET_SOURCE_ROUTE_REQ = 0x0001, - XNCP_CMD_GET_BOARD_NAME_REQ = 0x0002, - XNCP_CMD_GET_MANUF_NAME_REQ = 0x0003, + XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ = 0x0002, XNCP_CMD_GET_SUPPORTED_FEATURES_RSP = XNCP_CMD_GET_SUPPORTED_FEATURES_REQ | 0x8000, XNCP_CMD_SET_SOURCE_ROUTE_RSP = XNCP_CMD_SET_SOURCE_ROUTE_REQ | 0x8000, - XNCP_CMD_GET_BOARD_NAME_RSP = XNCP_CMD_GET_BOARD_NAME_REQ | 0x8000, - XNCP_CMD_GET_MANUF_NAME_RSP = XNCP_CMD_GET_MANUF_NAME_REQ | 0x8000, + XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_RSP = XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ | 0x8000, XNCP_CMD_UNKNOWN = 0xFFFF } XNCP_COMMAND; @@ -44,11 +42,11 @@ typedef enum { #define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) #define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) -#define FEATURE_BOARD_MANUF (0b00000000000000000000000000000100) +#define FEATURE_MFG_TOKEN_OVERRIDES (0b00000000000000000000000000000100) #define SUPPORTED_FEATURES ( \ FEATURE_MEMBER_OF_ALL_GROUPS \ | FEATURE_MANUAL_SOURCE_ROUTE \ - | FEATURE_BOARD_MANUF \ + | FEATURE_MFG_TOKEN_OVERRIDES \ ) @@ -151,22 +149,28 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, uint8_t *replyPayloadLength, uint8_t *replyPayload) { - *replyPayloadLength = 0; - - uint8_t rsp_status = EMBER_ERR_FATAL; - uint16_t req_command_id = XNCP_CMD_UNKNOWN; + uint8_t rsp_status = EMBER_SUCCESS; uint16_t rsp_command_id = XNCP_CMD_UNKNOWN; - if (messageLength >= 3) { - rsp_status = EMBER_SUCCESS; - req_command_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); - - uint8_t req_status = messagePayload[2]; - (void)req_status; + if (messageLength < 3) { + rsp_status = EMBER_BAD_ARGUMENT; - messagePayload += 3; + replyPayload[0] = (uint8_t)((rsp_command_id >> 0) & 0xFF); + replyPayload[1] = (uint8_t)((rsp_command_id >> 8) & 0xFF); + replyPayload[2] = rsp_status; + return EMBER_SUCCESS; } + uint16_t req_command_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); + uint8_t req_status = messagePayload[2]; + (void)req_status; + + // Strip the packet header to simplify command parsing below + messagePayload += 3; + messageLength -= 3; + + // Leave space for the reply packet header + *replyPayloadLength = 0; *replyPayloadLength += 2; // Space for the response command ID *replyPayloadLength += 1; // Space for the status @@ -186,12 +190,12 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, rsp_command_id = XNCP_CMD_SET_SOURCE_ROUTE_RSP; rsp_status = EMBER_SUCCESS; - if ((messageLength < 4) || (messageLength % 2 != 0)) { + if (messageLength % 2 != 0) { rsp_status = EMBER_BAD_ARGUMENT; break; } - uint8_t num_relays = (messageLength - 4) / 2; + uint8_t num_relays = messageLength / 2; if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1) { rsp_status = EMBER_BAD_ARGUMENT; @@ -200,7 +204,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, // If we don't find a better index, pick one at random to replace uint8_t insertion_index = emberGetPseudoRandomNumber() % XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; - uint16_t node_id = BUILD_UINT16(messagePayload[2], messagePayload[3]); + uint16_t node_id = BUILD_UINT16(messagePayload[0], messagePayload[1]); for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { ManualSourceRoute *route = &manual_source_routes[i]; @@ -216,7 +220,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, ManualSourceRoute *route = &manual_source_routes[insertion_index]; for (uint8_t i = 0; i < num_relays; i++) { - uint16_t relay = BUILD_UINT16(messagePayload[4 + 2 * i + 0], messagePayload[4 + 2 * i + 1]); + uint16_t relay = BUILD_UINT16(messagePayload[2 + 2 * i + 0], messagePayload[2 + 2 * i + 1]); route->relays[i] = relay; } @@ -227,23 +231,39 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; } - case XNCP_CMD_GET_BOARD_NAME_REQ: { - rsp_command_id = XNCP_CMD_GET_BOARD_NAME_RSP; + case XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ: { + rsp_command_id = XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_RSP; rsp_status = EMBER_SUCCESS; - uint8_t name_length = strlen(XNCP_BOARD_NAME); - *replyPayloadLength += name_length; - memcpy(replyPayload, XNCP_BOARD_NAME, name_length); - break; - } + if (messageLength != 1) { + rsp_status = EMBER_BAD_ARGUMENT; + break; + } - case XNCP_CMD_GET_MANUF_NAME_REQ: { - rsp_command_id = XNCP_CMD_GET_MANUF_NAME_RSP; - rsp_status = EMBER_SUCCESS; + uint8_t token_id = messagePayload[0]; + char *override_value; + + switch (token_id) { + case EZSP_MFG_STRING: { + override_value = XNCP_MFG_MANUF_NAME; + break; + } + + case EZSP_MFG_BOARD_NAME: { + override_value = XNCP_MFG_BOARD_NAME; + break; + } + + default: { + rsp_status = EMBER_NOT_FOUND; + override_value = ""; + break; + } + } - uint8_t name_length = strlen(XNCP_MANUF_NAME); - *replyPayloadLength += name_length; - memcpy(replyPayload, XNCP_MANUF_NAME, name_length); + uint8_t value_length = strlen(override_value); + memcpy(replyPayload + *replyPayloadLength, override_value, value_length); + *replyPayloadLength += value_length; break; } diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index b4a410bd..190b5ea9 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -10,7 +10,7 @@ // Some manufacturers do not write a board or manufacturer name to the NCP. // Rather than writing the manufacturing tokens within the application, you can instead // supply overrides that will be preferred to the manufacturing token values. -#define XNCP_BOARD_NAME ("") -#define XNCP_MANUF_NAME ("") +#define XNCP_MFG_MANUF_NAME ("") +#define XNCP_MFG_BOARD_NAME ("") #endif /* CONFIG_XNCP_CONFIG_H_ */ From 641d160b5d83d7aaaefa69715056196527cb2151 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 29 May 2024 21:27:43 -0400 Subject: [PATCH 16/34] Fix command parsing for `SET_SOURCE_ROUTE_REQ` --- src/zigbee_ncp/app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index fa203076..d7d06fe8 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -190,12 +190,12 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, rsp_command_id = XNCP_CMD_SET_SOURCE_ROUTE_RSP; rsp_status = EMBER_SUCCESS; - if (messageLength % 2 != 0) { + if ((messageLength < 2) || (messageLength % 2 != 0)) { rsp_status = EMBER_BAD_ARGUMENT; break; } - uint8_t num_relays = messageLength / 2; + uint8_t num_relays = (messageLength - 2) / 2; if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1) { rsp_status = EMBER_BAD_ARGUMENT; From 6b0897ee1ca5add3456103675eebca9eb64fee73 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sat, 1 Jun 2024 12:14:32 -0400 Subject: [PATCH 17/34] WIP: Disable automatic source routing and inject source routes directly --- src/zigbee_ncp/app.c | 120 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 23 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index d7d06fe8..1151006d 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -25,8 +25,13 @@ #include "config/xncp_config.h" + #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) + +extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; +extern uint8_t sli_zigbee_route_table_size; + typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, XNCP_CMD_SET_SOURCE_ROUTE_REQ = 0x0001, @@ -59,6 +64,25 @@ typedef struct ManualSourceRoute { ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE]; + +ManualSourceRoute* get_manual_source_route(EmberNodeId destination) +{ + uint8_t index = 0xFF; + + for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { + if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { + index = i; + break; + } + } + + if (index == 0xFF) { + return NULL; + } + + return &manual_source_routes[index]; +} + //---------------------- // Implemented Callbacks @@ -81,7 +105,7 @@ void emberAfMainInitCallback(void) } } -/** @brief Packet filter callback +/** @brief Incoming packet filter callback * * Filters and/or mutates incoming packets. Currently used only for wildcard multicast * group membership. @@ -108,40 +132,82 @@ EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType pack return EMBER_ACCEPT_PACKET; } - -void nc_zigbee_override_append_source_route(EmberNodeId destination, - EmberMessageBuffer *header, - bool *consumed) +/** @brief Outgoing packet filter callback + * + * Filters and/or mutates outgoing packets. Currently injects manual source routes. + */ +EmberPacketAction emberAfOutgoingPacketFilterCallback(EmberZigbeePacketType packetType, + uint8_t* packetData, + uint8_t* size_p, + void* data) { - uint8_t index = 0xFF; + // Only mutate NWK data packets + if (packetType != EMBER_ZIGBEE_PACKET_TYPE_NWK_DATA) { + return EMBER_ACCEPT_PACKET; + } - for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { - if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { - index = i; - break; - } + uint16_t frame_control = BUILD_UINT16(packetData[0], packetData[1]); + + // Don't mutate multicast traffic + if (frame_control & 0b0000000100000000) { + return EMBER_ACCEPT_PACKET; } - if (index == 0xFF) { - *consumed = false; - return; + uint16_t destination = BUILD_UINT16(packetData[2], packetData[3]); + + // Don't mutate broadcast traffic + if (destination >= 0xFFFC) { + return EMBER_ACCEPT_PACKET; } - ManualSourceRoute *route = &manual_source_routes[index]; + ManualSourceRoute* source_route = get_manual_source_route(destination); + + // If we do not have a source route, continue as normal + if (source_route == NULL) { + return EMBER_ACCEPT_PACKET; + } - uint8_t relay_index = 0; + // Flip the source routing bit + packetData[1] |= 0b00000100; - *consumed = true; - route->active = false; // Disable the route after a single use + // And make room for the source route: relay_count, relay_index, list of relays + uint8_t bytes_to_grow = 1 + 1 + 2 * source_route->num_relays; + uint8_t aux_header_size = 2; - emberAppendToLinkedBuffers(*header, &route->num_relays, 1); - emberAppendToLinkedBuffers(*header, &relay_index, 1); + // Extended source + if (frame_control & 0b0001000000000000) { + aux_header_size += 8; + } else { + aux_header_size += 2; + } - for (uint8_t i = 0; i < route->num_relays; i++) { - emberAppendToLinkedBuffers(*header, (uint8_t*)&route->relays[i], 2); + // Extended destination + if (frame_control & 0b0000100000000000) { + aux_header_size += 8; + } else { + aux_header_size += 2; } - return; + // Radius and sequence + aux_header_size += 2; + + // The source route list is after the AUX header, before the security header + memmove( + packetData + bytes_to_grow + aux_header_size, + packetData + aux_header_size, + *size_p - aux_header_size + ); + *size_p += bytes_to_grow; + + packetData[aux_header_size + 0] = source_route->num_relays; + packetData[aux_header_size + 1] = 0; // Relay index + + for (uint8_t i = 0; i < source_route->num_relays; i++) { + packetData[aux_header_size + 2 + 2 * i + 0] = (source_route->relays[i] >> 0) & 0xFF; + packetData[aux_header_size + 2 + 2 * i + 1] = (source_route->relays[i] >> 8) & 0xFF; + } + + return EMBER_MANGLE_PACKET; } @@ -228,6 +294,14 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, route->num_relays = num_relays; route->active = true; + // Add a fake route to the routing table to skip routing to the node + sli_zigbee_route_table_entry_t *route_table_entry = &sli_zigbee_route_table[0]; + route_table_entry->destination = node_id; + route_table_entry->nextHop = node_id; + route_table_entry->status = 0; // ACTIVE=0 + route_table_entry->cost = 0; + route_table_entry->networkIndex = 0; + break; } From 6b4571d6b4a4a5e6a7a5403ff6c7552b24231b94 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 2 Jun 2024 13:13:28 -0400 Subject: [PATCH 18/34] WIP: Disable the packet handoff component and go lower --- src/zigbee_ncp/app.c | 87 +++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 1151006d..c861f31b 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -20,6 +20,7 @@ #include "ember-types.h" #include "ezsp-enum.h" #include "random.h" +#include "mac-flat-header.h" #include "stack/include/message.h" @@ -27,7 +28,8 @@ #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) - +#define emberPacketHandoffIncomingHandler sli_zigbee_af_packet_handoff_incoming_callback +#define emberPacketHandoffOutgoingHandler sli_zigbee_af_packet_handoff_outgoing_callback extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; extern uint8_t sli_zigbee_route_table_size; @@ -110,42 +112,72 @@ void emberAfMainInitCallback(void) * Filters and/or mutates incoming packets. Currently used only for wildcard multicast * group membership. */ -EmberPacketAction emberAfIncomingPacketFilterCallback(EmberZigbeePacketType packetType, - uint8_t* packetData, - uint8_t* size_p, - void* data) +EmberPacketAction emberPacketHandoffIncomingHandler(EmberZigbeePacketType packetType, + EmberMessageBuffer packetBuffer, + uint8_t index, + void *data) { - if ((packetType == EMBER_ZIGBEE_PACKET_TYPE_APS_DATA) && (*size_p >= 3)) { - uint8_t deliveryMode = (packetData[0] & 0b00001100) >> 2; + if (packetType != EMBER_ZIGBEE_PACKET_TYPE_APS_DATA) { + return EMBER_ACCEPT_PACKET; + } - // Ensure we automatically "join" every multicast group - if (deliveryMode == 0x03) { - // Take ownership over the first entry and continuously rewrite it - EmberMulticastTableEntry *tableEntry = &(sl_zigbee_get_multicast_table()[0]); + uint8_t* packetData = emberMessageBufferContents(packetBuffer); + uint16_t packetSize = emberMessageBufferLength(packetBuffer); - tableEntry->endpoint = 1; - tableEntry->multicastId = BUILD_UINT16(packetData[1], packetData[2]); - tableEntry->networkIndex = 0; - } + // Skip over the 802.15.4 header to the payload + uint8_t payload_offset = sl_mac_flat_field_offset(packetData, true, EMBER_PH_FIELD_MAC_PAYLOAD); + packetData += payload_offset; + packetSize -= payload_offset; + + if (packetSize < 3) { + return EMBER_ACCEPT_PACKET; } + uint8_t deliveryMode = (packetData[0] & 0b00001100) >> 2; + + // Only look at multicast packets + if (deliveryMode != 0x03) { + return EMBER_ACCEPT_PACKET; + } + + // Take ownership over the first entry and continuously rewrite it + EmberMulticastTableEntry *tableEntry = &(sl_zigbee_get_multicast_table()[0]); + + tableEntry->endpoint = 1; + tableEntry->multicastId = BUILD_UINT16(packetData[1], packetData[2]); + tableEntry->networkIndex = 0; + return EMBER_ACCEPT_PACKET; } +#define emberPacketHandoffOutgoingHandler sli_zigbee_af_packet_handoff_outgoing_callback + /** @brief Outgoing packet filter callback * * Filters and/or mutates outgoing packets. Currently injects manual source routes. */ -EmberPacketAction emberAfOutgoingPacketFilterCallback(EmberZigbeePacketType packetType, - uint8_t* packetData, - uint8_t* size_p, - void* data) +EmberPacketAction emberPacketHandoffOutgoingHandler(EmberZigbeePacketType packetType, + EmberMessageBuffer packetBuffer, + uint8_t index, + void *data) { // Only mutate NWK data packets if (packetType != EMBER_ZIGBEE_PACKET_TYPE_NWK_DATA) { return EMBER_ACCEPT_PACKET; } + uint8_t* packetData = emberMessageBufferContents(packetBuffer); + uint16_t packetSize = emberMessageBufferLength(packetBuffer); + + // Skip over the 802.15.4 header to the payload + uint8_t payload_offset = sl_mac_flat_field_offset(packetData, true, EMBER_PH_FIELD_MAC_PAYLOAD); + packetData += payload_offset; + packetSize -= payload_offset; + + if (packetSize < 4) { + return EMBER_ACCEPT_PACKET; + } + uint16_t frame_control = BUILD_UINT16(packetData[0], packetData[1]); // Don't mutate multicast traffic @@ -172,6 +204,12 @@ EmberPacketAction emberAfOutgoingPacketFilterCallback(EmberZigbeePacketType pack // And make room for the source route: relay_count, relay_index, list of relays uint8_t bytes_to_grow = 1 + 1 + 2 * source_route->num_relays; + + // Grow and re-load the buffer, ensuring we again skip ahead to the payload + emberExtendLinkedBuffer(packetBuffer, bytes_to_grow); + packetData = emberMessageBufferContents(packetBuffer); + packetData += payload_offset; + uint8_t aux_header_size = 2; // Extended source @@ -191,13 +229,10 @@ EmberPacketAction emberAfOutgoingPacketFilterCallback(EmberZigbeePacketType pack // Radius and sequence aux_header_size += 2; - // The source route list is after the AUX header, before the security header - memmove( - packetData + bytes_to_grow + aux_header_size, - packetData + aux_header_size, - *size_p - aux_header_size - ); - *size_p += bytes_to_grow; + // Shift the packet data to make room between the AUX header and the plaintext payload + for (uint8_t i = 0; i < packetSize - aux_header_size; i++) { + packetData[aux_header_size + bytes_to_grow + i] = packetData[aux_header_size + i]; + } packetData[aux_header_size + 0] = source_route->num_relays; packetData[aux_header_size + 1] = 0; // Relay index From eec537b351bdc5c8bde1068239368a20eac8eb9d Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:42:59 -0400 Subject: [PATCH 19/34] Revert back to source routing override until GSDK bugfix --- src/zigbee_ncp/app.c | 102 ++++++++++++------------------------------- 1 file changed, 27 insertions(+), 75 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index c861f31b..fdb31b81 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -28,8 +28,6 @@ #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) -#define emberPacketHandoffIncomingHandler sli_zigbee_af_packet_handoff_incoming_callback -#define emberPacketHandoffOutgoingHandler sli_zigbee_af_packet_handoff_outgoing_callback extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; extern uint8_t sli_zigbee_route_table_size; @@ -112,7 +110,7 @@ void emberAfMainInitCallback(void) * Filters and/or mutates incoming packets. Currently used only for wildcard multicast * group membership. */ -EmberPacketAction emberPacketHandoffIncomingHandler(EmberZigbeePacketType packetType, +EmberPacketAction sli_zigbee_af_packet_handoff_incoming_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, void *data) @@ -150,99 +148,53 @@ EmberPacketAction emberPacketHandoffIncomingHandler(EmberZigbeePacketType packet return EMBER_ACCEPT_PACKET; } -#define emberPacketHandoffOutgoingHandler sli_zigbee_af_packet_handoff_outgoing_callback /** @brief Outgoing packet filter callback * - * Filters and/or mutates outgoing packets. Currently injects manual source routes. + * Filters and/or mutates outgoing packets. */ -EmberPacketAction emberPacketHandoffOutgoingHandler(EmberZigbeePacketType packetType, +EmberPacketAction sli_zigbee_af_packet_handoff_outgoing_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, void *data) { - // Only mutate NWK data packets - if (packetType != EMBER_ZIGBEE_PACKET_TYPE_NWK_DATA) { - return EMBER_ACCEPT_PACKET; - } - - uint8_t* packetData = emberMessageBufferContents(packetBuffer); - uint16_t packetSize = emberMessageBufferLength(packetBuffer); - - // Skip over the 802.15.4 header to the payload - uint8_t payload_offset = sl_mac_flat_field_offset(packetData, true, EMBER_PH_FIELD_MAC_PAYLOAD); - packetData += payload_offset; - packetSize -= payload_offset; - - if (packetSize < 4) { - return EMBER_ACCEPT_PACKET; - } - - uint16_t frame_control = BUILD_UINT16(packetData[0], packetData[1]); - - // Don't mutate multicast traffic - if (frame_control & 0b0000000100000000) { - return EMBER_ACCEPT_PACKET; - } - - uint16_t destination = BUILD_UINT16(packetData[2], packetData[3]); + return EMBER_ACCEPT_PACKET; +} - // Don't mutate broadcast traffic - if (destination >= 0xFFFC) { - return EMBER_ACCEPT_PACKET; - } - ManualSourceRoute* source_route = get_manual_source_route(destination); +void nc_zigbee_override_append_source_route(EmberNodeId destination, + EmberMessageBuffer *header, + bool *consumed) +{ + uint8_t index = 0xFF; - // If we do not have a source route, continue as normal - if (source_route == NULL) { - return EMBER_ACCEPT_PACKET; + for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { + if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { + index = i; + break; + } } - // Flip the source routing bit - packetData[1] |= 0b00000100; - - // And make room for the source route: relay_count, relay_index, list of relays - uint8_t bytes_to_grow = 1 + 1 + 2 * source_route->num_relays; - - // Grow and re-load the buffer, ensuring we again skip ahead to the payload - emberExtendLinkedBuffer(packetBuffer, bytes_to_grow); - packetData = emberMessageBufferContents(packetBuffer); - packetData += payload_offset; - - uint8_t aux_header_size = 2; - - // Extended source - if (frame_control & 0b0001000000000000) { - aux_header_size += 8; - } else { - aux_header_size += 2; + if (index == 0xFF) { + *consumed = false; + return; } - // Extended destination - if (frame_control & 0b0000100000000000) { - aux_header_size += 8; - } else { - aux_header_size += 2; - } + ManualSourceRoute *route = &manual_source_routes[index]; - // Radius and sequence - aux_header_size += 2; + uint8_t relay_index = 0; - // Shift the packet data to make room between the AUX header and the plaintext payload - for (uint8_t i = 0; i < packetSize - aux_header_size; i++) { - packetData[aux_header_size + bytes_to_grow + i] = packetData[aux_header_size + i]; - } + *consumed = true; + route->active = false; // Disable the route after a single use - packetData[aux_header_size + 0] = source_route->num_relays; - packetData[aux_header_size + 1] = 0; // Relay index + emberAppendToLinkedBuffers(*header, &route->num_relays, 1); + emberAppendToLinkedBuffers(*header, &relay_index, 1); - for (uint8_t i = 0; i < source_route->num_relays; i++) { - packetData[aux_header_size + 2 + 2 * i + 0] = (source_route->relays[i] >> 0) & 0xFF; - packetData[aux_header_size + 2 + 2 * i + 1] = (source_route->relays[i] >> 8) & 0xFF; + for (uint8_t i = 0; i < route->num_relays; i++) { + emberAppendToLinkedBuffers(*header, (uint8_t*)&route->relays[i], 2); } - return EMBER_MANGLE_PACKET; + return; } From 95d97bd722b7daa2fbaa42a8d6cbdf531720b0e9 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:44:25 -0400 Subject: [PATCH 20/34] Remove routing table modifications --- src/zigbee_ncp/app.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index fdb31b81..891d0774 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -29,8 +29,6 @@ #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) -extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; -extern uint8_t sli_zigbee_route_table_size; typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, @@ -281,14 +279,6 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, route->num_relays = num_relays; route->active = true; - // Add a fake route to the routing table to skip routing to the node - sli_zigbee_route_table_entry_t *route_table_entry = &sli_zigbee_route_table[0]; - route_table_entry->destination = node_id; - route_table_entry->nextHop = node_id; - route_table_entry->status = 0; // ACTIVE=0 - route_table_entry->cost = 0; - route_table_entry->networkIndex = 0; - break; } From 440811816f18bd05daf4187e253d90fef27963b5 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:44:39 -0400 Subject: [PATCH 21/34] Reorder `#define`s for readability --- src/zigbee_ncp/app.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 891d0774..45a9dda6 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -29,6 +29,15 @@ #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) +#define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) +#define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) +#define FEATURE_MFG_TOKEN_OVERRIDES (0b00000000000000000000000000000100) +#define SUPPORTED_FEATURES ( \ + FEATURE_MEMBER_OF_ALL_GROUPS \ + | FEATURE_MANUAL_SOURCE_ROUTE \ + | FEATURE_MFG_TOKEN_OVERRIDES \ +) + typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, @@ -42,17 +51,6 @@ typedef enum { XNCP_CMD_UNKNOWN = 0xFFFF } XNCP_COMMAND; - -#define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) -#define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) -#define FEATURE_MFG_TOKEN_OVERRIDES (0b00000000000000000000000000000100) -#define SUPPORTED_FEATURES ( \ - FEATURE_MEMBER_OF_ALL_GROUPS \ - | FEATURE_MANUAL_SOURCE_ROUTE \ - | FEATURE_MFG_TOKEN_OVERRIDES \ -) - - typedef struct ManualSourceRoute { bool active; uint16_t destination; From 7736aa9a3971f05cd5b57655777a929a49f6f960 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:22:17 -0400 Subject: [PATCH 22/34] [TEST] Log all known counters --- src/zigbee_ncp/app.c | 129 ++++++++++++++++++++++++++ src/zigbee_ncp/zigbee_ncp.slcp | 165 +++++++++++++++++++++++++++++++++ 2 files changed, 294 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 45a9dda6..567967d9 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -61,6 +61,17 @@ typedef struct ManualSourceRoute { ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE]; +typedef struct EnqueuedEvent { + bool sent; + uint8_t length; + uint8_t message[64]; +} EnqueuedEvent; + + +#define NC_MAX_ENQUEUED_EVENTS (8) +EnqueuedEvent nc_enqueued_events[NC_MAX_ENQUEUED_EVENTS]; + + ManualSourceRoute* get_manual_source_route(EmberNodeId destination) { uint8_t index = 0xFF; @@ -99,6 +110,24 @@ void emberAfMainInitCallback(void) for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { manual_source_routes[i].active = false; } + + for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { + nc_enqueued_events[i].sent = true; + } +} + +void emberAfMainTickCallback(void) +{ + for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { + EnqueuedEvent *event = &nc_enqueued_events[i]; + + if (event->sent) { + continue; + } + + emberAfPluginXncpSendCustomEzspMessage(event->length, event->message); + event->sent = true; + } } /** @brief Incoming packet filter callback @@ -193,6 +222,106 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, return; } +void nc_enqueue_event(uint8_t length, char* message) { + for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { + EnqueuedEvent *event = &nc_enqueued_events[i]; + + if (!event->sent) { + continue; + } + + event->sent = false; + event->length = length; + memcpy(event->message, message, length); + break; + } +} + + +void nc_incoming_message(void* first_arg, ...) { nc_enqueue_event(16, "incoming_message"); } +void nc_message_sent(void* first_arg, ...) { nc_enqueue_event(12, "message_sent"); } +void nc_trust_center_join(void* first_arg, ...) { nc_enqueue_event(17, "trust_center_join"); } +void nc_mark_buffers(void* first_arg, ...) {}//{ nc_enqueue_event(12, "mark_buffers"); } +void nc_packet_handoff_incoming(void* first_arg, ...) { nc_enqueue_event(23, "packet_handoff_incoming"); } +void nc_packet_handoff_outgoing(void* first_arg, ...) { nc_enqueue_event(23, "packet_handoff_outgoing"); } +void nc_incoming_mfg_test_message(void* first_arg, ...) { nc_enqueue_event(25, "incoming_mfg_test_message"); } +void nc_stack_status(void* first_arg, ...) { nc_enqueue_event(12, "stack_status"); } +void nc_redirect_outgoing_message(void* first_arg, ...) { nc_enqueue_event(25, "redirect_outgoing_message"); } +void nc_energy_scan_result(void* first_arg, ...) { nc_enqueue_event(18, "energy_scan_result"); } +void nc_network_found(void* first_arg, ...) { nc_enqueue_event(13, "network_found"); } +void nc_scan_complete(void* first_arg, ...) { nc_enqueue_event(13, "scan_complete"); } +void nc_unused_pan_id_found(void* first_arg, ...) { nc_enqueue_event(19, "unused_pan_id_found"); } +void nc_child_join(void* first_arg, ...) { nc_enqueue_event(10, "child_join"); } +void nc_duty_cycle(void* first_arg, ...) { nc_enqueue_event(10, "duty_cycle"); } +void nc_remote_set_binding(void* first_arg, ...) { nc_enqueue_event(18, "remote_set_binding"); } +void nc_remote_delete_binding(void* first_arg, ...) { nc_enqueue_event(21, "remote_delete_binding"); } +void nc_poll_complete(void* first_arg, ...) { nc_enqueue_event(13, "poll_complete"); } +void nc_poll(void* first_arg, ...) { nc_enqueue_event(4, "poll"); } +void nc_debug(void* first_arg, ...) { nc_enqueue_event(5, "debug"); } +void nc_incoming_many_to_one_route_request(void* first_arg, ...) { nc_enqueue_event(34, "incoming_many_to_one_route_request"); } +void nc_incoming_route_error(void* first_arg, ...) { nc_enqueue_event(20, "incoming_route_error"); } +void nc_incoming_network_status(void* first_arg, ...) { nc_enqueue_event(23, "incoming_network_status"); } +void nc_incoming_route_record(void* first_arg, ...) { nc_enqueue_event(21, "incoming_route_record"); } +void nc_id_conflict(void* first_arg, ...) { nc_enqueue_event(11, "id_conflict"); } +void nc_mac_passthrough_message(void* first_arg, ...) { nc_enqueue_event(23, "mac_passthrough_message"); } +void nc_stack_token_changed(void* first_arg, ...) { nc_enqueue_event(19, "stack_token_changed"); } +void nc_timer(void* first_arg, ...) { nc_enqueue_event(5, "timer"); } +void nc_counter_rollover(void* first_arg, ...) { nc_enqueue_event(16, "counter_rollover"); } +void nc_raw_transmit_complete(void* first_arg, ...) { nc_enqueue_event(21, "raw_transmit_complete"); } +void nc_switch_network_key(void* first_arg, ...) { nc_enqueue_event(18, "switch_network_key"); } +void nc_zigbee_key_establishment(void* first_arg, ...) { nc_enqueue_event(24, "zigbee_key_establishment"); } +void nc_generate_cbke_keys(void* first_arg, ...) { nc_enqueue_event(18, "generate_cbke_keys"); } +void nc_calculate_smacs(void* first_arg, ...) { nc_enqueue_event(15, "calculate_smacs"); } +void nc_dsa_sign(void* first_arg, ...) { nc_enqueue_event(8, "dsa_sign"); } +void nc_dsa_verify(void* first_arg, ...) { nc_enqueue_event(10, "dsa_verify"); } +void nc_incoming_bootload_message(void* first_arg, ...) { nc_enqueue_event(25, "incoming_bootload_message"); } +void nc_bootload_transmit_complete(void* first_arg, ...) { nc_enqueue_event(26, "bootload_transmit_complete"); } +void nc_zll_network_found(void* first_arg, ...) { nc_enqueue_event(17, "zll_network_found"); } +void nc_zll_scan_complete(void* first_arg, ...) { nc_enqueue_event(17, "zll_scan_complete"); } +void nc_zll_address_assignment(void* first_arg, ...) { nc_enqueue_event(22, "zll_address_assignment"); } +void nc_zll_touch_link_target(void* first_arg, ...) { nc_enqueue_event(21, "zll_touch_link_target"); } +void nc_mac_filter_match_message(void* first_arg, ...) { nc_enqueue_event(24, "mac_filter_match_message"); } +void nc_d_gp_sent(void* first_arg, ...) { nc_enqueue_event(9, "d_gp_sent"); } +void nc_pan_id_conflict(void* first_arg, ...) { nc_enqueue_event(15, "pan_id_conflict"); } +void nc_orphan_notification(void* first_arg, ...) { nc_enqueue_event(19, "orphan_notification"); } +void nc_counter(void* first_arg, ...) {}//{ nc_enqueue_event(7, "counter"); } +void nc_mac_passthrough_filter(void* first_arg, ...) { nc_enqueue_event(22, "mac_passthrough_filter"); } +void nc_generate_cbke_keys_handler283k1(void* first_arg, ...) { nc_enqueue_event(31, "generate_cbke_keys_handler283k1"); } +void nc_calculate_smacs_handler283k1(void* first_arg, ...) { nc_enqueue_event(28, "calculate_smacs_handler283k1"); } +void nc_gpep_incoming_message(void* first_arg, ...) { nc_enqueue_event(21, "gpep_incoming_message"); } +void nc_rtos_idle(void* first_arg, ...) { nc_enqueue_event(9, "rtos_idle"); } +void nc_rtos_stack_wakeup_isr(void* first_arg, ...) { nc_enqueue_event(21, "rtos_stack_wakeup_isr"); } +void nc_radio_needs_calibrating(void* first_arg, ...) { nc_enqueue_event(23, "radio_needs_calibrating"); } +void nc_scan_error(void* first_arg, ...) { nc_enqueue_event(10, "scan_error"); } + +const char * COUNTER_STRINGS[] = {EMBER_COUNTER_STRINGS}; + +void emberAfCounterCallback( + // Type of Counter + EmberCounterType type, + // Counter Info and value + EmberCounterInfo info) +{ + uint8_t buffer[64] = {0}; + strcpy((char*)buffer, COUNTER_STRINGS[type]); + uint8_t len = strlen(buffer); + buffer[len++] = " "; + + EmberNodeId destinationNodeId; + + if (emberCounterRequiresDestinationNodeId(type) && emberCounterRequiresPhyIndex(type)) { + destinationNodeId = ((EmberExtraCounterInfo *) (info.otherFields))->destinationNodeId; + } else if (emberCounterRequiresDestinationNodeId(type)) { + destinationNodeId = *((EmberNodeId*)info.otherFields); + } else { + destinationNodeId = 0xFFFF; + } + + memcpy(buffer + len, &destinationNodeId, sizeof(destinationNodeId)); + + nc_enqueue_event(sizeof(buffer), &buffer); +} + EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 5ac2ad92..2a6c4173 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -73,6 +73,171 @@ template_contribution: - name: zigbee_stack_callback priority: -9999 value: {callback_type: override_append_source_route, function_name: nc_zigbee_override_append_source_route} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_message, function_name: nc_incoming_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: message_sent, function_name: nc_message_sent} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: trust_center_join, function_name: nc_trust_center_join} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: mark_buffers, function_name: nc_mark_buffers} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: packet_handoff_incoming, function_name: nc_packet_handoff_incoming} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: packet_handoff_outgoing, function_name: nc_packet_handoff_outgoing} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_mfg_test_message, function_name: nc_incoming_mfg_test_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: stack_status, function_name: nc_stack_status} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: redirect_outgoing_message, function_name: nc_redirect_outgoing_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: energy_scan_result, function_name: nc_energy_scan_result} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: network_found, function_name: nc_network_found} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: scan_complete, function_name: nc_scan_complete} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: unused_pan_id_found, function_name: nc_unused_pan_id_found} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: child_join, function_name: nc_child_join} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: duty_cycle, function_name: nc_duty_cycle} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: remote_set_binding, function_name: nc_remote_set_binding} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: remote_delete_binding, function_name: nc_remote_delete_binding} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: poll_complete, function_name: nc_poll_complete} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: poll, function_name: nc_poll} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: debug, function_name: nc_debug} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_many_to_one_route_request, function_name: nc_incoming_many_to_one_route_request} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_route_error, function_name: nc_incoming_route_error} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_network_status, function_name: nc_incoming_network_status} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_route_record, function_name: nc_incoming_route_record} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: id_conflict, function_name: nc_id_conflict} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: mac_passthrough_message, function_name: nc_mac_passthrough_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: stack_token_changed, function_name: nc_stack_token_changed} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: timer, function_name: nc_timer} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: counter_rollover, function_name: nc_counter_rollover} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: raw_transmit_complete, function_name: nc_raw_transmit_complete} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: switch_network_key, function_name: nc_switch_network_key} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: zigbee_key_establishment, function_name: nc_zigbee_key_establishment} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: generate_cbke_keys, function_name: nc_generate_cbke_keys} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: calculate_smacs, function_name: nc_calculate_smacs} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: dsa_sign, function_name: nc_dsa_sign} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: dsa_verify, function_name: nc_dsa_verify} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: incoming_bootload_message, function_name: nc_incoming_bootload_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: bootload_transmit_complete, function_name: nc_bootload_transmit_complete} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: zll_network_found, function_name: nc_zll_network_found} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: zll_scan_complete, function_name: nc_zll_scan_complete} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: zll_address_assignment, function_name: nc_zll_address_assignment} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: zll_touch_link_target, function_name: nc_zll_touch_link_target} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: mac_filter_match_message, function_name: nc_mac_filter_match_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: d_gp_sent, function_name: nc_d_gp_sent} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: pan_id_conflict, function_name: nc_pan_id_conflict} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: orphan_notification, function_name: nc_orphan_notification} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: counter, function_name: nc_counter} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: mac_passthrough_filter, function_name: nc_mac_passthrough_filter} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: generate_cbke_keys_handler283k1, function_name: nc_generate_cbke_keys_handler283k1} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: calculate_smacs_handler283k1, function_name: nc_calculate_smacs_handler283k1} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: gpep_incoming_message, function_name: nc_gpep_incoming_message} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: rtos_idle, function_name: nc_rtos_idle} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: rtos_stack_wakeup_isr, function_name: nc_rtos_stack_wakeup_isr} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: radio_needs_calibrating, function_name: nc_radio_needs_calibrating} +- name: zigbee_stack_callback + priority: -9999 + value: {callback_type: scan_error, function_name: nc_scan_error} filter: - name: Wireless Technology From 379a7e6311160eb3083741ff25d578659039f038 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:22:46 -0400 Subject: [PATCH 23/34] Revert "[TEST] Log all known counters" This reverts commit c13f5f96e2c6f9562813a0010476398470b61c65. --- src/zigbee_ncp/app.c | 129 -------------------------- src/zigbee_ncp/zigbee_ncp.slcp | 165 --------------------------------- 2 files changed, 294 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 567967d9..45a9dda6 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -61,17 +61,6 @@ typedef struct ManualSourceRoute { ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE]; -typedef struct EnqueuedEvent { - bool sent; - uint8_t length; - uint8_t message[64]; -} EnqueuedEvent; - - -#define NC_MAX_ENQUEUED_EVENTS (8) -EnqueuedEvent nc_enqueued_events[NC_MAX_ENQUEUED_EVENTS]; - - ManualSourceRoute* get_manual_source_route(EmberNodeId destination) { uint8_t index = 0xFF; @@ -110,24 +99,6 @@ void emberAfMainInitCallback(void) for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { manual_source_routes[i].active = false; } - - for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { - nc_enqueued_events[i].sent = true; - } -} - -void emberAfMainTickCallback(void) -{ - for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { - EnqueuedEvent *event = &nc_enqueued_events[i]; - - if (event->sent) { - continue; - } - - emberAfPluginXncpSendCustomEzspMessage(event->length, event->message); - event->sent = true; - } } /** @brief Incoming packet filter callback @@ -222,106 +193,6 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, return; } -void nc_enqueue_event(uint8_t length, char* message) { - for (uint8_t i = 0; i < NC_MAX_ENQUEUED_EVENTS; i++) { - EnqueuedEvent *event = &nc_enqueued_events[i]; - - if (!event->sent) { - continue; - } - - event->sent = false; - event->length = length; - memcpy(event->message, message, length); - break; - } -} - - -void nc_incoming_message(void* first_arg, ...) { nc_enqueue_event(16, "incoming_message"); } -void nc_message_sent(void* first_arg, ...) { nc_enqueue_event(12, "message_sent"); } -void nc_trust_center_join(void* first_arg, ...) { nc_enqueue_event(17, "trust_center_join"); } -void nc_mark_buffers(void* first_arg, ...) {}//{ nc_enqueue_event(12, "mark_buffers"); } -void nc_packet_handoff_incoming(void* first_arg, ...) { nc_enqueue_event(23, "packet_handoff_incoming"); } -void nc_packet_handoff_outgoing(void* first_arg, ...) { nc_enqueue_event(23, "packet_handoff_outgoing"); } -void nc_incoming_mfg_test_message(void* first_arg, ...) { nc_enqueue_event(25, "incoming_mfg_test_message"); } -void nc_stack_status(void* first_arg, ...) { nc_enqueue_event(12, "stack_status"); } -void nc_redirect_outgoing_message(void* first_arg, ...) { nc_enqueue_event(25, "redirect_outgoing_message"); } -void nc_energy_scan_result(void* first_arg, ...) { nc_enqueue_event(18, "energy_scan_result"); } -void nc_network_found(void* first_arg, ...) { nc_enqueue_event(13, "network_found"); } -void nc_scan_complete(void* first_arg, ...) { nc_enqueue_event(13, "scan_complete"); } -void nc_unused_pan_id_found(void* first_arg, ...) { nc_enqueue_event(19, "unused_pan_id_found"); } -void nc_child_join(void* first_arg, ...) { nc_enqueue_event(10, "child_join"); } -void nc_duty_cycle(void* first_arg, ...) { nc_enqueue_event(10, "duty_cycle"); } -void nc_remote_set_binding(void* first_arg, ...) { nc_enqueue_event(18, "remote_set_binding"); } -void nc_remote_delete_binding(void* first_arg, ...) { nc_enqueue_event(21, "remote_delete_binding"); } -void nc_poll_complete(void* first_arg, ...) { nc_enqueue_event(13, "poll_complete"); } -void nc_poll(void* first_arg, ...) { nc_enqueue_event(4, "poll"); } -void nc_debug(void* first_arg, ...) { nc_enqueue_event(5, "debug"); } -void nc_incoming_many_to_one_route_request(void* first_arg, ...) { nc_enqueue_event(34, "incoming_many_to_one_route_request"); } -void nc_incoming_route_error(void* first_arg, ...) { nc_enqueue_event(20, "incoming_route_error"); } -void nc_incoming_network_status(void* first_arg, ...) { nc_enqueue_event(23, "incoming_network_status"); } -void nc_incoming_route_record(void* first_arg, ...) { nc_enqueue_event(21, "incoming_route_record"); } -void nc_id_conflict(void* first_arg, ...) { nc_enqueue_event(11, "id_conflict"); } -void nc_mac_passthrough_message(void* first_arg, ...) { nc_enqueue_event(23, "mac_passthrough_message"); } -void nc_stack_token_changed(void* first_arg, ...) { nc_enqueue_event(19, "stack_token_changed"); } -void nc_timer(void* first_arg, ...) { nc_enqueue_event(5, "timer"); } -void nc_counter_rollover(void* first_arg, ...) { nc_enqueue_event(16, "counter_rollover"); } -void nc_raw_transmit_complete(void* first_arg, ...) { nc_enqueue_event(21, "raw_transmit_complete"); } -void nc_switch_network_key(void* first_arg, ...) { nc_enqueue_event(18, "switch_network_key"); } -void nc_zigbee_key_establishment(void* first_arg, ...) { nc_enqueue_event(24, "zigbee_key_establishment"); } -void nc_generate_cbke_keys(void* first_arg, ...) { nc_enqueue_event(18, "generate_cbke_keys"); } -void nc_calculate_smacs(void* first_arg, ...) { nc_enqueue_event(15, "calculate_smacs"); } -void nc_dsa_sign(void* first_arg, ...) { nc_enqueue_event(8, "dsa_sign"); } -void nc_dsa_verify(void* first_arg, ...) { nc_enqueue_event(10, "dsa_verify"); } -void nc_incoming_bootload_message(void* first_arg, ...) { nc_enqueue_event(25, "incoming_bootload_message"); } -void nc_bootload_transmit_complete(void* first_arg, ...) { nc_enqueue_event(26, "bootload_transmit_complete"); } -void nc_zll_network_found(void* first_arg, ...) { nc_enqueue_event(17, "zll_network_found"); } -void nc_zll_scan_complete(void* first_arg, ...) { nc_enqueue_event(17, "zll_scan_complete"); } -void nc_zll_address_assignment(void* first_arg, ...) { nc_enqueue_event(22, "zll_address_assignment"); } -void nc_zll_touch_link_target(void* first_arg, ...) { nc_enqueue_event(21, "zll_touch_link_target"); } -void nc_mac_filter_match_message(void* first_arg, ...) { nc_enqueue_event(24, "mac_filter_match_message"); } -void nc_d_gp_sent(void* first_arg, ...) { nc_enqueue_event(9, "d_gp_sent"); } -void nc_pan_id_conflict(void* first_arg, ...) { nc_enqueue_event(15, "pan_id_conflict"); } -void nc_orphan_notification(void* first_arg, ...) { nc_enqueue_event(19, "orphan_notification"); } -void nc_counter(void* first_arg, ...) {}//{ nc_enqueue_event(7, "counter"); } -void nc_mac_passthrough_filter(void* first_arg, ...) { nc_enqueue_event(22, "mac_passthrough_filter"); } -void nc_generate_cbke_keys_handler283k1(void* first_arg, ...) { nc_enqueue_event(31, "generate_cbke_keys_handler283k1"); } -void nc_calculate_smacs_handler283k1(void* first_arg, ...) { nc_enqueue_event(28, "calculate_smacs_handler283k1"); } -void nc_gpep_incoming_message(void* first_arg, ...) { nc_enqueue_event(21, "gpep_incoming_message"); } -void nc_rtos_idle(void* first_arg, ...) { nc_enqueue_event(9, "rtos_idle"); } -void nc_rtos_stack_wakeup_isr(void* first_arg, ...) { nc_enqueue_event(21, "rtos_stack_wakeup_isr"); } -void nc_radio_needs_calibrating(void* first_arg, ...) { nc_enqueue_event(23, "radio_needs_calibrating"); } -void nc_scan_error(void* first_arg, ...) { nc_enqueue_event(10, "scan_error"); } - -const char * COUNTER_STRINGS[] = {EMBER_COUNTER_STRINGS}; - -void emberAfCounterCallback( - // Type of Counter - EmberCounterType type, - // Counter Info and value - EmberCounterInfo info) -{ - uint8_t buffer[64] = {0}; - strcpy((char*)buffer, COUNTER_STRINGS[type]); - uint8_t len = strlen(buffer); - buffer[len++] = " "; - - EmberNodeId destinationNodeId; - - if (emberCounterRequiresDestinationNodeId(type) && emberCounterRequiresPhyIndex(type)) { - destinationNodeId = ((EmberExtraCounterInfo *) (info.otherFields))->destinationNodeId; - } else if (emberCounterRequiresDestinationNodeId(type)) { - destinationNodeId = *((EmberNodeId*)info.otherFields); - } else { - destinationNodeId = 0xFFFF; - } - - memcpy(buffer + len, &destinationNodeId, sizeof(destinationNodeId)); - - nc_enqueue_event(sizeof(buffer), &buffer); -} - EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, diff --git a/src/zigbee_ncp/zigbee_ncp.slcp b/src/zigbee_ncp/zigbee_ncp.slcp index 2a6c4173..5ac2ad92 100644 --- a/src/zigbee_ncp/zigbee_ncp.slcp +++ b/src/zigbee_ncp/zigbee_ncp.slcp @@ -73,171 +73,6 @@ template_contribution: - name: zigbee_stack_callback priority: -9999 value: {callback_type: override_append_source_route, function_name: nc_zigbee_override_append_source_route} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_message, function_name: nc_incoming_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: message_sent, function_name: nc_message_sent} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: trust_center_join, function_name: nc_trust_center_join} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: mark_buffers, function_name: nc_mark_buffers} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: packet_handoff_incoming, function_name: nc_packet_handoff_incoming} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: packet_handoff_outgoing, function_name: nc_packet_handoff_outgoing} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_mfg_test_message, function_name: nc_incoming_mfg_test_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: stack_status, function_name: nc_stack_status} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: redirect_outgoing_message, function_name: nc_redirect_outgoing_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: energy_scan_result, function_name: nc_energy_scan_result} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: network_found, function_name: nc_network_found} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: scan_complete, function_name: nc_scan_complete} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: unused_pan_id_found, function_name: nc_unused_pan_id_found} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: child_join, function_name: nc_child_join} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: duty_cycle, function_name: nc_duty_cycle} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: remote_set_binding, function_name: nc_remote_set_binding} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: remote_delete_binding, function_name: nc_remote_delete_binding} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: poll_complete, function_name: nc_poll_complete} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: poll, function_name: nc_poll} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: debug, function_name: nc_debug} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_many_to_one_route_request, function_name: nc_incoming_many_to_one_route_request} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_route_error, function_name: nc_incoming_route_error} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_network_status, function_name: nc_incoming_network_status} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_route_record, function_name: nc_incoming_route_record} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: id_conflict, function_name: nc_id_conflict} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: mac_passthrough_message, function_name: nc_mac_passthrough_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: stack_token_changed, function_name: nc_stack_token_changed} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: timer, function_name: nc_timer} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: counter_rollover, function_name: nc_counter_rollover} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: raw_transmit_complete, function_name: nc_raw_transmit_complete} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: switch_network_key, function_name: nc_switch_network_key} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: zigbee_key_establishment, function_name: nc_zigbee_key_establishment} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: generate_cbke_keys, function_name: nc_generate_cbke_keys} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: calculate_smacs, function_name: nc_calculate_smacs} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: dsa_sign, function_name: nc_dsa_sign} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: dsa_verify, function_name: nc_dsa_verify} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: incoming_bootload_message, function_name: nc_incoming_bootload_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: bootload_transmit_complete, function_name: nc_bootload_transmit_complete} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: zll_network_found, function_name: nc_zll_network_found} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: zll_scan_complete, function_name: nc_zll_scan_complete} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: zll_address_assignment, function_name: nc_zll_address_assignment} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: zll_touch_link_target, function_name: nc_zll_touch_link_target} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: mac_filter_match_message, function_name: nc_mac_filter_match_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: d_gp_sent, function_name: nc_d_gp_sent} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: pan_id_conflict, function_name: nc_pan_id_conflict} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: orphan_notification, function_name: nc_orphan_notification} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: counter, function_name: nc_counter} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: mac_passthrough_filter, function_name: nc_mac_passthrough_filter} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: generate_cbke_keys_handler283k1, function_name: nc_generate_cbke_keys_handler283k1} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: calculate_smacs_handler283k1, function_name: nc_calculate_smacs_handler283k1} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: gpep_incoming_message, function_name: nc_gpep_incoming_message} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: rtos_idle, function_name: nc_rtos_idle} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: rtos_stack_wakeup_isr, function_name: nc_rtos_stack_wakeup_isr} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: radio_needs_calibrating, function_name: nc_radio_needs_calibrating} -- name: zigbee_stack_callback - priority: -9999 - value: {callback_type: scan_error, function_name: nc_scan_error} filter: - name: Wireless Technology From 2e6253483b23180fa4fc7257e5789772d45a662e Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:48:55 -0400 Subject: [PATCH 24/34] Fix compile-time warning about missing XNCP functions --- src/zigbee_ncp/app.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 45a9dda6..f273aac0 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -23,6 +23,7 @@ #include "mac-flat-header.h" #include "stack/include/message.h" +#include "app/ncp/plugin/xncp/xncp.h" #include "config/xncp_config.h" From f76f3fc4ee436281b415398c20ed3b94fdf08fba Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:59:08 -0400 Subject: [PATCH 25/34] Actually use `get_manual_source_route` --- src/zigbee_ncp/app.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index f273aac0..c93e7a83 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -163,22 +163,13 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, EmberMessageBuffer *header, bool *consumed) { - uint8_t index = 0xFF; - - for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { - if (manual_source_routes[i].active && (manual_source_routes[i].destination == destination)) { - index = i; - break; - } - } + ManualSourceRoute *route = get_manual_source_route(destination); - if (index == 0xFF) { + if (route == NULL) { *consumed = false; return; } - ManualSourceRoute *route = &manual_source_routes[index]; - uint8_t relay_index = 0; *consumed = true; From 8c0e818e3911d8a2af41c73e9f65c67d98877a7c Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:02:10 -0400 Subject: [PATCH 26/34] Migrate `app.c` to `app.cpp` --- src/zigbee_ncp/{app.c => app.cpp} | 32 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) rename src/zigbee_ncp/{app.c => app.cpp} (96%) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.cpp similarity index 96% rename from src/zigbee_ncp/app.c rename to src/zigbee_ncp/app.cpp index c93e7a83..9702a959 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.cpp @@ -15,17 +15,19 @@ * ******************************************************************************/ -#include PLATFORM_HEADER -#include "ember.h" -#include "ember-types.h" -#include "ezsp-enum.h" -#include "random.h" -#include "mac-flat-header.h" - -#include "stack/include/message.h" -#include "app/ncp/plugin/xncp/xncp.h" - -#include "config/xncp_config.h" +extern "C" { + #include PLATFORM_HEADER + #include "ember.h" + #include "ember-types.h" + #include "ezsp-enum.h" + #include "random.h" + #include "mac-flat-header.h" + + #include "stack/include/message.h" + #include "app/ncp/plugin/xncp/xncp.h" + + #include "config/xncp_config.h" +} #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) @@ -87,6 +89,7 @@ ManualSourceRoute* get_manual_source_route(EmberNodeId destination) * * Application framework equivalent of ::emberRadioNeedsCalibratingHandler */ +extern "C" void emberAfRadioNeedsCalibratingCallback(void) { sl_mac_calibrate_current_channel(); @@ -95,6 +98,7 @@ void emberAfRadioNeedsCalibratingCallback(void) /** @brief Init * Application init function */ +extern "C" void emberAfMainInitCallback(void) { for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { @@ -107,6 +111,7 @@ void emberAfMainInitCallback(void) * Filters and/or mutates incoming packets. Currently used only for wildcard multicast * group membership. */ +extern "C" EmberPacketAction sli_zigbee_af_packet_handoff_incoming_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, @@ -150,6 +155,7 @@ EmberPacketAction sli_zigbee_af_packet_handoff_incoming_callback(EmberZigbeePack * * Filters and/or mutates outgoing packets. */ +extern "C" EmberPacketAction sli_zigbee_af_packet_handoff_outgoing_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, @@ -159,6 +165,7 @@ EmberPacketAction sli_zigbee_af_packet_handoff_outgoing_callback(EmberZigbeePack } +extern "C" void nc_zigbee_override_append_source_route(EmberNodeId destination, EmberMessageBuffer *header, bool *consumed) @@ -186,6 +193,7 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, } +extern "C" EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, uint8_t *replyPayloadLength, @@ -282,7 +290,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, } uint8_t token_id = messagePayload[0]; - char *override_value; + const char *override_value; switch (token_id) { case EZSP_MFG_STRING: { From 38855b0ed6d136eb82f3b4ea979b8ae7d99a3997 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:17:12 -0400 Subject: [PATCH 27/34] Revert "Migrate `app.c` to `app.cpp`" This reverts commit 591bd077061214b7b606956166d211d8a2eb53db. --- src/zigbee_ncp/{app.cpp => app.c} | 32 ++++++++++++------------------- 1 file changed, 12 insertions(+), 20 deletions(-) rename src/zigbee_ncp/{app.cpp => app.c} (96%) diff --git a/src/zigbee_ncp/app.cpp b/src/zigbee_ncp/app.c similarity index 96% rename from src/zigbee_ncp/app.cpp rename to src/zigbee_ncp/app.c index 9702a959..c93e7a83 100644 --- a/src/zigbee_ncp/app.cpp +++ b/src/zigbee_ncp/app.c @@ -15,19 +15,17 @@ * ******************************************************************************/ -extern "C" { - #include PLATFORM_HEADER - #include "ember.h" - #include "ember-types.h" - #include "ezsp-enum.h" - #include "random.h" - #include "mac-flat-header.h" - - #include "stack/include/message.h" - #include "app/ncp/plugin/xncp/xncp.h" - - #include "config/xncp_config.h" -} +#include PLATFORM_HEADER +#include "ember.h" +#include "ember-types.h" +#include "ezsp-enum.h" +#include "random.h" +#include "mac-flat-header.h" + +#include "stack/include/message.h" +#include "app/ncp/plugin/xncp/xncp.h" + +#include "config/xncp_config.h" #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) @@ -89,7 +87,6 @@ ManualSourceRoute* get_manual_source_route(EmberNodeId destination) * * Application framework equivalent of ::emberRadioNeedsCalibratingHandler */ -extern "C" void emberAfRadioNeedsCalibratingCallback(void) { sl_mac_calibrate_current_channel(); @@ -98,7 +95,6 @@ void emberAfRadioNeedsCalibratingCallback(void) /** @brief Init * Application init function */ -extern "C" void emberAfMainInitCallback(void) { for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) { @@ -111,7 +107,6 @@ void emberAfMainInitCallback(void) * Filters and/or mutates incoming packets. Currently used only for wildcard multicast * group membership. */ -extern "C" EmberPacketAction sli_zigbee_af_packet_handoff_incoming_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, @@ -155,7 +150,6 @@ EmberPacketAction sli_zigbee_af_packet_handoff_incoming_callback(EmberZigbeePack * * Filters and/or mutates outgoing packets. */ -extern "C" EmberPacketAction sli_zigbee_af_packet_handoff_outgoing_callback(EmberZigbeePacketType packetType, EmberMessageBuffer packetBuffer, uint8_t index, @@ -165,7 +159,6 @@ EmberPacketAction sli_zigbee_af_packet_handoff_outgoing_callback(EmberZigbeePack } -extern "C" void nc_zigbee_override_append_source_route(EmberNodeId destination, EmberMessageBuffer *header, bool *consumed) @@ -193,7 +186,6 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, } -extern "C" EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, uint8_t *messagePayload, uint8_t *replyPayloadLength, @@ -290,7 +282,7 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, } uint8_t token_id = messagePayload[0]; - const char *override_value; + char *override_value; switch (token_id) { case EZSP_MFG_STRING: { From 3a37cce327820bfdece33dc693adb603445f2123 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 5 Jun 2024 18:12:04 -0400 Subject: [PATCH 28/34] Implement a firmware build string command --- src/zigbee_ncp/app.c | 14 ++++++++++++++ src/zigbee_ncp/config/xncp_config.h | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index c93e7a83..df722e51 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -33,10 +33,12 @@ #define FEATURE_MEMBER_OF_ALL_GROUPS (0b00000000000000000000000000000001) #define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) #define FEATURE_MFG_TOKEN_OVERRIDES (0b00000000000000000000000000000100) +#define FEATURE_BUILD_STRING (0b00000000000000000000000000001000) #define SUPPORTED_FEATURES ( \ FEATURE_MEMBER_OF_ALL_GROUPS \ | FEATURE_MANUAL_SOURCE_ROUTE \ | FEATURE_MFG_TOKEN_OVERRIDES \ + | FEATURE_BUILD_STRING \ ) @@ -44,10 +46,12 @@ typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, XNCP_CMD_SET_SOURCE_ROUTE_REQ = 0x0001, XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ = 0x0002, + XNCP_CMD_GET_BUILD_STRING_REQ = 0x0003, XNCP_CMD_GET_SUPPORTED_FEATURES_RSP = XNCP_CMD_GET_SUPPORTED_FEATURES_REQ | 0x8000, XNCP_CMD_SET_SOURCE_ROUTE_RSP = XNCP_CMD_SET_SOURCE_ROUTE_REQ | 0x8000, XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_RSP = XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ | 0x8000, + XNCP_CMD_GET_BUILD_STRING_RSP = XNCP_CMD_GET_BUILD_STRING_REQ | 0x8000, XNCP_CMD_UNKNOWN = 0xFFFF } XNCP_COMMAND; @@ -308,6 +312,16 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; } + case XNCP_CMD_GET_BUILD_STRING_REQ: { + rsp_command_id = XNCP_CMD_GET_BUILD_STRING_RSP; + rsp_status = EMBER_SUCCESS; + + uint8_t value_length = strlen(XNCP_BUILD_STRING); + memcpy(replyPayload + *replyPayloadLength, XNCP_BUILD_STRING, value_length); + *replyPayloadLength += value_length; + break; + } + default: { rsp_status = EMBER_NOT_FOUND; break; diff --git a/src/zigbee_ncp/config/xncp_config.h b/src/zigbee_ncp/config/xncp_config.h index 190b5ea9..fd85149b 100644 --- a/src/zigbee_ncp/config/xncp_config.h +++ b/src/zigbee_ncp/config/xncp_config.h @@ -13,4 +13,8 @@ #define XNCP_MFG_MANUF_NAME ("") #define XNCP_MFG_BOARD_NAME ("") + +// Specify a build string that can be read by the host, augmenting its version info +#define XNCP_BUILD_STRING ("") + #endif /* CONFIG_XNCP_CONFIG_H_ */ From 777bf4106b0728bf94496ef5dde7404fbecd26c2 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:12:19 -0400 Subject: [PATCH 29/34] Correctly set the relay index and handle empty source routes --- src/zigbee_ncp/app.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index df722e51..734c1083 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -174,16 +174,22 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, return; } - uint8_t relay_index = 0; - *consumed = true; + + // Empty source routes are not permitted + if (route->num_relays == 0) { + return; + } + + uint8_t relay_index = route->num_relays - 1; + route->active = false; // Disable the route after a single use emberAppendToLinkedBuffers(*header, &route->num_relays, 1); emberAppendToLinkedBuffers(*header, &relay_index, 1); for (uint8_t i = 0; i < route->num_relays; i++) { - emberAppendToLinkedBuffers(*header, (uint8_t*)&route->relays[i], 2); + emberAppendToLinkedBuffers(*header, (uint8_t*)&route->relays[route->num_relays - i - 1], 2); } return; From a6b3c46f5c2d819886ecf4bd5817fa7524d94119 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:18:24 -0400 Subject: [PATCH 30/34] Insert a fake entry into the routing table to source route a single hop --- src/zigbee_ncp/app.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 734c1083..6e33ab9d 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -41,6 +41,8 @@ | FEATURE_BUILD_STRING \ ) +extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; + typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, @@ -178,6 +180,14 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, // Empty source routes are not permitted if (route->num_relays == 0) { + // Add a fake route to the routing table to help EmberZNet just send the packet + sli_zigbee_route_table_entry_t *route_table_entry = &sli_zigbee_route_table[0]; + route_table_entry->destination = route->destination; + route_table_entry->nextHop = route->destination; + route_table_entry->status = 0; // ACTIVE=0 + route_table_entry->cost = 0; + route_table_entry->networkIndex = 0; + return; } From e0f78ca8f291ebfe37d6a625bc5865251a393744 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:29:57 -0400 Subject: [PATCH 31/34] Pick routing table entry at random when forcing a direct route --- src/zigbee_ncp/app.c | 48 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index 6e33ab9d..ee337788 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -42,6 +42,18 @@ ) extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[]; +extern uint8_t sli_zigbee_route_table_size; + +/* + * Indicates whether this entry is active (0), being + * discovered (1), unused (3), or validating (4). + */ +typedef enum { + EMBER_ROUTE_ACTIVE = 0, + EMBER_ROUTE_BEING_DISCOVERED = 1, + EMBER_ROUTE_UNUSED = 3, + EMBER_ROUTE_VALIDATING = 4 +} EmberRouteStatus; typedef enum { @@ -56,7 +68,7 @@ typedef enum { XNCP_CMD_GET_BUILD_STRING_RSP = XNCP_CMD_GET_BUILD_STRING_REQ | 0x8000, XNCP_CMD_UNKNOWN = 0xFFFF -} XNCP_COMMAND; +} XncpCommand; typedef struct ManualSourceRoute { bool active; @@ -86,6 +98,34 @@ ManualSourceRoute* get_manual_source_route(EmberNodeId destination) return &manual_source_routes[index]; } + +sli_zigbee_route_table_entry_t* find_free_routing_table_entry(EmberNodeId destination) { + uint8_t index = 0xFF; + + sli_zigbee_route_table_entry_t *route_table_entry = NULL; + + for (uint8_t i = 0; i < sli_zigbee_route_table_size; i++) { + route_table_entry = &sli_zigbee_route_table[i]; + + if (route_table_entry->destination == destination) { + // Perfer a route to the destination, if one exists + return route_table_entry; + } else if (route_table_entry->status == EMBER_ROUTE_UNUSED) { + // Otherwise, keep track of the most recent unused route + index = i; + continue; + } + } + + // If we have no free route slots, we still need to insert somewhere. Pick at random. + if (index == 0xFF) { + index = emberGetPseudoRandomNumber() % sli_zigbee_route_table_size; + } + + return &sli_zigbee_route_table[index]; +} + + //---------------------- // Implemented Callbacks @@ -178,13 +218,13 @@ void nc_zigbee_override_append_source_route(EmberNodeId destination, *consumed = true; - // Empty source routes are not permitted + // Empty source routes are invalid according to the spec if (route->num_relays == 0) { // Add a fake route to the routing table to help EmberZNet just send the packet - sli_zigbee_route_table_entry_t *route_table_entry = &sli_zigbee_route_table[0]; + sli_zigbee_route_table_entry_t *route_table_entry = find_free_routing_table_entry(route->destination); route_table_entry->destination = route->destination; route_table_entry->nextHop = route->destination; - route_table_entry->status = 0; // ACTIVE=0 + route_table_entry->status = EMBER_ROUTE_ACTIVE; route_table_entry->cost = 0; route_table_entry->networkIndex = 0; From 146acea87e9bcbb8f58c1210be1164fef3c838b6 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:26:06 -0400 Subject: [PATCH 32/34] Expose the current date in templates --- tools/build_project.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/build_project.py b/tools/build_project.py index bf9b044a..ec8c865f 100755 --- a/tools/build_project.py +++ b/tools/build_project.py @@ -17,6 +17,7 @@ import contextlib import subprocess import multiprocessing +from datetime import datetime, timezone from ruamel.yaml import YAML @@ -402,6 +403,7 @@ def main(): value_template_env = { "git_repo_hash": get_git_commit_id(repo=pathlib.Path(__file__).parent.parent), "manifest_name": args.manifest.stem, + "now": datetime.now(timezone.utc), } # Actually search for C defines within config From a2f13ad9e17028973773bde63e2357d63abbb964 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:50:29 -0400 Subject: [PATCH 33/34] Add a new XNCP command to return the firmware flow control settings --- src/zigbee_ncp/app.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index ee337788..e1fdc0a2 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -24,8 +24,10 @@ #include "stack/include/message.h" #include "app/ncp/plugin/xncp/xncp.h" +#include "em_usart.h" #include "config/xncp_config.h" +#include "config/sl_iostream_usart_vcom_config.h" #define BUILD_UINT16(low, high) (((uint16_t)(low) << 0) | ((uint16_t)(high) << 8)) @@ -56,16 +58,23 @@ typedef enum { } EmberRouteStatus; +typedef enum { + XNCP_FLOW_CONTROL_TYPE_SOFTWARE = 0x00, + XNCP_FLOW_CONTROL_TYPE_HARDWARE = 0x01, +} XncpFlowControlType; + typedef enum { XNCP_CMD_GET_SUPPORTED_FEATURES_REQ = 0x0000, XNCP_CMD_SET_SOURCE_ROUTE_REQ = 0x0001, XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ = 0x0002, XNCP_CMD_GET_BUILD_STRING_REQ = 0x0003, + XNCP_CMD_GET_FLOW_CONTROL_TYPE_REQ = 0x0004, XNCP_CMD_GET_SUPPORTED_FEATURES_RSP = XNCP_CMD_GET_SUPPORTED_FEATURES_REQ | 0x8000, XNCP_CMD_SET_SOURCE_ROUTE_RSP = XNCP_CMD_SET_SOURCE_ROUTE_REQ | 0x8000, XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_RSP = XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ | 0x8000, XNCP_CMD_GET_BUILD_STRING_RSP = XNCP_CMD_GET_BUILD_STRING_REQ | 0x8000, + XNCP_CMD_GET_FLOW_CONTROL_TYPE_RSP = XNCP_CMD_GET_FLOW_CONTROL_TYPE_REQ | 0x8000, XNCP_CMD_UNKNOWN = 0xFFFF } XncpCommand; @@ -378,6 +387,33 @@ EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength, break; } + case XNCP_CMD_GET_FLOW_CONTROL_TYPE_REQ: { + rsp_command_id = XNCP_CMD_GET_FLOW_CONTROL_TYPE_RSP; + rsp_status = EMBER_SUCCESS; + + XncpFlowControlType flow_control_type; + + switch (SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE) { + case usartHwFlowControlCtsAndRts: { + flow_control_type = XNCP_FLOW_CONTROL_TYPE_HARDWARE; + break; + } + + case usartHwFlowControlNone: { + flow_control_type = XNCP_FLOW_CONTROL_TYPE_SOFTWARE; + break; + } + + default: { + flow_control_type = XNCP_FLOW_CONTROL_TYPE_SOFTWARE; + break; + } + } + + replyPayload[(*replyPayloadLength)++] = (uint8_t)(flow_control_type & 0xFF); + break; + } + default: { rsp_status = EMBER_NOT_FOUND; break; From fb7d9fd853a90a7e930bda90855fecc6de4502e6 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:56:15 -0400 Subject: [PATCH 34/34] Add `FEATURE_FLOW_CONTROL_TYPE` to the feature bitmap --- src/zigbee_ncp/app.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/zigbee_ncp/app.c b/src/zigbee_ncp/app.c index e1fdc0a2..6725bfc6 100644 --- a/src/zigbee_ncp/app.c +++ b/src/zigbee_ncp/app.c @@ -36,11 +36,14 @@ #define FEATURE_MANUAL_SOURCE_ROUTE (0b00000000000000000000000000000010) #define FEATURE_MFG_TOKEN_OVERRIDES (0b00000000000000000000000000000100) #define FEATURE_BUILD_STRING (0b00000000000000000000000000001000) +#define FEATURE_FLOW_CONTROL_TYPE (0b00000000000000000000000000010000) + #define SUPPORTED_FEATURES ( \ FEATURE_MEMBER_OF_ALL_GROUPS \ | FEATURE_MANUAL_SOURCE_ROUTE \ | FEATURE_MFG_TOKEN_OVERRIDES \ | FEATURE_BUILD_STRING \ + | FEATURE_FLOW_CONTROL_TYPE \ ) extern sli_zigbee_route_table_entry_t sli_zigbee_route_table[];