use crate::error::PfcpError;
use crate::ie::{Ie, IeType};
use crate::message::{header::Header, Message, MsgType};
use crate::types::{Seid, SequenceNumber};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionEstablishmentRequest {
pub header: Header,
pub node_id: Ie, pub fseid: Ie, pub create_pdrs: Vec<Ie>, pub create_fars: Vec<Ie>, pub create_urrs: Vec<Ie>, pub create_qers: Vec<Ie>, pub create_bars: Vec<Ie>, pub create_traffic_endpoints: Vec<Ie>, pub pdn_type: Option<Ie>, pub fq_csids: Vec<Ie>, pub user_plane_inactivity_timer: Option<Ie>, pub user_id: Option<Ie>, pub trace_information: Option<Ie>, pub apn_dnn: Option<Ie>, pub create_mars: Vec<Ie>, pub pfcpsm_req_flags: Option<Ie>, pub create_bridge_info_for_tsc: Option<Ie>, pub create_srrs: Vec<Ie>, pub provide_atsss_control_information: Option<Ie>, pub recovery_time_stamp: Option<Ie>, pub s_nssai: Option<Ie>, pub hplmn_s_nssai: Option<Ie>, pub provide_rds_configuration_information: Option<Ie>, pub rat_type: Option<Ie>, pub l2tp_tunnel_informations: Vec<Ie>, pub l2tp_session_information: Option<Ie>, pub group_id: Option<Ie>, pub mbs_session_n4mb_control_information: Option<Ie>, pub mbs_session_n4_control_information: Vec<Ie>, pub dscp_to_ppi_control_information: Option<Ie>, pub tl_containers: Vec<Ie>, pub ue_level_measurements_configuration: Option<Ie>, pub cp_function_features: Option<Ie>, pub ethernet_pdu_session_information: Option<Ie>, pub ies: Vec<Ie>,
}
impl Message for SessionEstablishmentRequest {
fn marshal(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(self.marshaled_size());
self.marshal_into(&mut buf);
buf
}
fn marshal_into(&self, buf: &mut Vec<u8>) {
buf.reserve(self.marshaled_size());
self.header.marshal_into(buf);
self.node_id.marshal_into(buf);
self.fseid.marshal_into(buf);
for ie in &self.create_pdrs {
ie.marshal_into(buf);
}
for ie in &self.create_fars {
ie.marshal_into(buf);
}
for ie in &self.create_urrs {
ie.marshal_into(buf);
}
for ie in &self.create_qers {
ie.marshal_into(buf);
}
for ie in &self.create_bars {
ie.marshal_into(buf);
}
for ie in &self.create_traffic_endpoints {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.pdn_type {
ie.marshal_into(buf);
}
for ie in &self.fq_csids {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.user_id {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.s_nssai {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.trace_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.recovery_time_stamp {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.cp_function_features {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.apn_dnn {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.user_plane_inactivity_timer {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.pfcpsm_req_flags {
ie.marshal_into(buf);
}
for ie in &self.create_mars {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.create_bridge_info_for_tsc {
ie.marshal_into(buf);
}
for ie in &self.create_srrs {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.provide_atsss_control_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.hplmn_s_nssai {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.ethernet_pdu_session_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.rat_type {
ie.marshal_into(buf);
}
for ie in &self.l2tp_tunnel_informations {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.l2tp_session_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.provide_rds_configuration_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.group_id {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.mbs_session_n4mb_control_information {
ie.marshal_into(buf);
}
for ie in &self.mbs_session_n4_control_information {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.dscp_to_ppi_control_information {
ie.marshal_into(buf);
}
for ie in &self.tl_containers {
ie.marshal_into(buf);
}
if let Some(ref ie) = self.ue_level_measurements_configuration {
ie.marshal_into(buf);
}
for ie in &self.ies {
ie.marshal_into(buf);
}
}
fn marshaled_size(&self) -> usize {
let mut size = self.header.len() as usize;
size += self.node_id.len() as usize;
size += self.fseid.len() as usize;
for ie in &self.create_pdrs {
size += ie.len() as usize;
}
for ie in &self.create_fars {
size += ie.len() as usize;
}
for ie in &self.create_urrs {
size += ie.len() as usize;
}
for ie in &self.create_qers {
size += ie.len() as usize;
}
for ie in &self.create_bars {
size += ie.len() as usize;
}
for ie in &self.create_traffic_endpoints {
size += ie.len() as usize;
}
if let Some(ref ie) = self.pdn_type {
size += ie.len() as usize;
}
for ie in &self.fq_csids {
size += ie.len() as usize;
}
if let Some(ref ie) = self.user_id {
size += ie.len() as usize;
}
if let Some(ref ie) = self.s_nssai {
size += ie.len() as usize;
}
if let Some(ref ie) = self.trace_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.recovery_time_stamp {
size += ie.len() as usize;
}
if let Some(ref ie) = self.cp_function_features {
size += ie.len() as usize;
}
if let Some(ref ie) = self.apn_dnn {
size += ie.len() as usize;
}
if let Some(ref ie) = self.user_plane_inactivity_timer {
size += ie.len() as usize;
}
if let Some(ref ie) = self.pfcpsm_req_flags {
size += ie.len() as usize;
}
for ie in &self.create_mars {
size += ie.len() as usize;
}
if let Some(ref ie) = self.create_bridge_info_for_tsc {
size += ie.len() as usize;
}
for ie in &self.create_srrs {
size += ie.len() as usize;
}
if let Some(ref ie) = self.provide_atsss_control_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.hplmn_s_nssai {
size += ie.len() as usize;
}
if let Some(ref ie) = self.ethernet_pdu_session_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.rat_type {
size += ie.len() as usize;
}
for ie in &self.l2tp_tunnel_informations {
size += ie.len() as usize;
}
if let Some(ref ie) = self.l2tp_session_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.provide_rds_configuration_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.group_id {
size += ie.len() as usize;
}
if let Some(ref ie) = self.mbs_session_n4mb_control_information {
size += ie.len() as usize;
}
for ie in &self.mbs_session_n4_control_information {
size += ie.len() as usize;
}
if let Some(ref ie) = self.dscp_to_ppi_control_information {
size += ie.len() as usize;
}
for ie in &self.tl_containers {
size += ie.len() as usize;
}
if let Some(ref ie) = self.ue_level_measurements_configuration {
size += ie.len() as usize;
}
for ie in &self.ies {
size += ie.len() as usize;
}
size
}
fn unmarshal(data: &[u8]) -> Result<Self, PfcpError> {
let header = Header::unmarshal(data)?;
let mut node_id = None;
let mut fseid = None;
let mut create_pdrs = Vec::new();
let mut create_fars = Vec::new();
let mut create_urrs = Vec::new();
let mut create_qers = Vec::new();
let mut create_bars = Vec::new();
let mut create_traffic_endpoints = Vec::new();
let mut pdn_type = None;
let mut fq_csids = Vec::new();
let mut user_id = None;
let mut s_nssai = None;
let mut trace_information = None;
let mut recovery_time_stamp = None;
let mut cp_function_features = None;
let mut apn_dnn = None;
let mut user_plane_inactivity_timer = None;
let mut pfcpsm_req_flags = None;
let mut create_mars = Vec::new();
let mut create_bridge_info_for_tsc = None;
let mut create_srrs = Vec::new();
let mut provide_atsss_control_information = None;
let mut hplmn_s_nssai = None;
let mut ethernet_pdu_session_information = None;
let mut rat_type = None;
let mut l2tp_tunnel_informations = Vec::new();
let mut l2tp_session_information = None;
let mut provide_rds_configuration_information = None;
let mut group_id = None;
let mut mbs_session_n4mb_control_information = None;
let mut mbs_session_n4_control_information = Vec::new();
let mut dscp_to_ppi_control_information = None;
let mut tl_containers = Vec::new();
let mut ue_level_measurements_configuration = None;
let mut ies = Vec::new();
let mut offset = header.len() as usize;
while offset < data.len() {
let ie = Ie::unmarshal(&data[offset..])?;
let ie_len = ie.len() as usize;
match ie.ie_type {
IeType::NodeId => node_id = Some(ie),
IeType::Fseid => fseid = Some(ie),
IeType::CreatePdr => create_pdrs.push(ie),
IeType::CreateFar => create_fars.push(ie),
IeType::CreateUrr => create_urrs.push(ie),
IeType::CreateQer => create_qers.push(ie),
IeType::CreateBar => create_bars.push(ie),
IeType::CreateTrafficEndpoint => create_traffic_endpoints.push(ie),
IeType::PdnType => pdn_type = Some(ie),
IeType::FqCsid => fq_csids.push(ie),
IeType::UserId => user_id = Some(ie),
IeType::Snssai => s_nssai = Some(ie),
IeType::TraceInformation => trace_information = Some(ie),
IeType::RecoveryTimeStamp => recovery_time_stamp = Some(ie),
IeType::CpFunctionFeatures => cp_function_features = Some(ie),
IeType::ApnDnn => apn_dnn = Some(ie),
IeType::UserPlaneInactivityTimer => user_plane_inactivity_timer = Some(ie),
IeType::PfcpsmReqFlags => pfcpsm_req_flags = Some(ie),
IeType::CreateMar => create_mars.push(ie),
IeType::CreateBridgeInfoForTsc => create_bridge_info_for_tsc = Some(ie),
IeType::CreateSrr => create_srrs.push(ie),
IeType::ProvideAtsssControlInformation => {
provide_atsss_control_information = Some(ie)
}
IeType::HplmnSNssai => hplmn_s_nssai = Some(ie),
IeType::EthernetPduSessionInformation => {
ethernet_pdu_session_information = Some(ie)
}
IeType::RatType => rat_type = Some(ie),
IeType::L2tpTunnelInformation => l2tp_tunnel_informations.push(ie),
IeType::L2tpSessionInformation => l2tp_session_information = Some(ie),
IeType::ProvideRdsConfigurationInformation => {
provide_rds_configuration_information = Some(ie)
}
IeType::GroupId => group_id = Some(ie),
IeType::MbsSessionN4mbControlInformation => {
mbs_session_n4mb_control_information = Some(ie)
}
IeType::MbsSessionN4ControlInformation => {
mbs_session_n4_control_information.push(ie)
}
IeType::DscpToPpiControlInformation => dscp_to_ppi_control_information = Some(ie),
IeType::TlContainer => tl_containers.push(ie),
IeType::UeLevelMeasurementsConfiguration => {
ue_level_measurements_configuration = Some(ie)
}
_ => ies.push(ie),
}
offset += ie_len;
}
if create_pdrs.is_empty() {
return Err(PfcpError::MissingMandatoryIe {
ie_type: IeType::CreatePdr,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
});
}
if create_fars.is_empty() {
return Err(PfcpError::MissingMandatoryIe {
ie_type: IeType::CreateFar,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
});
}
Ok(SessionEstablishmentRequest {
header,
node_id: node_id.ok_or(PfcpError::MissingMandatoryIe {
ie_type: IeType::NodeId,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
})?,
fseid: fseid.ok_or(PfcpError::MissingMandatoryIe {
ie_type: IeType::Fseid,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
})?,
create_pdrs,
create_fars,
create_urrs,
create_qers,
create_bars,
create_traffic_endpoints,
pdn_type,
fq_csids,
user_id,
s_nssai,
trace_information,
recovery_time_stamp,
cp_function_features,
apn_dnn,
user_plane_inactivity_timer,
pfcpsm_req_flags,
create_mars,
create_bridge_info_for_tsc,
create_srrs,
provide_atsss_control_information,
hplmn_s_nssai,
ethernet_pdu_session_information,
rat_type,
l2tp_tunnel_informations,
l2tp_session_information,
provide_rds_configuration_information,
group_id,
mbs_session_n4mb_control_information,
mbs_session_n4_control_information,
dscp_to_ppi_control_information,
tl_containers,
ue_level_measurements_configuration,
ies,
})
}
fn msg_type(&self) -> MsgType {
MsgType::SessionEstablishmentRequest
}
fn seid(&self) -> Option<Seid> {
if self.header.has_seid {
Some(self.header.seid)
} else {
None
}
}
fn sequence(&self) -> SequenceNumber {
self.header.sequence_number
}
fn set_sequence(&mut self, seq: SequenceNumber) {
self.header.sequence_number = seq;
}
fn ies(&self, ie_type: IeType) -> crate::message::IeIter<'_> {
use crate::message::IeIter;
match ie_type {
IeType::NodeId => IeIter::single(Some(&self.node_id), ie_type),
IeType::Fseid => IeIter::single(Some(&self.fseid), ie_type),
IeType::CreatePdr => IeIter::multiple(&self.create_pdrs, ie_type),
IeType::CreateFar => IeIter::multiple(&self.create_fars, ie_type),
IeType::CreateUrr => IeIter::multiple(&self.create_urrs, ie_type),
IeType::CreateQer => IeIter::multiple(&self.create_qers, ie_type),
IeType::CreateBar => IeIter::multiple(&self.create_bars, ie_type),
IeType::CreateTrafficEndpoint => {
IeIter::multiple(&self.create_traffic_endpoints, ie_type)
}
IeType::PdnType => IeIter::single(self.pdn_type.as_ref(), ie_type),
IeType::FqCsid => IeIter::multiple(&self.fq_csids, ie_type),
IeType::UserPlaneInactivityTimer => {
IeIter::single(self.user_plane_inactivity_timer.as_ref(), ie_type)
}
IeType::UserId => IeIter::single(self.user_id.as_ref(), ie_type),
IeType::TraceInformation => IeIter::single(self.trace_information.as_ref(), ie_type),
IeType::ApnDnn => IeIter::single(self.apn_dnn.as_ref(), ie_type),
IeType::PfcpsmReqFlags => IeIter::single(self.pfcpsm_req_flags.as_ref(), ie_type),
IeType::CreateMar => IeIter::multiple(&self.create_mars, ie_type),
IeType::RecoveryTimeStamp => IeIter::single(self.recovery_time_stamp.as_ref(), ie_type),
IeType::Snssai => IeIter::single(self.s_nssai.as_ref(), ie_type),
IeType::CpFunctionFeatures => {
IeIter::single(self.cp_function_features.as_ref(), ie_type)
}
IeType::CreateBridgeInfoForTsc => {
IeIter::single(self.create_bridge_info_for_tsc.as_ref(), ie_type)
}
IeType::CreateSrr => IeIter::multiple(&self.create_srrs, ie_type),
IeType::ProvideAtsssControlInformation => {
IeIter::single(self.provide_atsss_control_information.as_ref(), ie_type)
}
IeType::HplmnSNssai => IeIter::single(self.hplmn_s_nssai.as_ref(), ie_type),
IeType::EthernetPduSessionInformation => {
IeIter::single(self.ethernet_pdu_session_information.as_ref(), ie_type)
}
IeType::RatType => IeIter::single(self.rat_type.as_ref(), ie_type),
IeType::L2tpTunnelInformation => {
IeIter::multiple(&self.l2tp_tunnel_informations, ie_type)
}
IeType::L2tpSessionInformation => {
IeIter::single(self.l2tp_session_information.as_ref(), ie_type)
}
IeType::ProvideRdsConfigurationInformation => {
IeIter::single(self.provide_rds_configuration_information.as_ref(), ie_type)
}
IeType::GroupId => IeIter::single(self.group_id.as_ref(), ie_type),
IeType::MbsSessionN4mbControlInformation => {
IeIter::single(self.mbs_session_n4mb_control_information.as_ref(), ie_type)
}
IeType::MbsSessionN4ControlInformation => {
IeIter::multiple(&self.mbs_session_n4_control_information, ie_type)
}
IeType::DscpToPpiControlInformation => {
IeIter::single(self.dscp_to_ppi_control_information.as_ref(), ie_type)
}
IeType::TlContainer => IeIter::multiple(&self.tl_containers, ie_type),
IeType::UeLevelMeasurementsConfiguration => {
IeIter::single(self.ue_level_measurements_configuration.as_ref(), ie_type)
}
_ => IeIter::generic(&self.ies, ie_type),
}
}
fn all_ies(&self) -> Vec<&Ie> {
let mut result = vec![&self.node_id, &self.fseid];
result.extend(self.create_pdrs.iter());
result.extend(self.create_fars.iter());
result.extend(self.create_urrs.iter());
result.extend(self.create_qers.iter());
result.extend(self.create_bars.iter());
result.extend(self.create_traffic_endpoints.iter());
if let Some(ref ie) = self.pdn_type {
result.push(ie);
}
result.extend(self.fq_csids.iter());
if let Some(ref ie) = self.user_id {
result.push(ie);
}
if let Some(ref ie) = self.s_nssai {
result.push(ie);
}
if let Some(ref ie) = self.trace_information {
result.push(ie);
}
if let Some(ref ie) = self.recovery_time_stamp {
result.push(ie);
}
if let Some(ref ie) = self.cp_function_features {
result.push(ie);
}
if let Some(ref ie) = self.apn_dnn {
result.push(ie);
}
if let Some(ref ie) = self.user_plane_inactivity_timer {
result.push(ie);
}
if let Some(ref ie) = self.pfcpsm_req_flags {
result.push(ie);
}
result.extend(self.create_mars.iter());
if let Some(ref ie) = self.create_bridge_info_for_tsc {
result.push(ie);
}
result.extend(self.create_srrs.iter());
if let Some(ref ie) = self.provide_atsss_control_information {
result.push(ie);
}
if let Some(ref ie) = self.hplmn_s_nssai {
result.push(ie);
}
if let Some(ref ie) = self.ethernet_pdu_session_information {
result.push(ie);
}
if let Some(ref ie) = self.rat_type {
result.push(ie);
}
result.extend(self.l2tp_tunnel_informations.iter());
if let Some(ref ie) = self.l2tp_session_information {
result.push(ie);
}
if let Some(ref ie) = self.provide_rds_configuration_information {
result.push(ie);
}
if let Some(ref ie) = self.group_id {
result.push(ie);
}
if let Some(ref ie) = self.mbs_session_n4mb_control_information {
result.push(ie);
}
result.extend(self.mbs_session_n4_control_information.iter());
if let Some(ref ie) = self.dscp_to_ppi_control_information {
result.push(ie);
}
result.extend(self.tl_containers.iter());
if let Some(ref ie) = self.ue_level_measurements_configuration {
result.push(ie);
}
result.extend(self.ies.iter());
result
}
}
#[derive(Debug, Default)]
pub struct SessionEstablishmentRequestBuilder {
seid: Seid,
seq: SequenceNumber,
node_id: Option<Ie>,
fseid: Option<Ie>,
create_pdrs: Vec<Ie>,
create_fars: Vec<Ie>,
create_urrs: Vec<Ie>,
create_qers: Vec<Ie>,
create_bars: Vec<Ie>,
create_traffic_endpoints: Vec<Ie>,
pdn_type: Option<Ie>,
fq_csids: Vec<Ie>,
user_id: Option<Ie>,
s_nssai: Option<Ie>,
trace_information: Option<Ie>,
recovery_time_stamp: Option<Ie>,
cp_function_features: Option<Ie>,
apn_dnn: Option<Ie>,
user_plane_inactivity_timer: Option<Ie>,
pfcpsm_req_flags: Option<Ie>,
create_mars: Vec<Ie>,
create_bridge_info_for_tsc: Option<Ie>,
create_srrs: Vec<Ie>,
provide_atsss_control_information: Option<Ie>,
hplmn_s_nssai: Option<Ie>,
ethernet_pdu_session_information: Option<Ie>,
rat_type: Option<Ie>,
l2tp_tunnel_informations: Vec<Ie>,
l2tp_session_information: Option<Ie>,
provide_rds_configuration_information: Option<Ie>,
group_id: Option<Ie>,
mbs_session_n4mb_control_information: Option<Ie>,
mbs_session_n4_control_information: Vec<Ie>,
dscp_to_ppi_control_information: Option<Ie>,
tl_containers: Vec<Ie>,
ue_level_measurements_configuration: Option<Ie>,
ies: Vec<Ie>,
}
impl SessionEstablishmentRequestBuilder {
pub fn new(seid: impl Into<Seid>, seq: impl Into<SequenceNumber>) -> Self {
SessionEstablishmentRequestBuilder {
seid: seid.into(),
seq: seq.into(),
node_id: None,
fseid: None,
create_pdrs: Vec::new(),
create_fars: Vec::new(),
create_urrs: Vec::new(),
create_qers: Vec::new(),
create_bars: Vec::new(),
create_traffic_endpoints: Vec::new(),
pdn_type: None,
fq_csids: Vec::new(),
user_id: None,
s_nssai: None,
trace_information: None,
recovery_time_stamp: None,
cp_function_features: None,
apn_dnn: None,
user_plane_inactivity_timer: None,
pfcpsm_req_flags: None,
create_mars: Vec::new(),
create_bridge_info_for_tsc: None,
create_srrs: Vec::new(),
provide_atsss_control_information: None,
hplmn_s_nssai: None,
ethernet_pdu_session_information: None,
rat_type: None,
l2tp_tunnel_informations: Vec::new(),
l2tp_session_information: None,
provide_rds_configuration_information: None,
group_id: None,
mbs_session_n4mb_control_information: None,
mbs_session_n4_control_information: Vec::new(),
dscp_to_ppi_control_information: None,
tl_containers: Vec::new(),
ue_level_measurements_configuration: None,
ies: Vec::new(),
}
}
pub fn node_id<T>(mut self, node_id: T) -> Self
where
T: Into<std::net::IpAddr>,
{
use crate::ie::node_id::NodeId;
let ip_addr = node_id.into();
let node = match ip_addr {
std::net::IpAddr::V4(v4) => NodeId::new_ipv4(v4),
std::net::IpAddr::V6(v6) => NodeId::new_ipv6(v6),
};
self.node_id = Some(node.to_ie());
self
}
pub fn node_id_fqdn(mut self, fqdn: &str) -> Self {
use crate::ie::node_id::NodeId;
let node = NodeId::new_fqdn(fqdn);
self.node_id = Some(node.to_ie());
self
}
pub fn node_id_ie(mut self, node_id: Ie) -> Self {
self.node_id = Some(node_id);
self
}
pub fn fseid<T>(mut self, seid: impl Into<Seid>, ip_addr: T) -> Self
where
T: Into<std::net::IpAddr>,
{
use crate::ie::fseid::Fseid;
let ip_addr = ip_addr.into();
let fseid = match ip_addr {
std::net::IpAddr::V4(v4) => Fseid::new(seid, Some(v4), None),
std::net::IpAddr::V6(v6) => Fseid::new(seid, None, Some(v6)),
};
self.fseid = Some(Ie::new(IeType::Fseid, fseid.marshal()));
self
}
pub fn fseid_ie(mut self, fseid: Ie) -> Self {
self.fseid = Some(fseid);
self
}
pub fn create_pdrs(mut self, create_pdrs: Vec<Ie>) -> Self {
self.create_pdrs = create_pdrs;
self
}
pub fn create_fars(mut self, create_fars: Vec<Ie>) -> Self {
self.create_fars = create_fars;
self
}
pub fn create_urrs(mut self, create_urrs: Vec<Ie>) -> Self {
self.create_urrs = create_urrs;
self
}
pub fn create_qers(mut self, create_qers: Vec<Ie>) -> Self {
self.create_qers = create_qers;
self
}
pub fn add_pdr(mut self, pdr: crate::ie::create_pdr::CreatePdr) -> Self {
self.create_pdrs.push(pdr.to_ie());
self
}
pub fn add_far(mut self, far: crate::ie::create_far::CreateFar) -> Self {
self.create_fars.push(far.to_ie());
self
}
pub fn add_urr(mut self, urr: crate::ie::create_urr::CreateUrr) -> Self {
self.create_urrs.push(urr.to_ie());
self
}
pub fn add_qer(mut self, qer: crate::ie::create_qer::CreateQer) -> Self {
self.create_qers.push(qer.to_ie());
self
}
pub fn add_bar(mut self, bar: crate::ie::create_bar::CreateBar) -> Self {
self.create_bars.push(bar.to_ie());
self
}
pub fn add_traffic_endpoint(
mut self,
te: crate::ie::create_traffic_endpoint::CreateTrafficEndpoint,
) -> Self {
self.create_traffic_endpoints.push(te.to_ie());
self
}
pub fn create_bars(mut self, create_bars: Vec<Ie>) -> Self {
self.create_bars = create_bars;
self
}
pub fn create_traffic_endpoints(mut self, create_traffic_endpoints: Vec<Ie>) -> Self {
self.create_traffic_endpoints = create_traffic_endpoints;
self
}
pub fn pdn_type(mut self, pdn_type: Ie) -> Self {
self.pdn_type = Some(pdn_type);
self
}
pub fn fq_csid(mut self, ie: Ie) -> Self {
self.fq_csids.push(ie);
self
}
pub fn user_id(mut self, user_id: Ie) -> Self {
self.user_id = Some(user_id);
self
}
pub fn s_nssai(mut self, s_nssai: Ie) -> Self {
self.s_nssai = Some(s_nssai);
self
}
pub fn trace_information(mut self, trace_information: Ie) -> Self {
self.trace_information = Some(trace_information);
self
}
pub fn recovery_time_stamp(mut self, timestamp: std::time::SystemTime) -> Self {
use crate::ie::recovery_time_stamp::RecoveryTimeStamp;
let ts = RecoveryTimeStamp::new(timestamp);
self.recovery_time_stamp = Some(Ie::new(IeType::RecoveryTimeStamp, ts.marshal().to_vec()));
self
}
pub fn recovery_time_stamp_ie(mut self, recovery_time_stamp: Ie) -> Self {
self.recovery_time_stamp = Some(recovery_time_stamp);
self
}
pub fn cp_function_features(mut self, cp_function_features: Ie) -> Self {
self.cp_function_features = Some(cp_function_features);
self
}
pub fn apn_dnn(mut self, apn_dnn: Ie) -> Self {
self.apn_dnn = Some(apn_dnn);
self
}
pub fn user_plane_inactivity_timer(mut self, user_plane_inactivity_timer: Ie) -> Self {
self.user_plane_inactivity_timer = Some(user_plane_inactivity_timer);
self
}
pub fn pfcpsm_req_flags(mut self, pfcpsm_req_flags: Ie) -> Self {
self.pfcpsm_req_flags = Some(pfcpsm_req_flags);
self
}
pub fn ethernet_pdu_session_information(
mut self,
ethernet_pdu_session_information: Ie,
) -> Self {
self.ethernet_pdu_session_information = Some(ethernet_pdu_session_information);
self
}
pub fn rat_type(mut self, rat_type: Ie) -> Self {
self.rat_type = Some(rat_type);
self
}
pub fn add_l2tp_tunnel_information(mut self, ie: Ie) -> Self {
self.l2tp_tunnel_informations.push(ie);
self
}
pub fn l2tp_session_information(mut self, ie: Ie) -> Self {
self.l2tp_session_information = Some(ie);
self
}
pub fn provide_rds_configuration_information(mut self, ie: Ie) -> Self {
self.provide_rds_configuration_information = Some(ie);
self
}
pub fn create_bridge_info_for_tsc(mut self, ie: Ie) -> Self {
self.create_bridge_info_for_tsc = Some(ie);
self
}
pub fn add_mar(mut self, mar: crate::ie::create_mar::CreateMar) -> Self {
self.create_mars.push(mar.to_ie());
self
}
pub fn create_mars(mut self, ies: Vec<Ie>) -> Self {
self.create_mars = ies;
self
}
pub fn add_srr(mut self, srr: crate::ie::create_srr::CreateSrr) -> Self {
self.create_srrs.push(srr.to_ie());
self
}
pub fn create_srrs(mut self, ies: Vec<Ie>) -> Self {
self.create_srrs = ies;
self
}
pub fn provide_atsss_control_information(mut self, ie: Ie) -> Self {
self.provide_atsss_control_information = Some(ie);
self
}
pub fn hplmn_s_nssai(mut self, ie: Ie) -> Self {
self.hplmn_s_nssai = Some(ie);
self
}
pub fn group_id(mut self, ie: Ie) -> Self {
self.group_id = Some(ie);
self
}
pub fn mbs_session_n4mb_control_information(mut self, ie: Ie) -> Self {
self.mbs_session_n4mb_control_information = Some(ie);
self
}
pub fn add_mbs_session_n4_control_information(mut self, ie: Ie) -> Self {
self.mbs_session_n4_control_information.push(ie);
self
}
pub fn dscp_to_ppi_control_information(mut self, ie: Ie) -> Self {
self.dscp_to_ppi_control_information = Some(ie);
self
}
pub fn tl_container(mut self, ie: Ie) -> Self {
self.tl_containers.push(ie);
self
}
pub fn ue_level_measurements_configuration(mut self, ie: Ie) -> Self {
self.ue_level_measurements_configuration = Some(ie);
self
}
pub fn ies(mut self, ies: Vec<Ie>) -> Self {
self.ies = ies;
self
}
pub fn build(self) -> Result<SessionEstablishmentRequest, PfcpError> {
let node_id = self.node_id.ok_or(PfcpError::MissingMandatoryIe {
ie_type: IeType::NodeId,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
})?;
let fseid = self.fseid.ok_or(PfcpError::MissingMandatoryIe {
ie_type: IeType::Fseid,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
})?;
if self.create_pdrs.is_empty() {
return Err(PfcpError::MissingMandatoryIe {
ie_type: IeType::CreatePdr,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
});
}
if self.create_fars.is_empty() {
return Err(PfcpError::MissingMandatoryIe {
ie_type: IeType::CreateFar,
message_type: Some(MsgType::SessionEstablishmentRequest),
parent_ie: None,
});
}
let mut payload_len = node_id.len() + fseid.len();
for ie in &self.create_pdrs {
payload_len += ie.len();
}
for ie in &self.create_fars {
payload_len += ie.len();
}
for ie in &self.create_urrs {
payload_len += ie.len();
}
for ie in &self.create_qers {
payload_len += ie.len();
}
for ie in &self.create_bars {
payload_len += ie.len();
}
for ie in &self.create_traffic_endpoints {
payload_len += ie.len();
}
if let Some(ie) = &self.pdn_type {
payload_len += ie.len();
}
for ie in &self.fq_csids {
payload_len += ie.len();
}
if let Some(ie) = &self.user_id {
payload_len += ie.len();
}
if let Some(ie) = &self.s_nssai {
payload_len += ie.len();
}
if let Some(ie) = &self.trace_information {
payload_len += ie.len();
}
if let Some(ie) = &self.recovery_time_stamp {
payload_len += ie.len();
}
if let Some(ie) = &self.cp_function_features {
payload_len += ie.len();
}
if let Some(ie) = &self.apn_dnn {
payload_len += ie.len();
}
if let Some(ie) = &self.user_plane_inactivity_timer {
payload_len += ie.len();
}
if let Some(ie) = &self.pfcpsm_req_flags {
payload_len += ie.len();
}
for ie in &self.create_mars {
payload_len += ie.len();
}
if let Some(ie) = &self.create_bridge_info_for_tsc {
payload_len += ie.len();
}
for ie in &self.create_srrs {
payload_len += ie.len();
}
if let Some(ie) = &self.provide_atsss_control_information {
payload_len += ie.len();
}
if let Some(ie) = &self.hplmn_s_nssai {
payload_len += ie.len();
}
if let Some(ie) = &self.ethernet_pdu_session_information {
payload_len += ie.len();
}
if let Some(ie) = &self.rat_type {
payload_len += ie.len();
}
for ie in &self.l2tp_tunnel_informations {
payload_len += ie.len();
}
if let Some(ie) = &self.l2tp_session_information {
payload_len += ie.len();
}
if let Some(ie) = &self.provide_rds_configuration_information {
payload_len += ie.len();
}
if let Some(ie) = &self.group_id {
payload_len += ie.len();
}
if let Some(ie) = &self.mbs_session_n4mb_control_information {
payload_len += ie.len();
}
for ie in &self.mbs_session_n4_control_information {
payload_len += ie.len();
}
if let Some(ie) = &self.dscp_to_ppi_control_information {
payload_len += ie.len();
}
for ie in &self.tl_containers {
payload_len += ie.len();
}
if let Some(ie) = &self.ue_level_measurements_configuration {
payload_len += ie.len();
}
for ie in &self.ies {
payload_len += ie.len();
}
let mut header = Header::new(
MsgType::SessionEstablishmentRequest,
true,
self.seid,
self.seq,
);
header.length = payload_len + (header.len() - 4);
Ok(SessionEstablishmentRequest {
header,
node_id,
fseid,
create_pdrs: self.create_pdrs,
create_fars: self.create_fars,
create_urrs: self.create_urrs,
create_qers: self.create_qers,
create_bars: self.create_bars,
create_traffic_endpoints: self.create_traffic_endpoints,
pdn_type: self.pdn_type,
fq_csids: self.fq_csids,
user_id: self.user_id,
s_nssai: self.s_nssai,
trace_information: self.trace_information,
recovery_time_stamp: self.recovery_time_stamp,
cp_function_features: self.cp_function_features,
apn_dnn: self.apn_dnn,
user_plane_inactivity_timer: self.user_plane_inactivity_timer,
pfcpsm_req_flags: self.pfcpsm_req_flags,
create_mars: self.create_mars,
create_bridge_info_for_tsc: self.create_bridge_info_for_tsc,
create_srrs: self.create_srrs,
provide_atsss_control_information: self.provide_atsss_control_information,
hplmn_s_nssai: self.hplmn_s_nssai,
ethernet_pdu_session_information: self.ethernet_pdu_session_information,
rat_type: self.rat_type,
l2tp_tunnel_informations: self.l2tp_tunnel_informations,
l2tp_session_information: self.l2tp_session_information,
provide_rds_configuration_information: self.provide_rds_configuration_information,
group_id: self.group_id,
mbs_session_n4mb_control_information: self.mbs_session_n4mb_control_information,
mbs_session_n4_control_information: self.mbs_session_n4_control_information,
dscp_to_ppi_control_information: self.dscp_to_ppi_control_information,
tl_containers: self.tl_containers,
ue_level_measurements_configuration: self.ue_level_measurements_configuration,
ies: self.ies,
})
}
pub fn marshal(self) -> Result<Vec<u8>, PfcpError> {
Ok(self.build()?.marshal())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ie::{
fseid::Fseid, node_id::NodeId, recovery_time_stamp::RecoveryTimeStamp, IeType,
};
use crate::types::Seid;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::SystemTime;
fn create_minimal_pdr_far() -> (Vec<Ie>, Vec<Ie>) {
use crate::ie::{
create_far::CreateFar,
create_pdr::CreatePdr,
destination_interface::Interface,
far_id::FarId,
pdi::Pdi,
pdr_id::PdrId,
precedence::Precedence,
source_interface::{SourceInterface, SourceInterfaceValue},
};
let pdi = Pdi {
source_interface: SourceInterface::new(SourceInterfaceValue::Access),
f_teid: None,
network_instance: None,
ue_ip_address: None,
sdf_filter: None,
application_id: None,
ethernet_packet_filter: None,
redundant_transmission_parameters: None,
protocol_description: None,
};
let pdr = CreatePdr::new(
PdrId::new(1),
Precedence::new(100),
pdi,
None, Some(FarId::new(1)),
None, None, None, );
let far = CreateFar::builder(FarId::new(1))
.forward_to(Interface::Access)
.build()
.unwrap();
(vec![pdr.to_ie()], vec![far.to_ie()])
}
#[test]
fn test_session_establishment_builder_ergonomic_node_id_ipv4() {
let ipv4 = Ipv4Addr::new(192, 168, 1, 1);
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id(ipv4)
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(*request.sequence(), 1);
assert_eq!(request.seid(), Some(Seid(0x1234)));
assert_eq!(request.node_id.ie_type, IeType::NodeId);
let node = NodeId::unmarshal(&request.node_id.payload).unwrap();
assert_eq!(node, NodeId::IPv4(ipv4));
}
#[test]
fn test_session_establishment_builder_ergonomic_node_id_ipv6() {
let ipv6 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id(ipv6)
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
let node = NodeId::unmarshal(&request.node_id.payload).unwrap();
assert_eq!(node, NodeId::IPv6(ipv6));
}
#[test]
fn test_session_establishment_builder_ergonomic_node_id_fqdn() {
let fqdn = "upf.example.com";
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_fqdn(fqdn)
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
let node = NodeId::unmarshal(&request.node_id.payload).unwrap();
assert_eq!(node, NodeId::FQDN(fqdn.to_string()));
}
#[test]
fn test_session_establishment_builder_ergonomic_fseid_ipv4() {
let ipv4 = Ipv4Addr::new(10, 0, 0, 1);
let seid = 0x5678;
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.fseid(seid, ipv4)
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(request.fseid.ie_type, IeType::Fseid);
let fseid = Fseid::unmarshal(&request.fseid.payload).unwrap();
assert_eq!(fseid.seid, Seid(seid));
assert_eq!(fseid.ipv4_address, Some(ipv4));
assert_eq!(fseid.ipv6_address, None);
}
#[test]
fn test_session_establishment_builder_ergonomic_fseid_ipv6() {
let ipv6 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
let seid = 0x5678;
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.fseid(seid, ipv6)
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
let fseid = Fseid::unmarshal(&request.fseid.payload).unwrap();
assert_eq!(fseid.seid, Seid(seid));
assert_eq!(fseid.ipv4_address, None);
assert_eq!(fseid.ipv6_address, Some(ipv6));
}
#[test]
fn test_session_establishment_builder_ergonomic_recovery_timestamp() {
let timestamp = SystemTime::now();
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.recovery_time_stamp(timestamp)
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert!(request.recovery_time_stamp.is_some());
let ie = request.recovery_time_stamp.unwrap();
assert_eq!(ie.ie_type, IeType::RecoveryTimeStamp);
let recovered = RecoveryTimeStamp::unmarshal(&ie.payload).unwrap();
let duration = timestamp
.duration_since(recovered.timestamp)
.unwrap_or_else(|e| e.duration());
assert!(duration.as_secs() < 1);
}
#[test]
fn test_session_establishment_builder_ergonomic_full_chain() {
let (pdrs, fars) = create_minimal_pdr_far();
let request = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id(Ipv4Addr::new(192, 168, 1, 1))
.fseid(0x5678, Ipv4Addr::new(10, 0, 0, 1))
.recovery_time_stamp(SystemTime::now())
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(*request.sequence(), 1);
assert_eq!(request.seid(), Some(Seid(0x1234)));
assert!(request.recovery_time_stamp.is_some());
let bytes = request.marshal();
let unmarshaled = SessionEstablishmentRequest::unmarshal(&bytes).unwrap();
assert_eq!(*unmarshaled.sequence(), 1);
assert_eq!(unmarshaled.seid(), Some(Seid(0x1234)));
}
#[test]
fn test_session_establishment_builder_ergonomic_marshal_method() {
let (pdrs, fars) = create_minimal_pdr_far();
let bytes = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id(Ipv4Addr::new(192, 168, 1, 1))
.fseid(0x5678, Ipv4Addr::new(10, 0, 0, 1))
.create_pdrs(pdrs)
.create_fars(fars)
.marshal()
.unwrap();
let request = SessionEstablishmentRequest::unmarshal(&bytes).unwrap();
assert_eq!(*request.sequence(), 1);
assert_eq!(request.seid(), Some(Seid(0x1234)));
}
#[test]
fn test_session_establishment_builder_validation_missing_node_id() {
let (pdrs, fars) = create_minimal_pdr_far();
let result = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_pdrs(pdrs)
.create_fars(fars)
.build();
assert!(result.is_err());
match result.unwrap_err() {
PfcpError::MissingMandatoryIe { ie_type, .. } => {
assert_eq!(ie_type, IeType::NodeId);
}
_ => panic!("Expected MissingMandatoryIe error"),
}
}
#[test]
fn test_session_establishment_builder_validation_missing_fseid() {
let (pdrs, fars) = create_minimal_pdr_far();
let result = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.create_pdrs(pdrs)
.create_fars(fars)
.build();
assert!(result.is_err());
match result.unwrap_err() {
PfcpError::MissingMandatoryIe { ie_type, .. } => {
assert_eq!(ie_type, IeType::Fseid);
}
_ => panic!("Expected MissingMandatoryIe error"),
}
}
#[test]
fn test_session_establishment_builder_validation_missing_pdrs() {
let (_, fars) = create_minimal_pdr_far();
let result = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_fars(fars)
.build();
assert!(result.is_err());
match result.unwrap_err() {
PfcpError::MissingMandatoryIe { ie_type, .. } => {
assert_eq!(ie_type, IeType::CreatePdr);
}
_ => panic!("Expected MissingMandatoryIe error"),
}
}
#[test]
fn test_session_establishment_builder_validation_missing_fars() {
let (pdrs, _) = create_minimal_pdr_far();
let result = SessionEstablishmentRequestBuilder::new(0x1234, 1)
.node_id_ie(Ie::new(IeType::NodeId, vec![]))
.fseid_ie(Ie::new(IeType::Fseid, vec![0; 9]))
.create_pdrs(pdrs)
.build();
assert!(result.is_err());
match result.unwrap_err() {
PfcpError::MissingMandatoryIe { ie_type, .. } => {
assert_eq!(ie_type, IeType::CreateFar);
}
_ => panic!("Expected MissingMandatoryIe error"),
}
}
#[test]
fn test_builder_with_all_optional_ies() {
let (pdrs, fars) = create_minimal_pdr_far();
let urr = Ie::new(IeType::CreateUrr, vec![0, 81, 0, 4, 0, 0, 0, 1]);
let qer = Ie::new(IeType::CreateQer, vec![0, 109, 0, 4, 0, 0, 0, 1]);
let bar = Ie::new(IeType::CreateBar, vec![0, 85, 0, 1, 1]);
let pdn_ie = Ie::new(IeType::PdnType, vec![0x01]);
let apn_ie = Ie::new(
IeType::ApnDnn,
vec![8, 105, 110, 116, 101, 114, 110, 101, 116],
);
let msg = SessionEstablishmentRequestBuilder::new(0x1234, 100)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x5678, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_urrs(vec![urr])
.create_qers(vec![qer])
.create_bars(vec![bar])
.pdn_type(pdn_ie)
.apn_dnn(apn_ie)
.build()
.unwrap();
assert!(!msg.create_urrs.is_empty());
assert!(!msg.create_qers.is_empty());
assert!(!msg.create_bars.is_empty());
assert!(msg.pdn_type.is_some());
assert!(msg.apn_dnn.is_some());
}
#[test]
fn test_builder_with_multiple_pdrs_and_fars() {
let pdr1 = Ie::new(IeType::CreatePdr, vec![0, 56, 0, 2, 0, 1]);
let pdr2 = Ie::new(IeType::CreatePdr, vec![0, 56, 0, 2, 0, 2]);
let pdr3 = Ie::new(IeType::CreatePdr, vec![0, 56, 0, 2, 0, 3]);
let far1 = Ie::new(IeType::CreateFar, vec![0, 108, 0, 4, 0, 0, 0, 1]);
let far2 = Ie::new(IeType::CreateFar, vec![0, 108, 0, 4, 0, 0, 0, 2]);
let msg = SessionEstablishmentRequestBuilder::new(0xABCD, 200)
.node_id(std::net::Ipv4Addr::new(192, 168, 1, 1))
.fseid(0x9876, std::net::Ipv4Addr::new(192, 168, 1, 2))
.create_pdrs(vec![pdr1, pdr2, pdr3])
.create_fars(vec![far1, far2])
.build()
.unwrap();
assert_eq!(msg.create_pdrs.len(), 3);
assert_eq!(msg.create_fars.len(), 2);
}
#[test]
fn test_builder_with_traffic_endpoints() {
let (pdrs, fars) = create_minimal_pdr_far();
let te = Ie::new(IeType::CreateTrafficEndpoint, vec![0, 131, 0, 1, 1]);
let msg = SessionEstablishmentRequestBuilder::new(0x1111, 300)
.node_id(std::net::Ipv4Addr::new(10, 1, 1, 1))
.fseid(0x2222, std::net::Ipv4Addr::new(10, 1, 1, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_traffic_endpoints(vec![te])
.build()
.unwrap();
assert_eq!(msg.create_traffic_endpoints.len(), 1);
}
#[test]
fn test_builder_with_user_plane_inactivity_timer() {
let (pdrs, fars) = create_minimal_pdr_far();
let timer = Ie::new(IeType::UserPlaneInactivityTimer, vec![0, 0, 0, 60]);
let msg = SessionEstablishmentRequestBuilder::new(0x3333, 400)
.node_id(std::net::Ipv4Addr::new(10, 2, 2, 1))
.fseid(0x4444, std::net::Ipv4Addr::new(10, 2, 2, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.user_plane_inactivity_timer(timer)
.build()
.unwrap();
assert!(msg.user_plane_inactivity_timer.is_some());
}
#[test]
fn test_marshal_unmarshal_minimal() {
let (pdrs, fars) = create_minimal_pdr_far();
let original = SessionEstablishmentRequestBuilder::new(0x5555, 500)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x6666, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
let marshaled = original.marshal();
let parsed = crate::message::parse(&marshaled).unwrap();
assert_eq!(parsed.msg_type(), MsgType::SessionEstablishmentRequest);
assert_eq!(*parsed.sequence(), 500);
assert_eq!(parsed.seid(), Some(Seid(0x5555)));
}
#[test]
fn test_marshal_unmarshal_with_optional_ies() {
let (pdrs, fars) = create_minimal_pdr_far();
let pdn_ie = Ie::new(IeType::PdnType, vec![0x01]);
let apn_ie = Ie::new(
IeType::ApnDnn,
vec![8, 105, 110, 116, 101, 114, 110, 101, 116],
);
let original = SessionEstablishmentRequestBuilder::new(0x7777, 600)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x8888, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.pdn_type(pdn_ie)
.apn_dnn(apn_ie)
.build()
.unwrap();
let marshaled = original.marshal();
let unmarshaled = SessionEstablishmentRequest::unmarshal(&marshaled).unwrap();
assert_eq!(*unmarshaled.header.seid, 0x7777);
assert_eq!(*unmarshaled.header.sequence_number, 600);
assert!(unmarshaled.pdn_type.is_some());
assert!(unmarshaled.apn_dnn.is_some());
}
#[test]
fn test_marshal_unmarshal_with_urrs_qers_bars() {
let (pdrs, fars) = create_minimal_pdr_far();
let urr = Ie::new(IeType::CreateUrr, vec![0, 81, 0, 4, 0, 0, 0, 1]);
let qer = Ie::new(IeType::CreateQer, vec![0, 109, 0, 4, 0, 0, 0, 1]);
let bar = Ie::new(IeType::CreateBar, vec![0, 85, 0, 1, 1]);
let original = SessionEstablishmentRequestBuilder::new(0x9999, 700)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xAAAA, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_urrs(vec![urr])
.create_qers(vec![qer])
.create_bars(vec![bar])
.build()
.unwrap();
let marshaled = original.marshal();
let unmarshaled = SessionEstablishmentRequest::unmarshal(&marshaled).unwrap();
assert_eq!(unmarshaled.create_urrs.len(), 1);
assert_eq!(unmarshaled.create_qers.len(), 1);
assert_eq!(unmarshaled.create_bars.len(), 1);
}
#[test]
fn test_message_trait_methods() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0xBBBB, 800)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xCCCC, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(msg.msg_type(), MsgType::SessionEstablishmentRequest);
assert_eq!(msg.msg_name(), "SessionEstablishmentRequest");
assert_eq!(*msg.sequence(), 800);
assert_eq!(msg.seid(), Some(Seid(0xBBBB)));
assert_eq!(msg.version(), 1);
}
#[test]
fn test_message_set_sequence() {
let (pdrs, fars) = create_minimal_pdr_far();
let mut msg = SessionEstablishmentRequestBuilder::new(0xDDDD, 900)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xEEEE, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(*msg.sequence(), 900);
msg.set_sequence(1000.into());
assert_eq!(*msg.sequence(), 1000);
}
#[test]
fn test_ies() {
let (pdrs, fars) = create_minimal_pdr_far();
let pdn_ie = Ie::new(IeType::PdnType, vec![0x01]);
let msg = SessionEstablishmentRequestBuilder::new(0xFFFF, 1100)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x1111, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.pdn_type(pdn_ie.clone())
.build()
.unwrap();
let found = msg.ies(IeType::PdnType).next();
assert!(found.is_some());
assert_eq!(found.unwrap().ie_type, IeType::PdnType);
let node_found = msg.ies(IeType::NodeId).next();
assert!(node_found.is_some());
let not_found = msg.ies(IeType::Cause).next();
assert!(not_found.is_none());
}
#[test]
fn test_ipv4_session_establishment() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0x12345678, 1200)
.node_id(std::net::Ipv4Addr::new(192, 168, 1, 10))
.fseid(0x87654321, std::net::Ipv4Addr::new(192, 168, 1, 20))
.create_pdrs(pdrs)
.create_fars(fars)
.pdn_type(Ie::new(IeType::PdnType, vec![0x01])) .apn_dnn(Ie::new(
IeType::ApnDnn,
vec![8, 105, 110, 116, 101, 114, 110, 101, 116],
))
.build()
.unwrap();
assert_eq!(*msg.header.seid, 0x12345678);
assert!(msg.pdn_type.is_some());
}
#[test]
fn test_ipv6_session_establishment() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0xABCDEF01, 1300)
.node_id(std::net::Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1))
.fseid(
0x01FEDCBA,
std::net::Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2),
)
.create_pdrs(pdrs)
.create_fars(fars)
.pdn_type(Ie::new(IeType::PdnType, vec![0x02])) .build()
.unwrap();
assert_eq!(*msg.header.seid, 0xABCDEF01);
}
#[test]
fn test_dual_stack_session_establishment() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0x11223344, 1400)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x44332211, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.pdn_type(Ie::new(IeType::PdnType, vec![0x03])) .build()
.unwrap();
assert!(msg.pdn_type.is_some());
}
#[test]
fn test_session_with_usage_reporting() {
let (pdrs, fars) = create_minimal_pdr_far();
let urr1 = Ie::new(IeType::CreateUrr, vec![0, 81, 0, 4, 0, 0, 0, 1]);
let urr2 = Ie::new(IeType::CreateUrr, vec![0, 81, 0, 4, 0, 0, 0, 2]);
let msg = SessionEstablishmentRequestBuilder::new(0x55667788, 1500)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x88776655, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_urrs(vec![urr1, urr2])
.build()
.unwrap();
assert_eq!(msg.create_urrs.len(), 2);
}
#[test]
fn test_session_with_qos() {
let (pdrs, fars) = create_minimal_pdr_far();
let qer1 = Ie::new(IeType::CreateQer, vec![0, 109, 0, 4, 0, 0, 0, 1]);
let qer2 = Ie::new(IeType::CreateQer, vec![0, 109, 0, 4, 0, 0, 0, 2]);
let msg = SessionEstablishmentRequestBuilder::new(0x99AABBCC, 1600)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xCCBBAA99, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_qers(vec![qer1, qer2])
.build()
.unwrap();
assert_eq!(msg.create_qers.len(), 2);
}
#[test]
fn test_session_with_buffering() {
let (pdrs, fars) = create_minimal_pdr_far();
let bar = Ie::new(IeType::CreateBar, vec![0, 85, 0, 1, 1]);
let msg = SessionEstablishmentRequestBuilder::new(0xDDEEFF00, 1700)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x00FFEEDD, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_bars(vec![bar])
.build()
.unwrap();
assert_eq!(msg.create_bars.len(), 1);
}
#[test]
fn test_complex_session_all_rules() {
let pdr1 = Ie::new(IeType::CreatePdr, vec![0, 56, 0, 2, 0, 1]);
let pdr2 = Ie::new(IeType::CreatePdr, vec![0, 56, 0, 2, 0, 2]);
let far1 = Ie::new(IeType::CreateFar, vec![0, 108, 0, 4, 0, 0, 0, 1]);
let far2 = Ie::new(IeType::CreateFar, vec![0, 108, 0, 4, 0, 0, 0, 2]);
let urr = Ie::new(IeType::CreateUrr, vec![0, 81, 0, 4, 0, 0, 0, 1]);
let qer = Ie::new(IeType::CreateQer, vec![0, 109, 0, 4, 0, 0, 0, 1]);
let bar = Ie::new(IeType::CreateBar, vec![0, 85, 0, 1, 1]);
let msg = SessionEstablishmentRequestBuilder::new(0x11111111, 1800)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x22222222, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(vec![pdr1, pdr2])
.create_fars(vec![far1, far2])
.create_urrs(vec![urr])
.create_qers(vec![qer])
.create_bars(vec![bar])
.pdn_type(Ie::new(IeType::PdnType, vec![0x01]))
.apn_dnn(Ie::new(
IeType::ApnDnn,
vec![8, 105, 110, 116, 101, 114, 110, 101, 116],
))
.build()
.unwrap();
assert_eq!(msg.create_pdrs.len(), 2);
assert_eq!(msg.create_fars.len(), 2);
assert_eq!(msg.create_urrs.len(), 1);
assert_eq!(msg.create_qers.len(), 1);
assert_eq!(msg.create_bars.len(), 1);
assert!(msg.pdn_type.is_some());
assert!(msg.apn_dnn.is_some());
}
#[test]
fn test_fqdn_node_id() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0x33333333, 1900)
.node_id_fqdn("smf.example.com")
.fseid(0x44444444, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.build()
.unwrap();
assert_eq!(msg.node_id.ie_type, IeType::NodeId);
}
#[test]
fn test_direct_marshal_from_builder() {
let (pdrs, fars) = create_minimal_pdr_far();
let bytes = SessionEstablishmentRequestBuilder::new(0x55555555, 2000)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x66666666, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.marshal()
.unwrap();
assert!(!bytes.is_empty());
assert!(bytes.len() > 16); }
#[test]
fn test_empty_optional_vecs() {
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0x77777777, 2100)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x88888888, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_urrs(vec![]) .create_qers(vec![])
.create_bars(vec![])
.build()
.unwrap();
assert_eq!(msg.create_urrs.len(), 0);
assert_eq!(msg.create_qers.len(), 0);
assert_eq!(msg.create_bars.len(), 0);
}
#[test]
fn test_add_bar_typed() {
use crate::ie::bar_id::BarId;
use crate::ie::create_bar::CreateBar;
let (pdrs, fars) = create_minimal_pdr_far();
let bar = CreateBar::new(BarId::new(1), None);
let msg = SessionEstablishmentRequestBuilder::new(0xAAAA, 2200)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xBBBB, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.add_bar(bar)
.build()
.unwrap();
assert_eq!(msg.create_bars.len(), 1);
}
#[test]
fn test_add_traffic_endpoint_typed() {
use crate::ie::create_traffic_endpoint::{CreateTrafficEndpoint, TrafficEndpointId};
let (pdrs, fars) = create_minimal_pdr_far();
let te = CreateTrafficEndpoint::new(TrafficEndpointId::new(1));
let msg = SessionEstablishmentRequestBuilder::new(0xCCCC, 2300)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xDDDD, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.add_traffic_endpoint(te)
.build()
.unwrap();
assert_eq!(msg.create_traffic_endpoints.len(), 1);
}
#[test]
fn test_add_bar_multiple_accumulates() {
use crate::ie::bar_id::BarId;
use crate::ie::create_bar::CreateBar;
let (pdrs, fars) = create_minimal_pdr_far();
let msg = SessionEstablishmentRequestBuilder::new(0xEEEE, 2400)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0xFFFF, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.add_bar(CreateBar::new(BarId::new(1), None))
.add_bar(CreateBar::new(BarId::new(2), None))
.build()
.unwrap();
assert_eq!(msg.create_bars.len(), 2);
}
#[test]
fn test_session_establishment_request_new_ies_roundtrip() {
let (pdrs, fars) = create_minimal_pdr_far();
let bridge_ie = Ie::new(IeType::CreateBridgeInfoForTsc, vec![0x01, 0x02]);
let hplmn_ie = Ie::new(IeType::HplmnSNssai, vec![0x01, 0x02, 0x03, 0x04]);
let group_id_ie = Ie::new(IeType::GroupId, vec![0x05]);
let dscp_ie = Ie::new(IeType::DscpToPpiControlInformation, vec![0x06]);
let tl_container_ie = Ie::new(IeType::TlContainer, vec![0x07, 0x08]);
let msg = SessionEstablishmentRequestBuilder::new(0xABCDEF, 99)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x1234, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.create_bridge_info_for_tsc(bridge_ie.clone())
.hplmn_s_nssai(hplmn_ie.clone())
.group_id(group_id_ie.clone())
.dscp_to_ppi_control_information(dscp_ie.clone())
.tl_container(tl_container_ie.clone())
.build()
.unwrap();
assert_eq!(msg.create_bridge_info_for_tsc, Some(bridge_ie));
assert_eq!(msg.hplmn_s_nssai, Some(hplmn_ie));
assert_eq!(msg.group_id, Some(group_id_ie));
assert_eq!(msg.dscp_to_ppi_control_information, Some(dscp_ie));
assert_eq!(msg.tl_containers.len(), 1);
assert_eq!(msg.tl_containers[0], tl_container_ie);
let bytes = msg.marshal();
let parsed = SessionEstablishmentRequest::unmarshal(&bytes).unwrap();
assert!(parsed.create_bridge_info_for_tsc.is_some());
assert!(parsed.hplmn_s_nssai.is_some());
assert!(parsed.group_id.is_some());
assert!(parsed.dscp_to_ppi_control_information.is_some());
assert_eq!(parsed.tl_containers.len(), 1);
}
#[test]
fn test_ue_level_measurements_configuration_roundtrip() {
let (pdrs, fars) = create_minimal_pdr_far();
let ulmc_ie = Ie::new(IeType::UeLevelMeasurementsConfiguration, vec![0x01, 0x02]);
let msg = SessionEstablishmentRequestBuilder::new(0xABCDEF, 100)
.node_id(std::net::Ipv4Addr::new(10, 0, 0, 1))
.fseid(0x1234, std::net::Ipv4Addr::new(10, 0, 0, 2))
.create_pdrs(pdrs)
.create_fars(fars)
.ue_level_measurements_configuration(ulmc_ie.clone())
.build()
.unwrap();
assert_eq!(msg.ue_level_measurements_configuration, Some(ulmc_ie));
let bytes = msg.marshal();
let parsed = SessionEstablishmentRequest::unmarshal(&bytes).unwrap();
assert!(parsed.ue_level_measurements_configuration.is_some());
assert_eq!(
msg.ue_level_measurements_configuration,
parsed.ue_level_measurements_configuration
);
}
}