1use core::fmt;
8use core::mem::size_of;
9
10const NUM_STORAGE_PERMISSIONS: usize = 8;
13
14pub enum InitialTbfParseError {
17 UnableToParse,
22
23 InvalidHeader(u32),
28}
29
30impl From<core::array::TryFromSliceError> for InitialTbfParseError {
31 fn from(_error: core::array::TryFromSliceError) -> Self {
35 InitialTbfParseError::UnableToParse
36 }
37}
38
39pub enum TbfParseError {
41 NotEnoughFlash,
43
44 UnsupportedVersion(u16),
46
47 ChecksumMismatch(u32, u32),
51
52 BadTlvEntry(usize),
56
57 BadProcessName,
60
61 InternalError,
67
68 TooManyEntries(usize),
73}
74
75impl From<core::array::TryFromSliceError> for TbfParseError {
76 fn from(_error: core::array::TryFromSliceError) -> Self {
80 TbfParseError::InternalError
81 }
82}
83
84impl fmt::Debug for TbfParseError {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 match self {
87 TbfParseError::NotEnoughFlash => write!(f, "Buffer too short to parse TBF header"),
88 TbfParseError::UnsupportedVersion(version) => {
89 write!(f, "TBF version {} unsupported", version)
90 }
91 TbfParseError::ChecksumMismatch(app, calc) => write!(
92 f,
93 "Checksum verification failed: app:{:#x}, calc:{:#x}",
94 app, calc
95 ),
96 TbfParseError::BadTlvEntry(tipe) => write!(f, "TLV entry type {} is invalid", tipe),
97 TbfParseError::BadProcessName => write!(f, "Process name not UTF-8"),
98 TbfParseError::InternalError => write!(f, "Internal kernel error. This is a bug."),
99 TbfParseError::TooManyEntries(tipe) => {
100 write!(
101 f,
102 "There are too many variable entries of {} for Tock to parse",
103 tipe
104 )
105 }
106 }
107 }
108}
109
110pub const TBF_HEADER_V2_BASE_SIZE: usize = 16;
114
115#[derive(Clone, Copy, Debug)]
117pub struct TbfHeaderV2Base {
118 pub(crate) version: u16,
119 pub(crate) header_size: u16,
120 pub(crate) total_size: u32,
121 pub(crate) flags: u32,
122 pub(crate) checksum: u32,
123}
124
125#[derive(Clone, Copy, Debug)]
127pub enum TbfHeaderTypes {
128 TbfHeaderMain = 1,
129 TbfHeaderWriteableFlashRegions = 2,
130 TbfHeaderPackageName = 3,
131 TbfHeaderFixedAddresses = 5,
132 TbfHeaderPermissions = 6,
133 TbfHeaderStoragePermissions = 7,
134 TbfHeaderKernelVersion = 8,
135 TbfHeaderProgram = 9,
136 TbfHeaderShortId = 10,
137 TbfFooterCredentials = 128,
138
139 Unknown,
143}
144
145#[derive(Clone, Copy, Debug)]
147pub struct TbfTlv {
148 pub(crate) tipe: TbfHeaderTypes,
149 pub(crate) length: u16,
150}
151
152#[derive(Clone, Copy, Debug)]
160pub struct TbfHeaderV2Main {
161 init_fn_offset: u32,
162 protected_trailer_size: u32,
163 minimum_ram_size: u32,
164}
165
166#[derive(Clone, Copy, Debug)]
176pub struct TbfHeaderV2Program {
177 init_fn_offset: u32,
178 protected_trailer_size: u32,
179 minimum_ram_size: u32,
180 binary_end_offset: u32,
181 version: u32,
182}
183
184#[derive(Clone, Copy, Debug, Default)]
189pub struct TbfHeaderV2WriteableFlashRegion {
190 writeable_flash_region_offset: u32,
191 writeable_flash_region_size: u32,
192}
193
194#[derive(Clone, Copy, Debug, Default)]
207pub struct TbfHeaderV2FixedAddresses {
208 start_process_ram: u32,
212 start_process_flash: u32,
216}
217
218#[derive(Clone, Copy, Debug, Default)]
219struct TbfHeaderDriverPermission {
220 driver_number: u32,
221 offset: u32,
222 allowed_commands: u64,
223}
224
225#[derive(Clone, Copy, Debug)]
227pub struct TbfHeaderV2Permissions<const L: usize> {
228 length: u16,
229 perms: [TbfHeaderDriverPermission; L],
230}
231
232#[derive(Clone, Copy, Debug)]
234pub struct TbfHeaderV2StoragePermissions<const L: usize> {
235 write_id: Option<core::num::NonZeroU32>,
236 read_length: u16,
237 read_ids: [u32; L],
238 modify_length: u16,
239 modify_ids: [u32; L],
240}
241
242#[derive(Clone, Copy, Debug)]
243pub struct TbfHeaderV2KernelVersion {
244 major: u16,
245 minor: u16,
246}
247
248#[derive(Clone, Copy, Debug)]
252pub struct TbfHeaderV2ShortId {
253 short_id: Option<core::num::NonZeroU32>,
254}
255
256#[derive(Clone, Copy, Debug, Eq, PartialEq)]
257pub enum TbfFooterV2CredentialsType {
258 Reserved = 0,
259 Rsa3072Key = 1,
260 Rsa4096Key = 2,
261 SHA256 = 3,
262 SHA384 = 4,
263 SHA512 = 5,
264 EcdsaNistP256 = 6,
265}
266
267#[derive(Clone, Copy, Debug)]
268pub struct TbfFooterV2Credentials {
269 format: TbfFooterV2CredentialsType,
270 data: &'static [u8],
271}
272
273impl TbfFooterV2Credentials {
274 pub fn format(&self) -> TbfFooterV2CredentialsType {
275 self.format
276 }
277
278 pub fn data(&self) -> &'static [u8] {
279 self.data
280 }
281}
282
283impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Base {
286 type Error = TbfParseError;
287
288 fn try_from(b: &[u8]) -> Result<TbfHeaderV2Base, Self::Error> {
289 if b.len() < 16 {
290 return Err(TbfParseError::InternalError);
291 }
292 Ok(TbfHeaderV2Base {
293 version: u16::from_le_bytes(
294 b.get(0..2)
295 .ok_or(TbfParseError::InternalError)?
296 .try_into()?,
297 ),
298 header_size: u16::from_le_bytes(
299 b.get(2..4)
300 .ok_or(TbfParseError::InternalError)?
301 .try_into()?,
302 ),
303 total_size: u32::from_le_bytes(
304 b.get(4..8)
305 .ok_or(TbfParseError::InternalError)?
306 .try_into()?,
307 ),
308 flags: u32::from_le_bytes(
309 b.get(8..12)
310 .ok_or(TbfParseError::InternalError)?
311 .try_into()?,
312 ),
313 checksum: u32::from_le_bytes(
314 b.get(12..16)
315 .ok_or(TbfParseError::InternalError)?
316 .try_into()?,
317 ),
318 })
319 }
320}
321
322impl core::convert::TryFrom<u16> for TbfHeaderTypes {
323 type Error = TbfParseError;
324
325 fn try_from(h: u16) -> Result<TbfHeaderTypes, Self::Error> {
326 match h {
327 1 => Ok(TbfHeaderTypes::TbfHeaderMain),
328 2 => Ok(TbfHeaderTypes::TbfHeaderWriteableFlashRegions),
329 3 => Ok(TbfHeaderTypes::TbfHeaderPackageName),
330 5 => Ok(TbfHeaderTypes::TbfHeaderFixedAddresses),
331 6 => Ok(TbfHeaderTypes::TbfHeaderPermissions),
332 7 => Ok(TbfHeaderTypes::TbfHeaderStoragePermissions),
333 8 => Ok(TbfHeaderTypes::TbfHeaderKernelVersion),
334 9 => Ok(TbfHeaderTypes::TbfHeaderProgram),
335 10 => Ok(TbfHeaderTypes::TbfHeaderShortId),
336 128 => Ok(TbfHeaderTypes::TbfFooterCredentials),
337 _ => Ok(TbfHeaderTypes::Unknown),
338 }
339 }
340}
341
342impl core::convert::TryFrom<&[u8]> for TbfTlv {
343 type Error = TbfParseError;
344
345 fn try_from(b: &[u8]) -> Result<TbfTlv, Self::Error> {
346 Ok(TbfTlv {
347 tipe: u16::from_le_bytes(
348 b.get(0..2)
349 .ok_or(TbfParseError::InternalError)?
350 .try_into()?,
351 )
352 .try_into()?,
353 length: u16::from_le_bytes(
354 b.get(2..4)
355 .ok_or(TbfParseError::InternalError)?
356 .try_into()?,
357 ),
358 })
359 }
360}
361
362impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Main {
363 type Error = TbfParseError;
364
365 fn try_from(b: &[u8]) -> Result<TbfHeaderV2Main, Self::Error> {
366 if b.len() < 12 {
368 return Err(TbfParseError::InternalError);
369 }
370 Ok(TbfHeaderV2Main {
371 init_fn_offset: u32::from_le_bytes(
372 b.get(0..4)
373 .ok_or(TbfParseError::InternalError)?
374 .try_into()?,
375 ),
376 protected_trailer_size: u32::from_le_bytes(
377 b.get(4..8)
378 .ok_or(TbfParseError::InternalError)?
379 .try_into()?,
380 ),
381 minimum_ram_size: u32::from_le_bytes(
382 b.get(8..12)
383 .ok_or(TbfParseError::InternalError)?
384 .try_into()?,
385 ),
386 })
387 }
388}
389
390impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Program {
391 type Error = TbfParseError;
392 fn try_from(b: &[u8]) -> Result<TbfHeaderV2Program, Self::Error> {
393 if b.len() < 20 {
395 return Err(TbfParseError::InternalError);
396 }
397 Ok(TbfHeaderV2Program {
398 init_fn_offset: u32::from_le_bytes(
399 b.get(0..4)
400 .ok_or(TbfParseError::InternalError)?
401 .try_into()?,
402 ),
403 protected_trailer_size: u32::from_le_bytes(
404 b.get(4..8)
405 .ok_or(TbfParseError::InternalError)?
406 .try_into()?,
407 ),
408 minimum_ram_size: u32::from_le_bytes(
409 b.get(8..12)
410 .ok_or(TbfParseError::InternalError)?
411 .try_into()?,
412 ),
413 binary_end_offset: u32::from_le_bytes(
414 b.get(12..16)
415 .ok_or(TbfParseError::InternalError)?
416 .try_into()?,
417 ),
418 version: u32::from_le_bytes(
419 b.get(16..20)
420 .ok_or(TbfParseError::InternalError)?
421 .try_into()?,
422 ),
423 })
424 }
425}
426
427impl core::convert::TryFrom<&[u8]> for TbfHeaderV2WriteableFlashRegion {
428 type Error = TbfParseError;
429
430 fn try_from(b: &[u8]) -> Result<TbfHeaderV2WriteableFlashRegion, Self::Error> {
431 Ok(TbfHeaderV2WriteableFlashRegion {
432 writeable_flash_region_offset: u32::from_le_bytes(
433 b.get(0..4)
434 .ok_or(TbfParseError::InternalError)?
435 .try_into()?,
436 ),
437 writeable_flash_region_size: u32::from_le_bytes(
438 b.get(4..8)
439 .ok_or(TbfParseError::InternalError)?
440 .try_into()?,
441 ),
442 })
443 }
444}
445
446impl core::convert::TryFrom<&[u8]> for TbfHeaderV2FixedAddresses {
447 type Error = TbfParseError;
448
449 fn try_from(b: &[u8]) -> Result<TbfHeaderV2FixedAddresses, Self::Error> {
450 Ok(TbfHeaderV2FixedAddresses {
451 start_process_ram: u32::from_le_bytes(
452 b.get(0..4)
453 .ok_or(TbfParseError::InternalError)?
454 .try_into()?,
455 ),
456 start_process_flash: u32::from_le_bytes(
457 b.get(4..8)
458 .ok_or(TbfParseError::InternalError)?
459 .try_into()?,
460 ),
461 })
462 }
463}
464
465impl core::convert::TryFrom<&[u8]> for TbfHeaderDriverPermission {
466 type Error = TbfParseError;
467
468 fn try_from(b: &[u8]) -> Result<TbfHeaderDriverPermission, Self::Error> {
469 if b.len() < 16 {
471 return Err(TbfParseError::InternalError);
472 }
473 Ok(TbfHeaderDriverPermission {
474 driver_number: u32::from_le_bytes(
475 b.get(0..4)
476 .ok_or(TbfParseError::InternalError)?
477 .try_into()?,
478 ),
479 offset: u32::from_le_bytes(
480 b.get(4..8)
481 .ok_or(TbfParseError::InternalError)?
482 .try_into()?,
483 ),
484 allowed_commands: u64::from_le_bytes(
485 b.get(8..16)
486 .ok_or(TbfParseError::InternalError)?
487 .try_into()?,
488 ),
489 })
490 }
491}
492
493impl<const L: usize> core::convert::TryFrom<&[u8]> for TbfHeaderV2StoragePermissions<L> {
494 type Error = TbfParseError;
495
496 fn try_from(b: &[u8]) -> Result<TbfHeaderV2StoragePermissions<L>, Self::Error> {
497 let mut read_end = 6;
498
499 let write_id = core::num::NonZeroU32::new(u32::from_le_bytes(
500 b.get(0..4)
501 .ok_or(TbfParseError::NotEnoughFlash)?
502 .try_into()?,
503 ));
504
505 let read_length = u16::from_le_bytes(
506 b.get(4..6)
507 .ok_or(TbfParseError::NotEnoughFlash)?
508 .try_into()?,
509 );
510
511 let mut read_ids: [u32; L] = [0; L];
512 for i in 0..read_length as usize {
513 let start = 6 + (i * size_of::<u32>());
514 read_end = start + size_of::<u32>();
515 if let Some(read_id) = read_ids.get_mut(i) {
516 *read_id = u32::from_le_bytes(
517 b.get(start..read_end)
518 .ok_or(TbfParseError::NotEnoughFlash)?
519 .try_into()?,
520 );
521 } else {
522 return Err(TbfParseError::BadTlvEntry(
523 TbfHeaderTypes::TbfHeaderStoragePermissions as usize,
524 ));
525 }
526 }
527
528 let modify_length = u16::from_le_bytes(
529 b.get(read_end..(read_end + 2))
530 .ok_or(TbfParseError::NotEnoughFlash)?
531 .try_into()?,
532 );
533
534 let mut modify_ids: [u32; L] = [0; L];
535 for i in 0..modify_length as usize {
536 let start = read_end + 2 + (i * size_of::<u32>());
537 let modify_end = start + size_of::<u32>();
538 if let Some(modify_id) = modify_ids.get_mut(i) {
539 *modify_id = u32::from_le_bytes(
540 b.get(start..modify_end)
541 .ok_or(TbfParseError::NotEnoughFlash)?
542 .try_into()?,
543 );
544 } else {
545 return Err(TbfParseError::BadTlvEntry(
546 TbfHeaderTypes::TbfHeaderStoragePermissions as usize,
547 ));
548 }
549 }
550
551 Ok(TbfHeaderV2StoragePermissions {
552 write_id,
553 read_length,
554 read_ids,
555 modify_length,
556 modify_ids,
557 })
558 }
559}
560
561impl core::convert::TryFrom<&[u8]> for TbfHeaderV2KernelVersion {
562 type Error = TbfParseError;
563
564 fn try_from(b: &[u8]) -> Result<TbfHeaderV2KernelVersion, Self::Error> {
565 Ok(TbfHeaderV2KernelVersion {
566 major: u16::from_le_bytes(
567 b.get(0..2)
568 .ok_or(TbfParseError::InternalError)?
569 .try_into()?,
570 ),
571 minor: u16::from_le_bytes(
572 b.get(2..4)
573 .ok_or(TbfParseError::InternalError)?
574 .try_into()?,
575 ),
576 })
577 }
578}
579
580impl core::convert::TryFrom<&[u8]> for TbfHeaderV2ShortId {
581 type Error = TbfParseError;
582
583 fn try_from(b: &[u8]) -> Result<TbfHeaderV2ShortId, Self::Error> {
584 Ok(TbfHeaderV2ShortId {
585 short_id: core::num::NonZeroU32::new(u32::from_le_bytes(
586 b.get(0..4)
587 .ok_or(TbfParseError::InternalError)?
588 .try_into()?,
589 )),
590 })
591 }
592}
593
594impl core::convert::TryFrom<&'static [u8]> for TbfFooterV2Credentials {
595 type Error = TbfParseError;
596
597 fn try_from(b: &'static [u8]) -> Result<TbfFooterV2Credentials, Self::Error> {
598 let format = u32::from_le_bytes(
599 b.get(0..4)
600 .ok_or(TbfParseError::InternalError)?
601 .try_into()?,
602 );
603 let ftype = match format {
604 0 => TbfFooterV2CredentialsType::Reserved,
605 1 => TbfFooterV2CredentialsType::Rsa3072Key,
606 2 => TbfFooterV2CredentialsType::Rsa4096Key,
607 3 => TbfFooterV2CredentialsType::SHA256,
608 4 => TbfFooterV2CredentialsType::SHA384,
609 5 => TbfFooterV2CredentialsType::SHA512,
610 6 => TbfFooterV2CredentialsType::EcdsaNistP256,
611 _ => {
612 return Err(TbfParseError::BadTlvEntry(
613 TbfHeaderTypes::TbfFooterCredentials as usize,
614 ));
615 }
616 };
617 let length = match ftype {
618 TbfFooterV2CredentialsType::Reserved => 0,
619 TbfFooterV2CredentialsType::Rsa3072Key => 768,
620 TbfFooterV2CredentialsType::Rsa4096Key => 1024,
621 TbfFooterV2CredentialsType::SHA256 => 32,
622 TbfFooterV2CredentialsType::SHA384 => 48,
623 TbfFooterV2CredentialsType::SHA512 => 64,
624 TbfFooterV2CredentialsType::EcdsaNistP256 => 64,
625 };
626 let data = &b
627 .get(4..(length + 4))
628 .ok_or(TbfParseError::NotEnoughFlash)?;
629 Ok(TbfFooterV2Credentials {
630 format: ftype,
631 data,
632 })
633 }
634}
635
636pub enum CommandPermissions {
640 NoPermsAtAll,
642 NoPermsThisDriver,
645 Mask(u64),
648}
649
650#[derive(Clone, Copy, Debug)]
656pub struct TbfHeaderV2<'a> {
657 pub(crate) base: TbfHeaderV2Base,
658 pub(crate) main: Option<TbfHeaderV2Main>,
659 pub(crate) program: Option<TbfHeaderV2Program>,
660 pub(crate) package_name: Option<&'a str>,
661 pub(crate) writeable_regions: Option<&'a [u8]>,
662 pub(crate) fixed_addresses: Option<&'a [u8]>,
663 pub(crate) permissions: Option<&'a [u8]>,
664 pub(crate) storage_permissions: Option<&'a [u8]>,
665 pub(crate) kernel_version: Option<TbfHeaderV2KernelVersion>,
666 pub(crate) short_id: Option<TbfHeaderV2ShortId>,
667}
668
669#[derive(Debug)]
676pub enum TbfHeader<'a> {
677 TbfHeaderV2(TbfHeaderV2<'a>),
678 Padding(TbfHeaderV2Base),
679}
680
681impl<'a> TbfHeader<'a> {
682 pub fn length(&self) -> u16 {
684 match *self {
685 TbfHeader::TbfHeaderV2(hd) => hd.base.header_size,
686 TbfHeader::Padding(base) => base.header_size,
687 }
688 }
689
690 pub fn is_app(&self) -> bool {
692 match *self {
693 TbfHeader::TbfHeaderV2(_) => true,
694 TbfHeader::Padding(_) => false,
695 }
696 }
697
698 pub fn enabled(&self) -> bool {
701 match *self {
702 TbfHeader::TbfHeaderV2(hd) => {
703 hd.base.flags & 0x00000001 == 1
705 }
706 TbfHeader::Padding(_) => false,
707 }
708 }
709
710 pub fn get_minimum_app_ram_size(&self) -> u32 {
714 match *self {
715 TbfHeader::TbfHeaderV2(hd) => {
716 if hd.program.is_some() {
717 hd.program.map_or(0, |p| p.minimum_ram_size)
718 } else if hd.main.is_some() {
719 hd.main.map_or(0, |m| m.minimum_ram_size)
720 } else {
721 0
722 }
723 }
724 _ => 0,
725 }
726 }
727
728 pub fn get_protected_size(&self) -> u32 {
731 match *self {
732 TbfHeader::TbfHeaderV2(hd) => {
733 if hd.program.is_some() {
734 hd.program.map_or(0, |p| {
735 (hd.base.header_size as u32) + p.protected_trailer_size
736 })
737 } else if hd.main.is_some() {
738 hd.main.map_or(0, |m| {
739 (hd.base.header_size as u32) + m.protected_trailer_size
740 })
741 } else {
742 0
743 }
744 }
745 _ => 0,
746 }
747 }
748
749 pub fn get_app_start_offset(&self) -> u32 {
753 self.get_protected_size()
756 }
757
758 pub fn get_init_function_offset(&self) -> u32 {
761 match *self {
762 TbfHeader::TbfHeaderV2(hd) => {
763 if hd.program.is_some() {
764 hd.program
765 .map_or(0, |p| p.init_fn_offset + (hd.base.header_size as u32))
766 } else if hd.main.is_some() {
767 hd.main
768 .map_or(0, |m| m.init_fn_offset + (hd.base.header_size as u32))
769 } else {
770 0
771 }
772 }
773 _ => 0,
774 }
775 }
776
777 pub fn get_package_name(&self) -> Option<&'a str> {
779 match *self {
780 TbfHeader::TbfHeaderV2(hd) => hd.package_name,
781 _ => None,
782 }
783 }
784
785 pub fn number_writeable_flash_regions(&self) -> usize {
787 match *self {
788 TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or(0, |wr_slice| {
789 let wfr_len = size_of::<TbfHeaderV2WriteableFlashRegion>();
790 wr_slice.len() / wfr_len
791 }),
792 _ => 0,
793 }
794 }
795
796 pub fn get_writeable_flash_region(&self, index: usize) -> (usize, usize) {
798 match *self {
799 TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or((0, 0), |wr_slice| {
800 fn get_region(
801 wr_slice: &[u8],
802 index: usize,
803 ) -> Result<TbfHeaderV2WriteableFlashRegion, ()> {
804 let wfr_len = size_of::<TbfHeaderV2WriteableFlashRegion>();
805
806 let wfr = wr_slice
807 .get(index * wfr_len..(index + 1) * wfr_len)
808 .ok_or(())?
809 .try_into()
810 .or(Err(()))?;
811 Ok(wfr)
812 }
813
814 match get_region(wr_slice, index) {
815 Ok(wr) => (
816 wr.writeable_flash_region_offset as usize,
817 wr.writeable_flash_region_size as usize,
818 ),
819 Err(()) => (0, 0),
820 }
821 }),
822 _ => (0, 0),
823 }
824 }
825
826 pub fn get_fixed_address_ram(&self) -> Option<u32> {
829 let hd = match self {
830 TbfHeader::TbfHeaderV2(hd) => hd,
831 _ => return None,
832 };
833 let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?;
834 match fixed_addresses.start_process_ram {
835 0xFFFFFFFF => None,
836 start => Some(start),
837 }
838 }
839
840 pub fn get_fixed_address_flash(&self) -> Option<u32> {
843 let hd = match self {
844 TbfHeader::TbfHeaderV2(hd) => hd,
845 _ => return None,
846 };
847 let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?;
848 match fixed_addresses.start_process_flash {
849 0xFFFFFFFF => None,
850 start => Some(start),
851 }
852 }
853
854 pub fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions {
867 match self {
868 TbfHeader::TbfHeaderV2(hd) => match hd.permissions {
869 Some(permissions_tlv_slice) => {
870 fn get_command_permissions_result(
872 permissions_tlv_slice: &[u8],
873 driver_num: usize,
874 offset: usize,
875 ) -> Result<CommandPermissions, ()> {
876 let mut found_driver_num: bool = false;
877 let perm_len = size_of::<TbfHeaderDriverPermission>();
878
879 let number_perms = u16::from_le_bytes(
881 permissions_tlv_slice
882 .get(0..2)
883 .ok_or(())?
884 .try_into()
885 .or(Err(()))?,
886 );
887 let permissions_slice = permissions_tlv_slice.get(2..).ok_or(())?;
889
890 for i in 0..number_perms as usize {
892 let perm: TbfHeaderDriverPermission = permissions_slice
893 .get((i * perm_len)..((i + 1) * perm_len))
894 .ok_or(())?
895 .try_into()
896 .or(Err(()))?;
897
898 if perm.driver_number == driver_num as u32 {
899 found_driver_num = true;
900 if perm.offset == offset as u32 {
901 return Ok(CommandPermissions::Mask(perm.allowed_commands));
902 }
903 }
904 }
905
906 if found_driver_num {
907 Ok(CommandPermissions::Mask(0))
911 } else {
912 Ok(CommandPermissions::NoPermsThisDriver)
913 }
914 }
915
916 get_command_permissions_result(permissions_tlv_slice, driver_num, offset)
917 .unwrap_or(CommandPermissions::NoPermsAtAll)
918 }
919 _ => CommandPermissions::NoPermsAtAll,
920 },
921 _ => CommandPermissions::NoPermsAtAll,
922 }
923 }
924
925 pub fn get_storage_write_id(&self) -> Option<core::num::NonZeroU32> {
930 match self {
931 TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
932 Some(storage_permissions_tlv_slice) => {
933 core::num::NonZeroU32::new(u32::from_le_bytes(
935 storage_permissions_tlv_slice.get(0..4)?.try_into().ok()?,
936 ))
937 }
938 _ => None,
939 },
940 _ => None,
941 }
942 }
943
944 pub fn get_storage_read_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> {
947 match self {
948 TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
949 Some(storage_permissions_tlv_slice) => {
950 let storage_permissions: TbfHeaderV2StoragePermissions<
951 NUM_STORAGE_PERMISSIONS,
952 > = storage_permissions_tlv_slice.try_into().ok()?;
953
954 Some((
955 storage_permissions.read_length.into(),
956 storage_permissions.read_ids,
957 ))
958 }
959 _ => None,
960 },
961 _ => None,
962 }
963 }
964
965 pub fn get_storage_modify_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> {
968 match self {
969 TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
970 Some(storage_permissions_tlv_slice) => {
971 let storage_permissions: TbfHeaderV2StoragePermissions<
972 NUM_STORAGE_PERMISSIONS,
973 > = storage_permissions_tlv_slice.try_into().ok()?;
974
975 Some((
976 storage_permissions.modify_length.into(),
977 storage_permissions.modify_ids,
978 ))
979 }
980 _ => None,
981 },
982 _ => None,
983 }
984 }
985
986 pub fn get_kernel_version(&self) -> Option<(u16, u16)> {
989 match self {
990 TbfHeader::TbfHeaderV2(hd) => match hd.kernel_version {
991 Some(kernel_version) => Some((kernel_version.major, kernel_version.minor)),
992 _ => None,
993 },
994 _ => None,
995 }
996 }
997
998 pub fn get_binary_end(&self) -> u32 {
1002 match self {
1003 TbfHeader::TbfHeaderV2(hd) => hd
1004 .program
1005 .map_or(hd.base.total_size, |p| p.binary_end_offset),
1006 _ => 0,
1007 }
1008 }
1009
1010 pub fn get_binary_version(&self) -> u32 {
1013 match self {
1014 TbfHeader::TbfHeaderV2(hd) => hd.program.map_or(0, |p| p.version),
1015 _ => 0,
1016 }
1017 }
1018
1019 pub fn get_fixed_short_id(&self) -> Option<core::num::NonZeroU32> {
1022 match self {
1023 TbfHeader::TbfHeaderV2(hd) => hd.short_id.and_then(|si| si.short_id),
1024 _ => None,
1025 }
1026 }
1027}