Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb85569f authored by Emil Goode's avatar Emil Goode Committed by David S. Miller
Browse files

usbnet: remove generic hard_header_len check

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.
- Removes a call to dev_kfree_skb_any() and instead utilizes the
  dev->done list to queue skbs for cleanup.

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: default avatarEmil Goode <emilgoode@gmail.com>
Reported-by: default avatarIgor Gnatenko <i.gnatenko.brain@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 08b44656
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -1118,6 +1118,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
	u16 hdr_off;
	u16 hdr_off;
	u32 *pkt_hdr;
	u32 *pkt_hdr;


	/* This check is no longer done by usbnet */
	if (skb->len < dev->net->hard_header_len)
		return 0;

	skb_trim(skb, skb->len - 4);
	skb_trim(skb, skb->len - 4);
	memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
	memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
	le32_to_cpus(&rx_hdr);
	le32_to_cpus(&rx_hdr);
+4 −0
Original line number Original line Diff line number Diff line
@@ -84,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
	u32			size;
	u32			size;
	u32			count;
	u32			count;


	/* This check is no longer done by usbnet */
	if (skb->len < dev->net->hard_header_len)
		return 0;

	header = (struct gl_header *) skb->data;
	header = (struct gl_header *) skb->data;


	// get the packet count of the received skb
	// get the packet count of the received skb
+3 −2
Original line number Original line Diff line number Diff line
@@ -526,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
{
	u8 status;
	u8 status;


	if (skb->len == 0) {
	/* This check is no longer done by usbnet */
		dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
	if (skb->len < dev->net->hard_header_len) {
		dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
		return 0;
		return 0;
	}
	}


+4 −0
Original line number Original line Diff line number Diff line
@@ -364,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
	struct nc_trailer	*trailer;
	struct nc_trailer	*trailer;
	u16			hdr_len, packet_len;
	u16			hdr_len, packet_len;


	/* This check is no longer done by usbnet */
	if (skb->len < dev->net->hard_header_len)
		return 0;

	if (!(skb->len & 0x01)) {
	if (!(skb->len & 0x01)) {
		netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
		netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
			   skb->len, dev->net->hard_header_len, dev->hard_mtu,
			   skb->len, dev->net->hard_header_len, dev->hard_mtu,
+4 −4
Original line number Original line Diff line number Diff line
@@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
{
	__be16 proto;
	__be16 proto;


	/* usbnet rx_complete guarantees that skb->len is at least
	/* This check is no longer done by usbnet */
	 * hard_header_len, so we can inspect the dest address without
	if (skb->len < dev->net->hard_header_len)
	 * checking skb->len
		return 0;
	 */

	switch (skb->data[0] & 0xf0) {
	switch (skb->data[0] & 0xf0) {
	case 0x40:
	case 0x40:
		proto = htons(ETH_P_IP);
		proto = htons(ETH_P_IP);
Loading