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-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0267c3c1-7268-bdac-ccb6-8aebf29311ca@roeck-us.net>
Date:   Sun, 5 Nov 2017 12:34:31 -0800
From:   Guenter Roeck <linux@...ck-us.net>
To:     Mike Looijmans <mike.looijmans@...ic.nl>,
        Alan Stern <stern@...land.harvard.edu>
Cc:     linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org,
        gregkh@...uxfoundation.org
Subject: Re: [PATCH][RFC] usb: hub: Cycle HUB power when initialization fails

On 11/05/2017 10:41 AM, Mike Looijmans wrote:
> On 03-11-17 18:27, Alan Stern wrote:
>> On Fri, 3 Nov 2017, Mike Looijmans wrote:
>>
>>> Sometimes the USB device gets confused about the state of the initialization and
>>> the connection fails. In particular, the device thinks that it's already set up
>>> and running while the host thinks the device still needs to be configured. To
>>
>> How do you know that this is really the issue?  How can the device
>> think it's already set if it doesn't have an assigned address?
> 
> It seems to me that the device just doesn't react at all on the host requests to assign an address. I've seen this happen with various custom mass-storage like appliances, but also DVB tuners and such. The device won't return to a working state until you unplug it and put it back, or, and that's what the patch does, just power-cycle the USB port, which has the same effect.
> 

We have seen this problem with Ethernet dongles left in a bad/hung state during
a previous boot, so it definitely does happen. This happened, for example, with
the r8152 driver with upstream commit 2f25abe6bac ("r8152: prevent the driver
from transmitting packets with carrier off") missing.

Problem though, as mentioned, is that many hubs don't implement this feature,
and if I understand correctly root hubs don't implement it either.

Guenter

>>> work around this issue, power-cycle the hub's output to issue a sort of "reset"
>>> to the device. This makes the device restart its state machine and then the
>>> initialization succeeds.
>>>
>>> This fixes problems where the kernel reports a list of errors like this:
>>>
>>> usb 1-1.3: device not accepting address 19, error -71
>>>
>>> The end result is a non-functioning device. After this patch, the sequence
>>> becomes like this:
>>>
>>> usb 1-1.3: new high-speed USB device number 18 using ci_hdrc
>>> usb 1-1.3: device not accepting address 18, error -71
>>> usb 1-1.3: new high-speed USB device number 19 using ci_hdrc
>>> usb 1-1.3: device not accepting address 19, error -71
>>> usb 1-1-port3: attempt power cycle
>>> usb 1-1.3: new high-speed USB device number 21 using ci_hdrc
>>> usb-storage 1-1.3:1.2: USB Mass Storage device detected
>>>
>>> Signed-off-by: Mike Looijmans <mike.looijmans@...ic.nl>
>>> ---
>>> This is a fix I did for a customer which might be appropriate for upstream. What do you think?
>>>
>>>   drivers/usb/core/hub.c | 13 ++++++++++---
>>>   1 file changed, 10 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
>>> index e9ce6bb..a30c1e7 100644
>>> --- a/drivers/usb/core/hub.c
>>> +++ b/drivers/usb/core/hub.c
>>> @@ -2611,7 +2611,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
>>>   #define PORT_RESET_TRIES    5
>>>   #define SET_ADDRESS_TRIES    2
>>>   #define GET_DESCRIPTOR_TRIES    2
>>> -#define SET_CONFIG_TRIES    (2 * (use_both_schemes + 1))
>>> +#define SET_CONFIG_TRIES    (4 * (use_both_schemes + 1))
>>
>> We already have too many retry loops.  I am not keen on the idea of
>> adding even more.  How about leaving this value the same and adding the
>> power cycle?
> 
> I'm fine with that as well.
> 
>> The ideal, however, would be to find out what is wrong with the device
>> and see what needs to be done to fix it properly.  This change won't
>> work on many computers (desktops and laptops) because they don't have
>> real USB port-power switching.  A lot of hubs don't have it either.
> 
> I'm pretty sure it's the device's fault, but they're out there and probably not upgradable anyway if you could get the manufacturer to pick up the phone.
> 
> On desktop/laptop machines the problem isn't as pressing since there's a often a user there who can unplug the thing. It's really nasty on embedded systems, and they tend to have the USB power wired through a supply limiter/switch.
> I'm thinking worst that could happen on desktops is that the patch won't have any effect at all.
> 
> So what do you think, is this worth a v2 patch for general consumption or should I keep this a "private" patch for systems that have demonstrated to benefit from it?
> 
> 
>>>   #define USE_NEW_SCHEME(i)    ((i) / 2 == (int)old_scheme_first)
>>>   #define HUB_ROOT_RESET_TIME    60    /* times are in msec */
>>> @@ -4805,7 +4805,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
>>>       status = 0;
>>>       for (i = 0; i < SET_CONFIG_TRIES; i++) {
>>> -
>>
>> Gratuitous whitespace change.
>>
>>>           /* reallocate for each attempt, since references
>>>            * to the previous one can escape in various ways
>>>            */
>>> @@ -4935,6 +4934,15 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
>>>           usb_put_dev(udev);
>>>           if ((status == -ENOTCONN) || (status == -ENOTSUPP))
>>>               break;
>>> +
>>> +        /* When halfway through our retry count, power-cycle the port */
>>> +        if (i == (SET_CONFIG_TRIES / 2) - 1) {
>>> +            dev_info(&port_dev->dev, "attempt power cycle\n");
>>> +            usb_hub_set_port_power(hdev, hub, port1, false);
>>> +            msleep(800);
>>> +            usb_hub_set_port_power(hdev, hub, port1, true);
>>> +            msleep(hub_power_on_good_delay(hub));
>>> +        }
>>>       }
>>>       if (hub->hdev->parent ||
>>>               !hcd->driver->port_handed_over ||
>>> @@ -5476,7 +5484,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
>>>       udev->bos = NULL;
>>>       for (i = 0; i < SET_CONFIG_TRIES; ++i) {
>>> -
>>
>> Another gratuitous change.
>>
>>>           /* ep0 maxpacket size may change; let the HCD know about it.
>>>            * Other endpoints will be handled by re-enumeration. */
>>>           usb_ep0_reinit(udev);
>>
>> Alan Stern
>>
> 
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ