aboutsummaryrefslogtreecommitdiff
path: root/tools/syz-usbgen/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/syz-usbgen/keyboard.c')
-rw-r--r--tools/syz-usbgen/keyboard.c650
1 files changed, 650 insertions, 0 deletions
diff --git a/tools/syz-usbgen/keyboard.c b/tools/syz-usbgen/keyboard.c
new file mode 100644
index 000000000..2a6015d4e
--- /dev/null
+++ b/tools/syz-usbgen/keyboard.c
@@ -0,0 +1,650 @@
+// +build
+
+// Copyright 2019 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/types.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/hid.h>
+#include <linux/usb/ch9.h>
+
+/*----------------------------------------------------------------------*/
+
+struct hid_class_descriptor {
+ __u8 bDescriptorType;
+ __le16 wDescriptorLength;
+} __attribute__ ((packed));
+
+struct hid_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __le16 bcdHID;
+ __u8 bCountryCode;
+ __u8 bNumDescriptors;
+
+ struct hid_class_descriptor desc[1];
+} __attribute__ ((packed));
+
+/*----------------------------------------------------------------------*/
+
+enum usb_fuzzer_event_type {
+ USB_FUZZER_EVENT_INVALID,
+ USB_FUZZER_EVENT_CONNECT,
+ USB_FUZZER_EVENT_DISCONNECT,
+ USB_FUZZER_EVENT_SUSPEND,
+ USB_FUZZER_EVENT_RESUME,
+ USB_FUZZER_EVENT_CONTROL,
+};
+
+struct usb_fuzzer_event {
+ uint32_t type;
+ uint32_t length;
+ char data[0];
+};
+
+struct usb_fuzzer_init {
+ uint64_t speed;
+ const char *driver_name;
+ const char *device_name;
+};
+
+struct usb_fuzzer_ep_io {
+ uint16_t ep;
+ uint16_t flags;
+ uint32_t length;
+ char data[0];
+};
+
+#define USB_FUZZER_IOCTL_INIT _IOW('U', 0, struct usb_fuzzer_init)
+#define USB_FUZZER_IOCTL_RUN _IO('U', 1)
+#define USB_FUZZER_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_fuzzer_event)
+#define USB_FUZZER_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP0_READ _IOWR('U', 4, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
+#define USB_FUZZER_IOCTL_EP_WRITE _IOW('U', 7, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_EP_READ _IOWR('U', 8, struct usb_fuzzer_ep_io)
+#define USB_FUZZER_IOCTL_CONFIGURE _IO('U', 9)
+#define USB_FUZZER_IOCTL_VBUS_DRAW _IOW('U', 10, uint32_t)
+
+/*----------------------------------------------------------------------*/
+
+int usb_fuzzer_open() {
+ int fd = open("/sys/kernel/debug/usb-fuzzer", O_RDWR);
+ if (fd < 0) {
+ perror("open()");
+ exit(EXIT_FAILURE);
+ }
+ return fd;
+}
+
+void usb_fuzzer_init(int fd, enum usb_device_speed speed) {
+ struct usb_fuzzer_init arg;
+ arg.speed = speed;
+ arg.driver_name = "dummy_udc";
+ arg.device_name = "dummy_udc.0";
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_INIT, &arg);
+ if (rv != 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_INIT)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void usb_fuzzer_run(int fd) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_RUN, 0);
+ if (rv != 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_RUN)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void usb_fuzzer_event_fetch(int fd, struct usb_fuzzer_event *event) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_EVENT_FETCH, event);
+ if (rv != 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_EVENT_FETCH)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void usb_fuzzer_ep0_read(int fd, struct usb_fuzzer_ep_io *io) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_EP0_READ, io);
+ if (rv != 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_EP0_READ)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void usb_fuzzer_ep0_write(int fd, struct usb_fuzzer_ep_io *io) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_EP0_WRITE, io);
+ if (rv != 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_EP0_WRITE)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+int usb_fuzzer_ep_enable(int fd, struct usb_endpoint_descriptor *desc) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_EP_ENABLE, desc);
+ if (rv < 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_EP_ENABLE)");
+ exit(EXIT_FAILURE);
+ }
+ return rv;
+}
+
+int usb_fuzzer_ep_write(int fd, struct usb_fuzzer_ep_io *io) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_EP_WRITE, io);
+ if (rv < 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_EP_WRITE)");
+ exit(EXIT_FAILURE);
+ }
+ return rv;
+}
+
+void usb_fuzzer_configure(int fd) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_CONFIGURE, 0);
+ if (rv < 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_CONFIGURED)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void usb_fuzzer_vbus_draw(int fd, uint32_t power) {
+ int rv = ioctl(fd, USB_FUZZER_IOCTL_VBUS_DRAW, power);
+ if (rv < 0) {
+ perror("ioctl(USB_FUZZER_IOCTL_VBUS_DRAW)");
+ exit(EXIT_FAILURE);
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+#define MAX_PACKET_SIZE 64
+
+#define USB_VENDOR 0x046d
+#define USB_PRODUCT 0xc312
+
+#define STRING_ID_MANUFACTURER 0
+#define STRING_ID_PRODUCT 1
+#define STRING_ID_SERIAL 2
+#define STRING_ID_CONFIG 3
+#define STRING_ID_INTERFACE 4
+
+struct usb_device_descriptor usb_device = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = 0,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = MAX_PACKET_SIZE,
+ .idVendor = __constant_cpu_to_le16(USB_VENDOR),
+ .idProduct = __constant_cpu_to_le16(USB_PRODUCT),
+ .bcdDevice = 0,
+ .iManufacturer = STRING_ID_MANUFACTURER,
+ .iProduct = STRING_ID_PRODUCT,
+ .iSerialNumber = STRING_ID_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+struct usb_config_descriptor usb_config = {
+ .bLength = USB_DT_CONFIG_SIZE,
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength = 0, // computed later
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STRING_ID_CONFIG,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 0x32,
+};
+
+struct usb_interface_descriptor usb_interface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = STRING_ID_INTERFACE,
+};
+
+struct usb_endpoint_descriptor usb_endpoint = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN | 1,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 5,
+};
+
+char usb_hid_report[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ 0x09, 0x06, // Usage (Keyboard) 2
+ 0xa1, 0x01, // Collection (Application) 4
+ 0x05, 0x07, // Usage Page (Keyboard) 6
+ 0x19, 0xe0, // Usage Minimum (224) 8
+ 0x29, 0xe7, // Usage Maximum (231) 10
+ 0x15, 0x00, // Logical Minimum (0) 12
+ 0x25, 0x01, // Logical Maximum (1) 14
+ 0x75, 0x01, // Report Size (1) 16
+ 0x95, 0x08, // Report Count (8) 18
+ 0x81, 0x02, // Input (Data,Var,Abs) 20
+ 0x95, 0x01, // Report Count (1) 22
+ 0x75, 0x08, // Report Size (8) 24
+ 0x81, 0x01, // Input (Cnst,Arr,Abs) 26
+ 0x95, 0x03, // Report Count (3) 28
+ 0x75, 0x01, // Report Size (1) 30
+ 0x05, 0x08, // Usage Page (LEDs) 32
+ 0x19, 0x01, // Usage Minimum (1) 34
+ 0x29, 0x03, // Usage Maximum (3) 36
+ 0x91, 0x02, // Output (Data,Var,Abs) 38
+ 0x95, 0x05, // Report Count (5) 40
+ 0x75, 0x01, // Report Size (1) 42
+ 0x91, 0x01, // Output (Cnst,Arr,Abs) 44
+ 0x95, 0x06, // Report Count (6) 46
+ 0x75, 0x08, // Report Size (8) 48
+ 0x15, 0x00, // Logical Minimum (0) 50
+ 0x26, 0xff, 0x00, // Logical Maximum (255) 52
+ 0x05, 0x07, // Usage Page (Keyboard) 55
+ 0x19, 0x00, // Usage Minimum (0) 57
+ 0x2a, 0xff, 0x00, // Usage Maximum (255) 59
+ 0x81, 0x00, // Input (Data,Arr,Abs) 62
+ 0xc0, // End Collection 64
+};
+
+struct hid_descriptor usb_hid = {
+ .bLength = 9,
+ .bDescriptorType = HID_DT_HID,
+ .bcdHID = __constant_cpu_to_le16(0x0110),
+ .bCountryCode = 0,
+ .bNumDescriptors = 1,
+ .desc = {
+ {
+ .bDescriptorType = HID_DT_REPORT,
+ .wDescriptorLength = sizeof(usb_hid_report),
+ }
+ },
+};
+
+int build_config(char *data, int length) {
+ struct usb_config_descriptor *config = (struct usb_config_descriptor *)data;
+ int total_length = 0;
+
+ assert(length >= sizeof(usb_config));
+ memcpy(data, &usb_config, sizeof(usb_config));
+ data += sizeof(usb_config);
+ length -= sizeof(usb_config);
+ total_length += sizeof(usb_config);
+
+ assert(length >= sizeof(usb_interface));
+ memcpy(data, &usb_interface, sizeof(usb_interface));
+ data += sizeof(usb_interface);
+ length -= sizeof(usb_interface);
+ total_length += sizeof(usb_interface);
+
+ assert(length >= sizeof(usb_hid));
+ memcpy(data, &usb_hid, sizeof(usb_hid));
+ data += sizeof(usb_hid);
+ length -= sizeof(usb_hid);
+ total_length += sizeof(usb_hid);
+
+ assert(length >= USB_DT_ENDPOINT_SIZE);
+ memcpy(data, &usb_endpoint, USB_DT_ENDPOINT_SIZE);
+ data += USB_DT_ENDPOINT_SIZE;
+ length -= USB_DT_ENDPOINT_SIZE;
+ total_length += USB_DT_ENDPOINT_SIZE;
+
+ config->wTotalLength = __cpu_to_le16(total_length);
+ printf("config->wTotalLength: %d\n", total_length);
+
+ return total_length;
+}
+
+/*----------------------------------------------------------------------*/
+
+void log_control_request(struct usb_ctrlrequest *ctrl) {
+ printf(" bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n",
+ ctrl->bRequestType, (ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+ ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+
+ switch (ctrl->bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ printf(" type = USB_TYPE_STANDARD\n");
+ break;
+ case USB_TYPE_CLASS:
+ printf(" type = USB_TYPE_CLASS\n");
+ break;
+ case USB_TYPE_VENDOR:
+ printf(" type = USB_TYPE_VENDOR\n");
+ break;
+ default:
+ printf(" type = unknown = %d\n", (int)ctrl->bRequestType);
+ break;
+ }
+
+ switch (ctrl->bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ printf(" req = USB_REQ_GET_DESCRIPTOR\n");
+ switch (ctrl->wValue >> 8) {
+ case USB_DT_DEVICE:
+ printf(" descriptor = USB_DT_DEVICE\n");
+ break;
+ case USB_DT_CONFIG:
+ printf(" descriptor = USB_DT_CONFIG, index = %d\n", (int)(ctrl->wValue & 0xff));
+ break;
+ case USB_DT_STRING:
+ printf(" descriptor = USB_DT_STRING\n");
+ break;
+ case USB_DT_INTERFACE:
+ printf(" descriptor = USB_DT_INTERFACE\n");
+ break;
+ case USB_DT_ENDPOINT:
+ printf(" descriptor = USB_DT_ENDPOINT\n");
+ break;
+ case USB_DT_DEVICE_QUALIFIER:
+ printf(" descriptor = USB_DT_DEVICE_QUALIFIER\n");
+ break;
+ case USB_DT_OTHER_SPEED_CONFIG:
+ printf(" descriptor = USB_DT_OTHER_SPEED_CONFIG\n");
+ break;
+ case USB_DT_INTERFACE_POWER:
+ printf(" descriptor = USB_DT_INTERFACE_POWER\n");
+ break;
+ case USB_DT_OTG:
+ printf(" descriptor = USB_DT_OTG\n");
+ break;
+ case USB_DT_DEBUG:
+ printf(" descriptor = USB_DT_DEBUG\n");
+ break;
+ case USB_DT_INTERFACE_ASSOCIATION:
+ printf(" descriptor = USB_DT_INTERFACE_ASSOCIATION\n");
+ break;
+ case USB_DT_SECURITY:
+ printf(" descriptor = USB_DT_SECURITY\n");
+ break;
+ case USB_DT_KEY:
+ printf(" descriptor = USB_DT_KEY\n");
+ break;
+ case USB_DT_ENCRYPTION_TYPE:
+ printf(" descriptor = USB_DT_ENCRYPTION_TYPE\n");
+ break;
+ case USB_DT_BOS:
+ printf(" descriptor = USB_DT_BOS\n");
+ break;
+ case USB_DT_DEVICE_CAPABILITY:
+ printf(" descriptor = USB_DT_DEVICE_CAPABILITY\n");
+ break;
+ case USB_DT_WIRELESS_ENDPOINT_COMP:
+ printf(" descriptor = USB_DT_WIRELESS_ENDPOINT_COMP\n");
+ break;
+ case USB_DT_PIPE_USAGE:
+ printf(" descriptor = USB_DT_PIPE_USAGE\n");
+ break;
+ case USB_DT_SS_ENDPOINT_COMP:
+ printf(" descriptor = USB_DT_SS_ENDPOINT_COMP\n");
+ break;
+ case HID_DT_HID:
+ printf(" descriptor = HID_DT_HID\n");
+ return;
+ case HID_DT_REPORT:
+ printf(" descriptor = HID_DT_REPORT\n");
+ return;
+ case HID_DT_PHYSICAL:
+ printf(" descriptor = HID_DT_PHYSICAL\n");
+ return;
+ default:
+ printf(" descriptor = unknown = 0x%x\n", (int)(ctrl->wValue >> 8));
+ break;
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ printf(" req = USB_REQ_SET_CONFIGURATION, value = %d\n", (int)ctrl->wValue);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ printf(" req = USB_REQ_GET_CONFIGURATION\n");
+ break;
+ case USB_REQ_SET_INTERFACE:
+ printf(" req = USB_REQ_SET_INTERFACE\n");
+ break;
+ case USB_REQ_GET_INTERFACE:
+ printf(" req = USB_REQ_GET_INTERFACE\n");
+ break;
+ case USB_REQ_GET_STATUS:
+ printf(" req = USB_REQ_GET_STATUS\n");
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ printf(" req = USB_REQ_CLEAR_FEATURE\n");
+ break;
+ case USB_REQ_SET_FEATURE:
+ printf(" req = USB_REQ_SET_FEATURE\n");
+ break;
+ default:
+ printf(" req = unknown = 0x%x\n", (int)ctrl->bRequest);
+ break;
+ }
+ break;
+ case USB_TYPE_CLASS:
+ switch (ctrl->bRequest) {
+ case HID_REQ_GET_REPORT:
+ printf(" req = HID_REQ_GET_REPORT\n");
+ break;
+ case HID_REQ_GET_IDLE:
+ printf(" req = HID_REQ_GET_IDLE\n");
+ break;
+ case HID_REQ_GET_PROTOCOL:
+ printf(" req = HID_REQ_GET_PROTOCOL\n");
+ break;
+ case HID_REQ_SET_REPORT:
+ printf(" req = HID_REQ_SET_REPORT\n");
+ break;
+ case HID_REQ_SET_IDLE:
+ printf(" req = HID_REQ_SET_IDLE\n");
+ break;
+ case HID_REQ_SET_PROTOCOL:
+ printf(" req = HID_REQ_SET_PROTOCOL\n");
+ break;
+ default:
+ printf(" req = unknown = 0x%x\n", (int)ctrl->bRequest);
+ break;
+ }
+ break;
+ default:
+ printf(" req = unknown = 0x%x\n", (int)ctrl->bRequest);
+ break;
+ }
+}
+
+void log_event(struct usb_fuzzer_event *event) {
+ switch (event->type) {
+ case USB_FUZZER_EVENT_CONNECT:
+ printf("event: connect, length: %u\n", event->length);
+ break;
+ case USB_FUZZER_EVENT_DISCONNECT:
+ printf("event: disconnect, length: %u\n", event->length);
+ break;
+ case USB_FUZZER_EVENT_SUSPEND:
+ printf("event: suspend, length: %u\n", event->length);
+ break;
+ case USB_FUZZER_EVENT_RESUME:
+ printf("event: resume, length: %u\n", event->length);
+ break;
+ case USB_FUZZER_EVENT_CONTROL:
+ printf("event: control, length: %u\n", event->length);
+ log_control_request((struct usb_ctrlrequest *)&event->data[0]);
+ break;
+ default:
+ printf("event: unknown, length: %u\n", event->length);
+ }
+}
+
+/*----------------------------------------------------------------------*/
+
+struct usb_fuzzer_control_event {
+ struct usb_fuzzer_event inner;
+ struct usb_ctrlrequest ctrl;
+};
+
+struct usb_fuzzer_control_io {
+ struct usb_fuzzer_ep_io inner;
+ char data[MAX_PACKET_SIZE];
+};
+
+struct usb_fuzzer_keyboard_io {
+ struct usb_fuzzer_ep_io inner;
+ char data[8];
+};
+
+int keyboard_connect(int fd) {
+ int config_length;
+ int ep = -1;
+
+ bool done = false;
+ while (!done) {
+ struct usb_fuzzer_control_event event;
+ event.inner.type = 0;
+ event.inner.length = sizeof(event.ctrl);
+
+ struct usb_fuzzer_control_io response;
+ response.inner.ep = 0;
+ response.inner.flags = 0;
+ response.inner.length = 0;
+
+ usb_fuzzer_event_fetch(fd, (struct usb_fuzzer_event *)&event);
+ log_event((struct usb_fuzzer_event *)&event);
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ continue;
+
+ switch (event.ctrl.bRequestType & USB_TYPE_MASK) {
+ case USB_TYPE_STANDARD:
+ switch (event.ctrl.bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ switch (event.ctrl.wValue >> 8) {
+ case USB_DT_DEVICE:
+ memcpy(&response.data[0], &usb_device, sizeof(usb_device));
+ response.inner.length = sizeof(usb_device);
+ goto reply;
+ case USB_DT_CONFIG:
+ config_length = build_config(&response.data[0], sizeof(response.data));
+ response.inner.length = config_length;
+ goto reply;
+ case USB_DT_STRING:
+ response.data[0] = 4;
+ response.data[1] = USB_DT_STRING;
+ if ((event.ctrl.wValue & 0xff) == 0) {
+ response.data[2] = 0x09;
+ response.data[3] = 0x04;
+ } else {
+ response.data[2] = 'x';
+ response.data[3] = 0x00;
+ }
+ response.inner.length = 4;
+ goto reply;
+ case HID_DT_REPORT:
+ memcpy(&response.data[0], &usb_hid_report[0], sizeof(usb_hid_report));
+ response.inner.length = sizeof(usb_hid_report);
+ goto reply;
+ default:
+ printf("fail: no response\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ ep = usb_fuzzer_ep_enable(fd, &usb_endpoint);
+ usb_fuzzer_vbus_draw(fd, usb_config.bMaxPower);
+ usb_fuzzer_configure(fd);
+ response.inner.length = 0;
+ goto reply;
+ case USB_REQ_GET_INTERFACE:
+ response.data[0] = usb_interface.bInterfaceNumber;
+ response.inner.length = 1;
+ goto reply;
+ default:
+ printf("fail: no response\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case USB_TYPE_CLASS:
+ switch (event.ctrl.bRequest) {
+ case HID_REQ_SET_REPORT:
+ response.inner.length = 1;
+ done = true;
+ goto reply;
+ case HID_REQ_SET_IDLE:
+ response.inner.length = 0;
+ goto reply;
+ case HID_REQ_SET_PROTOCOL:
+ response.inner.length = 0;
+ done = true;
+ goto reply;
+ default:
+ printf("fail: no response\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ printf("fail: no response\n");
+ exit(EXIT_FAILURE);
+ }
+
+reply:
+ if (event.ctrl.wLength < response.inner.length)
+ response.inner.length = event.ctrl.wLength;
+ if (event.ctrl.bRequestType & USB_DIR_IN)
+ usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io *)&response);
+ else
+ usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_ep_io *)&response);
+ }
+
+ printf("endpoint: #%d\n", ep);
+ return ep;
+}
+
+void keyboard_loop(int fd, int ep) {
+ struct usb_fuzzer_keyboard_io io;
+ io.inner.ep = ep;
+ io.inner.flags = 0;
+ io.inner.length = 8;
+
+ while (true) {
+ memcpy(&io.inner.data[0], "\x00\x00\x1b\x00\x00\x00\x00\x00", 8);
+ int rv = usb_fuzzer_ep_write(fd, (struct usb_fuzzer_ep_io *)&io);
+ printf("key down: %d\n", rv);
+
+ memcpy(&io.inner.data[0], "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
+ rv = usb_fuzzer_ep_write(fd, (struct usb_fuzzer_ep_io *)&io);
+ printf("key up: %d\n", rv);
+
+ sleep(1);
+ }
+}
+
+int main(int argc, char **argv) {
+ int fd = usb_fuzzer_open();
+ usb_fuzzer_init(fd, USB_SPEED_HIGH);
+ usb_fuzzer_run(fd);
+
+ int ep = keyboard_connect(fd);
+
+ keyboard_loop(fd, ep);
+
+ close(fd);
+
+ return 0;
+}