This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Converting from TI RF Packet Sniffer Format (PSD) to PCAP Format

Other Parts Discussed in Thread: CC2531

1106.PSD_2_PCAP_Convert 1.0.0.zip

While working on a project, I put together a C++ program to convert files that are outputted from the TI Packet Sniffer program in PSD format to the PCAP format that can be used with Wireshark. I thought it might be useful to others, so I'm posting it here along with the source code under GNU General Public License. Functionality is pretty basic at this point and it runs on the command line.

Usage: PSD_2_PCAP_Convert <source PSD file> <destination PCAP file>

It has been tested under Windows XP and Windows 7 with output from the CC2531DK USB Dongle and seems to work. The only thing that appears to be lost is the packet checksum, which appears to have been replaced with signal strength info from the Sniffer program.

Hope it helps someone else out there,

Torrey Bievenour

Vision Quest Lighting, Inc.

  • Hi Torrey,

     

    This may be an old topic, but I would certainly want to use your C++ program that you shared here. However you left no readme file in the zip file for me to understand further.

    I was wondering can you tell me exactly how to use that program?

    When I double click the .exe file; I got an error message: "The application has failed to start because its side-by-side configuration is incorrect. Please see
    the application event log or use the command-line sxstrace.exe tool for more detail."


    Can you explain?

  • Denz,

    Sorry for not posting a README for this program. It is a pretty basic program and must be run from the command line. The syntax is:

    PSD_2_PCAP_Convert <input file name> <output file name>

    It was built in Visual Basic for Win32 targets. I have used it in Windows XP and Windows 7 environments. The problem that you're mentioning might have something to do with the Microsoft Visual C++ Redistributable. You can download one version of it here: http://www.microsoft.com/downloads/en/details.aspx?familyid=766a6af7-ec73-40ff-b072-9112bab119c2&displaylang=en (you can get to other versions from here too, not sure what would be the most appropriate)

    If you still have problems getting it working, let me know and I'll do my best to help you out.

    Torrey Bievenour

  • Hi Torrey,

    Thanks for replying. I was thinking you were no longer active here after waiting for 2 days. I'm really glad you did :)

    I've already followed your instructions and downloaded the Microsoft Visual C++ Redistributable. (Should I restart my PC? Cause I didn't) So here's the printscreen of the command I typed on my cmd screen (with various way of keying in the filename). And yet I'm still getting the same error after following your instructions.

    I'm attaching a sxstrace.exe output for running the command "C:\Users\Denz\Desktop\PSD_2_PCAP_Convert_Folder>PSD_2_PCAP_Convert.exe" on the cmd window. The attachment can be excess here: http://www.box.net/shared/15gsem2vfu1vx6ge1726

    Let me know if I'm missing any more steps, doing it wrongly or if you require more debugging log files that you may need

    I'm using a win7 machine by the way.

     

  • I'm not on here too often, so responses tend to take a day or two. I'd like to help you out as best I can though.

    I've recompiled the project and included CRT DLLs that others have indicated might be needed to run the app. Everything I can find about "side-by-side configuration" errors points to either VC++ redistributables like you installed or .NET. Although it probably shouldn't need .NET, we have .NET 3.5 and lower installed on all our machines (which makes things easier since most of our Windows development is done in Visual Studio).

    Give this updated build a shot (and just put all the files into the folder you are running from). If it doesn't work, please send the same debugging data as before and I'll check it out.

    - Torrey

    1524.PSD_2_PCAP_Convert.zip

  • Torrey,

    Seems to work with the DLL files that you have included and after you had recompiled!!

    I'm not sure whether it's working as expectantly though. On my wireshark screen, in the protocol column it only states "IEEE 802.15.4", not Zigbee.

    But no matter, i m going to investigate it again when I'm free.

    Thanks man!

  • Great! I'm glad to hear you've had success in getting this running.

    The IEEE 802.15.4/Zigbee protocol analyzer is somewhat new for Wireshark, so the level of analysis possible may vary depending on version. I opened a PCAP file (attached, a very basic establishment of a link between a node and coordinator) on Wireshark 1.2.9 and saw both IEEE 802.15.4 and Zigbee protocols recognized, although many more of the first. Since Zigbee operates under 802.15.4, I'm not sure where Wireshark draws the line between the two protocols. And I think if the analyzer doesn't recognize the specific "command", it just puts it in as 802.15.4 with a data string at the end. Hopefully higher versions of Wireshark (now up to 1.6.0) offer more support.

    Also keep in mind that, because the data is not available in the original file, the checksum will always fail, so every packet in Wireshark will show as "Bad FCS". I guess I could have calculated a fake correct one, but did not.

    Thanks,
    Torrey

     8713.Sniff1.zip

  • 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++;
    }
  • Hi All,

    This is a shameless plug for my attempt at solving this problem.

    I added two existing tools together to make one that reads from the USB packet sniffer and pipes to Wireshark.

    Get it here: https://github.com/andrewdodd/ccsniffpiper

    I hope it helps,

    Andrew

    PS. Torrey, your converter tool has been great value for me!

  • Just a small tip: you can actually run this script and the TI sniffer and wireshark all in the same PC. You just have to change the sendSocketIpAddress to a neighbour (i.e. an existing machine connected to the PC like e.g. the default gateway) and you will see the 802.15.4 traffic when monitoring with wireshark your interface.
  • I have translate the PSD_2_PCAP_Convert to ANSI C, so it does not need any library.

    It can be compiled on any platform, It uses the same GPL licence.

    I was uploading a zip file with PSD_2_PCAP_Convert.c and PSD_2_PCAP_Convert.exe comiled with MingW for Windows 32.

    I am not sure if the TI forum upload it correctly.

    In any case the  PSD_2_PCAP_Convert.c source code is follow.

    Erez

    psd2pcap.zip

    // PSD (TI RF Packet Sniffer Format) to PCAP Converter

    // Version 1.0.0

    // This program takes in a PSD file and converts it to PCAP format for use in programs like Wireshark.

    // Copyright (C) 2010 Torrey M. Bievenour

     

    //  This program is free software: you can redistribute it and/or modify

    //    it under the terms of the GNU General Public License as published by

    //    the Free Software Foundation, either version 3 of the License, or

    //    (at your option) any later version.

    //  This program is distributed in the hope that it will be useful,

    //    but WITHOUT ANY WARRANTY; without even the implied warranty of

    //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    //    See the GNU General Public License for more details.

    //  You should have received a copy of the GNU General Public License

    //    along with this program.  If not, see <http://www.gnu.org/licenses/>.

     

    // PSD_2_PCAP_Convert.cpp : Defines the entry point for the console application.

    // Convert to C to avoid using C++ libraries.

     

    #include <stdio.h>

    #include <stdlib.h>

    #include <stdint.h>

    #include <fcntl.h>

    #include <sys\stat.h>

     

    // const int PSD_Packet_Size = 151;

     

    struct PSD_Packet_s

    {

            uint8_t  Information;

            uint32_t Number;

            uint64_t Timestamp;

            uint8_t  Length;

            unsigned char Remainder[137]; // Based on fixed record size of 151 bytes

    };

     

    struct PCAP_Packet_Header_s

    {

            uint32_t ts_sec;

            uint32_t ts_usec;

            uint32_t incl_len;

            uint32_t orig_len;

    };

     

    uint64_t endian_swap64(uint64_t x)

    {

            return (x>>56) |

                   ((x<<40) & 0x00FF000000000000) |

                   ((x<<24) & 0x0000FF0000000000) |

                   ((x<<8) &  0x000000FF00000000) |

                   ((x>>8) &  0x00000000FF000000) |

                   ((x>>24) & 0x0000000000FF0000) |

                   ((x>>40) & 0x000000000000FF00) |

                   (x<<56);

    }

     

    uint32_t endian_swap32(uint32_t x)

    {

            return (x>>24) |

                   ((x<<8) & 0x00FF0000) |

                   ((x>>8) & 0x0000FF00) |

                   (x<<24);

    }

     

    int main(int argc, char* argv[])

    {

            if(argc != 3)

            {

                   printf("The function requires exactly two arguments, an input and an output file.\n");

                   return 1;

            }

            printf("Input File: %s\nOutput File: %s\n", argv[1], argv[2]);

     

            int inFile = open(argv[1], O_RDONLY | O_BINARY);

            if(inFile > 0)

            {

                   struct PSD_Packet_s inPacket; // Incoming PSD packet

                   struct PCAP_Packet_Header_s outPacket; // Outgoing PCAP packet header

     

                   int outFile = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);

                   if(outFile > 0)

                   {  // Write global header

                           uint32_t pcapMagicNumber = 0xa1b2c3d4; // Native byte ordering

                           uint16_t pcapVersionMajor = 2; // Current version is 2.4

                           uint16_t pcapVersionMinor = 4;

                           int32_t pcapThisZone = 0;    // GMT

                           uint32_t pcapSigFigs = 0;    // Zero value for sig figs as standard

                           uint32_t pcapSnapLen = 128;  // Max Zigbee packet length

                           uint32_t pcapNetwork = 0xC3; // Ethernet = 1, 802 Networks = 6, From Wireshark sample PCAP = 0xC3

                           write(outFile, &pcapMagicNumber, sizeof(pcapMagicNumber));

                           write(outFile, &pcapVersionMajor, sizeof(pcapVersionMajor));

                           write(outFile, &pcapVersionMinor, sizeof(pcapVersionMinor));

                           write(outFile, &pcapThisZone, sizeof(pcapThisZone));

                           write(outFile, &pcapSigFigs, sizeof(pcapSigFigs));

                           write(outFile, &pcapSnapLen, sizeof(pcapSnapLen));

                           write(outFile, &pcapNetwork, sizeof(pcapNetwork));

                   }

                   else

                   {

                           printf("Unable to open output file.\n");

                           close(inFile);

                           return 3;

                   }

     

                   while(read(inFile, &inPacket, sizeof(inPacket)) == sizeof(inPacket))

                   {

                           // Length of incoming actual packet data

                           uint8_t inPacketDataLength = inPacket.Length;

     

                           // Check Intformation byte to see if length includes FCS.

                           if(inPacket.Information & 0x01 == 0)

                                   inPacketDataLength += 2; // Add FCS to packet length

     

                           if(inPacketDataLength > 137)

                           {

                                   printf("Paket length is too big %d !!!\n", inPacketDataLength);

                                   inPacketDataLength = 137;

                           }

     

                           printf("Packet\n%d\n%d\n%d\n%d\n"

                                   "<STARTREMAIN>%p<ENDREMAIN>\n"

                                   "<STARTDATA>%x<ENDDATA>%x\n"

                                   "<STARTFCS>%x%x<ENDFCS>\n",

                                   inPacket.Information,

                                   inPacket.Number,

                                   inPacket.Timestamp,

                                   inPacket.Length,

                                   inPacket.Remainder,

                                   inPacket.Remainder[0],

                                   inPacket.Remainder[inPacketDataLength - 2],  // FCS1

                                   inPacket.Remainder[inPacketDataLength - 1]); // FCS2

     

                           // Write packet header

                           outPacket.ts_sec = inPacket.Timestamp / 1000000; // Convert to integer seconds

                           outPacket.ts_usec = inPacket.Timestamp - (outPacket.ts_sec * 1000000); // Pick up remainder

                           outPacket.incl_len = inPacketDataLength; // Get data length as included (include FCS)

                           outPacket.orig_len = inPacketDataLength; // Get data length as original (include FCS)

                           write(outFile, &outPacket, sizeof(outPacket));

                           // Write packet data

                           write(outFile, inPacket.Remainder, inPacketDataLength);

                   }

                   close(inFile);

                   close(outFile);

            }

            else

            {

                   printf("Unable to open input file.");

                   return 2;

            }

            return 0;

    }

     

  • Hi,
    I have tried this and only appear to have success when I retrieve the FCS when counting the start of the payload from byte offset 16. I still have issues with some packets (command packets), but at least now have distinction between data, command, ack and beacon frames. See my change below (it may require further work). One difference I could pick up in the documentation of my CC2531 is that the .psd format has the packet length two bytes in the header. According to this original article it was taken as one byte in the perl program.
    <snip>
    print sprintf("Generic sniffer used if = 1: value=%d", $hdr_infoIncompletePacket);
    $hdr_number = unpack("V", substr($buffer, 1, 4)); #32 bit little endian

    $hdr_timeStamp = unpack("Q", substr($buffer, 5, 8)); #unsigned 64 bit
    $hdr_timeStampLsb = unpack("V", substr($buffer, 5, 4));
    $hdr_timeStampMsb = unpack("V", substr($buffer, 9, 4));
    $hdr_len = unpack("C", substr($buffer, 13, 1));
    #$hdr_len = unpack("v", substr($buffer, 13, 2)); #vh

    # 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
    print "\n Payload len includes FCS\n";
    $payload_len -= 2;
    }
    $payload = substr($buffer, 16, $payload_len); // now start the payload at byte 16
    #$payload = substr($buffer, 15, $payload_len);

    $fcs = substr($buffer, (15 + $payload_len), 2);
    <snip>

  • Hello,

    I'm using the Packet Sniffer to get logs communications between my zigbee devices. The Logs are saved in PSD formate. I download this aplication to convert PSD files in PCAP files and the conversion was succedded. Although, when i open the PCAP file with Wireshark, i insert the TRUST CENTER LINK KEY in the zigbee protocol settings with authentication AES 128, 64bits, but the logs continous with "Malformed formate".
    Somewone can help me with this problema or can explain to me what I'm doing wrong.
    The wireshark version that I'm using is 2.2.6 (April 2017)

    Best regards

    Nalves