drop packets that fail decryption again

In e739f55 we started rejecting all undecryptable packets because the
logic to simply ignore invalid packets was incomplete, so that was a
simplification.

However we do actually need this, even in legitimate connections,
because Firefox sends "padded" Initial packets (i.e. UDP packet with
Initial and a bunch of zero bytes appended), and we would close the
connection.

We do still need to close the connection if the first packet is broken,
in order to avoid keeping a connection alive when some junk that looks
like Initial is received and no other data is received afterwards, so
the logic is updated to check for the number of packet already processed
before deciding whether to send Error::Done (i.e. ignore packet) or some
other error which would cause the connection to be closed.

We already have a test case for this situation from the commit mentioned
above.
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
index dcf2fed..b72724f 100644
--- a/src/h3/mod.rs
+++ b/src/h3/mod.rs
@@ -2318,8 +2318,9 @@
         let d = [0; 20];
 
         s.pipe.client.stream_send(e_stream_id, &d, false).unwrap();
-        s.pipe.client.stream_send(d_stream_id, &d, false).unwrap();
+        s.advance().ok();
 
+        s.pipe.client.stream_send(d_stream_id, &d, false).unwrap();
         s.advance().ok();
 
         loop {
diff --git a/src/lib.rs b/src/lib.rs
index 6f1d271..1bc17d3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1285,6 +1285,8 @@
             hdr.pkt_num_len,
         );
 
+        let pn_len = hdr.pkt_num_len;
+
         trace!(
             "{} rx pkt {:?} len={} pn={}",
             self.trace_id,
@@ -1294,7 +1296,30 @@
         );
 
         let mut payload =
-            packet::decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, &aead)?;
+            match packet::decrypt_pkt(&mut b, pn, pn_len, payload_len, &aead) {
+                Ok(v) => v,
+
+                Err(e) => {
+                    // Ignore packets that fail decryption, but only if we have
+                    // successfully processed at least another packet for the
+                    // connection. This way we can avoid closing the connection
+                    // when junk is injected, but we don't keep a connection
+                    // alive in case we only received junk.
+
+                    if self.recv_count == 0 {
+                        return Err(e);
+                    }
+
+                    trace!(
+                        "{} dropped undecryptable packet type={:?} len={}",
+                        self.trace_id,
+                        hdr.ty,
+                        payload_len
+                    );
+
+                    return Err(Error::Done);
+                },
+            };
 
         if self.pkt_num_spaces[epoch].recv_pkt_num.contains(pn) {
             trace!("{} ignored duplicate packet {}", self.trace_id, pn);