use crate::error::PfcpError;
use crate::ie::IeType;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum CauseValue {
Reserved = 0,
RequestAccepted = 1,
MoreUsageReportToSend = 2,
RequestPartiallyAccepted = 3,
RequestRejected = 64,
SessionContextNotFound = 65,
MandatoryIeMissing = 66,
ConditionalIeMissing = 67,
InvalidLength = 68,
MandatoryIeIncorrect = 69,
InvalidForwardingPolicy = 70,
InvalidFteidAllocationOption = 71,
NoEstablishedPfcpAssociation = 72,
RuleCreationModificationFailure = 73,
PfcpEntityInCongestion = 74,
NoResourcesAvailable = 75,
ServiceNotSupported = 76,
SystemFailure = 77,
RedirectionRequested = 78,
AllDynamicAddressesOccupied = 79,
UnknownPredefinedRule = 80,
UnknownApplicationId = 81,
L2tpTunnelEstablishmentFailure = 82,
L2tpSessionEstablishmentFailure = 83,
L2tpTunnelRelease = 84,
L2tpSessionRelease = 85,
PfcpSessionRestorationFailure = 86,
L2tpTunnelEstablishmentFailureTunnelAuthFailure = 87,
L2tpSessionEstablishmentFailureSessionAuthFailure = 88,
L2tpTunnelEstablishmentFailureLnsNotReachable = 89,
Unknown,
}
impl From<u8> for CauseValue {
fn from(v: u8) -> Self {
match v {
0 => CauseValue::Reserved,
1 => CauseValue::RequestAccepted,
2 => CauseValue::MoreUsageReportToSend,
3 => CauseValue::RequestPartiallyAccepted,
64 => CauseValue::RequestRejected,
65 => CauseValue::SessionContextNotFound,
66 => CauseValue::MandatoryIeMissing,
67 => CauseValue::ConditionalIeMissing,
68 => CauseValue::InvalidLength,
69 => CauseValue::MandatoryIeIncorrect,
70 => CauseValue::InvalidForwardingPolicy,
71 => CauseValue::InvalidFteidAllocationOption,
72 => CauseValue::NoEstablishedPfcpAssociation,
73 => CauseValue::RuleCreationModificationFailure,
74 => CauseValue::PfcpEntityInCongestion,
75 => CauseValue::NoResourcesAvailable,
76 => CauseValue::ServiceNotSupported,
77 => CauseValue::SystemFailure,
78 => CauseValue::RedirectionRequested,
79 => CauseValue::AllDynamicAddressesOccupied,
80 => CauseValue::UnknownPredefinedRule,
81 => CauseValue::UnknownApplicationId,
82 => CauseValue::L2tpTunnelEstablishmentFailure,
83 => CauseValue::L2tpSessionEstablishmentFailure,
84 => CauseValue::L2tpTunnelRelease,
85 => CauseValue::L2tpSessionRelease,
86 => CauseValue::PfcpSessionRestorationFailure,
87 => CauseValue::L2tpTunnelEstablishmentFailureTunnelAuthFailure,
88 => CauseValue::L2tpSessionEstablishmentFailureSessionAuthFailure,
89 => CauseValue::L2tpTunnelEstablishmentFailureLnsNotReachable,
_ => CauseValue::Unknown,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Cause {
pub value: CauseValue,
}
impl Cause {
pub fn new(value: CauseValue) -> Self {
Cause { value }
}
pub fn marshal(&self) -> [u8; 1] {
[self.value as u8]
}
pub fn unmarshal(data: &[u8]) -> Result<Self, PfcpError> {
if data.is_empty() {
return Err(PfcpError::invalid_length("Cause", IeType::Cause, 1, 0));
}
Ok(Cause {
value: CauseValue::from(data[0]),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cause_marshal_unmarshal() {
let cause = Cause::new(CauseValue::RequestAccepted);
let marshaled = cause.marshal();
assert_eq!(marshaled, [1]);
let unmarshaled = Cause::unmarshal(&marshaled).unwrap();
assert_eq!(unmarshaled, cause);
}
#[test]
fn test_cause_unmarshal_invalid_data() {
let data = [];
let result = Cause::unmarshal(&data);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(matches!(err, PfcpError::InvalidLength { .. }));
assert!(err.to_string().contains("Cause"));
assert!(err.to_string().contains("1"));
assert!(err.to_string().contains("0"));
}
#[test]
fn test_cause_value_from_u8() {
assert_eq!(CauseValue::from(1), CauseValue::RequestAccepted);
assert_eq!(CauseValue::from(2), CauseValue::MoreUsageReportToSend);
assert_eq!(CauseValue::from(3), CauseValue::RequestPartiallyAccepted);
assert_eq!(CauseValue::from(64), CauseValue::RequestRejected);
assert_eq!(CauseValue::from(65), CauseValue::SessionContextNotFound);
assert_eq!(CauseValue::from(66), CauseValue::MandatoryIeMissing);
assert_eq!(CauseValue::from(78), CauseValue::RedirectionRequested);
assert_eq!(
CauseValue::from(89),
CauseValue::L2tpTunnelEstablishmentFailureLnsNotReachable
);
assert_eq!(CauseValue::from(4), CauseValue::Unknown); assert_eq!(CauseValue::from(63), CauseValue::Unknown); assert_eq!(CauseValue::from(90), CauseValue::Unknown); assert_eq!(CauseValue::from(255), CauseValue::Unknown); }
#[test]
fn test_cause_reserved_value() {
let cause = Cause::new(CauseValue::Reserved);
let marshaled = cause.marshal();
assert_eq!(marshaled, [0]);
let unmarshaled = Cause::unmarshal(&marshaled).unwrap();
assert_eq!(unmarshaled.value, CauseValue::Reserved);
}
#[test]
fn test_cause_rejection_values() {
let cause = Cause::new(CauseValue::RequestRejected);
let marshaled = cause.marshal();
assert_eq!(marshaled, [64]);
let cause = Cause::new(CauseValue::SessionContextNotFound);
let marshaled = cause.marshal();
assert_eq!(marshaled, [65]);
}
}