Skip to content

Commit 6eedeb0

Browse files
silabs-aydoganerzr
authored andcommitted
store: SWPROT-9246: "NLS Node List Get/Report" implementation (#53)
Merge in UIC/uic from task/ayersoz/SWPROT-9246-nls-node-list-get-report-implementation to z-wave/main [Philippe Coval] That change was split libs2 changes are in previous commits Last-update: 2025-03-05 Relate-to: #50 Forwarded: #53 Signed-off-by: Philippe Coval <philippe.coval@silabs.com>
1 parent ebc984e commit 6eedeb0

File tree

6 files changed

+504
-16
lines changed

6 files changed

+504
-16
lines changed

applications/zpc/components/zpc_attribute_store/include/zwave_utils.h

+9
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,15 @@ sl_status_t zwave_store_inclusion_protocol(zwave_node_id_t node_id,
169169
sl_status_t zwave_get_node_granted_keys(zwave_node_id_t node_id,
170170
zwave_keyset_t *keys);
171171

172+
/**
173+
* @brief Set the node granted keys object
174+
*
175+
* @param node_id
176+
* @param keys
177+
*/
178+
sl_status_t zwave_set_node_granted_keys(zwave_node_id_t node_id,
179+
zwave_keyset_t *keyset);
180+
172181
/**
173182
* @brief Verify whether a node/endpoint supports a Command Class
174183
* using the attribute Store.

applications/zpc/components/zpc_attribute_store/src/zwave_utils.c

+19
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,25 @@ sl_status_t zwave_get_node_granted_keys(zwave_node_id_t node_id,
263263
sizeof(zwave_keyset_t));
264264
}
265265

266+
// Write the granted keys for a node from the attribute store
267+
sl_status_t zwave_set_node_granted_keys(zwave_node_id_t node_id,
268+
zwave_keyset_t *keyset)
269+
{
270+
// Find the node from the attribute store:
271+
unid_t unid;
272+
zwave_unid_from_node_id(node_id, unid);
273+
274+
// Find out attribute store node based on the UNID
275+
attribute_store_node_t node_id_node
276+
= attribute_store_network_helper_create_node_id_node(unid);
277+
278+
// Write down the granted keys for that node
279+
return attribute_store_set_child_reported(node_id_node,
280+
ATTRIBUTE_GRANTED_SECURITY_KEYS,
281+
keyset,
282+
sizeof(zwave_keyset_t));
283+
}
284+
266285
bool zwave_node_want_supervision_frame(zwave_node_id_t node_id,
267286
zwave_endpoint_id_t endpoint_id)
268287
{

applications/zpc/components/zpc_attribute_store/test/zwave_utils_test.c

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ int suiteTearDown(int num_failures)
3939
/// Called before each and every test
4040
void setUp() {}
4141

42+
void test_set_node_granted_keys_happy_case()
43+
{
44+
zwave_node_id_t test_node_id = 119;
45+
attribute_store_node_t test_node_id_node = 1;
46+
zwave_keyset_t keyset
47+
= ZWAVE_CONTROLLER_S2_AUTHENTICATED_KEY | ZWAVE_CONTROLLER_S2_ACCESS_KEY;
48+
49+
attribute_store_network_helper_create_node_id_node_ExpectAndReturn(
50+
0,
51+
test_node_id_node);
52+
attribute_store_network_helper_create_node_id_node_IgnoreArg_node_unid();
53+
54+
attribute_store_set_child_reported_ExpectAndReturn(
55+
test_node_id_node,
56+
ATTRIBUTE_GRANTED_SECURITY_KEYS,
57+
&keyset,
58+
sizeof(keyset),
59+
SL_STATUS_OK);
60+
61+
TEST_ASSERT_EQUAL(SL_STATUS_OK,
62+
zwave_set_node_granted_keys(test_node_id, &keyset));
63+
}
64+
4265
void test_get_nls_state_reported_happy_case()
4366
{
4467
zwave_node_id_t test_node_id = 119;

applications/zpc/components/zwave/zwave_transports/s2/src/zwave_s2_transport.c

+175-15
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
#define S2_NONCE_REPORT_MOS_SOS_INDEX 3
5858
#define S2_NONCE_REPORT_MOS_SOS_MASK 0x3
5959

60+
// Number of nodes per byte in NLS state node mask
61+
#define NLS_ENABLED_NODES_PER_BYTE 8
62+
6063
struct S2 *s2_ctx;
6164

6265
typedef enum { SINGLECAST, MULTICAST } zwave_s2_current_transmission_type_t;
@@ -84,6 +87,17 @@ static s2_transport_session_state_t state = {};
8487
static uint8_t secure_nif[ZWAVE_MAX_FRAME_SIZE];
8588
static uint8_t secure_nif_length;
8689

90+
// NLS context
91+
typedef struct s2_node_nls_context {
92+
zwave_nodemask_t node_list; // bitmask containing NLS enabled nodes in the network
93+
uint16_t node_list_length; // length of the list in bytes (is not equal to the number of nodes in the network)
94+
zwave_node_id_t next_sent_node_id; // node ID of the NLS enabled node to be sent next
95+
uint16_t nls_enabled_node_cnt; // total number of NLS enabled nodes in the network
96+
uint16_t nls_enabled_node_sent_cnt; // number of NLS enabled nodes already sent to the joining node
97+
} s2_node_nls_context_t;
98+
99+
static s2_node_nls_context_t node_nls_context = {0};
100+
87101
static uint8_t
88102
encapsulation_to_class(zwave_controller_encapsulation_scheme_t encap)
89103
{
@@ -414,18 +428,17 @@ uint8_t S2_send_frame_multi(struct S2 *ctxt,
414428
0);
415429
}
416430

417-
418431
void S2_notify_nls_state_report(node_t srcNode, uint8_t class_id, bool nls_capability, bool nls_state)
419432
{
420433
(void)class_id;
421434

422-
sl_log_debug(LOG_TAG, "NLS state report received for node %d, capability : %d, state: %d", srcNode, (bool)nls_capability, (bool)nls_state);
435+
sl_log_debug(LOG_TAG, "NLS state report received for node %d, capability : %d, state: %d", srcNode, nls_capability, nls_state);
423436

424437
if (zwave_store_nls_support((zwave_node_id_t)srcNode,
425-
(bool)nls_capability,
438+
nls_capability,
426439
REPORTED_ATTRIBUTE)
427440
|| zwave_store_nls_state((zwave_node_id_t)srcNode,
428-
(bool)nls_state,
441+
nls_state,
429442
REPORTED_ATTRIBUTE)) {
430443
sl_log_error(LOG_TAG, "Error setting NLS attributes");
431444
return;
@@ -443,24 +456,171 @@ void S2_save_nls_state(void)
443456
// not relevant for ZPC
444457
}
445458

446-
int8_t S2_get_nls_node_list(node_t srcNode, bool request, bool *is_last_node, uint16_t *node_id, uint8_t *granted_keys, bool *nls_state)
459+
sl_status_t compute_next_nls_enabled_node(void)
447460
{
448-
// to be implemented later on
449-
(void)srcNode;
450-
(void)request;
451-
return 0;
461+
for (uint16_t i = (node_nls_context.next_sent_node_id + 1);
462+
i <= (node_nls_context.node_list_length * NLS_ENABLED_NODES_PER_BYTE);
463+
i++) {
464+
uint8_t nls_enabled = ZW_IS_NODE_IN_MASK(i, node_nls_context.node_list);
465+
if (nls_enabled) {
466+
node_nls_context.next_sent_node_id = i;
467+
return SL_STATUS_OK;
468+
}
469+
}
470+
471+
return SL_STATUS_NOT_FOUND;
452472
}
453473

454-
int8_t S2_notify_nls_node_list_report(node_t srcNode, uint16_t id_of_node, uint8_t keys_node_bitmask, bool nls_state)
474+
static uint16_t compute_nls_enabled_node_cnt(void)
455475
{
456-
// to be implemented later on
457-
(void)srcNode;
458-
(void)id_of_node;
459-
(void)keys_node_bitmask;
460-
(void)nls_state;
476+
for (uint16_t i = 1;
477+
i <= (node_nls_context.node_list_length * NLS_ENABLED_NODES_PER_BYTE);
478+
i++) {
479+
uint8_t nls_enabled = ZW_IS_NODE_IN_MASK(i, node_nls_context.node_list);
480+
if (nls_enabled) {
481+
node_nls_context.nls_enabled_node_cnt++;
482+
}
483+
}
484+
485+
return node_nls_context.nls_enabled_node_cnt;
486+
}
487+
488+
/*
489+
This command is received by the trust center (SIS). We can retrieve the list from the controller when the
490+
joining node requests it for the first node (request flag is set to 0) and then send the cached
491+
information for the remaining nodes.
492+
493+
This function is not supposed to send a frame. It just fills the necessary fields of the report frame of the
494+
command in question and let libS2 send it.
495+
496+
If there is no NLS enabled nodes or last NLS enabled node is sent, `nls_state` is not set to true so libS2
497+
should not send the report frame.
498+
*/
499+
int8_t S2_get_nls_node_list(node_t srcNode,
500+
bool request,
501+
bool *is_last_node,
502+
uint16_t *node_id,
503+
uint8_t *granted_keys,
504+
bool *nls_state)
505+
{
506+
sl_status_t status = SL_STATUS_OK;
507+
*is_last_node = false;
508+
*node_id = 0;
509+
*granted_keys = 0;
510+
*nls_state = false;
511+
512+
sl_log_debug(LOG_TAG,
513+
"NLS Node List Get received from node %d, request: %d",
514+
srcNode,
515+
request);
516+
517+
if (request == false) {
518+
memset(&node_nls_context, 0, sizeof(s2_node_nls_context_t));
519+
status = zwapi_get_nls_nodes(&node_nls_context.node_list_length,
520+
node_nls_context.node_list);
521+
if (status != SL_STATUS_OK) {
522+
sl_log_error(LOG_TAG, "Error getting NLS nodes, %d", status);
523+
return -1;
524+
}
525+
compute_nls_enabled_node_cnt();
526+
}
527+
528+
if (node_nls_context.nls_enabled_node_cnt == 0) {
529+
sl_log_warning(LOG_TAG, "No NLS enabled nodes found in the controller NVM");
530+
return -1;
531+
}
532+
533+
if (node_nls_context.nls_enabled_node_sent_cnt
534+
== node_nls_context.nls_enabled_node_cnt) {
535+
sl_log_warning(LOG_TAG, "All NLS enabled nodes are already sent");
536+
return -1;
537+
}
538+
539+
if (node_nls_context.nls_enabled_node_sent_cnt
540+
== node_nls_context.nls_enabled_node_cnt - 1) {
541+
*is_last_node = true;
542+
}
543+
544+
status = compute_next_nls_enabled_node();
545+
if (status != SL_STATUS_OK) {
546+
sl_log_debug(LOG_TAG, "No NLS enabled nodes found in the controller NVM");
547+
return -1;
548+
}
549+
550+
zwave_keyset_t keyset = {0};
551+
status
552+
= zwave_get_node_granted_keys(node_nls_context.next_sent_node_id, &keyset);
553+
if (status != SL_STATUS_OK) {
554+
sl_log_error(LOG_TAG,
555+
"Error getting granted keys of the node %d",
556+
node_nls_context.next_sent_node_id);
557+
return -1;
558+
}
559+
*granted_keys = (uint8_t)keyset;
560+
561+
node_nls_context.nls_enabled_node_sent_cnt++;
562+
563+
*node_id = node_nls_context.next_sent_node_id;
564+
*nls_state = true;
565+
461566
return 0;
462567
}
463568

569+
/*
570+
This command is received by the joining node (secondary controller).
571+
*/
572+
int8_t S2_notify_nls_node_list_report(node_t srcNode,
573+
uint16_t id_of_node,
574+
uint8_t keys_node_bitmask,
575+
bool nls_state)
576+
{
577+
sl_status_t status = SL_STATUS_OK;
578+
579+
sl_log_debug(LOG_TAG,
580+
"NLS Node List Report received from the node %d, NLS state: %d",
581+
srcNode,
582+
nls_state);
583+
584+
if (nls_state) {
585+
status = zwapi_enable_node_nls(id_of_node);
586+
if (SL_STATUS_OK != status) {
587+
sl_log_error(
588+
LOG_TAG,
589+
"Error saving NLS state of the node %d in the controller NVM",
590+
id_of_node);
591+
return -1;
592+
}
593+
594+
if (zwave_store_nls_support((zwave_node_id_t)id_of_node,
595+
true,
596+
REPORTED_ATTRIBUTE)
597+
|| zwave_store_nls_state((zwave_node_id_t)id_of_node,
598+
true,
599+
REPORTED_ATTRIBUTE)) {
600+
sl_log_error(LOG_TAG,
601+
"Error setting NLS attributes of the node %d",
602+
id_of_node);
603+
return -1;
604+
}
605+
606+
status = zwave_set_node_granted_keys((zwave_node_id_t)id_of_node,
607+
&keys_node_bitmask);
608+
if (SL_STATUS_OK != status) {
609+
sl_log_error(LOG_TAG,
610+
"Error setting granted keys of the node %d",
611+
id_of_node);
612+
return -1;
613+
}
614+
615+
sl_log_debug(LOG_TAG, "Saved NLS state of the node %d", id_of_node);
616+
return 0;
617+
}
618+
619+
// Consider the case as error where NLS state is sent as 0. The protocol
620+
// should send only NLS enabled nodes.
621+
return -1;
622+
}
623+
464624
/************************* Our interface functions ****************************/
465625

466626
sl_status_t

applications/zpc/components/zwave/zwave_transports/s2/test/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ target_add_unittest(
6161
zwave_api_mock
6262
uic_contiki_stub
6363
zwave_tx_mock
64+
zpc_attribute_store_test_helper
6465
zwave_network_management_mock)
6566

6667
# ####################### S2 Protocol CC Encryption test ##################################

0 commit comments

Comments
 (0)