]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.4.83/net-asix-handle-packets-crossing-urb-boundaries.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.4.83 / net-asix-handle-packets-crossing-urb-boundaries.patch
1 From emilgoode@gmail.com Fri Mar 7 17:03:47 2014
2 From: Lucas Stach <dev@lynxeye.de>
3 Date: Thu, 27 Feb 2014 12:51:38 +0100
4 Subject: net: asix: handle packets crossing URB boundaries
5 To: gregkh@linuxfoundation.org
6 Cc: i.gnatenko.brain@gmail.com, stable@vger.kernel.org, stable-commits@vger.kernel.org, Emil Goode <emilgoode@gmail.com>, Lucas Stach <dev@lynxeye.de>, "David S. Miller" <davem@davemloft.net>
7 Message-ID: <1393501899-17169-2-git-send-email-emilgoode@gmail.com>
8
9 From: Lucas Stach <dev@lynxeye.de>
10
11 commit 8b5b6f5413e97c3e8bafcdd67553d508f4f698cd upstream.
12
13 ASIX AX88772B started to pack data even more tightly. Packets and the ASIX packet
14 header may now cross URB boundaries. To handle this we have to introduce
15 some state between individual calls to asix_rx_fixup().
16
17 Signed-off-by: Lucas Stach <dev@lynxeye.de>
18 Signed-off-by: David S. Miller <davem@davemloft.net>
19 [ Emil: backported to 3.4: dropped changes to drivers/net/usb/ax88172a.c ]
20 Signed-off-by: Emil Goode <emilgoode@gmail.com>
21 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
22 ---
23 drivers/net/usb/asix.c | 125 ++++++++++++++++++++++++++++++++++++++-----------
24 1 file changed, 97 insertions(+), 28 deletions(-)
25
26 --- a/drivers/net/usb/asix.c
27 +++ b/drivers/net/usb/asix.c
28 @@ -183,6 +183,17 @@ struct ax88172_int_data {
29 __le16 res3;
30 } __packed;
31
32 +struct asix_rx_fixup_info {
33 + struct sk_buff *ax_skb;
34 + u32 header;
35 + u16 size;
36 + bool split_head;
37 +};
38 +
39 +struct asix_common_private {
40 + struct asix_rx_fixup_info rx_fixup_info;
41 +};
42 +
43 static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
44 u16 size, void *data)
45 {
46 @@ -304,49 +315,89 @@ asix_write_cmd_async(struct usbnet *dev,
47 }
48 }
49
50 -static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
51 +static int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
52 + struct asix_rx_fixup_info *rx)
53 {
54 int offset = 0;
55
56 - while (offset + sizeof(u32) < skb->len) {
57 - struct sk_buff *ax_skb;
58 - u16 size;
59 - u32 header = get_unaligned_le32(skb->data + offset);
60 -
61 - offset += sizeof(u32);
62 -
63 - /* get the packet length */
64 - size = (u16) (header & 0x7ff);
65 - if (size != ((~header >> 16) & 0x07ff)) {
66 - netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
67 - return 0;
68 + while (offset + sizeof(u16) <= skb->len) {
69 + u16 remaining = 0;
70 + unsigned char *data;
71 +
72 + if (!rx->size) {
73 + if ((skb->len - offset == sizeof(u16)) ||
74 + rx->split_head) {
75 + if (!rx->split_head) {
76 + rx->header = get_unaligned_le16(
77 + skb->data + offset);
78 + rx->split_head = true;
79 + offset += sizeof(u16);
80 + break;
81 + } else {
82 + rx->header |= (get_unaligned_le16(
83 + skb->data + offset)
84 + << 16);
85 + rx->split_head = false;
86 + offset += sizeof(u16);
87 + }
88 + } else {
89 + rx->header = get_unaligned_le32(skb->data +
90 + offset);
91 + offset += sizeof(u32);
92 + }
93 +
94 + /* get the packet length */
95 + rx->size = (u16) (rx->header & 0x7ff);
96 + if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
97 + netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
98 + rx->header, offset);
99 + rx->size = 0;
100 + return 0;
101 + }
102 + rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
103 + rx->size);
104 + if (!rx->ax_skb)
105 + return 0;
106 }
107
108 - if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
109 - (size + offset > skb->len)) {
110 + if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
111 netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
112 - size);
113 + rx->size);
114 + kfree_skb(rx->ax_skb);
115 return 0;
116 }
117 - ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
118 - if (!ax_skb)
119 - return 0;
120
121 - skb_put(ax_skb, size);
122 - memcpy(ax_skb->data, skb->data + offset, size);
123 - usbnet_skb_return(dev, ax_skb);
124 + if (rx->size > skb->len - offset) {
125 + remaining = rx->size - (skb->len - offset);
126 + rx->size = skb->len - offset;
127 + }
128 +
129 + data = skb_put(rx->ax_skb, rx->size);
130 + memcpy(data, skb->data + offset, rx->size);
131 + if (!remaining)
132 + usbnet_skb_return(dev, rx->ax_skb);
133
134 - offset += (size + 1) & 0xfffe;
135 + offset += (rx->size + 1) & 0xfffe;
136 + rx->size = remaining;
137 }
138
139 if (skb->len != offset) {
140 - netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
141 - skb->len);
142 + netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
143 + skb->len, offset);
144 return 0;
145 }
146 +
147 return 1;
148 }
149
150 +static int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
151 +{
152 + struct asix_common_private *dp = dev->driver_priv;
153 + struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
154 +
155 + return asix_rx_fixup_internal(dev, skb, rx);
156 +}
157 +
158 static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
159 gfp_t flags)
160 {
161 @@ -1110,9 +1161,19 @@ static int ax88772_bind(struct usbnet *d
162 dev->rx_urb_size = 2048;
163 }
164
165 + dev->driver_priv = kzalloc(sizeof(struct asix_common_private),
166 + GFP_KERNEL);
167 + if (!dev->driver_priv)
168 + return -ENOMEM;
169 +
170 return 0;
171 }
172
173 +static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
174 +{
175 + kfree(dev->driver_priv);
176 +}
177 +
178 static const struct ethtool_ops ax88178_ethtool_ops = {
179 .get_drvinfo = asix_get_drvinfo,
180 .get_link = asix_get_link,
181 @@ -1445,6 +1506,11 @@ static int ax88178_bind(struct usbnet *d
182 dev->rx_urb_size = 2048;
183 }
184
185 + dev->driver_priv = kzalloc(sizeof(struct asix_common_private),
186 + GFP_KERNEL);
187 + if (!dev->driver_priv)
188 + return -ENOMEM;
189 +
190 return 0;
191 }
192
193 @@ -1491,22 +1557,25 @@ static const struct driver_info hawking_
194 static const struct driver_info ax88772_info = {
195 .description = "ASIX AX88772 USB 2.0 Ethernet",
196 .bind = ax88772_bind,
197 + .unbind = ax88772_unbind,
198 .status = asix_status,
199 .link_reset = ax88772_link_reset,
200 .reset = ax88772_reset,
201 - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
202 - .rx_fixup = asix_rx_fixup,
203 + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
204 + FLAG_MULTI_PACKET,
205 + .rx_fixup = asix_rx_fixup_common,
206 .tx_fixup = asix_tx_fixup,
207 };
208
209 static const struct driver_info ax88178_info = {
210 .description = "ASIX AX88178 USB 2.0 Ethernet",
211 .bind = ax88178_bind,
212 + .unbind = ax88772_unbind,
213 .status = asix_status,
214 .link_reset = ax88178_link_reset,
215 .reset = ax88178_reset,
216 .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
217 - .rx_fixup = asix_rx_fixup,
218 + .rx_fixup = asix_rx_fixup_common,
219 .tx_fixup = asix_tx_fixup,
220 };
221