Wireshark mailing list archives

Re: [tcpdump-workers] What's the difference between NdisMediumBare80211 (DLT_IEEE802_11) and NdisMediumRadio80211 (DLT_IEEE802_11_RADIO)


From: Yang Luo <hsluoyb () gmail com>
Date: Sun, 10 Apr 2016 10:15:40 +0800

Hi Guy,

I have fixed the bugs you pointed out:
https://github.com/nmap/npcap/commit/244e81226e99944f6bd4c12d713e97cb59139ec0

And I have also finished the radiotap "Rate" header. The looking up code is
like:

------------------------------------------------------------
USHORT
NPF_LookUpDataRateMappingTable(
IN POPEN_INSTANCE pOpen,
IN UCHAR ucDataRate
)
{
UINT i;
PDOT11_DATA_RATE_MAPPING_TABLE pTable = &pOpen->DataRateMappingTable;
USHORT usRetDataRateValue = 0;
TRACE_ENTER();

if (!pOpen->HasDataRateMappingTable)
{
TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Data rate mapping table not found, Open
= %p\n", pOpen);
TRACE_EXIT();
return usRetDataRateValue;
}

for (i = 0; i < pTable->uDataRateMappingLength; i ++)
{
if (pTable->DataRateMappingEntries[i].ucDataRateIndex == ucDataRate)
{
usRetDataRateValue = pTable->DataRateMappingEntries[i].usDataRateValue;
break;
}
}

TRACE_EXIT();
return usRetDataRateValue;
}
#endif
------------------------------------------------------------

And there's also a truncation from usDataRateValue (16 bits) to Radiotap
"Rate" field (8 bits). I hope a direct assignment is OK:
*((UCHAR*)Dot11RadiotapHeader + cur) = (UCHAR) usDataRateValue;

My capture result is like:
Data Rate: 22.0 Mb/s

My network speed is usually 10Mb/s - 100Mb/s. So I believe this is a valid
result.

And I also found the "SSI Signal" can be many values in my capture: -57
dBm, -91 dBm, -10 dBm, -94 dBm.
So I think it's somewhat meaningful too.


AFAIK, the radiotap feature is finished now. The software is:
https://github.com/nmap/npcap/releases/download/v0.06-r14/npcap-nmap-0.06-r14-wifi2.exe


Cheers,
Yang


On Sat, Apr 9, 2016 at 3:32 PM, Guy Harris <guy () alum mit edu> wrote:

On Apr 8, 2016, at 9:25 PM, Yang Luo <hsluoyb () gmail com> wrote:

On Thu, Apr 7, 2016 at 9:37 AM, Guy Harris <guy () alum mit edu> wrote:

   provide a radiotap Flags field with 0x10 set if the frame includes
the FCS (you'll probably have to experiment a bit to see whether you get
the FCS or not - the answer might differ for data and management frames,
based on Network Monitor's behavior) and with 0x40 set if
DOT11_RECV_FLAG_RAW_PACKET_FCS_FAILURE is set in uReceiveFlags;

FCS is the suffix 4 bytes of a packet. Actually I didn't see those 4
bytes in the packets (only 802.11 data for now) using Wireshark (captured
by npcap-nmap-0.06-r13-wifi.exe). So I'm afraid  it's the case that I can't
get FCS for data frames? As I didn't start the work of capturing management
frames yet. it will not be considered for now.

So I think I will just leave FLags field with 0x00 then.

Yes, that's the right thing to do.

   provide a radiotap Channel field where the frequency value is the
uChCenterFrequency field of the structure and the flags are derived from
the uChCenterFrequency and uPhyId fields of the structure - assuming that
the uPhyId value is one of the ones from


https://msdn.microsoft.com/en-us/library/windows/hardware/ff548741(v=vs.85).aspx

   then the mapping would be:

        dot11_phy_type_fhss - set 0x0800 in the flags (11 legacy FHSS);

        dot11_phy_type_ofdm - set 0x0040 in the flags (11a);

        dot11_phy_type_hrdsss - set 0x0020 in the flags (11b);

        dot11_phy_type_erp - set 0x0040 in the flags (11g, unknown
whether it's pure or not);

   and, unless it's dot11_phy_type_irbaseband, set 0x0100 if the
frequency is in the 5 GHz range or set 0x0080 if it's in the 2.4 GHz range;

How to determine if uChCenterFrequency is 5GHz or 2.4GHz? What about the
following conditions?
if (pwInfo->uChCenterFrequency == 5000)
and
if (pwInfo->uChCenterFrequency == 2400)

No, it's a range, not a value.  A test we use in Wireshark for CommView
files is to check whether the center frequency is > 2484, so do

        if (pwInfo->uChCenterFrequency > 2484)
                5 GHz band;
        else
                2.4 GHz band;

Also I found the frequency of Radiotap "Channel" field is 16bit, but
uChCenterFrequency is a ULONG type (32bit). They are both MHz unit. I hope
a direct assignment is OK?

It's OK for now, but 2^16 MHz is 65 GHz, and there's apparently some
discussion of 60 GHz wireless communication, so, while a 16-bit frequency
field might not become a problem in the short term, it might become a
problem later.  That'd require a change to radiotap.

If the frequency is > 65535 MHz, I'd leave the channel field out.

   provide a radiotap Antenna signal field whose value is the value of
the lRSSI field in the structure;

Again a size truncating issue. I found radiotap Antenna signal field is
8bit. And pwInfo->lRSSI is a LONG type (32bit). is a direct assignment OK?

100 dBm is 10,000,000,000 milliwatts, at least if I'm interpreting

        https://en.wikipedia.org/wiki/Decibel

correctly, so that's 10,000,000 watts.

I *really* would not want to be anywhere near a Wi-Fi station transmitting
at that power level. :-)

-100 dBm is 1/10,000,000,000 milliwatts, which is .1 picowatt; I'm not a
radio expert, but I suspect there might not be any radios capable of
detecting that low a power level except in specialized physics or radio
astronomy cases.  (It's 1/10th the power consumption of an average human
cell:


https://en.wikipedia.org/wiki/Orders_of_magnitude_(power)#Picowatt_.2810.E2.88.9212_watt.29

so it's not much power.)

So I don't think you have to worry about a dBm power level that doesn't
fit in 8 bits.  You should leave out the antenna signal field if the value
doesn't fit in 8 bits.

   if the phy is dot11_phy_type_ht, provide a radiotap MCS field where
the known field is 0 and the other fields are also zeroed out (i.e., it's
11n, but we don't know anything else about it);

   if the phy is dot11_phy_type_vht, provide a radiotap VHT field where
the known field is 0 and the other fields are also zeroed out (i.e., it's
11ac, but we don't know anything else about it).

So simply speaking, if phy is dot11_phy_type_ht, then MCS field (3
bytes) all zero.
If phy is dot11_phy_type_vht, then VHT field (12 bytes) all zero.

Yes.  It would nice if Microsoft were to specify, and vendors' drivers
were to supply, more information, but at least supplying "empty" MCS and
VHT fields will let the program processing the capture know that the packet
was an HT or VHT packet.

Also, another question is, how large buffer is needed at most for the
whole Radiotap header (including Radiotap data)?
Like the below code, I allocated a buffer of 256 bytes. I don't know if
this is enough big. Or if there are any better handle ways?

The beginning of the radiotap header is 8 bytes.

Then the fields you'd supply, if *all* the fields were present, would be:

        TSFT: 8 bytes

        Flags: 1 byte

        Rate: 1 byte

        Channel: 4 bytes

        Antenna signal: 1 byte, plus 1 byte of alignment *if* this is a
VHT frame

        MCS or VHT: MCS = 12 bytes, VHT = 12 bytes

so the largest radiotap header you'd supply would be 8+8+1+1+4+2+12 = 36
bytes.

For now, all the code about the Radiotap is here:
---------------------------------------------------------------

                      PDOT11_EXTSTA_RECV_CONTEXT  pwInfo;
                      IEEE80211_RADIOTAP_HEADER RadiotapHeader = { 0 };

                      CHAR buf[256];
                      int cur = 0;

You should actually initialize it to 8, to leave room for the
IEEE80211_RADIOTAP_HEADER at the beginning.

It's probably easiest to construct the IEEE80211_RADIOTAP_HEADER while
you're filling in the rest of the radiotap header, and then copy it in
place at the end.

                      // [Radiotap] "Flags" field.

                      if (TRUE) // The packet doesn't have FCS. We
always have no FCS for all packets currently.
                      {
                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_FLAGS;
                              *((UCHAR*)buf + cur) = 0x0; // 0x0: none
                              cur += sizeof(UCHAR) / sizeof(UCHAR);
                      }
                      else // The packet has FCS.
                      {
                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_FLAGS;
                              *((UCHAR*)buf + cur) = 0x10; // 0x10:
frame includes FCS

                              // FCS check fails.
                              if ((pwInfo->uReceiveFlags &
DOT11_RECV_FLAG_RAW_PACKET_FCS_FAILURE) ==
DOT11_RECV_FLAG_RAW_PACKET_FCS_FAILURE)
                              {
                                      *((UCHAR*)buf + cur) |= 0x40; //
0x40: frame failed FCS check
                              }

                              cur += sizeof(UCHAR) / sizeof(UCHAR);
                      }

You're providing a Flags field in all cases, so I'd just do

                        // [Radiotap] "Flags" field.
                        RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_FLAGS;
                        if (TRUE) // The packet doesn't have FCS. We
always have no FCS for all packets currently.
                        {
                                *((UCHAR*)buf + cur) = 0x0; // 0x0: none
                        }
                        else // The packet has FCS.
                        {
                                *((UCHAR*)buf + cur) = 0x10; // 0x10:
frame includes FCS

                                // FCS check fails.
                                if ((pwInfo->uReceiveFlags &
DOT11_RECV_FLAG_RAW_PACKET_FCS_FAILURE) ==
DOT11_RECV_FLAG_RAW_PACKET_FCS_FAILURE)
                                {
                                        *((UCHAR*)buf + cur) |= 0x40; //
0x40: frame failed FCS check
                                }
                        }
                        cur += sizeof(UCHAR) / sizeof(UCHAR);

                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_CHANNEL;
                              *((USHORT*)buf + cur) = flags;
                              cur += sizeof(USHORT) / sizeof(UCHAR);
                              *((USHORT*)buf + cur) =
pwInfo->uChCenterFrequency;
                              cur += sizeof(USHORT) / sizeof(UCHAR);
                      }

The frequency comes before the channel, so that should be

                                *((USHORT*)buf + cur) =
pwInfo->uChCenterFrequency;
                                cur += sizeof(USHORT) / sizeof(UCHAR);
                                *((USHORT*)buf + cur) = flags;
                                cur += sizeof(USHORT) / sizeof(UCHAR);

                      // [Radiotap] "Antenna signal" field.
                      if (TRUE)
                      {
                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_DBM_ANTSIGNAL;
                              RtlCopyMemory(buf + cur, &pwInfo->lRSSI,
sizeof(UCHAR) / sizeof(UCHAR));
                              cur += sizeof(UCHAR) / sizeof(UCHAR);
                      }

                      // [Radiotap] "MCS" field.
                      if (pwInfo->uPhyId == dot11_phy_type_ht)
                      {
                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_MCS;
                              RtlZeroMemory(buf + cur, 3 * sizeof(UCHAR)
/ sizeof(UCHAR));
                              cur += 3 * sizeof(UCHAR) / sizeof(UCHAR);
                      }
                      // [Radiotap] "VHT" field.
                      else if (pwInfo->uPhyId == dot11_phy_type_vht)
                      {
                              RadiotapHeader.it_present |=
IEEE80211_RADIOTAP_VHT;
                              RtlZeroMemory(buf + cur, 12 *
sizeof(UCHAR) / sizeof(UCHAR));
                              cur += 12 * sizeof(UCHAR) / sizeof(UCHAR);
                      }

You'd need to do

                        cur += sizeof(UCHAR) / sizeof(UCHAR);

before putting the VHT field into the packet, because the VHT field has to
be aligned on a 2-byte boundary, and the antenna field is on a 2-byte
boundary but is only 1 byte long.  (The MCS field, however, doesn't have to
be aligned on a 2-byte boundary, so you *don't* need to pad anything for HT
frames.)

After all this is done, you'd need to do

        // Set the total length of the radiotap header
        RadiotapHeader.it_len = cur;

and then do

        RtlCopyMemory(buf, &RadiotapHeader, sizeof RadiotapHeader);

to put the IEEE80211_RADIOTAP_HEADER at the beginning of the radiotap
header.


___________________________________________________________________________
Sent via:    Wireshark-dev mailing list <wireshark-dev () wireshark org>
Archives:    https://www.wireshark.org/lists/wireshark-dev
Unsubscribe: https://wireshark.org/mailman/options/wireshark-dev
             mailto:wireshark-dev-request () wireshark org?subject=unsubscribe

Current thread: