usb: misc bugfixes.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJWzDoNAAoJEEy22O7T6HE4uPoP/0219mBQ3GpHOD+NMNjL0ukb biBUeN1Sglo6XJ/D8UadGH0IBiwePyLCEIcwiF9NRTWfgWQHWR+onaZocHgROMgw 9SjERlgx1H/ghYvuavRviKzwJcou4lORyE1ypSRHGKNTcBJd/WnINNbH704QNEnH RI4N2apAPL9Ch1vWEgSSEeIenNIMsojTl6pkuka4TsgyYuI+cZKMhmgjqHBpvCkW psDh3IBmXdCDEfAI6Go+5a8a0yzwk78Lqoao6PLdfv7txZRnjqcuypTrco7zdH2T Df8NEfixi+57uPBntjoXZfK+iAQAD/CuLgsOpaTtehnckYbMMjYMyfop+ZLyrBKN Fn1m7BM6T7Ia+X28VOmQIK3tq+n03ioOricxBGTd3trm3MCYl2D4tE3jl9czx+Nf 0UcbzhWdKTFzYrr8pCmAIQvr3VH096bo7MK0t9/ld4OD4vAgknVMLbPiEgV8e23I iBXW6ZofL3dSEmIizeZ0kDegqO7SFDRoQkyqWUCQdsnhappMUIERmuYku8ATJUt+ Pa9NDDOc6VGKd3+LtmVCi3WtoYspaKIENx9hf47+kswVth8afhIEhND4ztBKqLd9 1jlr4sjotEFE1qphVyMfElWt4wf+mk0TzTo8KvuUn3jRdqxWy8WLVF7jrA565X7T BsjCVTxk9zebeN2pXYsg =f11y -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160223-1' into staging usb: misc bugfixes. # gpg: Signature made Tue 23 Feb 2016 10:53:01 GMT using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-usb-20160223-1: ohci: allocate timer only once. usb: add pid check at the first of uhci_handle_td() usb: check RNDIS buffer offsets & length usb: check RNDIS message length tusb6010: move from hw/timer to hw/usb usb: check USB configuration descriptor object Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ea6e4981bf
|
@ -25,7 +25,6 @@ obj-$(CONFIG_OMAP) += omap_gptimer.o
|
||||||
obj-$(CONFIG_OMAP) += omap_synctimer.o
|
obj-$(CONFIG_OMAP) += omap_synctimer.o
|
||||||
obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
|
obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
|
||||||
obj-$(CONFIG_SH4) += sh_timer.o
|
obj-$(CONFIG_SH4) += sh_timer.o
|
||||||
obj-$(CONFIG_TUSB6010) += tusb6010.o
|
|
||||||
obj-$(CONFIG_DIGIC) += digic-timer.o
|
obj-$(CONFIG_DIGIC) += digic-timer.o
|
||||||
|
|
||||||
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
|
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
|
||||||
|
|
|
@ -10,6 +10,8 @@ common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci-sysbus.o
|
||||||
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
|
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
|
||||||
common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
|
common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_TUSB6010) += tusb6010.o
|
||||||
|
|
||||||
# emulated usb devices
|
# emulated usb devices
|
||||||
common-obj-$(CONFIG_USB) += dev-hub.o
|
common-obj-$(CONFIG_USB) += dev-hub.o
|
||||||
common-obj-$(CONFIG_USB) += dev-hid.o
|
common-obj-$(CONFIG_USB) += dev-hid.o
|
||||||
|
|
|
@ -129,9 +129,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
||||||
|
s->setup_index = 0;
|
||||||
p->actual_length = 0;
|
p->actual_length = 0;
|
||||||
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||||
s->setup_index = 0;
|
if (s->setup_len > sizeof(s->data_buf)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||||
|
s->setup_len, sizeof(s->data_buf));
|
||||||
|
p->status = USB_RET_STALL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||||
|
@ -152,13 +159,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||||
}
|
}
|
||||||
s->setup_state = SETUP_STATE_DATA;
|
s->setup_state = SETUP_STATE_DATA;
|
||||||
} else {
|
} else {
|
||||||
if (s->setup_len > sizeof(s->data_buf)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
|
||||||
s->setup_len, sizeof(s->data_buf));
|
|
||||||
p->status = USB_RET_STALL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (s->setup_len == 0)
|
if (s->setup_len == 0)
|
||||||
s->setup_state = SETUP_STATE_ACK;
|
s->setup_state = SETUP_STATE_ACK;
|
||||||
else
|
else
|
||||||
|
@ -177,7 +177,7 @@ static void do_token_in(USBDevice *s, USBPacket *p)
|
||||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||||
|
|
||||||
switch(s->setup_state) {
|
switch(s->setup_state) {
|
||||||
case SETUP_STATE_ACK:
|
case SETUP_STATE_ACK:
|
||||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||||
|
|
|
@ -654,7 +654,8 @@ typedef struct USBNetState {
|
||||||
|
|
||||||
static int is_rndis(USBNetState *s)
|
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,
|
static int ndis_query(USBNetState *s, uint32_t oid,
|
||||||
|
@ -915,8 +916,9 @@ static int rndis_query_response(USBNetState *s,
|
||||||
|
|
||||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||||
if (bufoffs + buflen > length)
|
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||||
return USB_RET_STALL;
|
return USB_RET_STALL;
|
||||||
|
}
|
||||||
|
|
||||||
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
||||||
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
||||||
|
@ -961,8 +963,9 @@ static int rndis_set_response(USBNetState *s,
|
||||||
|
|
||||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||||
if (bufoffs + buflen > length)
|
if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||||
return USB_RET_STALL;
|
return USB_RET_STALL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
||||||
bufoffs + (uint8_t *) buf, buflen);
|
bufoffs + (uint8_t *) buf, buflen);
|
||||||
|
@ -1212,8 +1215,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
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);
|
qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s->out_ptr -= len;
|
s->out_ptr -= len;
|
||||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||||
|
|
|
@ -1347,16 +1347,6 @@ static void ohci_frame_boundary(void *opaque)
|
||||||
*/
|
*/
|
||||||
static int ohci_bus_start(OHCIState *ohci)
|
static int ohci_bus_start(OHCIState *ohci)
|
||||||
{
|
{
|
||||||
ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
|
||||||
ohci_frame_boundary,
|
|
||||||
ohci);
|
|
||||||
|
|
||||||
if (ohci->eof_timer == NULL) {
|
|
||||||
trace_usb_ohci_bus_eof_timer_failed(ohci->name);
|
|
||||||
ohci_die(ohci);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_usb_ohci_start(ohci->name);
|
trace_usb_ohci_start(ohci->name);
|
||||||
|
|
||||||
/* Delay the first SOF event by one frame time as
|
/* Delay the first SOF event by one frame time as
|
||||||
|
@ -1373,11 +1363,7 @@ static int ohci_bus_start(OHCIState *ohci)
|
||||||
static void ohci_bus_stop(OHCIState *ohci)
|
static void ohci_bus_stop(OHCIState *ohci)
|
||||||
{
|
{
|
||||||
trace_usb_ohci_stop(ohci->name);
|
trace_usb_ohci_stop(ohci->name);
|
||||||
if (ohci->eof_timer) {
|
timer_del(ohci->eof_timer);
|
||||||
timer_del(ohci->eof_timer);
|
|
||||||
timer_free(ohci->eof_timer);
|
|
||||||
}
|
|
||||||
ohci->eof_timer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets a flag in a port status register but only set it if the port is
|
/* Sets a flag in a port status register but only set it if the port is
|
||||||
|
@ -1907,6 +1893,9 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||||
usb_packet_init(&ohci->usb_packet);
|
usb_packet_init(&ohci->usb_packet);
|
||||||
|
|
||||||
ohci->async_td = 0;
|
ohci->async_td = 0;
|
||||||
|
|
||||||
|
ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
|
ohci_frame_boundary, ohci);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPE_PCI_OHCI "pci-ohci"
|
#define TYPE_PCI_OHCI "pci-ohci"
|
||||||
|
@ -1976,6 +1965,9 @@ static void usb_ohci_exit(PCIDevice *dev)
|
||||||
if (!ohci->masterbus) {
|
if (!ohci->masterbus) {
|
||||||
usb_bus_release(&s->bus);
|
usb_bus_release(&s->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer_del(s->eof_timer);
|
||||||
|
timer_free(s->eof_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_ohci_reset_pci(DeviceState *d)
|
static void usb_ohci_reset_pci(DeviceState *d)
|
||||||
|
@ -2041,23 +2033,13 @@ static bool ohci_eof_timer_needed(void *opaque)
|
||||||
{
|
{
|
||||||
OHCIState *ohci = opaque;
|
OHCIState *ohci = opaque;
|
||||||
|
|
||||||
return ohci->eof_timer != NULL;
|
return timer_pending(ohci->eof_timer);
|
||||||
}
|
|
||||||
|
|
||||||
static int ohci_eof_timer_pre_load(void *opaque)
|
|
||||||
{
|
|
||||||
OHCIState *ohci = opaque;
|
|
||||||
|
|
||||||
ohci_bus_start(ohci);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_ohci_eof_timer = {
|
static const VMStateDescription vmstate_ohci_eof_timer = {
|
||||||
.name = "ohci-core/eof-timer",
|
.name = "ohci-core/eof-timer",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.pre_load = ohci_eof_timer_pre_load,
|
|
||||||
.needed = ohci_eof_timer_needed,
|
.needed = ohci_eof_timer_needed,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_TIMER_PTR(eof_timer, OHCIState),
|
VMSTATE_TIMER_PTR(eof_timer, OHCIState),
|
||||||
|
|
|
@ -773,8 +773,22 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||||
bool spd;
|
bool spd;
|
||||||
bool queuing = (q != NULL);
|
bool queuing = (q != NULL);
|
||||||
uint8_t pid = td->token & 0xff;
|
uint8_t pid = td->token & 0xff;
|
||||||
UHCIAsync *async = uhci_async_find_td(s, td_addr);
|
UHCIAsync *async;
|
||||||
|
|
||||||
|
switch (pid) {
|
||||||
|
case USB_TOKEN_OUT:
|
||||||
|
case USB_TOKEN_SETUP:
|
||||||
|
case USB_TOKEN_IN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* invalid pid : frame interrupted */
|
||||||
|
s->status |= UHCI_STS_HCPERR;
|
||||||
|
s->cmd &= ~UHCI_CMD_RS;
|
||||||
|
uhci_update_irq(s);
|
||||||
|
return TD_RESULT_STOP_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
async = uhci_async_find_td(s, td_addr);
|
||||||
if (async) {
|
if (async) {
|
||||||
if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
|
if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
|
||||||
assert(q == NULL || q == async->queue);
|
assert(q == NULL || q == async->queue);
|
||||||
|
@ -880,11 +894,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* invalid pid : frame interrupted */
|
abort(); /* Never to execute */
|
||||||
uhci_async_free(async);
|
|
||||||
s->status |= UHCI_STS_HCPERR;
|
|
||||||
uhci_update_irq(s);
|
|
||||||
return TD_RESULT_STOP_FRAME;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (async->packet.status == USB_RET_ASYNC) {
|
if (async->packet.status == USB_RET_ASYNC) {
|
||||||
|
|
Loading…
Reference in a new issue