1use core::{marker::PhantomData, ops::Range};
2
3use crate::{
4 BuildError, ChannelId, Fcf, FloodHops, MicSize, NodeHint, OptionNumber, PacketType, PublicKey,
5 Scf, SecInfo, UnsealedPacket, options::OptionEncoder,
6};
7
8pub mod state {
10 pub struct NeedsSource;
12 pub struct NeedsCounter;
14 pub struct Configuring;
16 pub struct Complete;
18}
19
20pub struct PacketBuilder<'a> {
25 buf: &'a mut [u8],
26}
27
28impl<'a> PacketBuilder<'a> {
29 pub fn new(buf: &'a mut [u8]) -> Self {
31 Self { buf }
32 }
33
34 pub fn broadcast(self) -> BroadcastBuilder<'a, state::NeedsSource> {
36 Builder::new(self.buf, PacketType::Broadcast)
37 }
38
39 pub fn mac_ack(self, dst: NodeHint, ack_tag: [u8; 8]) -> MacAckBuilder<'a, state::Configuring> {
41 let mut builder = Builder::new(self.buf, PacketType::MacAck);
42 builder.ack_dst = Some(dst);
43 builder.ack_tag = Some(ack_tag);
44 builder
45 }
46
47 pub fn unicast(self, dst: NodeHint) -> UnicastBuilder<'a, state::NeedsSource> {
49 let mut builder = Builder::new(self.buf, PacketType::Unicast);
50 builder.dst = Some(dst);
51 builder
52 }
53
54 pub fn multicast(self, channel: ChannelId) -> MulticastBuilder<'a, state::NeedsSource> {
56 let mut builder = Builder::new(self.buf, PacketType::Multicast);
57 builder.channel = Some(channel);
58 builder
59 }
60
61 pub fn blind_unicast(
63 self,
64 channel: ChannelId,
65 dst: NodeHint,
66 ) -> BlindUnicastBuilder<'a, state::NeedsSource> {
67 let mut builder = Builder::new(self.buf, PacketType::BlindUnicast);
68 builder.channel = Some(channel);
69 builder.dst = Some(dst);
70 builder
71 }
72}
73
74pub type BroadcastBuilder<'a, S> = Builder<'a, BroadcastKind, S>;
76pub type MacAckBuilder<'a, S> = Builder<'a, MacAckKind, S>;
78pub type UnicastBuilder<'a, S> = Builder<'a, UnicastKind, S>;
80pub type MulticastBuilder<'a, S> = Builder<'a, MulticastKind, S>;
82pub type BlindUnicastBuilder<'a, S> = Builder<'a, BlindUnicastKind, S>;
84
85pub struct BroadcastKind;
87pub struct MacAckKind;
89pub struct UnicastKind;
91pub struct MulticastKind;
93pub struct BlindUnicastKind;
95
96enum SourceValue {
97 Hint(NodeHint),
98 Full(PublicKey),
99}
100
101pub struct Builder<'a, K, S> {
103 buf: &'a mut [u8],
104 packet_type: PacketType,
105 options_used: bool,
106 options_finalized: bool,
107 options_len: usize,
108 last_option_number: Option<u16>,
109 option_error: Option<BuildError>,
110 source: Option<SourceValue>,
111 dst: Option<NodeHint>,
112 channel: Option<ChannelId>,
113 ack_dst: Option<NodeHint>,
114 ack_tag: Option<[u8; 8]>,
115 frame_counter: Option<u32>,
116 encrypted: bool,
117 mic_size: MicSize,
118 salt: Option<u16>,
119 flood_hops: Option<FloodHops>,
120 payload: Option<Range<usize>>,
121 blind_addr: Option<Range<usize>>,
122 _marker: PhantomData<(K, S)>,
123}
124
125impl<'a, K, S> Builder<'a, K, S> {
126 fn new(buf: &'a mut [u8], packet_type: PacketType) -> Self {
127 Self {
128 buf,
129 packet_type,
130 options_used: false,
131 options_finalized: false,
132 options_len: 0,
133 last_option_number: None,
134 option_error: None,
135 source: None,
136 dst: None,
137 channel: None,
138 ack_dst: None,
139 ack_tag: None,
140 frame_counter: None,
141 encrypted: matches!(
142 packet_type,
143 PacketType::BlindUnicast | PacketType::BlindUnicastAckReq
144 ),
145 mic_size: MicSize::Mic16,
146 salt: None,
147 flood_hops: None,
148 payload: None,
149 blind_addr: None,
150 _marker: PhantomData,
151 }
152 }
153
154 fn with_state<NS>(self) -> Builder<'a, K, NS> {
155 Builder {
156 buf: self.buf,
157 packet_type: self.packet_type,
158 options_used: self.options_used,
159 options_finalized: self.options_finalized,
160 options_len: self.options_len,
161 last_option_number: self.last_option_number,
162 option_error: self.option_error,
163 source: self.source,
164 dst: self.dst,
165 channel: self.channel,
166 ack_dst: self.ack_dst,
167 ack_tag: self.ack_tag,
168 frame_counter: self.frame_counter,
169 encrypted: self.encrypted,
170 mic_size: self.mic_size,
171 salt: self.salt,
172 flood_hops: self.flood_hops,
173 payload: self.payload,
174 blind_addr: self.blind_addr,
175 _marker: PhantomData,
176 }
177 }
178
179 fn push_option(&mut self, number: u16, value: &[u8]) {
180 if self.option_error.is_some() {
181 return;
182 }
183 if let Some(last) = self.last_option_number {
184 if number < last {
185 self.option_error = Some(BuildError::OptionOutOfOrder);
186 return;
187 }
188 }
189 let mut live = match self.last_option_number {
190 Some(last_number) => {
191 OptionEncoder::with_last_number(&mut self.buf[1 + self.options_len..], last_number)
192 }
193 None => OptionEncoder::new(&mut self.buf[1 + self.options_len..]),
194 };
195 match live.put(number, value) {
196 Ok(()) => {
197 self.options_len += live.finish();
198 self.options_used = true;
199 self.last_option_number = Some(number);
200 }
201 Err(err) => self.option_error = Some(err.into()),
202 }
203 }
204
205 fn finalize_options(&mut self) -> Result<(), BuildError> {
206 if !self.options_used || self.options_finalized {
207 return Ok(());
208 }
209 let mut encoder = OptionEncoder::new(&mut self.buf[1 + self.options_len..]);
210 encoder.end_marker()?;
211 self.options_len += encoder.finish();
212 self.options_finalized = true;
213 Ok(())
214 }
215
216 fn write_common_prefix(&mut self) -> Result<usize, BuildError> {
217 if let Some(err) = self.option_error {
218 return Err(err);
219 }
220 self.finalize_options()?;
221 let full_source = matches!(self.source, Some(SourceValue::Full(_)));
222 let fcf = Fcf::new(
223 self.packet_type,
224 full_source,
225 self.options_used,
226 self.flood_hops.is_some(),
227 );
228 if self.buf.is_empty() {
229 return Err(BuildError::BufferTooSmall);
230 }
231 self.buf[0] = fcf.0;
232 let mut cursor = 1;
233 cursor += self.options_len;
234 if let Some(fhops) = self.flood_hops {
235 self.buf
236 .get_mut(cursor)
237 .ok_or(BuildError::BufferTooSmall)
238 .map(|slot| *slot = fhops.0)?;
239 cursor += 1;
240 }
241 Ok(cursor)
242 }
243
244 fn write_source(&mut self, cursor: &mut usize) -> Result<(), BuildError> {
245 match self.source {
246 Some(SourceValue::Hint(hint)) => {
247 let end = *cursor + 3;
248 self.buf
249 .get_mut(*cursor..end)
250 .ok_or(BuildError::BufferTooSmall)?
251 .copy_from_slice(&hint.0);
252 *cursor = end;
253 }
254 Some(SourceValue::Full(key)) => {
255 let end = *cursor + 32;
256 self.buf
257 .get_mut(*cursor..end)
258 .ok_or(BuildError::BufferTooSmall)?
259 .copy_from_slice(&key.0);
260 *cursor = end;
261 }
262 None => return Err(BuildError::MissingSource),
263 }
264 Ok(())
265 }
266
267 fn stage_payload(&mut self, data: &[u8]) {
268 let scratch_start = match self.buf.len().checked_sub(data.len()) {
269 Some(value) => value,
270 None => {
271 self.option_error = Some(BuildError::BufferTooSmall);
272 return;
273 }
274 };
275 if let Some(slot) = self.buf.get_mut(scratch_start..scratch_start + data.len()) {
276 slot.copy_from_slice(data);
277 self.payload = Some(scratch_start..scratch_start + data.len());
278 } else {
279 self.option_error = Some(BuildError::BufferTooSmall);
280 }
281 }
282
283 fn copy_staged_payload(&mut self, cursor: &mut usize) -> Result<Range<usize>, BuildError> {
284 let payload = self.payload.clone().ok_or(BuildError::MissingPayload)?;
285 let len = payload.end - payload.start;
286 let start = *cursor;
287 let end = start + len;
288 if end > self.buf.len() {
289 return Err(BuildError::BufferTooSmall);
290 }
291 self.buf.copy_within(payload, start);
292 *cursor = end;
293 Ok(start..end)
294 }
295
296 fn stage_blind_addr(&mut self, cursor: &mut usize) -> Result<Range<usize>, BuildError> {
297 let dst = self.dst.ok_or(BuildError::MissingDestination)?;
298 let start = *cursor;
299 let dst_end = start + 3;
300 self.buf
301 .get_mut(start..dst_end)
302 .ok_or(BuildError::BufferTooSmall)?
303 .copy_from_slice(&dst.0);
304 *cursor = dst_end;
305 self.write_source(cursor)?;
306 let end = *cursor;
307 Ok(start..end)
308 }
309}
310
311impl<'a> BroadcastBuilder<'a, state::NeedsSource> {
312 pub fn source_hint(mut self, hint: NodeHint) -> BroadcastBuilder<'a, state::Configuring> {
314 self.source = Some(SourceValue::Hint(hint));
315 self.with_state()
316 }
317
318 pub fn source_full(mut self, key: &PublicKey) -> BroadcastBuilder<'a, state::Configuring> {
320 self.source = Some(SourceValue::Full(*key));
321 self.with_state()
322 }
323}
324
325impl<'a> UnicastBuilder<'a, state::NeedsSource> {
326 pub fn source_hint(mut self, hint: NodeHint) -> UnicastBuilder<'a, state::NeedsCounter> {
328 self.source = Some(SourceValue::Hint(hint));
329 self.with_state()
330 }
331
332 pub fn source_full(mut self, key: &PublicKey) -> UnicastBuilder<'a, state::NeedsCounter> {
334 self.source = Some(SourceValue::Full(*key));
335 self.with_state()
336 }
337}
338
339impl<'a> MulticastBuilder<'a, state::NeedsSource> {
340 pub fn source_hint(mut self, hint: NodeHint) -> MulticastBuilder<'a, state::NeedsCounter> {
342 self.source = Some(SourceValue::Hint(hint));
343 self.with_state()
344 }
345
346 pub fn source_full(mut self, key: &PublicKey) -> MulticastBuilder<'a, state::NeedsCounter> {
348 self.source = Some(SourceValue::Full(*key));
349 self.with_state()
350 }
351}
352
353impl<'a> BlindUnicastBuilder<'a, state::NeedsSource> {
354 pub fn source_hint(mut self, hint: NodeHint) -> BlindUnicastBuilder<'a, state::NeedsCounter> {
356 self.source = Some(SourceValue::Hint(hint));
357 self.with_state()
358 }
359
360 pub fn source_full(mut self, key: &PublicKey) -> BlindUnicastBuilder<'a, state::NeedsCounter> {
362 self.source = Some(SourceValue::Full(*key));
363 self.with_state()
364 }
365}
366
367impl<'a> UnicastBuilder<'a, state::NeedsCounter> {
368 pub fn frame_counter(mut self, counter: u32) -> UnicastBuilder<'a, state::Configuring> {
370 self.frame_counter = Some(counter);
371 self.with_state()
372 }
373}
374
375impl<'a> MulticastBuilder<'a, state::NeedsCounter> {
376 pub fn frame_counter(mut self, counter: u32) -> MulticastBuilder<'a, state::Configuring> {
378 self.frame_counter = Some(counter);
379 self.with_state()
380 }
381}
382
383impl<'a> BlindUnicastBuilder<'a, state::NeedsCounter> {
384 pub fn frame_counter(mut self, counter: u32) -> BlindUnicastBuilder<'a, state::Configuring> {
386 self.frame_counter = Some(counter);
387 self.with_state()
388 }
389}
390
391macro_rules! impl_configuring_common {
392 ($name:ident<$state:ty>) => {
393 impl<'a> $name<'a, $state> {
394 pub fn flood_hops(mut self, remaining: u8) -> Self {
396 if let Some(value) = FloodHops::new(remaining, 0) {
397 self.flood_hops = Some(value);
398 }
399 self
400 }
401
402 pub fn region_code(mut self, code: [u8; 2]) -> Self {
404 self.push_option(OptionNumber::RegionCode.as_u16(), &code);
405 self
406 }
407
408 pub fn trace_route(mut self) -> Self {
410 self.push_option(OptionNumber::TraceRoute.as_u16(), &[]);
411 self
412 }
413
414 pub fn source_route(mut self, hops: &[crate::RouterHint]) -> Self {
416 let mut encoded = [0u8; 30];
417 let needed = hops.len() * 2;
418 if needed > encoded.len() {
419 self.option_error = Some(BuildError::BufferTooSmall);
420 return self;
421 }
422 for (index, hop) in hops.iter().enumerate() {
423 encoded[index * 2..index * 2 + 2].copy_from_slice(&hop.0);
424 }
425 self.push_option(OptionNumber::SourceRoute.as_u16(), &encoded[..needed]);
426 self
427 }
428
429 pub fn option(mut self, number: OptionNumber, value: &[u8]) -> Self {
431 self.push_option(number.as_u16(), value);
432 self
433 }
434 }
435 };
436}
437
438impl_configuring_common!(BroadcastBuilder<state::Configuring>);
439impl_configuring_common!(MacAckBuilder<state::Configuring>);
440impl_configuring_common!(UnicastBuilder<state::Configuring>);
441impl_configuring_common!(MulticastBuilder<state::Configuring>);
442impl_configuring_common!(BlindUnicastBuilder<state::Configuring>);
443
444impl<'a> UnicastBuilder<'a, state::Configuring> {
445 pub fn ack_requested(mut self) -> Self {
447 self.packet_type = PacketType::UnicastAckReq;
448 self
449 }
450
451 pub fn encrypted(mut self) -> Self {
453 self.encrypted = true;
454 self
455 }
456
457 pub fn mic_size(mut self, size: MicSize) -> Self {
459 self.mic_size = size;
460 self
461 }
462
463 pub fn salt(mut self, salt: u16) -> Self {
465 self.salt = Some(salt);
466 self
467 }
468
469 pub fn payload(mut self, data: &[u8]) -> UnicastBuilder<'a, state::Complete> {
471 self.stage_payload(data);
472 self.with_state()
473 }
474}
475
476impl<'a> MulticastBuilder<'a, state::Configuring> {
477 pub fn encrypted(mut self) -> Self {
479 self.encrypted = true;
480 self
481 }
482
483 pub fn mic_size(mut self, size: MicSize) -> Self {
485 self.mic_size = size;
486 self
487 }
488
489 pub fn salt(mut self, salt: u16) -> Self {
491 self.salt = Some(salt);
492 self
493 }
494
495 pub fn payload(mut self, data: &[u8]) -> MulticastBuilder<'a, state::Complete> {
497 self.stage_payload(data);
498 self.with_state()
499 }
500}
501
502impl<'a> BlindUnicastBuilder<'a, state::Configuring> {
503 pub fn ack_requested(mut self) -> Self {
505 self.packet_type = PacketType::BlindUnicastAckReq;
506 self
507 }
508
509 pub fn encrypted(mut self) -> Self {
511 self.encrypted = true;
512 self
513 }
514
515 pub fn unencrypted(mut self) -> Self {
521 self.encrypted = false;
522 self
523 }
524
525 pub fn mic_size(mut self, size: MicSize) -> Self {
527 self.mic_size = size;
528 self
529 }
530
531 pub fn salt(mut self, salt: u16) -> Self {
533 self.salt = Some(salt);
534 self
535 }
536
537 pub fn payload(mut self, data: &[u8]) -> BlindUnicastBuilder<'a, state::Complete> {
539 self.stage_payload(data);
540 self.with_state()
541 }
542}
543
544impl<'a> BroadcastBuilder<'a, state::Configuring> {
545 pub fn payload(mut self, data: &[u8]) -> BroadcastBuilder<'a, state::Complete> {
547 self.stage_payload(data);
548 self.with_state()
549 }
550
551 pub fn build(mut self) -> Result<&'a [u8], BuildError> {
553 let mut cursor = self.write_common_prefix()?;
554 self.write_source(&mut cursor)?;
555 if self.payload.is_some() {
556 let _ = self.copy_staged_payload(&mut cursor)?;
557 }
558 Ok(&self.buf[..cursor])
559 }
560}
561
562impl<'a> BroadcastBuilder<'a, state::Complete> {
563 pub fn build(self) -> Result<&'a [u8], BuildError> {
565 self.with_state::<state::Configuring>().build()
566 }
567}
568
569impl<'a> MacAckBuilder<'a, state::Configuring> {
570 pub fn build(mut self) -> Result<&'a [u8], BuildError> {
572 let mut cursor = self.write_common_prefix()?;
573 let dst = self.ack_dst.ok_or(BuildError::MissingDestination)?;
574 self.buf
575 .get_mut(cursor..cursor + 3)
576 .ok_or(BuildError::BufferTooSmall)?
577 .copy_from_slice(&dst.0);
578 cursor += 3;
579 let ack_tag = self.ack_tag.ok_or(BuildError::MissingAckTag)?;
580 self.buf
581 .get_mut(cursor..cursor + 8)
582 .ok_or(BuildError::BufferTooSmall)?
583 .copy_from_slice(&ack_tag);
584 cursor += 8;
585 Ok(&self.buf[..cursor])
586 }
587}
588
589impl<'a> UnicastBuilder<'a, state::Complete> {
590 pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
591 self.with_state::<state::Configuring>().build()
592 }
593}
594
595impl<'a> UnicastBuilder<'a, state::Configuring> {
596 pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
597 let mut cursor = self.write_common_prefix()?;
598 let dst = self.dst.ok_or(BuildError::MissingDestination)?;
599 self.buf
600 .get_mut(cursor..cursor + 3)
601 .ok_or(BuildError::BufferTooSmall)?
602 .copy_from_slice(&dst.0);
603 cursor += 3;
604 self.write_source(&mut cursor)?;
605 let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
606 let sec_info = SecInfo {
607 scf,
608 frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
609 salt: self.salt,
610 };
611 let sec_start = cursor;
612 cursor += sec_info.encode(
613 self.buf
614 .get_mut(cursor..)
615 .ok_or(BuildError::BufferTooSmall)?,
616 )?;
617 let body_range = self.copy_staged_payload(&mut cursor)?;
618 let mic_start = cursor;
619 let mic_end = mic_start + self.mic_size.byte_len();
620 self.buf
621 .get_mut(mic_start..mic_end)
622 .ok_or(BuildError::BufferTooSmall)?
623 .fill(0);
624 cursor = mic_end;
625 Ok(UnsealedPacket::new(
626 self.buf,
627 cursor,
628 body_range,
629 None,
630 mic_start..mic_end,
631 sec_start..sec_start + sec_info.wire_len(),
632 1..1 + self.options_len,
633 ))
634 }
635}
636
637impl<'a> MulticastBuilder<'a, state::Complete> {
638 pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
639 self.with_state::<state::Configuring>().build()
640 }
641}
642
643impl<'a> MulticastBuilder<'a, state::Configuring> {
644 pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
645 let mut cursor = self.write_common_prefix()?;
646 let channel = self.channel.ok_or(BuildError::MissingChannel)?;
647 self.buf
648 .get_mut(cursor..cursor + 2)
649 .ok_or(BuildError::BufferTooSmall)?
650 .copy_from_slice(&channel.0);
651 cursor += 2;
652 let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
653 let sec_info = SecInfo {
654 scf,
655 frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
656 salt: self.salt,
657 };
658 let sec_start = cursor;
659 cursor += sec_info.encode(
660 self.buf
661 .get_mut(cursor..)
662 .ok_or(BuildError::BufferTooSmall)?,
663 )?;
664 let body_start = cursor;
665 self.write_source(&mut cursor)?;
666 let payload_range = self.copy_staged_payload(&mut cursor)?;
667 let body_range = if self.encrypted {
668 body_start..payload_range.end
669 } else {
670 payload_range
671 };
672 let mic_start = cursor;
673 let mic_end = mic_start + self.mic_size.byte_len();
674 self.buf
675 .get_mut(mic_start..mic_end)
676 .ok_or(BuildError::BufferTooSmall)?
677 .fill(0);
678 cursor = mic_end;
679 Ok(UnsealedPacket::new(
680 self.buf,
681 cursor,
682 body_range,
683 None,
684 mic_start..mic_end,
685 sec_start..sec_start + sec_info.wire_len(),
686 1..1 + self.options_len,
687 ))
688 }
689}
690
691impl<'a> BlindUnicastBuilder<'a, state::Complete> {
692 pub fn build(self) -> Result<UnsealedPacket<'a>, BuildError> {
693 self.with_state::<state::Configuring>().build()
694 }
695}
696
697impl<'a> BlindUnicastBuilder<'a, state::Configuring> {
698 pub fn build(mut self) -> Result<UnsealedPacket<'a>, BuildError> {
699 let mut cursor = self.write_common_prefix()?;
700 let channel = self.channel.ok_or(BuildError::MissingChannel)?;
701 self.buf
702 .get_mut(cursor..cursor + 2)
703 .ok_or(BuildError::BufferTooSmall)?
704 .copy_from_slice(&channel.0);
705 cursor += 2;
706 let scf = Scf::new(self.encrypted, self.mic_size, self.salt.is_some());
707 let sec_info = SecInfo {
708 scf,
709 frame_counter: self.frame_counter.ok_or(BuildError::MissingFrameCounter)?,
710 salt: self.salt,
711 };
712 let sec_start = cursor;
713 cursor += sec_info.encode(
714 self.buf
715 .get_mut(cursor..)
716 .ok_or(BuildError::BufferTooSmall)?,
717 )?;
718 let blind_addr_range = self.stage_blind_addr(&mut cursor)?;
719 let body_range = self.copy_staged_payload(&mut cursor)?;
720 let mic_start = cursor;
721 let mic_end = mic_start + self.mic_size.byte_len();
722 self.buf
723 .get_mut(mic_start..mic_end)
724 .ok_or(BuildError::BufferTooSmall)?
725 .fill(0);
726 cursor = mic_end;
727 Ok(UnsealedPacket::new(
728 self.buf,
729 cursor,
730 body_range,
731 Some(blind_addr_range),
732 mic_start..mic_end,
733 sec_start..sec_start + sec_info.wire_len(),
734 1..1 + self.options_len,
735 ))
736 }
737}