1#!/usr/bin/env python3 2# 3# Copyright (c) 2018, 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 os 32import struct 33import time 34 35# https://www.tcpdump.org/linktypes.html 36DLT_IEEE802_15_4_WITHFCS = 195 37DLT_IEEE802_15_4_TAP = 283 38PCAP_MAGIC_NUMBER = 0xA1B2C3D4 39PCAP_VERSION_MAJOR = 2 40PCAP_VERSION_MINOR = 4 41 42PACKET_VERIFICATION = int(os.getenv('PACKET_VERIFICATION', 0)) 43 44 45class PcapCodec(object): 46 """ Utility class for .pcap formatters. """ 47 48 def __init__(self, filename): 49 self._dlt = DLT_IEEE802_15_4_WITHFCS if PACKET_VERIFICATION else DLT_IEEE802_15_4_TAP 50 self._pcap_file = open('%s.pcap' % filename, 'wb') 51 self._pcap_file.write(self.encode_header()) 52 53 def encode_header(self): 54 """ Returns a pcap file header. """ 55 return struct.pack( 56 "<LHHLLLL", 57 PCAP_MAGIC_NUMBER, 58 PCAP_VERSION_MAJOR, 59 PCAP_VERSION_MINOR, 60 0, 61 0, 62 256, 63 self._dlt, 64 ) 65 66 def encode_frame(self, frame, sec, usec): 67 """ Returns a pcap encapsulation of the given frame. """ 68 length = 0 69 70 if self._dlt == DLT_IEEE802_15_4_TAP: 71 # Append TLVs according to 802.15.4 TAP specification: 72 # https://github.com/jkcko/ieee802.15.4-tap 73 pcap_tap_fcs_tlv = struct.pack("<HHL", 0, 1, 1) 74 pcap_tap_channel_tlv = struct.pack("<HHHH", 3, 3, frame[0], 0) 75 length = 4 + len(pcap_tap_fcs_tlv) + len(pcap_tap_channel_tlv) 76 pcap_tap_header = struct.pack("<HH", 0, length) 77 78 frame = frame[1:] 79 length += len(frame) 80 pcap_frame = struct.pack("<LLLL", sec, usec, length, length) 81 82 if self._dlt == DLT_IEEE802_15_4_TAP: 83 pcap_frame += pcap_tap_header + pcap_tap_fcs_tlv + pcap_tap_channel_tlv 84 85 pcap_frame += frame 86 return pcap_frame 87 88 def _get_timestamp(self): 89 """ Returns the internal timestamp. """ 90 timestamp = time.time() 91 timestamp_sec = int(timestamp) 92 timestamp_usec = int((timestamp - timestamp_sec) * 1000000) 93 return timestamp_sec, timestamp_usec 94 95 def append(self, frame, timestamp=None): 96 """ Appends a frame. """ 97 if timestamp is None: 98 timestamp = self._get_timestamp() 99 pkt = self.encode_frame(frame, *timestamp) 100 self._pcap_file.write(pkt) 101 self._pcap_file.flush() 102 return pkt 103 104 def __del__(self): 105 self._pcap_file.close() 106