ndn_packet/lp/
decode.rs

1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3
4use bytes::Bytes;
5use ndn_tlv::TlvReader;
6
7use super::{CachePolicyType, decode_be_u64};
8use crate::nack::NackReason;
9use crate::tlv_type;
10
11/// A decoded NDNLPv2 LpPacket.
12#[derive(Debug)]
13pub struct LpPacket {
14    /// The network-layer fragment (Interest or Data wire bytes).
15    /// `None` for bare Ack-only packets (no payload).
16    pub fragment: Option<Bytes>,
17    /// Nack header — present when this LpPacket carries a Nack.
18    pub nack: Option<NackReason>,
19    /// Hop-by-hop congestion mark (0 = no congestion).
20    pub congestion_mark: Option<u64>,
21    /// Fragment sequence number (for reassembly ordering).
22    pub sequence: Option<u64>,
23    /// Zero-based index of this fragment within the original packet.
24    pub frag_index: Option<u64>,
25    /// Total number of fragments the original packet was split into.
26    pub frag_count: Option<u64>,
27    /// Piggybacked Ack TxSequences (NDNLPv2 reliability).
28    pub acks: Vec<u64>,
29    /// PIT token (opaque, 1-32 bytes).
30    pub pit_token: Option<Bytes>,
31    /// Incoming face ID (local control header).
32    pub incoming_face_id: Option<u64>,
33    /// Next-hop face ID (local control header).
34    pub next_hop_face_id: Option<u64>,
35    /// Cache policy.
36    pub cache_policy: Option<CachePolicyType>,
37    /// Reliability TxSequence (0x0348) — distinct from fragmentation Sequence (0x51).
38    pub tx_sequence: Option<u64>,
39    /// NonDiscovery flag (presence = true).
40    pub non_discovery: bool,
41    /// Prefix announcement (raw Data bytes).
42    pub prefix_announcement: Option<Bytes>,
43}
44
45impl LpPacket {
46    /// Decode an LpPacket from raw wire bytes.
47    ///
48    /// The input must start with TLV type 0x64 (LP_PACKET).
49    pub fn decode(raw: Bytes) -> Result<Self, crate::PacketError> {
50        let mut reader = TlvReader::new(raw);
51        let (typ, value) = reader.read_tlv()?;
52        if typ != tlv_type::LP_PACKET {
53            return Err(crate::PacketError::UnknownPacketType(typ));
54        }
55
56        let mut inner = TlvReader::new(value);
57        let mut fragment = None;
58        let mut nack = None;
59        let mut congestion_mark = None;
60        let mut sequence = None;
61        let mut frag_index = None;
62        let mut frag_count = None;
63        let mut acks = Vec::new();
64        let mut pit_token = None;
65        let mut incoming_face_id = None;
66        let mut next_hop_face_id = None;
67        let mut cache_policy = None;
68        let mut tx_sequence = None;
69        let mut non_discovery = false;
70        let mut prefix_announcement = None;
71
72        while !inner.is_empty() {
73            let (t, v) = inner.read_tlv()?;
74            match t {
75                tlv_type::LP_FRAGMENT => {
76                    fragment = Some(v);
77                }
78                tlv_type::NACK => {
79                    nack = Some(decode_nack_header(v)?);
80                }
81                tlv_type::LP_CONGESTION_MARK => {
82                    congestion_mark = Some(decode_be_u64(&v));
83                }
84                tlv_type::LP_SEQUENCE => {
85                    sequence = Some(decode_be_u64(&v));
86                }
87                tlv_type::LP_FRAG_INDEX => {
88                    frag_index = Some(decode_be_u64(&v));
89                }
90                tlv_type::LP_FRAG_COUNT => {
91                    frag_count = Some(decode_be_u64(&v));
92                }
93                tlv_type::LP_ACK => {
94                    acks.push(decode_be_u64(&v));
95                }
96                tlv_type::LP_PIT_TOKEN => {
97                    if v.is_empty() || v.len() > 32 {
98                        return Err(crate::PacketError::MalformedPacket(
99                            "PitToken length must be 1-32".into(),
100                        ));
101                    }
102                    pit_token = Some(v);
103                }
104                tlv_type::LP_INCOMING_FACE_ID => {
105                    incoming_face_id = Some(decode_be_u64(&v));
106                }
107                tlv_type::LP_NEXT_HOP_FACE_ID => {
108                    next_hop_face_id = Some(decode_be_u64(&v));
109                }
110                tlv_type::LP_CACHE_POLICY => {
111                    let mut cp_reader = TlvReader::new(v);
112                    while !cp_reader.is_empty() {
113                        let (ct, cv) = cp_reader.read_tlv()?;
114                        if ct == tlv_type::LP_CACHE_POLICY_TYPE {
115                            let code = decode_be_u64(&cv);
116                            cache_policy = Some(if code == 1 {
117                                CachePolicyType::NoCache
118                            } else {
119                                CachePolicyType::Other(code)
120                            });
121                        }
122                    }
123                }
124                tlv_type::LP_TX_SEQUENCE => {
125                    tx_sequence = Some(decode_be_u64(&v));
126                }
127                tlv_type::LP_NON_DISCOVERY => {
128                    non_discovery = true;
129                }
130                tlv_type::LP_PREFIX_ANNOUNCEMENT => {
131                    prefix_announcement = Some(v);
132                }
133                tlv_type::INTEREST | tlv_type::DATA => {
134                    let mut w = ndn_tlv::TlvWriter::new();
135                    w.write_tlv(t, &v);
136                    fragment = Some(w.finish());
137                }
138                _ => {}
139            }
140        }
141
142        // A valid LpPacket must have either a fragment or at least one Ack.
143        if fragment.is_none() && acks.is_empty() {
144            return Err(crate::PacketError::MalformedPacket(
145                "LpPacket has neither fragment nor acks".into(),
146            ));
147        }
148
149        Ok(Self {
150            fragment,
151            nack,
152            congestion_mark,
153            sequence,
154            frag_index,
155            frag_count,
156            acks,
157            pit_token,
158            incoming_face_id,
159            next_hop_face_id,
160            cache_policy,
161            tx_sequence,
162            non_discovery,
163            prefix_announcement,
164        })
165    }
166}
167
168impl LpPacket {
169    /// Returns `true` if this LpPacket is a fragment of a larger packet.
170    pub fn is_fragmented(&self) -> bool {
171        self.frag_count.is_some_and(|c| c > 1)
172    }
173
174    /// Returns `true` if this LpPacket is a bare Ack (no payload fragment).
175    pub fn is_ack_only(&self) -> bool {
176        self.fragment.is_none() && !self.acks.is_empty()
177    }
178}
179
180/// Decode the Nack header field value to extract the NackReason.
181fn decode_nack_header(value: Bytes) -> Result<NackReason, crate::PacketError> {
182    if value.is_empty() {
183        // Nack with no reason = unspecified.
184        return Ok(NackReason::Other(0));
185    }
186    let mut reader = TlvReader::new(value);
187    while !reader.is_empty() {
188        let (t, v) = reader.read_tlv()?;
189        if t == tlv_type::NACK_REASON {
190            let mut code = 0u64;
191            for &b in v.iter() {
192                code = (code << 8) | b as u64;
193            }
194            return Ok(NackReason::from_code(code));
195        }
196    }
197    Ok(NackReason::Other(0))
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203    use crate::encode::encode_interest;
204    use crate::lp::{
205        LpHeaders, encode_lp_acks, encode_lp_nack, encode_lp_packet, encode_lp_reliable,
206        encode_lp_with_headers, is_lp_packet, nni,
207    };
208    use crate::{Interest, Name, NameComponent};
209    use bytes::Bytes;
210    use ndn_tlv::TlvWriter;
211
212    fn name(comps: &[&[u8]]) -> Name {
213        Name::from_components(
214            comps
215                .iter()
216                .map(|c| NameComponent::generic(Bytes::copy_from_slice(c))),
217        )
218    }
219
220    #[test]
221    fn encode_decode_lp_nack_roundtrip() {
222        let n = name(&[b"test", b"nack"]);
223        let interest_wire = encode_interest(&n, None);
224        let lp_wire = encode_lp_nack(NackReason::NoRoute, &interest_wire);
225
226        assert!(is_lp_packet(&lp_wire));
227
228        let lp = LpPacket::decode(lp_wire).unwrap();
229        assert_eq!(lp.nack, Some(NackReason::NoRoute));
230        assert!(lp.congestion_mark.is_none());
231
232        // Fragment should be the original Interest.
233        let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
234        assert_eq!(*interest.name, n);
235    }
236
237    #[test]
238    fn encode_decode_congestion_nack() {
239        let n = name(&[b"hello"]);
240        let interest_wire = encode_interest(&n, None);
241        let lp_wire = encode_lp_nack(NackReason::Congestion, &interest_wire);
242
243        let lp = LpPacket::decode(lp_wire).unwrap();
244        assert_eq!(lp.nack, Some(NackReason::Congestion));
245    }
246
247    #[test]
248    fn decode_lp_packet_without_nack() {
249        let n = name(&[b"test"]);
250        let interest_wire = encode_interest(&n, None);
251
252        let mut w = TlvWriter::new();
253        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
254            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
255        });
256        let lp_wire = w.finish();
257
258        let lp = LpPacket::decode(lp_wire).unwrap();
259        assert!(lp.nack.is_none());
260        let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
261        assert_eq!(*interest.name, n);
262    }
263
264    #[test]
265    fn decode_lp_packet_with_congestion_mark() {
266        let n = name(&[b"test"]);
267        let interest_wire = encode_interest(&n, None);
268
269        let mut w = TlvWriter::new();
270        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
271            w.write_tlv(crate::tlv_type::LP_CONGESTION_MARK, &1u64.to_be_bytes());
272            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
273        });
274        let lp_wire = w.finish();
275
276        let lp = LpPacket::decode(lp_wire).unwrap();
277        assert_eq!(lp.congestion_mark, Some(1));
278    }
279
280    #[test]
281    fn decode_wrong_type_errors() {
282        let mut w = TlvWriter::new();
283        w.write_tlv(0x05, &[]);
284        assert!(LpPacket::decode(w.finish()).is_err());
285    }
286
287    #[test]
288    fn decode_missing_fragment_errors() {
289        let mut w = TlvWriter::new();
290        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
291            w.write_nested(crate::tlv_type::NACK, |w| {
292                w.write_tlv(crate::tlv_type::NACK_REASON, &[150]);
293            });
294        });
295        assert!(LpPacket::decode(w.finish()).is_err());
296    }
297
298    #[test]
299    fn decode_fragmentation_fields() {
300        let n = name(&[b"test"]);
301        let interest_wire = encode_interest(&n, None);
302
303        let mut w = TlvWriter::new();
304        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
305            w.write_tlv(crate::tlv_type::LP_SEQUENCE, &42u64.to_be_bytes());
306            w.write_tlv(crate::tlv_type::LP_FRAG_INDEX, &[0]);
307            w.write_tlv(crate::tlv_type::LP_FRAG_COUNT, &[3]);
308            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
309        });
310        let lp = LpPacket::decode(w.finish()).unwrap();
311        assert_eq!(lp.sequence, Some(42));
312        assert_eq!(lp.frag_index, Some(0));
313        assert_eq!(lp.frag_count, Some(3));
314        assert!(lp.is_fragmented());
315    }
316
317    #[test]
318    fn unfragmented_packet_not_fragmented() {
319        let n = name(&[b"test"]);
320        let interest_wire = encode_interest(&n, None);
321
322        let mut w = TlvWriter::new();
323        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
324            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
325        });
326        let lp = LpPacket::decode(w.finish()).unwrap();
327        assert!(!lp.is_fragmented());
328        assert!(lp.sequence.is_none());
329        assert!(lp.frag_index.is_none());
330        assert!(lp.frag_count.is_none());
331    }
332
333    #[test]
334    fn encode_decode_lp_reliable_roundtrip() {
335        let n = name(&[b"test"]);
336        let interest_wire = encode_interest(&n, None);
337
338        let wire = encode_lp_reliable(&interest_wire, 42, None, &[10, 20]);
339        let lp = LpPacket::decode(wire).unwrap();
340        assert_eq!(lp.sequence, Some(42));
341        assert_eq!(lp.frag_index, None);
342        assert_eq!(lp.frag_count, None);
343        assert_eq!(lp.acks, vec![10, 20]);
344        let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
345        assert_eq!(*interest.name, n);
346    }
347
348    #[test]
349    fn encode_decode_lp_reliable_with_frag_info() {
350        let wire = encode_lp_reliable(&[0x05, 0x00], 100, Some((1, 3)), &[]);
351        let lp = LpPacket::decode(wire).unwrap();
352        assert_eq!(lp.sequence, Some(100));
353        assert_eq!(lp.frag_index, Some(1));
354        assert_eq!(lp.frag_count, Some(3));
355        assert!(lp.acks.is_empty());
356    }
357
358    #[test]
359    fn encode_decode_lp_acks_roundtrip() {
360        let wire = encode_lp_acks(&[5, 6, 7]);
361        let lp = LpPacket::decode(wire).unwrap();
362        assert!(lp.fragment.is_none());
363        assert_eq!(lp.acks, vec![5, 6, 7]);
364        assert!(lp.is_ack_only());
365    }
366
367    #[test]
368    fn decode_bare_ack_no_fragment_ok() {
369        let wire = encode_lp_acks(&[99]);
370        assert!(LpPacket::decode(wire).is_ok());
371    }
372
373    #[test]
374    fn decode_empty_lp_packet_errors() {
375        let mut w = TlvWriter::new();
376        w.write_nested(crate::tlv_type::LP_PACKET, |_| {});
377        assert!(LpPacket::decode(w.finish()).is_err());
378    }
379
380    // ─── NDNLPv2 header field tests ──────────────────────────────────────────
381
382    #[test]
383    fn decode_pit_token_valid() {
384        let n = name(&[b"test"]);
385        let interest_wire = encode_interest(&n, None);
386
387        let mut w = TlvWriter::new();
388        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
389            w.write_tlv(crate::tlv_type::LP_PIT_TOKEN, &[0xAB, 0xCD, 0xEF, 0x01]);
390            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
391        });
392        let lp = LpPacket::decode(w.finish()).unwrap();
393        assert_eq!(lp.pit_token.as_deref(), Some(&[0xAB, 0xCD, 0xEF, 0x01][..]));
394    }
395
396    #[test]
397    fn decode_pit_token_too_long_rejected() {
398        let n = name(&[b"test"]);
399        let interest_wire = encode_interest(&n, None);
400
401        let mut w = TlvWriter::new();
402        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
403            w.write_tlv(crate::tlv_type::LP_PIT_TOKEN, &[0u8; 33]);
404            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
405        });
406        assert!(LpPacket::decode(w.finish()).is_err());
407    }
408
409    #[test]
410    fn decode_pit_token_empty_rejected() {
411        let n = name(&[b"test"]);
412        let interest_wire = encode_interest(&n, None);
413
414        let mut w = TlvWriter::new();
415        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
416            w.write_tlv(crate::tlv_type::LP_PIT_TOKEN, &[]);
417            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
418        });
419        assert!(LpPacket::decode(w.finish()).is_err());
420    }
421
422    #[test]
423    fn decode_cache_policy_no_cache() {
424        let n = name(&[b"test"]);
425        let interest_wire = encode_interest(&n, None);
426
427        let mut w = TlvWriter::new();
428        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
429            w.write_nested(crate::tlv_type::LP_CACHE_POLICY, |w| {
430                w.write_tlv(crate::tlv_type::LP_CACHE_POLICY_TYPE, &[1]);
431            });
432            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
433        });
434        let lp = LpPacket::decode(w.finish()).unwrap();
435        assert_eq!(lp.cache_policy, Some(CachePolicyType::NoCache));
436    }
437
438    #[test]
439    fn decode_incoming_and_next_hop_face_id() {
440        let n = name(&[b"test"]);
441        let interest_wire = encode_interest(&n, None);
442
443        let mut w = TlvWriter::new();
444        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
445            let (buf, len) = nni(42);
446            w.write_tlv(crate::tlv_type::LP_INCOMING_FACE_ID, &buf[..len]);
447            let (buf, len) = nni(99);
448            w.write_tlv(crate::tlv_type::LP_NEXT_HOP_FACE_ID, &buf[..len]);
449            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
450        });
451        let lp = LpPacket::decode(w.finish()).unwrap();
452        assert_eq!(lp.incoming_face_id, Some(42));
453        assert_eq!(lp.next_hop_face_id, Some(99));
454    }
455
456    #[test]
457    fn decode_non_discovery_flag() {
458        let n = name(&[b"test"]);
459        let interest_wire = encode_interest(&n, None);
460
461        let mut w = TlvWriter::new();
462        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
463            w.write_tlv(crate::tlv_type::LP_NON_DISCOVERY, &[]);
464            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
465        });
466        let lp = LpPacket::decode(w.finish()).unwrap();
467        assert!(lp.non_discovery);
468    }
469
470    #[test]
471    fn decode_tx_sequence() {
472        let n = name(&[b"test"]);
473        let interest_wire = encode_interest(&n, None);
474
475        let mut w = TlvWriter::new();
476        w.write_nested(crate::tlv_type::LP_PACKET, |w| {
477            let (buf, len) = nni(12345);
478            w.write_tlv(crate::tlv_type::LP_TX_SEQUENCE, &buf[..len]);
479            w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
480        });
481        let lp = LpPacket::decode(w.finish()).unwrap();
482        assert_eq!(lp.tx_sequence, Some(12345));
483    }
484
485    #[test]
486    fn decode_without_new_fields_still_works() {
487        let n = name(&[b"test"]);
488        let interest_wire = encode_interest(&n, None);
489        let lp_wire = encode_lp_packet(&interest_wire);
490
491        let lp = LpPacket::decode(lp_wire).unwrap();
492        assert!(lp.pit_token.is_none());
493        assert!(lp.incoming_face_id.is_none());
494        assert!(lp.next_hop_face_id.is_none());
495        assert!(lp.cache_policy.is_none());
496        assert!(lp.tx_sequence.is_none());
497        assert!(!lp.non_discovery);
498        assert!(lp.prefix_announcement.is_none());
499    }
500
501    #[test]
502    fn encode_lp_with_headers_roundtrip() {
503        let n = name(&[b"test"]);
504        let interest_wire = encode_interest(&n, None);
505
506        let headers = LpHeaders {
507            pit_token: Some(Bytes::from_static(&[0x01, 0x02, 0x03])),
508            congestion_mark: Some(5),
509            incoming_face_id: Some(42),
510            cache_policy: Some(CachePolicyType::NoCache),
511        };
512        let wire = encode_lp_with_headers(&interest_wire, &headers);
513        let lp = LpPacket::decode(wire).unwrap();
514
515        assert_eq!(lp.pit_token.as_deref(), Some(&[0x01, 0x02, 0x03][..]));
516        assert_eq!(lp.congestion_mark, Some(5));
517        assert_eq!(lp.incoming_face_id, Some(42));
518        assert_eq!(lp.cache_policy, Some(CachePolicyType::NoCache));
519        let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
520        assert_eq!(*interest.name, n);
521    }
522
523    #[test]
524    fn encode_lp_with_headers_empty_headers() {
525        let n = name(&[b"test"]);
526        let interest_wire = encode_interest(&n, None);
527
528        let headers = LpHeaders {
529            pit_token: None,
530            congestion_mark: None,
531            incoming_face_id: None,
532            cache_policy: None,
533        };
534        let wire = encode_lp_with_headers(&interest_wire, &headers);
535        let lp = LpPacket::decode(wire).unwrap();
536
537        assert!(lp.pit_token.is_none());
538        assert!(lp.congestion_mark.is_none());
539        assert!(lp.incoming_face_id.is_none());
540        assert!(lp.cache_policy.is_none());
541        let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
542        assert_eq!(*interest.name, n);
543    }
544}