#![allow(missing_docs)]
use super::ParseError;
pub const PAYLOAD_HEADER_LEN: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PayloadKind {
None,
SecurityAssociation, KeyExchange, IdentificationInitiator, IdentificationResponder, Certificate, CertificateRequest, Authentication, Nonce, Notify, Delete, VendorId, TrafficSelectorInitiator, TrafficSelectorResponder, Encrypted, Configuration, EapPayload, EncryptedFragment, Other(u8),
}
impl PayloadKind {
pub fn from_u8(v: u8) -> Self {
match v {
0 => Self::None,
33 => Self::SecurityAssociation,
34 => Self::KeyExchange,
35 => Self::IdentificationInitiator,
36 => Self::IdentificationResponder,
37 => Self::Certificate,
38 => Self::CertificateRequest,
39 => Self::Authentication,
40 => Self::Nonce,
41 => Self::Notify,
42 => Self::Delete,
43 => Self::VendorId,
44 => Self::TrafficSelectorInitiator,
45 => Self::TrafficSelectorResponder,
46 => Self::Encrypted,
47 => Self::Configuration,
48 => Self::EapPayload,
53 => Self::EncryptedFragment,
other => Self::Other(other),
}
}
pub fn as_u8(self) -> u8 {
match self {
Self::None => 0,
Self::SecurityAssociation => 33,
Self::KeyExchange => 34,
Self::IdentificationInitiator => 35,
Self::IdentificationResponder => 36,
Self::Certificate => 37,
Self::CertificateRequest => 38,
Self::Authentication => 39,
Self::Nonce => 40,
Self::Notify => 41,
Self::Delete => 42,
Self::VendorId => 43,
Self::TrafficSelectorInitiator => 44,
Self::TrafficSelectorResponder => 45,
Self::Encrypted => 46,
Self::Configuration => 47,
Self::EapPayload => 48,
Self::EncryptedFragment => 53,
Self::Other(v) => v,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PayloadHeader {
pub next_payload: PayloadKind,
pub critical: bool,
pub length: u16,
}
impl PayloadHeader {
pub fn parse(bytes: &[u8]) -> Result<Self, ParseError> {
if bytes.len() < PAYLOAD_HEADER_LEN {
return Err(ParseError::Truncated {
what: "payload header",
need: PAYLOAD_HEADER_LEN,
got: bytes.len(),
});
}
Ok(Self {
next_payload: PayloadKind::from_u8(bytes[0]),
critical: bytes[1] & 0b1000_0000 != 0,
length: u16::from_be_bytes([bytes[2], bytes[3]]),
})
}
}
#[derive(Debug, Clone)]
pub struct RawPayload<'a> {
pub kind: PayloadKind,
pub header: PayloadHeader,
pub body: &'a [u8],
}
#[derive(Debug, Clone)]
pub enum Payload<'a> {
Raw(RawPayload<'a>),
}
pub fn walk_chain<'a>(
first_kind: PayloadKind,
mut bytes: &'a [u8],
) -> Result<Vec<RawPayload<'a>>, ParseError> {
let mut out = Vec::new();
let mut kind = first_kind;
while kind != PayloadKind::None {
let header = PayloadHeader::parse(bytes)?;
let total = header.length as usize;
if total < PAYLOAD_HEADER_LEN {
return Err(ParseError::BadLength {
what: "payload",
value: total,
});
}
if bytes.len() < total {
return Err(ParseError::Truncated {
what: "payload body",
need: total,
got: bytes.len(),
});
}
let body = &bytes[PAYLOAD_HEADER_LEN..total];
out.push(RawPayload { kind, header, body });
kind = header.next_payload;
bytes = &bytes[total..];
if matches!(
out.last().unwrap().kind,
PayloadKind::Encrypted | PayloadKind::EncryptedFragment
) {
break;
}
}
Ok(out)
}