//! The spec for GSMTAP is here: use deku::prelude::*; use num_enum::TryFromPrimitive; #[derive(Debug, Copy, Clone, PartialEq)] pub enum GsmtapType { Um(UmSubtype), Abis, UmBurst, /* raw burst bits */ SIM, /* ISO 7816 smart card interface */ TetraI1, /* tetra air interface */ TetraI1Burst, /* tetra air interface */ WmxBurst, /* WiMAX burst */ GbLlc, /* GPRS Gb interface: LLC */ GbSndcp, /* GPRS Gb interface: SNDCP */ Gmr1Um, /* GMR-1 L2 packets */ UmtsRlcMac, UmtsRrc(UmtsRrcSubtype), LteRrc(LteRrcSubtype), /* LTE interface */ LteMac, /* LTE MAC interface */ LteMacFramed, /* LTE MAC with context hdr */ OsmocoreLog, /* libosmocore logging */ QcDiag, /* Qualcomm DIAG frame */ LteNas(LteNasSubtype), /* LTE Non-Access Stratum */ E1T1, /* E1/T1 Lines */ GsmRlp, /* GSM RLP frames as per 3GPP TS 24.022 */ } // based on https://github.com/fgsect/scat/blob/97442580e628de414c9f7c2a185f4e28d0ee7523/src/scat/parsers/qualcomm/diagltelogparser.py#L1337 #[repr(u8)] #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)] pub enum LteNasSubtype { Plain = 0, Secure = 1, } #[repr(u8)] #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)] pub enum UmSubtype { Unknown = 0x00, Bcch = 0x01, Ccch = 0x02, Rach = 0x03, Agch = 0x04, Pch = 0x05, Sdcch = 0x06, Sdcch4 = 0x07, Sdcch8 = 0x08, TchF = 0x09, TchH = 0x0a, Pacch = 0x0b, Cbch52 = 0x0c, Pdch = 0x0d, Ptcch = 0x0e, Cbch51 = 0x0f, } #[repr(u8)] #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)] pub enum UmtsRrcSubtype { DlDcch = 0, UlDcch = 1, DlCcch = 2, UlCcch = 3, Pcch = 4, DlShcch = 5, UlShcch = 6, BcchFach = 7, BcchBch = 8, Mcch = 9, Msch = 10, HandoverToUTRANCommand = 11, InterRATHandoverInfo = 12, SystemInformationBCH = 13, SystemInformationContainer = 14, UERadioAccessCapabilityInfo = 15, MasterInformationBlock = 16, SysInfoType1 = 17, SysInfoType2 = 18, SysInfoType3 = 19, SysInfoType4 = 20, SysInfoType5 = 21, SysInfoType5bis = 22, SysInfoType6 = 23, SysInfoType7 = 24, SysInfoType8 = 25, SysInfoType9 = 26, SysInfoType10 = 27, SysInfoType11 = 28, SysInfoType11bis = 29, SysInfoType12 = 30, SysInfoType13 = 31, SysInfoType13_1 = 32, SysInfoType13_2 = 33, SysInfoType13_3 = 34, SysInfoType13_4 = 35, SysInfoType14 = 36, SysInfoType15 = 37, SysInfoType15bis = 38, SysInfoType15_1 = 39, SysInfoType15_1bis = 40, SysInfoType15_2 = 41, SysInfoType15_2bis = 42, SysInfoType15_2ter = 43, SysInfoType15_3 = 44, SysInfoType15_3bis = 45, SysInfoType15_4 = 46, SysInfoType15_5 = 47, SysInfoType15_6 = 48, SysInfoType15_7 = 49, SysInfoType15_8 = 50, SysInfoType16 = 51, SysInfoType17 = 52, SysInfoType18 = 53, SysInfoType19 = 54, SysInfoType20 = 55, SysInfoType21 = 56, SysInfoType22 = 57, SysInfoTypeSB1 = 58, SysInfoTypeSB2 = 59, ToTargetRNCContainer = 60, TargetRNCToSourceRNCContainer = 61, } #[repr(u8)] #[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)] pub enum LteRrcSubtype { DlCcch = 0, DlDcch = 1, UlCcch = 2, UlDcch = 3, BcchBch = 4, BcchDlSch = 5, PCCH = 6, MCCH = 7, BcchBchMbms = 8, BcchDlSchBr = 9, BcchDlSchMbms = 10, ScMcch = 11, SbcchSlBch = 12, SbcchSlBchV2x = 13, DlCcchNb = 14, DlDcchNb = 15, UlCcchNb = 16, UlDcchNb = 17, BcchBchNb = 18, BcchBchTddNb = 19, BcchDlSchNb = 20, PcchNb = 21, ScMcchNb = 22, } #[derive(Debug)] pub enum GsmtapTypeError { InvalidTypeSubtypeCombo(u8, u8), } impl GsmtapType { pub fn new(gsmtap_type: u8, gsmtap_subtype: u8) -> Result { let maybe_result = match gsmtap_type { 0x01 => match UmSubtype::try_from(gsmtap_subtype) { Ok(subtype) => Some(GsmtapType::Um(subtype)), _ => None, }, 0x02 => Some(GsmtapType::Abis), 0x03 => Some(GsmtapType::UmBurst), 0x04 => Some(GsmtapType::SIM), 0x05 => Some(GsmtapType::TetraI1), 0x06 => Some(GsmtapType::TetraI1Burst), 0x07 => Some(GsmtapType::WmxBurst), 0x08 => Some(GsmtapType::GbLlc), 0x09 => Some(GsmtapType::GbSndcp), 0x0a => Some(GsmtapType::Gmr1Um), 0x0b => Some(GsmtapType::UmtsRlcMac), 0x0c => match UmtsRrcSubtype::try_from(gsmtap_subtype) { Ok(subtype) => Some(GsmtapType::UmtsRrc(subtype)), _ => None, }, 0x0d => match LteRrcSubtype::try_from(gsmtap_subtype) { Ok(subtype) => Some(GsmtapType::LteRrc(subtype)), _ => None, }, 0x0e => Some(GsmtapType::LteMac), 0x0f => Some(GsmtapType::LteMacFramed), 0x10 => Some(GsmtapType::OsmocoreLog), 0x11 => Some(GsmtapType::QcDiag), 0x12 => match LteNasSubtype::try_from(gsmtap_subtype) { Ok(subtype) => Some(GsmtapType::LteNas(subtype)), _ => None, }, 0x13 => Some(GsmtapType::E1T1), 0x14 => Some(GsmtapType::GsmRlp), _ => None, }; match maybe_result { Some(result) => Ok(result), None => Err(GsmtapTypeError::InvalidTypeSubtypeCombo( gsmtap_type, gsmtap_subtype, )), } } pub fn get_type(&self) -> u8 { match self { GsmtapType::Um(_) => 0x01, GsmtapType::Abis => 0x02, GsmtapType::UmBurst => 0x03, GsmtapType::SIM => 0x04, GsmtapType::TetraI1 => 0x05, GsmtapType::TetraI1Burst => 0x06, GsmtapType::WmxBurst => 0x07, GsmtapType::GbLlc => 0x08, GsmtapType::GbSndcp => 0x09, GsmtapType::Gmr1Um => 0x0a, GsmtapType::UmtsRlcMac => 0x0b, GsmtapType::UmtsRrc(_) => 0x0c, GsmtapType::LteRrc(_) => 0x0d, GsmtapType::LteMac => 0x0e, GsmtapType::LteMacFramed => 0x0f, GsmtapType::OsmocoreLog => 0x10, GsmtapType::QcDiag => 0x11, GsmtapType::LteNas(_) => 0x12, GsmtapType::E1T1 => 0x13, GsmtapType::GsmRlp => 0x14, } } pub fn get_subtype(&self) -> u8 { match self { GsmtapType::Um(subtype) => *subtype as u8, GsmtapType::UmtsRrc(subtype) => *subtype as u8, GsmtapType::LteRrc(subtype) => *subtype as u8, GsmtapType::LteNas(subtype) => *subtype as u8, _ => 0, } } } #[derive(Debug, Clone, PartialEq, DekuWrite)] #[deku(endian = "big")] pub struct GsmtapHeader { #[deku(skip)] pub gsmtap_type: GsmtapType, #[deku(assert_eq = "2")] pub version: u8, #[deku(assert_eq = "4")] pub header_len: u8, // length in 4-byte words #[deku(update = "self.gsmtap_type.get_type()")] pub packet_type: u8, pub timeslot: u8, #[deku(bits = 1)] pub pcs_band_indicator: bool, #[deku(bits = 1)] pub uplink: bool, #[deku(bits = 14)] pub arfcn: u16, pub signal_dbm: i8, pub signal_noise_ratio_db: u8, pub frame_number: u32, #[deku(update = "self.gsmtap_type.get_subtype()")] pub subtype: u8, pub antenna_number: u8, pub subslot: u8, #[deku(assert_eq = "0")] pub reserved: u8, } impl GsmtapHeader { pub fn new(gsmtap_type: GsmtapType) -> Self { GsmtapHeader { gsmtap_type, version: 2, header_len: 4, packet_type: gsmtap_type.get_type(), timeslot: 0, pcs_band_indicator: false, uplink: false, arfcn: 0, signal_dbm: 0, signal_noise_ratio_db: 0, frame_number: 0, subtype: gsmtap_type.get_subtype(), antenna_number: 0, subslot: 0, reserved: 0, } } } #[derive(Debug, PartialEq, Clone, DekuWrite)] pub struct GsmtapMessage { pub header: GsmtapHeader, pub payload: Vec, }