Files
rayhunter/lib/src/analysis/information_element.rs
Markus Unterwaditzer e320874854 Remove PartialEq, Clone, Serialize from LTE RRC parser
Compiling telecom-parser takes 2 minutes on my machine. After removing
those derives it takes 1:15. I suspect it's mostly serde though.
2025-07-15 15:21:02 -07:00

106 lines
4.2 KiB
Rust

//! The term "information element" is used by 3GPP to describe "structural
//! elements containing single or multiple fields" in 2G/3G/4G/5G. We use
//! the term to refer to a structured, fully parsed message in any telcom
//! standard.
use crate::gsmtap::{GsmtapMessage, GsmtapType, LteNasSubtype, LteRrcSubtype};
use pycrate_rs::nas::NASMessage;
use telcom_parser::{decode, lte_rrc};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum InformationElementError {
#[error("Failed decoding RRC message")]
RRCDecodingError(#[from] telcom_parser::ParsingError),
#[error("Failed decoding NAS message")]
NASDecodingError(#[from] pycrate_rs::nas::ParseError),
#[error("Unsupported LTE RRC subtype {0:?}")]
UnsupportedGsmtapType(GsmtapType),
}
#[derive(Debug)]
pub enum InformationElement {
GSM,
UMTS,
// This element of the enum is substantially larger than the others,
// so we box it to prevent the size of the enum (any variant) from blowing up.
LTE(Box<LteInformationElement>),
FiveG,
}
#[derive(Debug)]
pub enum LteInformationElement {
DlCcch(lte_rrc::DL_CCCH_Message),
// This element of the enum is substantially larger than the others,
// so we box it to prevent the size of the enum (any variant) from blowing up.
DlDcch(Box<lte_rrc::DL_DCCH_Message>),
UlCcch(lte_rrc::UL_CCCH_Message),
UlDcch(lte_rrc::UL_DCCH_Message),
BcchBch(lte_rrc::BCCH_BCH_Message),
BcchDlSch(lte_rrc::BCCH_DL_SCH_Message),
PCCH(lte_rrc::PCCH_Message),
MCCH(lte_rrc::MCCH_Message),
ScMcch(lte_rrc::SC_MCCH_Message_r13),
BcchBchMbms(lte_rrc::BCCH_BCH_Message_MBMS),
BcchDlSchBr(lte_rrc::BCCH_DL_SCH_Message_BR),
BcchDlSchMbms(lte_rrc::BCCH_DL_SCH_Message_MBMS),
SbcchSlBch(lte_rrc::SBCCH_SL_BCH_Message),
SbcchSlBchV2x(lte_rrc::SBCCH_SL_BCH_Message_V2X_r14),
NAS(NASMessage),
// FIXME: unclear which message these "NB" types map to
//DlCcchNb(),
//DlDcchNb(),
//UlCcchNb(),
//UlDcchNb(),
//BcchBchNb(),
//BcchBchTddNb(),
//BcchDlSchNb(),
//PcchNb(),
//ScMcchNb(),
}
impl TryFrom<&GsmtapMessage> for InformationElement {
type Error = InformationElementError;
fn try_from(gsmtap_msg: &GsmtapMessage) -> Result<Self, Self::Error> {
match gsmtap_msg.header.gsmtap_type {
GsmtapType::LteRrc(lte_rrc_subtype) => {
use LteInformationElement as R;
use LteRrcSubtype as L;
let lte = match lte_rrc_subtype {
L::DlCcch => R::DlCcch(decode(&gsmtap_msg.payload)?),
L::DlDcch => R::DlDcch(Box::new(decode(&gsmtap_msg.payload)?)),
L::UlCcch => R::UlCcch(decode(&gsmtap_msg.payload)?),
L::UlDcch => R::UlDcch(decode(&gsmtap_msg.payload)?),
L::BcchBch => R::BcchBch(decode(&gsmtap_msg.payload)?),
L::BcchDlSch => R::BcchDlSch(decode(&gsmtap_msg.payload)?),
L::PCCH => R::PCCH(decode(&gsmtap_msg.payload)?),
L::MCCH => R::MCCH(decode(&gsmtap_msg.payload)?),
L::ScMcch => R::ScMcch(decode(&gsmtap_msg.payload)?),
L::BcchBchMbms => R::BcchBchMbms(decode(&gsmtap_msg.payload)?),
L::BcchDlSchBr => R::BcchDlSchBr(decode(&gsmtap_msg.payload)?),
L::BcchDlSchMbms => R::BcchDlSchMbms(decode(&gsmtap_msg.payload)?),
L::SbcchSlBch => R::SbcchSlBch(decode(&gsmtap_msg.payload)?),
L::SbcchSlBchV2x => R::SbcchSlBchV2x(decode(&gsmtap_msg.payload)?),
_ => {
return Err(InformationElementError::UnsupportedGsmtapType(
gsmtap_msg.header.gsmtap_type,
));
}
};
Ok(InformationElement::LTE(Box::new(lte)))
}
GsmtapType::LteNas(LteNasSubtype::Plain) => {
let msg = NASMessage::parse(&gsmtap_msg.payload)?;
Ok(InformationElement::LTE(Box::new(
LteInformationElement::NAS(msg),
)))
}
_ => Err(InformationElementError::UnsupportedGsmtapType(
gsmtap_msg.header.gsmtap_type,
)),
}
}
}