]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/usb-net.c
fmopl: Fix spelling in code and comments
[mirror_qemu.git] / hw / usb-net.c
index c49fd62a41b89d9561960db107af501d3b6d2b6c..a8b7c8dd76953b10594612b50ba7693ed170ee29 100644 (file)
 
 #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(void *opaque, const uint8_t *buf, int size)
+static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 {
-    USBNetState *s = 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,73 +1290,137 @@ static void usbnet_receive(void *opaque, const uint8_t *buf, int 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(void *opaque)
+static int usbnet_can_receive(VLANClientState *nc)
 {
-    USBNetState *s = 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 *nc)
+{
+    USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    s->nic = NULL;
+}
+
 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_free(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));
-    if (!s)
-        return NULL;
-    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;
+}
 
-    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_receive, usbnet_can_receive, s);
+static USBDevice *usb_net_init(const char *cmdline)
+{
+    USBDevice *dev;
+    QemuOpts *opts;
+    int idx;
 
-    qemu_format_nic_info_str(s->vc, s->mac);
+    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");
 
-    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;
+    idx = net_client_init(NULL, opts, 0);
+    if (idx == -1) {
+        return NULL;
+    }
+
+    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)