mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-05-17 21:34:46 -07:00
Merge pull request #41 from EFForg/run-heuristics
Add rayhunter-check, a basic tool for running QMDL heuristics
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -313,9 +313,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.1"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da"
|
||||
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -323,9 +323,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.1"
|
||||
version = "4.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb"
|
||||
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1093,6 +1093,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"pcap-file-tokio",
|
||||
"serde",
|
||||
"telcom-parser",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -1104,6 +1105,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"chrono",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"futures-core",
|
||||
@@ -1113,6 +1115,7 @@ dependencies = [
|
||||
"mime_guess",
|
||||
"rayhunter",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempdir",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
|
||||
@@ -5,7 +5,11 @@ edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "rayhunter-daemon"
|
||||
path = "src/main.rs"
|
||||
path = "src/daemon.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "rayhunter-check"
|
||||
path = "src/check.rs"
|
||||
|
||||
[dependencies]
|
||||
rayhunter = { path = "../lib" }
|
||||
@@ -25,3 +29,5 @@ tempdir = "0.3.7"
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
tokio-stream = "0.1.14"
|
||||
futures = "0.3.30"
|
||||
clap = { version = "4.5.2", features = ["derive"] }
|
||||
serde_json = "1.0.114"
|
||||
|
||||
132
bin/src/check.rs
Normal file
132
bin/src/check.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use std::{future, path::PathBuf, pin::pin};
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
use rayhunter::{analysis::{analyzer::{Event, EventType, Harness}, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer}, diag::DataType, gsmtap_parser::GsmtapParser, qmdl::QmdlReader};
|
||||
use tokio::fs::File;
|
||||
use serde::Serialize;
|
||||
use clap::Parser;
|
||||
use futures::TryStreamExt;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about)]
|
||||
struct Args {
|
||||
#[arg(short, long)]
|
||||
qmdl_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct AnalyzerMetadata {
|
||||
name: String,
|
||||
description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct ReportMetadata {
|
||||
num_packets_analyzed: usize,
|
||||
num_packets_skipped: usize,
|
||||
num_warnings: usize,
|
||||
first_packet_time: DateTime<FixedOffset>,
|
||||
last_packet_time: DateTime<FixedOffset>,
|
||||
analyzers: Vec<AnalyzerMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct PacketAnalysis {
|
||||
timestamp: DateTime<FixedOffset>,
|
||||
events: Vec<Option<Event>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct AnalysisReport {
|
||||
metadata: ReportMetadata,
|
||||
analysis: Vec<PacketAnalysis>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
let args = Args::parse();
|
||||
|
||||
let mut harness = Harness::new();
|
||||
harness.add_analyzer(Box::new(LteSib6And7DowngradeAnalyzer{}));
|
||||
|
||||
let mut num_packets_analyzed = 0;
|
||||
let mut num_warnings = 0;
|
||||
let mut first_packet_time: Option<DateTime<FixedOffset>> = None;
|
||||
let mut last_packet_time: Option<DateTime<FixedOffset>> = None;
|
||||
let mut skipped_message_reasons: Vec<String> = Vec::new();
|
||||
let mut analysis: Vec<PacketAnalysis> = Vec::new();
|
||||
let mut analyzers: Vec<AnalyzerMetadata> = Vec::new();
|
||||
|
||||
let names = harness.get_names();
|
||||
let descriptions = harness.get_names();
|
||||
for (name, description) in names.iter().zip(descriptions.iter()) {
|
||||
analyzers.push(AnalyzerMetadata {
|
||||
name: name.to_string(),
|
||||
description: description.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let qmdl_file = File::open(args.qmdl_path).await.expect("failed to open QMDL file");
|
||||
let file_size = qmdl_file.metadata().await.expect("failed to get QMDL file metadata").len();
|
||||
let mut gsmtap_parser = GsmtapParser::new();
|
||||
let mut qmdl_reader = QmdlReader::new(qmdl_file, Some(file_size as usize));
|
||||
let mut qmdl_stream = pin!(qmdl_reader.as_stream()
|
||||
.try_filter(|container| future::ready(container.data_type == DataType::UserSpace)));
|
||||
while let Some(container) = qmdl_stream.try_next().await.expect("failed getting QMDL container") {
|
||||
for maybe_qmdl_message in container.into_messages() {
|
||||
let qmdl_message = match maybe_qmdl_message {
|
||||
Ok(msg) => msg,
|
||||
Err(err) => {
|
||||
skipped_message_reasons.push(format!("{:?}", err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let gsmtap_message = match gsmtap_parser.parse(qmdl_message) {
|
||||
Ok(msg) => msg,
|
||||
Err(err) => {
|
||||
skipped_message_reasons.push(format!("{:?}", err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let Some((timestamp, gsmtap_msg)) = gsmtap_message else {
|
||||
continue;
|
||||
};
|
||||
let element = match InformationElement::try_from(&gsmtap_msg) {
|
||||
Ok(element) => element,
|
||||
Err(err) => {
|
||||
skipped_message_reasons.push(format!("{:?}", err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if first_packet_time.is_none() {
|
||||
first_packet_time = Some(timestamp.to_datetime());
|
||||
}
|
||||
last_packet_time = Some(timestamp.to_datetime());
|
||||
num_packets_analyzed += 1;
|
||||
let analysis_result = harness.analyze_information_element(&element);
|
||||
if analysis_result.iter().any(Option::is_some) {
|
||||
num_warnings += analysis_result.iter()
|
||||
.filter(|maybe_event| matches!(maybe_event, Some(Event { event_type: EventType::QualitativeWarning { .. }, .. })))
|
||||
.count();
|
||||
analysis.push(PacketAnalysis {
|
||||
timestamp: timestamp.to_datetime(),
|
||||
events: analysis_result,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let report = AnalysisReport {
|
||||
metadata: ReportMetadata {
|
||||
num_packets_analyzed,
|
||||
num_packets_skipped: skipped_message_reasons.len(),
|
||||
num_warnings,
|
||||
first_packet_time: first_packet_time.expect("no packet times set"),
|
||||
last_packet_time: last_packet_time.expect("no packet times set"),
|
||||
analyzers,
|
||||
},
|
||||
analysis,
|
||||
};
|
||||
|
||||
println!("{}", serde_json::to_string(&report).expect("failed to serialize report"));
|
||||
}
|
||||
@@ -48,7 +48,7 @@ pub async fn get_pcap(State(state): State<Arc<ServerState>>, Path(qmdl_name): Pa
|
||||
for maybe_msg in container.into_messages() {
|
||||
match maybe_msg {
|
||||
Ok(msg) => {
|
||||
let maybe_gsmtap_msg = gsmtap_parser.recv_message(msg)
|
||||
let maybe_gsmtap_msg = gsmtap_parser.parse(msg)
|
||||
.expect("error parsing gsmtap message");
|
||||
if let Some((timestamp, gsmtap_msg)) = maybe_gsmtap_msg {
|
||||
pcap_writer.write_gsmtap_message(gsmtap_msg, timestamp).await
|
||||
|
||||
@@ -18,3 +18,4 @@ telcom-parser = { path = "../telcom-parser" }
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
futures-core = "0.3.30"
|
||||
futures = "0.3.30"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::information_element::InformationElement;
|
||||
|
||||
@@ -7,6 +8,7 @@ use super::information_element::InformationElement;
|
||||
/// * Low: if combined with a large number of other Warnings, user should investigate
|
||||
/// * Medium: if combined with a few other Warnings, user should investigate
|
||||
/// * High: user should investigate
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub enum Severity {
|
||||
Low,
|
||||
Medium,
|
||||
@@ -15,14 +17,17 @@ pub enum Severity {
|
||||
|
||||
/// [QualitativeWarning] events will always be shown to the user in some manner,
|
||||
/// while `Informational` ones may be hidden based on user settings.
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum EventType {
|
||||
Informational,
|
||||
QualitativeWarning(Severity),
|
||||
QualitativeWarning { severity: Severity },
|
||||
}
|
||||
|
||||
/// Events are user-facing signals that can be emitted by an [Analyzer] upon a
|
||||
/// message being received. They can be used to signifiy an IC detection
|
||||
/// warning, or just to display some relevant information to the user.
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct Event {
|
||||
pub event_type: EventType,
|
||||
pub message: String,
|
||||
@@ -49,3 +54,37 @@ pub trait Analyzer {
|
||||
/// thousands of them alongside many other [Analyzers](Analyzer).
|
||||
fn analyze_information_element(&mut self, ie: &InformationElement) -> Option<Event>;
|
||||
}
|
||||
|
||||
pub struct Harness {
|
||||
analyzers: Vec<Box<dyn Analyzer>>,
|
||||
}
|
||||
|
||||
impl Harness {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
analyzers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_analyzer(&mut self, analyzer: Box<dyn Analyzer>) {
|
||||
self.analyzers.push(analyzer);
|
||||
}
|
||||
|
||||
pub fn analyze_information_element(&mut self, ie: &InformationElement) -> Vec<Option<Event>> {
|
||||
self.analyzers.iter_mut()
|
||||
.map(|analyzer| analyzer.analyze_information_element(ie))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_names(&self) -> Vec<Cow<'_, str>> {
|
||||
self.analyzers.iter()
|
||||
.map(|analyzer| analyzer.get_name())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_descriptions(&self) -> Vec<Cow<'_, str>> {
|
||||
self.analyzers.iter()
|
||||
.map(|analyzer| analyzer.get_description())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,31 +52,34 @@ pub enum LteInformationElement {
|
||||
//ScMcchNb(),
|
||||
}
|
||||
|
||||
impl TryFrom<&GsmtapMessage> for LteInformationElement {
|
||||
impl TryFrom<&GsmtapMessage> for InformationElement {
|
||||
type Error = InformationElementError;
|
||||
|
||||
fn try_from(gsmtap_msg: &GsmtapMessage) -> Result<Self, Self::Error> {
|
||||
if let GsmtapType::LteRrc(lte_rrc_subtype) = gsmtap_msg.header.gsmtap_type {
|
||||
use LteRrcSubtype as L;
|
||||
use LteInformationElement as R;
|
||||
return match lte_rrc_subtype {
|
||||
L::DlCcch => Ok(R::DlCcch(decode(&gsmtap_msg.payload)?)),
|
||||
L::DlDcch => Ok(R::DlDcch(decode(&gsmtap_msg.payload)?)),
|
||||
L::UlCcch => Ok(R::UlCcch(decode(&gsmtap_msg.payload)?)),
|
||||
L::UlDcch => Ok(R::UlDcch(decode(&gsmtap_msg.payload)?)),
|
||||
L::BcchBch => Ok(R::BcchBch(decode(&gsmtap_msg.payload)?)),
|
||||
L::BcchDlSch => Ok(R::BcchDlSch(decode(&gsmtap_msg.payload)?)),
|
||||
L::PCCH => Ok(R::PCCH(decode(&gsmtap_msg.payload)?)),
|
||||
L::MCCH => Ok(R::MCCH(decode(&gsmtap_msg.payload)?)),
|
||||
L::ScMcch => Ok(R::ScMcch(decode(&gsmtap_msg.payload)?)),
|
||||
L::BcchBchMbms => Ok(R::BcchBchMbms(decode(&gsmtap_msg.payload)?)),
|
||||
L::BcchDlSchBr => Ok(R::BcchDlSchBr(decode(&gsmtap_msg.payload)?)),
|
||||
L::BcchDlSchMbms => Ok(R::BcchDlSchMbms(decode(&gsmtap_msg.payload)?)),
|
||||
L::SbcchSlBch => Ok(R::SbcchSlBch(decode(&gsmtap_msg.payload)?)),
|
||||
L::SbcchSlBchV2x => Ok(R::SbcchSlBchV2x(decode(&gsmtap_msg.payload)?)),
|
||||
_ => Err(InformationElementError::UnsupportedGsmtapType(gsmtap_msg.header.gsmtap_type)),
|
||||
};
|
||||
match gsmtap_msg.header.gsmtap_type {
|
||||
GsmtapType::LteRrc(lte_rrc_subtype) => {
|
||||
use LteRrcSubtype as L;
|
||||
use LteInformationElement as R;
|
||||
let lte = match lte_rrc_subtype {
|
||||
L::DlCcch => R::DlCcch(decode(&gsmtap_msg.payload)?),
|
||||
L::DlDcch => R::DlDcch(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(lte))
|
||||
},
|
||||
_ => Err(InformationElementError::UnsupportedGsmtapType(gsmtap_msg.header.gsmtap_type)),
|
||||
}
|
||||
Err(InformationElementError::UnsupportedGsmtapType(gsmtap_msg.header.gsmtap_type))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ use super::information_element::{InformationElement, LteInformationElement};
|
||||
use telcom_parser::lte_rrc::{BCCH_DL_SCH_MessageType, BCCH_DL_SCH_MessageType_c1, CellReselectionPriority, SystemInformationBlockType7, SystemInformationCriticalExtensions, SystemInformation_r8_IEsSib_TypeAndInfo, SystemInformation_r8_IEsSib_TypeAndInfo_Entry};
|
||||
|
||||
/// Based on heuristic T7 from Shinjo Park's "Why We Cannot Win".
|
||||
pub struct LteSib7DowngradeAnalyzer {
|
||||
pub struct LteSib6And7DowngradeAnalyzer {
|
||||
}
|
||||
|
||||
impl LteSib7DowngradeAnalyzer {
|
||||
impl LteSib6And7DowngradeAnalyzer {
|
||||
fn unpack_system_information<'a>(&self, ie: &'a InformationElement) -> Option<&'a SystemInformation_r8_IEsSib_TypeAndInfo> {
|
||||
if let InformationElement::LTE(LteInformationElement::BcchDlSch(bcch_dl_sch_message)) = ie {
|
||||
if let BCCH_DL_SCH_MessageType::C1(BCCH_DL_SCH_MessageType_c1::SystemInformation(system_information)) = &bcch_dl_sch_message.message {
|
||||
@@ -22,13 +22,13 @@ impl LteSib7DowngradeAnalyzer {
|
||||
}
|
||||
|
||||
// TODO: keep track of SIB state to compare LTE reselection blocks w/ 2g/3g ones
|
||||
impl Analyzer for LteSib7DowngradeAnalyzer {
|
||||
impl Analyzer for LteSib6And7DowngradeAnalyzer {
|
||||
fn get_name(&self) -> Cow<str> {
|
||||
Cow::from("LTE SIB 7 Downgrade")
|
||||
Cow::from("LTE SIB 6/7 Downgrade")
|
||||
}
|
||||
|
||||
fn get_description(&self) -> Cow<str> {
|
||||
Cow::from("Tests for LTE cells broadcasting a SIB type 7 which include 2G/3G frequencies with higher priorities.")
|
||||
Cow::from("Tests for LTE cells broadcasting a SIB type 6 and 7 which include 2G/3G frequencies with higher priorities.")
|
||||
}
|
||||
|
||||
fn analyze_information_element(&mut self, ie: &InformationElement) -> Option<super::analyzer::Event> {
|
||||
@@ -41,7 +41,7 @@ impl Analyzer for LteSib7DowngradeAnalyzer {
|
||||
if let Some(CellReselectionPriority(p)) = carrier_info.cell_reselection_priority {
|
||||
if p == 0 {
|
||||
return Some(Event {
|
||||
event_type: EventType::QualitativeWarning(Severity::High),
|
||||
event_type: EventType::QualitativeWarning { severity: Severity::High },
|
||||
message: "LTE cell advertised a 3G cell for priority 0 reselection".to_string(),
|
||||
});
|
||||
}
|
||||
@@ -53,7 +53,7 @@ impl Analyzer for LteSib7DowngradeAnalyzer {
|
||||
if let Some(CellReselectionPriority(p)) = carrier_info.cell_reselection_priority {
|
||||
if p == 0 {
|
||||
return Some(Event {
|
||||
event_type: EventType::QualitativeWarning(Severity::High),
|
||||
event_type: EventType::QualitativeWarning { severity: Severity::High },
|
||||
message: "LTE cell advertised a 3G cell for priority 0 reselection".to_string(),
|
||||
});
|
||||
}
|
||||
@@ -66,7 +66,7 @@ impl Analyzer for LteSib7DowngradeAnalyzer {
|
||||
if let Some(CellReselectionPriority(p)) = carrier_info.common_info.cell_reselection_priority {
|
||||
if p == 0 {
|
||||
return Some(Event {
|
||||
event_type: EventType::QualitativeWarning(Severity::High),
|
||||
event_type: EventType::QualitativeWarning { severity: Severity::High },
|
||||
message: "LTE cell advertised a 2G cell for priority 0 reselection".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ impl GsmtapParser {
|
||||
GsmtapParser {}
|
||||
}
|
||||
|
||||
pub fn recv_message(&mut self, msg: Message) -> Result<Option<(Timestamp, GsmtapMessage)>, GsmtapParserError> {
|
||||
pub fn parse(&mut self, msg: Message) -> Result<Option<(Timestamp, GsmtapMessage)>, GsmtapParserError> {
|
||||
if let Message::Log { timestamp, body, .. } = msg {
|
||||
match self.log_to_gsmtap(body)? {
|
||||
Some(msg) => Ok(Some((timestamp, msg))),
|
||||
|
||||
@@ -42,7 +42,7 @@ fn test_lte_rrc_ota() {
|
||||
}
|
||||
}
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[0x10, 0x15]);
|
||||
assert_eq!(gsmtap_msg.header.packet_type, 13);
|
||||
assert_eq!(gsmtap_msg.header.timeslot, 0);
|
||||
@@ -85,7 +85,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x10, 0x15,
|
||||
]);
|
||||
@@ -132,7 +132,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x40, 0x85, 0x8e, 0xc4, 0xe5, 0xbf, 0xe0, 0x50,
|
||||
0xdc, 0x29, 0x15, 0x16, 0x00,
|
||||
@@ -183,7 +183,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x08, 0x10, 0xa7, 0x14, 0x53, 0x59, 0xa6, 0x05,
|
||||
0x43, 0x68, 0xc0, 0x3b, 0xda, 0x30, 0x04, 0xa6,
|
||||
@@ -229,7 +229,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x28, 0x18, 0x40, 0x16, 0x08, 0x08, 0x80, 0x00,
|
||||
0x00,
|
||||
@@ -274,7 +274,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x40, 0x0c, 0x8e, 0xc9, 0x42, 0x89, 0xe0,
|
||||
]);
|
||||
@@ -324,7 +324,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x08, 0x10, 0xa5, 0x34, 0x61, 0x41, 0xa3, 0x1c,
|
||||
0x31, 0x68, 0x04, 0x40, 0x1a, 0x00, 0x49, 0x16,
|
||||
@@ -370,7 +370,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[0x2c, 0x00]);
|
||||
assert_eq!(gsmtap_msg.header.packet_type, 13);
|
||||
assert_eq!(gsmtap_msg.header.timeslot, 0);
|
||||
@@ -412,7 +412,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x40, 0x0b, 0x8e, 0xc1, 0xdd, 0x13, 0xb0,
|
||||
]);
|
||||
@@ -455,7 +455,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[0x2e, 0x02]);
|
||||
assert_eq!(gsmtap_msg.header.packet_type, 13);
|
||||
assert_eq!(gsmtap_msg.header.timeslot, 0);
|
||||
@@ -501,7 +501,7 @@ fn test_lte_rrc_ota() {
|
||||
},
|
||||
},
|
||||
});
|
||||
let (_, gsmtap_msg) = parser.recv_message(parsed).unwrap().unwrap();
|
||||
let (_, gsmtap_msg) = parser.parse(parsed).unwrap().unwrap();
|
||||
assert_eq!(&gsmtap_msg.payload, &[
|
||||
0x40, 0x49, 0x88, 0x05, 0xc0, 0x97, 0x02, 0xd3,
|
||||
0xb0, 0x98, 0x1c, 0x20, 0xa0, 0x81, 0x8c, 0x43,
|
||||
|
||||
Reference in New Issue
Block a user