Re: BUG: iPNPstring in f_printer USB gadget is reduced by two bytes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> On Tue, Nov 30, 2021 at 08:01:46PM +0200, Volodymyr Lisivka wrote:
> > Description:
> >
> > Printer USB gadget uses iPNPstring to communicate device name and
> > command language with host. Linux driver for printer gadget sends
> > GET_DEVICE_ID response packet without 2 last bytes, which may cause
> > trouble for the host driver.
> >
> > Steps to reproduce:
> >
> > Use Raspberry Pi, or an other device with USB OTG plug. Raspberry Pi 4
> > was used by issue author.
> > Configure plug to be in peripheral mode, e.g. by adding
> > dtoverlay=dwc2,dr_mode=peripheral to /boot/config.txt.
> > Connect OTG port to host and reboot Raspberry Pi.
> > Load g_printer module using command sudo modprobe g_printer.
> > Use command ./get-iPNPstring.pl /dev/usb/lp1 to get iPNPstring from
> > the device. (See get-iPNPstring.pl.gz ). As alternative, kernel usbmon
> > or WireShark can be used to capture raw USB packet for GET_DEVICE_ID
> > response.
> >
> > Expected result:
> >
> > It's expected to receive same string as defined in module:
> > iPNPstring='MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;'
> >
> > Actual result:
> >
> > iPNPstring='MFG:linux;MDL:g_printer;CLS:PRINTER;SN:'
> >
> > (Notice that last 2 chars are missing).
> >
> > Workarround:
> >
> > Just add two space to the end of printer gadget iPNPstring.
> >
> > Root cause:
> >
> > In drivers/usb/gadget/function/f_printer.c, length of iPNPstring is
> > used as length of the whole packet, without length of 2 byte size
> > field.
>
> If I understand correctly, the length should be inclusive of the two
> length bytes, but currently this driver encodes it exclusive.
>
> The USB printer class specification says:
>
> ... a device ID string that is compatible with IEEE 1284.  See
> IEEE 1284 for syntax and formatting information
>
> and goes on to specify that this includes the length in the first two
> bytes as big endian.
>
> I don't have access to IEEE 1284, but looking in drivers/parport/probe.c
> which implements the host side of IEEE 1284, we find
> parport_read_device_id() with the comment:
>
> /* Some devices wrongly send LE length, and some send it two
> * bytes short. Construct a sorted array of lengths to try. */
>
> and code that assumes the values are inclusive of the length bytes.
>
> So the patch below looks like it does the right thing to me, although it
> appears whitespace damaged and it may be clearer to introduce a separate
> variable for the string length compared to the value.

diff --git a/drivers/usb/gadget/function/f_printer.c
b/drivers/usb/gadget/function/f_printer.c
index 236ecc968..403faa05b 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -987,6 +987,7 @@ static int printer_func_setup(struct usb_function *f,
        u16                     wIndex = le16_to_cpu(ctrl->wIndex);
        u16                     wValue = le16_to_cpu(ctrl->wValue);
        u16                     wLength = le16_to_cpu(ctrl->wLength);
+       u16                     pnp_length;

        DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
                ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
@@ -1003,11 +1004,12 @@ static int printer_func_setup(struct usb_function *f,
                                value = 0;
                                break;
                        }
-                       value = strlen(dev->pnp_string);
+                       pnp_length = strlen(dev->pnp_string);
+                       value = pnp_length + 2;
                        buf[0] = (value >> 8) & 0xFF;
                        buf[1] = value & 0xFF;
-                       memcpy(buf + 2, dev->pnp_string, value);
-                       DBG(dev, "1284 PNP String: %x %s\n", value,
+                       memcpy(buf + 2, dev->pnp_string, pnp_length);
+                       DBG(dev, "1284 PNP String: %x %s\n", pnp_length,
                            dev->pnp_string);
                        break;



>
> Are you interested in working up a proper patch, as described in
> Documentation/process/submitting-patches.rst ?
>

No. It's my second patch in 15 years. If you have a proper procedure
for diffing/patching, then make corresponding targets in the top
Makefile, e.g. `make diff` or `make patch`.



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux