1#!/usr/bin/env python3 2# 3# Copyright (c) 2022, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29""" Module to provide codec utilities for .pcap formatters. """ 30 31import struct 32import time 33 34# https://www.tcpdump.org/linktypes.html 35DLT_IEEE802_15_4_WITHFCS = 195 36 37PCAP_MAGIC_NUMBER = 0xA1B2C3D4 38PCAP_VERSION_MAJOR = 2 39PCAP_VERSION_MINOR = 4 40 41 42class PcapCodec(object): 43 """ Utility class for .pcap formatters. """ 44 45 def __init__(self, channel, filename): 46 self._dlt = DLT_IEEE802_15_4_WITHFCS 47 self._channel = channel 48 49 self._pcap_writer = open(filename, 'wb') 50 self._write(self._encode_header()) 51 52 def _write(self, content): 53 self._pcap_writer.write(content) 54 self._pcap_writer.flush() 55 56 def _encode_header(self): 57 """ Return a pcap file header. """ 58 59 return struct.pack( 60 '<LHHLLLL', 61 PCAP_MAGIC_NUMBER, 62 PCAP_VERSION_MAJOR, 63 PCAP_VERSION_MINOR, 64 0, 65 0, 66 256, 67 self._dlt, 68 ) 69 70 def _encode_frame(self, frame, sec, usec): 71 """ Return a pcap encapsulation of the given frame. """ 72 73 # Ignore the first byte storing channel. 74 frame = frame[1:] 75 76 length = len(frame) 77 pcap_frame = struct.pack('<LLLL', sec, usec, length, length) 78 pcap_frame += frame 79 return pcap_frame 80 81 def _get_timestamp(self): 82 """ Return the internal timestamp. """ 83 84 timestamp = time.time() 85 timestamp_sec = int(timestamp) 86 timestamp_usec = int((timestamp - timestamp_sec) * 1000000) 87 return timestamp_sec, timestamp_usec 88 89 def append(self, frame): 90 """ Append a frame. """ 91 92 # Filter channel. 93 if frame[0] != self._channel: 94 return 95 96 timestamp = self._get_timestamp() 97 self._write(self._encode_frame(frame, *timestamp)) 98 99 def close(self): 100 self._pcap_writer.close() 101