Module: PWN::SDR::Decoder::ZigBee
- Defined in:
- lib/pwn/sdr/decoder/zigbee.rb
Overview
IEEE 802.15.4 O-QPSK (2.4 GHz ZigBee/Thread) true-air decoder.
2 Mchip/s half-sine O-QPSK ≡ MSK, so I/Q → PWN::FFI::Liquid gmskdem (BT=0.5) at 2 Msps → chip stream. Each 4-bit symbol maps to a 32-chip PN sequence (Table 73, IEEE 802.15.4-2011); soft- correlate every 32 chips against the 16 sequences → symbols → nibbles → bytes. Hunt SHR (4×0x00 preamble + SFD 0xA7) → PHR len → MHR (FCF/seq/PAN/addr) → FCS (CRC-16-KERMIT). Emits per-frame src:, dst:, frame_type:, len:, fcs_ok:.
Defined Under Namespace
Classes: DemodIQ
Constant Summary collapse
- CHIP_RATE =
2_000_000- PN32 =
16 × 32-chip PN sequences (symbol 0..15). Each row is one 32-bit word; chips are LSB-first (c0 = bit0).
[ 0xD9C3522E, 0xED9C3522, 0x2ED9C352, 0x22ED9C35, 0x522ED9C3, 0x3522ED9C, 0xC3522ED9, 0x9C3522ED, 0x8C96077B, 0xB8C96077, 0x7B8C9607, 0x77B8C960, 0x077B8C96, 0x6077B8C9, 0x96077B8C, 0xC96077B8 ].freeze
- PN_CHIPS =
PN32.map { |w| Array.new(32) { |i| (w >> i) & 1 } }.freeze
- SFD =
0xA7- FRAME_TYPE =
{ 0 => 'Beacon', 1 => 'Data', 2 => 'ACK', 3 => 'MAC-Cmd' }.freeze
Class Method Summary collapse
-
.authors ⇒ Object
- Author(s)
0day Inc.
-
.decode(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::SDR::Decoder::ZigBee.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' ).
- .help ⇒ Object
- .parse_line(opts = {}) ⇒ Object
Class Method Details
.authors ⇒ Object
- Author(s)
0day Inc. support@0dayinc.com
182 183 184 |
# File 'lib/pwn/sdr/decoder/zigbee.rb', line 182 public_class_method def self. "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n" end |
.decode(opts = {}) ⇒ Object
- Supported Method Parameters
PWN::SDR::Decoder::ZigBee.decode( freq_obj: 'required - freq_obj returned from PWN::SDR::GQRX.init_freq' )
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/pwn/sdr/decoder/zigbee.rb', line 152 public_class_method def self.decode(opts = {}) freq_obj = opts[:freq_obj] hz = PWN::SDR.hz_to_i(freq: freq_obj[:freq]) ch = ((hz - 2_405_000_000) / 5_000_000).round + 11 rate = (opts[:sample_rate] || freq_obj[:iq_rate] || 4_000_000).to_i PWN::SDR::Decoder::Base.run_iq( freq_obj: freq_obj, protocol: 'ZigBee', sample_rate: rate, source: opts[:source], file: opts[:file], demod: DemodIQ.new(rate: rate, channel: ch), note: 'O-QPSK 2 Mcps ≡ MSK — I/Q→gmskdem→32-chip PN correlate→SHR/SFD→PHR/MHR/FCS.', describe: proc { |b| { modulation: 'O-QPSK', channel: ch, classification: b[:duration_ms] < 5 ? 'ACK' : 'MAC-frame' } } ) end |
.help ⇒ Object
186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/pwn/sdr/decoder/zigbee.rb', line 186 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 (≥4 Msps)' ) #{self}.authors " end |
.parse_line(opts = {}) ⇒ Object
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/pwn/sdr/decoder/zigbee.rb', line 169 public_class_method def self.parse_line(opts = {}) line = opts[:line].to_s out = { protocol: 'ZigBee' } out[:pan] = ::Regexp.last_match(1) if line =~ /PAN[:= ]+([0-9A-Fa-f]+)/i out[:src] = ::Regexp.last_match(1) if line =~ /src[:= ]+([0-9A-Fa-f:]+)/i out[:dst] = ::Regexp.last_match(1) if line =~ /dst[:= ]+([0-9A-Fa-f:]+)/i out[:cmd] = ::Regexp.last_match(1) if line =~ /\b(Beacon|Data|ACK|Cmd)\b/i out[:summary] = "ZigBee #{out[:cmd]} PAN=#{out[:pan]} #{out[:src]}→#{out[:dst]}" out.compact end |