Class: PWN::SDR::Decoder::Bluetooth::ExtendedHeader
- Inherits:
-
Object
- Object
- PWN::SDR::Decoder::Bluetooth::ExtendedHeader
- Defined in:
- lib/pwn/sdr/decoder/bluetooth.rb
Overview
Length-bounded extended advertising header parser.
Class Method Summary collapse
-
.parse(opts = {}) ⇒ Object
Core Vol 6 Part B 2.3.4: flagged fields in fixed order, bounded by ExtHdrLen.
Class Method Details
.parse(opts = {}) ⇒ Object
Core Vol 6 Part B 2.3.4: flagged fields in fixed order, bounded by ExtHdrLen. Preserve ACAD/SyncInfo as bytes rather than invent fields.
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/pwn/sdr/decoder/bluetooth.rb', line 281 public_class_method def self.parse(opts = {}) payload = opts[:payload] size = payload[0] & 63 mode = payload[0] >> 6 return nil if mode == 3 || size + 1 > payload.length out = { adv_mode: mode } if size.positive? flags = payload[1] return nil if flags.anybits?(0x80) cursor = 2 { adv_addr: 6, target_addr: 6, cte_info: 1, adi: 2, aux_ptr: 3, sync_info: 18, tx_power: 1 }.each_with_index do |(name, width), bit| next if flags[bit].zero? return nil if cursor + width > size + 1 data = payload[cursor, width] cursor += width case name when :adv_addr, :target_addr out[name] = data.reverse.map { |b| format('%02X', b) }.join(':') when :adi out[:advertising_did] = data[0] | ((data[1] & 15) << 8) out[:advertising_sid] = data[1] >> 4 when :tx_power out[name] = data[0] >= 128 ? data[0] - 256 : data[0] else out[:"#{name}_hex"] = data.pack('C*').unpack1('H*').upcase end end out[:acad_hex] = payload[cursor, size + 1 - cursor].pack('C*').unpack1('H*').upcase end out[:advertising_data_hex] = payload.drop(size + 1).pack('C*').unpack1('H*').upcase out end |