l2tp 0.2.0

High-level L2TP interface for Linux kernel
Documentation
use crate::{Cookie, IfName, L2SpecType, PseudowireType, SessionId, SessionStats, TunnelId};

pub struct SessionConfig {
    pub tunnel_id: TunnelId,
    pub session_id: SessionId,
    pub peer_session_id: SessionId,
    pub pseudowire_type: PseudowireType,
    pub l2spec_type: L2SpecType,
    pub cookie: Cookie,
    pub peer_cookie: Cookie,
    pub recv_seq: bool,
    pub send_seq: bool,
    pub lns_mode: bool,
    pub recv_timeout_ms: Option<u64>,
    pub ifname: Option<IfName>,
}

impl SessionConfig {
    pub fn eth(tunnel_id: TunnelId, session_id: SessionId, peer_session_id: SessionId) -> Self {
        Self {
            tunnel_id,
            session_id,
            peer_session_id,
            pseudowire_type: PseudowireType::Eth,
            l2spec_type: L2SpecType::None,
            cookie: Cookie::none(),
            peer_cookie: Cookie::none(),
            recv_seq: false,
            send_seq: false,
            lns_mode: false,
            recv_timeout_ms: None,
            ifname: None,
        }
    }
}

#[derive(Debug, Clone)]
pub struct SessionInfo {
    pub tunnel_id: TunnelId,
    pub session_id: SessionId,
    pub peer_session_id: SessionId,
    pub pseudowire_type: PseudowireType,
    pub l2spec_type: L2SpecType,
    pub recv_seq: bool,
    pub send_seq: bool,
    pub lns_mode: bool,
    pub recv_timeout_ms: Option<u64>,
    pub ifname: Option<IfName>,
    pub using_ipsec: bool,
}

#[derive(Debug, Clone, Default)]
pub struct SessionModify {
    pub recv_seq: Option<bool>,
    pub send_seq: Option<bool>,
    pub lns_mode: Option<bool>,
    pub recv_timeout_ms: Option<u64>,
}

pub struct SessionHandle {
    pub(crate) tunnel_id: TunnelId,
    pub(crate) session_id: SessionId,
    pub(crate) ifname: Option<IfName>,
    pub(crate) auto_delete: bool,
    pub(crate) handle: crate::handle::L2tpHandle,
}

impl SessionHandle {
    pub fn tunnel_id(&self) -> TunnelId {
        self.tunnel_id
    }

    pub fn session_id(&self) -> SessionId {
        self.session_id
    }

    pub fn ifname(&self) -> Option<&IfName> {
        self.ifname.as_ref()
    }

    pub fn set_auto_delete(&mut self, v: bool) {
        self.auto_delete = v;
    }

    pub async fn get(&self) -> crate::Result<SessionInfo> {
        self.handle
            .get_session(self.tunnel_id, self.session_id)
            .await
    }

    pub async fn stats(&self) -> crate::Result<SessionStats> {
        self.handle
            .session_stats(self.tunnel_id, self.session_id)
            .await
    }

    pub async fn modify(&self, params: SessionModify) -> crate::Result<()> {
        self.handle
            .modify_session(self.tunnel_id, self.session_id, params)
            .await
    }
}

impl Drop for SessionHandle {
    fn drop(&mut self) {
        if !self.auto_delete {
            return;
        }

        let handle = self.handle.clone();
        let tunnel_id = self.tunnel_id;
        let session_id = self.session_id;

        if let Ok(runtime) = tokio::runtime::Handle::try_current() {
            runtime.spawn(async move {
                let _ = handle.delete_session(tunnel_id, session_id).await;
            });
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn session_eth_constructor_sets_expected_defaults() {
        let config = SessionConfig::eth(TunnelId(1), SessionId(2), SessionId(3));

        assert_eq!(config.tunnel_id, TunnelId(1));
        assert_eq!(config.session_id, SessionId(2));
        assert_eq!(config.peer_session_id, SessionId(3));
        assert_eq!(config.pseudowire_type, PseudowireType::Eth);
        assert_eq!(config.l2spec_type, L2SpecType::None);
        assert_eq!(config.cookie.as_bytes(), &[]);
        assert_eq!(config.peer_cookie.as_bytes(), &[]);
        assert!(!config.recv_seq);
        assert!(!config.send_seq);
        assert!(!config.lns_mode);
        assert_eq!(config.recv_timeout_ms, None);
        assert_eq!(config.ifname, None);
    }
}