Quantcast
Channel: Wireless Connectivity
Viewing all articles
Browse latest Browse all 116964

Forum Post: RE: Converting from TI RF Packet Sniffer Format (PSD) to PCAP Format

$
0
0

I ran across this thread while trying to find a way to connect the CC2531 USB dongle to Wireshark. I thought I'd reply in case anyone else is looking for a way to use wireshark as a sniffer front end.

This perl script runs on the PC running SmartRF Packet Sniffer and it formats/forwards packets to another PC running Wireshark. The packets show up in SmartRF one one PC and Wireshark on another PC. This is very useful if you have a custom protocol on top of 802.15.4 and/or ZigBee and want to use Wireshark to decode it. I didn't really test the timestamp stuff in the ZEP header, so that probably needs some work.

Hope it helps someone else down the line.

-Brian

# wireshark_adaptor.pl
# This script runs on the same PC that has the CC2531 USB 
# dongle connected and is running SmartRF Packet Sniffer.
# Packet flow is as follows:
# - Dongle to SmartRF Sniffer program via USB
# - SmartRF to wireshark_adaptor.pl script via broadcast UDP:5000 socket on localhost
# - wireshark_adaptor.pl script to PC running wireshark via UDP:17754 socket
#
# I also run a simple script on the wireshark PC to open and
# accept packets on UDP:17754 so the wireshark PC doesn't complain
#
# I breifly tried to setup and send to a local loopback device
# so wireshark could run on the same PC as the SmartRF packet
# sniffer, but I couldn't get it to work.
#
# This script was adapted from the udp_receiver.pl script that
# comes with SmartRF 
use IO::Socket::INET;
use Time::HiRes;
# Disable output buffering
$| = 1;
#Local port setup in TI SmartRF Packet Sniffer "Settings->Packet Broadcast"
$receiveSocketPort= 5000;
#Default UDP port for ZEP packet decoding in wireshark
$sendSocketPort = 17754;
#PC IP address running wireshark
$sendSocketIpAddress = '192.168.1.72';
# Create receiver socket to connect to TI tool
my $receiveSocket = IO::Socket::INET->new(
    Proto=>'udp',
    LocalPort=>$receiveSocketPort
) or die "Could not create socket: $!\n";
print "\nUDP Server: waiting for client on port $receiveSocketPort ...";
# Create socket to remote PC running wireshark
my $sendSocket = IO::Socket::INET->new(
    Proto    => 'udp',
    PeerPort => $sendSocketPort,
    PeerAddr => $sendSocketIpAddress,
) or die "Could not create socket: $!\n";
# Eventually it would be nice to imply channel from the port. 
# For example: use port 5012 for channel 12 and 5013 for channel
# 13 and then the deviceId could just be the port number
$chId = 12;
$deviceId = 0;
# counter for number of received packets from SmartRF tool.
$cnt= 1;
while(1)
{
    # Wait for received data
    $receiveSocket->recv($buffer,1024);
    $n = length $buffer;
    # Keep some simple debug print per packet to show that something is going on.
    print "\n $cnt received : $n bytes\n";
    #####################################################################################
    # Unpact the header from the TI CC2531 dongle
    #   This format is defined in Section 5 of SmartRF Packet Sniffer User Manual.pdf
    #####################################################################################
    $hdr_info                 = unpack("C", substr($buffer, 0, 1));
    $hdr_infoLenWithFcs       = ($hdr_info & 0x01);
    $hdr_infoCorrelationUsed  = (($hdr_info & 0x02) >> 1);
    $hdr_infoIncompletePacket = (($hdr_info & 0x04) >> 2);
    $hdr_number       = unpack("V", substr($buffer, 1, 4));
    $hdr_timeStamp    = unpack("Q", substr($buffer, 5, 8));
    $hdr_timeStampLsb = unpack("V", substr($buffer, 5, 4));
    $hdr_timeStampMsb = unpack("V", substr($buffer, 9, 4));
    $hdr_len          = unpack("C", substr($buffer, 13, 1));
    # Need to check info bit to see if FCS bytes are included in length
    $payload_len = $hdr_len;
    if( $hdr_infoLenWithFcs == 1 )
    {
        # Payload len includes FCS bytes so adjust the payload length
        $payload_len -= 2;
    }
    $payload            = substr($buffer, 14, $payload_len);
    $fcs                = substr($buffer, (14 + $payload_len), 2);
    $fcs_absRssi        = -73 + unpack("C", substr($fcs, 0, 1));
    $fcs_crcOk          = ((unpack("C", substr($fcs, 1, 1)) & 0x80) >> 7);
    $fcs_lqiCorrelation = (unpack("C", substr($fcs, 1, 1)) & 0x7F);
    # Some printouts to verify parsing was OK. Not really needed so
    # comment out for now
    #print sprintf( "Header \tInfo:0x%02X \n\tNumber:%u \n\tTimeStamp:%u \n\tLen:%u \n", $hdr_info, $hdr_number, $hdr_timeStamp, $hdr_len );
    #print sprintf( "RSSI:%2d CRC-OK:%d ", $fcs_absRssi, $fcs_crcOk );
    #if( $hdr_infoCorrelationUsed == 1 )
    #{
    #    print sprintf( "Correlation:%d\n", $fcs_lqiCorrelation );
    #}
    #else
    #{
    #    print sprintf( "LQI:%d\n", $fcs_lqiCorrelation );
    #}
    #####################################################################################
    # Start Building the ZEP header. Online documentation of this header is terrible.
    # I referenced source code from wireshark to get format. epan/dissectors/packet-zep.c
    #####################################################################################
    # Need to grab the MAC frame-type from the payload to figure out which
    # ZEP header to use. MAC frame type is the 3 lsb bits of the first byte
    # Reference 802.15.4 spec for bit-fields in MAC header.
    $macFrameType = (ord(substr($payload, 0, 1)) & 0x07);
    $macSeqNum    = ord(substr($payload, 2, 1));
    # Debug printout of frame type and payload contents.
    #print sprintf( "Payload: type:%d \n\t", $macFrameType );
    #for($i=0; $i<$payload_len; $i++ )
    #{
    #    print sprintf("%02X ", ord(substr($payload, $i, 1)));
    #}
    #print "\n";
    # ZEP packet decoder expects RSSI to be signed absolute dBm and TI dongle sends up
    # relative dB from -73dBm. FCS bytes are expected by wireshark at the tail end of
    # the packet and the ZEP length is expected to include these FCS bytes
    $zepFcs = pack("CC", $fcs_absRssi,  (($fcs_crcOk << 7) | $fcs_lqiCorrelation));
    # build different ZEP header depending on the mac frame type
    # originally I Build ZEPv2 header for ACK but I don't like the fact that you lose
    # the RSSI, Channel Number, and Device Id info. I want to support multiple devices/channels
    # so I want to see which channel/device the ack was received on. If you want to use ZEPv2
    # header for ACK then you need to drop the $payload and $zepFcs from the $zepPacket
    # and you probably want to replace the sequence number in the ZEPv2 header with teh MAC
    # sequence number so you can align the ack with the packet being ack'd
    # 
    if( $macFrameType == 2 )
    {
        # Build ZEPv1 header to get complete ACK info in wireshark
        $zepHdr_len = 16;
        $zepHdr = pack("aaCCnCCNnCC", 'E', 'X', 1, 
                       $chId, $deviceId, 0, $fcs_lqiCorrelation, 0, 0, 0, ($payload_len + 2) );
        $zepPacket = $zepHdr . $payload . $zepFcs;
        $zepPacketLen = ($zepHdr_len + $payload_len + 2);
    }
    else
    {
        # Build ZEPv2 header for data note: timestamp is probably bogus
        $zepHdr_len = 32;
        $zepHdr = pack("aaCCCnCCNNNQnC", 'E', 'X', 2,
                       $macFrameType, $chId, $deviceId, 0, $fcs_lqiCorrelation, $hdr_timeStampMsb, $hdr_timeStampLsb, $hdr_number, 0, 0, ($payload_len + 2) ); 
        $zepPacket = $zepHdr . $payload . $zepFcs;
        $zepPacketLen = ($zepHdr_len + $payload_len + 2);
    }
    #More debug printing.
    #for($i=0; $i<$zepPacketLen; $i++ )
    #{
    #    print sprintf("%02X ", ord(substr($zepPacket, $i, 1)));
    #}
    #print "\n";
    # Send properly formatted ZEP packet to PC running Wireshark.
    $sendSocket->send($zepPacket) or die "ZEP Packet Send error: $!\n";
    $cnt++;
}

Viewing all articles
Browse latest Browse all 116964

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>