Class: PWN::SDR::Decoder::P25::PacketData
- Inherits:
-
Object
- Object
- PWN::SDR::Decoder::P25::PacketData
- Defined in:
- lib/pwn/sdr/decoder/p25.rb
Overview
Unconfirmed rate-1/2 packet data units, separately bounded by BTF.
Class Method Summary collapse
Class Method Details
.parse(opts = {}) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 280 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 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/pwn/sdr/decoder/p25.rb', line 268 public_class_method def self.parse(opts = {}) data = opts[:data] info = opts[:info] decoder = opts[:decoder] return :incomplete if data.length < 154 decoded = decoder.call(data[56, 98]) return nil unless decoded header, errors = decoded return nil unless DSP.crc16(bytes: header.first(10), init: 0, xorout: 0xFFFF) == ((header[10] << 8) | header[11]) return nil unless (header[0] & 31) == 0x15 && header[0].nobits?(0xC0) && header[1].allbits?(0xC0) && header[6].anybits?(0x80) blocks = header[6] & 127 pad = header[7] & 31 offset = header[9] & 63 return nil unless blocks.positive? && pad <= 11 && header[7].nobits?(0xE0) && header[8].zero? && header[9].nobits?(0xC0) count = 56 + ((blocks + 1) * 98) return :incomplete if data.length < count bytes = [] blocks.times do |index| part = decoder.call(data[154 + (index * 98), 98]) return nil unless part bytes.concat(part[0]) errors += part[1] end crc = 0 bytes[0...-4].each do |byte| 7.downto(0) do |bit| feedback = ((crc >> 31) ^ (byte >> bit)) & 1 crc = (crc << 1) & 0xFFFFFFFF crc ^= 0x04C11DB7 if feedback == 1 end end received = bytes.last(4).reduce(0) { |value, byte| (value << 8) | byte } return nil unless (crc ^ 0xFFFFFFFF) == received length = bytes.length - pad - 4 return nil if length.negative? || offset > length payload = bytes.first(length).pack('C*').unpack1('H*').upcase sap = header[1] & 63 # Only SAP 0/4 are interpreted as clear user/packet data. Unknown # and encrypted services remain opaque; no key guessing. encrypted = if sap == 9 true else ([0, 4].include?(sap) ? false : nil) end [{ protocol: 'P25', event: 'pdu', capability: 'unconfirmed-pdu', decoded: true, nac: format('%03X', info >> 4), duid: 12, duid_name: 'PDU', format: 0x15, sap: sap, manufacturer_id: header[2], outbound: header[0].anybits?(0x20), llid: (header[3] << 16) | (header[4] << 8) | header[5], blocks: blocks, pad_octets: pad, data_header_offset: offset, header_crc_ok: true, packet_crc_ok: true, checksum_verified: true, fec_corrected_bits: errors, encrypted: encrypted, payload_hex: encrypted == false ? payload : nil, ciphertext_hex: encrypted == true ? payload : nil, opaque_payload_hex: encrypted.nil? ? payload : nil }, count] end |