aboutsummaryrefslogtreecommitdiff
path: root/hw/usb
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-03-07 14:06:42 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-03-07 14:06:42 +0000
commit3a75ef6a0fe397b0d36930415be6b123750a6afe (patch)
tree86c709408efdab7dc6e1642820a16327748af519 /hw/usb
parent32694e98b8d7a246345448a8f707d2e11d6c65e2 (diff)
parentba4c735b4fc74e309ce4b2551d258e442ef513a5 (diff)
Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190307-pull-request' into staging
usb: mtp fixes, guest-reset switch for usb-host. # gpg: Signature made Thu 07 Mar 2019 09:53:55 GMT # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/usb-20190307-pull-request: Introduce new "no_guest_reset" parameter for usb-host device usb-mtp: prevent null dereference while deleting objects usb-mtp: fix some usb_mtp_write_data return paths usb-mtp: return incomplete transfer on a lstat failure Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/usb')
-rw-r--r--hw/usb/dev-mtp.c41
-rw-r--r--hw/usb/host-libusb.c7
2 files changed, 31 insertions, 17 deletions
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 4ee4fc5a89..06e376bcd2 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -1177,9 +1177,7 @@ static int usb_mtp_deletefn(MTPState *s, MTPObject *o, uint32_t trans)
usb_mtp_object_free_one(s, o);
success = true;
}
- }
-
- if (o->format == FMT_ASSOCIATION) {
+ } else if (o->format == FMT_ASSOCIATION) {
if (rmdir(o->path)) {
partial_delete = true;
} else {
@@ -1591,17 +1589,21 @@ done:
return ret;
}
-static void usb_mtp_update_object(MTPObject *parent, char *name)
+static int usb_mtp_update_object(MTPObject *parent, char *name)
{
+ int ret = -1;
+
MTPObject *o =
usb_mtp_object_lookup_name(parent, name, strlen(name));
if (o) {
- lstat(o->path, &o->stat);
+ ret = lstat(o->path, &o->stat);
}
+
+ return ret;
}
-static void usb_mtp_write_data(MTPState *s)
+static int usb_mtp_write_data(MTPState *s)
{
MTPData *d = s->data_out;
MTPObject *parent =
@@ -1609,6 +1611,7 @@ static void usb_mtp_write_data(MTPState *s)
char *path = NULL;
uint64_t rc;
mode_t mask = 0644;
+ int ret = 0;
assert(d != NULL);
@@ -1617,13 +1620,13 @@ static void usb_mtp_write_data(MTPState *s)
if (!parent || !s->write_pending) {
usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
0, 0, 0, 0);
- return;
+ return 1;
}
if (s->dataset.filename) {
path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename);
if (s->dataset.format == FMT_ASSOCIATION) {
- d->fd = mkdir(path, mask);
+ ret = mkdir(path, mask);
goto free;
}
d->fd = open(path, O_CREAT | O_WRONLY |
@@ -1653,15 +1656,21 @@ static void usb_mtp_write_data(MTPState *s)
goto done;
}
if (d->write_status != WRITE_END) {
- return;
+ g_free(path);
+ return ret;
} else {
- /* Only for < 4G file sizes */
- if (s->dataset.size != 0xFFFFFFFF && d->offset != s->dataset.size) {
+ /*
+ * Return an incomplete transfer if file size doesn't match
+ * for < 4G file or if lstat fails which will result in an incorrect
+ * file size
+ */
+ if ((s->dataset.size != 0xFFFFFFFF &&
+ d->offset != s->dataset.size) ||
+ usb_mtp_update_object(parent, s->dataset.filename)) {
usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans,
0, 0, 0, 0);
goto done;
}
- usb_mtp_update_object(parent, s->dataset.filename);
}
}
@@ -1676,12 +1685,14 @@ done:
*/
if (d->fd != -1) {
close(d->fd);
+ d->fd = -1;
}
free:
g_free(s->dataset.filename);
s->dataset.size = 0;
g_free(path);
s->write_pending = false;
+ return ret;
}
static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
@@ -1718,14 +1729,12 @@ static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
s->write_pending = true;
if (s->dataset.format == FMT_ASSOCIATION) {
- usb_mtp_write_data(s);
- /* next_handle will be allocated to the newly created dir */
- if (d->fd == -1) {
+ if (usb_mtp_write_data(s)) {
+ /* next_handle will be allocated to the newly created dir */
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
return;
}
- d->fd = -1;
}
usb_mtp_queue_result(s, RES_OK, d->trans, 3, QEMU_STORAGE_ID,
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 833250a886..67b7465915 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -82,7 +82,7 @@ struct USBHostDevice {
uint32_t options;
uint32_t loglevel;
bool needs_autoscan;
-
+ bool allow_guest_reset;
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
int seen, errcount;
@@ -1456,6 +1456,10 @@ static void usb_host_handle_reset(USBDevice *udev)
USBHostDevice *s = USB_HOST_DEVICE(udev);
int rc;
+ if (!s->allow_guest_reset) {
+ return;
+ }
+
trace_usb_host_reset(s->bus_num, s->addr);
rc = libusb_reset_device(s->dh);
@@ -1573,6 +1577,7 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
+ DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true),
DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
LIBUSB_LOG_LEVEL_WARNING),
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,