File Format of the Airopeek (Etherpeek) .apc Capture File rev. 9

By Dmitri Varsanofiev

This is a brute-force analysis (reading the files with the naked eye) of the new .apc file format (used in revision 2.0.1 of the Airopeek and V9 of EtherPeek, as well as OmniPeek). Sources of Ethereal were extremely helpful. Since I am only interested in 802.11 capture files, only this format has been analyzed by me - notes on the EtherPeek / OmniPeek versions of the format below belong to Guy Harris and Jeff Beaujon respectively. As of today, Ethereal  (0.10.0) apparently supports this file format - mission accomplished

Note that all integer fields in the file are in the Intel ("little endian", a.k.a. "hard to read") byte order - even if the capture has been done on a MAC.

Sections

File consists of three sections. Each section is prefixed with a 4-byte text tag:

Version Information

Starts with a 4-byte length of the section (including the length field itself) and a 4-byte field with value 00,02,00,00. This might be some signal for the UTF encoding - I do not know.

After that, plain XML text (AiroPeek example, lines terminated by CR):

<?xml version="1.0" encoding="UTF-8"?>
<VersionInfo>
    <FileVersion>9</FileVersion>
    <AppVersion>5.1.1.2</AppVersion>
    <ProdVersion>2.0.1.0</ProdVersion>
</VersionInfo>

Per Jeff Beaujon's information, the OmniPeek version information looks like:

<VersionInfo>
    <FileVersion>9</FileVersion>
    <AppVersion>6.0.0.30</AppVersion>
    <ProdVersion>4.0.1.0</ProdVersion>
</VersionInfo>

Session Information

Starts with a 4-byte length of the section (including the length field itself) and a 4-byte field with value 00,02,00,00.

After that, plain XML text:

<?xml version="1.0" encoding="UTF-8"?>
<Session>
    <RawTime>1066871103</RawTime>
    <Time>10/23/2003 01:05:03</Time>
    <TimeZoneBias>480</TimeZoneBias>
    <MediaType>0</MediaType>
    <MediaSubType>3</MediaSubType>
    <LinkSpeed>54000000</LinkSpeed>
    <PacketCount>6657</PacketCount>
    <Domain>1</Domain>
    <DataRates>
        <Rate>2</Rate>
        <Rate>4</Rate>
        <Rate>11</Rate>
        <Rate>12</Rate>
        <Rate>18</Rate>
        <Rate>22</Rate>
        <Rate>24</Rate>
        <Rate>36</Rate>
        <Rate>44</Rate>
        <Rate>48</Rate>
        <Rate>66</Rate>
        <Rate>72</Rate>
        <Rate>96</Rate>
        <Rate>108</Rate>
        <Rate>144</Rate>
        <Rate>192</Rate>
        <Rate>216</Rate>
    </DataRates>
    <ChannelList>
        <Channel>1</Channel>
        <Channel>2</Channel>
        <Channel>3</Channel>
        <Channel>4</Channel>
        <Channel>5</Channel>
        <Channel>6</Channel>
        <Channel>7</Channel>
        <Channel>8</Channel>
        <Channel>9</Channel>
        <Channel>10</Channel>
        <Channel>11</Channel>
        <Channel>36</Channel>
        <Channel>40</Channel>
        <Channel>42</Channel>
        <Channel>44</Channel>
        <Channel>48</Channel>
        <Channel>50</Channel>
        <Channel>52</Channel>
        <Channel>56</Channel>
        <Channel>58</Channel>
        <Channel>60</Channel>
        <Channel>64</Channel>
        <Channel>149</Channel>
        <Channel>153</Channel>
        <Channel>157</Channel>
        <Channel>161</Channel>
    </ChannelList>
</Session>

Some comments might be useful here:

Packets

Section contains captured frames prefixed by headers. The frames include the 4 bytes of 802.11 FCS (CRC) - these are also included in frame length. Note that the frame length is repeated twice, most likely to support "slices" (explanation by Guy Harris can be found below). Headers and frames have no alignment - header can start at the odd byte boundary.

Fields in the header are prefixed by a two-byte "tag" (I include it into length). A lot of info on headers came from Martin Regner.

Offset Length Tag Field
0 6 00,00 Frame length, including the FCS. This is the total frame length, smaller fragments ("slices") theoretically can happen after the header, but never were observed in the wild.
6 6 01,00 LSB of the time stamp. Resolution is 1 nanosecond.
12 6 02,00 MSB of the time stamp
18 6 03,00 "Flags and Status". Flags are in the first byte of the field (perhaps, two bytes in total), status is in the third (and, perhaps, fourth) bytes. Information from the chipset obtained on the reception.
Bitmask of Flags (hex):
01 = Control packet (ACK / RTS / CTS ...)
02 = CRC error (802.11 FCS failure)
04 = "Frame Error"
10 = "Trigger"
Bitmask of Status (hex):
02 = "Truncated"
04 = Encrypted
08 = Decryption Error (802.11 ICV failure)
20 = "Sliced"??? According to Martin Regner, this flag is not stored. Corresponding bit is triggered by FrameLength != SliceLength.
40 = Short 802.11b preamble
24 6 04,00 Channel number (1,2,3, etc.) as a 4-byte integer.
30 6 05,00 Rate in traditional 802.11 0.5 Mbps increments as a 4-byte integer (for example, 6 Mbps is encoded as 0C,00,00,00)
36 6 06,00 Signal level in % as a 4-byte integer. For example, (55,00,00,00) corresponds to 85% of the signal level.
42 6 07,00 Signal level in dBm as a 4-byte signed integer. For example, (DD,FF,FF,FF) corresponds to -35 dBm.
48 6 08,00 Noise level in % as a 4-byte integer. For example, (3D,00,00,00) corresponds to 61% of the noise level.
54 6 09,00 Noise level expressed in dBm as a 4-byte integer. Value equal to 01,80,FF,FF corresponds to "do not show". DD, FF, FF, FF corresponds to -35 dBm.
  6 0D,00 (optional) Per Jeff Beaujon, this is carrier frequency in MHz
60 6 ff,ff End field - slice length as a 4-byte integer. In every case I've seen this is simply the frame length. Frame (slice) body starts immediately afterwards.

Observation by Joshua Wright:

In the data immediately following the string "pkts" that defines the packet information for the file, I have 8 bytes of padding before the leading 2 bytes of the record (the other unknown field, always 0's, before the frame length).

Observations by Guy Harris:

[The Ethernet file format uses] only 0x0000 (frame length), 0x0001 (time stamp LSB), 0x0002 (time stamp MSB) 0x0003 (flags and status), 0x000D (zero), and 0xffff (slice length) ...  Each [Ethernet] packet appears to have 4 extra bytes of 0 at the end (not an FCS).

Observation by Jeff Beaujon:

000A, 000D, and 000E tags appear to be specific to captures saved with Omnipeek.

Slices

This explanation belongs to Guy Harris.

At least some capture programs support what some of those programs call "slicing" the frame, which means saving no more than the first N bytes of the frame, for a user-specified value of N. libpcap-based programs such as tcpdump/WinDump, Ethereal, and Analyzer support that notion, as does Sun's snoop and as do various capture programs for Windows.

The AiroPeek NX Quick Tour suggests that it does so - see page 2. There's a "Limit each packet to [] bytes" item in the "Capture Options" dialog box (Ethereal displays it similarly ... ), and they refer to that as a "packet slicing option".

I suspect that if a "Limit each packet to" value is specified when capturing, the total frame length will reflect how big the packet was on the wire (or on the air), while the length of the first slice will be the minimum of the total frame length and the "Limit each packet to..." value.

Observation by Jeff Beaujon:

[I needed to adjust] the frame length (tag 0000) after removing the IV field from the frame. I assumed that when I reduced the frame length I must also reduce the slice length (tag FFFF). This apparently is not the case since reducing the slice length corrupts the .apc file

Time Values

This guess also belongs to Guy Harris.

The time stamps appear to be in nanoseconds since the Windows FILETIME epoch, i.e. nanoseconds since midnight, January 1, 1601.

Open Questions

If you happen to find the answers to these, feel free to contact me at airopeek [AT] varsanofiev.com.

  1. Where are the fields (not yet seen in the wild :-)  tagged with 0B, 0C?
  2. What are the values of the fields tagged 0A and 0E?