|
@@ -305,88 +305,40 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
|
|
|
|
static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
|
|
{
|
|
|
- u8 *head;
|
|
|
- u32 header;
|
|
|
- char *packet;
|
|
|
- struct sk_buff *ax_skb;
|
|
|
- u16 size;
|
|
|
+ int offset = 0;
|
|
|
|
|
|
- head = (u8 *) skb->data;
|
|
|
- memcpy(&header, head, sizeof(header));
|
|
|
- le32_to_cpus(&header);
|
|
|
- packet = head + sizeof(header);
|
|
|
+ while (offset + sizeof(u32) < skb->len) {
|
|
|
+ struct sk_buff *ax_skb;
|
|
|
+ u16 size;
|
|
|
+ u32 header = get_unaligned_le32(skb->data + offset);
|
|
|
|
|
|
- skb_pull(skb, 4);
|
|
|
-
|
|
|
- while (skb->len > 0) {
|
|
|
- if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
|
|
|
- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
|
|
|
+ offset += sizeof(u32);
|
|
|
|
|
|
/* get the packet length */
|
|
|
- size = (u16) (header & 0x000007ff);
|
|
|
-
|
|
|
- if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
|
|
|
- u8 alignment = (unsigned long)skb->data & 0x3;
|
|
|
- if (alignment != 0x2) {
|
|
|
- /*
|
|
|
- * not 16bit aligned so use the room provided by
|
|
|
- * the 32 bit header to align the data
|
|
|
- *
|
|
|
- * note we want 16bit alignment as MAC header is
|
|
|
- * 14bytes thus ip header will be aligned on
|
|
|
- * 32bit boundary so accessing ipheader elements
|
|
|
- * using a cast to struct ip header wont cause
|
|
|
- * an unaligned accesses.
|
|
|
- */
|
|
|
- u8 realignment = (alignment + 2) & 0x3;
|
|
|
- memmove(skb->data - realignment,
|
|
|
- skb->data,
|
|
|
- size);
|
|
|
- skb->data -= realignment;
|
|
|
- skb_set_tail_pointer(skb, size);
|
|
|
- }
|
|
|
- return 2;
|
|
|
+ size = (u16) (header & 0x7ff);
|
|
|
+ if (size != ((~header >> 16) & 0x07ff)) {
|
|
|
+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- if (size > dev->net->mtu + ETH_HLEN) {
|
|
|
+ if ((size > dev->net->mtu + ETH_HLEN) ||
|
|
|
+ (size + offset > skb->len)) {
|
|
|
netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
|
|
|
size);
|
|
|
return 0;
|
|
|
}
|
|
|
- ax_skb = skb_clone(skb, GFP_ATOMIC);
|
|
|
- if (ax_skb) {
|
|
|
- u8 alignment = (unsigned long)packet & 0x3;
|
|
|
- ax_skb->len = size;
|
|
|
-
|
|
|
- if (alignment != 0x2) {
|
|
|
- /*
|
|
|
- * not 16bit aligned use the room provided by
|
|
|
- * the 32 bit header to align the data
|
|
|
- */
|
|
|
- u8 realignment = (alignment + 2) & 0x3;
|
|
|
- memmove(packet - realignment, packet, size);
|
|
|
- packet -= realignment;
|
|
|
- }
|
|
|
- ax_skb->data = packet;
|
|
|
- skb_set_tail_pointer(ax_skb, size);
|
|
|
- usbnet_skb_return(dev, ax_skb);
|
|
|
- } else {
|
|
|
+ ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
|
|
|
+ if (!ax_skb)
|
|
|
return 0;
|
|
|
- }
|
|
|
-
|
|
|
- skb_pull(skb, (size + 1) & 0xfffe);
|
|
|
|
|
|
- if (skb->len < sizeof(header))
|
|
|
- break;
|
|
|
+ skb_put(ax_skb, size);
|
|
|
+ memcpy(ax_skb->data, skb->data + offset, size);
|
|
|
+ usbnet_skb_return(dev, ax_skb);
|
|
|
|
|
|
- head = (u8 *) skb->data;
|
|
|
- memcpy(&header, head, sizeof(header));
|
|
|
- le32_to_cpus(&header);
|
|
|
- packet = head + sizeof(header);
|
|
|
- skb_pull(skb, 4);
|
|
|
+ offset += (size + 1) & 0xfffe;
|
|
|
}
|
|
|
|
|
|
- if (skb->len < 0) {
|
|
|
+ if (skb->len != offset) {
|
|
|
netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
|
|
|
skb->len);
|
|
|
return 0;
|
|
@@ -1541,7 +1493,7 @@ static const struct driver_info ax88772_info = {
|
|
|
.status = asix_status,
|
|
|
.link_reset = ax88772_link_reset,
|
|
|
.reset = ax88772_reset,
|
|
|
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
|
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
|
|
|
.rx_fixup = asix_rx_fixup,
|
|
|
.tx_fixup = asix_tx_fixup,
|
|
|
};
|