⬢ DragonFlyBSD Kernel Audit
DF-5407 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/u4b/serial/uplcom.c
+++ b/sys/bus/u4b/serial/uplcom.c
@@ -121,6 +121,15 @@
 #define	UPLCOM_INTR_INTERVAL		0	/* default */
 #endif
 
+/*
+ * Attach-path control-request timeout bound: uplcom_reset() plus
+ * uplcom_pl2303_init() chain 14 sequential synchronous EP0 requests, and
+ * usbd_do_request() defaults to a 5000 ms timeout, so an in-spec-but-slow
+ * (NAK-ing) device could pin the per-bus USB explore thread for ~70 s
+ * during attach.  Bound each request to 250 ms instead.
+ */
+#define	UPLCOM_INIT_TIMEOUT		250	/* ms */
+
 #define	UPLCOM_BULK_BUF_SIZE 1024	/* bytes */
 
 #define	UPLCOM_SET_REQUEST		0x01
@@ -162,7 +171,7 @@
 
 static usb_error_t uplcom_reset(struct uplcom_softc *, struct usb_device *);
 static usb_error_t uplcom_pl2303_do(struct usb_device *, int8_t, uint8_t,
-			uint16_t, uint16_t, uint16_t);
+			uint16_t, uint16_t, uint16_t, usb_timeout_t);
 static int	uplcom_pl2303_init(struct usb_device *, uint8_t);
 static void	uplcom_cfg_set_dtr(struct ucom_softc *, uint8_t);
 static void	uplcom_cfg_set_rts(struct ucom_softc *, uint8_t);
@@ -469,12 +478,13 @@
 	req.wIndex[1] = 0;
 	USETW(req.wLength, 0);
 
-	return (usbd_do_request(udev, NULL, &req, NULL));
+	return (usbd_do_request_flags(udev, NULL, &req, NULL, 0, NULL,
+	    UPLCOM_INIT_TIMEOUT));
 }
 
 static usb_error_t
 uplcom_pl2303_do(struct usb_device *udev, int8_t req_type, uint8_t request,
-    uint16_t value, uint16_t index, uint16_t length)
+    uint16_t value, uint16_t index, uint16_t length, usb_timeout_t timeout)
 {
 	struct usb_device_request req;
 	usb_error_t err;
@@ -486,7 +496,7 @@
 	USETW(req.wIndex, index);
 	USETW(req.wLength, length);
 
-	err = usbd_do_request(udev, NULL, &req, buf);
+	err = usbd_do_request_flags(udev, NULL, &req, buf, 0, NULL, timeout);
 	if (err) {
 		DPRINTF("error=%s\n", usbd_errstr(err));
 		return (1);
@@ -499,27 +509,27 @@
 {
 	int err;
 
-	if (uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0)
-	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0)
-	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0))
+	if (uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0, UPLCOM_INIT_TIMEOUT))
 		return (EIO);
 
 	if (chiptype == TYPE_PL2303HX)
-		err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0);
+		err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0, UPLCOM_INIT_TIMEOUT);
 	else
-		err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0);
+		err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0, UPLCOM_INIT_TIMEOUT);
 	if (err)
 		return (EIO);
 
-	if (uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0))
+	if (uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0, UPLCOM_INIT_TIMEOUT)
+	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0, UPLCOM_INIT_TIMEOUT))
 		return (EIO);
 	return (0);
 }