Skip to content

Commit a198369

Browse files
committed
GH-43: Credential Set
UIC-3222: Credential Set on Credential Operation Type UIC-3222: Set Credential (delete) improvement UIC-3222: Credential SET also look in desired values UIC-3222: Fix delete operation on Credential SET UIC-3222: Allow extra bytes when testing set/get commands Bug-SiliconLabs: UIC-3222 Bug-GitHub: #43 Signed-off-by: Philippe Coval <[email protected]>
1 parent a3c8925 commit a198369

File tree

5 files changed

+464
-57
lines changed

5 files changed

+464
-57
lines changed

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

-1
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,6 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_MODIFIER_NOD
996996
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_OPERATION_TYPE,
997997
((COMMAND_CLASS_USER_CREDENTIAL << 8) | 0x1F))
998998

999-
1000999
/////////////////////////////////////////////////
10011000
// Z-Wave Plus Info CC
10021001
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_ZWAVEPLUS_INFO_VERSION,

applications/zpc/components/zpc_attribute_store/include/command_class_types/zwave_command_class_user_credential_types.h

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ typedef uint16_t user_credential_slot_t;
5151
///> Operation type. uint8_t
5252
typedef uint8_t user_credential_operation_type_t;
5353

54+
///> Operation type. uint8_t
55+
typedef uint8_t user_credential_operation_type_t;
56+
5457
#ifdef __cplusplus
5558
extern "C" {
5659
#endif

applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ static const std::vector<attribute_schema_t> attribute_schema = {
402402
{ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_READ_BACK, "User Credential Credential Read Back Flag", ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_SLOT, U8_STORAGE_TYPE},
403403
{ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_MODIFIER_TYPE, "User Credential Credential Modifier type", ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_SLOT, U8_STORAGE_TYPE},
404404
{ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_MODIFIER_NODE_ID, "User Credential Credential Node ID", ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_SLOT, U16_STORAGE_TYPE},
405+
{ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_OPERATION_TYPE, "User Credential Credential Operation Type", ATTRIBUTE_COMMAND_CLASS_USER_CREDENTIAL_CREDENTIAL_SLOT, U8_STORAGE_TYPE},
405406

406407
/////////////////////////////////////////////////////////////////////
407408
// Z-Wave Plus Info Command Class attributes

applications/zpc/components/zwave_command_classes/src/zwave_command_class_user_credential.cpp

+252-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ struct user_field_data {
7777
uint8_t shift_right = 0;
7878
};
7979

80+
// Used to create command frame
81+
struct attribute_command_data {
82+
// Attribute type that will be fetched from the base_node
83+
attribute_store_type_t attribute_type;
84+
// Attribute value state (reported, desired,...)
85+
attribute_store_node_value_state_t attribute_state;
86+
// If not ATTRIBUTE_STORE_INVALID_NODE, the function will not fetch attribute_type
87+
// but will use this node directly
88+
attribute_store_node_t node = ATTRIBUTE_STORE_INVALID_NODE;
89+
};
90+
8091
/////////////////////////////////////////////////////////////////////////////
8192
// Type Helpers
8293
/////////////////////////////////////////////////////////////////////////////
@@ -311,6 +322,154 @@ sl_status_t
311322
return status;
312323
}
313324

325+
/**
326+
* @brief Create a command frame (SET or GET) based on the attribute store
327+
*
328+
* @param command Command to send (will be in frame[1], e.g USER_SET)
329+
* @param command_data Attributes that will be in the frame (in order of appearance in the frame)
330+
* @param base_node If not specified otherwise will fetch the attributes that are under this node
331+
* @param frame Frame object from the callback
332+
* @param frame_length Frame size from the callback
333+
*
334+
* @return sl_status_t SL_STATUS_OK if everything was fine
335+
*/
336+
sl_status_t create_command_frame(uint8_t command,
337+
std::vector<attribute_command_data> command_data,
338+
attribute_store_node_t base_node,
339+
uint8_t *frame,
340+
uint16_t *frame_length)
341+
{
342+
frame[0] = COMMAND_CLASS_USER_CREDENTIAL;
343+
frame[1] = command;
344+
345+
uint16_t current_index = 2;
346+
347+
for (auto &attribute_info: command_data) {
348+
auto node_storage_type
349+
= attribute_store_get_storage_type(attribute_info.attribute_type);
350+
auto attribute_description
351+
= attribute_store_get_type_name(attribute_info.attribute_type);
352+
353+
attribute_store_node_t node;
354+
if (attribute_info.node == ATTRIBUTE_STORE_INVALID_NODE) {
355+
node = attribute_store_get_first_child_by_type(
356+
base_node,
357+
attribute_info.attribute_type);
358+
} else {
359+
node = attribute_info.node;
360+
}
361+
362+
if (node == ATTRIBUTE_STORE_INVALID_NODE) {
363+
sl_log_critical(LOG_TAG,
364+
"Can't find node for Attribute %s",
365+
attribute_description);
366+
return SL_STATUS_FAIL;
367+
}
368+
369+
sl_status_t status;
370+
switch (node_storage_type) {
371+
case U8_STORAGE_TYPE: {
372+
uint8_t uint8_value;
373+
status = attribute_store_read_value(node,
374+
attribute_info.attribute_state,
375+
&uint8_value,
376+
sizeof(uint8_value));
377+
frame[current_index++] = uint8_value;
378+
} break;
379+
case U16_STORAGE_TYPE: {
380+
uint16_t uint16_value;
381+
status = attribute_store_read_value(node,
382+
attribute_info.attribute_state,
383+
&uint16_value,
384+
sizeof(uint16_value));
385+
auto exploded_uint16 = explode_uint16(uint16_value);
386+
frame[current_index++] = exploded_uint16.msb;
387+
frame[current_index++] = exploded_uint16.lsb;
388+
} break;
389+
// Variable length field
390+
case BYTE_ARRAY_STORAGE_TYPE: {
391+
// First get the length
392+
auto credential_length_node = attribute_store_get_node_parent(node);
393+
394+
uint8_t credential_data_length = 0;
395+
status = attribute_store_read_value(
396+
credential_length_node,
397+
attribute_info.attribute_state,
398+
&credential_data_length,
399+
sizeof(credential_data_length));
400+
401+
if (status != SL_STATUS_OK) {
402+
sl_log_error(
403+
LOG_TAG,
404+
"Missing BYTE_ARRAY_STORAGE_TYPE length for attribute %s",
405+
attribute_description);
406+
return SL_STATUS_NOT_SUPPORTED;
407+
}
408+
409+
frame[current_index++] = credential_data_length;
410+
411+
// Then the data
412+
std::vector<uint8_t> credential_data;
413+
credential_data.resize(credential_data_length);
414+
status = attribute_store_read_value(node,
415+
attribute_info.attribute_state,
416+
credential_data.data(),
417+
credential_data_length);
418+
419+
for (const uint8_t &cred: credential_data) {
420+
frame[current_index++] = cred;
421+
}
422+
423+
} break;
424+
425+
case C_STRING_STORAGE_TYPE: {
426+
char c_user_name[MAX_CHAR_SIZE];
427+
// Unfortunately attribute_store_get_string is not exposed so we need to do this
428+
switch (attribute_info.attribute_state) {
429+
case DESIRED_OR_REPORTED_ATTRIBUTE:
430+
status
431+
= attribute_store_get_desired_else_reported_string(node,
432+
c_user_name,
433+
MAX_CHAR_SIZE);
434+
break;
435+
case DESIRED_ATTRIBUTE:
436+
status = attribute_store_get_desired_string(node,
437+
c_user_name,
438+
MAX_CHAR_SIZE);
439+
break;
440+
case REPORTED_ATTRIBUTE:
441+
status = attribute_store_get_reported_string(node,
442+
c_user_name,
443+
MAX_CHAR_SIZE);
444+
break;
445+
}
446+
447+
std::string user_name = c_user_name;
448+
for (const char &c: user_name) {
449+
frame[current_index++] = c;
450+
}
451+
452+
} break;
453+
default:
454+
sl_log_critical(LOG_TAG,
455+
"Not supported type for %s",
456+
attribute_description);
457+
return SL_STATUS_FAIL;
458+
}
459+
460+
if (status != SL_STATUS_OK) {
461+
sl_log_error(LOG_TAG,
462+
"Can't get value of Attribute %s",
463+
attribute_description);
464+
return SL_STATUS_NOT_SUPPORTED;
465+
}
466+
}
467+
468+
*frame_length = current_index;
469+
470+
return SL_STATUS_OK;
471+
}
472+
314473
/////////////////////////////////////////////////////////////////////////////
315474
// Version & Attribute Creation
316475
/////////////////////////////////////////////////////////////////////////////
@@ -623,7 +782,7 @@ sl_status_t zwave_command_class_user_credential_all_user_checksum_handle_report(
623782
}
624783

625784
/////////////////////////////////////////////////////////////////////////////
626-
// Credential Get/Report
785+
// Credential Set/Get/Report
627786
/////////////////////////////////////////////////////////////////////////////
628787

629788
// Start credential interview process by starting with 0,0
@@ -669,6 +828,93 @@ void trigger_get_credential(attribute_store_node_t user_unique_id_node,
669828
}
670829
}
671830

831+
static sl_status_t zwave_command_class_user_credential_credential_set(
832+
attribute_store_node_t credential_operation_type_node,
833+
uint8_t *frame,
834+
uint16_t *frame_length)
835+
{
836+
// Identifiers nodes
837+
attribute_store_node_t credential_slot_node
838+
= attribute_store_get_first_parent_with_type(credential_operation_type_node,
839+
ATTRIBUTE(CREDENTIAL_SLOT));
840+
attribute_store_node_t credential_type_node
841+
= attribute_store_get_first_parent_with_type(credential_slot_node,
842+
ATTRIBUTE(CREDENTIAL_TYPE));
843+
attribute_store_node_t user_unique_id_node
844+
= attribute_store_get_first_parent_with_type(credential_type_node,
845+
ATTRIBUTE(USER_UNIQUE_ID));
846+
// Since CREDENTIAL_DATA is not directly under credential_slot_node we need to fetch it first
847+
attribute_store_node_t credential_length_node
848+
= attribute_store_get_first_child_by_type(
849+
credential_slot_node,
850+
ATTRIBUTE(CREDENTIAL_DATA_LENGTH));
851+
attribute_store_node_t credential_node
852+
= attribute_store_get_first_child_by_type(credential_length_node,
853+
ATTRIBUTE(CREDENTIAL_DATA));
854+
// Get operation type
855+
user_credential_operation_type_t operation_type = 0;
856+
sl_status_t status
857+
= attribute_store_get_desired(credential_operation_type_node,
858+
&operation_type,
859+
sizeof(operation_type));
860+
861+
if (status != SL_STATUS_OK) {
862+
sl_log_error(LOG_TAG,
863+
"Can't get operation type. Not sending CREDENTIAL_SET.");
864+
return SL_STATUS_NOT_SUPPORTED;
865+
}
866+
867+
sl_log_debug(LOG_TAG,
868+
"Credential SET for Credential Slot %d, Credential Type %d, "
869+
"User %d (operation type : %d)",
870+
static_cast<user_credential_slot_t>(
871+
attribute_store_get_reported_number(credential_slot_node)),
872+
static_cast<user_credential_type_t>(
873+
attribute_store_get_reported_number(credential_type_node)),
874+
static_cast<user_credential_user_unique_id_t>(
875+
attribute_store_get_reported_number(user_unique_id_node)),
876+
operation_type);
877+
878+
// Since the data is not linear we provide the node directly
879+
std::vector<attribute_command_data> set_data
880+
= {{ATTRIBUTE(USER_UNIQUE_ID),
881+
DESIRED_OR_REPORTED_ATTRIBUTE,
882+
user_unique_id_node},
883+
{ATTRIBUTE(CREDENTIAL_TYPE),
884+
DESIRED_OR_REPORTED_ATTRIBUTE,
885+
credential_type_node},
886+
{ATTRIBUTE(CREDENTIAL_SLOT),
887+
DESIRED_OR_REPORTED_ATTRIBUTE,
888+
credential_slot_node},
889+
{ATTRIBUTE(CREDENTIAL_OPERATION_TYPE),
890+
DESIRED_ATTRIBUTE,
891+
credential_operation_type_node}};
892+
893+
// Add the credential data if we are not trying to remove a credential
894+
if (operation_type != USER_CREDENTIAL_OPERATION_TYPE_DELETE) {
895+
set_data.push_back({ATTRIBUTE(CREDENTIAL_DATA),
896+
DESIRED_OR_REPORTED_ATTRIBUTE,
897+
credential_node});
898+
}
899+
status = create_command_frame(CREDENTIAL_SET,
900+
set_data,
901+
credential_slot_node,
902+
frame,
903+
frame_length);
904+
905+
if (status != SL_STATUS_OK) {
906+
sl_log_error(LOG_TAG, "Can't create Credential SET frame");
907+
return SL_STATUS_NOT_SUPPORTED;
908+
}
909+
// If we are deleting the credential we are setting 0x00 as a credential length
910+
if (operation_type == USER_CREDENTIAL_OPERATION_TYPE_DELETE) {
911+
frame[*frame_length] = 0x00;
912+
*frame_length += 1;
913+
}
914+
915+
return SL_STATUS_OK;
916+
}
917+
672918
/**
673919
* @brief Credential GET
674920
*
@@ -1328,6 +1574,11 @@ sl_status_t zwave_command_class_user_credential_init()
13281574
NULL,
13291575
&zwave_command_class_user_credential_credential_get);
13301576

1577+
attribute_resolver_register_rule(
1578+
ATTRIBUTE(CREDENTIAL_OPERATION_TYPE),
1579+
&zwave_command_class_user_credential_credential_set,
1580+
NULL);
1581+
13311582
// https://github.com/Z-Wave-Alliance/AWG/pull/124#discussion_r1484473752
13321583
// Discussion about delaying the user interview process after the inclusion
13331584

0 commit comments

Comments
 (0)