@@ -1007,6 +1007,11 @@ user_credential_user_unique_id_t get_user_id(const uint8_t *event_parameters)
10071007{
10081008 return get_uint16_value (event_parameters, INDEX_USER_UNIQUE_ID);
10091009}
1010+ user_credential_modifier_type_t get_credential_modifier_type (const uint8_t *event_parameters)
1011+ {
1012+ // TODO : Update this with the new specification where CREDENTIAL_DATA doesn't exists anymore
1013+ return event_parameters[8 ];
1014+ }
10101015
10111016attribute_store_node_t
10121017 get_credential_type_node (attribute_store_node_t endpoint_node,
@@ -1441,6 +1446,50 @@ void on_notification_event(attribute_store_node_t endpoint_node,
14411446 credential_slot,
14421447 user_id);
14431448 } break ;
1449+ // Credential unchanged
1450+ case 0x2E : {
1451+ sl_log_debug (LOG_TAG, " Notification : Credential Unchanged" );
1452+ if (!notification_handler::credential::is_report_size_conform (
1453+ event_parameters_length)) {
1454+ return ;
1455+ }
1456+
1457+ // Used in logs
1458+ user_credential_type_t credential_type
1459+ = notification_handler::credential::get_credential_type (
1460+ event_parameters);
1461+ user_credential_slot_t credential_slot
1462+ = notification_handler::credential::get_credential_slot (
1463+ event_parameters);
1464+ user_credential_user_unique_id_t user_id
1465+ = notification_handler::credential::get_user_id (event_parameters);
1466+
1467+ // Type and slot
1468+ auto credential_slot_node = get_credential_slot_node_by_type ();
1469+ if (credential_slot_node == ATTRIBUTE_STORE_INVALID_NODE) {
1470+ return ;
1471+ }
1472+
1473+ // If user doesn't exists in the device we try to remove it also from our side
1474+ user_credential_modifier_type_t modifier_type
1475+ = notification_handler::credential::get_credential_modifier_type (event_parameters);
1476+ if (modifier_type == CREDENTIAL_REPORT_DNE) {
1477+ attribute_store_delete_node (credential_slot_node);
1478+ } else {
1479+ sl_log_info (LOG_TAG,
1480+ " Credential Unchanged, clearing desired values. For Type "
1481+ " %d, Slot %d (User %d)" ,
1482+ credential_type,
1483+ credential_slot,
1484+ user_id);
1485+
1486+ attribute_store_undefine_desired (credential_slot_node);
1487+ attribute_store_undefine_desired (
1488+ attribute_store_get_node_child_by_type (credential_slot_node,
1489+ ATTRIBUTE (CREDENTIAL_DATA),
1490+ 0 ));
1491+ }
1492+ } break ;
14441493 default :
14451494 break ;
14461495 }
@@ -2129,6 +2178,19 @@ sl_status_t zwave_command_class_user_credential_credential_handle_report(
21292178 return SL_STATUS_NOT_SUPPORTED;
21302179 }
21312180
2181+ // Remove node if it doesn't exist anymore on the end device
2182+ if (frame_data[INDEX_CREDENTIAL_MODIFIER_TYPE] == CREDENTIAL_REPORT_DNE) {
2183+ sl_log_info (
2184+ LOG_TAG,
2185+ " Credential Node %d (credential type %d, user %d) doesn't exist "
2186+ " anymore, removing it" ,
2187+ credential_slot,
2188+ credential_type,
2189+ user_id);
2190+ attribute_store_delete_node (credential_slot_node);
2191+ return SL_STATUS_OK;
2192+ }
2193+
21322194 // Update credential slot node & type
21332195 attribute_store_set_reported (credential_type_node,
21342196 &credential_type,
@@ -2202,6 +2264,123 @@ sl_status_t zwave_command_class_user_credential_credential_handle_report(
22022264 return SL_STATUS_OK;
22032265}
22042266
2267+ sl_status_t zwave_command_class_user_credential_credential_set_error_handle_report (
2268+ const zwave_controller_connection_info_t *connection_info,
2269+ const uint8_t *frame_data,
2270+ uint16_t frame_length)
2271+ {
2272+ if (frame_length < 13 ) {
2273+ sl_log_warning (LOG_TAG,
2274+ " CREDENTIAL_SET_ERROR_REPORT frame length is not valid" );
2275+ return SL_STATUS_NOT_SUPPORTED;
2276+ }
2277+
2278+ // We don't need the rest of the frame, we just ensure that the attribute store is valid
2279+ uint8_t error_code = frame_data[2 ];
2280+ user_credential_user_unique_id_t user_id = get_uint16_value (frame_data, 3 );
2281+ user_credential_type_t credential_type = frame_data[5 ];
2282+ user_credential_slot_t credential_slot = get_uint16_value (frame_data, 6 );
2283+
2284+
2285+ attribute_store_node_t endpoint_node
2286+ = zwave_command_class_get_endpoint_node (connection_info);
2287+ attribute_store_node_t credential_type_node;
2288+ attribute_store_node_t credential_slot_node;
2289+
2290+ auto remove_credential_slot_if_possible = [&](attribute_store_node_t credential_slot_node) {
2291+ if (attribute_store_node_exists (credential_slot_node)) {
2292+ sl_log_debug (LOG_TAG,
2293+ " Removing credential slot : user %d, "
2294+ " credential type %d, credential slot %d" ,
2295+ user_id,
2296+ credential_type,
2297+ credential_slot);
2298+ attribute_store_delete_node (credential_slot_node);
2299+ } else {
2300+ sl_log_debug (LOG_TAG,
2301+ " No credential slot found for user %d, credential type "
2302+ " %d, credential slot %d" ,
2303+ user_id,
2304+ credential_type,
2305+ credential_slot);
2306+ }
2307+ };
2308+ switch (error_code) {
2309+ // Credential Add Rejected Location Occupied : 0x00
2310+ // If attempting to add a credential where a credential of that Credential Type at that Credential Slot already exists, and the new credential data differs
2311+ case CREDENTIAL_SET_ERROR_REPORT_CREDENTIALADDREJECTEDLOCATIONOCCUPIED:
2312+ sl_log_error (LOG_TAG,
2313+ " Credential data rejected as it already exists : user %d, "
2314+ " credential type %d, credential slot %d" ,
2315+ user_id,
2316+ credential_type,
2317+ credential_slot);
2318+ // Try to find the node in the store
2319+ get_credential_type_node (endpoint_node, user_id, credential_type, DESIRED_ATTRIBUTE, credential_type_node);
2320+ if (!attribute_store_node_exists (credential_type_node)) {
2321+ get_credential_type_node (endpoint_node, user_id, credential_type, REPORTED_ATTRIBUTE, credential_type_node);
2322+ }
2323+
2324+ get_credential_slot_node (credential_type_node, credential_slot, DESIRED_ATTRIBUTE, credential_slot_node);
2325+
2326+ remove_credential_slot_if_possible (credential_slot_node);
2327+ break ;
2328+ // Credential Modify Rejected Location Empty : 0x01
2329+ case CREDENTIAL_SET_ERROR_REPORT_CREDENTIALMODIFYREJECTEDLOCATIONEMPTY:
2330+ sl_log_error (LOG_TAG,
2331+ " Credential data cannot be modified as it does not exists : user %d, "
2332+ " credential type %d, credential slot %d" ,
2333+ user_id,
2334+ credential_type,
2335+ credential_slot);
2336+
2337+ // Try to find the node in the store
2338+ get_credential_type_node (endpoint_node, user_id, credential_type, DESIRED_ATTRIBUTE, credential_type_node);
2339+ if (!attribute_store_node_exists (credential_type_node)) {
2340+ get_credential_type_node (endpoint_node, user_id, credential_type, REPORTED_ATTRIBUTE, credential_type_node);
2341+ }
2342+
2343+ if (!attribute_store_node_exists (credential_type_node)) {
2344+ sl_log_debug (LOG_TAG,
2345+ " No credential type found for user %d, credential type %d" ,
2346+ user_id,
2347+ credential_type);
2348+ return SL_STATUS_OK;
2349+ }
2350+
2351+ get_credential_slot_node (credential_type_node, credential_slot, DESIRED_ATTRIBUTE, credential_slot_node);
2352+ if (!attribute_store_node_exists (credential_slot_node)) {
2353+ get_credential_slot_node (credential_type_node, credential_slot, REPORTED_ATTRIBUTE, credential_slot_node);
2354+ }
2355+
2356+ remove_credential_slot_if_possible (credential_slot_node);
2357+ break ;
2358+ // Duplicate Credential : 0x02
2359+ case CREDENTIAL_SET_ERROR_REPORT_DUPLICATECREDENTIAL:
2360+ // Do nothing, the credential GET will clean up for us
2361+ sl_log_warning (LOG_TAG,
2362+ " Duplicate Credential for user %d, credential type %d, "
2363+ " credential slot %d" ,
2364+ user_id,
2365+ credential_type,
2366+ credential_slot);
2367+ break ;
2368+ // Manufacturer Security Rules : 0x03
2369+ case CREDENTIAL_SET_ERROR_REPORT_MANUFACTURERSECURITYRULES:
2370+ // Do nothing, the credential GET will clean up for us
2371+ sl_log_warning (
2372+ LOG_TAG,
2373+ " Credential data rejected as it doesn't respect manufacturer "
2374+ " security rules : user %d, credential type %d, "
2375+ " credential slot %d" ,
2376+ user_id,
2377+ credential_type,
2378+ credential_slot);
2379+ break ;
2380+ }
2381+
2382+ return SL_STATUS_OK;
2383+ }
22052384// ///////////////////////////////////////////////////////////////////////////
22062385// User Set/Get/Report/Set Error Report
22072386// ///////////////////////////////////////////////////////////////////////////
@@ -3212,6 +3391,11 @@ sl_status_t zwave_command_class_user_credential_control_handler(
32123391 connection_info,
32133392 frame_data,
32143393 frame_length);
3394+ case CREDENTIAL_SET_ERROR_REPORT:
3395+ return zwave_command_class_user_credential_credential_set_error_handle_report (
3396+ connection_info,
3397+ frame_data,
3398+ frame_length);
32153399 case USER_CAPABILITIES_REPORT:
32163400 return zwave_command_class_user_credential_user_capabilities_handle_report (
32173401 connection_info,
0 commit comments