aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2023-10-30 12:22:36 +0100
committerlaforge <laforge@osmocom.org>2023-12-17 22:48:00 +0000
commit6b0f9179b1f1c05e293e3a246d5d29c640eb73fd (patch)
tree6ee8b8c6d295fba7e7cab4d273934f493be75883
parente74944f639949aa05fe0fbc3c6e9acab4c357e90 (diff)
usb: Deal with truncated ISO IN transfers
It seems that in some circumstances, an ISO IN transfer can be truncated by the bus / host. In such situation we'd currently pass a non-modulo-32 length to the mux_demux (deframer) code, and it ASSERTs on that. Let's try to handle this more gracefully by substituting random garbage and letting higher layers deal with massive bit errors. Related: OS#5490 Change-Id: Ic453325b93b0e12727625a1495a948d96df4b542
-rw-r--r--src/e1d.h1
-rw-r--r--src/intf_line.c1
-rw-r--r--src/usb.c27
3 files changed, 29 insertions, 0 deletions
diff --git a/src/e1d.h b/src/e1d.h
index 1c7c4c4..45ecb82 100644
--- a/src/e1d.h
+++ b/src/e1d.h
@@ -59,6 +59,7 @@ enum e1d_line_ctr {
LINE_CTR_RX_REMOTE_A,
LINE_CTR_FRAMES_MUXED_E1T,
LINE_CTR_FRAMES_DEMUXED_E1O,
+ LINE_CTR_USB_ISO_TRUNC,
};
enum e1d_line_stat_item {
diff --git a/src/intf_line.c b/src/intf_line.c
index 3895653..f41214e 100644
--- a/src/intf_line.c
+++ b/src/intf_line.c
@@ -60,6 +60,7 @@ static const struct rate_ctr_desc line_ctr_description[] = {
[LINE_CTR_RX_REMOTE_A] ={ "rx:remote_alarm", "Rx Frames Reporting Remote Alarm"},
[LINE_CTR_FRAMES_MUXED_E1T] = { "tx:frames_muxed", "E1 Tx Frames multiplexed" },
[LINE_CTR_FRAMES_DEMUXED_E1O] = { "rx:frames_demuxed", "E1 Rx Frames demultiplexed" },
+ [LINE_CTR_USB_ISO_TRUNC] = { "rx:usb_iso_trunc", "USB ISO packets truncated" },
};
static const struct rate_ctr_group_desc line_ctrg_desc = {
diff --git a/src/usb.c b/src/usb.c
index 1ff9b43..fcffc12 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -131,6 +131,33 @@ e1_usb_xfer_in(struct e1_usb_flow *flow, uint8_t *buf, int len, size_t size)
{
if (len == 0)
return 0;
+
+ if (len < 4) {
+ LOGPLI(flow->line, DE1D, LOGL_ERROR, "IN EP %02x ISO packet truncated: len = %u\n",
+ flow->ep, len);
+ line_ctr_add(flow->line, LINE_CTR_USB_ISO_TRUNC, 1);
+ return 0;
+ }
+
+ if (len > 4 && (len - 4) % 32) {
+ /* some ISO IN packet was truncated. Apparently this
+ * does happen, see https://osmocom.org/issues/5490 -
+ * there is little we can do here, but instead of the
+ * earlier ASSERT, we just feed some garbage for the
+ * last few timeslots, resulting in bit errors etc. */
+ LOGPLI(flow->line, DE1D, LOGL_ERROR, "IN EP %02x ISO packet truncated: len-4 = %u\n",
+ flow->ep, len - 4);
+ line_ctr_add(flow->line, LINE_CTR_USB_ISO_TRUNC, 1);
+
+ /* The assumption here is that only the last E1 frame is
+ * truncated, as we have no idea how many E1 frames the
+ * USB device firmware wanted to send us. */
+ len += 32 - (len % 32);
+ /* don't overflow the underlying buffer */
+ if (len > (int) size)
+ len = size;
+ }
+
return e1_line_demux_in(flow->line, buf + 4, len - 4, buf[3] & 0xf);
}