diff options
author | Harald Welte <laforge@osmocom.org> | 2023-10-30 12:22:36 +0100 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2023-12-17 22:48:00 +0000 |
commit | 6b0f9179b1f1c05e293e3a246d5d29c640eb73fd (patch) | |
tree | 6ee8b8c6d295fba7e7cab4d273934f493be75883 | |
parent | e74944f639949aa05fe0fbc3c6e9acab4c357e90 (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.h | 1 | ||||
-rw-r--r-- | src/intf_line.c | 1 | ||||
-rw-r--r-- | src/usb.c | 27 |
3 files changed, 29 insertions, 0 deletions
@@ -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 = { @@ -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); } |