Skip to content

Commit

Permalink
Merge branch 'refs/heads/puddly/packet-filter-multicast-extension' in…
Browse files Browse the repository at this point in the history
…to tjj/test
  • Loading branch information
TheJulianJES committed May 29, 2024
2 parents 133a422 + 6657ab2 commit 0440391
Show file tree
Hide file tree
Showing 5 changed files with 349 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/ncp-uart-hw/.cproject

Large diffs are not rendered by default.

243 changes: 243 additions & 0 deletions src/ncp-uart-hw/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,47 @@

#include PLATFORM_HEADER
#include "ember.h"
#include "ember-types.h"
#include "ezsp-enum.h"
#include "random.h"

#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 {
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_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_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;
uint8_t num_relays;
uint16_t relays[EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT];
} ManualSourceRoute;

ManualSourceRoute manual_source_routes[XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE];

//----------------------
// Implemented Callbacks
Expand All @@ -35,4 +76,206 @@ void emberAfRadioNeedsCalibratingCallback(void)
*/
void emberAfMainInitCallback(void)
{
for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) {
manual_source_routes[i].active = false;
}
}

/** @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_DATA) && (*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 = BUILD_UINT16(packetData[1], packetData[2]);
tableEntry->networkIndex = 0;
}
}

return EMBER_ACCEPT_PACKET;
}


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;
}
}

if (index == 0xFF) {
*consumed = false;
return;
}

ManualSourceRoute *route = &manual_source_routes[index];

uint8_t relay_index = 0;

*consumed = true;
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);
}

return;
}


EmberStatus emberAfPluginXncpIncomingCustomFrameCallback(uint8_t messageLength,
uint8_t *messagePayload,
uint8_t *replyPayloadLength,
uint8_t *replyPayload) {
uint8_t rsp_status = EMBER_SUCCESS;
uint16_t rsp_command_id = XNCP_CMD_UNKNOWN;

if (messageLength < 3) {
rsp_status = EMBER_BAD_ARGUMENT;

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

switch (req_command_id) {
case XNCP_CMD_GET_SUPPORTED_FEATURES_REQ: {
rsp_command_id = XNCP_CMD_GET_SUPPORTED_FEATURES_RSP;
rsp_status = EMBER_SUCCESS;

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_REQ: {
rsp_command_id = XNCP_CMD_SET_SOURCE_ROUTE_RSP;
rsp_status = EMBER_SUCCESS;

if (messageLength % 2 != 0) {
rsp_status = EMBER_BAD_ARGUMENT;
break;
}

uint8_t num_relays = messageLength / 2;

if (num_relays > EMBER_MAX_SOURCE_ROUTE_RELAY_COUNT + 1) {
rsp_status = EMBER_BAD_ARGUMENT;
break;
}

// 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[0], messagePayload[1]);

for (uint8_t i = 0; i < XNCP_MANUAL_SOURCE_ROUTE_TABLE_SIZE; i++) {
ManualSourceRoute *route = &manual_source_routes[i];

if (route->active == false) {
insertion_index = i;
} else if (route->destination == node_id) {
insertion_index = i;
break;
}
}

ManualSourceRoute *route = &manual_source_routes[insertion_index];

for (uint8_t i = 0; i < num_relays; i++) {
uint16_t relay = BUILD_UINT16(messagePayload[2 + 2 * i + 0], messagePayload[2 + 2 * i + 1]);
route->relays[i] = relay;
}

route->destination = node_id;
route->num_relays = num_relays;
route->active = true;

break;
}

case XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_REQ: {
rsp_command_id = XNCP_CMD_GET_MFG_TOKEN_OVERRIDE_RSP;
rsp_status = EMBER_SUCCESS;

if (messageLength != 1) {
rsp_status = EMBER_BAD_ARGUMENT;
break;
}

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 value_length = strlen(override_value);
memcpy(replyPayload + *replyPayloadLength, override_value, value_length);
*replyPayloadLength += value_length;
break;
}

default: {
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;
}
78 changes: 78 additions & 0 deletions src/ncp-uart-hw/config/packet-handoff-config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/***************************************************************************//**
* @brief Zigbee Packet Handoff component configuration header.
*\n*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/

// <<< Use Configuration Wizard in Context Menu >>>

// <h>Zigbee Packet Handoff configuration

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ALL_PACKETS> Handoff All Packets
// <i> Default: TRUE
// <i> Allow all packets
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ALL_PACKETS 1

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_RAW_MAC> Handoff Raw Mac
// <i> Default: FALSE
// <i> Allow raw mac
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_RAW_MAC 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_MAC_COMMAND> Handoff Mac Commands
// <i> Default: FALSE
// <i> Allow mac command
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_MAC_COMMAND 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_NETWORK_DATA> Handoff Network Data
// <i> Default: FALSE
// <i> Allow network data
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_NETWORK_DATA 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_NETWORK_COMMAND> Handoff Network Commands
// <i> Default: FALSE
// <i> Allow network command
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_NETWORK_COMMAND 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_APS_DATA> Handoff APS Data
// <i> Default: FALSE
// <i> Allow aps data
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_APS_DATA 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_APS_COMMAND> Handoff APS Commands
// <i> Default: FALSE
// <i> Allow aps command
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_APS_COMMAND 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ZDO> Handoff ZDO Commands
// <i> Default: FALSE
// <i> Allow zdo
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ZDO 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ZCL> Handoff ZCL Commands
// <i> Default: FALSE
// <i> Allow zcl
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_ZCL 0

// <q EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_BEACON> Handoff Beacons
// <i> Default: FALSE
// <i> Allow beacon
#define EMBER_AF_PLUGIN_PACKET_HANDOFF_ALLOW_BEACON 0

// <o PACKET_HANDOFF_BUFFER_SIZE> Packet Handoff Buffer Size <128-512>
// <i> Default: 256
// <i> Handoff buffer size
#define PACKET_HANDOFF_BUFFER_SIZE 256

// </h>

// <<< end of configuration section >>>
16 changes: 16 additions & 0 deletions src/ncp-uart-hw/config/xncp_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#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 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_MFG_MANUF_NAME ("")
#define XNCP_MFG_BOARD_NAME ("")

#endif /* CONFIG_XNCP_CONFIG_H_ */
6 changes: 6 additions & 0 deletions src/ncp-uart-hw/ncp-uart-hw.slcp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,20 @@ component:
- {id: zigbee_gp}
- {id: zigbee_mfglib}
- {id: zigbee_ncp_uart_hardware}
- {id: zigbee_packet_handoff}
- {id: zigbee_pro_stack}
- {id: zigbee_r22_support}
- {id: zigbee_security_link_keys}
- {id: zigbee_source_route}
- {id: zigbee_token_interface}
- {id: zigbee_xncp}
- {id: zigbee_zll}
define:
- {name: EMBER_CUSTOM_MAC_FILTER_TABLE_SIZE, value: '15'}
template_contribution:
- name: zigbee_stack_callback
priority: -9999
value: {callback_type: override_append_source_route, function_name: nc_zigbee_override_append_source_route}
configuration:
- {name: SL_BOARD_ENABLE_VCOM, value: '1'}
- {name: SL_IOSTREAM_USART_VCOM_FLOW_CONTROL_TYPE, value: usartHwFlowControlCtsAndRts}
Expand Down

0 comments on commit 0440391

Please sign in to comment.