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#[derive(Debug)]
13pub struct LpPacket {
14 pub fragment: Option<Bytes>,
17 pub nack: Option<NackReason>,
19 pub congestion_mark: Option<u64>,
21 pub sequence: Option<u64>,
23 pub frag_index: Option<u64>,
25 pub frag_count: Option<u64>,
27 pub acks: Vec<u64>,
29 pub pit_token: Option<Bytes>,
31 pub incoming_face_id: Option<u64>,
33 pub next_hop_face_id: Option<u64>,
35 pub cache_policy: Option<CachePolicyType>,
37 pub tx_sequence: Option<u64>,
39 pub non_discovery: bool,
41 pub prefix_announcement: Option<Bytes>,
43}
44
45impl LpPacket {
46 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 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 pub fn is_fragmented(&self) -> bool {
171 self.frag_count.is_some_and(|c| c > 1)
172 }
173
174 pub fn is_ack_only(&self) -> bool {
176 self.fragment.is_none() && !self.acks.is_empty()
177 }
178}
179
180fn decode_nack_header(value: Bytes) -> Result<NackReason, crate::PacketError> {
182 if value.is_empty() {
183 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 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 #[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}