X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/e3f5ec2b5e92706e3b807059f79b1fb5d936e567..ba43d28916c4f51c19bd7366089155ce81bee058:/hw/usb-net.c diff --git a/hw/usb-net.c b/hw/usb-net.c index d8d5e773f5..a8b7c8dd76 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -25,8 +25,11 @@ #include "qemu-common.h" #include "usb.h" +#include "usb-desc.h" #include "net.h" -#include "sys-queue.h" +#include "qemu-queue.h" +#include "sysemu.h" +#include "iov.h" /*#define TRAFFIC_DEBUG*/ /* Thanks to NetChip Technologies for donating this product ID. @@ -71,11 +74,6 @@ enum usbstring_idx { #define USB_DT_CS_INTERFACE 0x24 #define USB_DT_CS_ENDPOINT 0x25 -#define ClassInterfaceRequest \ - ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) -#define ClassInterfaceOutRequest \ - ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - #define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 #define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 #define USB_CDC_REQ_SET_LINE_CODING 0x20 @@ -93,182 +91,209 @@ enum usbstring_idx { #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ -/* - * mostly the same descriptor as the linux gadget rndis driver - */ -static const uint8_t qemu_net_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - USB_DT_DEVICE, /* u8 bDescriptorType; Device */ - 0x00, 0x02, /* u16 bcdUSB; v2.0 */ - USB_CLASS_COMM, /* u8 bDeviceClass; */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full only ] */ - 0x40, /* u8 bMaxPacketSize0 */ - RNDIS_VENDOR_NUM & 0xff, RNDIS_VENDOR_NUM >> 8, /* u16 idVendor; */ - RNDIS_PRODUCT_NUM & 0xff, RNDIS_PRODUCT_NUM >> 8, /* u16 idProduct; */ - 0x00, 0x00, /* u16 bcdDevice */ - STRING_MANUFACTURER, /* u8 iManufacturer; */ - STRING_PRODUCT, /* u8 iProduct; */ - STRING_SERIALNUMBER, /* u8 iSerialNumber; */ - 0x02, /* u8 bNumConfigurations; */ +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", +}; + +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, + } + } + } +}; + +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 uint8_t qemu_net_rndis_config_descriptor[] = { - /* Configuration Descriptor */ - 0x09, /* u8 bLength */ - USB_DT_CONFIG, /* u8 bDescriptorType */ - 0x43, 0x00, /* le16 wTotalLength */ - 0x02, /* u8 bNumInterfaces */ - DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */ - STRING_RNDIS, /* u8 iConfiguration */ - 0xc0, /* u8 bmAttributes */ - 0x32, /* u8 bMaxPower */ - /* RNDIS Control Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x00, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x01, /* u8 bNumEndpoints */ - USB_CLASS_COMM, /* u8 bInterfaceClass */ - USB_CDC_SUBCLASS_ACM, /* u8 bInterfaceSubClass */ - USB_CDC_ACM_PROTO_VENDOR, /* u8 bInterfaceProtocol */ - STRING_RNDIS_CONTROL, /* u8 iInterface */ - /* Header Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ - 0x10, 0x01, /* le16 bcdCDC */ - /* Call Management Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_CALL_MANAGEMENT_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bmCapabilities */ - 0x01, /* u8 bDataInterface */ - /* ACM Descriptor */ - 0x04, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_ACM_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bmCapabilities */ - /* Union Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bMasterInterface0 */ - 0x01, /* u8 bSlaveInterface0 */ - /* Status Descriptor */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 1, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ - STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ - 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ - /* RNDIS Data Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x02, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - STRING_DATA, /* u8 iInterface */ - /* Source Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00, /* u8 bInterval */ - /* Sink Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_OUT | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00 /* u8 bInterval */ +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, + .bmAttributes = 0xc0, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface_rndis), + .ifs = desc_iface_rndis, + },{ + .bNumInterfaces = 2, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = STRING_CDC, + .bmAttributes = 0xc0, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface_cdc), + .ifs = desc_iface_cdc, + } + }, }; -static const uint8_t qemu_net_cdc_config_descriptor[] = { - /* Configuration Descriptor */ - 0x09, /* u8 bLength */ - USB_DT_CONFIG, /* u8 bDescriptorType */ - 0x50, 0x00, /* le16 wTotalLength */ - 0x02, /* u8 bNumInterfaces */ - DEV_CONFIG_VALUE, /* u8 bConfigurationValue */ - STRING_CDC, /* u8 iConfiguration */ - 0xc0, /* u8 bmAttributes */ - 0x32, /* u8 bMaxPower */ - /* CDC Control Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x00, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x01, /* u8 bNumEndpoints */ - USB_CLASS_COMM, /* u8 bInterfaceClass */ - USB_CDC_SUBCLASS_ETHERNET, /* u8 bInterfaceSubClass */ - USB_CDC_PROTO_NONE, /* u8 bInterfaceProtocol */ - STRING_CONTROL, /* u8 iInterface */ - /* Header Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_HEADER_TYPE, /* u8 bDescriptorSubType */ - 0x10, 0x01, /* le16 bcdCDC */ - /* Union Descriptor */ - 0x05, /* u8 bLength */ - USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ - USB_CDC_UNION_TYPE, /* u8 bDescriptorSubType */ - 0x00, /* u8 bMasterInterface0 */ - 0x01, /* u8 bSlaveInterface0 */ - /* Ethernet Descriptor */ - 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 */ - /* Status Descriptor */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 1, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_INT, /* u8 bmAttributes */ - STATUS_BYTECOUNT & 0xff, STATUS_BYTECOUNT >> 8, /* le16 wMaxPacketSize */ - 1 << LOG2_STATUS_INTERVAL_MSEC, /* u8 bInterval */ - /* CDC Data (nop) Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x00, /* u8 bAlternateSetting */ - 0x00, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - 0x00, /* u8 iInterface */ - /* CDC Data Interface */ - 0x09, /* u8 bLength */ - USB_DT_INTERFACE, /* u8 bDescriptorType */ - 0x01, /* u8 bInterfaceNumber */ - 0x01, /* u8 bAlternateSetting */ - 0x02, /* u8 bNumEndpoints */ - USB_CLASS_CDC_DATA, /* u8 bInterfaceClass */ - 0x00, /* u8 bInterfaceSubClass */ - 0x00, /* u8 bInterfaceProtocol */ - STRING_DATA, /* u8 iInterface */ - /* Source Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_IN | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00, /* u8 bInterval */ - /* Sink Endpoint */ - 0x07, /* u8 bLength */ - USB_DT_ENDPOINT, /* u8 bDescriptorType */ - USB_DIR_OUT | 2, /* u8 bEndpointAddress */ - USB_ENDPOINT_XFER_BULK, /* u8 bmAttributes */ - 0x40, 0x00, /* le16 wMaxPacketSize */ - 0x00 /* u8 bInterval */ +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, }; /* @@ -595,7 +620,7 @@ static const uint32_t oid_supported_list[] = #define NDIS_MAC_OPTION_8021P_PRIORITY (1 << 6) struct rndis_response { - TAILQ_ENTRY(rndis_response) entries; + QTAILQ_ENTRY(rndis_response) entries; uint32_t length; uint8_t buf[0]; }; @@ -603,14 +628,12 @@ struct rndis_response { typedef struct USBNetState { USBDevice dev; - unsigned int rndis; enum rndis_state rndis_state; uint32_t medium; uint32_t speed; uint32_t media_state; uint16_t filter; uint32_t vendorid; - uint8_t mac[6]; unsigned int out_ptr; uint8_t out_buf[2048]; @@ -620,10 +643,16 @@ typedef struct USBNetState { uint8_t in_buf[2048]; char usbstring_mac[13]; - VLANClientState *vc; - TAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp; + NICState *nic; + NICConf conf; + QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp; } USBNetState; +static int is_rndis(USBNetState *s) +{ + return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE; +} + static int ndis_query(USBNetState *s, uint32_t oid, uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf, size_t outlen) @@ -741,12 +770,12 @@ static int ndis_query(USBNetState *s, uint32_t oid, /* ieee802.3 OIDs (table 4-3) */ /* mandatory */ case OID_802_3_PERMANENT_ADDRESS: - memcpy(outbuf, s->mac, 6); + memcpy(outbuf, s->conf.macaddr.a, 6); return 6; /* mandatory */ case OID_802_3_CURRENT_ADDRESS: - memcpy(outbuf, s->mac, 6); + memcpy(outbuf, s->conf.macaddr.a, 6); return 6; /* mandatory */ @@ -812,10 +841,10 @@ static int rndis_get_response(USBNetState *s, uint8_t *buf) if (!r) return ret; - TAILQ_REMOVE(&s->rndis_resp, r, entries); + QTAILQ_REMOVE(&s->rndis_resp, r, entries); ret = r->length; memcpy(buf, r->buf, r->length); - qemu_free(r); + g_free(r); return ret; } @@ -823,9 +852,9 @@ static int rndis_get_response(USBNetState *s, uint8_t *buf) static void *rndis_queue_response(USBNetState *s, unsigned int length) { struct rndis_response *r = - qemu_mallocz(sizeof(struct rndis_response) + length); + g_malloc0(sizeof(struct rndis_response) + length); - TAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); + QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); r->length = length; return &r->buf[0]; @@ -836,8 +865,8 @@ static void rndis_clear_responsequeue(USBNetState *s) struct rndis_response *r; while ((r = s->rndis_resp.tqh_first)) { - TAILQ_REMOVE(&s->rndis_resp, r, entries); - qemu_free(r); + QTAILQ_REMOVE(&s->rndis_resp, r, entries); + g_free(r); } } @@ -977,11 +1006,10 @@ static int rndis_keepalive_response(USBNetState *s, static int rndis_parse(USBNetState *s, uint8_t *data, int length) { - uint32_t msg_type, msg_length; + uint32_t msg_type; le32 *tmp = (le32 *) data; - msg_type = le32_to_cpup(tmp++); - msg_length = le32_to_cpup(tmp++); + msg_type = le32_to_cpup(tmp); switch (msg_type) { case RNDIS_INITIALIZE_MSG: @@ -1015,59 +1043,23 @@ static void usb_net_handle_reset(USBDevice *dev) { } -static const char * const 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", -}; - -static int usb_net_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_net_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBNetState *s = (USBNetState *) dev; - int ret = 0; - - switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; + int ret; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + ret = 0; + switch(request) { case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: - if (!s->rndis || value || index != 0) + if (!is_rndis(s) || value || index != 0) { goto fail; + } #ifdef TRAFFIC_DEBUG { unsigned int i; @@ -1084,8 +1076,9 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, break; case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE: - if (!s->rndis || value || index != 0) + if (!is_rndis(s) || value || index != 0) { goto fail; + } ret = rndis_get_response(s, data); if (!ret) { data[0] = 0; @@ -1105,85 +1098,6 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, #endif break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - ret = sizeof(qemu_net_dev_descriptor); - memcpy(data, qemu_net_dev_descriptor, ret); - break; - - case USB_DT_CONFIG: - switch (value & 0xff) { - case 0: - ret = sizeof(qemu_net_rndis_config_descriptor); - memcpy(data, qemu_net_rndis_config_descriptor, ret); - break; - - case 1: - ret = sizeof(qemu_net_cdc_config_descriptor); - memcpy(data, qemu_net_cdc_config_descriptor, ret); - break; - - default: - goto fail; - } - - data[2] = ret & 0xff; - data[3] = ret >> 8; - break; - - case USB_DT_STRING: - switch (value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - - case STRING_ETHADDR: - ret = set_usb_string(data, s->usbstring_mac); - break; - - default: - if (usb_net_stringtable[value & 0xff]) { - ret = set_usb_string(data, - usb_net_stringtable[value & 0xff]); - break; - } - - goto fail; - } - break; - - default: - goto fail; - } - break; - - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = s->rndis ? DEV_RNDIS_CONFIG_VALUE : DEV_CONFIG_VALUE; - ret = 1; - break; - - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - switch (value & 0xff) { - case DEV_CONFIG_VALUE: - s->rndis = 0; - break; - - case DEV_RNDIS_CONFIG_VALUE: - s->rndis = 1; - break; - - default: - goto fail; - } - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: case InterfaceRequest | USB_REQ_GET_INTERFACE: data[0] = 0; @@ -1208,28 +1122,23 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, static int usb_net_handle_statusin(USBNetState *s, USBPacket *p) { + le32 buf[2]; int ret = 8; - if (p->len < 8) + if (p->iov.size < 8) { return USB_RET_STALL; + } - ((le32 *) p->data)[0] = cpu_to_le32(1); - ((le32 *) p->data)[1] = cpu_to_le32(0); + buf[0] = cpu_to_le32(1); + buf[1] = cpu_to_le32(0); + usb_packet_copy(p, buf, 8); if (!s->rndis_resp.tqh_first) ret = USB_RET_NAK; #ifdef TRAFFIC_DEBUG - fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret); - { - int i; - fprintf(stderr, ":"); - for (i = 0; i < ret; i++) { - if (!(i & 15)) - fprintf(stderr, "\n%04x:", i); - fprintf(stderr, " %02x", p->data[i]); - } - fprintf(stderr, "\n\n"); - } + fprintf(stderr, "usbnet: interrupt poll len %zu return %d", + p->iov.size, ret); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); #endif return ret; @@ -1249,28 +1158,20 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) return ret; } ret = s->in_len - s->in_ptr; - if (ret > p->len) - ret = p->len; - memcpy(p->data, &s->in_buf[s->in_ptr], ret); + if (ret > p->iov.size) { + ret = p->iov.size; + } + usb_packet_copy(p, &s->in_buf[s->in_ptr], ret); s->in_ptr += ret; if (s->in_ptr >= s->in_len && - (s->rndis || (s->in_len & (64 - 1)) || !ret)) { + (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { /* no short packet necessary */ s->in_ptr = s->in_len = 0; } #ifdef TRAFFIC_DEBUG - fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret); - { - int i; - fprintf(stderr, ":"); - for (i = 0; i < ret; i++) { - if (!(i & 15)) - fprintf(stderr, "\n%04x:", i); - fprintf(stderr, " %02x", p->data[i]); - } - fprintf(stderr, "\n\n"); - } + fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); #endif return ret; @@ -1278,34 +1179,25 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) { - int ret = p->len; + int ret = p->iov.size; 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; #ifdef TRAFFIC_DEBUG - fprintf(stderr, "usbnet: data out len %u\n", p->len); - { - int i; - fprintf(stderr, ":"); - for (i = 0; i < p->len; i++) { - if (!(i & 15)) - fprintf(stderr, "\n%04x:", i); - fprintf(stderr, " %02x", p->data[i]); - } - fprintf(stderr, "\n\n"); - } + fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size); #endif if (sz > ret) sz = ret; - memcpy(&s->out_buf[s->out_ptr], p->data, sz); + usb_packet_copy(p, &s->out_buf[s->out_ptr], sz); s->out_ptr += sz; - if (!s->rndis) { + if (!is_rndis(s)) { if (ret < 64) { - qemu_send_packet(s->vc, s->out_buf, s->out_ptr); + qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); s->out_ptr = 0; } return ret; @@ -1317,7 +1209,7 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); if (offs + size <= len) - qemu_send_packet(s->vc, s->out_buf + offs, size); + qemu_send_packet(&s->nic->nc, s->out_buf + offs, size); } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); @@ -1364,22 +1256,22 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) } if (ret == USB_RET_STALL) fprintf(stderr, "usbnet: failed data transaction: " - "pid 0x%x ep 0x%x len 0x%x\n", - p->pid, p->devep, p->len); + "pid 0x%x ep 0x%x len 0x%zx\n", + p->pid, p->devep, p->iov.size); return ret; } -static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; struct rndis_packet_msg_type *msg; - if (s->rndis) { + if (is_rndis(s)) { msg = (struct rndis_packet_msg_type *) s->in_buf; if (!s->rndis_state == RNDIS_DATA_INITIALIZED) - return; + return -1; if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return; + return -1; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); @@ -1398,29 +1290,30 @@ static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) s->in_len = size + sizeof(struct rndis_packet_msg_type); } else { if (size > sizeof(s->in_buf)) - return; + return -1; memcpy(s->in_buf, buf, size); s->in_len = size; } s->in_ptr = 0; + return size; } -static int usbnet_can_receive(VLANClientState *vc) +static int usbnet_can_receive(VLANClientState *nc) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) + if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) { return 1; + } return !s->in_len; } -static void usbnet_cleanup(VLANClientState *vc) +static void usbnet_cleanup(VLANClientState *nc) { - USBNetState *s = vc->opaque; + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - rndis_clear_responsequeue(s); - qemu_free(s); + s->nic = NULL; } static void usb_net_handle_destroy(USBDevice *dev) @@ -1428,50 +1321,106 @@ static void usb_net_handle_destroy(USBDevice *dev) USBNetState *s = (USBNetState *) dev; /* TODO: remove the nd_table[] entry */ - qemu_del_vlan_client(s->vc); + rndis_clear_responsequeue(s); + qemu_del_vlan_client(&s->nic->nc); } -USBDevice *usb_net_init(NICInfo *nd) -{ - USBNetState *s; +static NetClientInfo net_usbnet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = usbnet_can_receive, + .receive = usbnet_receive, + .cleanup = usbnet_cleanup, +}; - s = qemu_mallocz(sizeof(USBNetState)); - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_generic_handle_packet; +static int usb_net_initfn(USBDevice *dev) +{ + USBNetState *s = DO_UPCAST(USBNetState, dev, dev); - s->dev.handle_reset = usb_net_handle_reset; - s->dev.handle_control = usb_net_handle_control; - s->dev.handle_data = usb_net_handle_data; - s->dev.handle_destroy = usb_net_handle_destroy; + usb_desc_init(dev); - s->rndis = 1; s->rndis_state = RNDIS_UNINITIALIZED; + QTAILQ_INIT(&s->rndis_resp); + 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; - memcpy(s->mac, nd->macaddr, 6); - TAILQ_INIT(&s->rndis_resp); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, + s->dev.qdev.info->name, s->dev.qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + 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]); + usb_desc_set_string(dev, STRING_ETHADDR, s->usbstring_mac); + + add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet@0"); + return 0; +} + +static USBDevice *usb_net_init(const char *cmdline) +{ + USBDevice *dev; + QemuOpts *opts; + int idx; - pstrcpy(s->dev.devname, sizeof(s->dev.devname), - "QEMU USB Network Interface"); - s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - usbnet_can_receive, - usbnet_receive, - NULL, - usbnet_cleanup, s); + opts = qemu_opts_parse(qemu_find_opts("net"), cmdline, 0); + if (!opts) { + return NULL; + } + qemu_opt_set(opts, "type", "nic"); + qemu_opt_set(opts, "model", "usb"); - qemu_format_nic_info_str(s->vc, s->mac); + idx = net_client_init(NULL, opts, 0); + if (idx == -1) { + return NULL; + } - snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), - "%02x%02x%02x%02x%02x%02x", - 0x40, s->mac[1], s->mac[2], - s->mac[3], s->mac[4], s->mac[5]); - fprintf(stderr, "usbnet: initialized mac %02x:%02x:%02x:%02x:%02x:%02x\n", - s->mac[0], s->mac[1], s->mac[2], - s->mac[3], s->mac[4], s->mac[5]); - - return (USBDevice *) s; + dev = usb_create(NULL /* FIXME */, "usb-net"); + if (!dev) { + return NULL; + } + qdev_set_nic_properties(&dev->qdev, &nd_table[idx]); + qdev_init_nofail(&dev->qdev); + return dev; +} + +static const VMStateDescription vmstate_usb_net = { + .name = "usb-net", + .unmigratable = 1, +}; + +static struct USBDeviceInfo net_info = { + .product_desc = "QEMU USB Network Interface", + .qdev.name = "usb-net", + .qdev.fw_name = "network", + .qdev.size = sizeof(USBNetState), + .qdev.vmsd = &vmstate_usb_net, + .usb_desc = &desc_net, + .init = usb_net_initfn, + .handle_packet = usb_generic_handle_packet, + .handle_reset = usb_net_handle_reset, + .handle_control = usb_net_handle_control, + .handle_data = usb_net_handle_data, + .handle_destroy = usb_net_handle_destroy, + .usbdevice_name = "net", + .usbdevice_init = usb_net_init, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(USBNetState, conf), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void usb_net_register_devices(void) +{ + usb_qdev_register(&net_info); } +device_init(usb_net_register_devices)