rs-pfcp 0.4.0

High-performance Rust implementation of PFCP (Packet Forwarding Control Protocol) for 5G networks with 100% 3GPP TS 29.244 Release 18 compliance
Documentation
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use super::header::{Header, IE_HEADER_SIZE};

pub const ALTERNATE_SMF_IP_ADDRESS: u16 = 141;

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct AlternateSmfIpAddress {
    pub header: Header,
    pub v4: bool,
    pub v6: bool,
    pub ip_address: IpAddr,
}

impl AlternateSmfIpAddress {
    pub fn new(ip_address: IpAddr, instance: u8) -> Self {
        let mut alt_ip = AlternateSmfIpAddress {
            header: Header {
                ie_type: ALTERNATE_SMF_IP_ADDRESS,
                ie_length: 0,
                instance,
            },
            ip_address,
            ..Default::default()
        };
        match ip_address {
            IpAddr::V4(_) => {
                alt_ip.v4 = true;
                alt_ip.header.ie_length = 5;
            }
            IpAddr::V6(_) => {
                alt_ip.v6 = true;
                alt_ip.header.ie_length = 17;
            }
        }
        alt_ip
    }

    pub fn marshal(&self) -> Vec<u8> {
        let mut buffer = self.header.marshal();
        let mut flags = 0;
        if self.v6 {
            flags |= 0b0000_0010;
        }
        if self.v4 {
            flags |= 0b0000_0001;
        }
        buffer.push(flags);
        match self.ip_address {
            IpAddr::V4(ip) => buffer.extend_from_slice(&ip.octets()),
            IpAddr::V6(ip) => buffer.extend_from_slice(&ip.octets()),
        }
        buffer
    }

    pub fn unmarshal(buffer: &[u8]) -> Result<Self, String> {
        let mut alt_ip = AlternateSmfIpAddress::default();
        alt_ip.header.unmarshal(buffer)?;
        let flags = buffer[IE_HEADER_SIZE as usize];
        alt_ip.v4 = (flags & 0b0000_0001) != 0;
        alt_ip.v6 = (flags & 0b0000_0010) != 0;
        if alt_ip.v4 {
            let mut ip = [0; 4];
            ip.copy_from_slice(&buffer[IE_HEADER_SIZE as usize + 1..IE_HEADER_SIZE as usize + 5]);
            alt_ip.ip_address = IpAddr::V4(Ipv4Addr::from(ip));
        } else if alt_ip.v6 {
            let mut ip = [0; 16];
            ip.copy_from_slice(&buffer[IE_HEADER_SIZE as usize + 1..IE_HEADER_SIZE as usize + 17]);
            alt_ip.ip_address = IpAddr::V6(Ipv6Addr::from(ip));
        }
        Ok(alt_ip)
    }

    pub fn get_length(&self) -> u16 {
        self.header.ie_length + IE_HEADER_SIZE
    }
}