Add 4 tests for the new revoke ioctl, for read/write/ioctl and poll.

Signed-off-by: Benjamin Tissoires <bent...@kernel.org>
Reviewed-by: Peter Hutterer <peter.hutte...@who-t.net>

---

new in v4

Changes to v4:
- fix a few error messages
- also check for ENODEV errno when required
- use ENODEV instead of its plain value
---
 tools/testing/selftests/hid/hidraw.c | 147 +++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/tools/testing/selftests/hid/hidraw.c 
b/tools/testing/selftests/hid/hidraw.c
index 37372709130c..f8b4f7ff292c 100644
--- a/tools/testing/selftests/hid/hidraw.c
+++ b/tools/testing/selftests/hid/hidraw.c
@@ -3,6 +3,11 @@
 
 #include "hid_common.h"
 
+/* for older kernels */
+#ifndef HIDIOCREVOKE
+#define HIDIOCREVOKE         _IOW('H', 0x0D, int) /* Revoke device access */
+#endif /* HIDIOCREVOKE */
+
 FIXTURE(hidraw) {
        int dev_id;
        int uhid_fd;
@@ -84,6 +89,148 @@ TEST_F(hidraw, raw_event)
        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->uhid_fd, 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->uhid_fd, 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->uhid_fd, 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);
+}
+
 int main(int argc, char **argv)
 {
        return test_harness_run(argc, argv);

-- 
2.46.0


Reply via email to