On Wed, Feb 03, 2021 at 11:10:45AM +0000, Edd Barrett wrote:
> Hi,
> 
> CCing ratchov@ and kettenis@ with some context.
> 
> In short: my change broke ugen, which expects to scan up the interface
> range until an interface doesn't exist.
> 
> On Wed, Feb 03, 2021 at 06:25:48AM +0100, Marcus Glocker wrote:
> > 
> > Index: dev/usb/usbdi.c
> > ===================================================================
> > RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
> > retrieving revision 1.109
> > diff -u -p -u -p -r1.109 usbdi.c
> > --- dev/usb/usbdi.c     1 Feb 2021 09:21:51 -0000       1.109
> > +++ dev/usb/usbdi.c     2 Feb 2021 06:07:41 -0000
> > @@ -642,6 +642,10 @@ usbd_device2interface_handle(struct usbd
> > 
> >         if (dev->cdesc == NULL)
> >                 return (USBD_NOT_CONFIGURED);
> > +       if (ifaceno < dev->cdesc->bNumInterfaces) {
> > +               *iface = &dev->ifaces[ifaceno];
> > +               return (USBD_NORMAL_COMPLETION);
> > +       }
> >         /*
> >          * The correct interface should be at dev->ifaces[ifaceno], but 
> > we've
> >          * seen non-compliant devices in the wild which present 
> > non-contiguous
> >
> > So OK if I commit this fix Edd, Stuart?
> 
> I'm OK with it as a quick-fix. At least it will make both of the devices
> in question work.
> 
> But in the long run, it's not hard to imagine other non-compliant
> devices which would still be defeated by this code.
> 
> Suppose a device presents its contiguous interfaces in reverse order, e.g.:
> [2, 1, 0]. Now suppose a device driver asks for interface 2. We will
> find interface 0, as we never check if it's the right interface and we
> never reach the part of the code that scans the array.
> 
> In other words, just because an index exists, doesn't mean it's the right
> interface.
> 
> I think (and I'm not much of a kernel hacker, so I reserve the right be wrong)
> the correct solution is to:
> 
>  * always loop over the array looking for the right interface.
>  * change ugen, so that it's scanning resilient to gaps in interface range.
> 

Not sure is your above proposition enough. Here is part of dmesg with
some debugging statments for 2 devices which trigger 
usbd_device2interface_handle()

See MMM markers.

...
ulpt0 at uhub0 port 3 configuration 1 interface 1 "Samsung Electronics Co., 
Ltd. M2070 Series" rev 2.00/1.00 addr 2
ulpt0: using bi-directional mode
ugen0 at uhub0 port 3 configuration 1 "Samsung Electronics Co., Ltd. M2070 
Series" rev 2.00/1.00 addr 2
MMM: USBD_NORMAL_COMPLETION v1 ifaceno=0 bNumInterfaces=2 
[usbd_device2interface_handle()|usbdi.c|649]
uhub2 at uhub1 port 1 configuration 1 interface 0 "Advanced Micro Devices Hub" 
rev 2.00/0.18 addr 2
umb0 at uhub2 port 3 configuration 1 interface 12 "Sierra Wireless, 
Incorporated Sierra Wireless MC7455 Qualcomm\M-. Snapdragon? X7 LTE-A" rev 
2.00/0.06 addr 3
ugen1 at uhub2 port 3 configuration 1 "Sierra Wireless, Incorporated Sierra 
Wireless MC7455 Qualcomm\M-. Snapdragon? X7 LTE-A" rev 2.00/0.06 addr 3
MMM: USBD_NORMAL_COMPLETION v1 ifaceno=0 bNumInterfaces=5 
[usbd_device2interface_handle()|usbdi.c|649]
MMM: USBD_NORMAL_COMPLETION v1 ifaceno=1 bNumInterfaces=5 
[usbd_device2interface_handle()|usbdi.c|649]
MMM: USBD_NORMAL_COMPLETION v1 ifaceno=2 bNumInterfaces=5 
[usbd_device2interface_handle()|usbdi.c|649]
vscsi0 at root
scsibus2 at vscsi0: 256 targets
...

For ugen1 (belongs to physical device, whih also attaches a umb(4)) we
can see that ifaceno has value of 0, 1, 2, but from lsusb we see that:

(from earliers Marcus Glocker's email)

Index   Interface Number
-----   ---------------
0       0
1       2
2       3
3       12
4       13

for ifaceno 1 and 2 it will not equal to bInterfaceNumber if we iterate
the for (idx = 0; idx < dev->cdesc->bNumInterfaces; idx++) loop.

I don't have good picture for how all the functions work with each
other, but it does feel like substantial work is needed here, to piece
everything together.

-- 
Regards,
 Mikolaj

Reply via email to