* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu-common.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "net/net.h"
-#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
#include "qemu/queue.h"
#include "qemu/config-file.h"
#include "sysemu/sysemu.h"
#include "qemu/iov.h"
+#include "qemu/cutils.h"
/*#define TRAFFIC_DEBUG*/
/* Thanks to NetChip Technologies for donating this product ID.
.bNumInterfaces = 2,
.bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
.iConfiguration = STRING_RNDIS,
- .bmAttributes = 0xc0,
+ .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
.bMaxPower = 0x32,
.nif = ARRAY_SIZE(desc_iface_rndis),
.ifs = desc_iface_rndis,
.bNumInterfaces = 2,
.bConfigurationValue = DEV_CONFIG_VALUE,
.iConfiguration = STRING_CDC,
- .bmAttributes = 0xc0,
+ .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
.bMaxPower = 0x32,
.nif = ARRAY_SIZE(desc_iface_cdc),
.ifs = desc_iface_cdc,
QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
} USBNetState;
+#define TYPE_USB_NET "usb-net"
+#define USB_NET(obj) OBJECT_CHECK(USBNetState, (obj), TYPE_USB_NET)
+
static int is_rndis(USBNetState *s)
{
- return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
+ return s->dev.config ?
+ s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
}
static int ndis_query(USBNetState *s, uint32_t oid,
/* general oids (table 4-1) */
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
- ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
+ for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++) {
+ stl_le_p(outbuf + (i * sizeof(le32)), oid_supported_list[i]);
+ }
return sizeof(oid_supported_list);
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
+ stl_le_p(outbuf, s->medium);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
+ stl_le_p(outbuf, s->medium);
return sizeof(le32);
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_LINK_SPEED:
- *((le32 *) outbuf) = cpu_to_le32(s->speed);
+ stl_le_p(outbuf, s->speed);
return sizeof(le32);
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_VENDOR_ID:
- *((le32 *) outbuf) = cpu_to_le32(s->vendorid);
+ stl_le_p(outbuf, s->vendorid);
return sizeof(le32);
/* mandatory */
return strlen((char *)outbuf) + 1;
case OID_GEN_VENDOR_DRIVER_VERSION:
- *((le32 *) outbuf) = cpu_to_le32(1);
+ stl_le_p(outbuf, 1);
return sizeof(le32);
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
- *((le32 *) outbuf) = cpu_to_le32(s->filter);
+ stl_le_p(outbuf, s->filter);
return sizeof(le32);
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+ stl_le_p(outbuf, RNDIS_MAX_TOTAL_SIZE);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(s->media_state);
+ stl_le_p(outbuf, s->media_state);
return sizeof(le32);
case OID_GEN_PHYSICAL_MEDIUM:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
case OID_GEN_MAC_OPTIONS:
- *((le32 *) outbuf) = cpu_to_le32(
- NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
- NDIS_MAC_OPTION_FULL_DUPLEX);
+ stl_le_p(outbuf, NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_FULL_DUPLEX);
return sizeof(le32);
/* statistics OIDs (table 4-2) */
/* mandatory */
case OID_GEN_XMIT_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_XMIT_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* ieee802.3 OIDs (table 4-3) */
/* mandatory */
case OID_802_3_MULTICAST_LIST:
- *((le32 *) outbuf) = cpu_to_le32(0xe0000000);
+ stl_le_p(outbuf, 0xe0000000);
return sizeof(le32);
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(1);
+ stl_le_p(outbuf, 1);
return sizeof(le32);
case OID_802_3_MAC_OPTIONS:
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
default:
{
switch (oid) {
case OID_GEN_CURRENT_PACKET_FILTER:
- s->filter = le32_to_cpup((le32 *) inbuf);
+ s->filter = ldl_le_p(inbuf);
if (s->filter) {
s->rndis_state = RNDIS_DATA_INITIALIZED;
} else {
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
buflen = le32_to_cpu(buf->InformationBufferLength);
- if (bufoffs + buflen > length)
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
return USB_RET_STALL;
+ }
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
bufoffs + (uint8_t *) buf, buflen, infobuf,
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
buflen = le32_to_cpu(buf->InformationBufferLength);
- if (bufoffs + buflen > length)
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
return USB_RET_STALL;
+ }
ret = ndis_set(s, le32_to_cpu(buf->OID),
bufoffs + (uint8_t *) buf, buflen);
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
{
- uint32_t msg_type;
- le32 *tmp = (le32 *) data;
-
- msg_type = le32_to_cpup(tmp);
+ uint32_t msg_type = ldl_le_p(data);
switch (msg_type) {
case RNDIS_INITIALIZE_MSG:
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);
- if (offs + size <= len)
+ if (offs < len && size < len && offs + size <= len) {
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
+ }
}
s->out_ptr -= len;
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
uint8_t *in_buf = s->in_buf;
size_t total_size = size;
+ if (!s->dev.config) {
+ return -1;
+ }
+
if (is_rndis(s)) {
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
return -1;
return size;
}
-static int usbnet_can_receive(NetClientState *nc)
-{
- USBNetState *s = qemu_get_nic_opaque(nc);
-
- if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) {
- return 1;
- }
-
- return !s->in_len;
-}
-
static void usbnet_cleanup(NetClientState *nc)
{
USBNetState *s = qemu_get_nic_opaque(nc);
}
static NetClientInfo net_usbnet_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
- .can_receive = usbnet_can_receive,
.receive = usbnet_receive,
.cleanup = usbnet_cleanup,
};
-static int usb_net_initfn(USBDevice *dev)
+static void usb_net_realize(USBDevice *dev, Error **errrp)
{
- USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
+ USBNetState *s = USB_NET(dev);
usb_desc_create_serial(dev);
usb_desc_init(dev);
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 void usb_net_instance_init(Object *obj)
+{
+ USBDevice *dev = USB_DEVICE(obj);
+ USBNetState *s = USB_NET(dev);
+
+ device_add_bootindex_property(obj, &s->conf.bootindex,
+ "bootindex", "/ethernet-phy@0",
+ &dev->qdev, NULL);
}
static USBDevice *usb_net_init(USBBus *bus, const char *cmdline)
QemuOpts *opts;
int idx;
- opts = qemu_opts_parse(qemu_find_opts("net"), cmdline, 0);
+ opts = qemu_opts_parse_noisily(qemu_find_opts("net"), cmdline, false);
if (!opts) {
return NULL;
}
- qemu_opt_set(opts, "type", "nic");
- qemu_opt_set(opts, "model", "usb");
+ qemu_opt_set(opts, "type", "nic", &error_abort);
+ qemu_opt_set(opts, "model", "usb", &error_abort);
idx = net_client_init(opts, 0, &local_err);
if (local_err) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_report_err(local_err);
return NULL;
}
dev = usb_create(bus, "usb-net");
- if (!dev) {
- return NULL;
- }
qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
- qdev_init_nofail(&dev->qdev);
return dev;
}
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
- uc->init = usb_net_initfn;
+ uc->realize = usb_net_realize;
uc->product_desc = "QEMU USB Network Interface";
uc->usb_desc = &desc_net;
uc->handle_reset = usb_net_handle_reset;
}
static const TypeInfo net_info = {
- .name = "usb-net",
+ .name = TYPE_USB_NET,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBNetState),
.class_init = usb_net_class_initfn,
+ .instance_init = usb_net_instance_init,
};
static void usb_net_register_types(void)
{
type_register_static(&net_info);
- usb_legacy_register("usb-net", "net", usb_net_init);
+ usb_legacy_register(TYPE_USB_NET, "net", usb_net_init);
}
type_init(usb_net_register_types)