[PATCH] net: asix: handle packets crossing URB boundaries

Sascha Hauer s.hauer at pengutronix.de
Sun Sep 21 21:54:59 PDT 2014


On Tue, Sep 16, 2014 at 03:31:56PM +0200, Rolf Evers-Fischer wrote:
> From: Lucas Stach <dev at lynxeye.de>
> 
> ASIX AX88772B started to pack data even more tightly. Packets and the ASIX packet
> header may now cross URB boundaries. To handle this we have to introduce
> some state between individual calls to asix_rx_fixup().
> 
> Signed-off-by: Lucas Stach <dev at lynxeye.de>
> Signed-off-by: David S. Miller <davem at davemloft.net>
> [ Rolf: ported from kernel to barebox 2014.09.0 ]
> Signed-off-by: Rolf Evers-Fischer <embedded24 at evers-fischer.de>

Applied, thanks

Sascha

> ---
>  drivers/net/usb/asix.c | 123 ++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 91 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
> index d6ac322..14a8c76 100644
> --- a/drivers/net/usb/asix.c
> +++ b/drivers/net/usb/asix.c
> @@ -7,6 +7,7 @@
>  #include <errno.h>
>  #include <malloc.h>
>  #include <asm/byteorder.h>
> +#include <asm/unaligned.h>
>  
>  /* ASIX AX8817X based USB 2.0 Ethernet Devices */
>  
> @@ -134,6 +135,8 @@
>  
>  #define FLAG_EEPROM_MAC		(1UL << 0) /* init device MAC from eeprom */
>  
> +#define RX_FIXUP_SIZE	1514
> +
>  /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
>  struct asix_data {
>  	u8 multi_filter[AX_MCAST_FILTER_SIZE];
> @@ -150,6 +153,18 @@ struct ax88172_int_data {
>  	__le16 res3;
>  } __attribute__ ((packed));
>  
> +struct asix_rx_fixup_info {
> +	u32 header;
> +	u16 size;
> +	u16 offset;
> +	bool split_head;
> +	unsigned char ax_skb[RX_FIXUP_SIZE];
> +};
> +
> +struct asix_common_private {
> +	struct asix_rx_fixup_info rx_fixup_info;
> +};
> +
>  static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
>  			    u16 size, void *data)
>  {
> @@ -409,49 +424,87 @@ static int ax88172_get_ethaddr(struct eth_device *edev, unsigned char *adr)
>  	return 0;
>  }
>  
> -static int asix_rx_fixup(struct usbnet *dev, void *buf, int len)
> +int asix_rx_fixup_internal(struct usbnet *dev, void *buf, int len,
> +			   struct asix_rx_fixup_info *rx)
>  {
> -	unsigned int header;
> -	unsigned short size;
> -
> -	memcpy(&header, (void*) buf, sizeof(header));
> -	le32_to_cpus(&header);
> -	buf += 4;
> -	len -= 4;
> -
> -	while (len > 0) {
> -		if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
> -			dev_err(&dev->edev.dev, "asix_rx_fixup() Bad Header Length\n");
> -
> -		/* get the packet length */
> -		size = (unsigned short) (header & 0x07ff);
> -
> -		if (size > 1514) {
> -			dev_err(&dev->edev.dev, "asix_rx_fixup() Bad RX Length %d\n", size);
> -			return 0;
> +	int offset = 0;
> +
> +	while (offset + sizeof(u16) < len) {
> +		u16 remaining = 0;
> +
> +		if (!rx->size) {
> +			if ((len - offset == sizeof(u16)) ||
> +			    rx->split_head) {
> +				if (!rx->split_head) {
> +					rx->header = get_unaligned_le16(
> +							buf + offset);
> +					rx->split_head = true;
> +					offset += sizeof(u16);
> +					break;
> +				} else {
> +					rx->header |= (get_unaligned_le16(
> +							buf + offset)
> +							<< 16);
> +					rx->split_head = false;
> +					offset += sizeof(u16);
> +				}
> +			} else {
> +				rx->header = get_unaligned_le32(buf +
> +								offset);
> +				offset += sizeof(u32);
> +			}
> +			rx->offset = 0U;
> +
> +			/* get the packet length */
> +			rx->size = (u16) (rx->header & 0x7ff);
> +			if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
> +				dev_err(&dev->edev.dev, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
> +					   rx->header, offset);
> +				rx->size = 0;
> +				return -1;
> +			}
>  		}
> +		if (rx->size > RX_FIXUP_SIZE) {
> +			dev_err(&dev->edev.dev, "asix_rx_fixup() Bad RX Length %d\n",
> +				   rx->size);
> +			rx->offset = 0U;
> +			rx->size = 0U;
>  
> -		net_receive(&dev->edev, buf, size);
> +			return -1;
> +		}
>  
> -		buf += ((size + 1) & 0xfffe);
> -		len -= ((size + 1) & 0xfffe);
> +		if (rx->size > (len - offset)) {
> +			remaining = rx->size - (len - offset);
> +			rx->size = len - offset;
> +		}
>  
> -		if (len == 0)
> -			break;
> +		memcpy(rx->ax_skb + rx->offset, buf + offset, rx->size);
> +		rx->offset += rx->size;
> +		if (!remaining)
> +			net_receive(&dev->edev, rx->ax_skb,
> +						(u16) (rx->header & 0x7ff));
>  
> -		memcpy(&header, (void*) buf, sizeof(header));
> -		le32_to_cpus(&header);
> -		buf += 4;
> -		len -= 4;
> +		offset += ((rx->size + 1) & 0xfffe);
> +		rx->size = remaining;
>  	}
>  
> -	if (len < 0) {
> -		dev_err(&dev->edev.dev,"asix_rx_fixup() Bad SKB Length %d\n", len);
> +	if (len != offset) {
> +		dev_err(&dev->edev.dev, "asix_rx_fixup() Bad SKB Length %d, %d\n",
> +			   len, offset);
>  		return -1;
>  	}
> +
>  	return 0;
>  }
>  
> +static int asix_rx_fixup_common(struct usbnet *dev, void *buf, int len)
> +{
> +	struct asix_common_private *dp = dev->driver_priv;
> +	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
> +
> +	return asix_rx_fixup_internal(dev, buf, len, rx);
> +}
> +
>  static int asix_tx_fixup(struct usbnet *dev,
>  				void *buf, int len,
>  				void *nbuf, int *nlen)
> @@ -632,6 +685,11 @@ static int ax88772_bind(struct usbnet *dev)
>  		dev->rx_urb_size = 2048;
>  	}
>  
> +	dev->driver_priv = kzalloc(sizeof(struct asix_common_private),
> +				GFP_KERNEL);
> +	if (!dev->driver_priv)
> +		return -ENOMEM;
> +
>  	return 0;
>  
>  out:
> @@ -641,6 +699,7 @@ out:
>  static void asix_unbind(struct usbnet *dev)
>  {
>  	mdiobus_unregister(&dev->miibus);
> +	kfree(dev->driver_priv);
>  }
>  
>  static struct driver_info ax8817x_info = {
> @@ -688,7 +747,7 @@ static struct driver_info ax88772_info = {
>  	.bind = ax88772_bind,
>  	.unbind = asix_unbind,
>  	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
> -	.rx_fixup = asix_rx_fixup,
> +	.rx_fixup = asix_rx_fixup_common,
>  	.tx_fixup = asix_tx_fixup,
>  };
>  
> @@ -697,7 +756,7 @@ static struct driver_info ax88772b_info = {
>  	.bind = ax88772_bind,
>  	.unbind = asix_unbind,
>  	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
> -	.rx_fixup = asix_rx_fixup,
> +	.rx_fixup = asix_rx_fixup_common,
>  	.tx_fixup = asix_tx_fixup,
>  	.data = FLAG_EEPROM_MAC,
>  };
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list