Skip to content

Commit e083cde

Browse files
bwh-ctsashalevin
authored andcommitted
usbnet: Fix tx_bytes statistic running backward in cdc_ncm
[ Upstream commit 7a1e890 ] cdc_ncm disagrees with usbnet about how much framing overhead should be counted in the tx_bytes statistics, and tries 'fix' this by decrementing tx_bytes on the transmit path. But statistics must never be decremented except due to roll-over; this will thoroughly confuse user-space. Also, tx_bytes is only incremented by usbnet in the completion path. Fix this by requiring drivers that set FLAG_MULTI_FRAME to set a tx_bytes delta along with the tx_packets count. Fixes: beeecd4 ("net: cdc_ncm/cdc_mbim: adding NCM protocol statistics") Signed-off-by: Ben Hutchings <[email protected]> Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent d0f6e5c commit e083cde

File tree

5 files changed

+22
-11
lines changed

5 files changed

+22
-11
lines changed

drivers/net/usb/asix_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
189189
skb_put(skb, sizeof(padbytes));
190190
}
191191

192-
usbnet_set_skb_tx_stats(skb, 1);
192+
usbnet_set_skb_tx_stats(skb, 1, 0);
193193
return skb;
194194
}
195195

drivers/net/usb/cdc_ncm.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,13 +1177,12 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
11771177
ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
11781178
ctx->tx_ntbs++;
11791179

1180-
/* usbnet has already counted all the framing overhead.
1180+
/* usbnet will count all the framing overhead by default.
11811181
* Adjust the stats so that the tx_bytes counter show real
11821182
* payload data instead.
11831183
*/
1184-
dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
1185-
1186-
usbnet_set_skb_tx_stats(skb_out, n);
1184+
usbnet_set_skb_tx_stats(skb_out, n,
1185+
ctx->tx_curr_frame_payload - skb_out->len);
11871186

11881187
return skb_out;
11891188

drivers/net/usb/sr9800.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
144144
skb_put(skb, sizeof(padbytes));
145145
}
146146

147-
usbnet_set_skb_tx_stats(skb, 1);
147+
usbnet_set_skb_tx_stats(skb, 1, 0);
148148
return skb;
149149
}
150150

drivers/net/usb/usbnet.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,9 +1347,19 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
13471347
} else
13481348
urb->transfer_flags |= URB_ZERO_PACKET;
13491349
}
1350-
entry->length = urb->transfer_buffer_length = length;
1351-
if (!(info->flags & FLAG_MULTI_PACKET))
1352-
usbnet_set_skb_tx_stats(skb, 1);
1350+
urb->transfer_buffer_length = length;
1351+
1352+
if (info->flags & FLAG_MULTI_PACKET) {
1353+
/* Driver has set number of packets and a length delta.
1354+
* Calculate the complete length and ensure that it's
1355+
* positive.
1356+
*/
1357+
entry->length += length;
1358+
if (WARN_ON_ONCE(entry->length <= 0))
1359+
entry->length = length;
1360+
} else {
1361+
usbnet_set_skb_tx_stats(skb, 1, length);
1362+
}
13531363

13541364
spin_lock_irqsave(&dev->txq.lock, flags);
13551365
retval = usb_autopm_get_interface_async(dev->intf);

include/linux/usb/usbnet.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,19 +227,21 @@ struct skb_data { /* skb->cb is one of these */
227227
struct urb *urb;
228228
struct usbnet *dev;
229229
enum skb_state state;
230-
size_t length;
230+
long length;
231231
unsigned long packets;
232232
};
233233

234234
/* Drivers that set FLAG_MULTI_PACKET must call this in their
235235
* tx_fixup method before returning an skb.
236236
*/
237237
static inline void
238-
usbnet_set_skb_tx_stats(struct sk_buff *skb, unsigned long packets)
238+
usbnet_set_skb_tx_stats(struct sk_buff *skb,
239+
unsigned long packets, long bytes_delta)
239240
{
240241
struct skb_data *entry = (struct skb_data *) skb->cb;
241242

242243
entry->packets = packets;
244+
entry->length = bytes_delta;
243245
}
244246

245247
extern int usbnet_open(struct net_device *net);

0 commit comments

Comments
 (0)