2008-07-18 00:47:13 +04:00
|
|
|
/*
|
|
|
|
* QEMU USB Net devices
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Thomas Sailer
|
|
|
|
* Copyright (c) 2008 Andrzej Zaborowski
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:17:12 +03:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2019-08-12 08:23:51 +03:00
|
|
|
#include "hw/qdev-properties.h"
|
2012-03-07 17:55:18 +04:00
|
|
|
#include "hw/usb.h"
|
2019-08-12 08:23:45 +03:00
|
|
|
#include "migration/vmstate.h"
|
2018-05-03 22:50:48 +03:00
|
|
|
#include "desc.h"
|
2012-10-24 10:43:34 +04:00
|
|
|
#include "net/net.h"
|
2014-09-19 10:48:25 +04:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/queue.h"
|
|
|
|
#include "qemu/config-file.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/sysemu.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/iov.h"
|
2019-05-23 17:35:07 +03:00
|
|
|
#include "qemu/module.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/cutils.h"
|
2020-09-03 23:43:22 +03:00
|
|
|
#include "qom/object.h"
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
/*#define TRAFFIC_DEBUG*/
|
|
|
|
/* Thanks to NetChip Technologies for donating this product ID.
|
|
|
|
* It's for devices with only CDC Ethernet configurations.
|
|
|
|
*/
|
|
|
|
#define CDC_VENDOR_NUM 0x0525 /* NetChip */
|
|
|
|
#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
|
|
|
|
/* For hardware that can talk RNDIS and either of the above protocols,
|
|
|
|
* use this ID ... the windows INF files will know it.
|
|
|
|
*/
|
|
|
|
#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
|
|
|
|
#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
|
|
|
|
|
|
|
|
enum usbstring_idx {
|
|
|
|
STRING_MANUFACTURER = 1,
|
|
|
|
STRING_PRODUCT,
|
|
|
|
STRING_ETHADDR,
|
|
|
|
STRING_DATA,
|
|
|
|
STRING_CONTROL,
|
|
|
|
STRING_RNDIS_CONTROL,
|
|
|
|
STRING_CDC,
|
|
|
|
STRING_SUBSET,
|
|
|
|
STRING_RNDIS,
|
|
|
|
STRING_SERIALNUMBER,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEV_CONFIG_VALUE 1 /* CDC or a subset */
|
|
|
|
#define DEV_RNDIS_CONFIG_VALUE 2 /* RNDIS; optional */
|
|
|
|
|
|
|
|
#define USB_CDC_SUBCLASS_ACM 0x02
|
|
|
|
#define USB_CDC_SUBCLASS_ETHERNET 0x06
|
|
|
|
|
|
|
|
#define USB_CDC_PROTO_NONE 0
|
|
|
|
#define USB_CDC_ACM_PROTO_VENDOR 0xff
|
|
|
|
|
|
|
|
#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
|
|
|
|
#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
|
|
|
|
#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
|
|
|
|
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
|
|
|
|
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
|
|
|
|
|
|
|
|
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
|
|
|
|
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
|
|
|
|
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
|
|
|
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
|
|
|
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
|
|
|
#define USB_CDC_REQ_SEND_BREAK 0x23
|
|
|
|
#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
|
|
|
|
#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
|
|
|
|
#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
|
|
|
|
#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
|
|
|
|
#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
|
|
|
|
|
2022-09-06 21:30:53 +03:00
|
|
|
#define USB_CDC_NETWORK_CONNECTION 0x00
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
|
|
|
|
#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
|
|
|
|
|
|
|
|
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
|
|
|
|
|
2010-11-26 12:25:06 +03:00
|
|
|
static const USBDescStrings usb_net_stringtable = {
|
|
|
|
[STRING_MANUFACTURER] = "QEMU",
|
|
|
|
[STRING_PRODUCT] = "RNDIS/QEMU USB Network Device",
|
|
|
|
[STRING_ETHADDR] = "400102030405",
|
|
|
|
[STRING_DATA] = "QEMU USB Net Data Interface",
|
|
|
|
[STRING_CONTROL] = "QEMU USB Net Control Interface",
|
|
|
|
[STRING_RNDIS_CONTROL] = "QEMU USB Net RNDIS Control Interface",
|
|
|
|
[STRING_CDC] = "QEMU USB Net CDC",
|
|
|
|
[STRING_SUBSET] = "QEMU USB Net Subset",
|
|
|
|
[STRING_RNDIS] = "QEMU USB Net RNDIS",
|
|
|
|
[STRING_SERIALNUMBER] = "1",
|
2008-07-18 00:47:13 +04:00
|
|
|
};
|
|
|
|
|
2010-11-26 12:25:06 +03:00
|
|
|
static const USBDescIface desc_iface_rndis[] = {
|
|
|
|
{
|
|
|
|
/* RNDIS Control Interface */
|
|
|
|
.bInterfaceNumber = 0,
|
|
|
|
.bNumEndpoints = 1,
|
|
|
|
.bInterfaceClass = USB_CLASS_COMM,
|
|
|
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
|
|
|
.bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
|
|
|
|
.iInterface = STRING_RNDIS_CONTROL,
|
|
|
|
.ndesc = 4,
|
|
|
|
.descs = (USBDescOther[]) {
|
|
|
|
{
|
|
|
|
/* Header Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x05, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x10, 0x01, /* le16 bcdCDC */
|
|
|
|
},
|
|
|
|
},{
|
|
|
|
/* Call Management Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x05, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x00, /* u8 bmCapabilities */
|
|
|
|
0x01, /* u8 bDataInterface */
|
|
|
|
},
|
|
|
|
},{
|
|
|
|
/* ACM Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x04, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x00, /* u8 bmCapabilities */
|
|
|
|
},
|
|
|
|
},{
|
|
|
|
/* Union Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x05, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x00, /* u8 bMasterInterface0 */
|
|
|
|
0x01, /* u8 bSlaveInterface0 */
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.eps = (USBDescEndpoint[]) {
|
|
|
|
{
|
|
|
|
.bEndpointAddress = USB_DIR_IN | 0x01,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
|
|
|
.wMaxPacketSize = STATUS_BYTECOUNT,
|
|
|
|
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},{
|
|
|
|
/* RNDIS Data Interface */
|
|
|
|
.bInterfaceNumber = 1,
|
|
|
|
.bNumEndpoints = 2,
|
|
|
|
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
|
|
|
.iInterface = STRING_DATA,
|
|
|
|
.eps = (USBDescEndpoint[]) {
|
|
|
|
{
|
|
|
|
.bEndpointAddress = USB_DIR_IN | 0x02,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
|
.wMaxPacketSize = 0x40,
|
|
|
|
},{
|
|
|
|
.bEndpointAddress = USB_DIR_OUT | 0x02,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
|
.wMaxPacketSize = 0x40,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
};
|
|
|
|
|
2010-11-26 12:25:06 +03:00
|
|
|
static const USBDescIface desc_iface_cdc[] = {
|
|
|
|
{
|
|
|
|
/* CDC Control Interface */
|
|
|
|
.bInterfaceNumber = 0,
|
|
|
|
.bNumEndpoints = 1,
|
|
|
|
.bInterfaceClass = USB_CLASS_COMM,
|
|
|
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
|
|
|
|
.bInterfaceProtocol = USB_CDC_PROTO_NONE,
|
|
|
|
.iInterface = STRING_CONTROL,
|
|
|
|
.ndesc = 3,
|
|
|
|
.descs = (USBDescOther[]) {
|
|
|
|
{
|
|
|
|
/* Header Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x05, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x10, 0x01, /* le16 bcdCDC */
|
|
|
|
},
|
|
|
|
},{
|
|
|
|
/* Union Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x05, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
0x00, /* u8 bMasterInterface0 */
|
|
|
|
0x01, /* u8 bSlaveInterface0 */
|
|
|
|
},
|
|
|
|
},{
|
|
|
|
/* Ethernet Descriptor */
|
|
|
|
.data = (uint8_t[]) {
|
|
|
|
0x0d, /* u8 bLength */
|
|
|
|
USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
|
|
|
|
USB_CDC_ETHERNET_TYPE, /* u8 bDescriptorSubType */
|
|
|
|
STRING_ETHADDR, /* u8 iMACAddress */
|
|
|
|
0x00, 0x00, 0x00, 0x00, /* le32 bmEthernetStatistics */
|
|
|
|
ETH_FRAME_LEN & 0xff,
|
|
|
|
ETH_FRAME_LEN >> 8, /* le16 wMaxSegmentSize */
|
|
|
|
0x00, 0x00, /* le16 wNumberMCFilters */
|
|
|
|
0x00, /* u8 bNumberPowerFilters */
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.eps = (USBDescEndpoint[]) {
|
|
|
|
{
|
|
|
|
.bEndpointAddress = USB_DIR_IN | 0x01,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
|
|
|
.wMaxPacketSize = STATUS_BYTECOUNT,
|
|
|
|
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},{
|
|
|
|
/* CDC Data Interface (off) */
|
|
|
|
.bInterfaceNumber = 1,
|
|
|
|
.bAlternateSetting = 0,
|
|
|
|
.bNumEndpoints = 0,
|
|
|
|
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
|
|
|
},{
|
|
|
|
/* CDC Data Interface */
|
|
|
|
.bInterfaceNumber = 1,
|
|
|
|
.bAlternateSetting = 1,
|
|
|
|
.bNumEndpoints = 2,
|
|
|
|
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
|
|
|
.iInterface = STRING_DATA,
|
|
|
|
.eps = (USBDescEndpoint[]) {
|
|
|
|
{
|
|
|
|
.bEndpointAddress = USB_DIR_IN | 0x02,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
|
.wMaxPacketSize = 0x40,
|
|
|
|
},{
|
|
|
|
.bEndpointAddress = USB_DIR_OUT | 0x02,
|
|
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
|
|
.wMaxPacketSize = 0x40,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const USBDescDevice desc_device_net = {
|
|
|
|
.bcdUSB = 0x0200,
|
|
|
|
.bDeviceClass = USB_CLASS_COMM,
|
|
|
|
.bMaxPacketSize0 = 0x40,
|
|
|
|
.bNumConfigurations = 2,
|
|
|
|
.confs = (USBDescConfig[]) {
|
|
|
|
{
|
|
|
|
.bNumInterfaces = 2,
|
|
|
|
.bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
|
|
|
|
.iConfiguration = STRING_RNDIS,
|
2013-12-16 11:42:49 +04:00
|
|
|
.bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
|
2010-11-26 12:25:06 +03:00
|
|
|
.bMaxPower = 0x32,
|
|
|
|
.nif = ARRAY_SIZE(desc_iface_rndis),
|
|
|
|
.ifs = desc_iface_rndis,
|
|
|
|
},{
|
|
|
|
.bNumInterfaces = 2,
|
|
|
|
.bConfigurationValue = DEV_CONFIG_VALUE,
|
|
|
|
.iConfiguration = STRING_CDC,
|
2013-12-16 11:42:49 +04:00
|
|
|
.bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
|
2010-11-26 12:25:06 +03:00
|
|
|
.bMaxPower = 0x32,
|
|
|
|
.nif = ARRAY_SIZE(desc_iface_cdc),
|
|
|
|
.ifs = desc_iface_cdc,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const USBDesc desc_net = {
|
|
|
|
.id = {
|
|
|
|
.idVendor = RNDIS_VENDOR_NUM,
|
|
|
|
.idProduct = RNDIS_PRODUCT_NUM,
|
|
|
|
.bcdDevice = 0,
|
|
|
|
.iManufacturer = STRING_MANUFACTURER,
|
|
|
|
.iProduct = STRING_PRODUCT,
|
|
|
|
.iSerialNumber = STRING_SERIALNUMBER,
|
|
|
|
},
|
|
|
|
.full = &desc_device_net,
|
|
|
|
.str = usb_net_stringtable,
|
2008-07-18 00:47:13 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RNDIS Definitions - in theory not specific to USB.
|
|
|
|
*/
|
|
|
|
#define RNDIS_MAXIMUM_FRAME_SIZE 1518
|
|
|
|
#define RNDIS_MAX_TOTAL_SIZE 1558
|
|
|
|
|
|
|
|
/* Remote NDIS Versions */
|
|
|
|
#define RNDIS_MAJOR_VERSION 1
|
|
|
|
#define RNDIS_MINOR_VERSION 0
|
|
|
|
|
|
|
|
/* Status Values */
|
|
|
|
#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */
|
|
|
|
#define RNDIS_STATUS_FAILURE 0xc0000001U /* Unspecified error */
|
|
|
|
#define RNDIS_STATUS_INVALID_DATA 0xc0010015U /* Invalid data */
|
|
|
|
#define RNDIS_STATUS_NOT_SUPPORTED 0xc00000bbU /* Unsupported request */
|
|
|
|
#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000bU /* Device connected */
|
|
|
|
#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000cU /* Device disconnected */
|
|
|
|
|
|
|
|
/* Message Set for Connectionless (802.3) Devices */
|
|
|
|
enum {
|
|
|
|
RNDIS_PACKET_MSG = 1,
|
|
|
|
RNDIS_INITIALIZE_MSG = 2, /* Initialize device */
|
|
|
|
RNDIS_HALT_MSG = 3,
|
|
|
|
RNDIS_QUERY_MSG = 4,
|
|
|
|
RNDIS_SET_MSG = 5,
|
|
|
|
RNDIS_RESET_MSG = 6,
|
|
|
|
RNDIS_INDICATE_STATUS_MSG = 7,
|
|
|
|
RNDIS_KEEPALIVE_MSG = 8,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Message completion */
|
|
|
|
enum {
|
|
|
|
RNDIS_INITIALIZE_CMPLT = 0x80000002U,
|
|
|
|
RNDIS_QUERY_CMPLT = 0x80000004U,
|
|
|
|
RNDIS_SET_CMPLT = 0x80000005U,
|
|
|
|
RNDIS_RESET_CMPLT = 0x80000006U,
|
|
|
|
RNDIS_KEEPALIVE_CMPLT = 0x80000008U,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Device Flags */
|
|
|
|
enum {
|
|
|
|
RNDIS_DF_CONNECTIONLESS = 1,
|
|
|
|
RNDIS_DF_CONNECTIONORIENTED = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define RNDIS_MEDIUM_802_3 0x00000000U
|
|
|
|
|
|
|
|
/* from drivers/net/sk98lin/h/skgepnmi.h */
|
|
|
|
#define OID_PNP_CAPABILITIES 0xfd010100
|
|
|
|
#define OID_PNP_SET_POWER 0xfd010101
|
|
|
|
#define OID_PNP_QUERY_POWER 0xfd010102
|
|
|
|
#define OID_PNP_ADD_WAKE_UP_PATTERN 0xfd010103
|
|
|
|
#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xfd010104
|
|
|
|
#define OID_PNP_ENABLE_WAKE_UP 0xfd010106
|
|
|
|
|
|
|
|
typedef uint32_t le32;
|
|
|
|
|
|
|
|
typedef struct rndis_init_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 MajorVersion;
|
|
|
|
le32 MinorVersion;
|
|
|
|
le32 MaxTransferSize;
|
|
|
|
} rndis_init_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_init_cmplt_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 Status;
|
|
|
|
le32 MajorVersion;
|
|
|
|
le32 MinorVersion;
|
|
|
|
le32 DeviceFlags;
|
|
|
|
le32 Medium;
|
|
|
|
le32 MaxPacketsPerTransfer;
|
|
|
|
le32 MaxTransferSize;
|
|
|
|
le32 PacketAlignmentFactor;
|
|
|
|
le32 AFListOffset;
|
|
|
|
le32 AFListSize;
|
|
|
|
} rndis_init_cmplt_type;
|
|
|
|
|
|
|
|
typedef struct rndis_halt_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
} rndis_halt_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_query_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 OID;
|
|
|
|
le32 InformationBufferLength;
|
|
|
|
le32 InformationBufferOffset;
|
|
|
|
le32 DeviceVcHandle;
|
|
|
|
} rndis_query_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_query_cmplt_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 Status;
|
|
|
|
le32 InformationBufferLength;
|
|
|
|
le32 InformationBufferOffset;
|
|
|
|
} rndis_query_cmplt_type;
|
|
|
|
|
|
|
|
typedef struct rndis_set_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 OID;
|
|
|
|
le32 InformationBufferLength;
|
|
|
|
le32 InformationBufferOffset;
|
|
|
|
le32 DeviceVcHandle;
|
|
|
|
} rndis_set_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_set_cmplt_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 Status;
|
|
|
|
} rndis_set_cmplt_type;
|
|
|
|
|
|
|
|
typedef struct rndis_reset_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 Reserved;
|
|
|
|
} rndis_reset_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_reset_cmplt_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 Status;
|
|
|
|
le32 AddressingReset;
|
|
|
|
} rndis_reset_cmplt_type;
|
|
|
|
|
|
|
|
typedef struct rndis_indicate_status_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 Status;
|
|
|
|
le32 StatusBufferLength;
|
|
|
|
le32 StatusBufferOffset;
|
|
|
|
} rndis_indicate_status_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_keepalive_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
} rndis_keepalive_msg_type;
|
|
|
|
|
|
|
|
typedef struct rndis_keepalive_cmplt_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 RequestID;
|
|
|
|
le32 Status;
|
|
|
|
} rndis_keepalive_cmplt_type;
|
|
|
|
|
|
|
|
struct rndis_packet_msg_type {
|
|
|
|
le32 MessageType;
|
|
|
|
le32 MessageLength;
|
|
|
|
le32 DataOffset;
|
|
|
|
le32 DataLength;
|
|
|
|
le32 OOBDataOffset;
|
|
|
|
le32 OOBDataLength;
|
|
|
|
le32 NumOOBDataElements;
|
|
|
|
le32 PerPacketInfoOffset;
|
|
|
|
le32 PerPacketInfoLength;
|
|
|
|
le32 VcHandle;
|
|
|
|
le32 Reserved;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rndis_config_parameter {
|
|
|
|
le32 ParameterNameOffset;
|
|
|
|
le32 ParameterNameLength;
|
|
|
|
le32 ParameterType;
|
|
|
|
le32 ParameterValueOffset;
|
|
|
|
le32 ParameterValueLength;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* implementation specific */
|
|
|
|
enum rndis_state
|
|
|
|
{
|
|
|
|
RNDIS_UNINITIALIZED,
|
|
|
|
RNDIS_INITIALIZED,
|
|
|
|
RNDIS_DATA_INITIALIZED,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* from ndis.h */
|
|
|
|
enum ndis_oid {
|
|
|
|
/* Required Object IDs (OIDs) */
|
|
|
|
OID_GEN_SUPPORTED_LIST = 0x00010101,
|
|
|
|
OID_GEN_HARDWARE_STATUS = 0x00010102,
|
|
|
|
OID_GEN_MEDIA_SUPPORTED = 0x00010103,
|
|
|
|
OID_GEN_MEDIA_IN_USE = 0x00010104,
|
|
|
|
OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105,
|
|
|
|
OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106,
|
|
|
|
OID_GEN_LINK_SPEED = 0x00010107,
|
|
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108,
|
|
|
|
OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109,
|
|
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010a,
|
|
|
|
OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010b,
|
|
|
|
OID_GEN_VENDOR_ID = 0x0001010c,
|
|
|
|
OID_GEN_VENDOR_DESCRIPTION = 0x0001010d,
|
|
|
|
OID_GEN_CURRENT_PACKET_FILTER = 0x0001010e,
|
|
|
|
OID_GEN_CURRENT_LOOKAHEAD = 0x0001010f,
|
|
|
|
OID_GEN_DRIVER_VERSION = 0x00010110,
|
|
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111,
|
|
|
|
OID_GEN_PROTOCOL_OPTIONS = 0x00010112,
|
|
|
|
OID_GEN_MAC_OPTIONS = 0x00010113,
|
|
|
|
OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114,
|
|
|
|
OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115,
|
|
|
|
OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116,
|
|
|
|
OID_GEN_SUPPORTED_GUIDS = 0x00010117,
|
|
|
|
OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118,
|
|
|
|
OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119,
|
|
|
|
OID_GEN_MACHINE_NAME = 0x0001021a,
|
|
|
|
OID_GEN_RNDIS_CONFIG_PARAMETER = 0x0001021b,
|
|
|
|
OID_GEN_VLAN_ID = 0x0001021c,
|
|
|
|
|
|
|
|
/* Optional OIDs */
|
|
|
|
OID_GEN_MEDIA_CAPABILITIES = 0x00010201,
|
|
|
|
OID_GEN_PHYSICAL_MEDIUM = 0x00010202,
|
|
|
|
|
|
|
|
/* Required statistics OIDs */
|
|
|
|
OID_GEN_XMIT_OK = 0x00020101,
|
|
|
|
OID_GEN_RCV_OK = 0x00020102,
|
|
|
|
OID_GEN_XMIT_ERROR = 0x00020103,
|
|
|
|
OID_GEN_RCV_ERROR = 0x00020104,
|
|
|
|
OID_GEN_RCV_NO_BUFFER = 0x00020105,
|
|
|
|
|
|
|
|
/* Optional statistics OIDs */
|
|
|
|
OID_GEN_DIRECTED_BYTES_XMIT = 0x00020201,
|
|
|
|
OID_GEN_DIRECTED_FRAMES_XMIT = 0x00020202,
|
|
|
|
OID_GEN_MULTICAST_BYTES_XMIT = 0x00020203,
|
|
|
|
OID_GEN_MULTICAST_FRAMES_XMIT = 0x00020204,
|
|
|
|
OID_GEN_BROADCAST_BYTES_XMIT = 0x00020205,
|
|
|
|
OID_GEN_BROADCAST_FRAMES_XMIT = 0x00020206,
|
|
|
|
OID_GEN_DIRECTED_BYTES_RCV = 0x00020207,
|
|
|
|
OID_GEN_DIRECTED_FRAMES_RCV = 0x00020208,
|
|
|
|
OID_GEN_MULTICAST_BYTES_RCV = 0x00020209,
|
|
|
|
OID_GEN_MULTICAST_FRAMES_RCV = 0x0002020a,
|
|
|
|
OID_GEN_BROADCAST_BYTES_RCV = 0x0002020b,
|
|
|
|
OID_GEN_BROADCAST_FRAMES_RCV = 0x0002020c,
|
|
|
|
OID_GEN_RCV_CRC_ERROR = 0x0002020d,
|
|
|
|
OID_GEN_TRANSMIT_QUEUE_LENGTH = 0x0002020e,
|
|
|
|
OID_GEN_GET_TIME_CAPS = 0x0002020f,
|
|
|
|
OID_GEN_GET_NETCARD_TIME = 0x00020210,
|
|
|
|
OID_GEN_NETCARD_LOAD = 0x00020211,
|
|
|
|
OID_GEN_DEVICE_PROFILE = 0x00020212,
|
|
|
|
OID_GEN_INIT_TIME_MS = 0x00020213,
|
|
|
|
OID_GEN_RESET_COUNTS = 0x00020214,
|
|
|
|
OID_GEN_MEDIA_SENSE_COUNTS = 0x00020215,
|
|
|
|
OID_GEN_FRIENDLY_NAME = 0x00020216,
|
|
|
|
OID_GEN_MINIPORT_INFO = 0x00020217,
|
|
|
|
OID_GEN_RESET_VERIFY_PARAMETERS = 0x00020218,
|
|
|
|
|
|
|
|
/* IEEE 802.3 (Ethernet) OIDs */
|
|
|
|
OID_802_3_PERMANENT_ADDRESS = 0x01010101,
|
|
|
|
OID_802_3_CURRENT_ADDRESS = 0x01010102,
|
|
|
|
OID_802_3_MULTICAST_LIST = 0x01010103,
|
|
|
|
OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104,
|
|
|
|
OID_802_3_MAC_OPTIONS = 0x01010105,
|
|
|
|
OID_802_3_RCV_ERROR_ALIGNMENT = 0x01020101,
|
|
|
|
OID_802_3_XMIT_ONE_COLLISION = 0x01020102,
|
|
|
|
OID_802_3_XMIT_MORE_COLLISIONS = 0x01020103,
|
|
|
|
OID_802_3_XMIT_DEFERRED = 0x01020201,
|
|
|
|
OID_802_3_XMIT_MAX_COLLISIONS = 0x01020202,
|
|
|
|
OID_802_3_RCV_OVERRUN = 0x01020203,
|
|
|
|
OID_802_3_XMIT_UNDERRUN = 0x01020204,
|
|
|
|
OID_802_3_XMIT_HEARTBEAT_FAILURE = 0x01020205,
|
|
|
|
OID_802_3_XMIT_TIMES_CRS_LOST = 0x01020206,
|
|
|
|
OID_802_3_XMIT_LATE_COLLISIONS = 0x01020207,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const uint32_t oid_supported_list[] =
|
|
|
|
{
|
|
|
|
/* the general stuff */
|
|
|
|
OID_GEN_SUPPORTED_LIST,
|
|
|
|
OID_GEN_HARDWARE_STATUS,
|
|
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
|
|
OID_GEN_MEDIA_IN_USE,
|
|
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
|
|
OID_GEN_LINK_SPEED,
|
|
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
|
|
OID_GEN_VENDOR_ID,
|
|
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
|
|
OID_GEN_VENDOR_DRIVER_VERSION,
|
|
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
|
|
OID_GEN_PHYSICAL_MEDIUM,
|
|
|
|
|
|
|
|
/* the statistical stuff */
|
|
|
|
OID_GEN_XMIT_OK,
|
|
|
|
OID_GEN_RCV_OK,
|
|
|
|
OID_GEN_XMIT_ERROR,
|
|
|
|
OID_GEN_RCV_ERROR,
|
|
|
|
OID_GEN_RCV_NO_BUFFER,
|
|
|
|
|
|
|
|
/* IEEE 802.3 */
|
|
|
|
/* the general stuff */
|
|
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
|
|
OID_802_3_MULTICAST_LIST,
|
|
|
|
OID_802_3_MAC_OPTIONS,
|
|
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
|
|
|
|
|
|
/* the statistical stuff */
|
|
|
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
|
|
OID_802_3_XMIT_ONE_COLLISION,
|
|
|
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA (1 << 0)
|
|
|
|
#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED (1 << 1)
|
|
|
|
#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND (1 << 2)
|
|
|
|
#define NDIS_MAC_OPTION_NO_LOOPBACK (1 << 3)
|
|
|
|
#define NDIS_MAC_OPTION_FULL_DUPLEX (1 << 4)
|
|
|
|
#define NDIS_MAC_OPTION_EOTX_INDICATION (1 << 5)
|
|
|
|
#define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6)
|
|
|
|
|
|
|
|
struct rndis_response {
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_ENTRY(rndis_response) entries;
|
2008-07-18 00:47:13 +04:00
|
|
|
uint32_t length;
|
misc: Replace zero-length arrays with flexible array member (automatic)
Description copied from Linux kernel commit from Gustavo A. R. Silva
(see [3]):
--v-- description start --v--
The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to
declare variable-length types such as these ones is a flexible
array member [1], introduced in C99:
struct foo {
int stuff;
struct boo array[];
};
By making use of the mechanism above, we will get a compiler
warning in case the flexible array does not occur last in the
structure, which will help us prevent some kind of undefined
behavior bugs from being unadvertenly introduced [2] to the
Linux codebase from now on.
--^-- description end --^--
Do the similar housekeeping in the QEMU codebase (which uses
C99 since commit 7be41675f7cb).
All these instances of code were found with the help of the
following Coccinelle script:
@@
identifier s, m, a;
type t, T;
@@
struct s {
...
t m;
- T a[0];
+ T a[];
};
@@
identifier s, m, a;
type t, T;
@@
struct s {
...
t m;
- T a[0];
+ T a[];
} QEMU_PACKED;
[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=76497732932f
[3] https://git.kernel.org/pub/scm/linux/kernel/git/gustavoars/linux.git/commit/?id=17642a2fbd2c1
Inspired-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2020-03-04 18:38:15 +03:00
|
|
|
uint8_t buf[];
|
2008-07-18 00:47:13 +04:00
|
|
|
};
|
|
|
|
|
2020-09-03 23:43:22 +03:00
|
|
|
struct USBNetState {
|
2008-07-18 00:47:13 +04:00
|
|
|
USBDevice dev;
|
|
|
|
|
|
|
|
enum rndis_state rndis_state;
|
|
|
|
uint32_t medium;
|
|
|
|
uint32_t speed;
|
|
|
|
uint32_t media_state;
|
|
|
|
uint16_t filter;
|
|
|
|
uint32_t vendorid;
|
|
|
|
|
2022-09-06 21:30:53 +03:00
|
|
|
uint16_t connection;
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
unsigned int out_ptr;
|
|
|
|
uint8_t out_buf[2048];
|
|
|
|
|
|
|
|
unsigned int in_ptr, in_len;
|
|
|
|
uint8_t in_buf[2048];
|
|
|
|
|
2012-11-17 15:47:14 +04:00
|
|
|
USBEndpoint *intr;
|
2022-09-06 21:30:50 +03:00
|
|
|
USBEndpoint *bulk_in;
|
2012-11-17 15:47:14 +04:00
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
char usbstring_mac[13];
|
2009-11-25 21:49:25 +03:00
|
|
|
NICState *nic;
|
|
|
|
NICConf conf;
|
2018-12-06 13:58:10 +03:00
|
|
|
QTAILQ_HEAD(, rndis_response) rndis_resp;
|
2020-09-03 23:43:22 +03:00
|
|
|
};
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2015-05-06 15:55:30 +03:00
|
|
|
#define TYPE_USB_NET "usb-net"
|
2020-09-16 21:25:19 +03:00
|
|
|
OBJECT_DECLARE_SIMPLE_TYPE(USBNetState, USB_NET)
|
2015-05-06 15:55:30 +03:00
|
|
|
|
2010-11-26 22:20:41 +03:00
|
|
|
static int is_rndis(USBNetState *s)
|
|
|
|
{
|
2016-02-11 14:01:20 +03:00
|
|
|
return s->dev.config ?
|
|
|
|
s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
|
2010-11-26 22:20:41 +03:00
|
|
|
}
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
static int ndis_query(USBNetState *s, uint32_t oid,
|
2008-08-21 21:58:08 +04:00
|
|
|
uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
|
|
|
|
size_t outlen)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
2008-12-22 23:33:55 +03:00
|
|
|
unsigned int i;
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
switch (oid) {
|
|
|
|
/* general oids (table 4-1) */
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_SUPPORTED_LIST:
|
2016-06-10 18:37:57 +03:00
|
|
|
for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++) {
|
|
|
|
stl_le_p(outbuf + (i * sizeof(le32)), oid_supported_list[i]);
|
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(oid_supported_list);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->medium);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_MEDIA_IN_USE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->medium);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, ETH_FRAME_LEN);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_LINK_SPEED:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->speed);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, ETH_FRAME_LEN);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, ETH_FRAME_LEN);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_VENDOR_ID:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->vendorid);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
2008-09-20 12:07:15 +04:00
|
|
|
pstrcpy((char *)outbuf, outlen, "QEMU USB RNDIS Net");
|
|
|
|
return strlen((char *)outbuf) + 1;
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 1);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->filter);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, RNDIS_MAX_TOTAL_SIZE);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, s->media_state);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
case OID_GEN_PHYSICAL_MEDIUM:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
case OID_GEN_MAC_OPTIONS:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
|
|
|
|
NDIS_MAC_OPTION_FULL_DUPLEX);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* statistics OIDs (table 4-2) */
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_XMIT_OK:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_RCV_OK:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_RCV_ERROR:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_GEN_RCV_NO_BUFFER:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* ieee802.3 OIDs (table 4-3) */
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
2009-11-25 21:49:25 +03:00
|
|
|
memcpy(outbuf, s->conf.macaddr.a, 6);
|
2008-07-18 00:47:13 +04:00
|
|
|
return 6;
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
2009-11-25 21:49:25 +03:00
|
|
|
memcpy(outbuf, s->conf.macaddr.a, 6);
|
2008-07-18 00:47:13 +04:00
|
|
|
return 6;
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0xe0000000);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 1);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
case OID_802_3_MAC_OPTIONS:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* ieee802.3 statistics OIDs (table 4-4) */
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
/* mandatory */
|
|
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
2016-06-10 18:37:57 +03:00
|
|
|
stl_le_p(outbuf, 0);
|
2008-07-18 00:47:13 +04:00
|
|
|
return sizeof(le32);
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "usbnet: unknown OID 0x%08x\n", oid);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ndis_set(USBNetState *s, uint32_t oid,
|
|
|
|
uint8_t *inbuf, unsigned int inlen)
|
|
|
|
{
|
|
|
|
switch (oid) {
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
2016-06-10 18:37:57 +03:00
|
|
|
s->filter = ldl_le_p(inbuf);
|
2008-07-18 00:47:13 +04:00
|
|
|
if (s->filter) {
|
|
|
|
s->rndis_state = RNDIS_DATA_INITIALIZED;
|
|
|
|
} else {
|
|
|
|
s->rndis_state = RNDIS_INITIALIZED;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_get_response(USBNetState *s, uint8_t *buf)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct rndis_response *r = s->rndis_resp.tqh_first;
|
|
|
|
|
|
|
|
if (!r)
|
|
|
|
return ret;
|
|
|
|
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_REMOVE(&s->rndis_resp, r, entries);
|
2008-07-18 00:47:13 +04:00
|
|
|
ret = r->length;
|
|
|
|
memcpy(buf, r->buf, r->length);
|
2011-08-21 07:09:37 +04:00
|
|
|
g_free(r);
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *rndis_queue_response(USBNetState *s, unsigned int length)
|
|
|
|
{
|
|
|
|
struct rndis_response *r =
|
2011-08-21 07:09:37 +04:00
|
|
|
g_malloc0(sizeof(struct rndis_response) + length);
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2012-11-17 15:47:14 +04:00
|
|
|
if (QTAILQ_EMPTY(&s->rndis_resp)) {
|
2013-01-29 15:44:35 +04:00
|
|
|
usb_wakeup(s->intr, 0);
|
2012-11-17 15:47:14 +04:00
|
|
|
}
|
|
|
|
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries);
|
2008-07-18 00:47:13 +04:00
|
|
|
r->length = length;
|
|
|
|
|
|
|
|
return &r->buf[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rndis_clear_responsequeue(USBNetState *s)
|
|
|
|
{
|
|
|
|
struct rndis_response *r;
|
|
|
|
|
|
|
|
while ((r = s->rndis_resp.tqh_first)) {
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_REMOVE(&s->rndis_resp, r, entries);
|
2011-08-21 07:09:37 +04:00
|
|
|
g_free(r);
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf)
|
|
|
|
{
|
|
|
|
rndis_init_cmplt_type *resp =
|
|
|
|
rndis_queue_response(s, sizeof(rndis_init_cmplt_type));
|
|
|
|
|
|
|
|
if (!resp)
|
|
|
|
return USB_RET_STALL;
|
|
|
|
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_INITIALIZE_CMPLT);
|
|
|
|
resp->MessageLength = cpu_to_le32(sizeof(rndis_init_cmplt_type));
|
|
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
|
|
|
|
resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
|
|
|
|
resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
|
|
|
|
resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
|
|
|
|
resp->MaxPacketsPerTransfer = cpu_to_le32(1);
|
|
|
|
resp->MaxTransferSize = cpu_to_le32(ETH_FRAME_LEN +
|
|
|
|
sizeof(struct rndis_packet_msg_type) + 22);
|
|
|
|
resp->PacketAlignmentFactor = cpu_to_le32(0);
|
|
|
|
resp->AFListOffset = cpu_to_le32(0);
|
|
|
|
resp->AFListSize = cpu_to_le32(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_query_response(USBNetState *s,
|
|
|
|
rndis_query_msg_type *buf, unsigned int length)
|
|
|
|
{
|
|
|
|
rndis_query_cmplt_type *resp;
|
|
|
|
/* oid_supported_list is the largest data reply */
|
|
|
|
uint8_t infobuf[sizeof(oid_supported_list)];
|
|
|
|
uint32_t bufoffs, buflen;
|
|
|
|
int infobuflen;
|
|
|
|
unsigned int resplen;
|
|
|
|
|
|
|
|
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
|
|
|
buflen = le32_to_cpu(buf->InformationBufferLength);
|
2016-02-16 21:53:41 +03:00
|
|
|
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
2008-07-18 00:47:13 +04:00
|
|
|
return USB_RET_STALL;
|
2016-02-16 21:53:41 +03:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
2008-08-21 21:58:08 +04:00
|
|
|
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
|
|
|
sizeof(infobuf));
|
2008-07-18 00:47:13 +04:00
|
|
|
resplen = sizeof(rndis_query_cmplt_type) +
|
|
|
|
((infobuflen < 0) ? 0 : infobuflen);
|
|
|
|
resp = rndis_queue_response(s, resplen);
|
|
|
|
if (!resp)
|
|
|
|
return USB_RET_STALL;
|
|
|
|
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_QUERY_CMPLT);
|
|
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
|
|
resp->MessageLength = cpu_to_le32(resplen);
|
|
|
|
|
|
|
|
if (infobuflen < 0) {
|
|
|
|
/* OID not supported */
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
|
|
|
resp->InformationBufferLength = cpu_to_le32(0);
|
|
|
|
resp->InformationBufferOffset = cpu_to_le32(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
resp->InformationBufferOffset =
|
|
|
|
cpu_to_le32(infobuflen ? sizeof(rndis_query_cmplt_type) - 8 : 0);
|
|
|
|
resp->InformationBufferLength = cpu_to_le32(infobuflen);
|
|
|
|
memcpy(resp + 1, infobuf, infobuflen);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_set_response(USBNetState *s,
|
|
|
|
rndis_set_msg_type *buf, unsigned int length)
|
|
|
|
{
|
|
|
|
rndis_set_cmplt_type *resp =
|
|
|
|
rndis_queue_response(s, sizeof(rndis_set_cmplt_type));
|
|
|
|
uint32_t bufoffs, buflen;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!resp)
|
|
|
|
return USB_RET_STALL;
|
|
|
|
|
|
|
|
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
|
|
|
buflen = le32_to_cpu(buf->InformationBufferLength);
|
2016-02-16 21:53:41 +03:00
|
|
|
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
2008-07-18 00:47:13 +04:00
|
|
|
return USB_RET_STALL;
|
2016-02-16 21:53:41 +03:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
|
|
|
bufoffs + (uint8_t *) buf, buflen);
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_SET_CMPLT);
|
|
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
|
|
resp->MessageLength = cpu_to_le32(sizeof(rndis_set_cmplt_type));
|
|
|
|
if (ret < 0) {
|
|
|
|
/* OID not supported */
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
|
|
|
|
{
|
|
|
|
rndis_reset_cmplt_type *resp =
|
|
|
|
rndis_queue_response(s, sizeof(rndis_reset_cmplt_type));
|
|
|
|
|
|
|
|
if (!resp)
|
|
|
|
return USB_RET_STALL;
|
|
|
|
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_RESET_CMPLT);
|
|
|
|
resp->MessageLength = cpu_to_le32(sizeof(rndis_reset_cmplt_type));
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
resp->AddressingReset = cpu_to_le32(1); /* reset information */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rndis_keepalive_response(USBNetState *s,
|
|
|
|
rndis_keepalive_msg_type *buf)
|
|
|
|
{
|
|
|
|
rndis_keepalive_cmplt_type *resp =
|
|
|
|
rndis_queue_response(s, sizeof(rndis_keepalive_cmplt_type));
|
|
|
|
|
|
|
|
if (!resp)
|
|
|
|
return USB_RET_STALL;
|
|
|
|
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_KEEPALIVE_CMPLT);
|
|
|
|
resp->MessageLength = cpu_to_le32(sizeof(rndis_keepalive_cmplt_type));
|
|
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-24 16:37:29 +04:00
|
|
|
/* Prepare to receive the next packet */
|
|
|
|
static void usb_net_reset_in_buf(USBNetState *s)
|
|
|
|
{
|
|
|
|
s->in_ptr = s->in_len = 0;
|
2013-01-30 15:12:22 +04:00
|
|
|
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
2012-08-24 16:37:29 +04:00
|
|
|
}
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
|
|
|
|
{
|
2016-06-10 18:37:57 +03:00
|
|
|
uint32_t msg_type = ldl_le_p(data);
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
switch (msg_type) {
|
|
|
|
case RNDIS_INITIALIZE_MSG:
|
|
|
|
s->rndis_state = RNDIS_INITIALIZED;
|
|
|
|
return rndis_init_response(s, (rndis_init_msg_type *) data);
|
|
|
|
|
|
|
|
case RNDIS_HALT_MSG:
|
|
|
|
s->rndis_state = RNDIS_UNINITIALIZED;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case RNDIS_QUERY_MSG:
|
|
|
|
return rndis_query_response(s, (rndis_query_msg_type *) data, length);
|
|
|
|
|
|
|
|
case RNDIS_SET_MSG:
|
|
|
|
return rndis_set_response(s, (rndis_set_msg_type *) data, length);
|
|
|
|
|
|
|
|
case RNDIS_RESET_MSG:
|
|
|
|
rndis_clear_responsequeue(s);
|
2012-08-24 16:37:29 +04:00
|
|
|
s->out_ptr = 0;
|
|
|
|
usb_net_reset_in_buf(s);
|
2008-07-18 00:47:13 +04:00
|
|
|
return rndis_reset_response(s, (rndis_reset_msg_type *) data);
|
|
|
|
|
|
|
|
case RNDIS_KEEPALIVE_MSG:
|
|
|
|
/* For USB: host does this every 5 seconds */
|
|
|
|
return rndis_keepalive_response(s, (rndis_keepalive_msg_type *) data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return USB_RET_STALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void usb_net_handle_reset(USBDevice *dev)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
static void usb_net_handle_control(USBDevice *dev, USBPacket *p,
|
2011-02-02 18:33:13 +03:00
|
|
|
int request, int value, int index, int length, uint8_t *data)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
USBNetState *s = (USBNetState *) dev;
|
2010-11-26 12:25:06 +03:00
|
|
|
int ret;
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2011-02-02 18:33:13 +03:00
|
|
|
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
2010-11-26 12:25:06 +03:00
|
|
|
if (ret >= 0) {
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
return;
|
2010-11-26 12:25:06 +03:00
|
|
|
}
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
switch(request) {
|
|
|
|
case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
|
2010-11-26 22:20:41 +03:00
|
|
|
if (!is_rndis(s) || value || index != 0) {
|
2008-07-18 00:47:13 +04:00
|
|
|
goto fail;
|
2010-11-26 22:20:41 +03:00
|
|
|
}
|
2008-09-06 21:47:39 +04:00
|
|
|
#ifdef TRAFFIC_DEBUG
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
fprintf(stderr, "SEND_ENCAPSULATED_COMMAND:");
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
if (!(i & 15))
|
|
|
|
fprintf(stderr, "\n%04x:", i);
|
|
|
|
fprintf(stderr, " %02x", data[i]);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ret = rndis_parse(s, data, length);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
p->status = ret;
|
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE:
|
2010-11-26 22:20:41 +03:00
|
|
|
if (!is_rndis(s) || value || index != 0) {
|
2008-07-18 00:47:13 +04:00
|
|
|
goto fail;
|
2010-11-26 22:20:41 +03:00
|
|
|
}
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->actual_length = rndis_get_response(s, data);
|
|
|
|
if (p->actual_length == 0) {
|
2008-07-18 00:47:13 +04:00
|
|
|
data[0] = 0;
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->actual_length = 1;
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
2008-09-06 21:47:39 +04:00
|
|
|
#ifdef TRAFFIC_DEBUG
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
for (i = 0; i < p->actual_length; i++) {
|
2008-07-18 00:47:13 +04:00
|
|
|
if (!(i & 15))
|
|
|
|
fprintf(stderr, "\n%04x:", i);
|
|
|
|
fprintf(stderr, " %02x", data[i]);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
2022-09-06 21:30:51 +03:00
|
|
|
case ClassInterfaceOutRequest | USB_CDC_SET_ETHERNET_PACKET_FILTER:
|
|
|
|
if (is_rndis(s)) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
default:
|
|
|
|
fail:
|
|
|
|
fprintf(stderr, "usbnet: failed control transaction: "
|
|
|
|
"request 0x%x value 0x%x index 0x%x length 0x%x\n",
|
|
|
|
request, value, index, length);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->status = USB_RET_STALL;
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
static void usb_net_handle_statusin(USBNetState *s, USBPacket *p)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
2022-09-06 21:30:53 +03:00
|
|
|
le32 rbuf[2];
|
|
|
|
uint16_t ebuf[4];
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2011-07-12 17:22:25 +04:00
|
|
|
if (p->iov.size < 8) {
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->status = USB_RET_STALL;
|
|
|
|
return;
|
2011-07-12 17:22:25 +04:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2022-09-06 21:30:53 +03:00
|
|
|
if (is_rndis(s)) {
|
|
|
|
rbuf[0] = cpu_to_le32(1);
|
|
|
|
rbuf[1] = cpu_to_le32(0);
|
|
|
|
usb_packet_copy(p, rbuf, 8);
|
|
|
|
if (!s->rndis_resp.tqh_first) {
|
|
|
|
p->status = USB_RET_NAK;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ebuf[0] =
|
|
|
|
cpu_to_be16(ClassInterfaceRequest | USB_CDC_NETWORK_CONNECTION);
|
|
|
|
ebuf[1] = cpu_to_le16(s->connection);
|
|
|
|
ebuf[2] = cpu_to_le16(1);
|
|
|
|
ebuf[3] = cpu_to_le16(0);
|
|
|
|
usb_packet_copy(p, ebuf, 8);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2008-09-06 21:47:39 +04:00
|
|
|
#ifdef TRAFFIC_DEBUG
|
2011-07-12 17:22:25 +04:00
|
|
|
fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->iov.size, p->status);
|
|
|
|
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status);
|
2008-07-18 00:47:13 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
static void usb_net_handle_datain(USBNetState *s, USBPacket *p)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
int len;
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
if (s->in_ptr > s->in_len) {
|
2012-08-24 16:37:29 +04:00
|
|
|
usb_net_reset_in_buf(s);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->status = USB_RET_NAK;
|
|
|
|
return;
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
if (!s->in_len) {
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->status = USB_RET_NAK;
|
|
|
|
return;
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
len = s->in_len - s->in_ptr;
|
|
|
|
if (len > p->iov.size) {
|
|
|
|
len = p->iov.size;
|
2011-07-12 17:22:25 +04:00
|
|
|
}
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
|
|
|
|
s->in_ptr += len;
|
2008-07-18 00:47:13 +04:00
|
|
|
if (s->in_ptr >= s->in_len &&
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
(is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
|
2008-07-18 00:47:13 +04:00
|
|
|
/* no short packet necessary */
|
2012-08-24 16:37:29 +04:00
|
|
|
usb_net_reset_in_buf(s);
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
|
2008-09-06 21:47:39 +04:00
|
|
|
#ifdef TRAFFIC_DEBUG
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
|
|
|
|
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
|
2008-07-18 00:47:13 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
int sz = sizeof(s->out_buf) - s->out_ptr;
|
|
|
|
struct rndis_packet_msg_type *msg =
|
|
|
|
(struct rndis_packet_msg_type *) s->out_buf;
|
|
|
|
uint32_t len;
|
|
|
|
|
2008-09-06 21:47:39 +04:00
|
|
|
#ifdef TRAFFIC_DEBUG
|
2011-07-12 17:22:25 +04:00
|
|
|
fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
|
|
|
|
iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
|
2008-07-18 00:47:13 +04:00
|
|
|
#endif
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
if (sz > p->iov.size) {
|
|
|
|
sz = p->iov.size;
|
|
|
|
}
|
2011-07-12 17:22:25 +04:00
|
|
|
usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
|
2008-07-18 00:47:13 +04:00
|
|
|
s->out_ptr += sz;
|
|
|
|
|
2010-11-26 22:20:41 +03:00
|
|
|
if (!is_rndis(s)) {
|
2022-09-06 21:30:52 +03:00
|
|
|
if (p->iov.size % 64 || p->iov.size == 0) {
|
2013-01-30 15:12:22 +04:00
|
|
|
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr);
|
2008-07-18 00:47:13 +04:00
|
|
|
s->out_ptr = 0;
|
|
|
|
}
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
return;
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
len = le32_to_cpu(msg->MessageLength);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
if (s->out_ptr < 8 || s->out_ptr < len) {
|
|
|
|
return;
|
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
|
|
|
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
|
|
|
uint32_t size = le32_to_cpu(msg->DataLength);
|
2016-02-16 21:53:41 +03:00
|
|
|
if (offs < len && size < len && offs + size <= len) {
|
2013-01-30 15:12:22 +04:00
|
|
|
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
|
2016-02-16 21:53:41 +03:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
s->out_ptr -= len;
|
|
|
|
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
|
|
|
}
|
|
|
|
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
static void usb_net_handle_data(USBDevice *dev, USBPacket *p)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
USBNetState *s = (USBNetState *) dev;
|
|
|
|
|
|
|
|
switch(p->pid) {
|
|
|
|
case USB_TOKEN_IN:
|
2012-01-12 16:23:01 +04:00
|
|
|
switch (p->ep->nr) {
|
2008-07-18 00:47:13 +04:00
|
|
|
case 1:
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
usb_net_handle_statusin(s, p);
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
usb_net_handle_datain(s, p);
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case USB_TOKEN_OUT:
|
2012-01-12 16:23:01 +04:00
|
|
|
switch (p->ep->nr) {
|
2008-07-18 00:47:13 +04:00
|
|
|
case 2:
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
usb_net_handle_dataout(s, p);
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fail:
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
p->status = USB_RET_STALL;
|
2008-07-18 00:47:13 +04:00
|
|
|
break;
|
|
|
|
}
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
|
|
|
|
if (p->status == USB_RET_STALL) {
|
2008-07-18 00:47:13 +04:00
|
|
|
fprintf(stderr, "usbnet: failed data transaction: "
|
2011-07-12 17:22:25 +04:00
|
|
|
"pid 0x%x ep 0x%x len 0x%zx\n",
|
2012-01-12 16:23:01 +04:00
|
|
|
p->pid, p->ep->nr, p->iov.size);
|
usb: split packet result into actual_length + status
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.
An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.
While already touching all the devices and controllers handle_packet /
handle_data / handle_control code, also change the return type of
these functions to void, solely storing the status in the packet. To
make the code paths for regular versus async packet handling more
uniform.
This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.
This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.
Note that there is usually no need to directly set packet->actual_length
form devices handle_data callback, as that is done by usb_packet_copy()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2012-11-01 20:15:01 +04:00
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
|
2012-07-24 19:35:13 +04:00
|
|
|
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
2013-01-30 15:12:23 +04:00
|
|
|
USBNetState *s = qemu_get_nic_opaque(nc);
|
2012-08-24 16:32:16 +04:00
|
|
|
uint8_t *in_buf = s->in_buf;
|
|
|
|
size_t total_size = size;
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2015-07-15 13:19:05 +03:00
|
|
|
if (!s->dev.config) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-26 22:20:41 +03:00
|
|
|
if (is_rndis(s)) {
|
2011-11-10 01:09:23 +04:00
|
|
|
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
2009-05-18 16:40:55 +04:00
|
|
|
return -1;
|
2011-11-10 01:09:23 +04:00
|
|
|
}
|
2012-08-24 16:32:16 +04:00
|
|
|
total_size += sizeof(struct rndis_packet_msg_type);
|
|
|
|
}
|
|
|
|
if (total_size > sizeof(s->in_buf)) {
|
|
|
|
return -1;
|
|
|
|
}
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2012-08-24 16:37:29 +04:00
|
|
|
/* Only accept packet if input buffer is empty */
|
|
|
|
if (s->in_len > 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-24 16:32:16 +04:00
|
|
|
if (is_rndis(s)) {
|
|
|
|
struct rndis_packet_msg_type *msg;
|
|
|
|
|
|
|
|
msg = (struct rndis_packet_msg_type *)in_buf;
|
2008-07-18 00:47:13 +04:00
|
|
|
memset(msg, 0, sizeof(struct rndis_packet_msg_type));
|
|
|
|
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
|
2012-08-24 16:32:16 +04:00
|
|
|
msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
|
|
|
|
msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
|
2008-07-18 00:47:13 +04:00
|
|
|
msg->DataLength = cpu_to_le32(size);
|
|
|
|
/* msg->OOBDataOffset;
|
|
|
|
* msg->OOBDataLength;
|
|
|
|
* msg->NumOOBDataElements;
|
|
|
|
* msg->PerPacketInfoOffset;
|
|
|
|
* msg->PerPacketInfoLength;
|
|
|
|
* msg->VcHandle;
|
|
|
|
* msg->Reserved;
|
|
|
|
*/
|
2012-08-24 16:32:16 +04:00
|
|
|
in_buf += sizeof(*msg);
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
2012-08-24 16:32:16 +04:00
|
|
|
|
|
|
|
memcpy(in_buf, buf, size);
|
|
|
|
s->in_len = total_size;
|
2008-07-18 00:47:13 +04:00
|
|
|
s->in_ptr = 0;
|
2022-09-06 21:30:50 +03:00
|
|
|
usb_wakeup(s->bulk_in, 0);
|
2009-05-18 16:40:55 +04:00
|
|
|
return size;
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
|
2012-07-24 19:35:13 +04:00
|
|
|
static void usbnet_cleanup(NetClientState *nc)
|
2009-04-17 21:11:08 +04:00
|
|
|
{
|
2013-01-30 15:12:23 +04:00
|
|
|
USBNetState *s = qemu_get_nic_opaque(nc);
|
2009-04-17 21:11:08 +04:00
|
|
|
|
2009-12-15 12:20:57 +03:00
|
|
|
s->nic = NULL;
|
2009-04-17 21:11:08 +04:00
|
|
|
}
|
|
|
|
|
qdev: Unrealize must not fail
Devices may have component devices and buses.
Device realization may fail. Realization is recursive: a device's
realize() method realizes its components, and device_set_realized()
realizes its buses (which should in turn realize the devices on that
bus, except bus_set_realized() doesn't implement that, yet).
When realization of a component or bus fails, we need to roll back:
unrealize everything we realized so far. If any of these unrealizes
failed, the device would be left in an inconsistent state. Must not
happen.
device_set_realized() lets it happen: it ignores errors in the roll
back code starting at label child_realize_fail.
Since realization is recursive, unrealization must be recursive, too.
But how could a partly failed unrealize be rolled back? We'd have to
re-realize, which can fail. This design is fundamentally broken.
device_set_realized() does not roll back at all. Instead, it keeps
unrealizing, ignoring further errors.
It can screw up even for a device with no buses: if the lone
dc->unrealize() fails, it still unregisters vmstate, and calls
listeners' unrealize() callback.
bus_set_realized() does not roll back either. Instead, it stops
unrealizing.
Fortunately, no unrealize method can fail, as we'll see below.
To fix the design error, drop parameter @errp from all the unrealize
methods.
Any unrealize method that uses @errp now needs an update. This leads
us to unrealize() methods that can fail. Merely passing it to another
unrealize method cannot cause failure, though. Here are the ones that
do other things with @errp:
* virtio_serial_device_unrealize()
Fails when qbus_set_hotplug_handler() fails, but still does all the
other work. On failure, the device would stay realized with its
resources completely gone. Oops. Can't happen, because
qbus_set_hotplug_handler() can't actually fail here. Pass
&error_abort to qbus_set_hotplug_handler() instead.
* hw/ppc/spapr_drc.c's unrealize()
Fails when object_property_del() fails, but all the other work is
already done. On failure, the device would stay realized with its
vmstate registration gone. Oops. Can't happen, because
object_property_del() can't actually fail here. Pass &error_abort
to object_property_del() instead.
* spapr_phb_unrealize()
Fails and bails out when remove_drcs() fails, but other work is
already done. On failure, the device would stay realized with some
of its resources gone. Oops. remove_drcs() fails only when
chassis_from_bus()'s object_property_get_uint() fails, and it can't
here. Pass &error_abort to remove_drcs() instead.
Therefore, no unrealize method can fail before this patch.
device_set_realized()'s recursive unrealization via bus uses
object_property_set_bool(). Can't drop @errp there, so pass
&error_abort.
We similarly unrealize with object_property_set_bool() elsewhere,
always ignoring errors. Pass &error_abort instead.
Several unrealize methods no longer handle errors from other unrealize
methods: virtio_9p_device_unrealize(),
virtio_input_device_unrealize(), scsi_qdev_unrealize(), ...
Much of the deleted error handling looks wrong anyway.
One unrealize methods no longer ignore such errors:
usb_ehci_pci_exit().
Several realize methods no longer ignore errors when rolling back:
v9fs_device_realize_common(), pci_qdev_unrealize(),
spapr_phb_realize(), usb_qdev_realize(), vfio_ccw_realize(),
virtio_device_realize().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-17-armbru@redhat.com>
2020-05-05 18:29:24 +03:00
|
|
|
static void usb_net_unrealize(USBDevice *dev)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
|
|
|
USBNetState *s = (USBNetState *) dev;
|
|
|
|
|
2008-07-18 01:00:05 +04:00
|
|
|
/* TODO: remove the nd_table[] entry */
|
2009-12-15 12:20:57 +03:00
|
|
|
rndis_clear_responsequeue(s);
|
2013-01-30 15:12:24 +04:00
|
|
|
qemu_del_nic(s->nic);
|
2008-07-18 00:47:13 +04:00
|
|
|
}
|
|
|
|
|
2009-12-15 12:20:57 +03:00
|
|
|
static NetClientInfo net_usbnet_info = {
|
qapi: Change Netdev into a flat union
This is a mostly-mechanical conversion that creates a new flat
union 'Netdev' QAPI type that covers all the branches of the
former 'NetClientOptions' simple union, where the branches are
now listed in a new 'NetClientDriver' enum rather than generated
from the simple union. The existence of a flat union has no
change to the command line syntax accepted for new code, and
will make it possible for a future patch to switch the QMP
command to parse a boxed union for no change to valid QMP; but
it does have some ripple effect on the C code when dealing with
the new types.
While making the conversion, note that the 'NetLegacy' type
remains unchanged: it applies only to legacy command line options,
and will not be ported to QMP, so it should remain a wrapper
around a simple union; to avoid confusion, the type named
'NetClientOptions' is now gone, and we introduce 'NetLegacyOptions'
in its place. Then, in the C code, we convert from NetLegacy to
Netdev as soon as possible, so that the bulk of the net stack
only has to deal with one QAPI type, not two. Note that since
the old legacy code always rejected 'hubport', we can just omit
that branch from the new 'NetLegacyOptions' simple union.
Based on an idea originally by Zoltán Kővágó <DirtY.iCE.hu@gmail.com>:
Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com>
although the sed script in that patch no longer applies due to
other changes in the tree since then, and I also did some manual
cleanups (such as fixing whitespace to keep checkpatch happy).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1468468228-27827-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Fixup from Eric squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-07-14 06:50:23 +03:00
|
|
|
.type = NET_CLIENT_DRIVER_NIC,
|
2009-12-15 12:20:57 +03:00
|
|
|
.size = sizeof(NICState),
|
|
|
|
.receive = usbnet_receive,
|
|
|
|
.cleanup = usbnet_cleanup,
|
|
|
|
};
|
|
|
|
|
2019-12-05 20:46:31 +03:00
|
|
|
static void usb_net_realize(USBDevice *dev, Error **errp)
|
2008-07-18 00:47:13 +04:00
|
|
|
{
|
2015-05-06 15:55:30 +03:00
|
|
|
USBNetState *s = USB_NET(dev);
|
2008-07-18 00:47:13 +04:00
|
|
|
|
2012-04-20 14:33:30 +04:00
|
|
|
usb_desc_create_serial(dev);
|
2010-11-26 22:20:41 +03:00
|
|
|
usb_desc_init(dev);
|
2008-07-18 00:47:13 +04:00
|
|
|
|
|
|
|
s->rndis_state = RNDIS_UNINITIALIZED;
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_INIT(&s->rndis_resp);
|
2009-08-31 16:23:59 +04:00
|
|
|
|
2008-07-18 00:47:13 +04:00
|
|
|
s->medium = 0; /* NDIS_MEDIUM_802_3 */
|
|
|
|
s->speed = 1000000; /* 100MBps, in 100Bps units */
|
|
|
|
s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */;
|
|
|
|
s->filter = 0;
|
|
|
|
s->vendorid = 0x1234;
|
2022-09-06 21:30:53 +03:00
|
|
|
s->connection = 1; /* Connected */
|
2012-11-17 15:47:14 +04:00
|
|
|
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
|
2022-09-06 21:30:50 +03:00
|
|
|
s->bulk_in = usb_ep_get(dev, USB_TOKEN_IN, 2);
|
2009-12-15 12:20:57 +03:00
|
|
|
|
|
|
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
|
|
|
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
|
2011-12-04 21:17:51 +04:00
|
|
|
object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
|
2013-01-30 15:12:22 +04:00
|
|
|
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
2009-12-15 12:20:57 +03:00
|
|
|
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
|
|
|
|
"%02x%02x%02x%02x%02x%02x",
|
|
|
|
0x40,
|
|
|
|
s->conf.macaddr.a[1],
|
|
|
|
s->conf.macaddr.a[2],
|
|
|
|
s->conf.macaddr.a[3],
|
|
|
|
s->conf.macaddr.a[4],
|
|
|
|
s->conf.macaddr.a[5]);
|
2010-11-26 12:25:06 +03:00
|
|
|
usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac);
|
2009-08-31 16:23:59 +04:00
|
|
|
}
|
|
|
|
|
2014-10-07 12:00:20 +04:00
|
|
|
static void usb_net_instance_init(Object *obj)
|
|
|
|
{
|
|
|
|
USBDevice *dev = USB_DEVICE(obj);
|
2015-05-06 15:55:30 +03:00
|
|
|
USBNetState *s = USB_NET(dev);
|
2014-10-07 12:00:20 +04:00
|
|
|
|
|
|
|
device_add_bootindex_property(obj, &s->conf.bootindex,
|
|
|
|
"bootindex", "/ethernet-phy@0",
|
2020-05-05 18:29:23 +03:00
|
|
|
&dev->qdev);
|
2014-10-07 12:00:20 +04:00
|
|
|
}
|
|
|
|
|
2011-07-20 12:06:07 +04:00
|
|
|
static const VMStateDescription vmstate_usb_net = {
|
|
|
|
.name = "usb-net",
|
|
|
|
.unmigratable = 1,
|
|
|
|
};
|
|
|
|
|
2011-12-08 07:34:16 +04:00
|
|
|
static Property net_properties[] = {
|
|
|
|
DEFINE_NIC_PROPERTIES(USBNetState, conf),
|
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
2011-12-16 00:53:10 +04:00
|
|
|
static void usb_net_class_initfn(ObjectClass *klass, void *data)
|
|
|
|
{
|
2011-12-08 07:34:16 +04:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2011-12-16 00:53:10 +04:00
|
|
|
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
|
|
|
|
|
2014-09-19 10:48:25 +04:00
|
|
|
uc->realize = usb_net_realize;
|
2011-12-16 00:53:10 +04:00
|
|
|
uc->product_desc = "QEMU USB Network Interface";
|
|
|
|
uc->usb_desc = &desc_net;
|
|
|
|
uc->handle_reset = usb_net_handle_reset;
|
|
|
|
uc->handle_control = usb_net_handle_control;
|
|
|
|
uc->handle_data = usb_net_handle_data;
|
2017-02-21 17:14:45 +03:00
|
|
|
uc->unrealize = usb_net_unrealize;
|
2013-07-29 18:17:45 +04:00
|
|
|
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
2011-12-08 07:34:16 +04:00
|
|
|
dc->fw_name = "network";
|
|
|
|
dc->vmsd = &vmstate_usb_net;
|
2020-01-10 18:30:32 +03:00
|
|
|
device_class_set_props(dc, net_properties);
|
2011-12-16 00:53:10 +04:00
|
|
|
}
|
|
|
|
|
2013-01-10 19:19:07 +04:00
|
|
|
static const TypeInfo net_info = {
|
2015-05-06 15:55:30 +03:00
|
|
|
.name = TYPE_USB_NET,
|
2011-12-08 07:34:16 +04:00
|
|
|
.parent = TYPE_USB_DEVICE,
|
|
|
|
.instance_size = sizeof(USBNetState),
|
|
|
|
.class_init = usb_net_class_initfn,
|
2014-10-07 12:00:20 +04:00
|
|
|
.instance_init = usb_net_instance_init,
|
2009-08-31 16:23:59 +04:00
|
|
|
};
|
|
|
|
|
2012-02-09 18:20:55 +04:00
|
|
|
static void usb_net_register_types(void)
|
2009-08-31 16:23:59 +04:00
|
|
|
{
|
2011-12-08 07:34:16 +04:00
|
|
|
type_register_static(&net_info);
|
2009-08-31 16:23:59 +04:00
|
|
|
}
|
2012-02-09 18:20:55 +04:00
|
|
|
|
|
|
|
type_init(usb_net_register_types)
|