aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/common_usb.h103
-rw-r--r--executor/executor.cc20
-rw-r--r--pkg/csource/csource.go1
-rw-r--r--sys/linux/vusb.txt258
4 files changed, 244 insertions, 138 deletions
diff --git a/executor/common_usb.h b/executor/common_usb.h
index 31071fd8c..8fe2b641b 100644
--- a/executor/common_usb.h
+++ b/executor/common_usb.h
@@ -139,6 +139,7 @@ int usb_fuzzer_vbus_draw(int fd, uint32 power)
struct usb_fuzzer_control_event {
struct usb_fuzzer_event inner;
struct usb_ctrlrequest ctrl;
+ char data[USB_MAX_PACKET_SIZE];
};
struct usb_fuzzer_ep_io_data {
@@ -180,8 +181,10 @@ static bool lookup_connect_response(struct vusb_connect_descriptors* descs, stru
return true;
case USB_DT_STRING:
str_idx = (uint8)ctrl->wValue;
- if (str_idx >= descs->strs_len)
- return false;
+ if (str_idx >= descs->strs_len && descs->strs_len > 0) {
+ // Use the last string if we ran out.
+ str_idx = descs->strs_len - 1;
+ }
*response_data = descs->strs[str_idx].str;
*response_length = descs->strs[str_idx].len;
return true;
@@ -232,27 +235,35 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
struct usb_device_index index;
memset(&index, 0, sizeof(index));
- int rv = false;
+ int rv = 0;
NONFAILING(rv = parse_usb_descriptor(dev, dev_len, &index));
- if (!rv)
- return -1;
+ if (!rv) {
+ debug("syz_usb_connect: parse_usb_descriptor failed with %d\n", rv);
+ return rv;
+ }
debug("syz_usb_connect: parsed usb descriptor\n");
int fd = usb_fuzzer_open();
- if (fd < 0)
- return -1;
+ if (fd < 0) {
+ debug("syz_usb_connect: usb_fuzzer_open failed with %d\n", rv);
+ return fd;
+ }
debug("syz_usb_connect: usb_fuzzer_open success\n");
char device[32];
sprintf(&device[0], "dummy_udc.%llu", procid);
rv = usb_fuzzer_init(fd, speed, "dummy_udc", &device[0]);
- if (rv < 0)
- return -1;
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_init failed with %d\n", rv);
+ return rv;
+ }
debug("syz_usb_connect: usb_fuzzer_init success\n");
rv = usb_fuzzer_run(fd);
- if (rv < 0)
- return -1;
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_run failed with %d\n", rv);
+ return rv;
+ }
debug("syz_usb_connect: usb_fuzzer_run success\n");
bool done = false;
@@ -261,28 +272,37 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
event.inner.type = 0;
event.inner.length = sizeof(event.ctrl);
rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
- if (rv < 0)
- return -1;
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_ep0_read failed with %d\n", rv);
+ return rv;
+ }
if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
continue;
- debug("syz_usb_connect: bRequestType: 0x%x, bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n",
- event.ctrl.bRequestType, event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);
+ debug("syz_usb_connect: bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n",
+ event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+ event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);
bool response_found = false;
char* response_data = NULL;
uint32 response_length = 0;
NONFAILING(response_found = lookup_connect_response(descs, &index, &event.ctrl, &response_data, &response_length, &done));
- if (!response_found)
+ if (!response_found) {
+ debug("syz_usb_connect: no response found\n");
return -1;
+ }
if (done) {
- int rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
- if (rv < 0)
- return -1;
+ rv = usb_fuzzer_vbus_draw(fd, index.config->bMaxPower);
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_vbus_draw failed with %d\n", rv);
+ return rv;
+ }
rv = usb_fuzzer_configure(fd);
- if (rv < 0)
- return -1;
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_configure failed with %d\n", rv);
+ return rv;
+ }
unsigned ep;
for (ep = 0; ep < index.eps_num; ep++) {
rv = usb_fuzzer_ep_enable(fd, index.eps[ep]);
@@ -302,7 +322,11 @@ static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatil
if (event.ctrl.wLength < response.inner.length)
response.inner.length = event.ctrl.wLength;
debug("syz_usb_connect: reply length = %d\n", response.inner.length);
- usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ if (rv < 0) {
+ debug("syz_usb_connect: usb_fuzzer_ep0_write failed with %d\n", rv);
+ return rv;
+ }
}
sleep_ms(200);
@@ -406,22 +430,34 @@ static volatile long syz_usb_control_io(volatile long a0, volatile long a1, vola
struct usb_fuzzer_control_event event;
event.inner.type = 0;
- event.inner.length = sizeof(event.ctrl);
+ event.inner.length = USB_MAX_PACKET_SIZE;
int rv = usb_fuzzer_ep0_read(fd, (struct usb_fuzzer_event*)&event);
- if (rv < 0)
- return -1;
- if (event.inner.type != USB_FUZZER_EVENT_CONTROL)
+ if (rv < 0) {
+ debug("syz_usb_control_io: usb_fuzzer_ep0_read failed with %d\n", rv);
+ return rv;
+ }
+ if (event.inner.type != USB_FUZZER_EVENT_CONTROL) {
+ debug("syz_usb_control_io: wrong event type: %d\n", (int)event.inner.type);
return -1;
+ }
- debug("syz_usb_control_io: bRequestType: 0x%x, bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n",
- event.ctrl.bRequestType, event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);
+ debug("syz_usb_control_io: bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, wIndex: 0x%x, wLength: %d\n",
+ event.ctrl.bRequestType, (event.ctrl.bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+ event.ctrl.bRequest, event.ctrl.wValue, event.ctrl.wIndex, event.ctrl.wLength);
+
+ if (!(event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength != 0) {
+ debug("syz_usb_control_io: OUT data:\n");
+ debug_dump_data(&event.data[0], event.ctrl.wLength);
+ }
bool response_found = false;
char* response_data = NULL;
uint32 response_length = 0;
NONFAILING(response_found = lookup_control_io_response(descs, resps, &event.ctrl, &response_data, &response_length));
- if (!response_found)
+ if (!response_found) {
+ debug("syz_usb_control_io: no response found\n");
return -1;
+ }
struct usb_fuzzer_ep_io_data response;
response.inner.ep = 0;
@@ -434,7 +470,14 @@ static volatile long syz_usb_control_io(volatile long a0, volatile long a1, vola
if (event.ctrl.wLength < response.inner.length)
response.inner.length = event.ctrl.wLength;
debug("syz_usb_control_io: response length = %d\n", response.inner.length);
- usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ debug_dump_data(&response.data[0], response.inner.length);
+ rv = usb_fuzzer_ep0_write(fd, (struct usb_fuzzer_ep_io*)&response);
+ if (rv < 0) {
+ debug("syz_usb_control_io: usb_fuzzer_ep0_write failed with %d\n", rv);
+ return rv;
+ }
+
+ sleep_ms(200);
return 0;
}
diff --git a/executor/executor.cc b/executor/executor.cc
index 2ea588b72..597f6d656 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -601,12 +601,16 @@ retry:
prog_extra_cover = true;
call_extra_cover = true;
}
- if (strcmp(syscalls[call_num].name, "syz_usb_connect") == 0) {
+ if (strncmp(syscalls[call_num].name, "syz_usb_connect", strlen("syz_usb_connect")) == 0) {
prog_extra_timeout = 2000;
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 2000;
}
- if (strcmp(syscalls[call_num].name, "syz_usb_disconnect") == 0) {
+ if (strncmp(syscalls[call_num].name, "syz_usb_control_io", strlen("syz_usb_control_io")) == 0) {
+ // Must match timeout in pkg/csource/csource.go.
+ call_extra_timeout = 200;
+ }
+ if (strncmp(syscalls[call_num].name, "syz_usb_disconnect", strlen("syz_usb_disconnect")) == 0) {
// Must match timeout in pkg/csource/csource.go.
call_extra_timeout = 200;
}
@@ -723,6 +727,7 @@ retry:
timeout_ms = 1000;
if (event_timedwait(&th->done, timeout_ms))
handle_completion(th);
+
// Check if any of previous calls have completed.
for (int i = 0; i < kMaxThreads; i++) {
th = &threads[i];
@@ -776,9 +781,10 @@ retry:
close_fds();
#endif
- if (!colliding && !collide && prog_extra_cover) {
+ if (prog_extra_cover) {
sleep_ms(500);
- write_extra_output();
+ if (!colliding && !collide)
+ write_extra_output();
}
if (flag_collide && !flag_inject_fault && !colliding && !collide) {
@@ -1446,10 +1452,12 @@ void debug_dump_data(const char* data, int length)
{
if (!flag_debug)
return;
- for (int i = 0; i < length; i++) {
+ int i;
+ for (i = 0; i < length; i++) {
debug("%02x ", data[i] & 0xff);
if (i % 16 == 15)
debug("\n");
}
- debug("\n");
+ if (i % 16 != 0)
+ debug("\n");
}
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index de99313d2..2a27ed42d 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -76,6 +76,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
// Must match timeouts in executor/executor.cc.
specialCallTimeouts := map[string]int{
"syz_usb_connect": 2000,
+ "syz_usb_control_io": 200,
"syz_usb_disconnect": 200,
}
timeoutExpr := "45"
diff --git a/sys/linux/vusb.txt b/sys/linux/vusb.txt
index 5e9177cd6..4eb8040ee 100644
--- a/sys/linux/vusb.txt
+++ b/sys/linux/vusb.txt
@@ -13,29 +13,34 @@ include <uapi/linux/usb/cdc.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* syzcalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
+resource fd_usb_hid[fd_usb]
+# These are generic syzcalls for emulating arbitrary USB devices.
+# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses])
syz_usb_ep_write(fd fd_usb, ep int16[0:31], len len[data], data buffer[in])
syz_usb_disconnect(fd fd_usb)
+# These are syzcalls specifically targeted to the HID device class.
+syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid
+syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid])
+
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# USB device, configuration, interface and endpoint descriptors.
-
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
- bcdUSB int16
+ bcdUSB flags[usb_versions, int16]
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
- bMaxPacketSize0 int8
+ bMaxPacketSize0 flags[usb_max_packet_sizes, int8]
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
@@ -47,14 +52,12 @@ type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE,
configs CFS
} [packed]
-# TODO: support more than one configuration.
-# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
-# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
-usb_device_descriptor {
- inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
-} [packed]
+usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
+
+# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
+usb_max_packet_sizes = 8, 16, 32, 64
-type usb_config_descriptor_t[IFS] {
+type usb_config_descriptor_t[ATTRS, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
@@ -62,19 +65,12 @@ type usb_config_descriptor_t[IFS] {
bNumInterfaces len[interfaces, int8]
bConfigurationValue int8
iConfiguration int8
- bmAttributes flags[usb_config_attributes, int8]
+ bmAttributes ATTRS
bMaxPower int8
interfaces IFS
} [packed]
-# TODO: support more than one interface.
-usb_config_descriptor {
- inner usb_config_descriptor_t[array[usb_interface_descriptor, 1]]
-} [packed]
-
-usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
-
type usb_interface_descriptor_t[CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
@@ -91,18 +87,12 @@ type usb_interface_descriptor_t[CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] {
endpoints EPS
} [packed]
-# bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
-# are patched by Go code, see sys/linux/init_vusb.go.
-usb_interface_descriptor {
- inner usb_interface_descriptor_t[0, 0, 0, array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
-} [packed]
-
-type usb_endpoint_descriptor_t[EXTRA] {
+type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] {
bLength const[USB_DT_ENDPOINT_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
- bEndpointAddress int8
- bmAttributes flags[usb_endpoint_attributes, int8]
+ bEndpointAddress ADDR
+ bmAttributes ATTRS
wMaxPacketSize int16
bInterval int8
bRefresh int8
@@ -111,17 +101,39 @@ type usb_endpoint_descriptor_t[EXTRA] {
extra EXTRA
} [packed]
-usb_endpoint_descriptor {
- inner usb_endpoint_descriptor_t[array[usb_endpoint_extra_descriptor, 0:2]]
-} [packed]
-
-usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
+# Generic USB device, configuration, interface and endpoint descriptors.
+
+# TODO: support more than one configuration.
+# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
+# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
+usb_device_descriptor {
+ inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
+} [packed]
+
+# TODO: support more than one interface.
+usb_config_descriptor {
+ inner usb_config_descriptor_t[flags[usb_config_attributes, int8], array[usb_interface_descriptor, 1]]
+} [packed]
+
+usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
+
+# bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
+# are patched by Go code, see sys/linux/init_vusb.go.
+usb_interface_descriptor {
+ inner usb_interface_descriptor_t[0, 0, 0, array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
+} [packed]
+
+usb_endpoint_descriptor {
+ inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
+} [packed]
+
+usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
+
+usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
# TODO: consider unifying with vusb_descriptors in case this struct significantly grows.
vusb_connect_descriptors {
@@ -138,6 +150,113 @@ vusb_connect_string_descriptor {
str ptr[in, usb_string_descriptor]
} [packed]
+vusb_descriptors {
+ len len[parent, int32]
+ generic ptr[in, vusb_descriptor_generic]
+ string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
+ hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
+ bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
+ hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_HUB, usb_hub_descriptor_hs]]
+ hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
+} [packed]
+
+vusb_descriptor_generic {
+ req_type flags[usb_request_types, int8]
+ desc_type flags[usb_descriptor_types, int8]
+ len bytesize[data, int32]
+ data usb_generic_descriptor
+} [packed]
+
+usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
+
+type vusb_descriptor_t[CLASS, REQ, DATA] {
+ type const[CLASS, int8]
+ req const[REQ, int8]
+ len bytesize[data, int32]
+ data DATA
+} [packed]
+
+vusb_responses {
+ len len[parent, int32]
+ generic ptr[in, vusb_response_generic]
+ set_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_INTERFACE, void]]
+ get_interface ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_INTERFACE, int8]]
+ set_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_CONFIGURATION, void]]
+ get_configuration ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_CONFIGURATION, int8]]
+ get_status_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
+ get_status_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
+ aiptek_get_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x1, array[int8, 3]]]
+ aiptek_set_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x9, array[int8, 3]]]
+ cdc_get_ntb_parameters ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
+} [packed]
+
+vusb_response_generic {
+ type flags[usb_request_types, int8]
+ req flags[usb_requests, int8]
+ len bytesize[data, int32]
+ data array[int8]
+} [packed]
+
+usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
+
+type vusb_response_t[CLASS, REQ, DATA] {
+ type const[CLASS, int8]
+ req const[REQ, int8]
+ len bytesize[data, int32]
+ data DATA
+} [packed]
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+# USB device, configuration, interface and endpoint descriptors for the HID device class.
+# Modelled after the Logitech K120 keyboard.
+
+usb_device_descriptor_hid {
+ inner usb_device_descriptor_t[0, 0, 0, 0x46d, 0xc31c, 64, array[usb_config_descriptor_hid, 1]]
+} [packed]
+
+usb_config_descriptor_hid {
+ inner usb_config_descriptor_t[const[USB_CONFIG_HID_ATTRIBUTES, int8], array[usb_interface_descriptor_hid, 1]]
+} [packed]
+
+usb_interface_descriptor_hid {
+ inner usb_interface_descriptor_t[USB_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_KEYBOARD, hid_descriptor_hid, array[usb_endpoint_descriptor_hid, 1]]
+} [packed]
+
+usb_endpoint_descriptor_hid {
+ inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], array[usb_endpoint_extra_descriptor, 0:2]]
+} [packed]
+
+define USB_CONFIG_HID_ATTRIBUTES (USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_WAKEUP)
+define USB_ENDPOINT_HID_ADDRESS (1 | USB_DIR_IN)
+define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
+
+# TODO: consider merging with vusb_descriptors.
+vusb_descriptors_hid {
+ len len[parent, int32]
+ generic ptr[in, vusb_descriptor_generic]
+ string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
+ hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
+ bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
+} [packed]
+
+# TODO: consider merging with vusb_responses.
+vusb_responses_hid {
+ len len[parent, int32]
+ generic ptr[in, vusb_response_generic]
+ set_idle ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_IDLE, void]]
+ set_report ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_REPORT, void]]
+ set_protocol ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_SET_PROTOCOL, void]]
+} [packed]
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
+
usb_string_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
@@ -152,11 +271,11 @@ usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
- bcdUSB int16
+ bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
- bMaxPacketSize0 int8
+ bMaxPacketSize0 flags[usb_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
@@ -505,7 +624,6 @@ usb_cdc_mbim_extended_desc {
# USB descriptors requested after the SET_CONFIGURATION request.
# TODO: define recusively to generate proper structures.
-
hid_descriptor_report {
items array[hid_report_item]
} [packed]
@@ -623,67 +741,3 @@ usb_cdc_ncm_ntb_parameters {
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-vusb_descriptors {
- len len[parent, int32]
- generic ptr[in, vusb_descriptor_generic]
- string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
- hid_report ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
- bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
- hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_HUB, usb_hub_descriptor_hs]]
- hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
-} [packed]
-
-vusb_descriptor_generic {
- req_type flags[usb_request_types, int8]
- desc_type flags[usb_descriptor_types, int8]
- len bytesize[data, int32]
- data usb_generic_descriptor
-} [packed]
-
-usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
-
-type vusb_descriptor_t[CLASS, REQ, DATA] {
- type const[CLASS, int8]
- req const[REQ, int8]
- len bytesize[data, int32]
- data DATA
-} [packed]
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-vusb_responses {
- len len[parent, int32]
- generic ptr[in, vusb_response_generic]
- set_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_INTERFACE, void]]
- get_interface ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_INTERFACE, int8]]
- set_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_SET_CONFIGURATION, void]]
- get_configuration ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_CONFIGURATION, int8]]
- get_status_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
- get_status_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
- aiptek_get_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x1, array[int8, 3]]]
- aiptek_set_report ptr[in, vusb_response_t[USB_TYPE_VENDOR, 0x9, array[int8, 3]]]
- cdc_get_ntb_parameters ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
-} [packed]
-
-vusb_response_generic {
- type flags[usb_request_types, int8]
- req flags[usb_requests, int8]
- len bytesize[data, int32]
- data array[int8]
-} [packed]
-
-usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
-
-type vusb_response_t[CLASS, REQ, DATA] {
- type const[CLASS, int8]
- req const[REQ, int8]
- len bytesize[data, int32]
- data DATA
-} [packed]
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #