Parsing ACK_FREQUENCY frame and TP min_ack_delay
diff --git a/include/quiche.h b/include/quiche.h
index 52b99e5..835d54e 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -171,6 +171,9 @@
 // Sets the congestion control algorithm used.
 void quiche_config_set_cc_algorithm(quiche_config *config, enum quiche_cc_algorithm algo);
 
+// Extension: Sets the `min_ack_delay` transport parameter.
+void quiche_config_ext_set_min_ack_delay(quiche_config *config, uint64_t v);
+
 // Frees the config object.
 void quiche_config_free(quiche_config *config);
 
diff --git a/src/ffi.rs b/src/ffi.rs
index a5be0d9..afc168c 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -232,6 +232,11 @@
 }
 
 #[no_mangle]
+pub extern fn quiche_config_ext_set_min_ack_delay(config: &mut Config, v: u64) {
+    config.ext_set_min_ack_delay(v);
+}
+
+#[no_mangle]
 pub extern fn quiche_config_free(config: *mut Config) {
     unsafe { Box::from_raw(config) };
 }
diff --git a/src/frame.rs b/src/frame.rs
index 744fc98..b9f8310 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -138,6 +138,13 @@
     },
 
     HandshakeDone,
+
+    AckFrequency {
+        sequence_number: u64,
+        packet_tolerance: u64,
+        update_max_ack_delay: u64,
+        ignore_order: bool,
+    },
 }
 
 impl Frame {
@@ -256,6 +263,13 @@
 
             0x1e => Frame::HandshakeDone,
 
+            0xaf => Frame::AckFrequency {
+                sequence_number: b.get_varint()?,
+                packet_tolerance: b.get_varint()?,
+                update_max_ack_delay: b.get_varint()?,
+                ignore_order: b.get_u8()? != 0,
+            },
+
             _ => return Err(Error::InvalidFrame),
         };
 
@@ -503,6 +517,20 @@
             Frame::HandshakeDone => {
                 b.put_varint(0x1e)?;
             },
+
+            Frame::AckFrequency {
+                sequence_number,
+                packet_tolerance,
+                update_max_ack_delay,
+                ignore_order,
+            } => {
+                b.put_varint(0xaf)?;
+
+                b.put_varint(*sequence_number)?;
+                b.put_varint(*packet_tolerance)?;
+                b.put_varint(*update_max_ack_delay)?;
+                b.put_u8(*ignore_order as u8)?;
+            },
         }
 
         Ok(before - b.cap())
@@ -676,6 +704,19 @@
             Frame::HandshakeDone => {
                 1 // frame type
             },
+
+            Frame::AckFrequency {
+                sequence_number,
+                packet_tolerance,
+                update_max_ack_delay,
+                ..
+            } => {
+                1 + // frame type
+                octets::varint_len(*sequence_number) + // sequence_number
+                octets::varint_len(*packet_tolerance) + // packet_tolerance
+                octets::varint_len(*update_max_ack_delay) + // update_max_ack_delay
+                1 // ignore_order
+            },
         }
     }
 
@@ -823,6 +864,19 @@
             Frame::HandshakeDone => {
                 write!(f, "HANDSHAKE_DONE")?;
             },
+
+            Frame::AckFrequency {
+                sequence_number,
+                packet_tolerance,
+                update_max_ack_delay,
+                ignore_order,
+            } => {
+                write!(
+                    f,
+                    "ACK_FREQUENCY sequence_number={} packet_tolerenace={} update_max_ack_delay={} ignore_order={}",
+                    sequence_number, packet_tolerance, update_max_ack_delay, ignore_order
+                )?;
+            },
         }
 
         Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 7227b97..b29a05f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -660,6 +660,13 @@
         self.local_transport_params.max_ack_delay = v;
     }
 
+    /// Sets the `min_ack_delay` transport parameter.
+    ///
+    /// The default value is `25000`.
+    pub fn ext_set_min_ack_delay(&mut self, v: u64) {
+        self.local_transport_params.min_ack_delay = Some(v);
+    }
+
     /// Sets the `disable_active_migration` transport parameter.
     ///
     /// The default value is `false`.
@@ -817,6 +824,16 @@
 
     /// Whether to send GREASE.
     grease: bool,
+
+    /// ACK Frequency config
+    ack_frequency: AckFrequency,
+}
+
+#[derive(Default)]
+struct AckFrequency {
+    sequence_number: Option<u64>,
+    packet_tolerance: u64,
+    ignore_order: bool,
 }
 
 /// Creates a new server-side connection.
@@ -1072,6 +1089,8 @@
             closed: false,
 
             grease: config.grease,
+
+            ack_frequency: Default::default(),
         });
 
         if let Some(odcid) = odcid {
@@ -1728,7 +1747,9 @@
         let mut payload_len = 0;
 
         // Create ACK frame.
-        if self.pkt_num_spaces[epoch].ack_elicited && !is_closing {
+        if (self.pkt_num_spaces[epoch].ack_elicited || self.ack_ok(epoch)) &&
+            !is_closing
+        {
             let ack_delay =
                 self.pkt_num_spaces[epoch].largest_rx_pkt_time.elapsed();
 
@@ -3016,6 +3037,40 @@
                 // Once the handshake is confirmed, we can drop Handshake keys.
                 self.drop_epoch_state(packet::EPOCH_HANDSHAKE);
             },
+
+            frame::Frame::AckFrequency {
+                sequence_number,
+                packet_tolerance,
+                update_max_ack_delay,
+                ignore_order,
+            } =>
+                if let Some(min_ack_delay) =
+                    self.local_transport_params.min_ack_delay
+                {
+                    // Check and update sequence_number if valid
+                    if let Some(seq) = self.ack_frequency.sequence_number {
+                        if seq >= sequence_number {
+                            return Err(Error::InvalidFrame);
+                        }
+                    }
+                    self.ack_frequency.sequence_number = Some(sequence_number);
+
+                    if packet_tolerance > 0 {
+                        self.ack_frequency.packet_tolerance = packet_tolerance;
+                    } else {
+                        return Err(Error::InvalidFrame);
+                    }
+
+                    if update_max_ack_delay >= min_ack_delay {
+                        self.local_transport_params.max_ack_delay =
+                            update_max_ack_delay;
+                    }
+
+                    self.ack_frequency.ignore_order = ignore_order;
+                } else {
+                    // AckFrequency Extension is not supported
+                    return Err(Error::InvalidFrame);
+                },
         }
 
         Ok(())
@@ -3081,6 +3136,12 @@
         let cap = self.max_tx_data as usize - self.tx_data as usize;
         cmp::min(cap, self.recovery.cwnd_available())
     }
+
+    // Ack strategy for application phase
+    fn ack_ok(&self, epoch: packet::Epoch) -> bool {
+        !self.pkt_num_spaces[epoch].recv_pkt_need_ack.is_empty() &&
+            self.pkt_num_spaces[epoch].next_pkt_num % 4 == 0
+    }
 }
 
 /// Statistics about the connection.
@@ -3133,6 +3194,7 @@
     pub disable_active_migration: bool,
     // pub preferred_address: ...,
     pub active_conn_id_limit: u64,
+    pub min_ack_delay: Option<u64>,
 }
 
 impl Default for TransportParams {
@@ -3152,6 +3214,7 @@
             max_ack_delay: 25,
             disable_active_migration: false,
             active_conn_id_limit: 0,
+            min_ack_delay: None,
         }
     }
 }
@@ -3272,6 +3335,10 @@
                     tp.active_conn_id_limit = val.get_varint()?;
                 },
 
+                0xde1a => {
+                    tp.min_ack_delay = Some(val.get_varint()?);
+                },
+
                 // Ignore unknown parameters.
                 _ => (),
             }
@@ -3383,6 +3450,12 @@
                 b.put_varint(tp.active_conn_id_limit)?;
             }
 
+            if let Some(min_ack_delay) = tp.min_ack_delay {
+                b.put_u16(0xde1a)?;
+                b.put_u16(octets::varint_len(min_ack_delay) as u16)?;
+                b.put_varint(min_ack_delay)?;
+            }
+
             b.off()
         };
 
@@ -3431,6 +3504,7 @@
         )?;
         write!(f, "ack_delay_exponent={} ", self.ack_delay_exponent)?;
         write!(f, "max_ack_delay={} ", self.max_ack_delay)?;
+        write!(f, "min_ack_delay={:?} ", self.min_ack_delay)?;
         write!(
             f,
             "disable_active_migration={}",
@@ -3758,12 +3832,13 @@
             max_ack_delay: 2_u64.pow(14) - 1,
             disable_active_migration: true,
             active_conn_id_limit: 8,
+            min_ack_delay: Some(1),
         };
 
         let mut raw_params = [42; 256];
         let mut raw_params =
             TransportParams::encode(&tp, true, &mut raw_params).unwrap();
-        assert_eq!(raw_params.len(), 101);
+        assert_eq!(raw_params.len(), 106);
 
         let new_tp = TransportParams::decode(&mut raw_params, false).unwrap();
 
diff --git a/src/ranges.rs b/src/ranges.rs
index 3d1f718..d81b7ca 100644
--- a/src/ranges.rs
+++ b/src/ranges.rs
@@ -107,6 +107,14 @@
         }
     }
 
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
     pub fn flatten(&self) -> Flatten {
         Flatten {
             inner: self.inner.iter(),