Wireshark and BACnet MS/TP

I wrote an article about Analyzing BACnet with Wireshark for ASHRAE Journal special supplement BACnet Today.  ASHRAE is very particular about endorsing specific company products, and removed some references I had to information about how BACnet MS/TP can be supported on Wireshark by adding an external interface which sends Ethernet SNAP protocol packets.  The external interface was originally a Cimetrics U+4 device which connects BACnet MS/TP via USB to a computer, and uses a special driver to appear as a network interface to Wireshark.

In April, 2008, I was informed that the Cimetrics U+4 packets showed up in Wireshark, but were not decoded correctly.  I asked for a sample of the capture, and reverse engineered the header.  I then created the BACnet MS/TP decoding in Wireshark in order to display the MS/TP data, and passed the BACnet Network Layer and Application Layer information along to the existing dissectors.

The beauty of the BACnet protocol is that it is layered.  The NPDU (network layer) and APDU (application layer) encodings are the same regardless of the datalink layer used.  The NDPU layer is decoded by packet-bacnet.c, which passes the APDU layer to packet-bacapp.c.  The BACnet MS/TP datalink layer is decoded by packet-mstp.c which I created, and passes the NPDU, if it exists, to packet-bacnet.c, for decoding.  The ARCNET, Ethernet, and BACnet/IP (packet-bvlc.c) all pass a relevant packet to packet-bacnet.c for BACnet decoding.  I created packet-cimetrics.c for the Cimetrics header which passes the BACnet MS/TP datalink layer to packet-mstp.c.

The BACnet MS/TP patches were accepted into the Wireshark repository on May 13, 2008, checked in as SVN 25291.  The SVN 25881 was a fix to the Length decoding.  The BACnet MS/TP decoding eventually made it into the Wireshark 1.1 development release, but is not present in the Wireshark 1.0 stable release.

Wireshark now sees packets with the Cimetrics U+4 signature encapsulated in the SNAP protocol as MS/TP packets, and it is able to open a file that has been saved in PCAP format using the MS/TP WTAP signature.  But I didn’t have a Cimetrics U+4 device.  So I used a standard RS485 converter, my open source BACnet stack, and wrote a simple application to packetize the MS/TP frames and saves them to PCAP format.  I could now capture MS/TP packets and view them!

In August, 2008, I received an email from John in New Zealand.  His intention was “to use an existing simple VB application that captures MS/TP traffic from a low cost USB to RS-485 converter, to send the MS/TP packets using Winsock/UDP to Wireshark for final dissection and display.”  I figured that we could do this by making use of the existing SNAP protocol dissector that I created for the Cimetrics packets.

I reused the code that I had written to save in PCAP format, and wrote a simple application to packetize the MS/TP frames and resend them on Ethernet as the Cimetrics U+4 signature encapsulated in the SNAP protocol.  I got it to work under Linux, but would probably need to use WinPcap to get it to work under Windows.

Sending those SNAP protocol packets on Ethernet allows the display of BACnet MS/TP packets in realtime alongside BACnet/IP and BACnet Ethernet.  This makes it very easy to relate traffic going to and from workstations and routers with what is happening on the BACnet MS/TP network.

There are some sample captures (see cimetrics_mstp.pcap and mstp_wtap.cap) that demostrate some of the abilities of Wireshark.

I use a USB to RS-485 converter from SerialGear USB-COMi-SI-M, and am told that the B&B Electronics USOPTL4 works very well.  I am also told that the USB to RS-485 adapters that use the FTDI chipset are great for this as they allow the use of 76800 baud which is usually the stumbling block for native MS/TP interfacing with a standard PC serial port.

About skarg

I write software for a living. So, I dedicated some web space for some stuff that I have worked on. I mostly write embedded C for PC based controllers, but I have dabbled in a few other areas as well.
This entry was posted in BACnet. Bookmark the permalink.

42 Responses to Wireshark and BACnet MS/TP

  1. Hello

    I did something similar. Not as cool as your solution.
    I didn’t want to buy any new hardware and I only had about 12hrs to get it working and use it to fix my system. So it quick and dirty.

    I created a little command line application that takes the MSTP frames with APDUs and encapsulates them in BACnet Eth packets. using the Ethernet frames MAC address for the MSTP MAC address. Then sent them out the port, looped it back and captured it with wireshark.

    Timing is a little off but not by much, and it Worked!

  2. Langstein says:

    Is a super idea mstp-way communication in wireshark. I find on the internet but so far only the version 1.0.8. In Sourceforge, however, is the speech of 1.1.0. Why is this getting?

  3. skarg says:

    The 1.0.x is the stable release of Wireshark, and the Wireshark team only wants bug fixes, not new features in it.

    So the new BACnet MS/TP decoding feature is still in the 1.1.x development branch until 1.1.x becomes the stable release.
    or specifically for Windows:

  4. Controls-Man says:

    From what I understand, to get WireShark 1.1.x to recieve the MS/TP data, a separate application needs to be built to packetize the data to get them on Ethernet. It looks like you made one for Linux. Do you have one for Windows using WinPcap or know where I could find one?

    Thanks in advance!

  5. skarg says:

    Today I added Win32 binary releases of mstpcap (along with the other BACnet/IP tools) to the BACnet Protocol Stack project hosted on SourceForge.net.

    The mstpcap tool stores the packets to a file (named with the current date and time), and puts up to 65535 packets into a single file. A new file is created when the file is full, or when mstpcap is first started.

    I have not tried to create an mstpsnap for Win32 with WinPcap.

  6. Andrej says:

    I used BACnet/IP to BACnet MS/TP Router (cimetrics e+ series), wich I conected with PC. On Router. I has connected mstp master deviece with this router. I wont use Wireshark to read BACnet MS/TP-Frames.
    Is it possible?How?

  7. skarg says:

    I don’t know of a way to read the BACnet MS/TP frames through that router. BACnet routers usually just “route” packets, and most of the MS/TP frames don’t get routed (token, poll-for-master, reply-to-poll-for-master, test-request, test-response, reply-postponed) You will need to add an RS485 card/converter to use the mstpcap utility and see the BACnet MS/TP frames.

  8. Andrej says:

    Hello Mr. Karg.

    I have ICP CON 7561 USB to RS485 converter.
    This converter uses the USB interface to conect with PC.

    And other converter to connect mstp-bus to serial interface.

    I can see the beatstream over HyperTerminal (serail interface (COMx)).

    It is possible to connect Wireshark on Serial Port an decode the beatsream?

  9. skarg says:

    Hello Andrej,

    To decode the serial port directly under Wireshark requires a driver that packetizes the serial stream, and makes the packets available as a network interface. I have not done any drivers like that for Linux (line discipline driver) or Windows.

    However, it is still possible to use mstpcap to capture the Serial Port stream, which packetize it into a file. Then open that file with Wireshark to view the MS/TP messages. It is also possible (at least under Linux currently) to use mstpsnap to capture the Serial Port stream and send it out on an Ethernet port and monitor the capture in realtime with Wireshark.

    Perhaps there will be better solutions (i.e. Wireshark Remote) for serial packet captures in the future that work on all platforms.

  10. Controls-Man says:


    I have to give you a big THANKS for the mstpcap-Wireshark 1.1.x development combo. It works GREAT! Using Wireshark filters work wonderful with your mstpcap tool.

    Thanks again!

  11. Kevin Edison says:

    It looks like it is a great tool, but when I run mstpcap in Windows, I receive an error: “Unable to open COM4”. Is there a way to specify the COM port? Is there some documentation that I am missing? Thanks!

  12. skarg says:

    from the demo/mstpcap/readme.txt file in the source code:

    BACnet MS/TP Capture Tool

    This tool captures BACnet MS/TP packets on an RS485 serial interface,
    and saves the packets to a file in Wireshark PCAP format for
    the BACnet MS/TP dissector to read. The filename has a date and time
    code in it, and will contain up to 65535 packets. A new file
    will be created at each 65535 packet interval. The tool can
    be stopped by using Control-C.

    Here is a sample of the tool running (use CTRL-C to quit).
    D:\code\bacnet-stack\bin>mstpcap COM3 38400
    Adjusted interface name to \\.\COM3
    mstpcap: Using \\.\COM3 for capture at 38400 bps.
    mstpcap: saving capture to mstp_20090729123548.cap
    1400 packets
    MAC MaxMstr Tokens Retries Treply Tusage Trpfm Tder Tpostpd
    0 0 525 0 32 0 0 0 0
    1 127 525 0 16 79 0 0 0

    The BACnet MS/TP capture tool also includes statistics which are
    listed for any MAC addresses found passing a token,
    or any MAC address replying to a DER message.
    The statistics are emitted when Control-C is pressed, or when
    65535 packets are captured and the new file is created.
    The statistics are cleared when the new file is created.

    MaxMstr = highest destination MAC address during PFM

    Tokens = number of tokens transmitted by this MAC address.

    Retries = number of second tokens sent to this MAC address.

    Treply = maximum number of milliseconds it took to reply with
    a token after receiving a token. Treply is required to be less
    than 25ms (but the mstpcap tool may not have that good of
    resolution on Windows).

    Tusage = the maximum number of milliseconds the
    device waits for a ReplyToPollForMaster or Token retry.
    Tusage is required to be between 20ms and 100ms.

    Trpfm = maximum number of milliseconds to respond to PFM with RPFM. It is
    required to be less than 25ms.

    Tder = maximum number of milliseconds that a device takes to
    respond to a DataExpectingReply request. Tder is required to be less
    than 250ms.

    Tpostpd = maximum number of milliseconds to respond to
    DataExpectingReply request with ReplyPostponed. Tpostpd is
    required to be less than 250ms.

    Note that the mstpcap tool may not have that good of
    resolution on Windows, so timing under 50ms may not be accurate.

  13. David says:

    Hola, alguien sabe de casualidad donde puedo encontrar informacion sobre el protocolo Bacnet? lo que quiero saber es como se envian los paquetes, como codificarlos y decodificarlos, el formato que tiene, etc.


  14. skarg says:

    David asks “Hi, anyone know by chance where I can find information about the protocol Bacnet? I want to know is how to send packets as encoding and decoding, the format has, etc..”.

    The official information is the ASHRAE 135-2008 BACnet standard, available from ashrae.org bookstore. You can use the open source BACnet stack or Wireshark to see how we have encoded and decoded the various services and data in BACnet.

  15. mike says:

    how to find out the encapsulation process of packets captured in wireshark?

  16. skarg says:

    The application code for the mstpcap utility shows the encapsulation process for a PCAP file format for a WTAP. See the write_global_header() and write_received_packet() functions.

    The magic is partly the data link type in the header:
    uint32_t network = 165; /* data link type – BACNET_MS_TP */

  17. Jochen says:

    We tried to get the 76800 to work with a FTDI chipset. We tried “mstpcap COM9 76800” but the mstpcap tells:
    mstpcap: Using \\.\COM9 for capture at 38400 bps.

    Do have an idea what is going wrong?

  18. skarg says:

    Hi Jochen,

    The 76800 is a non-standard baud rate (for personal computers, anyway), and the mstpcap tool is just using the computers serial port for communication. However, some chipset drivers, like FTDI, allow you to create a non-standard baud rate at one of the PC standard baud rates (i.e. 300 baud is now 76800). From the mstpcap.txt file:

    If you are using FTDI chip in your RS485 converter, you can alias an existing baud rate on Windows in the FTDIPORT.INF file in order to acheive non-standard 76800 bps:

    replace the 10,27,00,00 => divisor = 10000, rate = 300 bps alias

    hex values actual
    ———– ———
    27,C0,00,00 – 76923 bps => divisor=39.125
    27,00,00,00 – 76677 bps => divisor=39.000

    Then you would run:
    mstpcap COM9 300

    Note that earlier versions of mstpcap had only the standard MS/TP valid baud rates allowed. The current released version allows any of the standard computer baud rates to be used.

  19. Kris says:

    I’m not understanding how to use 76800 baud rate. Can you please show me what the “HRK,,”ConfigData” line should look like to make an alias where 300 baud is really 76800?


  20. skarg says:

    Here is a procedure that Chad Z. gave me for using the 76800 baud rate by faking a 300 baud entry on FTDI chip-set converters:
    1. Delete COM port in Device Manager
    2. Unplug USB dongle
    3. Delete the following files that are installed by FTDI.
    4. Copy the original ftdiport.ini to another name or location
    5. Edit the ftdiport.ini file and change the ConfigData value.

    for 300bps = 76677 bps:


    for 300bps = 76923 bps:

    6. Plug USB dongle back in and always select “Have Disk” and navigate to ftdibus.inf or ftdiport.inf files which should be in the same folder.

  21. Kris says:


    In case someone else has problems, I also had to get the latest VCP driver from FTDI’s site to get it to work. The latest driver SerialGear had would not work for me.

    Thanks again for all of the great information.

  22. Trevor says:

    I have been trying to get this to work for a little while now and it seems like its my capture program that isn’t working right. When I type in 300 it auto bauds to the 38400 and doesn’t even try to fake the 76800 at 300. I was wondering where I can get the capture program that allows 300 capture.

  23. skarg says:

    The latest mstpcap utility and friends is available at the BACnet Protocol Stack site hosted by SourceForge.net. Since we still update various things in the tools and in the stack, the download link is a moving target. It is currently at 0.6.0, and can be found here:

    One of the handy things that mstpcap does is display some capture statistics, and so we added the ability to scan an existing capture file and produce those statistics again. The option is “–scan” followed by a space and a capture file name.

    I also improved the timing resolution to 1ms on Windows.

  24. Michel D says:

    In the main.c file of the mstpcap project, there is an ordering function call problem in the main routine.

    The function RS485_Initialize() is called before the RS485_Set_Baud_Rate(). This is why even you want to set the port to an other baud rate than 38400, it always takes the 38400 baud rate.

    Just put the RS485_Set_Baud_Rate() before the RS485_Initialize() function and it will do the good job.

  25. Michel D says:

    I forgot to say that this problem is in the V0.6.0

  26. skarg says:

    Thanks for the bug report/fix on the baud rate problem. I have corrected it in the svn repository, and will release new binaries soon.

  27. Peter says:

    I’ve modified the program to allow the selection of 76800 as a baud rate as it will work directly with some serial port drivers.
    I use the USOPTL4 and it will work for the most part with that – I do get some receive errors on the port which are not being seen by my devices or the router which mey be down to a problem with my hardware setup or the USOPTL4 baud rate not being close enough to 76800 for comfort.

  28. skarg says:

    The latest mstpcap utility and BACnet/IP command line utilities are available at the BACnet Protocol Stack site hosted by SourceForge.net. Since we still update various things in the tools and in the stack, the download link is a moving target. It is currently at 0.7.1, and can be found here:

  29. Paul Cushing says:

    I made a little batch file to ask for the com port and baud rate and then run the mstpcap with them. Here it is if you’re interested:


    ECHO =============================
    ECHO ^| ^|
    ECHO ^| Run MSTP Capture Tool ^|
    ECHO ^| ^|
    ECHO =============================
    ECHO Press CTRL-C to finish capture
    set /p choice=”Enter your COM port (5): ”
    set /p choice2=”Enter your baud rate (38400): ”
    if “%choice%”==”” (set choice=5)
    if “%choice2%”==”” (set choice2=38400)
    mstpcap.exe COM%choice% %choice2%

    This just saves me from having to go to the DOS box and remember where I put the program. Put this in the folder with the program and add a shortcut to the batch file on the desktop for ease of use.

    Thanks for the tool. It works great for me.

  30. flori says:

    Is there any scheme or general rule how to decode a MS/TP raw frame? In more than 600 pages of the bacnet standard there does not exist a single example of decoding a whole frame. 600 pages without real examples….yes.

  31. skarg says:

    I have been working on a document “Understanding BACnet MS/TP Encoding” borrowed heavily from the existing document on http://www.bacnet.org that shows the encoding for ARCNET and PTP. I’m 1/3 of the way through converting all the text and examples to MS/TP, but have not had any time in the last dozen months to finish it. I even wrote a tool (bacnet-stack/demo/mstpcrc/) to help with the examples. Wireshark can also help with decoding.

    Here is one example from the document:

    The Who-Is and I-Am services are described in clause 16.10. The ASN.1 definition of these services is in clause 21. Who-Is and I-Am are Unconfirmed services. A BACnet-Unconfirmed-Request-PDU is defined in clause 20.1.3 as a service-choice followed by a service-request. The comment states that tags are not used in the header encoding. Header encoding for BACnet-Unconfirmed-Request-PDU is shown in clause

    The service-choice is defined to be of type BACnetUnconfirmedServiceChoice, which is defined in Clause 21 as an enumeration. The service-choice value for who-Is is 8.

    The service-request is defined to be of type BACnetUnconfirmedServiceRequest, which is defined in Clause 21. The CHOICE for who-Is is the production Who-Is-Request, which is defined in Clause 21 as a SEQUENCE consisting of an OPTIONAL pair of unsigned integers which specify the range of devices which should respond. The encoding of an unsigned integer is defined in clause 20.2.4. In this example, the integers are absent, meaning (according to clause 16.9.2) that all devices should respond with I-Am.

    In the example which follows, the network header specifies a global broadcast (DNET 0xFFFF, DADR of length 0). The network header contains no source network or address for the requester, as the requester is assumed in this example to reside on the same MS/TP network where the request is observed.

    Note that Unconfirmed services on MS/TP use a BACnet Data Not Expecting Reply frame, and the node must wait for a Token frame before sending this type of frame.


    MS/TP header
    0x55 Preamble
    0xFF Preamble
    0x06 Frame Type: BACnet Data Not Expecting Reply (6)
    0xFF Destination station address (broadcast)
    0x01 Source station address
    0x00 Data Length = 21
    0x8E Header CRC

    0x01 Network protocol version
    0x20 Network control octet (clause 6.2.2)
    Bit7 = 0 “BACnet APDU”
    Bit6 = 0 not used
    Bit5 = 1 DNET present
    Bit4 = 0 not used
    Bit3 = 0 SNET not present
    Bit2 = 0 no reply expected
    Bit1,0 = 00 normal priority
    0xFF DNET 65535 (broadcast)
    0x00 DLEN 0 (denotes broadcast)
    0xFF Hop Count 255 (clause 6.2.3)
    0x10 APDU type 1: Unconfirmed Request
    0x08 Service Choice 8: Who Is
    No Tagged Service parameters for this example

    0x15 Data CRC-16

  32. flori says:

    Thank you for your fast reply.
    The data part of the frame is the problem. I bought a bacnet to modbus gateway and I’m using wireshark to decode the bacnet frames. The Object Analog Input captured does not have all the all the property identifiers listed as R or W, but only 4: Object identifier, Present value, Status flags, Reliability.
    Check this reply frame please:

    0000 55 ff 06 00 02 00 22 c6 01 00 30 26 0e 0c 00 00
    0010 00 01 1e 29 55 4e 44 40 c0 00 00 4f 29 6f 4e 82
    0020 04 00 4f 29 67 4e 91 00 4f 1f 20 60

    06-expecting reply
    00-destination address
    02-source address
    c6-header crc
    30- APDU type and PDU Flags (complex ack)
    26-Invoke ID
    0e-Service choice readPropertyMultiple
    0c00000001- Object identifier analog input 1
    1e-Tag class 1, context tag number 1, opening tag
    2955- property ID Present Value + tag
    4440c00000-present value
    What are all those tags for? Are they necessary?
    Can a simple-ack be used to reply insdead of a complex-ack, as it is now?
    The slave’s address is set into the master, like in modbus? Since the slave does not talk if not interrogated can’t send messages like “I am”.

  33. skarg says:

    The MSTPCRC tool can take arbitrary hex-ascii and save it to Wireshark PCAP format, and the result can be viewed in Wireshark. The mstpcrc tool is included in the bundle of files available for download at:

    d:\code\bacnet-stack\bin>mstpcrc -m 55 ff 06 00 02 00 22 c6 01 00 30 26 0e 0c 00
    00 00 01 1e 29 55 4e 44 40 c0 00 00 4f 29 6f 4e 82 04 00 4f 29 67 4e 91 00 4f 1
    f 20 60
    mstpcap: saving capture to mstp_20130320130852.cap

    The tags are BACnet’s way of encoding values and service options on the wire. They are necessary.

    Each BACnet service defines the Result(+) that is expected, and a Simple-Ack is only permitted for certain services such as WriteProperty. So no, a SimpleACK cannot be used instead of a CompexACK.

    A Slave Node could send I-Am if a WhoIs was unicast with DataExpectingReply frame, but that is not how WhoIs is defined. Therefore, a Slave Node cannot send I-Am since it cannot have the Token.

  34. flori says:

    Thank you again.
    Again about tags. What does it mean “application tag” and “context specific tag”? What’s the difference? I’m sorry to bother you, but the standard it is not written in a simple and clear way.
    And a hint, please. For my job is much more simple to implement a slave than a master bacnet node. Which is the best solution? Can you also suggest me a valid PC basted Bacnet master software to test the slave? I bought a Babel Buster gateway, but it does not handle slave nodes, master only.
    Thank you

  35. skarg says:

    The BACnet Standard (ASHRAE/ANSI 135) explains about tags in Clause 20.2, including how to encode them and decode them. From BACnet:

    20.2 Encoding the Variable Part of BACnet APDUs
    The encoding of the header portions of BACnet APDUs has been specified in 20.1. This subclause describes the encoding
    procedures for the variable portion of BACnet APDUs referred to hereafter as “service parameters.” These parameters are of
    types BACnet-Confirmed-Service-Request, BACnet-Unconfirmed-Service-Request, BACnet-Confirmed-Service-ACK, and
    BACnet-Error. Each parameter is unambiguously defined by means of ASN.1 productions in Clause 21.
    All data elements in service parameters are identified by constructs known as “tags.” Each tag refers to a unique parameter or
    BACnet encoding uses two classes of tag. The first identifies fundamental datatypes used or defined in this standard, such as
    BOOLEANs, Unsigneds, CharacterStrings, Date, Time, or BACnetObjectIdentifiers. Where a datatype appears in upper case, its
    semantics are identical to the corresponding ASN.1 universal datatype of the same name, as indicated in Clause 21.
    Such tags are called “application” tags, and the values of the tags are specified in
    The second class of tag is used to identify data elements whose datatype may be inferred from the context in which they appear.
    These tags are called “context specific” tags.
    ASN.1 defines two other classes of tags, “universal” and “private.” The encoding scheme used by BACnet does not allow, nor
    do any BACnet ASN.1 productions require, the use of these classes of tags.
    In some instances, the datatype of a parameter cannot be deduced from the context in which it appears. In such cases, both a
    context specific and one or more application tags are required. These cases are indicated in the ASN.1 productions by service
    parameters whose datatypes are indicated by the keywords ABSTRACT-SYNTAX.&TYPE (ANY), CHOICE, SEQUENCE, or
    The subclauses that follow show how each tagged element is identified, its length specified, and its value encoded.

  36. Annie Johnson says:

    Dear Steve,

    I came across your site while searching for a method to read / capture serial port (RS232) data which I could later open in winshark. It looks like your program does just that but I dont have any experience in C so I wanted to confirm if this is indeed the case? Does your program capture all the data on the specified serial port and save it as a PCAP file which can be opened in wiershark?

    Also I dont know how and where your program will save serial (RS232) port output as a file in windows 7 and how and where to specify COM port and its baud rate etc in your program. A bit of guidance will be really appreciated.

    Kind Regards

  37. Joel says:

    Is there anyway to do this for ModbusRTU with wireshark?

  38. Pingback: Best Practices for Capturing Packets to use in Visual BACnet – Visual BACnet

  39. Pingback: Best Practices for Capturing Packets to use in Visual BACnet

  40. Pingback: How Healthy is your MS/TP Network? - Visual BACnet

  41. Chris says:

    Hi Steve, as a BACnet integrator who often needs to analyze network traffic I have found your mstpcap tool incredibly useful. Thank you for your work on this, truly good work. Currently to sniff the MSTP network I connect a USB to 485 converter to my laptop, connect to the network, run the mstp cap then go to wireshark to open the saved file. (Im using windows by the way) However i find myself wanting/needing to see the packets coming into wireshark live or at least in a continuous stream instead of constantly re opening the saved file that mstpcap creates. I have read in the text file in the bacnet tools folder about using a named pipe to bring the capture directly into wireshark? Could you explain how to set the named pipe up and get the packets flowing directly to wireshark? Or is extcap the way to go to get the packets going direct to wireshark?

    Thanks for any help you can provide,


  42. skarg says:

    extcap is the way to go since it uses a named pipe in a standard and easy to use manner.

Leave a Reply

Your email address will not be published. Required fields are marked *