mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-05-11 13:08:13 +02:00
Add post-TLS sensor identification infrastructure: TLS command mechanism (vcsfw_tls_cmd_send): - Reusable 2-state subsm for sending VCSFW commands inside TLS channel - Uses 0x44 prefix + TLS app_data wrapping for sends - Decrypts TLS response and extracts VCSFW status + payload Sensor identification (cmd 0x75): - validity_sensor_parse_identify() parses hw_major/hw_version - DeviceInfo table (26 entries): maps (major, version) to device name and sensor type, with exact and fuzzy matching - SensorTypeInfo table (14 entries): maps sensor_type to geometry parameters (bytes_per_line, line_width, calibration blob, etc.) Factory bits retrieval (cmd 0x6f): - validity_sensor_build_factory_bits_cmd() builds 9-byte command - Response stored in sensor state for calibration (Iteration 5) Open sequence integration: - 4 new SSM states: OPEN_SENSOR_IDENTIFY, OPEN_SENSOR_IDENTIFY_RECV, OPEN_SENSOR_FACTORY_BITS, OPEN_SENSOR_FACTORY_BITS_RECV - Sensor state init/clear wired into dev_open/dev_close New files: validity_sensor.h, validity_sensor.c Tests: 14 unit tests in test-validity-sensor.c (all passing) Full suite: 6/6 OK, 0 failures
347 lines
12 KiB
C
347 lines
12 KiB
C
/*
|
|
* Unit tests for validity sensor identification and HAL tables
|
|
*
|
|
* Copyright (C) 2024 libfprint contributors
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <glib.h>
|
|
#include <string.h>
|
|
|
|
#include "fpi-byte-utils.h"
|
|
|
|
#include "drivers/validity/validity_sensor.h"
|
|
|
|
/* ================================================================
|
|
* T4.1: test_identify_sensor_parse
|
|
*
|
|
* Verify that a valid cmd 0x75 response is parsed correctly into
|
|
* a ValiditySensorIdent (hw_major + hw_version).
|
|
*
|
|
* Wire format (after 2-byte status stripped):
|
|
* [zeroes:4 LE] [version:2 LE] [major:2 LE]
|
|
* ================================================================ */
|
|
static void
|
|
test_identify_sensor_parse (void)
|
|
{
|
|
ValiditySensorIdent ident;
|
|
|
|
/* Build synthetic response: zeroes=0, version=0x13, major=0x004a */
|
|
guint8 data[8];
|
|
FP_WRITE_UINT32_LE (&data[0], 0); /* zeroes */
|
|
FP_WRITE_UINT16_LE (&data[4], 0x0013); /* version */
|
|
FP_WRITE_UINT16_LE (&data[6], 0x004a); /* major */
|
|
|
|
gboolean ok = validity_sensor_parse_identify (data, sizeof (data), &ident);
|
|
|
|
g_assert_true (ok);
|
|
g_assert_cmpuint (ident.hw_major, ==, 0x004a);
|
|
g_assert_cmpuint (ident.hw_version, ==, 0x0013);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.2: test_identify_sensor_parse_truncated
|
|
*
|
|
* Verify that a response shorter than 8 bytes returns FALSE.
|
|
* ================================================================ */
|
|
static void
|
|
test_identify_sensor_parse_truncated (void)
|
|
{
|
|
ValiditySensorIdent ident;
|
|
|
|
guint8 data[7] = { 0 };
|
|
|
|
g_assert_false (validity_sensor_parse_identify (data, sizeof (data), &ident));
|
|
/* Also test with 0 length */
|
|
g_assert_false (validity_sensor_parse_identify (data, 0, &ident));
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.3: test_device_info_lookup_exact
|
|
*
|
|
* Verify that lookup with major=0x004a, version=0x13 returns the
|
|
* correct DeviceInfo for the ThinkPad T480s sensor.
|
|
* ================================================================ */
|
|
static void
|
|
test_device_info_lookup_exact (void)
|
|
{
|
|
const ValidityDeviceInfo *info;
|
|
|
|
info = validity_device_info_lookup (0x004a, 0x13);
|
|
|
|
g_assert_nonnull (info);
|
|
g_assert_cmpuint (info->major, ==, 0x004a);
|
|
g_assert_cmpuint (info->type, ==, 0x00b5);
|
|
g_assert_cmpuint (info->version, ==, 0x13);
|
|
g_assert_cmpstr (info->name, ==, "SYN 57K0 FM3297-02");
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.4: test_device_info_lookup_another
|
|
*
|
|
* Verify that lookup with major=0x0071, version=0x01 returns
|
|
* the VSI 55E entry (type 0xdb).
|
|
* ================================================================ */
|
|
static void
|
|
test_device_info_lookup_another (void)
|
|
{
|
|
const ValidityDeviceInfo *info;
|
|
|
|
info = validity_device_info_lookup (0x0071, 0x01);
|
|
|
|
g_assert_nonnull (info);
|
|
g_assert_cmpuint (info->type, ==, 0x00db);
|
|
g_assert_cmpstr (info->name, ==, "VSI 55E FM72-001");
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.5: test_device_info_lookup_unknown
|
|
*
|
|
* Verify that a completely unknown major returns NULL.
|
|
* ================================================================ */
|
|
static void
|
|
test_device_info_lookup_unknown (void)
|
|
{
|
|
const ValidityDeviceInfo *info;
|
|
|
|
info = validity_device_info_lookup (0xffff, 0x01);
|
|
|
|
g_assert_null (info);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.6: test_device_info_lookup_fuzzy
|
|
*
|
|
* Verify that when version_mask == 0x00, the entry matches any
|
|
* version (fuzzy match).
|
|
* ================================================================ */
|
|
static void
|
|
test_device_info_lookup_fuzzy (void)
|
|
{
|
|
const ValidityDeviceInfo *info;
|
|
|
|
/* major=0x0000 entries have version_mask=0x00 → always fuzzy match.
|
|
* But major=0x0000 needs to match the lookup major. */
|
|
info = validity_device_info_lookup (0x0000, 0x42);
|
|
|
|
/* Should match one of the wildcard entries */
|
|
g_assert_nonnull (info);
|
|
g_assert_cmpuint (info->major, ==, 0x0000);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.7: test_sensor_type_info_lookup
|
|
*
|
|
* Verify lookup of sensor type 0x00b5 returns correct geometry.
|
|
* ================================================================ */
|
|
static void
|
|
test_sensor_type_info_lookup (void)
|
|
{
|
|
const ValiditySensorTypeInfo *info;
|
|
|
|
info = validity_sensor_type_info_lookup (0x00b5);
|
|
|
|
g_assert_nonnull (info);
|
|
g_assert_cmpuint (info->sensor_type, ==, 0x00b5);
|
|
g_assert_cmpuint (info->bytes_per_line, ==, 0x78);
|
|
g_assert_cmpuint (info->repeat_multiplier, ==, 2);
|
|
g_assert_cmpuint (info->lines_per_calibration_data, ==, 112);
|
|
g_assert_cmpuint (info->line_width, ==, 112);
|
|
g_assert_nonnull (info->calibration_blob);
|
|
g_assert_cmpuint (info->calibration_blob_len, ==, 112);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.8: test_sensor_type_info_lookup_db
|
|
*
|
|
* Verify lookup of sensor type 0x00db (55E) returns correct geometry.
|
|
* ================================================================ */
|
|
static void
|
|
test_sensor_type_info_lookup_db (void)
|
|
{
|
|
const ValiditySensorTypeInfo *info;
|
|
|
|
info = validity_sensor_type_info_lookup (0x00db);
|
|
|
|
g_assert_nonnull (info);
|
|
g_assert_cmpuint (info->bytes_per_line, ==, 0x98);
|
|
g_assert_cmpuint (info->repeat_multiplier, ==, 1);
|
|
g_assert_cmpuint (info->lines_per_calibration_data, ==, 144);
|
|
g_assert_cmpuint (info->line_width, ==, 144);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.9: test_sensor_type_info_lookup_unknown
|
|
*
|
|
* Verify that an unknown sensor type returns NULL.
|
|
* ================================================================ */
|
|
static void
|
|
test_sensor_type_info_lookup_unknown (void)
|
|
{
|
|
g_assert_null (validity_sensor_type_info_lookup (0xbeef));
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.10: test_factory_bits_cmd_format
|
|
*
|
|
* Verify that the factory bits command is built correctly.
|
|
* Expected: [0x6f] [0x00 0x0e] [0x00 0x00] [0x00 0x00 0x00 0x00]
|
|
* ================================================================ */
|
|
static void
|
|
test_factory_bits_cmd_format (void)
|
|
{
|
|
guint8 buf[16];
|
|
gsize len;
|
|
|
|
len = validity_sensor_build_factory_bits_cmd (0x0e00, buf, sizeof (buf));
|
|
|
|
g_assert_cmpuint (len, ==, 9);
|
|
g_assert_cmpuint (buf[0], ==, 0x6f);
|
|
/* tag = 0x0e00 LE */
|
|
g_assert_cmpuint (buf[1], ==, 0x00);
|
|
g_assert_cmpuint (buf[2], ==, 0x0e);
|
|
/* pad 2 bytes */
|
|
g_assert_cmpuint (buf[3], ==, 0x00);
|
|
g_assert_cmpuint (buf[4], ==, 0x00);
|
|
/* pad 4 bytes */
|
|
g_assert_cmpuint (buf[5], ==, 0x00);
|
|
g_assert_cmpuint (buf[6], ==, 0x00);
|
|
g_assert_cmpuint (buf[7], ==, 0x00);
|
|
g_assert_cmpuint (buf[8], ==, 0x00);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.11: test_factory_bits_cmd_buffer_too_small
|
|
*
|
|
* Verify that a too-small buffer returns 0.
|
|
* ================================================================ */
|
|
static void
|
|
test_factory_bits_cmd_buffer_too_small (void)
|
|
{
|
|
guint8 buf[4];
|
|
gsize len;
|
|
|
|
len = validity_sensor_build_factory_bits_cmd (0x0e00, buf, sizeof (buf));
|
|
|
|
g_assert_cmpuint (len, ==, 0);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.12: test_identify_then_lookup
|
|
*
|
|
* End-to-end: parse identify_sensor response → DeviceInfo lookup →
|
|
* SensorTypeInfo lookup. Simulates the T480s sensor (06cb:009a).
|
|
* ================================================================ */
|
|
static void
|
|
test_identify_then_lookup (void)
|
|
{
|
|
ValiditySensorIdent ident;
|
|
const ValidityDeviceInfo *dev_info;
|
|
const ValiditySensorTypeInfo *type_info;
|
|
|
|
/* Simulate cmd 0x75 response for T480s: major=0x004a, version=0x13 */
|
|
guint8 data[8];
|
|
FP_WRITE_UINT32_LE (&data[0], 0);
|
|
FP_WRITE_UINT16_LE (&data[4], 0x0013);
|
|
FP_WRITE_UINT16_LE (&data[6], 0x004a);
|
|
|
|
g_assert_true (validity_sensor_parse_identify (data, sizeof (data), &ident));
|
|
g_assert_cmpuint (ident.hw_major, ==, 0x004a);
|
|
g_assert_cmpuint (ident.hw_version, ==, 0x0013);
|
|
|
|
dev_info = validity_device_info_lookup (ident.hw_major, ident.hw_version);
|
|
g_assert_nonnull (dev_info);
|
|
g_assert_cmpuint (dev_info->type, ==, 0x00b5);
|
|
|
|
type_info = validity_sensor_type_info_lookup (dev_info->type);
|
|
g_assert_nonnull (type_info);
|
|
g_assert_cmpuint (type_info->bytes_per_line, ==, 0x78);
|
|
g_assert_cmpuint (type_info->line_width, ==, 112);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.13: test_sensor_state_lifecycle
|
|
*
|
|
* Verify that init zeros the state and clear frees allocated data.
|
|
* ================================================================ */
|
|
static void
|
|
test_sensor_state_lifecycle (void)
|
|
{
|
|
ValiditySensorState state;
|
|
|
|
validity_sensor_state_init (&state);
|
|
g_assert_null (state.device_info);
|
|
g_assert_null (state.type_info);
|
|
g_assert_null (state.factory_bits);
|
|
g_assert_cmpuint (state.factory_bits_len, ==, 0);
|
|
|
|
/* Simulate storing factory bits */
|
|
state.factory_bits = g_memdup2 ("\x01\x02\x03", 3);
|
|
state.factory_bits_len = 3;
|
|
|
|
validity_sensor_state_clear (&state);
|
|
g_assert_null (state.factory_bits);
|
|
g_assert_cmpuint (state.factory_bits_len, ==, 0);
|
|
}
|
|
|
|
/* ================================================================
|
|
* T4.14: test_calibration_blob_present
|
|
*
|
|
* Verify that the calibration blob for type 0x00b5 has expected
|
|
* first and last bytes (from python-validity generated_tables).
|
|
* ================================================================ */
|
|
static void
|
|
test_calibration_blob_present (void)
|
|
{
|
|
const ValiditySensorTypeInfo *info;
|
|
|
|
info = validity_sensor_type_info_lookup (0x00b5);
|
|
g_assert_nonnull (info);
|
|
g_assert_nonnull (info->calibration_blob);
|
|
g_assert_cmpuint (info->calibration_blob_len, ==, 112);
|
|
|
|
/* First byte: 0x9b, last byte: 0x06 */
|
|
g_assert_cmpuint (info->calibration_blob[0], ==, 0x9b);
|
|
g_assert_cmpuint (info->calibration_blob[111], ==, 0x06);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
g_test_add_func ("/validity/sensor/identify/parse",
|
|
test_identify_sensor_parse);
|
|
g_test_add_func ("/validity/sensor/identify/truncated",
|
|
test_identify_sensor_parse_truncated);
|
|
g_test_add_func ("/validity/sensor/devinfo/lookup_exact",
|
|
test_device_info_lookup_exact);
|
|
g_test_add_func ("/validity/sensor/devinfo/lookup_another",
|
|
test_device_info_lookup_another);
|
|
g_test_add_func ("/validity/sensor/devinfo/lookup_unknown",
|
|
test_device_info_lookup_unknown);
|
|
g_test_add_func ("/validity/sensor/devinfo/lookup_fuzzy",
|
|
test_device_info_lookup_fuzzy);
|
|
g_test_add_func ("/validity/sensor/typeinfo/lookup",
|
|
test_sensor_type_info_lookup);
|
|
g_test_add_func ("/validity/sensor/typeinfo/lookup_db",
|
|
test_sensor_type_info_lookup_db);
|
|
g_test_add_func ("/validity/sensor/typeinfo/lookup_unknown",
|
|
test_sensor_type_info_lookup_unknown);
|
|
g_test_add_func ("/validity/sensor/factory_bits/cmd_format",
|
|
test_factory_bits_cmd_format);
|
|
g_test_add_func ("/validity/sensor/factory_bits/buffer_too_small",
|
|
test_factory_bits_cmd_buffer_too_small);
|
|
g_test_add_func ("/validity/sensor/identify_then_lookup",
|
|
test_identify_then_lookup);
|
|
g_test_add_func ("/validity/sensor/state_lifecycle",
|
|
test_sensor_state_lifecycle);
|
|
g_test_add_func ("/validity/sensor/calibration_blob_present",
|
|
test_calibration_blob_present);
|
|
|
|
return g_test_run ();
|
|
}
|