Skip to content

Commit 6b901a3

Browse files
thomaseizingerdjc
authored andcommitted
quinn-udp: sanitise segment_size
In order to perform GSO, an application needs to batch datagrams together into a big buffer. As part of such a batch, the last datagram is allowed to be less than the `segment_size` as that still allows the kernel to unambigously segment the content into individual packets. When GSO gets disabled at runtime due to lack of driver support, applications need to segment such a prepared batch themselves into individual `Transmit`s. Doing that may lead to situations in which a `Transmit` is handed to `quinn-udp` which still has the original `segment_size` set, yet its content is shorter than that. Not all kernels like that. Specifically, it has been observed that Android is particularly picky about these parameters. We already sanitise the `segment_size` such that it is not set when it is equal to the content length. To further increase the robustness of `quinn-udp`, we extend this check to only set it when it is strictly less than the content length. Related: #2201 Related: #2145 Related: firezone/firezone#8932
1 parent 458295c commit 6b901a3

File tree

1 file changed

+5
-3
lines changed

1 file changed

+5
-3
lines changed

quinn-udp/src/unix.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -612,11 +612,13 @@ fn prepare_msg(
612612
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn);
613613
}
614614

615-
// Only set the segment size if it is different from the size of the contents.
616-
// Some network drivers don't like being told to do GSO even if there is effectively only a single segment.
615+
// Only set the segment size if it is less than the size of the contents.
616+
// Some network drivers don't like being told to do GSO even if there is effectively only a single segment (i.e. `segment_size == transmit.contents.len()`)
617+
// Additionally, a `segment_size` that is greater than the content also means there is effectively only a single segment.
618+
// This case is actually quite common when splitting up a prepared GSO batch again after GSO has been disabled because the last datagram in a GSO batch is allowed to be smaller than the segment size.
617619
if let Some(segment_size) = transmit
618620
.segment_size
619-
.filter(|segment_size| *segment_size != transmit.contents.len())
621+
.filter(|segment_size| *segment_size < transmit.contents.len())
620622
{
621623
gso::set_segment_size(&mut encoder, segment_size as u16);
622624
}

0 commit comments

Comments
 (0)