| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (c) 2022-2024 Red Hat */
- #include "hid_common.h"
- #include <linux/input.h>
- #include <string.h>
- #include <sys/ioctl.h>
- /* for older kernels */
- #ifndef HIDIOCREVOKE
- #define HIDIOCREVOKE _IOW('H', 0x0D, int) /* Revoke device access */
- #endif /* HIDIOCREVOKE */
- FIXTURE(hidraw) {
- struct uhid_device hid;
- int hidraw_fd;
- };
- static void close_hidraw(FIXTURE_DATA(hidraw) * self)
- {
- if (self->hidraw_fd)
- close(self->hidraw_fd);
- self->hidraw_fd = 0;
- }
- FIXTURE_TEARDOWN(hidraw) {
- void *uhid_err;
- uhid_destroy(_metadata, &self->hid);
- close_hidraw(self);
- pthread_join(self->hid.tid, &uhid_err);
- }
- #define TEARDOWN_LOG(fmt, ...) do { \
- TH_LOG(fmt, ##__VA_ARGS__); \
- hidraw_teardown(_metadata, self, variant); \
- } while (0)
- FIXTURE_SETUP(hidraw)
- {
- int err;
- err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc));
- ASSERT_OK(err);
- self->hidraw_fd = open_hidraw(&self->hid);
- ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
- }
- /*
- * A simple test to see if the fixture is working fine.
- * If this fails, none of the other tests will pass.
- */
- TEST_F(hidraw, test_create_uhid)
- {
- }
- /*
- * Inject one event in the uhid device,
- * check that we get the same data through hidraw
- */
- TEST_F(hidraw, raw_event)
- {
- __u8 buf[10] = {0};
- int err;
- /* inject one event */
- buf[0] = 1;
- buf[1] = 42;
- uhid_send_event(_metadata, &self->hid, buf, 6);
- /* read the data from hidraw */
- memset(buf, 0, sizeof(buf));
- err = read(self->hidraw_fd, buf, sizeof(buf));
- ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
- ASSERT_EQ(buf[0], 1);
- ASSERT_EQ(buf[1], 42);
- }
- /*
- * After initial opening/checks of hidraw, revoke the hidraw
- * node and check that we can not read any more data.
- */
- TEST_F(hidraw, raw_event_revoked)
- {
- __u8 buf[10] = {0};
- int err;
- /* inject one event */
- buf[0] = 1;
- buf[1] = 42;
- uhid_send_event(_metadata, &self->hid, buf, 6);
- /* read the data from hidraw */
- memset(buf, 0, sizeof(buf));
- err = read(self->hidraw_fd, buf, sizeof(buf));
- ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
- ASSERT_EQ(buf[0], 1);
- ASSERT_EQ(buf[1], 42);
- /* call the revoke ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
- ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
- /* inject one other event */
- buf[0] = 1;
- buf[1] = 43;
- uhid_send_event(_metadata, &self->hid, buf, 6);
- /* read the data from hidraw */
- memset(buf, 0, sizeof(buf));
- err = read(self->hidraw_fd, buf, sizeof(buf));
- ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
- ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while reading the hidraw node: %d",
- errno);
- }
- /*
- * Revoke the hidraw node and check that we can not do any ioctl.
- */
- TEST_F(hidraw, ioctl_revoked)
- {
- int err, desc_size = 0;
- /* call the revoke ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
- ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
- /* do an ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
- ASSERT_EQ(err, -1) TH_LOG("ioctl_hidraw");
- ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while doing an ioctl: %d",
- errno);
- }
- /*
- * Setup polling of the fd, and check that revoke works properly.
- */
- TEST_F(hidraw, poll_revoked)
- {
- struct pollfd pfds[1];
- __u8 buf[10] = {0};
- int err, ready;
- /* setup polling */
- pfds[0].fd = self->hidraw_fd;
- pfds[0].events = POLLIN;
- /* inject one event */
- buf[0] = 1;
- buf[1] = 42;
- uhid_send_event(_metadata, &self->hid, buf, 6);
- while (true) {
- ready = poll(pfds, 1, 5000);
- ASSERT_EQ(ready, 1) TH_LOG("poll return value");
- if (pfds[0].revents & POLLIN) {
- memset(buf, 0, sizeof(buf));
- err = read(self->hidraw_fd, buf, sizeof(buf));
- ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
- ASSERT_EQ(buf[0], 1);
- ASSERT_EQ(buf[1], 42);
- /* call the revoke ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
- ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
- } else {
- break;
- }
- }
- ASSERT_TRUE(pfds[0].revents & POLLHUP);
- }
- /*
- * After initial opening/checks of hidraw, revoke the hidraw
- * node and check that we can not read any more data.
- */
- TEST_F(hidraw, write_event_revoked)
- {
- struct timespec time_to_wait;
- __u8 buf[10] = {0};
- int err;
- /* inject one event from hidraw */
- buf[0] = 1; /* report ID */
- buf[1] = 2;
- buf[2] = 42;
- pthread_mutex_lock(&uhid_output_mtx);
- memset(output_report, 0, sizeof(output_report));
- clock_gettime(CLOCK_REALTIME, &time_to_wait);
- time_to_wait.tv_sec += 2;
- err = write(self->hidraw_fd, buf, 3);
- ASSERT_EQ(err, 3) TH_LOG("unexpected error while writing to hidraw node: %d", err);
- err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
- ASSERT_OK(err) TH_LOG("error while calling waiting for the condition");
- ASSERT_EQ(output_report[0], 1);
- ASSERT_EQ(output_report[1], 2);
- ASSERT_EQ(output_report[2], 42);
- /* call the revoke ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
- ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
- /* inject one other event */
- buf[0] = 1;
- buf[1] = 43;
- err = write(self->hidraw_fd, buf, 3);
- ASSERT_LT(err, 0) TH_LOG("unexpected success while writing to hidraw node: %d", err);
- ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while writing to hidraw node: %d",
- errno);
- pthread_mutex_unlock(&uhid_output_mtx);
- }
- /*
- * Test HIDIOCGRDESCSIZE ioctl to get report descriptor size
- */
- TEST_F(hidraw, ioctl_rdescsize)
- {
- int desc_size = 0;
- int err;
- /* call HIDIOCGRDESCSIZE ioctl */
- err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
- ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESCSIZE ioctl failed");
- /* verify the size matches our test report descriptor */
- ASSERT_EQ(desc_size, sizeof(rdesc))
- TH_LOG("expected size %zu, got %d", sizeof(rdesc), desc_size);
- }
- /*
- * Test HIDIOCGRDESC ioctl to get report descriptor data
- */
- TEST_F(hidraw, ioctl_rdesc)
- {
- struct hidraw_report_descriptor desc;
- int err;
- /* get the full report descriptor */
- desc.size = sizeof(rdesc);
- err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc);
- ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed");
- /* verify the descriptor data matches our test descriptor */
- ASSERT_EQ(memcmp(desc.value, rdesc, sizeof(rdesc)), 0)
- TH_LOG("report descriptor data mismatch");
- }
- /*
- * Test HIDIOCGRDESC ioctl with smaller buffer size
- */
- TEST_F(hidraw, ioctl_rdesc_small_buffer)
- {
- struct hidraw_report_descriptor desc;
- int err;
- size_t small_size = sizeof(rdesc) / 2; /* request half the descriptor size */
- /* get partial report descriptor */
- desc.size = small_size;
- err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &desc);
- ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRDESC ioctl failed with small buffer");
- /* verify we got the first part of the descriptor */
- ASSERT_EQ(memcmp(desc.value, rdesc, small_size), 0)
- TH_LOG("partial report descriptor data mismatch");
- }
- /*
- * Test HIDIOCGRAWINFO ioctl to get device information
- */
- TEST_F(hidraw, ioctl_rawinfo)
- {
- struct hidraw_devinfo devinfo;
- int err;
- /* get device info */
- err = ioctl(self->hidraw_fd, HIDIOCGRAWINFO, &devinfo);
- ASSERT_EQ(err, 0) TH_LOG("HIDIOCGRAWINFO ioctl failed");
- /* verify device info matches our test setup */
- ASSERT_EQ(devinfo.bustype, BUS_USB)
- TH_LOG("expected bustype 0x03, got 0x%x", devinfo.bustype);
- ASSERT_EQ(devinfo.vendor, 0x0001)
- TH_LOG("expected vendor 0x0001, got 0x%x", devinfo.vendor);
- ASSERT_EQ(devinfo.product, 0x0a37)
- TH_LOG("expected product 0x0a37, got 0x%x", devinfo.product);
- }
- /*
- * Test HIDIOCGFEATURE ioctl to get feature report
- */
- TEST_F(hidraw, ioctl_gfeature)
- {
- __u8 buf[10] = {0};
- int err;
- /* set report ID 1 in first byte */
- buf[0] = 1;
- /* get feature report */
- err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
- ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGFEATURE ioctl failed, got %d", err);
- /* verify we got the expected feature data */
- ASSERT_EQ(buf[0], feature_data[0])
- TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
- ASSERT_EQ(buf[1], feature_data[1])
- TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
- }
- /*
- * Test HIDIOCGFEATURE ioctl with invalid report ID
- */
- TEST_F(hidraw, ioctl_gfeature_invalid)
- {
- __u8 buf[10] = {0};
- int err;
- /* set invalid report ID (not 1) */
- buf[0] = 2;
- /* try to get feature report */
- err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE should have failed with invalid report ID");
- ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
- }
- /*
- * Test ioctl with incorrect nr bits
- */
- TEST_F(hidraw, ioctl_invalid_nr)
- {
- char buf[256] = {0};
- int err;
- unsigned int bad_cmd;
- /*
- * craft an ioctl command with wrong _IOC_NR bits
- */
- bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */
- /* test the ioctl */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0) should have failed");
- ASSERT_EQ(errno, ENOTTY)
- TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0), got errno %d", errno);
- /*
- * craft an ioctl command with wrong _IOC_NR bits
- */
- bad_cmd = _IOC(_IOC_READ, 'H', 0x00, sizeof(buf)); /* 0 is not valid */
- /* test the ioctl */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0) should have failed");
- ASSERT_EQ(errno, ENOTTY)
- TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0), got errno %d", errno);
- /* also test with bigger number */
- bad_cmd = _IOC(_IOC_READ, 'H', 0x42, sizeof(buf)); /* 0x42 is not valid as well */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("ioctl read-only with wrong _IOC_NR (0x42) should have failed");
- ASSERT_EQ(errno, ENOTTY)
- TH_LOG("expected ENOTTY for wrong read-only _IOC_NR (0x42), got errno %d", errno);
- /* also test with bigger number: 0x42 is not valid as well */
- bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x42, sizeof(buf));
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("ioctl read-write with wrong _IOC_NR (0x42) should have failed");
- ASSERT_EQ(errno, ENOTTY)
- TH_LOG("expected ENOTTY for wrong read-write _IOC_NR (0x42), got errno %d", errno);
- }
- /*
- * Test ioctl with incorrect type bits
- */
- TEST_F(hidraw, ioctl_invalid_type)
- {
- char buf[256] = {0};
- int err;
- unsigned int bad_cmd;
- /*
- * craft an ioctl command with wrong _IOC_TYPE bits
- */
- bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'I', 0x01, sizeof(buf)); /* 'I' should be 'H' */
- /* test the ioctl */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("ioctl with wrong _IOC_TYPE (I) should have failed");
- ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_NR, got errno %d", errno);
- }
- /*
- * Test HIDIOCGFEATURE ioctl with incorrect _IOC_DIR bits
- */
- TEST_F(hidraw, ioctl_gfeature_invalid_dir)
- {
- __u8 buf[10] = {0};
- int err;
- unsigned int bad_cmd;
- /* set report ID 1 in first byte */
- buf[0] = 1;
- /*
- * craft an ioctl command with wrong _IOC_DIR bits
- * HIDIOCGFEATURE should have _IOC_WRITE|_IOC_READ, let's use only _IOC_WRITE
- */
- bad_cmd = _IOC(_IOC_WRITE, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */
- /* try to get feature report with wrong direction bits */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed");
- ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
- /* also test with only _IOC_READ */
- bad_cmd = _IOC(_IOC_READ, 'H', 0x07, sizeof(buf)); /* should be _IOC_WRITE|_IOC_READ */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGFEATURE with wrong _IOC_DIR should have failed");
- ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
- }
- /*
- * Test read-only ioctl with incorrect _IOC_DIR bits
- */
- TEST_F(hidraw, ioctl_readonly_invalid_dir)
- {
- char buf[256] = {0};
- int err;
- unsigned int bad_cmd;
- /*
- * craft an ioctl command with wrong _IOC_DIR bits
- * HIDIOCGRAWNAME should have _IOC_READ, let's use _IOC_WRITE
- */
- bad_cmd = _IOC(_IOC_WRITE, 'H', 0x04, sizeof(buf)); /* should be _IOC_READ */
- /* try to get device name with wrong direction bits */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed");
- ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
- /* also test with _IOC_WRITE|_IOC_READ */
- bad_cmd = _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x04, sizeof(buf)); /* should be only _IOC_READ */
- err = ioctl(self->hidraw_fd, bad_cmd, buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGRAWNAME with wrong _IOC_DIR should have failed");
- ASSERT_EQ(errno, EINVAL) TH_LOG("expected EINVAL for wrong _IOC_DIR, got errno %d", errno);
- }
- /*
- * Test HIDIOCSFEATURE ioctl to set feature report
- */
- TEST_F(hidraw, ioctl_sfeature)
- {
- __u8 buf[10] = {0};
- int err;
- /* prepare feature report data */
- buf[0] = 1; /* report ID */
- buf[1] = 0x42;
- buf[2] = 0x24;
- /* set feature report */
- err = ioctl(self->hidraw_fd, HIDIOCSFEATURE(3), buf);
- ASSERT_EQ(err, 3) TH_LOG("HIDIOCSFEATURE ioctl failed, got %d", err);
- /*
- * Note: The uhid mock doesn't validate the set report data,
- * so we just verify the ioctl succeeds
- */
- }
- /*
- * Test HIDIOCGINPUT ioctl to get input report
- */
- TEST_F(hidraw, ioctl_ginput)
- {
- __u8 buf[10] = {0};
- int err;
- /* set report ID 1 in first byte */
- buf[0] = 1;
- /* get input report */
- err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf);
- ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGINPUT ioctl failed, got %d", err);
- /* verify we got the expected input data */
- ASSERT_EQ(buf[0], feature_data[0])
- TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
- ASSERT_EQ(buf[1], feature_data[1])
- TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
- }
- /*
- * Test HIDIOCGINPUT ioctl with invalid report ID
- */
- TEST_F(hidraw, ioctl_ginput_invalid)
- {
- __u8 buf[10] = {0};
- int err;
- /* set invalid report ID (not 1) */
- buf[0] = 2;
- /* try to get input report */
- err = ioctl(self->hidraw_fd, HIDIOCGINPUT(sizeof(buf)), buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGINPUT should have failed with invalid report ID");
- ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
- }
- /*
- * Test HIDIOCSINPUT ioctl to set input report
- */
- TEST_F(hidraw, ioctl_sinput)
- {
- __u8 buf[10] = {0};
- int err;
- /* prepare input report data */
- buf[0] = 1; /* report ID */
- buf[1] = 0x55;
- buf[2] = 0xAA;
- /* set input report */
- err = ioctl(self->hidraw_fd, HIDIOCSINPUT(3), buf);
- ASSERT_EQ(err, 3) TH_LOG("HIDIOCSINPUT ioctl failed, got %d", err);
- /*
- * Note: The uhid mock doesn't validate the set report data,
- * so we just verify the ioctl succeeds
- */
- }
- /*
- * Test HIDIOCGOUTPUT ioctl to get output report
- */
- TEST_F(hidraw, ioctl_goutput)
- {
- __u8 buf[10] = {0};
- int err;
- /* set report ID 1 in first byte */
- buf[0] = 1;
- /* get output report */
- err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf);
- ASSERT_EQ(err, sizeof(feature_data)) TH_LOG("HIDIOCGOUTPUT ioctl failed, got %d", err);
- /* verify we got the expected output data */
- ASSERT_EQ(buf[0], feature_data[0])
- TH_LOG("expected feature_data[0] = %d, got %d", feature_data[0], buf[0]);
- ASSERT_EQ(buf[1], feature_data[1])
- TH_LOG("expected feature_data[1] = %d, got %d", feature_data[1], buf[1]);
- }
- /*
- * Test HIDIOCGOUTPUT ioctl with invalid report ID
- */
- TEST_F(hidraw, ioctl_goutput_invalid)
- {
- __u8 buf[10] = {0};
- int err;
- /* set invalid report ID (not 1) */
- buf[0] = 2;
- /* try to get output report */
- err = ioctl(self->hidraw_fd, HIDIOCGOUTPUT(sizeof(buf)), buf);
- ASSERT_LT(err, 0) TH_LOG("HIDIOCGOUTPUT should have failed with invalid report ID");
- ASSERT_EQ(errno, EIO) TH_LOG("expected EIO, got errno %d", errno);
- }
- /*
- * Test HIDIOCSOUTPUT ioctl to set output report
- */
- TEST_F(hidraw, ioctl_soutput)
- {
- __u8 buf[10] = {0};
- int err;
- /* prepare output report data */
- buf[0] = 1; /* report ID */
- buf[1] = 0x33;
- buf[2] = 0xCC;
- /* set output report */
- err = ioctl(self->hidraw_fd, HIDIOCSOUTPUT(3), buf);
- ASSERT_EQ(err, 3) TH_LOG("HIDIOCSOUTPUT ioctl failed, got %d", err);
- /*
- * Note: The uhid mock doesn't validate the set report data,
- * so we just verify the ioctl succeeds
- */
- }
- /*
- * Test HIDIOCGRAWNAME ioctl to get device name string
- */
- TEST_F(hidraw, ioctl_rawname)
- {
- char name[256] = {0};
- char expected_name[64];
- int err;
- /* get device name */
- err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(name)), name);
- ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWNAME ioctl failed, got %d", err);
- /* construct expected name based on device id */
- snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id);
- /* verify the name matches expected pattern */
- ASSERT_EQ(strcmp(name, expected_name), 0)
- TH_LOG("expected name '%s', got '%s'", expected_name, name);
- }
- /*
- * Test HIDIOCGRAWPHYS ioctl to get device physical address string
- */
- TEST_F(hidraw, ioctl_rawphys)
- {
- char phys[256] = {0};
- char expected_phys[64];
- int err;
- /* get device physical address */
- err = ioctl(self->hidraw_fd, HIDIOCGRAWPHYS(sizeof(phys)), phys);
- ASSERT_GT(err, 0) TH_LOG("HIDIOCGRAWPHYS ioctl failed, got %d", err);
- /* construct expected phys based on device id */
- snprintf(expected_phys, sizeof(expected_phys), "%d", self->hid.dev_id);
- /* verify the phys matches expected value */
- ASSERT_EQ(strcmp(phys, expected_phys), 0)
- TH_LOG("expected phys '%s', got '%s'", expected_phys, phys);
- }
- /*
- * Test HIDIOCGRAWUNIQ ioctl to get device unique identifier string
- */
- TEST_F(hidraw, ioctl_rawuniq)
- {
- char uniq[256] = {0};
- int err;
- /* get device unique identifier */
- err = ioctl(self->hidraw_fd, HIDIOCGRAWUNIQ(sizeof(uniq)), uniq);
- ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWUNIQ ioctl failed, got %d", err);
- /* uniq is typically empty in our test setup */
- ASSERT_EQ(strlen(uniq), 0) TH_LOG("expected empty uniq, got '%s'", uniq);
- }
- /*
- * Test device string ioctls with small buffer sizes
- */
- TEST_F(hidraw, ioctl_strings_small_buffer)
- {
- char small_buf[8] = {0};
- char expected_name[64];
- int err;
- /* test HIDIOCGRAWNAME with small buffer */
- err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(small_buf)), small_buf);
- ASSERT_EQ(err, sizeof(small_buf))
- TH_LOG("HIDIOCGRAWNAME with small buffer failed, got %d", err);
- /* construct expected truncated name */
- snprintf(expected_name, sizeof(expected_name), "test-uhid-device-%d", self->hid.dev_id);
- /* verify we got truncated name (first 8 chars, no null terminator guaranteed) */
- ASSERT_EQ(strncmp(small_buf, expected_name, sizeof(small_buf)), 0)
- TH_LOG("expected truncated name to match first %zu chars", sizeof(small_buf));
- /* Note: hidraw driver doesn't guarantee null termination when buffer is too small */
- }
- int main(int argc, char **argv)
- {
- return test_harness_run(argc, argv);
- }
|