diff options
Diffstat (limited to 'drivers/net/usb/asix_common.c')
-rw-r--r-- | drivers/net/usb/asix_common.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 6a8eddfea229..1e4768debcc9 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c | |||
@@ -56,6 +56,34 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, | |||
56 | int offset = 0; | 56 | int offset = 0; |
57 | u16 size; | 57 | u16 size; |
58 | 58 | ||
59 | /* When an Ethernet frame spans multiple URB socket buffers, | ||
60 | * do a sanity test for the Data header synchronisation. | ||
61 | * Attempt to detect the situation of the previous socket buffer having | ||
62 | * been truncated or a socket buffer was missing. These situations | ||
63 | * cause a discontinuity in the data stream and therefore need to avoid | ||
64 | * appending bad data to the end of the current netdev socket buffer. | ||
65 | * Also avoid unnecessarily discarding a good current netdev socket | ||
66 | * buffer. | ||
67 | */ | ||
68 | if (rx->remaining && (rx->remaining + sizeof(u32) <= skb->len)) { | ||
69 | offset = ((rx->remaining + 1) & 0xfffe) + sizeof(u32); | ||
70 | rx->header = get_unaligned_le32(skb->data + offset); | ||
71 | offset = 0; | ||
72 | |||
73 | size = (u16)(rx->header & 0x7ff); | ||
74 | if (size != ((~rx->header >> 16) & 0x7ff)) { | ||
75 | netdev_err(dev->net, "asix_rx_fixup() Data Header synchronisation was lost, remaining %d\n", | ||
76 | rx->remaining); | ||
77 | kfree_skb(rx->ax_skb); | ||
78 | rx->ax_skb = NULL; | ||
79 | /* Discard the incomplete netdev Ethernet frame and | ||
80 | * assume the Data header is at the start of the current | ||
81 | * URB socket buffer. | ||
82 | */ | ||
83 | rx->remaining = 0; | ||
84 | } | ||
85 | } | ||
86 | |||
59 | while (offset + sizeof(u16) <= skb->len) { | 87 | while (offset + sizeof(u16) <= skb->len) { |
60 | u16 copy_length; | 88 | u16 copy_length; |
61 | unsigned char *data; | 89 | unsigned char *data; |