mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-05-11 13:08:13 +02:00
Refactor Validity Driver Code for Improved Readability and Maintainability
- Introduced helper functions in validity_tls.c to encapsulate command sending and response handling for TLS flash read and handshake processes, reducing code duplication and enhancing clarity. - Reorganized the validity_verify.c file by creating dedicated functions for each step in the verification process, including capture building, matching, and result retrieval, to streamline the state machine logic. - Enhanced the delete and clear operations in validity_verify.c by modularizing the code into smaller functions, improving readability and maintainability. - Updated the list operations in validity_verify.c to utilize helper functions for fetching user storage and user details, simplifying the state management. - Overall, these changes aim to improve the structure of the code, making it easier to follow and modify in the future.
This commit is contained in:
parent
1971829873
commit
65277fce2f
6 changed files with 3446 additions and 2501 deletions
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -376,297 +376,404 @@ fwext_upload_data_free (gpointer data)
|
|||
g_free (ud);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fwext_send_write_hw_reg (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
guint8 cmd[10];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_hw_reg32 (FWEXT_HW_REG_WRITE_ADDR,
|
||||
FWEXT_HW_REG_WRITE_VALUE,
|
||||
cmd, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_write_hw_reg (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_HW_REG failed: status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_read_hw_reg (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
guint8 cmd[6];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_read_hw_reg32 (FWEXT_HW_REG_READ_ADDR,
|
||||
cmd, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_read_hw_reg (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"READ_HW_REG failed: status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
|
||||
guint32 value;
|
||||
|
||||
if (!validity_fwext_parse_read_hw_reg32 (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&value))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"READ_HW_REG response too short"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != 2 && value != 3)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected HW register value: %u "
|
||||
"(expected 2 or 3)", value));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("FWEXT: HW register 0x%08x = %u (OK)", FWEXT_HW_REG_READ_ADDR, value);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_load_file (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
|
||||
GError *error = NULL;
|
||||
GUsbDevice *usb_dev = fpi_device_get_usb_device (dev);
|
||||
guint16 vid = g_usb_device_get_vid (usb_dev);
|
||||
guint16 pid = g_usb_device_get_pid (usb_dev);
|
||||
|
||||
ud->vid = vid;
|
||||
ud->pid = pid;
|
||||
|
||||
g_autofree gchar *fw_path = validity_fwext_find_firmware (vid, pid, &error);
|
||||
|
||||
if (fw_path == NULL)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_fwext_load_file (fw_path, &ud->fwext, &error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ud->write_offset = 0;
|
||||
fp_info ("FWEXT: Loaded firmware file, %zu bytes to write",
|
||||
ud->fwext.payload_len);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_db_write_enable (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
gsize dbe_len;
|
||||
const guint8 *dbe = validity_fwext_get_db_write_enable (ud->vid,
|
||||
ud->pid,
|
||||
&dbe_len);
|
||||
|
||||
if (dbe == NULL || dbe_len == 0)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||
"No db_write_enable blob for "
|
||||
"%04x:%04x", ud->vid, ud->pid));
|
||||
return;
|
||||
}
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, dbe, dbe_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_db_write_enable (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"db_write_enable failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_write_chunk (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
|
||||
gsize remaining = ud->fwext.payload_len - ud->write_offset;
|
||||
gsize chunk_size = MIN (remaining, FWEXT_CHUNK_SIZE);
|
||||
|
||||
/* cmd buffer: 13-byte header + payload */
|
||||
g_autofree guint8 *cmd = g_malloc (13 + chunk_size);
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_flash (FWEXT_PARTITION,
|
||||
(guint32) ud->write_offset,
|
||||
ud->fwext.payload + ud->write_offset,
|
||||
chunk_size,
|
||||
cmd, &cmd_len);
|
||||
|
||||
fp_dbg ("FWEXT: Writing chunk at offset 0x%zx (%zu/%zu bytes)",
|
||||
ud->write_offset, ud->write_offset + chunk_size,
|
||||
ud->fwext.payload_len);
|
||||
|
||||
ud->write_offset += chunk_size;
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_write_chunk (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_FLASH chunk failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_cleanup (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
|
||||
/* Status 0x0491 means "nothing to commit" -- not an error */
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK &&
|
||||
self->cmd_response_status != 0x0491)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Cleanup cmd failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ud->write_offset < ud->fwext.payload_len)
|
||||
/* More chunks to write -- loop back to db_write_enable */
|
||||
fpi_ssm_jump_to_state (ssm, FWEXT_SEND_DB_WRITE_ENABLE);
|
||||
else
|
||||
/* All chunks written -- proceed to signature */
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_write_signature (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
|
||||
guint8 cmd[5 + FWEXT_SIGNATURE_SIZE];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_fw_sig (FWEXT_PARTITION,
|
||||
ud->fwext.signature,
|
||||
FWEXT_SIGNATURE_SIZE,
|
||||
cmd, &cmd_len);
|
||||
|
||||
fp_info ("FWEXT: Writing firmware signature (%d bytes)",
|
||||
FWEXT_SIGNATURE_SIZE);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_write_signature (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_FW_SIG failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_verify (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
ValidityFwInfo info;
|
||||
|
||||
if (!validity_fwext_parse_fw_info (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
self->cmd_response_status,
|
||||
&info) ||
|
||||
!info.loaded)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Firmware not detected after upload"));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("FWEXT: Upload verified -- firmware v%d.%d, %d modules",
|
||||
info.major, info.minor, info.module_count);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_reboot (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
guint8 cmd[3];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_reboot (cmd, &cmd_len);
|
||||
|
||||
fp_info ("FWEXT: Rebooting sensor to activate new firmware");
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_recv_reboot (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* Sensor will disconnect and re-enumerate on USB.
|
||||
* We mark SSM completed -- the caller (open sequence)
|
||||
* handles the post-reboot re-init. */
|
||||
fp_info ("FWEXT: Reboot sent. Device will re-enumerate.");
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_cleanup (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
guint8 cmd[] = { VCSFW_CMD_CLEANUP };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fwext_send_verify (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
guint8 cmd[] = { VCSFW_CMD_GET_FW_INFO, FWEXT_PARTITION };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
|
||||
void
|
||||
validity_fwext_upload_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (dev);
|
||||
FwextUploadData *ud = fpi_ssm_get_data (ssm);
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case FWEXT_SEND_WRITE_HW_REG:
|
||||
{
|
||||
guint8 cmd[10];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_hw_reg32 (FWEXT_HW_REG_WRITE_ADDR,
|
||||
FWEXT_HW_REG_WRITE_VALUE,
|
||||
cmd, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
fwext_send_write_hw_reg (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_WRITE_HW_REG:
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_HW_REG failed: status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
fwext_recv_write_hw_reg (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_READ_HW_REG:
|
||||
{
|
||||
guint8 cmd[6];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_read_hw_reg32 (FWEXT_HW_REG_READ_ADDR,
|
||||
cmd, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
fwext_send_read_hw_reg (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_READ_HW_REG:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"READ_HW_REG failed: status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
|
||||
guint32 value;
|
||||
|
||||
if (!validity_fwext_parse_read_hw_reg32 (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&value))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"READ_HW_REG response too short"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != 2 && value != 3)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Unexpected HW register value: %u "
|
||||
"(expected 2 or 3)", value));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("FWEXT: HW register 0x%08x = %u (OK)", FWEXT_HW_REG_READ_ADDR, value);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
fwext_recv_read_hw_reg (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_LOAD_FILE:
|
||||
{
|
||||
GError *error = NULL;
|
||||
GUsbDevice *usb_dev = fpi_device_get_usb_device (dev);
|
||||
guint16 vid = g_usb_device_get_vid (usb_dev);
|
||||
guint16 pid = g_usb_device_get_pid (usb_dev);
|
||||
|
||||
ud->vid = vid;
|
||||
ud->pid = pid;
|
||||
|
||||
g_autofree gchar *fw_path = validity_fwext_find_firmware (vid, pid, &error);
|
||||
|
||||
if (fw_path == NULL)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_fwext_load_file (fw_path, &ud->fwext, &error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ud->write_offset = 0;
|
||||
fp_info ("FWEXT: Loaded firmware file, %zu bytes to write",
|
||||
ud->fwext.payload_len);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
fwext_load_file (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_DB_WRITE_ENABLE:
|
||||
{
|
||||
gsize dbe_len;
|
||||
const guint8 *dbe = validity_fwext_get_db_write_enable (ud->vid,
|
||||
ud->pid,
|
||||
&dbe_len);
|
||||
|
||||
if (dbe == NULL || dbe_len == 0)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
||||
"No db_write_enable blob for "
|
||||
"%04x:%04x", ud->vid, ud->pid));
|
||||
return;
|
||||
}
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, dbe, dbe_len, NULL);
|
||||
}
|
||||
fwext_send_db_write_enable (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_DB_WRITE_ENABLE:
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"db_write_enable failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
fwext_recv_db_write_enable (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_WRITE_CHUNK:
|
||||
{
|
||||
gsize remaining = ud->fwext.payload_len - ud->write_offset;
|
||||
gsize chunk_size = MIN (remaining, FWEXT_CHUNK_SIZE);
|
||||
|
||||
/* cmd buffer: 13-byte header + payload */
|
||||
g_autofree guint8 *cmd = g_malloc (13 + chunk_size);
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_flash (FWEXT_PARTITION,
|
||||
(guint32) ud->write_offset,
|
||||
ud->fwext.payload + ud->write_offset,
|
||||
chunk_size,
|
||||
cmd, &cmd_len);
|
||||
|
||||
fp_dbg ("FWEXT: Writing chunk at offset 0x%zx (%zu/%zu bytes)",
|
||||
ud->write_offset, ud->write_offset + chunk_size,
|
||||
ud->fwext.payload_len);
|
||||
|
||||
ud->write_offset += chunk_size;
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
fwext_send_write_chunk (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_WRITE_CHUNK:
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_FLASH chunk failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
fwext_recv_write_chunk (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_CLEANUP:
|
||||
{
|
||||
guint8 cmd[] = { VCSFW_CMD_CLEANUP };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
fwext_send_cleanup (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_CLEANUP:
|
||||
/* Status 0x0491 means "nothing to commit" -- not an error */
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK &&
|
||||
self->cmd_response_status != 0x0491)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Cleanup cmd failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ud->write_offset < ud->fwext.payload_len)
|
||||
/* More chunks to write -- loop back to db_write_enable */
|
||||
fpi_ssm_jump_to_state (ssm, FWEXT_SEND_DB_WRITE_ENABLE);
|
||||
else
|
||||
/* All chunks written -- proceed to signature */
|
||||
fpi_ssm_next_state (ssm);
|
||||
fwext_recv_cleanup (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_WRITE_SIGNATURE:
|
||||
{
|
||||
guint8 cmd[5 + FWEXT_SIGNATURE_SIZE];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_write_fw_sig (FWEXT_PARTITION,
|
||||
ud->fwext.signature,
|
||||
FWEXT_SIGNATURE_SIZE,
|
||||
cmd, &cmd_len);
|
||||
|
||||
fp_info ("FWEXT: Writing firmware signature (%d bytes)",
|
||||
FWEXT_SIGNATURE_SIZE);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
fwext_send_write_signature (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_WRITE_SIGNATURE:
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"WRITE_FW_SIG failed: "
|
||||
"status=0x%04x",
|
||||
self->cmd_response_status));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
fwext_recv_write_signature (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_VERIFY:
|
||||
{
|
||||
guint8 cmd[] = { VCSFW_CMD_GET_FW_INFO, FWEXT_PARTITION };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
fwext_send_verify (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_VERIFY:
|
||||
{
|
||||
ValidityFwInfo info;
|
||||
|
||||
if (!validity_fwext_parse_fw_info (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
self->cmd_response_status,
|
||||
&info) ||
|
||||
!info.loaded)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"Firmware not detected after upload"));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("FWEXT: Upload verified -- firmware v%d.%d, %d modules",
|
||||
info.major, info.minor, info.module_count);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
fwext_recv_verify (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_SEND_REBOOT:
|
||||
{
|
||||
guint8 cmd[3];
|
||||
gsize cmd_len;
|
||||
|
||||
validity_fwext_build_reboot (cmd, &cmd_len);
|
||||
|
||||
fp_info ("FWEXT: Rebooting sensor to activate new firmware");
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
fwext_send_reboot (ssm, self);
|
||||
break;
|
||||
|
||||
case FWEXT_RECV_REBOOT:
|
||||
/* Sensor will disconnect and re-enumerate on USB.
|
||||
* We mark SSM completed -- the caller (open sequence)
|
||||
* handles the post-reboot re-init. */
|
||||
fp_info ("FWEXT: Reboot sent. Device will re-enumerate.");
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
fwext_recv_reboot (ssm, self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1725,6 +1725,23 @@ validity_tls_parse_server_finish (ValidityTlsState *tls,
|
|||
* TLS Flash Read SSM (reads flash partition 1 over USB)
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
tls_flash_read_cmd (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* READ_FLASH(partition=1, offset=0, size=0x1000)
|
||||
* Format from python-validity: pack('<BBBHLL', 0x40, partition, 1, 0, addr, size) */
|
||||
guint8 cmd[13];
|
||||
|
||||
cmd[0] = VCSFW_CMD_READ_FLASH;
|
||||
cmd[1] = 0x01; /* partition */
|
||||
cmd[2] = 0x01; /* access flag */
|
||||
FP_WRITE_UINT16_LE (&cmd[3], 0x0000); /* reserved */
|
||||
FP_WRITE_UINT32_LE (&cmd[5], 0x0000); /* offset */
|
||||
FP_WRITE_UINT32_LE (&cmd[9], 0x1000); /* size */
|
||||
vcsfw_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
|
||||
void
|
||||
validity_tls_flash_read_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
|
|
@ -1734,18 +1751,7 @@ validity_tls_flash_read_run_state (FpiSsm *ssm,
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case TLS_FLASH_READ_CMD:
|
||||
{
|
||||
/* READ_FLASH(partition=1, offset=0, size=0x1000)
|
||||
* Format from python-validity: pack('<BBBHLL', 0x40, partition, 1, 0, addr, size) */
|
||||
guint8 cmd[13];
|
||||
cmd[0] = VCSFW_CMD_READ_FLASH;
|
||||
cmd[1] = 0x01; /* partition */
|
||||
cmd[2] = 0x01; /* access flag */
|
||||
FP_WRITE_UINT16_LE (&cmd[3], 0x0000); /* reserved */
|
||||
FP_WRITE_UINT32_LE (&cmd[5], 0x0000); /* offset */
|
||||
FP_WRITE_UINT32_LE (&cmd[9], 0x1000); /* size */
|
||||
vcsfw_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
tls_flash_read_cmd (ssm, self);
|
||||
break;
|
||||
|
||||
case TLS_FLASH_READ_RECV:
|
||||
|
|
@ -1817,111 +1823,154 @@ tls_raw_recv_cb (FpiUsbTransfer *transfer,
|
|||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_hs_send_client_hello (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_tls_build_client_hello (&self->tls, &cmd_len);
|
||||
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT, cmd_len);
|
||||
memcpy (transfer->buffer, cmd, cmd_len);
|
||||
g_free (cmd);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_hs_recv_server_hello (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
/* Receive raw TLS records (ServerHello + CertReq + ServerHelloDone) */
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
tls_raw_recv_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_hs_send_client_finish (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
/* Parse the stored ServerHello response (synchronous) */
|
||||
GError *error = NULL;
|
||||
|
||||
if (!self->cmd_response_data)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"TLS handshake: no ServerHello response"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_tls_parse_server_hello (&self->tls,
|
||||
self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build and send Certificate + KeyExchange + CertVerify + CCS + Finished */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_tls_build_client_finish (&self->tls, &cmd_len);
|
||||
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT, cmd_len);
|
||||
memcpy (transfer->buffer, cmd, cmd_len);
|
||||
g_free (cmd);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_hs_recv_server_finish (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
/* Receive raw TLS records (CCS + encrypted Finished) */
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
tls_raw_recv_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_hs_parse_server_finish (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!self->cmd_response_data)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"TLS handshake: no ServerFinish response"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_tls_parse_server_finish (&self->tls,
|
||||
self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("TLS session established (secure_rx=%d secure_tx=%d)",
|
||||
self->tls.secure_rx, self->tls.secure_tx);
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
}
|
||||
|
||||
void
|
||||
validity_tls_handshake_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (dev);
|
||||
FpiUsbTransfer *transfer;
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case TLS_HS_SEND_CLIENT_HELLO:
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_tls_build_client_hello (&self->tls, &cmd_len);
|
||||
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT, cmd_len);
|
||||
memcpy (transfer->buffer, cmd, cmd_len);
|
||||
g_free (cmd);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
tls_hs_send_client_hello (ssm, self);
|
||||
break;
|
||||
|
||||
case TLS_HS_RECV_SERVER_HELLO:
|
||||
/* Receive raw TLS records (ServerHello + CertReq + ServerHelloDone) */
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
tls_raw_recv_cb, NULL);
|
||||
tls_hs_recv_server_hello (ssm, self);
|
||||
break;
|
||||
|
||||
case TLS_HS_SEND_CLIENT_FINISH:
|
||||
{
|
||||
/* Parse the stored ServerHello response (synchronous) */
|
||||
GError *error = NULL;
|
||||
if (!self->cmd_response_data)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"TLS handshake: no ServerHello response"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_tls_parse_server_hello (&self->tls,
|
||||
self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build and send Certificate + KeyExchange + CertVerify + CCS + Finished */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_tls_build_client_finish (&self->tls, &cmd_len);
|
||||
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->short_is_error = TRUE;
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_OUT, cmd_len);
|
||||
memcpy (transfer->buffer, cmd, cmd_len);
|
||||
g_free (cmd);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
fpi_ssm_usb_transfer_cb, NULL);
|
||||
}
|
||||
tls_hs_send_client_finish (ssm, self);
|
||||
break;
|
||||
|
||||
case TLS_HS_RECV_SERVER_FINISH:
|
||||
/* Receive raw TLS records (CCS + encrypted Finished) */
|
||||
transfer = fpi_usb_transfer_new (dev);
|
||||
transfer->ssm = ssm;
|
||||
fpi_usb_transfer_fill_bulk (transfer, VALIDITY_EP_CMD_IN,
|
||||
VALIDITY_MAX_TRANSFER_LEN);
|
||||
fpi_usb_transfer_submit (transfer, VALIDITY_USB_TIMEOUT, NULL,
|
||||
tls_raw_recv_cb, NULL);
|
||||
tls_hs_recv_server_finish (ssm, self);
|
||||
break;
|
||||
|
||||
case TLS_HS_PARSE_SERVER_FINISH:
|
||||
{
|
||||
GError *error = NULL;
|
||||
if (!self->cmd_response_data)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
||||
"TLS handshake: no ServerFinish response"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validity_tls_parse_server_finish (&self->tls,
|
||||
self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&error))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("TLS session established (secure_rx=%d secure_tx=%d)",
|
||||
self->tls.secure_rx, self->tls.secure_tx);
|
||||
fpi_ssm_mark_completed (ssm);
|
||||
}
|
||||
tls_hs_parse_server_finish (ssm, self);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,6 +317,158 @@ validity_find_gallery_match (GPtrArray *gallery,
|
|||
* Verify/Identify SSM
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
verify_build_capture (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_capture_build_cmd_02 (&self->capture,
|
||||
self->sensor.type_info,
|
||||
VALIDITY_CAPTURE_IDENTIFY,
|
||||
&cmd_len);
|
||||
|
||||
if (!cmd)
|
||||
{
|
||||
fp_warn ("Failed to build identify capture command");
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
return;
|
||||
}
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_capture_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("Capture (identify) failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_match_start (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* cmd 0x5E: match_finger */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_match_finger (&cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_match_start_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("match_finger failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
/* No match — continue to cleanup */
|
||||
fpi_ssm_jump_to_state (ssm, VERIFY_CLEANUP);
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_get_result (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* cmd 0x60: get_match_result */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_match_result (&cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_get_result_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_info ("No match found (status=0x%04x)",
|
||||
self->cmd_response_status);
|
||||
/* Store no-match indicator */
|
||||
g_clear_pointer (&self->bulk_data, g_free);
|
||||
self->bulk_data_len = 0;
|
||||
}
|
||||
else if (self->cmd_response_data && self->cmd_response_len > 0)
|
||||
{
|
||||
/* Store match result for later reporting */
|
||||
g_clear_pointer (&self->bulk_data, g_free);
|
||||
self->bulk_data = g_memdup2 (self->cmd_response_data,
|
||||
self->cmd_response_len);
|
||||
self->bulk_data_len = self->cmd_response_len;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_cleanup (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* cmd 0x62: match_cleanup */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_match_cleanup (&cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_led_on (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
gsize cmd_len;
|
||||
const guint8 *cmd = validity_capture_glow_start_cmd (&cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_get_prg_status (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* cmd 0x51: get_prg_status2 (after scan complete, before capture stop) */
|
||||
const guint8 cmd[] = { 0x51, 0x00, 0x20, 0x00, 0x00 };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_capture_stop (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* cmd 0x04: capture stop/cleanup */
|
||||
const guint8 cmd[] = { 0x04 };
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_led_off (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
gsize cmd_len;
|
||||
const guint8 *cmd = validity_capture_glow_end_cmd (&cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
|
|
@ -326,11 +478,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case VERIFY_LED_ON:
|
||||
{
|
||||
gsize cmd_len;
|
||||
const guint8 *cmd = validity_capture_glow_start_cmd (&cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
verify_led_on (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_LED_ON_RECV:
|
||||
|
|
@ -338,23 +486,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_BUILD_CAPTURE:
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_capture_build_cmd_02 (&self->capture,
|
||||
self->sensor.type_info,
|
||||
VALIDITY_CAPTURE_IDENTIFY,
|
||||
&cmd_len);
|
||||
if (!cmd)
|
||||
{
|
||||
fp_warn ("Failed to build identify capture command");
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||
return;
|
||||
}
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
verify_build_capture (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_CAPTURE_SEND:
|
||||
|
|
@ -362,17 +494,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_CAPTURE_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("Capture (identify) failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
verify_capture_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_WAIT_FINGER:
|
||||
|
|
@ -384,11 +506,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_GET_PRG_STATUS:
|
||||
{
|
||||
/* cmd 0x51: get_prg_status2 (after scan complete, before capture stop) */
|
||||
const guint8 cmd[] = { 0x51, 0x00, 0x20, 0x00, 0x00 };
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
verify_get_prg_status (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_GET_PRG_STATUS_RECV:
|
||||
|
|
@ -397,11 +515,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_CAPTURE_STOP:
|
||||
{
|
||||
/* cmd 0x04: capture stop/cleanup */
|
||||
const guint8 cmd[] = { 0x04 };
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, sizeof (cmd), NULL);
|
||||
}
|
||||
verify_capture_stop (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_CAPTURE_STOP_RECV:
|
||||
|
|
@ -410,27 +524,11 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_MATCH_START:
|
||||
{
|
||||
/* cmd 0x5E: match_finger */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_match_finger (&cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
verify_match_start (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_MATCH_START_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("match_finger failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
/* No match — continue to cleanup */
|
||||
fpi_ssm_jump_to_state (ssm, VERIFY_CLEANUP);
|
||||
return;
|
||||
}
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
verify_match_start_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_WAIT_MATCH_INT:
|
||||
|
|
@ -439,46 +537,15 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_GET_RESULT:
|
||||
{
|
||||
/* cmd 0x60: get_match_result */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_match_result (&cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
verify_get_result (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_GET_RESULT_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_info ("No match found (status=0x%04x)",
|
||||
self->cmd_response_status);
|
||||
/* Store no-match indicator */
|
||||
g_clear_pointer (&self->bulk_data, g_free);
|
||||
self->bulk_data_len = 0;
|
||||
}
|
||||
else if (self->cmd_response_data && self->cmd_response_len > 0)
|
||||
{
|
||||
/* Store match result for later reporting */
|
||||
g_clear_pointer (&self->bulk_data, g_free);
|
||||
self->bulk_data = g_memdup2 (self->cmd_response_data,
|
||||
self->cmd_response_len);
|
||||
self->bulk_data_len = self->cmd_response_len;
|
||||
}
|
||||
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
verify_get_result_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_CLEANUP:
|
||||
{
|
||||
/* cmd 0x62: match_cleanup */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_match_cleanup (&cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
verify_cleanup (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_CLEANUP_RECV:
|
||||
|
|
@ -487,11 +554,7 @@ verify_run_state (FpiSsm *ssm,
|
|||
break;
|
||||
|
||||
case VERIFY_LED_OFF:
|
||||
{
|
||||
gsize cmd_len;
|
||||
const guint8 *cmd = validity_capture_glow_end_cmd (&cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
}
|
||||
verify_led_off (ssm, self);
|
||||
break;
|
||||
|
||||
case VERIFY_LED_OFF_RECV:
|
||||
|
|
@ -612,115 +675,138 @@ validity_identify (FpDevice *device)
|
|||
* List prints — enumerate enrolled fingerprints from sensor DB
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
list_get_storage (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
|
||||
self->list_user_idx = 0;
|
||||
memset (&self->list_storage, 0, sizeof (self->list_storage));
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
list_get_storage_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_info ("No user storage found (status=0x%04x)",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
fp_info ("Failed to parse user storage — no enrolled prints");
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("Storage '%s': %u users",
|
||||
self->list_storage.name ? self->list_storage.name : "",
|
||||
self->list_storage.user_count);
|
||||
|
||||
if (self->list_storage.user_count == 0)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
list_get_user (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
list_get_user_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
GPtrArray *prints_array = fpi_ssm_get_data (ssm);
|
||||
|
||||
if (self->cmd_response_status == VCSFW_STATUS_OK &&
|
||||
self->cmd_response_data)
|
||||
{
|
||||
ValidityUser user = { 0 };
|
||||
|
||||
if (validity_db_parse_user (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&user))
|
||||
{
|
||||
for (guint16 i = 0; i < user.finger_count; i++)
|
||||
{
|
||||
FpPrint *print = fp_print_new (dev);
|
||||
gint finger = validity_subtype_to_finger (
|
||||
user.fingers[i].subtype);
|
||||
|
||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||
fpi_print_set_device_stored (print, TRUE);
|
||||
if (finger >= 0)
|
||||
fp_print_set_finger (print, (FpFinger) finger);
|
||||
|
||||
g_ptr_array_add (prints_array, print);
|
||||
}
|
||||
|
||||
validity_user_clear (&user);
|
||||
}
|
||||
}
|
||||
|
||||
self->list_user_idx++;
|
||||
|
||||
if (self->list_user_idx < self->list_storage.user_count)
|
||||
fpi_ssm_jump_to_state (ssm, LIST_GET_USER);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
list_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
{
|
||||
FpiDeviceValidity *self = FPI_DEVICE_VALIDITY (dev);
|
||||
GPtrArray *prints_array = fpi_ssm_get_data (ssm);
|
||||
|
||||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case LIST_GET_STORAGE:
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
self->list_user_idx = 0;
|
||||
memset (&self->list_storage, 0, sizeof (self->list_storage));
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
list_get_storage (ssm, self);
|
||||
break;
|
||||
|
||||
case LIST_GET_STORAGE_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_info ("No user storage found (status=0x%04x)",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
fp_info ("Failed to parse user storage — no enrolled prints");
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("Storage '%s': %u users",
|
||||
self->list_storage.name ? self->list_storage.name : "",
|
||||
self->list_storage.user_count);
|
||||
|
||||
if (self->list_storage.user_count == 0)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
list_get_storage_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case LIST_GET_USER:
|
||||
{
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, LIST_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
list_get_user (ssm, self);
|
||||
break;
|
||||
|
||||
case LIST_GET_USER_RECV:
|
||||
{
|
||||
if (self->cmd_response_status == VCSFW_STATUS_OK &&
|
||||
self->cmd_response_data)
|
||||
{
|
||||
ValidityUser user = { 0 };
|
||||
|
||||
if (validity_db_parse_user (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&user))
|
||||
{
|
||||
for (guint16 i = 0; i < user.finger_count; i++)
|
||||
{
|
||||
FpPrint *print = fp_print_new (dev);
|
||||
gint finger = validity_subtype_to_finger (
|
||||
user.fingers[i].subtype);
|
||||
|
||||
fpi_print_set_type (print, FPI_PRINT_RAW);
|
||||
fpi_print_set_device_stored (print, TRUE);
|
||||
if (finger >= 0)
|
||||
fp_print_set_finger (print, (FpFinger) finger);
|
||||
|
||||
g_ptr_array_add (prints_array, print);
|
||||
}
|
||||
|
||||
validity_user_clear (&user);
|
||||
}
|
||||
}
|
||||
|
||||
self->list_user_idx++;
|
||||
|
||||
if (self->list_user_idx < self->list_storage.user_count)
|
||||
fpi_ssm_jump_to_state (ssm, LIST_GET_USER);
|
||||
else
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
list_get_user_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case LIST_DONE:
|
||||
|
|
@ -767,6 +853,149 @@ validity_list (FpDevice *device)
|
|||
* Delete print — remove a fingerprint record from the sensor DB
|
||||
* ================================================================ */
|
||||
|
||||
|
||||
static void
|
||||
delete_get_storage (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_get_storage_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
FpDevice *dev = FP_DEVICE (self);
|
||||
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse into list_storage (shared with list SSM, not concurrent) */
|
||||
validity_user_storage_clear (&self->list_storage);
|
||||
if (!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
self->delete_storage_dbid = self->list_storage.dbid;
|
||||
|
||||
/* Extract finger subtype from the print to delete */
|
||||
{
|
||||
FpPrint *print = NULL;
|
||||
fpi_device_get_delete_data (dev, &print);
|
||||
|
||||
FpFinger finger = fp_print_get_finger (print);
|
||||
self->delete_finger_subtype = validity_finger_to_subtype (finger);
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_lookup_user (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* Look up the user matching the print to delete.
|
||||
* Iterate users to find one with a matching finger subtype.
|
||||
* python-validity: db.lookup_user(identity) */
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
/* No matching finger found across all users */
|
||||
fp_info ("Delete: no matching finger (subtype=%u) found in DB",
|
||||
self->delete_finger_subtype);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delete_lookup_user_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* Parse user and look for the finger to delete */
|
||||
if (self->cmd_response_status == VCSFW_STATUS_OK &&
|
||||
self->cmd_response_data)
|
||||
{
|
||||
ValidityUser user = { 0 };
|
||||
if (validity_db_parse_user (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&user))
|
||||
{
|
||||
for (guint16 i = 0; i < user.finger_count; i++)
|
||||
{
|
||||
if (user.fingers[i].subtype == self->delete_finger_subtype)
|
||||
{
|
||||
/* Found matching finger — store dbid for deletion */
|
||||
self->delete_finger_dbid = user.fingers[i].dbid;
|
||||
validity_user_clear (&user);
|
||||
fpi_ssm_next_state (ssm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
validity_user_clear (&user);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try next user — jump back to DELETE_LOOKUP_USER */
|
||||
self->list_user_idx++;
|
||||
fpi_ssm_jump_to_state (ssm, DELETE_LOOKUP_USER);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_del_record (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
/* Delete the finger record via cmd 0x48
|
||||
* python-validity: db.del_record(dbid) */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_del_record (
|
||||
self->delete_finger_dbid, &cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_del_record_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("del_record failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("Deleted finger record: dbid=%u", self->delete_finger_dbid);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
|
|
@ -776,135 +1005,27 @@ delete_run_state (FpiSsm *ssm,
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case DELETE_GET_STORAGE:
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
delete_get_storage (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_GET_STORAGE_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse into list_storage (shared with list SSM, not concurrent) */
|
||||
validity_user_storage_clear (&self->list_storage);
|
||||
if (!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
self->delete_storage_dbid = self->list_storage.dbid;
|
||||
|
||||
/* Extract finger subtype from the print to delete */
|
||||
{
|
||||
FpPrint *print = NULL;
|
||||
fpi_device_get_delete_data (dev, &print);
|
||||
|
||||
FpFinger finger = fp_print_get_finger (print);
|
||||
self->delete_finger_subtype = validity_finger_to_subtype (finger);
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
delete_get_storage_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_LOOKUP_USER:
|
||||
{
|
||||
/* Look up the user matching the print to delete.
|
||||
* Iterate users to find one with a matching finger subtype.
|
||||
* python-validity: db.lookup_user(identity) */
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
/* No matching finger found across all users */
|
||||
fp_info ("Delete: no matching finger (subtype=%u) found in DB",
|
||||
self->delete_finger_subtype);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
}
|
||||
delete_lookup_user (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_LOOKUP_USER_RECV:
|
||||
{
|
||||
/* Parse user and look for the finger to delete */
|
||||
if (self->cmd_response_status == VCSFW_STATUS_OK &&
|
||||
self->cmd_response_data)
|
||||
{
|
||||
ValidityUser user = { 0 };
|
||||
if (validity_db_parse_user (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&user))
|
||||
{
|
||||
for (guint16 i = 0; i < user.finger_count; i++)
|
||||
{
|
||||
if (user.fingers[i].subtype == self->delete_finger_subtype)
|
||||
{
|
||||
/* Found matching finger — store dbid for deletion */
|
||||
self->delete_finger_dbid = user.fingers[i].dbid;
|
||||
validity_user_clear (&user);
|
||||
fpi_ssm_next_state (ssm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
validity_user_clear (&user);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try next user — jump back to DELETE_LOOKUP_USER */
|
||||
self->list_user_idx++;
|
||||
fpi_ssm_jump_to_state (ssm, DELETE_LOOKUP_USER);
|
||||
}
|
||||
delete_lookup_user_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_DEL_RECORD:
|
||||
{
|
||||
/* Delete the finger record via cmd 0x48
|
||||
* python-validity: db.del_record(dbid) */
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_del_record (
|
||||
self->delete_finger_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
delete_del_record (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_DEL_RECORD_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
{
|
||||
fp_warn ("del_record failed: status=0x%04x",
|
||||
self->cmd_response_status);
|
||||
fpi_ssm_mark_failed (ssm,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||
return;
|
||||
}
|
||||
|
||||
fp_info ("Deleted finger record: dbid=%u", self->delete_finger_dbid);
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
delete_del_record_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case DELETE_DONE:
|
||||
|
|
@ -940,6 +1061,74 @@ validity_delete (FpDevice *device)
|
|||
* python-validity: for user in db.get_user_storage(): db.del_record(user.dbid)
|
||||
* ================================================================ */
|
||||
|
||||
static void
|
||||
clear_get_storage (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_get_storage_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
|
||||
validity_user_storage_clear (&self->list_storage);
|
||||
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK ||
|
||||
!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
/* No storage or parse error — nothing to clear */
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_del_user (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_del_record (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_del_user_recv (FpiSsm *ssm,
|
||||
FpiDeviceValidity *self)
|
||||
{
|
||||
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
fp_warn ("clear_storage: del_record(dbid=%u) failed: status=0x%04x",
|
||||
self->list_storage.user_dbids[self->list_user_idx],
|
||||
self->cmd_response_status);
|
||||
|
||||
self->list_user_idx++;
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DEL_USER);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_run_state (FpiSsm *ssm,
|
||||
FpDevice *dev)
|
||||
|
|
@ -949,62 +1138,19 @@ clear_run_state (FpiSsm *ssm,
|
|||
switch (fpi_ssm_get_cur_state (ssm))
|
||||
{
|
||||
case CLEAR_GET_STORAGE:
|
||||
{
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_get_user_storage (
|
||||
VALIDITY_STORAGE_NAME, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
clear_get_storage (ssm, self);
|
||||
break;
|
||||
|
||||
case CLEAR_GET_STORAGE_RECV:
|
||||
{
|
||||
validity_user_storage_clear (&self->list_storage);
|
||||
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK ||
|
||||
!self->cmd_response_data ||
|
||||
!validity_db_parse_user_storage (self->cmd_response_data,
|
||||
self->cmd_response_len,
|
||||
&self->list_storage))
|
||||
{
|
||||
/* No storage or parse error — nothing to clear */
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
self->list_user_idx = 0;
|
||||
fpi_ssm_next_state (ssm);
|
||||
}
|
||||
clear_get_storage_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case CLEAR_DEL_USER:
|
||||
{
|
||||
if (self->list_user_idx >= self->list_storage.user_count)
|
||||
{
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
guint16 user_dbid = self->list_storage.user_dbids[self->list_user_idx];
|
||||
|
||||
gsize cmd_len;
|
||||
guint8 *cmd = validity_db_build_cmd_del_record (user_dbid, &cmd_len);
|
||||
vcsfw_tls_cmd_send (self, ssm, cmd, cmd_len, NULL);
|
||||
g_free (cmd);
|
||||
}
|
||||
clear_del_user (ssm, self);
|
||||
break;
|
||||
|
||||
case CLEAR_DEL_USER_RECV:
|
||||
{
|
||||
if (self->cmd_response_status != VCSFW_STATUS_OK)
|
||||
fp_warn ("clear_storage: del_record(dbid=%u) failed: status=0x%04x",
|
||||
self->list_storage.user_dbids[self->list_user_idx],
|
||||
self->cmd_response_status);
|
||||
|
||||
self->list_user_idx++;
|
||||
fpi_ssm_jump_to_state (ssm, CLEAR_DEL_USER);
|
||||
}
|
||||
clear_del_user_recv (ssm, self);
|
||||
break;
|
||||
|
||||
case CLEAR_DONE:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue