sys/linux, executor: add basic USB HID fuzzing support

This commit adds the necessary descriptions and executor adjustments to
enable targeted fuzzing of the enumeration process of USB HID devices.
This commit is contained in:
Andrey Konovalov 2019-06-18 18:55:58 +02:00 committed by Andrey Konovalov
parent 35a4434115
commit fa26c3cf35
4 changed files with 245 additions and 139 deletions

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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"

View File

@ -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
type usb_config_descriptor_t[IFS] {
# 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[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,18 +101,40 @@ type usb_endpoint_descriptor_t[EXTRA] {
extra EXTRA
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[array[usb_endpoint_extra_descriptor, 0:2]]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 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
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: consider unifying with vusb_descriptors in case this struct significantly grows.
vusb_connect_descriptors {
qual_len len[qual, int32]
@ -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]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #