summaryrefslogtreecommitdiff
path: root/docs/usb-redirection-protocol.md
diff options
context:
space:
mode:
authorVictor Toso <victortoso@redhat.com>2021-02-02 14:19:30 +0100
committerVictor Toso <victortoso@redhat.com>2021-02-17 13:11:31 +0100
commitfa90781b381cbfe494d909b9a509070ec4d612f2 (patch)
tree402d16c2c3db060023ee8c696b3b00e8c5c46781 /docs/usb-redirection-protocol.md
parent5ee8d8b3b6be13e1856f997b4ec0a43de551deaa (diff)
docs: Move usb-redirection-protocol to Markdown
Adding a Table of Contents in the top as well, to help guide user to the right place. v2: - Use lists where necessary (Jakub) - Language name of the code blocks must be lower-case to work with Gitlab properly (Jakub) - A few missing code blocks missing (Jakub) - Surround <> with `` to be rendered properly in Gitlab (Jakub) - Format a few missing struct fields with `` (Jakub) - Fix: remove wrong apostrophes when forming plural (Jakub) Signed-off-by: Victor Toso <victortoso@redhat.com>
Diffstat (limited to 'docs/usb-redirection-protocol.md')
-rw-r--r--docs/usb-redirection-protocol.md1180
1 files changed, 1180 insertions, 0 deletions
diff --git a/docs/usb-redirection-protocol.md b/docs/usb-redirection-protocol.md
new file mode 100644
index 0000000..f778d3c
--- /dev/null
+++ b/docs/usb-redirection-protocol.md
@@ -0,0 +1,1180 @@
+# Index
+
+[[_TOC_]]
+
+# USB Network Redirection protocol description version 0.7 (19 May 2014)
+
+## Revisions
+
+### Version 0.1
+- Initial version (released as initial RFC without a version number)
+
+### Version 0.2
+- Version demo-ed at FOSDEM 2011
+- Remove `usb_redir_report_descriptor` packet, as it is not possible to get
+ the cached descriptors from the OS on all platforms and we can do without
+- Replace vm-host with usb-guest
+- Replace the synchroneous / asynchroneous commands nomenclature with
+ control / data packets
+- Move the packet id to the main packet header shared by all packets
+- Add note: "All integers in the protocol are send over the pipe in least
+ significant byte first order."
+- Add note: "All structs are packed"
+- s/data_size/length/
+- Add an `usb_redir_cancel_data_packet` packet
+- Add `usb_redir_reset` and `usb_redir_reset_status` packets
+
+### Version 0.3, released 14 July 2011
+- First "stable" version, all later versions should be compatible with this
+ version
+- Add an `usb_redir_device_connect` packet
+- Add an `usb_redir_device_disconnect` packet
+- Add an `usb_redir_interface_info` packet
+- Add an `usb_redir_ep_info` packet
+- Add support for interrupt transfers, add the following packets:
+ `usb_redir_start_interrupt_receiving`
+ `usb_redir_stop_interrupt_receiving`
+ `usb_redir_interrupt_receiving_status`
+ `usb_redir_interrupt_packet`
+- Add a list with the possible values for the status field
+- Report `usb_redir_stall` as iso status error to indicate a stream stop
+- Drop `usb_redir_disconnect` status, instead the usb-host should always
+ send a `usb_redir_device_disconnect` packet on device disconnection. The
+ reason behind this is that having to handle disconnection from data packet
+ handlers make things unnecessarily hard for the usb-guest
+- Drop `usb_redir_reset_status`, instead if reconnecting to the device fails
+ after reset the usb-host will send a `usb_redir_device_disconnect` packet
+
+### Version 0.3.1, released 18 August 2011
+- No protocol changes
+
+### Version 0.3.2, released 3 January 2012
+- The `usb_redir_device_connect_header` has been extended with a
+ `device_version_bcd` field. This is only send / received if both sides
+ have the `usb_redir_cap_connect_device_version` capability
+
+### Version 0.3.3, released 12 January 2012
+- No protocol changes
+
+### Version 0.4, released 22 February 2012
+- Add `usb_redir_filter_reject` and `usb_redir_filter_filter` packets and
+ an `usb_redir_cap_filter` capability flag
+- Add an `usb_redir_device_disconnect_ack` packet and
+ an `usb_redir_cap_device_disconnect_ack` capability flag
+
+### Version 0.4.1, released 25 February 2012
+- No protocol changes
+
+### Version 0.4.2, released 6 March 2012
+- Add `usb_redir_babble` status code
+- The `usb_redir_ep_info_header` has been extended with a `max_packet_size` field
+ This is only send / received if both sides have the
+ `usb_redir_cap_ep_info_max_packet_size` capability
+
+### Version 0.5, released 7 September 2012
+- Add the posibility to use 64 bits packet ids
+
+### Version 0.5.3, released 7 October 2012
+- Extend the length field in bulk packets headers to 32 bits, the extra 16
+ bits are only send / received if both sides have the
+ `usb_redir_cap_32bits_bulk_length` capability
+
+### Version 0.6, released 13 December 2012
+- Add support for buffered bulk input, new packets:
+ `usb_redir_start_bulk_receiving,` `usb_redir_stop_bulk_receiving`,
+ `usb_redir_bulk_receiving_status,` `usb_redir_buffered_bulk_packet`
+ New capability: `usb_redir_cap_bulk_receiving`
+
+### Version 0.7, released 19 May 2014
+- The `usb_redir_ep_info_header` has been extended with a `max_streams` field
+ This is only send / received if both sides have the
+ `usb_redir_cap_bulk_streams` capability.
+- Change bulk_stream packet definitions to allow allocating / freeing
+ streams on multiple endpoints in one go, technically this is a protocol
+ change, but no-one has implemented `usb_redir_cap_bulk_streams` so far, so
+ we can safely do this
+
+
+# USB redirection protocol version 0.7
+
+The protocol described in this document is meant for tunneling usb transfers
+to a single usb device. Note: not an entire hub, only a single device.
+
+The most significant use case for this is taking a usb device attached to
+some machine "a" which acts as a client / viewer to a virtual machine "v"
+hosted on another machine "b", and make the usb device show up inside the
+virtual machine as if it were attached directly to the virtual machine "v".
+
+The described protocol assumes a reliable ordered bidirectional transport is
+available, for example a tcp socket. All integers in the protocol are send
+over the pipe in least significant byte first order. All structs send over
+the pipe are packed (no padding).
+
+Definitions:
+
+- _usb-device_: The usb-device whose usb transfers are being tunneled.
+- _usb-guest_: The entity connecting to the usb-device and using it as if
+ connected directly to it. For example a virtual machine running a guest
+ os which accesses a usb-device over the network as if it is part of the
+ virtual machine.
+- _usb-host_: The entity making the usb-device available for use by a usb-guest.
+ For example a daemon on a machine which "exports" the usb-device over the
+ network which then "appears" inside a virtual machine on another machine.
+
+
+## Basic packet structure / communication
+
+Each packet exchanged between the usb-guest and the usb-host starts with a
+`usb_redir_header`, followed by an optional packet type specific header
+follow by optional additional data.
+
+The `usb_redir_header` each packet starts with looks as follows:
+
+```c
+struct usb_redir_header {
+ uint32_t type;
+ uint32_t length;
+ uint32_t id;
+}
+```
+
+Or, if both sides have the `usb_redir_cap_64bits_ids` capability, it looks as
+follows! :
+
+```c
+struct usb_redir_header {
+ uint32_t type;
+ uint32_t length;
+ uint64_t id;
+}
+```
+
+- type: This identifies the type of packet, from the type enum
+- length: Length of the optional type specific packet header + the optional
+ additional data. Can be 0.
+- id: A unique id, generated by the usb-guest when sending a packet,
+ the usb-host will use the same id in its response packet, allowing
+ the usb-guest to match responses to its original requests.
+
+There are 2 types of packets:
+
+1) control packets
+2) data packets
+
+Control packets are handled synchroneously inside the usb-host, it will hand
+the request over to the host os and then *wait* for a response. The usb-host
+will thus stop processing further packets. Where as for data packets the
+usb-host hands them over to the host os with the request to let the usb-host
+process know when there is a response from the usb-device.
+
+Note that control packets should only be send to the usb-host when no data
+packets are pending on the device / interface / endpoint affected by the
+control packet. Any pending data packets will get dropped, and any active
+iso streams / allocated bulk streams will get stopped / free-ed.
+
+
+### Packet type list
+
+#### control packets
+- `usb_redir_hello`
+- `usb_redir_device_connect`
+- `usb_redir_device_disconnect`
+- `usb_redir_reset`
+- `usb_redir_interface_info`
+- `usb_redir_ep_info`
+- `usb_redir_set_configuration`
+- `usb_redir_get_configuration`
+- `usb_redir_configuration_status`
+- `usb_redir_set_alt_setting`
+- `usb_redir_get_alt_setting`
+- `usb_redir_alt_setting_status`
+- `usb_redir_start_iso_stream`
+- `usb_redir_stop_iso_stream`
+- `usb_redir_iso_stream_status`
+- `usb_redir_start_interrupt_receiving`
+- `usb_redir_stop_interrupt_receiving`
+- `usb_redir_interrupt_receiving_status`
+- `usb_redir_alloc_bulk_streams`
+- `usb_redir_free_bulk_streams`
+- `usb_redir_bulk_streams_status`
+- `usb_redir_cancel_data_packet`
+- `usb_redir_filter_reject`
+- `usb_redir_filter_filter`
+- `usb_redir_device_disconnect_ack`
+- `usb_redir_start_bulk_receiving`
+- `usb_redir_stop_bulk_receiving`
+- `usb_redir_bulk_receiving_status`
+
+#### data packets
+- `usb_redir_control_packet`
+- `usb_redir_bulk_packet`
+- `usb_redir_iso_packet`
+- `usb_redir_interrupt_packet`
+- `usb_redir_buffered_bulk_packet`
+
+### Status code list
+
+Many usb-host replies have a status field, this field can have the following
+values:
+
+```c
+enum {
+ usb_redir_success,
+ usb_redir_cancelled, /* The transfer was cancelled */
+ usb_redir_inval, /* Invalid packet type / length / ep, etc. */
+ usb_redir_ioerror, /* IO error */
+ usb_redir_stall, /* Stalled */
+ usb_redir_timeout, /* Request timed out */
+ usb_redir_babble, /* The device has "babbled" */
+};
+```
+
+Note that in future versions there may be additional status codes to signal
+new / other *error* conditions. So any unknown status value should be
+interpreted as an error.
+
+
+## usb_redir_hello
+
+```
+usb_redir_header.type: usb_redir_hello
+usb_redir_header.length: <see description>
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+```c
+struct usb_redir_hello_header {
+ char version[64];
+ uint32_t capabilities[0];
+}
+```
+
+No packet type specific additional data.
+
+A packet of this type is send by both sides as soon as a connection is
+establised. It is mandatory that this packet is the first packet send by
+both sides! This packet contains:
+- version: A free form 0 terminated version string, useful for logging
+ should not be parsed! Suggested format: "qemu 0.13",
+ "usb-redir-daemon 0.1", etc.
+- capabilities: A variable length array for announcing capabilities.
+
+Note that since the peer caps are not known until the `usb_redir_hello`
+packet is received, the hello packet always has 32 bits id fields!
+
+The value of the length field depends on the size of the capabilities array.
+If we cross the 32 capabilities count, it will go from 1 `uint32_t` to 2,
+etc. the value is `64 + capabilities-array-size * sizeof(uint32_t)`.
+
+Currently the following capabilities are defined:
+
+```c
+enum {
+ /* Supports USB 3 bulk streams */
+ usb_redir_cap_bulk_streams,
+ /* The device_connect packet has the device_version_bcd field */
+ usb_redir_cap_connect_device_version,
+ /* Supports usb_redir_filter_reject and usb_redir_filter_filter pkts */
+ usb_redir_cap_filter,
+ /* Supports the usb_redir_device_disconnect_ack packet */
+ usb_redir_cap_device_disconnect_ack,
+ /* The ep_info packet has the max_packet_size field */
+ usb_redir_cap_ep_info_max_packet_size,
+ /* Supports 64 bits ids in usb_redir_header */
+ usb_redir_cap_64bits_ids,
+ /* Supports 32 bits length in usb_redir_bulk_packet_header */
+ usb_redir_cap_32bits_bulk_length,
+ /* Supports bulk receiving / buffered bulk input */
+ usb_redir_cap_bulk_receiving,
+};
+```
+
+## usb_redir_device_connect
+
+```
+usb_redir_header.type: usb_redir_device_connect
+usb_redir_header.length: sizeof(usb_redir_device_connect_header)
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+```c
+enum {
+ usb_redir_speed_low,
+ usb_redir_speed_full,
+ usb_redir_speed_high,
+ usb_redir_speed_super,
+ usb_redir_speed_unknown = 255
+}
+
+struct usb_redir_device_connect_header {
+ uint8_t speed;
+ uint8_t device_class;
+ uint8_t device_subclass;
+ uint8_t device_protocol;
+ uint16_t vendor_id;
+ uint16_t product_id;
+ uint16_t device_version_bcd;
+}
+```
+
+No packet type specific additional data.
+
+This packet gets send by the usb-host when a device becomes available (it is
+possible for the usb-host to wait for a device to get plugged in).
+
+The `device_version_bcd` field should only be send (and expected on receive)
+when both sides have the `usb_redir_cap_connect_device_version` capability.
+If this is not the case the length of the packet will be 2 bytes less!
+
+Note that a usb-host may re-use the existing connection for a new / re-plugged
+device in this case this packet can be send after a `usb_redir_device_disconnect`
+message to notify the usb-guest that a new device is available.
+
+Note the usbredir-host *must* first send `usb_redir_ep_info` followed by
+`usb_redir_interface_info` before sending the `usb_redir_device_connect_info`!
+
+## usb_redir_device_disconnect
+
+```
+usb_redir_header.type: usb_redir_device_disconnect
+usb_redir_header.length: 0
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet may be send by the usb-host to indicate that the device has been
+disconnect (unplugged). Note on some platforms the usb-host may not become
+aware of the disconnection until a usb packet is send to the device.
+
+## usb_redir_reset
+
+```
+usb_redir_header.type: usb_redir_reset
+usb_redir_header.length: 0
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to cause a reset of the usb
+device. Note that of things go wrong the usb-host may be unable to re-connect
+to the device after the reset! If this happens a `usb_redir_device_disconnect`
+packet will be send by the usb-host.
+
+## usb_redir_interface_info
+
+```
+usb_redir_header.type: usb_redir_interface_info
+usb_redir_header.length: sizeof(usb_redir_interface_info_header)
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+```c
+struct usb_redir_interface_info_header {
+ uint32_t interface_count;
+ uint8_t interface[32];
+ uint8_t interface_class[32];
+ uint8_t interface_subclass[32];
+ uint8_t interface_protocol[32];
+}
+```
+
+No packet type specific additional data.
+
+This packet gets send by the usb-host to inform the usb-guest about the
+interfaces of the device. It contains the interface number, class and protocol
+info for `interface_count` interfaces. This gets send after a (successful)
+initial connection, `set_config` and `set_alt_setting`.
+
+## usb_redir_ep_info
+
+```
+usb_redir_header.type: usb_redir_ep_info
+usb_redir_header.length: sizeof(usb_redir_ep_info_header)
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+```c
+enum {
+ /* Note these 4 match the usb spec! */
+ usb_redir_type_control,
+ usb_redir_type_iso,
+ usb_redir_type_bulk,
+ usb_redir_type_interrupt,
+ usb_redir_type_invalid = 255
+}
+
+struct usb_redir_ep_info_header {
+ uint8_t type[32];
+ uint8_t interval[32];
+ uint8_t interface[32];
+ uint16_t max_packet_size[32];
+ uint32_t max_streams[32];
+}
+```
+
+No packet type specific additional data.
+
+This packet gets send by the usb-host to let the usb-guest know the endpoint
+type, interval and interface it belongs to for all possible endpoints,
+first 0-15 out, then 0-15 in. This gets send after a (successful) initial
+connection, `set_config` and `set_alt_setting`.
+
+The `max_packet_size` field should only be send (and expected on receive)
+when both sides have the `usb_redir_cap_ep_info_max_packet_size` capability.
+If this is not the case the length of the packet will be 64 bytes less!
+
+The `max_streams` field should only be send (and expected on receive)
+when both sides have the `usb_redir_cap_bulk_streams` capability. If this is
+not the case the length of the packet will be 128 bytes less!
+
+Note implementations with the `usb_redir_cap_bulk_streams` capability must
+always also have the `usb_redir_cap_ep_info_max_packet_size` capability.
+Advertising `usb_redir_cap_bulk_streams` without
+`usb_redir_cap_ep_info_max_packet_size` is not allowed!
+
+
+## usb_redir_set_configuration
+
+```
+usb_redir_header.type: usb_redir_set_configuration
+usb_redir_header.length: sizeof(usb_redir_set_configuration_header)
+```
+
+```c
+struct usb_redir_set_configuration_header {
+ uint8_t configuration;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to set (change) the active
+configuration of the usb-device.
+
+## usb_redir_get_configuration
+
+```
+usb_redir_header.type: usb_redir_get_configuration
+usb_redir_header.length: 0
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to get (query) the active
+configuration of the usb-device.
+
+## usb_redir_configuration_status
+
+```
+usb_redir_header.type: usb_redir_configuration_status
+usb_redir_header.length: sizeof(usb_redir_configuration_status_header)
+```
+
+```c
+struct usb_redir_configuration_status_header {
+ uint8_t status;
+ uint8_t configuration;
+}
+```
+
+No packet type specific additional data.
+
+This is send by the usb-host in response to a `usb_redir_set_configuration` /
+`usb_redir_get_configuration` packet. It reports a status code and on success
+the resulting / active configuration.
+
+Note that after a successful `usb_redir_set_configuration` command the
+usbredir-host *must* first send `usb_redir_ep_info` followed by
+`usb_redir_interface_info` before sending the `usb_redir_configuration_status`,
+to ensure the usb-guest has the new info when it starts using the new
+configuration.
+
+
+## usb_redir_set_alt_setting
+
+```
+usb_redir_header.type: usb_redir_set_alt_setting
+usb_redir_header.length: sizeof(usb_redir_set_alt_setting_header)
+```
+
+```c
+struct usb_redir_set_alt_setting_header {
+ uint8_t interface;
+ uint8_t alt;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to set (change) the `alt_setting` of
+interface `<interface>` to `<alt>`.
+
+## usb_redir_get_alt_setting
+
+```
+usb_redir_header.type: usb_redir_get_alt_setting
+usb_redir_header.length: sizeof(usb_redir_get_alt_setting_header)
+```
+
+```c
+struct usb_redir_get_alt_setting_header {
+ uint8_t interface;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to get (query) the active
+`alt_setting` of an interface of the usb-device.
+
+## usb_redir_alt_setting_status
+
+```
+usb_redir_header.type: usb_redir_alt_setting_status
+usb_redir_header.length: sizeof(usb_redir_alt_setting_status_header)
+```
+
+```c
+struct usb_redir_alt_setting_status_header {
+ uint8_t status;
+ uint8_t interface;
+ uint8_t alt;
+}
+```
+
+No packet type specific additional data.
+
+This is send by the usb-host in response to a `usb_redir_set_alt_setting` /
+`usb_redir_get_alt_setting` packet. It reports a status code, the affected
+interface and on success the resulting / active `alt_setting` for that interface.
+
+Note that after a successful `usb_redir_set_alt_setting` command the
+usbredir-host *must* first send `usb_redir_ep_info` followed by
+`usb_redir_interface_info` before sending the `usb_redir_alt_setting_status`,
+to ensure the usb-guest has the new info when it starts using the new
+alt setting.
+
+
+## usb_redir_start_iso_stream
+
+```
+usb_redir_header.type: usb_redir_start_iso_stream
+usb_redir_header.length: sizeof(usb_redir_start_iso_stream_header)
+```
+
+```c
+struct usb_redir_start_iso_stream_header {
+ uint8_t endpoint;
+ uint8_t pkts_per_urb;
+ uint8_t no_urbs;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to start a iso stream on the
+designated endpoint of the usb-device.
+
+This function allocates `no_urbs` urbs with `pkts_per_urb` iso packets/frames
+per urb. For iso input endpoints these urbs will get submitted to the
+device *immediately*, for iso output endpoints the usb-host will wait till
+it has received `(pkts_per_urb * no_urbs / 2)` packets to fill its buffers,
+before submitting the first urb.
+
+## usb_redir_stop_iso_stream
+
+```
+usb_redir_header.type: usb_redir_stop_iso_stream
+usb_redir_header.length: sizeof(struct usb_redir_start_iso_stream_header)
+```
+
+```c
+struct usb_redir_stop_iso_stream_header {
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to stop an iso stream on the
+designated endpoint. This will cancel all pending urbs, flush the usb-host's
+buffers and free all relevant resources. Note that the usb-guest can still
+receive isoc data packets from an isoc in endpoint after sending this, as
+some data packets may already be inside the transport pipe.
+
+## usb_redir_iso_stream_status
+
+```
+usb_redir_header.type: usb_redir_iso_stream_status
+usb_redir_header.length: sizeof(usb_redir_iso_stream_status_header)
+```
+
+```c
+struct usb_redir_iso_stream_status_header {
+ uint8_t status;
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet is send by the usb-host in response to a
+`usb_redir_start_iso_stream` or `usb_redir_stop_iso_stream` packet. Note that
+for the starting of output iso streams a success status only indicates that
+all the buffers were successfully allocated, the actual stream is not
+started until enough packets are buffered.
+
+Note that this can also be send unsolicited by a usb-host in case of an
+error with an iso output stream, see `usb_redir_iso_packet`.
+
+To allow the usb-guest to detect if the stream was adversely stopped, the
+usb-host will always report `usb_redir_stall` as status if the stream was
+stopped for any reason other then an `usb_redir_stop_iso_stream`.
+
+
+## usb_redir_start_interrupt_receiving
+
+```
+usb_redir_header.type: usb_redir_start_interrupt_receiving
+usb_redir_header.length: sizeof(usb_redir_start_interrupt_receiving_header)
+```
+
+```c
+struct usb_redir_start_interrupt_receiving_header {
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to start receiving interrupts
+from the designated endpoint of the usb-device.
+
+This function is for *input* interrupt endpoints only. Input interrupt
+endpoints need to be polled timely otherwise data may get lost. So for
+input interrupt endpoints the usb-host takes care of the submitting and
+re-submitting of urbs.
+
+On receiving this packet the usb-host will start an interrupt transfer
+to the endpoint using the interval and `maxPacketSize` from the descriptors.
+When this transfer completes, the usb-host will send an
+`usb_redir_interrupt_packet` to the usb-guest, and will re-submit the urb.
+
+## usb_redir_stop_interrupt_receiving
+
+```
+usb_redir_header.type: usb_redir_stop_interrupt_receiving
+usb_redir_header.length: sizeof(struct usb_redir_start_interrupt_receiving_header)
+```
+
+```c
+struct usb_redir_stop_interrupt_receiving_header {
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to stop interrupt receiving on the
+designated endpoint. This will cancel the pending urb. Note that the usb-guest
+can still receive `usb_redir_interrupt_packet-s` after sending this, as
+some data packets may already be inside the transport pipe.
+
+## usb_redir_interrupt_receiving_status
+
+```
+usb_redir_header.type: usb_redir_interrupt_receiving_status
+usb_redir_header.length: sizeof(usb_redir_interrupt_receiving_status_header)
+```
+
+```c
+struct usb_redir_interrupt_receiving_status_header {
+ uint8_t status;
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet is send by the usb-host in response to a
+`usb_redir_start_interrupt_receiving` or `usb_redir_stop_interrupt_receiving`
+packet.
+
+Note that this can also be send unsolicited by a usb-host in case of an
+error re-submitting the interrupt urb.
+
+To allow the usb-guest to detect if the stream was adversely stopped, the
+usb-host will always report `usb_redir_stall` as status if the stream was
+stopped for any reason other then an `usb_redir_stop_interrupt_receiving`.
+
+
+## usb_redir_alloc_bulk_streams
+
+```
+usb_redir_header.type: usb_redir_alloc_bulk_streams
+usb_redir_header.length: sizeof(usb_redir_alloc_bulk_streams_header)
+```
+
+```c
+struct usb_redir_alloc_bulk_streams_header {
+ uint32_t endpoints; /* bitmask indicating on which eps to alloc streams */
+ uint32_t no_streams;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to the usb-host to request
+that the usb-host allocates IDs so the usb-guest can use up to `no_streams`
+stream IDs on the endpoints indicated by the `endpoints` bitmask. Endpoints in
+the bitmask are indicated by bit number (0-31) using the same numbering as
+in `usb_redir_ep_info_header`.
+
+## usb_redir_free_bulk_streams
+
+```
+usb_redir_header.type: usb_redir_free_bulk_streams
+usb_redir_header.length: sizeof(usb_redir_free_bulk_streams_header)
+```
+
+```c
+struct usb_redir_free_bulk_streams_header {
+ uint32_t endpoints; /* bitmask indicating on which eps to free streams */
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to the usb-host to free any
+bulk streams previously allocated on the endpoints indicated by the
+endpoints bitmask.
+
+## usb_redir_bulk_streams_status
+
+```
+usb_redir_header.type: usb_redir_bulk_streams_status
+usb_redir_header.length: sizeof(usb_redir_bulk_streams_status_header)
+```
+
+```c
+struct usb_redir_bulk_streams_status_header {
+ uint32_t endpoints; /* bitmask indicating eps this status message is for */
+ uint32_t no_streams;
+ uint8_t status;
+}
+```
+
+No packet type specific additional data.
+
+This packet is send by the usb-host in response to a
+`usb_redir_alloc_bulk_streams` or `usb_redir_free_bulk_streams` packet.
+
+For `usb_redir_alloc_bulk_streams` responses `no_streams` will be the `no_streams`
+passed to the `usb_redir_alloc_bulk_streams` packet. usb-hosts are not allowed
+to return less streams then requested! For `usb_redir_free_bulk_streams`
+responses `no_streams` will be 0.
+
+On a success status in response to a `usb_redir_alloc_bulk_streams`
+the usb-guest may use stream ids 1 through `no_streams`.
+
+
+## usb_redir_start_bulk_receiving
+
+```
+usb_redir_header.type: usb_redir_start_bulk_receiving
+usb_redir_header.length: sizeof(usb_redir_start_bulk_receiving_header)
+```
+
+```c
+struct usb_redir_start_bulk_receiving_header {
+ uint32_t stream_id;
+ uint32_t bytes_per_transfer;
+ uint8_t endpoint;
+ uint8_t no_transfers;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to start buffered reading from a
+bulk endpoint.
+
+Upon receiving this packet the usb-host will submit `no_transfers` bulk in
+transfer of `bytes_per_transfer` each to the designated endpoint of the
+usb-device. Upon completion of a transfer the usb-host will send an
+`usb_redir_buffered_bulk_packet` with the received data to the usb-guest,
+and immediately re-submit the completed transfer.
+
+Note `bytes_per_transfer` must be a multiple of the endpoints `max_packet_size`.
+
+Note this packet should only be send to usb-hosts with the
+`usb_redir_cap_bulk_receiving` capability.
+
+## usb_redir_stop_bulk_receiving
+
+```
+usb_redir_header.type: usb_redir_stop_bulk_receiving
+usb_redir_header.length: sizeof(usb_redir_stop_bulk_receiving_header)
+```
+
+```c
+struct usb_redir_stop_bulk_receiving_header {
+ uint32_t stream_id;
+ uint8_t endpoint;
+}
+```
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to stop bulk receiving on the
+designated endpoint. This will cancel all pending transfers. Note that the
+usb-guest can still receive `usb_redir_bulk_packet-s` after sending this, as
+some data packets may already be inside the transport pipe.
+
+Note this packet should only be send to usb-hosts with the
+`usb_redir_cap_bulk_receiving` capability.
+
+## usb_redir_bulk_receiving_status
+
+```
+usb_redir_header.type: usb_redir_bulk_receiving_status
+usb_redir_header.length: sizeof(usb_redir_bulk_receiving_status_header)
+```
+
+```c
+struct usb_redir_bulk_receiving_status_header {
+ uint32_t stream_id;
+ uint8_t endpoint;
+ uint8_t status;
+}
+```
+
+No packet type specific additional data.
+
+This packet is send by the usb-host in response to a
+`usb_redir_start_bulk_receiving` or `usb_redir_stop_bulk_receiving` packet.
+
+Note that this can also be send unsolicited by an usb-host in case of an
+error re-submitting the bulk transfer.
+
+To allow the usb-guest to detect if the stream was adversely stopped, the
+usb-host will always report `usb_redir_stall` as status if the stream was
+stopped for any reason other then an `usb_redir_stop_interrupt_receiving`.
+
+Note this packet should only be send to usb-guests with the
+`usb_redir_cap_bulk_receiving` capability.
+
+
+## usb_redir_cancel_data_packet
+
+```
+usb_redir_header.type: usb_redir_cancel_data_packet
+usb_redir_header.id <id of packet to cancel>
+usb_redir_header.length: 0
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet can be send by the usb-guest to cancel an earlier send data
+packet, the id should be set to the id used when sending the packet the
+guest now wishes to cancel.
+
+Note that the usb-guest will always receive back a data packet of the same type
+and with the same id, the usb-guest can check if the packet completed
+normally (before the cancel packet was processed by the usb-host), or was
+cancelled by looking at the return data packet's status field.
+
+## usb_redir_filter_reject
+
+```
+usb_redir_header.type: usb_redir_filter_reject
+usb_redir_header.length: 0
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet is send by the usb-guest after receiving a `usb_redir_device_connect`
+or `usb_redir_interface_info` packet which was rejected by an usb-guest side
+device filter. This packet should only be send to usb-hosts with the
+`usb_redir_cap_filter` capability.
+
+## usb_redir_filter_filter
+
+```
+usb_redir_header.type: usb_redir_filter_filter
+usb_redir_header.length: string-length + 1 (for 0 termination)
+usb_redir_header.id: 0 (always as this is an unsolicited packet)
+```
+
+No packet type specific header.
+
+The additional data contains a 0 terminated usredirfilter string.
+
+This packet can be send directly after the hello packet to inform the other
+side that a filter is in place and some devices may be rejected.
+
+An usredirfilter consists of one or more rules, where in string form each rule
+has the following format:
+ `<class>,<vendor>,<product>,<version>,<allow>`
+
+Values can be either in decimal format, or in hexadecimal format pre-fixed
+with 0x, a value of -1 can be used to allow any value.
+
+All rules of a filter are concatenated, separated by the '|' character
+to form a single usredirfilter string:
+ `<rule1>|<rule2>|<rule3>`
+
+If a device matches none of the rules the result of the filter is deny and
+the device will be rejected.
+
+For more info on filtering see usbredirfilter.h
+
+This packet should only be send to peers with the `usb_redir_cap_filter`
+capability.
+
+## usb_redir_device_disconnect_ack
+
+```
+usb_redir_header.type: usb_redir_device_disconnect_ack
+usb_redir_header.length: 0
+usb_redir_header.id: 0 (as the id of the device_disconnect is always 0)
+```
+
+No packet type specific header.
+
+No packet type specific additional data.
+
+This packet is send by the usb-guest after having processed a
+`usb_redir_device_disconnect` packet send by the usb-host. This allows an
+usb-host which wants to re-use an existing connection to know that the
+usb-guest has seen the disconnect and will not send any more packets intended
+for the disconnected device. Without this there is a race where the usb-host
+may have a new device available, but it is still receiving packets intended for
+the old device as the usb-guest has not yet seen the disconnect.
+
+Note this packet is only send if both sides have the
+`usb_redir_cap_device_disconnect_ack` capability.
+
+
+## usb_redir_control_packet
+
+```
+usb_redir_header.type: usb_redir_control_packet
+usb_redir_header.length: sizeof(usb_redir_control_packet_header) [+ length]
+```
+
+```c
+struct usb_redir_control_packet_header {
+ uint8_t endpoint;
+ uint8_t request;
+ uint8_t requesttype;
+ uint8_t status;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+}
+```
+
+The additional data contains the control msg data to be send / received.
+
+Packets of this type can be send by the usb-guest to the usb-host to
+initiate a control transfer on the usb-device. endpoint, request, requesttype,
+value and index have their standard meaning for usb control messages.
+The status field is only used in the usb-host's response.
+
+length is the amount of data the usb-guest is sending / expects to read
+(in the USB_DIR_IN case). Note that the length should only be added
+to `usb_redir_header.length` in one direction (and the actual packet
+length should match).
+
+When the control msg has been processed by the usb-device the usb-host sends
+a `usb_redir_control_packet` back to the usb-guest, with all fields unchanged
+except for the status field and length which get updated to match the
+actual results.
+
+
+## usb_redir_bulk_packet
+
+```
+usb_redir_header.type: usb_redir_bulk_packet
+usb_redir_header.length: sizeof(usb_redir_bulk_packet_header) [+ length]
+```
+
+```c
+struct usb_redir_bulk_packet_header {
+ uint8_t endpoint;
+ uint8_t status;
+ uint16_t length;
+ uint32_t stream_id;
+ uint16_t length_high; /* High 16 bits of the packet length */
+}
+```
+
+The additional data contains the bulk msg data to be send / received.
+
+Packets of this type can be send by the usb-guest to the usb-host to
+initiate a bulk transfer on the usb-device. `endpoint` and `stream_id` have
+their standard meaning for usb bulk messages. The `status` field is only used
+in the usb-host's response. `length` is the amount of data the usb-guest is
+sending / expects to read (depending on the direction of the endpoint).
+
+`length_high` contains the 16 high bits of length to allow packets larger
+then 65535 bytes, it is only send/received if both sides have the
+`usb_redir_cap_32bits_bulk_length` capability.
+
+When the bulk msg has been processed by the usb-device the usb-host sends
+a `usb_redir_bulk_packet` back to the usb-guest, with the `status` field and
+length updated to match the actual results.
+
+Note just as `usb_redir_control_packet` this packet only has additional data
+in one direction depending on the direction of the endpoint.
+
+Note see `usb_redir_buffered_bulk_packet` for an alternative for receiving data
+from bulk endpoints.
+
+
+## usb_redir_iso_packet
+
+```
+usb_redir_header.type: usb_redir_iso_packet
+usb_redir_header.length: sizeof(usb_redir_iso_packet_header) + length
+```
+
+```c
+struct usb_redir_iso_packet_header {
+ uint8_t endpoint;
+ uint8_t status;
+ uint16_t length;
+}
+```
+
+The additional data contains the iso msg data to be send / received.
+
+Packets of this type should be send continuesly (at the endpoint interval
+speed) as soon as an iso stream is started using `usb_redir_start_iso_stream`
+the direction in which they gets send depends on the endpoints direction.
+
+The status field only has meaning for packets send from the usb-host to
+the usb-guest (for iso input endpoints). Due to buffering it is not possibly
+to timely notify the usb-guest of transfer errors for iso output packets. The
+usb-host will try to clear any error conditions itself. If it fails to do
+so it will send a `usb_redir_iso_stream_status` to the usb-guest indicating
+there is a problem with the iso stream.
+
+Since `usb_redir_iso_packet`s are send continuously by the usb-host once
+a stream is started on an iso input endpoint, the usb-host cannot set the
+`usb_redir_header.id` to the id of the corresponding received packet. So for
+`usb_redir_iso_packet's` the usb-host simply starts with an id of 0 and
+increments this every packet. Note that when the usb-host has recovered from
+a stall the id will restart at 0!
+
+
+## usb_redir_interrupt_packet
+
+```
+usb_redir_header.type: usb_redir_interrupt_packet
+usb_redir_header.length: sizeof(usb_redir_interrupt_packet_header) [+ length]
+```
+
+```c
+struct usb_redir_interrupt_packet_header {
+ uint8_t endpoint;
+ uint8_t status;
+ uint16_t length;
+}
+```
+
+The additional data contains the interrupt msg data to be send / received.
+
+The handling of interrupt endpoints differs significantly depending on wether
+the endpoint is an input or output endpoint.
+
+# Input endpoints
+
+Input interrupt endpoints need to
+be polled timely otherwise data may get lost. So for input interrupt endpoints
+the usb-host takes care of the submitting and re-submitting of urbs, the
+usb-guest can start / stop the receiving of interrupt packets using the
+`usb_redir_start_interrupt_receiving` / `usb_redir_stop_interrupt_receiving`
+packets. Note that for an input interrupt endpoint `usb_redir_interrupt_packet-s`
+are only send in one direction, from the usb-host to the usb-guest!
+
+Since `usb_redir_interrupt_packet`s are send unsolicited by the usb-host once
+interrupt receiving has started, the usb-host cannot set the
+`usb_redir_header.id` to the id of the corresponding received packet. So for
+`usb_redir_interrupt_packet`s the usb-host simply starts with an id of 0 and
+increments this every packet. Note that when the usb-host has recovered from
+a stall the id will restart at 0!
+
+# Output endpoints
+
+For interrupt output endpoints the normal asynchroneous mechanism also used
+for control and bulk transfers is used:
+
+The usb-guest sends a `usb_redir_interrupt_packet` to the usb-host. When the
+interrupt msg has been processed by the usb-device the usb-host sends
+a `usb_redir_interrupt_packet` back to the usb-guest, with the status field and
+length updated to match the actual results. This packet only has additional
+data (the data to output) when send from usb-guest to usb-host.
+
+Note that since unlike with iso data there is usually no notion of a stream
+with interrupt data, buffering makes no sense for output interrupt packets,
+instead they are delivered asap. Despite this asap delivery it is likely
+that the timing constraints which apply to interrupt output transfers will
+not be met. The consequences of this will vary from device to device.
+
+
+## usb_redir_buffered_bulk_packet
+
+```
+usb_redir_header.type: usb_redir_bulk_packet
+usb_redir_header.length: sizeof(usb_redir_bulk_packet_header) + length
+usb_redir_header.id: starts at 0, incremented by 1 per send packet
+```
+
+```c
+struct usb_redir_buffered_bulk_packet_header {
+ uint32_t stream_id;
+ uint32_t length;
+ uint8_t endpoint;
+ uint8_t status;
+}
+```
+
+The additional data contains the bulk msg data received.
+
+Buffered bulk mode is intended for bulk *input* endpoints, where the data is
+of a streaming nature (not part of a command-response protocol). These
+endpoints' input buffer may overflow if data is not read quickly enough.
+So in buffered bulk mode the usb-host takes care of the submitting and
+re-submitting of bulk transfers. The usb-guest can start / stop the receiving
+of buffered bulk data using the `usb_redir_start_bulk_receiving` /
+`usb_redir_stop_bulk_receiving` packets.
+
+Note that `usb_redir_buffered_bulk_packet-s` are only send in one direction,
+from the usb-host to the usb-guest!
+
+Since `usb_redir_buffered_bulk_packet-s` are send unsolicited by the usb-host
+once bulk receiving has started, the usb-host cannot set the
+`usb_redir_header.id` to the id of the corresponding received packet. So for
+`usb_redir_buffered_bulk_packet-s` the usb-host simply starts with an id of 0 and
+increments this every packet. Note that when the usb-host has recovered from
+a stall the id will restart at 0!
+
+A typical example where buffered bulk mode should be used is with the bulk in
+endpoints of usb to serial convertors.
+
+Note buffered bulk mode can only be used when both sides have the
+`usb_redir_cap_bulk_receiving` capability.