netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Emil Goode <emilgoode@gmail.com>
To: "Bjørn Mork" <bjorn@mork.no>
Cc: Steve Glendinning <steve.glendinning@shawell.net>,
	Oliver Neukum <oneukum@suse.de>,
	"David S. Miller" <davem@davemloft.net>,
	Freddy Xin <freddy@asix.com.tw>,
	Eric Dumazet <edumazet@google.com>,
	Ming Lei <ming.lei@canonical.com>,
	Paul Gortmaker <paul.gortmaker@windriver.com>,
	Jeff Kirsher <jeffrey.t.kirsher@intel.com>,
	Liu Junliang <liujunliang_ljl@163.com>,
	Octavian Purdila <octavian.purdila@intel.com>,
	linux-usb@vger.kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH] usbnet: remove generic hard_header_len check
Date: Thu, 13 Feb 2014 12:20:16 +0100	[thread overview]
Message-ID: <20140213112016.GA4245@lianli> (raw)
In-Reply-To: <87fvnn4c2k.fsf@nemi.mork.no>

On Thu, Feb 13, 2014 at 10:05:39AM +0100, Bjørn Mork wrote:
> Emil Goode <emilgoode@gmail.com> writes:
> 
> > This patch removes a generic hard_header_len check from the usbnet
> > module that is causing dropped packages under certain circumstances
> > for devices that send rx packets that cross urb boundaries.
> >
> > One example is the AX88772B which occasionally send rx packets that
> > cross urb boundaries where the remaining partial packet is sent with
> > no hardware header. When the buffer with a partial packet is of less
> > number of octets than the value of hard_header_len the buffer is
> > discarded by the usbnet module.
> >
> > With AX88772B this can be reproduced by using ping with a packet
> > size between 1965-1976.
> >
> > The bug has been reported here:
> >
> > https://bugzilla.kernel.org/show_bug.cgi?id=29082
> >
> > This patch introduces the following changes:
> > - Removes the generic hard_header_len check in the rx_complete
> >   function in the usbnet module.
> > - Introduces a ETH_HLEN check for skbs that are not cloned from
> >   within a rx_fixup callback.
> > - For safety a hard_header_len check is added to each rx_fixup
> >   callback function that could be affected by this change.
> >   These extra checks could possibly be removed by someone
> >   who has the hardware to test.
> >
> > The changes place full responsibility on the rx_fixup callback
> > functions that clone skbs to only pass valid skbs to the
> > usbnet_skb_return function.
> >
> > Signed-off-by: Emil Goode <emilgoode@gmail.com>
> > Reported-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
> 
> 
> Great work!  Looks good to me.

Thank you :)

> Just a couple of questions:
> 
> > diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
> > index ff5c871..b2e2aee 100644
> > --- a/drivers/net/usb/qmi_wwan.c
> > +++ b/drivers/net/usb/qmi_wwan.c
> > @@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> >  {
> >  	__be16 proto;
> >  
> > -	/* usbnet rx_complete guarantees that skb->len is at least
> > -	 * hard_header_len, so we can inspect the dest address without
> > -	 * checking skb->len
> > -	 */
> > +	/* This check is no longer done by usbnet */
> > +	if (skb->len < dev->net->hard_header_len)
> > +		return 0;
> > +
> >  	switch (skb->data[0] & 0xf0) {
> >  	case 0x40:
> >  		proto = htons(ETH_P_IP);
> > diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
> > index a48bc0f..524a47a 100644
> > --- a/drivers/net/usb/rndis_host.c
> > +++ b/drivers/net/usb/rndis_host.c
> > @@ -492,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
> >   */
> >  int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> >  {
> > +	/* This check is no longer done by usbnet */
> > +	if (skb->len < dev->net->hard_header_len)
> > +		return 0;
> > +
> 
> Wouldn't it be better to test against ETH_HLEN, since that is a constant
> and "obviously correct" in this case?
 
Some minidrivers change the default hard_header_len value so using it
guarantees that the patch will not make any change to how the code is
currently working. Using ETH_HLEN could be more informative about what
the minidriver should check before passing skbs to usbnet_skb_return().
Then I think the comment should be changed as well. My intention was to
not make any changes that affect how the code works for devices I cannot
test, but I think either way is fine and if you insist on changing it
let me know.

> > diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
> > index 4671da7..dd10d58 100644
> > --- a/drivers/net/usb/usbnet.c
> > +++ b/drivers/net/usb/usbnet.c
> > @@ -542,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
> >  	}
> >  	// else network stack removes extra byte if we forced a short packet
> >  
> > -	if (skb->len) {
> > -		/* all data was already cloned from skb inside the driver */
> > -		if (dev->driver_info->flags & FLAG_MULTI_PACKET)
> > -			dev_kfree_skb_any(skb);
> > -		else
> > -			usbnet_skb_return(dev, skb);
> > +	/* all data was already cloned from skb inside the driver */
> > +	if (dev->driver_info->flags & FLAG_MULTI_PACKET)
> > +		goto done;
> > +
> > +	if (skb->len < ETH_HLEN) {
> > +		dev->net->stats.rx_errors++;
> > +		dev->net->stats.rx_length_errors++;
> > +		netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
> > +	} else {
> > +		usbnet_skb_return(dev, skb);
> >  		return;
> >  	}
> >  
> > -	netif_dbg(dev, rx_err, dev->net, "drop\n");
> > -	dev->net->stats.rx_errors++;
> >  done:
> >  	skb_queue_tail(&dev->done, skb);
> >  }
> 
> 
> At first glance I wondered where the dev_kfree_skb_any(skb) went.  But
> then I realized that you leave that to the common rx_cleanup path, using
> the dev->done queue.  Is that right?  If so, then I guess it could use a
> bit of explaining in the commit message?

Yes I should have put a comment in the changelog about this. All skbs that
are passed to rx_process have their state set to rx_cleanup and just because
the skb was cloned doesn't mean that we should free the original in a
different way. As it is I think we are acctually missing a call to
usb_free_urb that is called on the common rx_cleanup path.
I will resend and add a comment about this.

Best regards,

Emil Goode

  reply	other threads:[~2014-02-13 11:20 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-13  0:03 [PATCH] usbnet: remove generic hard_header_len check Emil Goode
2014-02-13  9:05 ` Bjørn Mork
2014-02-13 11:20   ` Emil Goode [this message]
2014-02-13 11:36     ` Bjørn Mork
2014-02-13 11:49     ` David Laight

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140213112016.GA4245@lianli \
    --to=emilgoode@gmail.com \
    --cc=bjorn@mork.no \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=freddy@asix.com.tw \
    --cc=jeffrey.t.kirsher@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=liujunliang_ljl@163.com \
    --cc=ming.lei@canonical.com \
    --cc=netdev@vger.kernel.org \
    --cc=octavian.purdila@intel.com \
    --cc=oneukum@suse.de \
    --cc=paul.gortmaker@windriver.com \
    --cc=steve.glendinning@shawell.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).