1use crate::protocol::byte_order::WriteBytesExt;
2
3use automotive_wire_codec::{Decode, DecodeIter, DecodeIterator, Encode};
4
5use super::{
6 Entry, EntryView, Flags, OptionView, Options,
7 entry::{ENTRY_SIZE, EntryIter},
8 options::OptionIter,
9};
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub struct Header<'a> {
17 pub flags: Flags,
19 pub entries: &'a [Entry],
21 pub options: &'a [Options],
23}
24
25impl<'a> Header<'a> {
26 #[must_use]
28 pub const fn new(flags: Flags, entries: &'a [Entry], options: &'a [Options]) -> Self {
29 Self {
30 flags,
31 entries,
32 options,
33 }
34 }
35}
36
37#[derive(Clone, Copy, Debug)]
56pub struct SdHeaderView<'a> {
57 flags: Flags,
58 entries_buf: &'a [u8],
59 options_buf: &'a [u8],
60 entry_count: usize,
62 option_count: usize,
64}
65
66impl<'a> SdHeaderView<'a> {
67 pub fn parse(buf: &'a [u8]) -> Result<Self, crate::protocol::Error> {
82 let (body, _rest) = SdBody::decode(buf)?;
92
93 let mut entry_count = 0usize;
98 for entry in body.entries() {
99 entry?.entry_type()?;
100 entry_count += 1;
101 }
102
103 let mut option_count = 0usize;
107 for option in body.options() {
108 option?.validate()?;
109 option_count += 1;
110 }
111
112 Ok(Self {
113 flags: body.flags,
114 entries_buf: body.entries_buf,
115 options_buf: body.options_buf,
116 entry_count,
117 option_count,
118 })
119 }
120
121 #[must_use]
123 pub fn flags(&self) -> Flags {
124 self.flags
125 }
126
127 #[must_use]
135 pub fn entries(&self) -> EntryIter<'a> {
136 EntryIter::new(self.entries_buf)
137 }
138
139 #[must_use]
148 pub fn options(&self) -> OptionIter<'a> {
149 OptionIter::new(self.options_buf)
150 }
151
152 #[must_use]
156 pub fn entry_count(&self) -> usize {
157 self.entry_count
158 }
159
160 #[must_use]
166 pub fn option_count(&self) -> usize {
167 self.option_count
168 }
169}
170
171#[derive(Clone, Copy, Debug)]
183pub struct SdBody<'a> {
184 flags: Flags,
185 entries_buf: &'a [u8],
186 options_buf: &'a [u8],
187}
188
189impl<'a> SdBody<'a> {
190 #[must_use]
192 pub fn flags(&self) -> Flags {
193 self.flags
194 }
195
196 #[must_use]
202 pub fn entries(&self) -> DecodeIterator<'a, EntryView<'a>> {
203 EntryView::iter(self.entries_buf)
204 }
205
206 #[must_use]
212 pub fn options(&self) -> DecodeIterator<'a, OptionView<'a>> {
213 OptionView::iter(self.options_buf)
214 }
215}
216
217impl<'a> Decode<'a> for SdBody<'a> {
218 type Error = crate::protocol::Error;
219
220 fn decode(buf: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
234 if buf.len() < 12 {
236 return Err(automotive_wire_codec::Incomplete {
237 needed: 12,
238 available: buf.len(),
239 }
240 .into());
241 }
242
243 let flags = Flags::from(buf[0]);
244 let entries_size = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]) as usize;
247
248 if !entries_size.is_multiple_of(ENTRY_SIZE) {
249 return Err(super::Error::IncorrectEntriesSize(entries_size).into());
250 }
251
252 let overflow = || automotive_wire_codec::Incomplete {
259 needed: usize::MAX,
260 available: buf.len(),
261 };
262
263 let entries_end = 8usize.checked_add(entries_size).ok_or_else(overflow)?;
265 let options_size_offset = entries_end;
266 let entries_section_end = entries_end.checked_add(4).ok_or_else(overflow)?;
267 if buf.len() < entries_section_end {
268 return Err(automotive_wire_codec::Incomplete {
269 needed: entries_section_end,
270 available: buf.len(),
271 }
272 .into());
273 }
274
275 let entries_buf = &buf[8..options_size_offset];
276
277 let options_size = u32::from_be_bytes([
278 buf[options_size_offset],
279 buf[options_size_offset + 1],
280 buf[options_size_offset + 2],
281 buf[options_size_offset + 3],
282 ]) as usize;
283
284 let options_start = entries_section_end;
285 let options_end = options_start
286 .checked_add(options_size)
287 .ok_or_else(overflow)?;
288 if buf.len() < options_end {
289 return Err(automotive_wire_codec::Incomplete {
290 needed: options_end,
291 available: buf.len(),
292 }
293 .into());
294 }
295
296 let options_buf = &buf[options_start..options_end];
297 let rest = &buf[options_end..];
298
299 Ok((
300 Self {
301 flags,
302 entries_buf,
303 options_buf,
304 },
305 rest,
306 ))
307 }
308}
309
310impl Encode for Header<'_> {
311 type Error = crate::protocol::Error;
312
313 fn encoded_size(&self) -> Result<usize, Self::Error> {
314 let mut size = 12 + self.entries.len() * ENTRY_SIZE;
315 for option in self.options {
316 size += option.size();
317 }
318 Ok(size)
319 }
320
321 fn encode(&self, writer: &mut impl embedded_io::Write) -> Result<usize, Self::Error> {
322 writer.write_u8(u8::from(self.flags))?;
323 let reserved: [u8; 3] = [0; 3];
324 writer.write_bytes(&reserved)?;
325 let entries_size = u32::try_from(self.entries.len() * 16).expect("entries size fits u32");
326 writer.write_u32_be(entries_size)?;
327 for entry in self.entries {
328 entry.encode(writer)?;
329 }
330 let mut options_size = 0;
331 for option in self.options {
332 options_size += option.size();
333 }
334 writer.write_u32_be(u32::try_from(options_size).expect("options size fits u32"))?;
335 for option in self.options {
336 option.encode(writer)?;
337 }
338 Ok(12 + entries_size as usize + options_size)
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use core::net::Ipv4Addr;
345
346 use super::*;
347 use crate::protocol::sd::{
348 Error as SdError, EventGroupEntry, OptionType, OptionsCount, RebootFlag, ServiceEntry,
349 TransportProtocol,
350 options::{
351 IPV4_OPTION_IP_OFFSET, IPV4_OPTION_LENGTH_FIELD, IPV4_OPTION_PORT_OFFSET,
352 IPV4_OPTION_PROTOCOL_OFFSET, IPV4_OPTION_WIRE_SIZE,
353 },
354 };
355 use automotive_wire_codec::Encode;
356
357 fn ipv4_endpoint_bytes(ip: [u8; 4], protocol: u8, port: u16) -> [u8; IPV4_OPTION_WIRE_SIZE] {
358 let mut b = [0u8; IPV4_OPTION_WIRE_SIZE];
359 b[0..2].copy_from_slice(&IPV4_OPTION_LENGTH_FIELD.to_be_bytes());
360 b[2] = u8::from(OptionType::IpV4Endpoint);
361 b[IPV4_OPTION_IP_OFFSET..IPV4_OPTION_IP_OFFSET + 4].copy_from_slice(&ip);
363 b[IPV4_OPTION_PROTOCOL_OFFSET] = protocol;
365 b[IPV4_OPTION_PORT_OFFSET..IPV4_OPTION_PORT_OFFSET + 2]
366 .copy_from_slice(&port.to_be_bytes());
367 b
368 }
369
370 fn raw_header(entries_size: u32, options_size: u32) -> [u8; 12] {
371 let mut b = [0u8; 12];
372 b[4..8].copy_from_slice(&entries_size.to_be_bytes());
374 b[8..12].copy_from_slice(&options_size.to_be_bytes());
375 b
376 }
377
378 #[test]
379 fn header_new_stores_fields() {
380 let flags = Flags::new_sd(RebootFlag::RecentlyRebooted);
381 let entries: &[Entry] = &[];
382 let options: &[Options] = &[];
383 let h = Header::new(flags, entries, options);
384 assert_eq!(h.flags, flags);
385 assert!(h.entries.is_empty());
386 assert!(h.options.is_empty());
387 }
388
389 #[test]
390 fn service_offer_round_trips() {
391 let ip = Ipv4Addr::new(192, 168, 1, 10);
392 let entry = Entry::OfferService(ServiceEntry {
393 service_id: 0x1234,
394 instance_id: 0x0001,
395 major_version: 1,
396 ttl: 0xFF_FFFF,
397 index_first_options_run: 0,
398 index_second_options_run: 0,
399 options_count: OptionsCount::new(1, 0),
400 minor_version: 0,
401 });
402 let endpoint = Options::IpV4Endpoint {
403 ip,
404 protocol: TransportProtocol::Udp,
405 port: 30509,
406 };
407 let entries = [entry];
408 let options = [endpoint];
409 let h = Header::new(
410 Flags::new_sd(RebootFlag::RecentlyRebooted),
411 &entries,
412 &options,
413 );
414 assert_eq!(h.encoded_size().unwrap(), 40);
415 let mut buf = [0u8; 64];
416 h.encode(&mut buf.as_mut_slice()).unwrap();
417 let view = SdHeaderView::parse(&buf[..h.encoded_size().unwrap()]).unwrap();
418 assert_eq!(view.entry_count(), 1);
419 let entry_view = view.entries().next().unwrap();
420 assert_eq!(entry_view.service_id(), 0x1234);
421 }
422
423 #[test]
424 fn subscribe_ack_round_trips() {
425 let entry = Entry::SubscribeAckEventGroup(EventGroupEntry::new(
426 0xAAAA, 0x0001, 1, 0xFF_FFFF, 0x0010,
427 ));
428 let entries = [entry];
429 let h = Header::new(Flags::new_sd(RebootFlag::RecentlyRebooted), &entries, &[]);
430 assert_eq!(h.encoded_size().unwrap(), 28);
431 let mut buf = [0u8; 32];
432 h.encode(&mut buf.as_mut_slice()).unwrap();
433 let view = SdHeaderView::parse(&buf[..h.encoded_size().unwrap()]).unwrap();
434 assert_eq!(view.entry_count(), 1);
435 }
436
437 #[test]
438 fn parse_exact_size_slice_succeeds() {
439 let entry = Entry::OfferService(ServiceEntry {
440 service_id: 0x1234,
441 instance_id: 0x0001,
442 major_version: 1,
443 ttl: 0xFF_FFFF,
444 index_first_options_run: 0,
445 index_second_options_run: 0,
446 options_count: OptionsCount::new(1, 0),
447 minor_version: 0,
448 });
449 let endpoint = Options::IpV4Endpoint {
450 ip: Ipv4Addr::new(192, 168, 1, 10),
451 protocol: TransportProtocol::Udp,
452 port: 30509,
453 };
454 let entries = [entry];
455 let options = [endpoint];
456 let h = Header::new(
457 Flags::new_sd(RebootFlag::RecentlyRebooted),
458 &entries,
459 &options,
460 );
461 let mut buf = [0u8; 64];
462 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
463 let view = SdHeaderView::parse(&buf[..n]).unwrap();
464 assert_eq!(view.entry_count(), 1);
465 }
466
467 #[test]
468 fn parse_options_size_below_minimum_returns_error() {
469 let prefix = raw_header(0, 2);
474 let mut buf = [0u8; 14];
475 buf[..12].copy_from_slice(&prefix);
476 assert!(matches!(
477 SdHeaderView::parse(&buf),
478 Err(crate::protocol::Error::Incomplete(
479 automotive_wire_codec::Incomplete {
480 needed: 4,
481 available: 2,
482 }
483 ))
484 ));
485 }
486
487 #[test]
488 fn parse_option_size_exceeds_declared_remaining_returns_error() {
489 let prefix = raw_header(0, 5);
490 let option = ipv4_endpoint_bytes([127, 0, 0, 1], 0x11, 1234);
491 let mut buf = [0u8; 24];
492 buf[..12].copy_from_slice(&prefix);
493 buf[12..24].copy_from_slice(&option);
494 assert!(matches!(
495 SdHeaderView::parse(&buf),
496 Err(crate::protocol::Error::Incomplete(
497 automotive_wire_codec::Incomplete {
498 needed: 12,
499 available: 5,
500 }
501 ))
502 ));
503 }
504
505 #[test]
508 fn sd_header_view_entry_count() {
509 let entries = [
510 Entry::FindService(ServiceEntry::find(0x0001)),
511 Entry::FindService(ServiceEntry::find(0x0002)),
512 ];
513 let h = Header::new(Flags::new_sd(RebootFlag::RecentlyRebooted), &entries, &[]);
514 let mut buf = [0u8; 64];
515 h.encode(&mut buf.as_mut_slice()).unwrap();
516 let view = SdHeaderView::parse(&buf[..h.encoded_size().unwrap()]).unwrap();
517 assert_eq!(view.entry_count(), 2);
518 }
519
520 #[test]
521 fn sd_header_view_accessors_yield_cached_counts() {
522 let ip = Ipv4Addr::new(192, 168, 1, 10);
525 let entries = [
526 Entry::FindService(ServiceEntry::find(0x0001)),
527 Entry::FindService(ServiceEntry::find(0x0002)),
528 ];
529 let options = [
530 Options::IpV4Endpoint {
531 ip,
532 protocol: TransportProtocol::Udp,
533 port: 30509,
534 },
535 Options::IpV4Endpoint {
536 ip,
537 protocol: TransportProtocol::Tcp,
538 port: 30510,
539 },
540 ];
541 let h = Header::new(
542 Flags::new_sd(RebootFlag::RecentlyRebooted),
543 &entries,
544 &options,
545 );
546 let mut buf = [0u8; 128];
547 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
548 let view = SdHeaderView::parse(&buf[..n]).unwrap();
549 assert_eq!(view.entry_count(), 2);
550 assert_eq!(view.option_count(), 2);
551 assert_eq!(view.entries().count(), view.entry_count());
553 assert_eq!(view.options().count(), view.option_count());
554 assert_eq!(view.entries().len(), view.entry_count());
556 }
557
558 #[test]
559 fn parse_rejects_trailing_partial_option() {
560 let prefix = raw_header(0, 12);
564 let mut option = ipv4_endpoint_bytes([10, 0, 0, 1], 0x11, 30490);
565 option[0..2].copy_from_slice(&13u16.to_be_bytes());
567 let mut buf = [0u8; 24];
568 buf[..12].copy_from_slice(&prefix);
569 buf[12..24].copy_from_slice(&option);
570 assert!(matches!(
571 SdHeaderView::parse(&buf),
572 Err(crate::protocol::Error::Incomplete(
573 automotive_wire_codec::Incomplete {
574 needed: 16,
575 available: 12,
576 }
577 ))
578 ));
579 }
580
581 #[test]
582 fn sd_header_view_flags() {
583 let h = Header::new(Flags::new_sd(RebootFlag::RecentlyRebooted), &[], &[]);
584 let mut buf = [0u8; 16];
585 h.encode(&mut buf.as_mut_slice()).unwrap();
586 let view = SdHeaderView::parse(&buf[..h.encoded_size().unwrap()]).unwrap();
587 assert_eq!(view.flags(), h.flags);
588 }
589
590 #[test]
591 fn parse_incorrect_entries_size_returns_error() {
592 let mut buf = [0u8; 12];
593 buf[4..8].copy_from_slice(&5u32.to_be_bytes());
594 assert!(matches!(
595 SdHeaderView::parse(&buf),
596 Err(crate::protocol::Error::Sd(SdError::IncorrectEntriesSize(5)))
597 ));
598 }
599
600 #[test]
601 fn parse_rejects_ipv4_option_with_invalid_transport_protocol() {
602 const SD_HEADER_PREFIX_SIZE: usize = 12;
607 let options_size = u32::try_from(IPV4_OPTION_WIRE_SIZE).expect("wire size fits u32");
608 let prefix = raw_header(0, options_size);
609 let option = ipv4_endpoint_bytes([10, 0, 0, 1], 0xAB, 30490);
610 let mut buf = [0u8; SD_HEADER_PREFIX_SIZE + IPV4_OPTION_WIRE_SIZE];
611 buf[..SD_HEADER_PREFIX_SIZE].copy_from_slice(&prefix);
612 buf[SD_HEADER_PREFIX_SIZE..].copy_from_slice(&option);
613 assert!(matches!(
614 SdHeaderView::parse(&buf),
615 Err(crate::protocol::Error::Sd(
616 SdError::InvalidOptionTransportProtocol(0xAB)
617 ))
618 ));
619 }
620
621 #[test]
624 fn sd_body_decode_slices_sections() {
625 let ip = Ipv4Addr::new(192, 168, 1, 10);
626 let entry = Entry::OfferService(ServiceEntry {
627 service_id: 0x1234,
628 instance_id: 0x0001,
629 major_version: 1,
630 ttl: 0xFF_FFFF,
631 index_first_options_run: 0,
632 index_second_options_run: 0,
633 options_count: OptionsCount::new(1, 0),
634 minor_version: 0,
635 });
636 let endpoint = Options::IpV4Endpoint {
637 ip,
638 protocol: TransportProtocol::Udp,
639 port: 30509,
640 };
641 let entries = [entry];
642 let options = [endpoint];
643 let h = Header::new(
644 Flags::new_sd(RebootFlag::RecentlyRebooted),
645 &entries,
646 &options,
647 );
648 let mut buf = [0u8; 64];
649 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
650 let (body, rest) = SdBody::decode(&buf[..n]).unwrap();
651 assert!(rest.is_empty());
652 assert_eq!(body.flags(), h.flags);
653 let entry_view = body.entries().next().unwrap().unwrap();
655 assert_eq!(entry_view.service_id(), 0x1234);
656 let opt_view = body.options().next().unwrap().unwrap();
657 assert_eq!(opt_view.as_ipv4().unwrap().0, ip);
658 }
659
660 #[test]
661 fn sd_body_decode_returns_trailing_remainder() {
662 let h = Header::new(Flags::new_sd(RebootFlag::RecentlyRebooted), &[], &[]);
663 let mut buf = [0u8; 32];
664 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
665 buf[n] = 0xDE;
667 buf[n + 1] = 0xAD;
668 buf[n + 2] = 0xBE;
669 let (_body, rest) = SdBody::decode(&buf[..n + 3]).unwrap();
670 assert_eq!(rest, &[0xDE, 0xAD, 0xBE]);
671 }
672
673 #[test]
674 fn sd_body_decode_defers_entry_type_validation() {
675 let mut buf = [0u8; 28];
679 buf[4..8].copy_from_slice(&16u32.to_be_bytes());
680 buf[8] = 0x03; let (body, rest) = SdBody::decode(&buf).unwrap();
683 assert!(rest.is_empty());
684 let entry_view = body.entries().next().unwrap().unwrap();
686 assert!(matches!(
687 entry_view.to_owned(),
688 Err(SdError::InvalidEntryType(0x03))
689 ));
690 assert!(matches!(
692 SdHeaderView::parse(&buf),
693 Err(crate::protocol::Error::Sd(SdError::InvalidEntryType(0x03)))
694 ));
695 }
696
697 #[test]
698 fn sd_body_decode_defers_option_validation() {
699 const PREFIX: usize = 12;
702 let options_size = u32::try_from(IPV4_OPTION_WIRE_SIZE).unwrap();
703 let prefix = raw_header(0, options_size);
704 let option = ipv4_endpoint_bytes([10, 0, 0, 1], 0xAB, 30490);
705 let mut buf = [0u8; PREFIX + IPV4_OPTION_WIRE_SIZE];
706 buf[..PREFIX].copy_from_slice(&prefix);
707 buf[PREFIX..].copy_from_slice(&option);
708 let (body, rest) = SdBody::decode(&buf).unwrap();
709 assert!(rest.is_empty());
710 let opt_view = body.options().next().unwrap().unwrap();
711 assert!(matches!(
712 opt_view.as_ipv4(),
713 Err(SdError::InvalidOptionTransportProtocol(0xAB))
714 ));
715 }
716
717 #[test]
718 fn sd_body_decode_too_short_is_incomplete() {
719 let buf = [0u8; 8];
720 assert!(matches!(
721 SdBody::decode(&buf),
722 Err(crate::protocol::Error::Incomplete(
723 automotive_wire_codec::Incomplete {
724 needed: 12,
725 available: 8,
726 }
727 ))
728 ));
729 }
730
731 #[test]
732 fn sd_body_decode_rejects_non_multiple_entries_size() {
733 let mut buf = [0u8; 12];
734 buf[4..8].copy_from_slice(&5u32.to_be_bytes());
735 assert!(matches!(
736 SdBody::decode(&buf),
737 Err(crate::protocol::Error::Sd(SdError::IncorrectEntriesSize(5)))
738 ));
739 }
740
741 #[test]
742 fn sd_body_entries_remaining_len_reports_count() {
743 let entries = [
744 Entry::FindService(ServiceEntry::find(0x0001)),
745 Entry::FindService(ServiceEntry::find(0x0002)),
746 ];
747 let h = Header::new(Flags::new_sd(RebootFlag::RecentlyRebooted), &entries, &[]);
748 let mut buf = [0u8; 64];
749 let n = h.encode(&mut buf.as_mut_slice()).unwrap();
750 let (body, _rest) = SdBody::decode(&buf[..n]).unwrap();
751 assert_eq!(body.entries().remaining_len(), Some(2));
752 }
753}