mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 18:09:57 +00:00
net: cdc_ncm: fix control message ordering
This is a context modified revert of commit6a9612e2cb
("net: cdc_ncm: remove ncm_parm field") which introduced a NCM specification violation, causing setup errors for some devices. These errors resulted in the device and host disagreeing about shared settings, with complete failure to communicate as the end result. The NCM specification require that many of the NCM specific control reuests are sent only while the NCM Data Interface is in alternate setting 0. Reverting the commit ensures that we follow this requirement. Fixes:6a9612e2cb
("net: cdc_ncm: remove ncm_parm field") Reported-and-tested-by: Pasi Kärkkäinen <pasik@iki.fi> Reported-by: Thomas Schäfer <tschaefer@t-online.de> Signed-off-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e367c2d03d
commit
ff0992e903
2 changed files with 24 additions and 25 deletions
|
@ -68,7 +68,6 @@ static struct usb_driver cdc_ncm_driver;
|
|||
static int cdc_ncm_setup(struct usbnet *dev)
|
||||
{
|
||||
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
|
||||
struct usb_cdc_ncm_ntb_parameters ncm_parm;
|
||||
u32 val;
|
||||
u8 flags;
|
||||
u8 iface_no;
|
||||
|
@ -82,22 +81,22 @@ static int cdc_ncm_setup(struct usbnet *dev)
|
|||
err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
|
||||
USB_TYPE_CLASS | USB_DIR_IN
|
||||
|USB_RECIP_INTERFACE,
|
||||
0, iface_no, &ncm_parm,
|
||||
sizeof(ncm_parm));
|
||||
0, iface_no, &ctx->ncm_parm,
|
||||
sizeof(ctx->ncm_parm));
|
||||
if (err < 0) {
|
||||
dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
|
||||
return err; /* GET_NTB_PARAMETERS is required */
|
||||
}
|
||||
|
||||
/* read correct set of parameters according to device mode */
|
||||
ctx->rx_max = le32_to_cpu(ncm_parm.dwNtbInMaxSize);
|
||||
ctx->tx_max = le32_to_cpu(ncm_parm.dwNtbOutMaxSize);
|
||||
ctx->tx_remainder = le16_to_cpu(ncm_parm.wNdpOutPayloadRemainder);
|
||||
ctx->tx_modulus = le16_to_cpu(ncm_parm.wNdpOutDivisor);
|
||||
ctx->tx_ndp_modulus = le16_to_cpu(ncm_parm.wNdpOutAlignment);
|
||||
ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
|
||||
ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
|
||||
ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
|
||||
ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
|
||||
ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
|
||||
/* devices prior to NCM Errata shall set this field to zero */
|
||||
ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams);
|
||||
ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported);
|
||||
ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
|
||||
ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
|
||||
|
||||
/* there are some minor differences in NCM and MBIM defaults */
|
||||
if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
|
||||
|
@ -146,7 +145,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
|
|||
}
|
||||
|
||||
/* inform device about NTB input size changes */
|
||||
if (ctx->rx_max != le32_to_cpu(ncm_parm.dwNtbInMaxSize)) {
|
||||
if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
|
||||
__le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
|
||||
|
||||
err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
|
||||
|
@ -162,14 +161,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
|
|||
dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
|
||||
CDC_NCM_NTB_MAX_SIZE_TX);
|
||||
ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
|
||||
|
||||
/* Adding a pad byte here simplifies the handling in
|
||||
* cdc_ncm_fill_tx_frame, by making tx_max always
|
||||
* represent the real skb max size.
|
||||
*/
|
||||
if (ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
|
||||
ctx->tx_max++;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -439,6 +430,10 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|||
goto error2;
|
||||
}
|
||||
|
||||
/* initialize data interface */
|
||||
if (cdc_ncm_setup(dev))
|
||||
goto error2;
|
||||
|
||||
/* configure data interface */
|
||||
temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
|
||||
if (temp) {
|
||||
|
@ -453,12 +448,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|||
goto error2;
|
||||
}
|
||||
|
||||
/* initialize data interface */
|
||||
if (cdc_ncm_setup(dev)) {
|
||||
dev_dbg(&intf->dev, "cdc_ncm_setup() failed\n");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
usb_set_intfdata(ctx->data, dev);
|
||||
usb_set_intfdata(ctx->control, dev);
|
||||
|
||||
|
@ -475,6 +464,15 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
|
|||
dev->hard_mtu = ctx->tx_max;
|
||||
dev->rx_urb_size = ctx->rx_max;
|
||||
|
||||
/* cdc_ncm_setup will override dwNtbOutMaxSize if it is
|
||||
* outside the sane range. Adding a pad byte here if necessary
|
||||
* simplifies the handling in cdc_ncm_fill_tx_frame, making
|
||||
* tx_max always represent the real skb max size.
|
||||
*/
|
||||
if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
|
||||
ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
|
||||
ctx->tx_max++;
|
||||
|
||||
return 0;
|
||||
|
||||
error2:
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
#define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
|
||||
|
||||
struct cdc_ncm_ctx {
|
||||
struct usb_cdc_ncm_ntb_parameters ncm_parm;
|
||||
struct hrtimer tx_timer;
|
||||
struct tasklet_struct bh;
|
||||
|
||||
|
|
Loading…
Reference in a new issue