diff --git a/ntp-proto/src/packet/mod.rs b/ntp-proto/src/packet/mod.rs index 11c7cc72a..aa7648357 100644 --- a/ntp-proto/src/packet/mod.rs +++ b/ntp-proto/src/packet/mod.rs @@ -130,7 +130,7 @@ struct NtpHeaderV3V4 { leap: NtpLeapIndicator, mode: NtpAssociationMode, stratum: u8, - poll: i8, + poll: PollInterval, precision: i8, root_delay: NtpDuration, root_dispersion: NtpDuration, @@ -159,7 +159,7 @@ impl NtpHeaderV3V4 { leap: NtpLeapIndicator::NoWarning, mode: NtpAssociationMode::Client, stratum: 0, - poll: 0, + poll: PollInterval::from_byte(0), precision: 0, root_delay: NtpDuration::default(), root_dispersion: NtpDuration::default(), @@ -181,7 +181,7 @@ impl NtpHeaderV3V4 { leap: NtpLeapIndicator::from_bits((data[0] & 0xC0) >> 6), mode: NtpAssociationMode::from_bits(data[0] & 0x07), stratum: data[1], - poll: data[2] as i8, + poll: PollInterval::from_byte(data[2]), precision: data[3] as i8, root_delay: NtpDuration::from_bits_short(data[4..8].try_into().unwrap()), root_dispersion: NtpDuration::from_bits_short(data[8..12].try_into().unwrap()), @@ -197,7 +197,7 @@ impl NtpHeaderV3V4 { fn serialize(&self, w: &mut W, version: u8) -> std::io::Result<()> { w.write_all(&[(self.leap.to_bits() << 6) | (version << 3) | self.mode.to_bits()])?; - w.write_all(&[self.stratum, self.poll as u8, self.precision as u8])?; + w.write_all(&[self.stratum, self.poll.as_byte(), self.precision as u8])?; w.write_all(&self.root_delay.to_bits_short())?; w.write_all(&self.root_dispersion.to_bits_short())?; w.write_all(&self.reference_id.to_bytes())?; @@ -210,7 +210,7 @@ impl NtpHeaderV3V4 { fn poll_message(poll_interval: PollInterval) -> (Self, RequestIdentifier) { let mut packet = Self::new(); - packet.poll = poll_interval.as_log(); + packet.poll = poll_interval; packet.mode = NtpAssociationMode::Client; // In order to increase the entropy of the transmit timestamp @@ -875,6 +875,14 @@ impl<'a> NtpPacket<'a> { } } + pub fn poll(&self) -> PollInterval { + match self.header { + NtpHeader::V3(h) | NtpHeader::V4(h) => h.poll, + #[cfg(feature = "ntpv5")] + NtpHeader::V5(h) => h.poll, + } + } + pub fn stratum(&self) -> u8 { match self.header { NtpHeader::V3(header) => header.stratum, @@ -1240,7 +1248,7 @@ mod tests { leap: NtpLeapIndicator::NoWarning, mode: NtpAssociationMode::Client, stratum: 2, - poll: 6, + poll: PollInterval::from_byte(6), precision: -24, root_delay: NtpDuration::from_fixed_int(1023 << 16), root_dispersion: NtpDuration::from_fixed_int(893 << 16), @@ -1269,7 +1277,7 @@ mod tests { leap: NtpLeapIndicator::NoWarning, mode: NtpAssociationMode::Client, stratum: 2, - poll: 6, + poll: PollInterval::from_byte(6), precision: -24, root_delay: NtpDuration::from_fixed_int(1023 << 16), root_dispersion: NtpDuration::from_fixed_int(893 << 16), @@ -1301,7 +1309,7 @@ mod tests { leap: NtpLeapIndicator::NoWarning, mode: NtpAssociationMode::Server, stratum: 2, - poll: 6, + poll: PollInterval::from_byte(6), precision: -23, root_delay: NtpDuration::from_fixed_int(566 << 16), root_dispersion: NtpDuration::from_fixed_int(951 << 16), diff --git a/ntp-proto/src/packet/v5/mod.rs b/ntp-proto/src/packet/v5/mod.rs index 986257916..39ceb2cc1 100644 --- a/ntp-proto/src/packet/v5/mod.rs +++ b/ntp-proto/src/packet/v5/mod.rs @@ -140,7 +140,7 @@ pub struct NtpHeaderV5 { pub leap: NtpLeapIndicator, pub mode: NtpMode, pub stratum: u8, - pub poll: i8, + pub poll: PollInterval, pub precision: i8, pub timescale: NtpTimescale, pub era: NtpEra, @@ -161,7 +161,7 @@ impl NtpHeaderV5 { leap: NtpLeapIndicator::NoWarning, mode: NtpMode::Request, stratum: 0, - poll: 0, + poll: PollInterval::from_byte(0), precision: 0, root_delay: NtpDuration::default(), root_dispersion: NtpDuration::default(), @@ -229,7 +229,7 @@ impl NtpHeaderV5 { leap: NtpLeapIndicator::from_bits((data[0] & 0xC0) >> 6), mode: NtpMode::from_bits(data[0] & 0x07)?, stratum: data[1], - poll: data[2] as i8, + poll: PollInterval::from_byte(data[2]), precision: data[3] as i8, timescale: NtpTimescale::from_bits(data[4])?, era: NtpEra(data[5]), @@ -248,7 +248,7 @@ impl NtpHeaderV5 { #[allow(dead_code)] pub(crate) fn serialize(&self, w: &mut W) -> std::io::Result<()> { w.write_all(&[(self.leap.to_bits() << 6) | (Self::VERSION << 3) | self.mode.to_bits()])?; - w.write_all(&[self.stratum, self.poll as u8, self.precision as u8])?; + w.write_all(&[self.stratum, self.poll.as_byte(), self.precision as u8])?; w.write_all(&[self.timescale.to_bits()])?; w.write_all(&[self.era.0])?; w.write_all(&self.flags.as_bits())?; @@ -263,7 +263,7 @@ impl NtpHeaderV5 { pub fn poll_message(poll_interval: PollInterval) -> (Self, RequestIdentifier) { let mut packet = Self::new(); - packet.poll = poll_interval.as_log(); + packet.poll = poll_interval; packet.mode = NtpMode::Request; let client_cookie = NtpClientCookie::new_random(); @@ -358,7 +358,7 @@ mod tests { assert_eq!(parsed.leap, NtpLeapIndicator::NoWarning); assert!(parsed.mode.is_request()); assert_eq!(parsed.stratum, 0); - assert_eq!(parsed.poll, 5); + assert_eq!(parsed.poll, PollInterval::from_byte(5)); assert_eq!(parsed.precision, 0); assert_eq!(parsed.timescale, NtpTimescale::Ut1); assert_eq!(parsed.era, NtpEra(0)); @@ -422,7 +422,7 @@ mod tests { assert_eq!(parsed.leap, NtpLeapIndicator::NoWarning); assert!(parsed.mode.is_response()); assert_eq!(parsed.stratum, 4); - assert_eq!(parsed.poll, 5); + assert_eq!(parsed.poll, PollInterval::from_byte(5)); assert_eq!(parsed.precision, 6); assert_eq!(parsed.timescale, NtpTimescale::Tai); assert_eq!(parsed.era, NtpEra(7)); @@ -468,7 +468,7 @@ mod tests { leap: NtpLeapIndicator::from_bits(i % 4), mode: NtpMode::from_bits(3 + (i % 2)).unwrap(), stratum: i.wrapping_add(1), - poll: i.wrapping_add(3) as i8, + poll: PollInterval::from_byte(i.wrapping_add(3)), precision: i.wrapping_add(4) as i8, timescale: NtpTimescale::from_bits(i % 4).unwrap(), era: NtpEra(i.wrapping_add(6)), diff --git a/ntp-proto/src/peer.rs b/ntp-proto/src/peer.rs index 8b75cf75f..9c1a81b11 100644 --- a/ntp-proto/src/peer.rs +++ b/ntp-proto/src/peer.rs @@ -572,6 +572,23 @@ impl Peer { self.stratum = message.stratum(); self.reference_id = message.reference_id(); + // Handle new requested poll interval + #[cfg(feature = "ntpv5")] + if message.version() == 5 { + let requested_poll = message.poll(); + + if requested_poll > self.remote_min_poll_interval { + debug!( + ?requested_poll, + ?self.remote_min_poll_interval, + "Adapting to longer poll interval requested by server" + ); + self.remote_min_poll_interval = requested_poll; + } + self.remote_min_poll_interval = + std::cmp::max(self.remote_min_poll_interval, requested_poll); + } + // generate a measurement let measurement = Measurement::from_packet( &message, diff --git a/ntp-proto/src/time_types.rs b/ntp-proto/src/time_types.rs index be66f8302..2207e7512 100644 --- a/ntp-proto/src/time_types.rs +++ b/ntp-proto/src/time_types.rs @@ -539,6 +539,14 @@ impl PollInterval { Self(value) } + pub fn from_byte(value: u8) -> Self { + Self(value as i8) + } + + pub fn as_byte(self) -> u8 { + self.0 as u8 + } + #[must_use] pub fn inc(self, limits: PollIntervalLimits) -> Self { Self(self.0 + 1).min(limits.max)