use crate::error::PfcpError;
use crate::message::MsgType;
use crate::types::{Seid, SequenceNumber};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Header {
pub version: u8,
pub has_fo: bool, pub has_mp: bool, pub has_seid: bool,
pub message_type: MsgType,
pub length: u16,
pub seid: Seid,
pub sequence_number: SequenceNumber,
pub message_priority: u8,
pub(crate) raw_message_type: u8,
}
impl Header {
pub fn new(
message_type: MsgType,
has_seid: bool,
seid: impl Into<Seid>,
sequence_number: impl Into<SequenceNumber>,
) -> Self {
Header {
version: 1,
has_fo: false,
has_mp: false,
has_seid,
message_type,
length: 0, seid: seid.into(),
sequence_number: sequence_number.into(),
message_priority: 0,
raw_message_type: message_type as u8,
}
}
pub fn new_unknown(
raw_message_type: u8,
has_seid: bool,
seid: impl Into<Seid>,
sequence_number: impl Into<SequenceNumber>,
) -> Result<Self, PfcpError> {
if MsgType::from(raw_message_type) != MsgType::Unknown {
return Err(PfcpError::invalid_value(
"PFCP message type",
raw_message_type.to_string(),
"must be a message type unknown to this crate",
));
}
let mut header = Self::new(MsgType::Unknown, has_seid, seid, sequence_number);
header.raw_message_type = raw_message_type;
Ok(header)
}
pub fn message_type_code(&self) -> u8 {
if self.message_type == MsgType::Unknown {
self.raw_message_type
} else {
self.message_type as u8
}
}
pub fn len(&self) -> u16 {
let mut length = 8;
if self.has_seid {
length += 8;
}
length
}
pub fn is_empty(&self) -> bool {
self.length == 0
}
pub fn marshal(&self) -> Vec<u8> {
let mut data = vec![0; self.len() as usize];
self.marshal_to(&mut data);
data
}
pub fn marshal_into(&self, buf: &mut Vec<u8>) {
let start = buf.len();
buf.resize(start + self.len() as usize, 0);
self.marshal_to(&mut buf[start..]);
}
pub fn marshal_to(&self, b: &mut [u8]) {
let flags = (self.version << 5)
| ((self.has_fo as u8) << 2)
| ((self.has_mp as u8) << 1)
| (self.has_seid as u8);
b[0] = flags;
b[1] = self.message_type_code();
b[2..4].copy_from_slice(&self.length.to_be_bytes());
let mut offset = 4;
if self.has_seid {
b[offset..offset + 8].copy_from_slice(&self.seid.0.to_be_bytes());
offset += 8;
}
let seq_bytes = self.sequence_number.0.to_be_bytes();
b[offset..offset + 3].copy_from_slice(&seq_bytes[1..]);
b[offset + 3] = self.message_priority;
}
pub fn unmarshal(b: &[u8]) -> Result<Self, PfcpError> {
if b.len() < 8 {
return Err(PfcpError::MessageParseError {
message_type: None,
reason: format!(
"Header too short (expected at least 8 bytes, got {})",
b.len()
),
});
}
let flags = b[0];
let version = flags >> 5;
let has_fo = (flags & 0x04) >> 2 == 1;
let has_mp = (flags & 0x02) >> 1 == 1;
let has_seid = (flags & 0x01) == 1;
let raw_message_type = b[1];
let message_type = MsgType::from(raw_message_type);
let length = u16::from_be_bytes([b[2], b[3]]);
let mut offset = 4;
let seid = if has_seid {
if b.len() < offset + 8 {
return Err(PfcpError::MessageParseError {
message_type: Some(message_type),
reason: format!(
"Header with SEID flag set but too short (expected at least {} bytes, got {})",
offset + 8,
b.len()
),
});
}
offset += 8;
u64::from_be_bytes([
b[offset - 8],
b[offset - 7],
b[offset - 6],
b[offset - 5],
b[offset - 4],
b[offset - 3],
b[offset - 2],
b[offset - 1],
])
} else {
0
};
if b.len() < offset + 4 {
return Err(PfcpError::MessageParseError {
message_type: Some(message_type),
reason: format!(
"Header sequence number part too short (expected at least {} bytes, got {})",
offset + 4,
b.len()
),
});
}
let sequence_number = SequenceNumber::new(u32::from_be_bytes([
0,
b[offset],
b[offset + 1],
b[offset + 2],
]));
let message_priority = b[offset + 3];
Ok(Header {
version,
has_fo,
has_mp,
has_seid,
message_type,
length,
seid: Seid(seid),
sequence_number,
message_priority,
raw_message_type,
})
}
}