aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/asix_common.c
diff options
context:
space:
mode:
authorDean Jenkins <Dean_Jenkins@mentor.com>2015-10-02 09:29:08 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-05 09:58:43 -0400
commit6a570814cd430fa5ef4f278e8046dcf12ee63f13 (patch)
tree42370c6d0d40944bbe9244f8f866a86f2b769ea4 /drivers/net/usb/asix_common.c
parent3f30b158eba5c604b6e0870027eef5d19fc9271d (diff)
asix: Continue processing URB if no RX netdev buffer
Avoid a loss of synchronisation of the Ethernet Data header 32-bit word due to a failure to get a netdev socket buffer. The ASIX RX handling algorithm returned 0 upon a failure to get an allocation of a netdev socket buffer. This causes the URB processing to stop which potentially causes a loss of synchronisation with the Ethernet Data header 32-bit word. Therefore, subsequent processing of URBs may be rejected due to a loss of synchronisation. This may cause additional good Ethernet frames to be discarded along with outputting of synchronisation error messages. Implement a solution which checks whether a netdev socket buffer has been allocated before trying to copy the Ethernet frame into the netdev socket buffer. But continue to process the URB so that synchronisation is maintained. Therefore, only a single Ethernet frame is discarded when no netdev socket buffer is available. Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com> Signed-off-by: Mark Craske <Mark_Craske@mentor.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/asix_common.c')
-rw-r--r--drivers/net/usb/asix_common.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 1e4768debcc9..a186b0a12d50 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -74,12 +74,14 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
74 if (size != ((~rx->header >> 16) & 0x7ff)) { 74 if (size != ((~rx->header >> 16) & 0x7ff)) {
75 netdev_err(dev->net, "asix_rx_fixup() Data Header synchronisation was lost, remaining %d\n", 75 netdev_err(dev->net, "asix_rx_fixup() Data Header synchronisation was lost, remaining %d\n",
76 rx->remaining); 76 rx->remaining);
77 kfree_skb(rx->ax_skb); 77 if (rx->ax_skb) {
78 rx->ax_skb = NULL; 78 kfree_skb(rx->ax_skb);
79 /* Discard the incomplete netdev Ethernet frame and 79 rx->ax_skb = NULL;
80 * assume the Data header is at the start of the current 80 /* Discard the incomplete netdev Ethernet frame
81 * URB socket buffer. 81 * and assume the Data header is at the start of
82 */ 82 * the current URB socket buffer.
83 */
84 }
83 rx->remaining = 0; 85 rx->remaining = 0;
84 } 86 }
85 } 87 }
@@ -121,9 +123,12 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
121 return 0; 123 return 0;
122 } 124 }
123 125
126 /* Sometimes may fail to get a netdev socket buffer but
127 * continue to process the URB socket buffer so that
128 * synchronisation of the Ethernet frame Data header
129 * word is maintained.
130 */
124 rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, size); 131 rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
125 if (!rx->ax_skb)
126 return 0;
127 132
128 rx->remaining = size; 133 rx->remaining = size;
129 } 134 }
@@ -136,10 +141,12 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
136 rx->remaining = 0; 141 rx->remaining = 0;
137 } 142 }
138 143
139 data = skb_put(rx->ax_skb, copy_length); 144 if (rx->ax_skb) {
140 memcpy(data, skb->data + offset, copy_length); 145 data = skb_put(rx->ax_skb, copy_length);
141 if (!rx->remaining) 146 memcpy(data, skb->data + offset, copy_length);
142 usbnet_skb_return(dev, rx->ax_skb); 147 if (!rx->remaining)
148 usbnet_skb_return(dev, rx->ax_skb);
149 }
143 150
144 offset += (copy_length + 1) & 0xfffe; 151 offset += (copy_length + 1) & 0xfffe;
145 } 152 }