Signal strength and timing advance capture#1061
Conversation
…ments (0xb17f) and RACH Timing Advance (0xb062)
untitaker
left a comment
There was a problem hiding this comment.
Didn't check the protocol details, as i'm not familar enough with them.
|
|
||
| // Parses a 0xb062 RACH response log and reconstructs a 7-byte MAC RAR PDU for Wireshark. | ||
| // Returns None if the log contains no MSG2 (no Timing Advance was received). | ||
| fn parse_rach_response(payload: &[u8]) -> Option<GsmtapMessage> { |
There was a problem hiding this comment.
Ideally this would be expressible in deku but I understand that it's fairly finnicky to do so.
Still, I would suggest to make this function and the one it calls more obviously panic-free. You have a lot of places where bounds checks are done entirely separately from access.
For example, instead of doing this:
if payload.len() < i + 4 {
return None;
}
let x = payload[i];
let y = payload[i + 3];you may as well write:
let x = payload.get(i)?;
let y = payload.get(i + 3)?;...which should be optimized to the same exact thing.
currently when rayhunter panics, the entire thing just shuts down. we could make it more resilient at a higher level, but so far I think we've done well with avoiding panics in the parser.
| pub enum LteMl1ServingCellMeasPacket { | ||
| #[deku(id = "4")] | ||
| V4 { | ||
| rrc_release: u16, |
There was a problem hiding this comment.
This doesn't seem right, rrc_rel is defined as B (for byte) on both v4 and v5 in scat: https://github.com/fgsect/scat/blob/a289d84d81c85612860ef5408c72a0b6306854d0/src/scat/parsers/qualcomm/diagltelogparser.py#L125-L129
|
General comment about testing: If you used scat as a reference implementation, can we also port their parser tests into this codebase? |
…ection of rrc_rel size
TBH, mostly because I'm not experienced enough with testing, so I'm a bit scared of making mistakes that would require more time to address than just shipping functional ones made for this use case. Otherwise, I'm happy to have that port included down the road (or if someone more confident with this wants to do it). |
|
@CGurity thanks for this! you couldn't have known this since i never pushed it, but i had a very similar branch (minus RACH packets) in the works months ago, but left it on the backburner until i finished the compressed QMDL branch. i just rebased it here: https://github.com/EFForg/rayhunter/tree/rssi you and i ended up with a very similar deku implementation for the serving cell measurement packets, but my branch has two major elements i'd love to see used here:
i locally tested your branch, and it works great with the SCAT tests, but throws a ton of fwiw i agree with @untitaker that i'd greatly prefer we use deku to parse RACH packets, and then serialize them back to binary when writing the gsmtap body |
|
if that feels like too much, i could take the reigns and rebase your branch on mine, then do the deku conversation for RACH packets myself |
|
Hello @wgreenberg ! Great to know that I wasn't too astray from the idea you have in mind. TBH, if you can take care of the rebase and it is not an issue for you, I would prefer that. I'm still moving very carefully with the code, and I'm scared to break something you did. If you are too busy or truly don't want to do it, let me know, and I can set aside time to try my best. |
no problem at all, i'll do that & open a new PR. thanks for getting the ball rolling on this! |
Pull Request Checklist
cargo fmt.You must check one of:
Relevant for issues #736 #756 and #154
The code allows the capture of signal strength and timing advances and their addition to the PCAP files in a way Wireshark understands, making the analysis of tower geolocation cases possible, especially when combined with the GPS data capture.
The code was tested in my city for a few days to make sure the data makes sense. Results are valid and consistent. I posted a utility here https://github.com/South-Lighthouse/fade-rayhunter-utility-scripts where I drop a PCAP with GPS coordinates, and the script will extract GPS coordinates, timing advances, signal strength, and tower identity to ask opencellid/google/beacondb for the stored location of the actual towers. A couple of examples are shared in the project Mattermost (screenshot below).
The relevant disclaimer: I used Claude Code a lot to propose where to look for the right info in the radio captures, debug stuff, the code with utility in the referenced external repo, and the text below with a walkthrough of the changes made. What I can totally vouch for is that I validated the code while authorizing changes, and I tested the resulting code, as you can check in the examples shared over Mattermost.
Technical walkthrough for reviewers
This PR adds collection and PCAP export of two new Qualcomm diag log codes to enable tower geolocation analysis. The goal: given a capture with GPS coordinates, an analyst can verify that a tower is physically located where it claims to be by cross-checking signal strength and timing advance against its known coordinates, among other potential checks.
Log code 0xb17f — LTE serving cell measurements
Qualcomm's physical layer emits this log periodically with RSRP (signal strength), PCI (Physical Cell ID), and EARFCN (frequency channel) for the camped cell. The binary layout was sourced from [SCAT's diagltelogparser.py](https://github.com/fgsect/scat/blob/master/src/scat/parsers/qualcomm/diagltelogparser.py), which is the canonical open-source reference for Qualcomm diag formats. Two struct versions exist in the wild (V4/V5), mainly differing in field sizes — the
LteMl1ServingCellMeasPacketenum indiag.rshandles both.These three values are stored in GSMTAP header fields that happen to be spare for this frame type:
signal_dbm→ RSRP,arfcn→ EARFCN,frame_number→ PCI. This makes all three queryable in Wireshark without needing a custom dissector.Log code 0xb062 — LTE MAC Random Access Response (Timing Advance)
Every time the device connects to a cell, the network sends a Random Access Response containing a Timing Advance value — how much earlier the device needs to transmit so its signals arrive on time at the base station. Since TA is proportional to round-trip propagation time, it is an independent distance estimate (~78 m per unit in LTE).
The parser walks the subpacket structure in
gsmtap_parser.rsto extract the TA and TC-RNTI from MSG2, then reconstructs a valid MAC RAR PDU (3GPP TS 36.321 §6.1.5) for inclusion in the PCAP. Qualcomm usesta = 0xFFFFas a sentinel for "RAR received but TA not valid" — those are dropped. Because Wireshark 4.x doesn't dispatch GSMTAP type 0x0f to itsmac-ltedissector, the TA is also stored inframe_numberso it's accessible asgsmtap.frame_nrwithout any plugin.