@@ -1007,6 +1007,11 @@ user_credential_user_unique_id_t get_user_id(const uint8_t *event_parameters)
1007
1007
{
1008
1008
return get_uint16_value (event_parameters, INDEX_USER_UNIQUE_ID);
1009
1009
}
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
+ }
1010
1015
1011
1016
attribute_store_node_t
1012
1017
get_credential_type_node (attribute_store_node_t endpoint_node,
@@ -1441,6 +1446,50 @@ void on_notification_event(attribute_store_node_t endpoint_node,
1441
1446
credential_slot,
1442
1447
user_id);
1443
1448
} 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 ;
1444
1493
default :
1445
1494
break ;
1446
1495
}
@@ -2129,6 +2178,19 @@ sl_status_t zwave_command_class_user_credential_credential_handle_report(
2129
2178
return SL_STATUS_NOT_SUPPORTED;
2130
2179
}
2131
2180
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
+
2132
2194
// Update credential slot node & type
2133
2195
attribute_store_set_reported (credential_type_node,
2134
2196
&credential_type,
@@ -2202,6 +2264,123 @@ sl_status_t zwave_command_class_user_credential_credential_handle_report(
2202
2264
return SL_STATUS_OK;
2203
2265
}
2204
2266
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
+ }
2205
2384
// ///////////////////////////////////////////////////////////////////////////
2206
2385
// User Set/Get/Report/Set Error Report
2207
2386
// ///////////////////////////////////////////////////////////////////////////
@@ -3212,6 +3391,11 @@ sl_status_t zwave_command_class_user_credential_control_handler(
3212
3391
connection_info,
3213
3392
frame_data,
3214
3393
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);
3215
3399
case USER_CAPABILITIES_REPORT:
3216
3400
return zwave_command_class_user_credential_user_capabilities_handle_report (
3217
3401
connection_info,
0 commit comments