lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210915121615.3790-1-heghedus.razvan@gmail.com>
Date:   Wed, 15 Sep 2021 15:16:13 +0300
From:   Razvan Heghedus <heghedus.razvan@...il.com>
To:     unlisted-recipients:; (no To-header on input)
Cc:     heghedus.razvan@...il.com,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Johan Hovold <johan@...nel.org>,
        Peter Chen <peter.chen@....com>,
        Anant Thazhemadam <anant.thazhemadam@...il.com>,
        linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH v2] usb: misc: ehset: Workaround for "special" hubs

The USB2.0 spec chapter 11.24.2.13 says that the USB port which is going
under test needs to be put in suspend state before sending the test
command. Many hubs, don't enforce this precondition and they work fine
without this step. But there are some "special" hubs, which requires to
disable the port power before sending the test command.

Because the USB spec mention that the port should be suspended, also
do this step before sending the test command. This could rise the
problem with other hubs which are not compliant with the spec and the
test command will not work if the port is suspend. If such hubs are
found, a similar workaround like the disable part could be implemented
to skip the suspend port command.

Signed-off-by: Razvan Heghedus <heghedus.razvan@...il.com>
---
 Changes in v2:
  - style change regarding multi-line comments and a new black line
    after local variable definitions
  - No more corporate email annotation
This time without that corporate email annotation.
Also has a couple of style changes regardind multi-line comments and a
black line after local variable definitions.
 drivers/usb/misc/ehset.c | 81 ++++++++++++++++++++++++++++++++--------
 1 file changed, 65 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
index f87890f9cd26..b848bbdee802 100644
--- a/drivers/usb/misc/ehset.c
+++ b/drivers/usb/misc/ehset.c
@@ -18,6 +18,47 @@
 #define TEST_SINGLE_STEP_GET_DEV_DESC		0x0107
 #define TEST_SINGLE_STEP_SET_FEATURE		0x0108
 
+/*
+ * A list of USB hubs which requires to disable the power
+ * to the port before starting the testing procedures.
+ */
+static const struct usb_device_id ehset_hub_list[] = {
+	{USB_DEVICE(0x0424, 0x4502)},
+	{USB_DEVICE(0x0424, 0x4913)},
+	{USB_DEVICE(0x0451, 0x8027)},
+	{}
+};
+
+static int ehset_prepare_port_for_testing(struct usb_device *hub_udev, u16 portnum)
+{
+	int ret = 0;
+
+	/*
+	 * The USB2.0 spec chapter 11.24.2.13 says that the USB port which is
+	 * going under test needs to be put in suspend before sending the
+	 * test command. Most hubs don't enforce this precondition, but there
+	 * are some hubs which needs to disable the power to the port before
+	 * starting the test.
+	 */
+	if (usb_match_id(to_usb_interface(hub_udev->dev.parent), ehset_hub_list)) {
+		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_CLEAR_FEATURE,
+					   USB_RT_PORT, USB_PORT_FEAT_ENABLE,
+					   portnum, NULL, 0, 1000, GFP_KERNEL);
+		/* Wait for the port to be disabled. It's an arbitrary value
+		 * which worked every time.
+		 */
+		msleep(100);
+	} else {
+		/* For the hubs which are compliant with the spec,
+		 * put the port in SUSPEND.
+		 */
+		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+					   USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
+					   portnum, NULL, 0, 1000, GFP_KERNEL);
+	}
+	return ret;
+}
+
 static int ehset_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
@@ -30,28 +71,36 @@ static int ehset_probe(struct usb_interface *intf,
 
 	switch (test_pid) {
 	case TEST_SE0_NAK_PID:
-		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-					   USB_RT_PORT, USB_PORT_FEAT_TEST,
-					   (USB_TEST_SE0_NAK << 8) | portnum,
-					   NULL, 0, 1000, GFP_KERNEL);
+		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+		if (!ret)
+			ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+						   USB_RT_PORT, USB_PORT_FEAT_TEST,
+						   (USB_TEST_SE0_NAK << 8) | portnum,
+						   NULL, 0, 1000, GFP_KERNEL);
 		break;
 	case TEST_J_PID:
-		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-					   USB_RT_PORT, USB_PORT_FEAT_TEST,
-					   (USB_TEST_J << 8) | portnum, NULL, 0,
-					   1000, GFP_KERNEL);
+		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+		if (!ret)
+			ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+						   USB_RT_PORT, USB_PORT_FEAT_TEST,
+						   (USB_TEST_J << 8) | portnum, NULL, 0,
+						   1000, GFP_KERNEL);
 		break;
 	case TEST_K_PID:
-		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-					   USB_RT_PORT, USB_PORT_FEAT_TEST,
-					   (USB_TEST_K << 8) | portnum, NULL, 0,
-					   1000, GFP_KERNEL);
+		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+		if (!ret)
+			ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+						   USB_RT_PORT, USB_PORT_FEAT_TEST,
+						   (USB_TEST_K << 8) | portnum, NULL, 0,
+						   1000, GFP_KERNEL);
 		break;
 	case TEST_PACKET_PID:
-		ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
-					   USB_RT_PORT, USB_PORT_FEAT_TEST,
-					   (USB_TEST_PACKET << 8) | portnum,
-					   NULL, 0, 1000, GFP_KERNEL);
+		ret = ehset_prepare_port_for_testing(hub_udev, portnum);
+		if (!ret)
+			ret = usb_control_msg_send(hub_udev, 0, USB_REQ_SET_FEATURE,
+						   USB_RT_PORT, USB_PORT_FEAT_TEST,
+						   (USB_TEST_PACKET << 8) | portnum,
+						   NULL, 0, 1000, GFP_KERNEL);
 		break;
 	case TEST_HS_HOST_PORT_SUSPEND_RESUME:
 		/* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
-- 
2.33.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ