Module: PWN::SDR::Decoder::LTE
- Defined in:
- lib/pwn/sdr/decoder/lte.rb
Overview
LTE (E-UTRA) true-air PSS/SSS cell search.
I/Q resampled to 1.92 Msps (128-FFT grid), time-domain PSS correlation against Zadoff-Chu roots 25,29,34 → N_ID_2 ∈ 0,1,2
- half-frame timing + coarse CFO. SSS m-sequence pair 5 symbols earlier → N_ID_1 ∈ 0..167 → PCI = 3·N_ID_1 + N_ID_2. All FFTs via PWN::FFI::FFTW; falls back to naive DFT for small N.
Defined Under Namespace
Classes: DemodIQ
Constant Summary collapse
- FS_BASE =
1_920_000- NFFT =
128- CP_NORM =
samples @ 1.92 Msps for symbols 1..6 (10 for symbol 0)
9- PSS_ROOTS =
{ 0 => 25, 1 => 29, 2 => 34 }.freeze
Class Method Summary collapse
-
.authors ⇒ Object
- Author(s)
0day Inc.
-
.cseq(opts = {}) ⇒ Object
Scrambling sequence c0 (x^5+x^3+1) tied to N_ID_2, ±1.
-
.decode(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::SDR::Decoder::LTE.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' ).
- .help ⇒ Object
-
.mseq(opts = {}) ⇒ Object
Length-31 m-sequence x^5+x^2+1, cyclic-shifted by
shift, as ±1. - .parse_line(opts = {}) ⇒ Object
-
.sss_indices(opts = {}) ⇒ Object
SSS helper: (m0, m1) pair for a given N_ID_1 per TS 36.211 §6.11.2.
Class Method Details
.authors ⇒ Object
- Author(s)
0day Inc. support@0dayinc.com
234 235 236 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 234 public_class_method def self. "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n" end |
.cseq(opts = {}) ⇒ Object
Scrambling sequence c0 (x^5+x^3+1) tied to N_ID_2, ±1.
187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 187 public_class_method def self.cseq(opts = {}) @cseq_base ||= begin reg = [0, 0, 0, 0, 1] Array.new(31) do o = reg[0] fb = reg[0] ^ reg[2] reg = reg[1..] + [fb] 1 - (2 * o) end end sh = opts[:nid2].to_i Array.new(31) { |n| @cseq_base[(n + sh) % 31] } end |
.decode(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::SDR::Decoder::LTE.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' )
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 206 public_class_method def self.decode(opts = {}) freq_obj = opts[:freq_obj] rate = (opts[:sample_rate] || freq_obj[:iq_rate] || 1_920_000).to_i PWN::SDR::Decoder::Base.run_iq( freq_obj: freq_obj, protocol: 'LTE', sample_rate: rate, source: opts[:source], file: opts[:file], demod: DemodIQ.new(rate: rate), note: 'OFDMA — I/Q→1.92 Msps→PSS ZC-correlate (FFTW)→N_ID_2+CFO→SSS m-seq→PCI.', describe: proc { |_b| { modulation: 'OFDMA', subcarrier_khz: 15 } } ) end |
.help ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 238 public_class_method def self.help puts "USAGE (true-air I/Q via PWN::FFI + detector fallback): #{self}.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq', source: 'optional - :auto|:rtlsdr|:adalm_pluto|:file', file: 'optional - .cu8/.cs16 capture (≥1.92 Msps)' ) #{self}.authors " end |
.mseq(opts = {}) ⇒ Object
Length-31 m-sequence x^5+x^2+1, cyclic-shifted by shift, as ±1.
172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 172 public_class_method def self.mseq(opts = {}) @mseq_base ||= begin reg = [0, 0, 0, 0, 1] Array.new(31) do o = reg[0] fb = reg[0] ^ reg[3] reg = reg[1..] + [fb] 1 - (2 * o) end end sh = opts[:shift].to_i Array.new(31) { |n| @mseq_base[(n + sh) % 31] } end |
.parse_line(opts = {}) ⇒ Object
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 221 public_class_method def self.parse_line(opts = {}) line = opts[:line].to_s out = { protocol: 'LTE' } out[:earfcn] = ::Regexp.last_match(1) if line =~ /EARFCN[:= ]+(\d+)/i out[:pci] = ::Regexp.last_match(1) if line =~ /(?:PCI|N_id_cell|Id)[:= ]+(\d{1,3})/i out[:prb] = (::Regexp.last_match(1) || ::Regexp.last_match(2)) if line =~ /(?:PRB[:= ]+(\d+)|(\d+)\s*PRB)/i out[:rsrp] = ::Regexp.last_match(1) if line =~ /(-?\d+(?:\.\d+)?)\s*dBm/ out[:summary] = "LTE PCI=#{out[:pci]} EARFCN=#{out[:earfcn]} PRB=#{out[:prb]} RSRP=#{out[:rsrp]}dBm" out.compact end |
.sss_indices(opts = {}) ⇒ Object
SSS helper: (m0, m1) pair for a given N_ID_1 per TS 36.211 §6.11.2.
161 162 163 164 165 166 167 168 169 |
# File 'lib/pwn/sdr/decoder/lte.rb', line 161 public_class_method def self.sss_indices(opts = {}) nid1 = opts[:nid1].to_i qp = (nid1 / 30) q = ((nid1 + (qp * (qp + 1) / 2)) / 30) mp = nid1 + (q * (q + 1) / 2) m0 = mp % 31 m1 = (m0 + (mp / 31) + 1) % 31 [m0, m1] end |