Packets/80211Bundle: RadiotapPacketParser create and field update
g0dil [Fri, 20 Aug 2010 06:40:22 +0000 (06:40 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1693 270642c3-0616-0410-b53a-bc976706d245

senf/Packets/80211Bundle/RadiotapPacket.cc
senf/Packets/80211Bundle/RadiotapPacket.cci [new file with mode: 0644]
senf/Packets/80211Bundle/RadiotapPacket.cti [new file with mode: 0644]
senf/Packets/80211Bundle/RadiotapPacket.hh
senf/Packets/80211Bundle/RadiotapPacket.test.cc

index 7c6d84a..4bf458d 100644 (file)
@@ -28,6 +28,7 @@
 // Custom includes
 #include "WLANPacket.hh"
 #include <boost/io/ios_state.hpp>
+#include <memory.h>
 
 extern "C" {
 #   include "radiotap/radiotap_iter.h"
@@ -36,38 +37,167 @@ extern "C" {
 #define prefix_
 ///////////////////////////////cc.p//////////////////////////////////////
 
-prefix_ void senf::RadiotapPacketParser::fillOffsetTable(boost::uint8_t * data, int maxLength,
-                                                         OffsetTable & table)
+///////////////////////////////////////////////////////////////////////////
+// Offset table management
+
+prefix_ senf::RadiotapPacketParser::OffsetTable &
+senf::RadiotapPacketParser::offsetTable(boost::uint32_t presentFlags)
+{
+    typedef std::map<boost::uint32_t, OffsetTable> OffsetMap;
+    static OffsetMap offsetMap;
+
+    OffsetMap::iterator i (offsetMap.find(presentFlags));
+    if (i == offsetMap.end())
+        i = offsetMap.insert(std::make_pair(presentFlags, OffsetTable())).first;
+    return i->second;
+}
+
+prefix_ void senf::RadiotapPacketParser::parseOffsetTable(boost::uint8_t * data, int maxLength,
+                                                          OffsetTable & table)
 {
-    memset(&table, 0, sizeof(table));
     struct ieee80211_radiotap_iterator iter;
     ieee80211_radiotap_iterator_init(&iter,
                                      (struct ieee80211_radiotap_header *)data,
                                      maxLength,
                                      0);
-    while (ieee80211_radiotap_iterator_next(&iter)==0) {
+    unsigned size (8u);
+    while (ieee80211_radiotap_iterator_next(&iter) == 0) {
         if (iter.is_radiotap_ns &&
             iter.this_arg_index <= int(senf::RadiotapPacketParser::MAX_INDEX))
             table[iter.this_arg_index] = iter.this_arg - data;
+        // We need to set size here in the loop since the iter fields are only valid
+        // when at least one present bit is set ...
+        size = iter.this_arg - data + iter.this_arg_size;
+    }
+    table[MAX_INDEX+1] = size;
+}
+
+prefix_ void senf::RadiotapPacketParser::buildOffsetTable(boost::uint32_t presentFlags,
+                                                          OffsetTable & table)
+{
+    SENF_ASSERT(!(presentFlags & ( (1<<IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE) |
+                                   (1<<IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
+                                   (1<<IEEE80211_RADIOTAP_EXT) )),
+                "Extended or vendor fields not supported");
+
+    struct ieee80211_radiotap_header header;
+    memset(&header, 0, sizeof(header));
+    // header.it_version = 0;
+
+    // Iterating this packet will generate invalid addresses but we don't care since neither
+    // radiotap.c nor we will ever dereference those pointers, we just calculate the offsets.
+    // This works, as long as we don't support extension headers ...
+    header.it_len = 0xFFFF;
+    header.it_present = presentFlags;
+
+    parseOffsetTable((boost::uint8_t*)&header, header.it_len, table);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::RadiotapPacketParser
+
+unsigned const senf::RadiotapPacketParser_Header::FIELD_SIZE[] = {
+    8, 1, 1, 4, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1 };
+
+prefix_ senf::UInt32Parser senf::RadiotapPacketParser::init_fcs()
+{
+    if (!has_fcs()) {
+        protect(), data().insert(data().end(), 4u, 0u);
+        init_flags().fcsAtEnd_() = true;
+    }
+    return fcs();
+}
+
+prefix_ void senf::RadiotapPacketParser::disable_fcs()
+{
+    if (has_fcs()) {
+        validate(RadiotapPacketParser_Header::fixed_bytes+4);
+        data().erase(data().end()-4, data().end());
+        flags().fcsAtEnd_() = false;
     }
-    table[MAX_INDEX+1] = iter.this_arg - data + iter.this_arg_size;
 }
 
 prefix_ senf::RadiotapPacketParser::OffsetTable const &
-senf::RadiotapPacketParser::offsetTable(boost::uint32_t presentFlags)
+senf::RadiotapPacketParser::currentTable()
+    const
 {
-    typedef std::map<boost::uint32_t, OffsetTable> OffsetMap;
-    static OffsetMap offsetMap;
+    OffsetTable & table (offsetTable(presentFlags()));
+    if (! table[MAX_INDEX+1])
+        parseOffsetTable(&(*data().begin()), data().size(), table);
+    return table;
+}
 
-    OffsetMap::iterator i (offsetMap.find(presentFlags));
-    if (i == offsetMap.end()) {
-        OffsetTable table;
-        fillOffsetTable(&(*data().begin()), data().size(), table);
-        i = offsetMap.insert(std::make_pair(presentFlags, table)).first;
+prefix_ senf::RadiotapPacketParser::OffsetTable const &
+senf::RadiotapPacketParser::getTable(boost::uint32_t presentFlags)
+    const
+{
+    OffsetTable & table(offsetTable(presentFlags));
+    if (! table[MAX_INDEX+1])
+        buildOffsetTable(presentFlags, table);
+    return table;
+}
+
+prefix_ void senf::RadiotapPacketParser::insertRemoveBytes(unsigned from , unsigned to, int bytes)
+{
+    data_iterator b (i() + from);
+    data_iterator e (i() + to);
+    if (bytes >= 0) {
+        // Insert some bytes cleaning the old bytes to 0 first
+        std::fill(b, e,  0u);
+        if (bytes > 0)
+            // need to protect the parser since data().insert() invalidates iterators
+            protect(), data().insert(e, bytes, 0u);
+    }
+    else { // bytes < 0
+        // Remove some bytes ...
+        // remember: bytes is negative ...
+        if (b < e + bytes)
+            std::fill(b, e + bytes, 0u);
+        data().erase(e + bytes, e);
     }
-    return i->second;
 }
 
+prefix_ void senf::RadiotapPacketParser::updatePresentFlags(boost::uint32_t flags)
+{
+    if (flags == presentFlags())
+        return;
+    validate(bytes());
+
+    OffsetTable const & oldTable (currentTable());
+    OffsetTable const & newTable (getTable(flags));
+    unsigned b (RadiotapPacketParser_Header::fixed_bytes);
+    int cumulativeNewBytes (0);
+
+    for (unsigned index (0); index <= MAX_INDEX; ++index) {
+        // Skip any unchanged fields
+        for (; index <= MAX_INDEX+1
+                 && ((oldTable[index] == 0 && newTable[index] == 0)
+                     || (oldTable[index]+cumulativeNewBytes == newTable[index])); ++index)
+            if (newTable[index] != 0)
+                b = newTable[index] + FIELD_SIZE[index];
+        if (index > MAX_INDEX+1)
+            break;
+        // Now skip over all changed fields
+        // (The condition index <= MAX_INDEX is not needed here since the last
+        // table entry MAX_INDEX+1 is always != 0 in both tables)
+        for (; ! (oldTable[index]!=0 && newTable[index]!=0); ++index) ;
+        // index now either points to
+        // a) an entry set in both tables
+        // b) at the end of the table which contains the total length
+        // (remember: the table has a size of MAX_INDEX+2 entries !!)
+        // in both cases, the difference between the new and old size
+        // is found from the difference between the old and the new table
+        // entry
+        int newBytes (newTable[index] - oldTable[index] - cumulativeNewBytes);
+        insertRemoveBytes(b, oldTable[index] + cumulativeNewBytes, newBytes);
+        cumulativeNewBytes += newBytes;
+        b = newTable[index] + FIELD_SIZE[index];
+    }
+    presentFlags() = flags;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::RadiotapPacketType
 
 prefix_ void senf::RadiotapPacketType::dump(packet p, std::ostream &os)
 {
@@ -76,69 +206,94 @@ prefix_ void senf::RadiotapPacketType::dump(packet p, std::ostream &os)
        << senf::fieldName("version") << unsigned(p->version()) << '\n'
        << senf::fieldName("length")  << unsigned(p->length()) << '\n';
 
-#   define DUMP_OPTIONAL_FIELD(name, sign, desc)                        \
+#   define FIELD(name, sign, desc)                                      \
         if (p->name ## Present())                                       \
             os << senf::fieldName(desc) << sign(p->name()) << '\n';
 
-    DUMP_OPTIONAL_FIELD( tsft, boost::uint64_t, "MAC timestamp" );
+#   define ENTER(name)                                                  \
+        if (p->name ## Present()) {                                     \
+            packet::Parser::name ## _t subparser (p->name());
 
-    if (p->flagsPresent()) {
-        os << senf::fieldName("flags");
+#   define SUBFIELD(name, sign, desc)                                   \
+        os << senf::fieldName(desc) << sign(subparser.name()) << '\n';
 
-#       define DUMP_FLAG(name,desc) if (p->flags().name()) os << desc " "
-        DUMP_FLAG(shortGI,            "ShortGI");
-        DUMP_FLAG(badFCS,             "BadFCS");
-        DUMP_FLAG(fcsAtEnd,           "FCSatEnd");
-        DUMP_FLAG(fragmentation,      "Frag");
-        DUMP_FLAG(wep,                "WEP");
-        DUMP_FLAG(shortPreamble,      "ShortPreamble");
-        DUMP_FLAG(cfp,                "CFP");
-#       undef DUMP_FLAG
+#   define LEAVE()                                                      \
+        }
 
-        os << '\n';
-    }
+#   define START_FLAGS(desc)                                            \
+        os << senf::fieldName(desc);
 
-    DUMP_OPTIONAL_FIELD( rate, unsigned, "rate" );
-
-    if (p->channelOptionsPresent()) {
-        os << senf::fieldName("channel frequency")
-           << unsigned(p->channelOptions().freq()) << '\n'
-           << senf::fieldName("channel flags");
-
-#       define DUMP_FLAG(name,desc) if (p->channelOptions().name()) os << desc " "
-        DUMP_FLAG(flag2ghz,           "2GHz");
-        DUMP_FLAG(ofdm,               "OFDM");
-        DUMP_FLAG(cck,                "CCK");
-        DUMP_FLAG(turbo,              "Turbo");
-        DUMP_FLAG(quarterRateChannel, "Rate/4");
-        DUMP_FLAG(halfRateChannel,    "Rate/2");
-        DUMP_FLAG(gsm,                "GSM");
-        DUMP_FLAG(staticTurbo,        "StaticTurbo");
-        DUMP_FLAG(gfsk,               "GFSK");
-        DUMP_FLAG(cckOfdm,            "CCKOFDM");
-        DUMP_FLAG(passive,            "Passive");
-        DUMP_FLAG(flag5ghz,           "5GHz");
-#       undef DUMP_FLAG
+#   define FLAG(name, desc)                                             \
+        if (subparser.name()) os << desc " "
 
+#   define END_FLAGS()                                                  \
         os << '\n';
-    }
 
-    DUMP_OPTIONAL_FIELD( fhss,              unsigned, "FHSS"                 );
-    DUMP_OPTIONAL_FIELD( dbmAntennaSignal,  signed,   "antenna signal (dBm)" );
-    DUMP_OPTIONAL_FIELD( dbmAntennaNoise,   signed,   "antenna noise (dBm)"  );
-    DUMP_OPTIONAL_FIELD( lockQuality,       unsigned, "lock quality"         );
-    DUMP_OPTIONAL_FIELD( txAttenuation,     unsigned, "tx attenuation"       );
-    DUMP_OPTIONAL_FIELD( dbTxAttenuation,   unsigned, "tx attenuation (dB)"  );
-    DUMP_OPTIONAL_FIELD( dbmTxAttenuation,  signed,   "tx attenuation (dBm)" );
-    DUMP_OPTIONAL_FIELD( antenna,           unsigned, "antenna"              );
-    DUMP_OPTIONAL_FIELD( dbAntennaSignal,   unsigned, "antenna signal (dB)"  );
-    DUMP_OPTIONAL_FIELD( dbAntennaNoise,    unsigned, "antenna noise (dB)"   );
-    DUMP_OPTIONAL_FIELD( headerFcs,         unsigned, "FCS (in header)"      );
+    FIELD           ( tsft,              boost::uint64_t, "MAC timestamp"        );
+    ENTER           ( flags                                                      );
+      START_FLAGS   (                                     "flags"                );
+        FLAG        (     shortGI,                            "ShortGI"          );
+        FLAG        (     badFCS,                             "BadFCS"           );
+        FLAG        (     fcsAtEnd,                           "FCSatEnd"         );
+        FLAG        (     fragmentation,                      "Frag"             );
+        FLAG        (     wep,                                "WEP"              );
+        FLAG        (     shortPreamble,                      "ShortPreamble"    );
+        FLAG        (     cfp,                                "CFP"              );
+      END_FLAGS     (                                                            );
+    LEAVE           (                                                            );
+    FIELD           ( rate,              unsigned,        "rate"                 );
+    ENTER           ( channelOptions                                             );
+      SUBFIELD      (     freq,          unsigned,        "channel frequency"    );
+      START_FLAGS   (                                     "channel flags"        );
+        FLAG        (     flag2ghz,                           "2GHz"             );
+        FLAG        (     ofdm,                               "OFDM"             );
+        FLAG        (     cck,                                "CCK"              );
+        FLAG        (     turbo,                              "Turbo"            );
+        FLAG        (     quarterRateChannel,                 "Rate/4"           );
+        FLAG        (     halfRateChannel,                    "Rate/2"           );
+        FLAG        (     gsm,                                "GSM"              );
+        FLAG        (     staticTurbo,                        "StaticTurbo"      );
+        FLAG        (     gfsk,                               "GFSK"             );
+        FLAG        (     cckOfdm,                            "CCK+OFDM"         );
+        FLAG        (     passive,                            "Passive"          );
+        FLAG        (     flag5ghz,                           "5GHz"             );
+      END_FLAGS     (                                                            );
+    LEAVE           (                                                            );
+    FIELD           ( fhss,              unsigned,        "FHSS"                 );
+    FIELD           ( dbmAntennaSignal,  signed,          "antenna signal (dBm)" );
+    FIELD           ( dbmAntennaNoise,   signed,          "antenna noise (dBm)"  );
+    FIELD           ( lockQuality,       unsigned,        "lock quality"         );
+    FIELD           ( txAttenuation,     unsigned,        "tx attenuation"       );
+    FIELD           ( dbTxAttenuation,   unsigned,        "tx attenuation (dB)"  );
+    FIELD           ( dbmTxAttenuation,  signed,          "tx attenuation (dBm)" );
+    FIELD           ( antenna,           unsigned,        "antenna"              );
+    FIELD           ( dbAntennaSignal,   unsigned,        "antenna signal (dB)"  );
+    FIELD           ( dbAntennaNoise,    unsigned,        "antenna noise (dB)"   );
+    ENTER           ( rxFlags                                                    );
+      START_FLAGS   (                                     "rx flags"             );
+        FLAG        (     badPlcp,                            "BadPLCP"          );
+      END_FLAGS     (                                                            );
+    LEAVE           (                                                            );
+    ENTER           ( txFlags                                                    );
+      START_FLAGS   (                                     "tx flags"             );
+        FLAG        (     fail,                               "Fail"             );
+        FLAG        (     txRts,                              "RTS"              );
+        FLAG        (     txCts,                              "CTS"              );
+      END_FLAGS     (                                                            );
+    LEAVE           (                                                            );
+    FIELD           ( rtsRetries,        unsigned,        "rts retries"          );
+    FIELD           ( dataRetries,       unsigned,        "data retries"         );
 
     if (p->flagsPresent() && p->flags().fcsAtEnd())
-        os << senf::fieldName("FCS (at end)") << unsigned(p->fcs()) << '\n';
+        os << senf::fieldName("fcs") << unsigned(p->fcs()) << '\n';
 
-#   undef DUMP_OPTIONAL_FIELD
+#   undef END_FLAGS
+#   undef FLAG
+#   undef START_FLAGS
+#   undef LEAVE
+#   undef SUBFIELD
+#   undef ENTER
+#   undef FIELD
 }
 
 
@@ -162,7 +317,7 @@ senf::RadiotapPacketType::nextPacketRange(packet p)
 {
     size_type h (senf::bytes(p.parser()));
     size_type t (p->flagsPresent() && p->flags().fcsAtEnd() ? 4 : 0);
-    return p.size() < h+t
+    return p.size() <= h+t
         ? no_range()
         : optional_range( range(p.data().begin() + h, p.data().end() - t) );
 }
diff --git a/senf/Packets/80211Bundle/RadiotapPacket.cci b/senf/Packets/80211Bundle/RadiotapPacket.cci
new file mode 100644 (file)
index 0000000..2164b40
--- /dev/null
@@ -0,0 +1,92 @@
+// $Id$
+//
+// Copyright (C) 2010
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief RadiotapPacket inline non-template implementation */
+
+//#include "RadiotapPacket.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::RadiotapPacketParser
+
+prefix_ senf::RadiotapPacketParser::RadiotapPacketParser(data_iterator i, state_type s)
+    : RadiotapPacketParser_Header(i,s)
+{}
+
+prefix_ senf::RadiotapPacketParser::size_type senf::RadiotapPacketParser::bytes()
+    const
+{
+    return calculateSize();
+}
+
+prefix_ senf::UInt32Parser senf::RadiotapPacketParser::fcs()
+{
+    validate(RadiotapPacketParser_Header::fixed_bytes+4);
+    return parse<senf::UInt32Parser>(data().end()-4);
+}
+
+prefix_ bool senf::RadiotapPacketParser::has_fcs()
+{
+    return flagsPresent() && flags().fcsAtEnd();
+}
+
+prefix_ unsigned senf::RadiotapPacketParser::frameType()
+{
+    return parse<RadiotapPacketParser_FrameType>(length()).frameType();
+}
+////////////////////////////////////////
+// private members
+
+prefix_ void senf::RadiotapPacketParser::initField(unsigned index)
+{
+    updatePresentFlags( presentFlags() | (1<<index) );
+}
+
+prefix_ void senf::RadiotapPacketParser::disableField(unsigned index)
+{
+    updatePresentFlags( presentFlags() & ~(1<<index) );
+}
+
+prefix_ senf::RadiotapPacketParser::size_type senf::RadiotapPacketParser::calculateSize()
+    const
+{
+    return currentTable()[MAX_INDEX+1];
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/senf/Packets/80211Bundle/RadiotapPacket.cti b/senf/Packets/80211Bundle/RadiotapPacket.cti
new file mode 100644 (file)
index 0000000..d1ba44c
--- /dev/null
@@ -0,0 +1,51 @@
+// $Id$
+//
+// Copyright (C) 2010
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief RadiotapPacket inline template implementation */
+
+//#include "RadiotapPacket.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+template <class Parser>
+prefix_ Parser senf::RadiotapPacketParser::parseField(unsigned index)
+{
+    return parse<Parser>(currentTable()[index]);
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index 966f2b7..f6bd76e 100644 (file)
@@ -51,6 +51,8 @@ namespace senf {
         SENF_PARSER_BITFIELD ( cfp,            1, bool );
 
         SENF_PARSER_FINALIZE ( RadiotapPacketParser_Flags );
+
+        friend class RadiotapPacketParser;
     };
 
     /** \brief Parse in Radiotap Header channel frequency and flag field
@@ -67,7 +69,7 @@ namespace senf {
         SENF_PARSER_BITFIELD  ( ofdm,                 1, bool  );
         SENF_PARSER_BITFIELD  ( cck,                  1, bool  );
         SENF_PARSER_BITFIELD  ( turbo,                1, bool  );
-        SENF_PARSER_SKIP_BITS ( 4                              ); //currently unused in radiotap
+        SENF_PARSER_SKIP_BITS ( 4                              );
         SENF_PARSER_BITFIELD  ( quarterRateChannel,   1, bool  );
         SENF_PARSER_BITFIELD  ( halfRateChannel,      1, bool  );
         SENF_PARSER_BITFIELD  ( gsm,                  1, bool  );
@@ -80,6 +82,29 @@ namespace senf {
         SENF_PARSER_FINALIZE ( RadiotapPacketParser_ChannelOptions );
     };
 
+    struct RadiotapPacketParser_RxFlags : public PacketParserBase
+    {
+#       include SENF_FIXED_PARSER()
+
+        SENF_PARSER_SKIP_BITS ( 6                              );
+        SENF_PARSER_BITFIELD  ( badPlcp,              1, bool  );
+        SENF_PARSER_SKIP_BITS ( 1                              );
+
+        SENF_PARSER_FINALIZE( RadiotapPacketParser_RxFlags );
+    };
+
+    struct RadiotapPacketParser_TxFlags : public PacketParserBase
+    {
+#       include SENF_FIXED_PARSER()
+
+        SENF_PARSER_SKIP_BITS ( 5                              );
+        SENF_PARSER_BITFIELD  ( txRts,                1, bool  );
+        SENF_PARSER_BITFIELD  ( txCts,                1, bool  );
+        SENF_PARSER_BITFIELD  ( fail,                 1, bool  );
+
+        SENF_PARSER_FINALIZE( RadiotapPacketParser_TxFlags );
+    };
+
     /** \brief Parse an Radiotap header
 
         Parser implementing the Radiotap header
@@ -112,10 +137,10 @@ namespace senf {
         SENF_PARSER_PRIVATE_FIELD ( presentFlags, UInt32LSBParser );
         SENF_PARSER_GOTO( presentFlags );
 
-        /*
-         * present flags
-         * indicate which data field are contained in the packet
-         */
+        // present flags indicate which data fields are contained in the packet
+        // BEWARE: LSB-first bit-order !!
+
+        // index: 7 - 0
         SENF_PARSER_BITFIELD_RO ( lockQualityPresent,      1, bool );
         SENF_PARSER_BITFIELD_RO ( dbmAntennaNoisePresent,  1, bool );
         SENF_PARSER_BITFIELD_RO ( dbmAntennaSignalPresent, 1, bool );
@@ -124,20 +149,77 @@ namespace senf {
         SENF_PARSER_BITFIELD_RO ( ratePresent,             1, bool );
         SENF_PARSER_BITFIELD_RO ( flagsPresent,            1, bool );
         SENF_PARSER_BITFIELD_RO ( tsftPresent,             1, bool );
-        SENF_PARSER_SKIP_BITS   ( 1                                ); //currently unused bits
-        SENF_PARSER_BITFIELD_RO ( headerFcsPresent,        1, bool );
+
+        // index: 15 - 8
+        SENF_PARSER_BITFIELD_RO ( txFlagsPresent,          1, bool );
+        SENF_PARSER_BITFIELD_RO ( rxFlagsPresent,          1, bool );
         SENF_PARSER_BITFIELD_RO ( dbAntennaNoisePresent,   1, bool );
         SENF_PARSER_BITFIELD_RO ( dbAntennaSignalPresent,  1, bool );
         SENF_PARSER_BITFIELD_RO ( antennaPresent,          1, bool );
         SENF_PARSER_BITFIELD_RO ( dbmTxAttenuationPresent, 1, bool );
         SENF_PARSER_BITFIELD_RO ( dbTxAttenuationPresent,  1, bool );
         SENF_PARSER_BITFIELD_RO ( txAttenuationPresent,    1, bool );
-        SENF_PARSER_SKIP_BITS   ( 8                                ); //currently unused bits
-        //if bit is set,another 32 bit present flag is attached (not implemented yet)
+
+        // index: 23 - 16
+        SENF_PARSER_SKIP_BITS   ( 6                                );
+        SENF_PARSER_BITFIELD_RO ( dataRetriesPresent,      1, bool );
+        SENF_PARSER_BITFIELD_RO ( rtsRetriesPresent,       1, bool );
+
+        // index: 31 - 24
         SENF_PARSER_BITFIELD_RO ( extendedBitmaskPresent,  1, bool );
-        SENF_PARSER_SKIP_BITS   ( 7                                ); //currently unused bits
+        SENF_PARSER_BITFIELD_RO ( vendorNamespacePresent,  1, bool );
+        SENF_PARSER_BITFIELD_RO ( resetRadiotapNamespace,  1, bool )
+        SENF_PARSER_SKIP_BITS   ( 5                                );
 
         SENF_PARSER_FINALIZE ( RadiotapPacketParser_Header );
+
+        enum PresentIndex {
+            // Could use the the entries from radiotap.h but I don't know,
+            // if I want to pollute the global and macro namespace even more ...
+            TSFT_INDEX              =  0,
+            FLAGS_INDEX             =  1,
+            RATE_INDEX              =  2,
+            CHANNEL_INDEX           =  3,
+            FHSS_INDEX              =  4,
+            DBM_ANTSIGNAL_INDEX     =  5,
+            DBM_ANTNOISE_INDEX      =  6,
+            LOCK_QUALITY_INDEX      =  7,
+            TX_ATTENUATION_INDEX    =  8,
+            DB_TX_ATTENUATION_INDEX =  9,
+            DBM_TX_POWER_INDEX      = 10,
+            ANTENNA_INDEX           = 11,
+            DB_ANTSIGNAL_INDEX      = 12,
+            DB_ANTNOISE_INDEX       = 13,
+            RX_FLAGS_INDEX          = 14,
+            TX_FLAGS_INDEX          = 15,
+            RTS_RETRIES_INDEX       = 16,
+            DATA_RETRIES_INDEX      = 17,
+
+            MAX_INDEX               = 17
+        };
+
+        enum PresentFlag {
+            TSFT_FLAG               = (1<<TSFT_INDEX),
+            FLAGS_FLAG              = (1<<FLAGS_INDEX),
+            RATE_FLAG               = (1<<RATE_INDEX),
+            CHANNEL_FLAG            = (1<<CHANNEL_INDEX),
+            FHSS_FLAG               = (1<<FHSS_INDEX),
+            DBM_ANTSIGNAL_FLAG      = (1<<DBM_ANTSIGNAL_INDEX),
+            DBM_ANTNOISE_FLAG       = (1<<DBM_ANTNOISE_INDEX),
+            LOCK_QUALITY_FLAG       = (1<<LOCK_QUALITY_INDEX),
+            TX_ATTENUATION_FLAG     = (1<<TX_ATTENUATION_INDEX),
+            DB_TX_ATTENUATION_FLAG  = (1<<DB_TX_ATTENUATION_INDEX),
+            DBM_TX_POWER_FLAG       = (1<<DBM_TX_POWER_INDEX),
+            ANTENNA_FLAG            = (1<<ANTENNA_INDEX),
+            DB_ANTSIGNAL_FLAG       = (1<<DB_ANTSIGNAL_INDEX),
+            DB_ANTNOISE_FLAG        = (1<<DB_ANTNOISE_INDEX),
+            RX_FLAGS_FLAG           = (1<<RX_FLAGS_INDEX),
+            TX_FLAGS_FLAG           = (1<<TX_FLAGS_INDEX),
+            RTS_RETRIES_FLAG        = (1<<RTS_RETRIES_INDEX),
+            DATA_RETRIES_FLAG       = (1<<DATA_RETRIES_INDEX)
+        };
+
+        static unsigned const FIELD_SIZE[MAX_INDEX+2];
     };
 
     struct RadiotapPacketParser_FrameType : public PacketParserBase
@@ -153,66 +235,85 @@ namespace senf {
 
     struct RadiotapPacketParser : public RadiotapPacketParser_Header
     {
-        RadiotapPacketParser(data_iterator i, state_type s) : RadiotapPacketParser_Header(i,s) {}
+        RadiotapPacketParser(data_iterator i, state_type s);
 
         static const size_type init_bytes = RadiotapPacketParser_Header::fixed_bytes;
 
-        size_type bytes() const { return length(); }
+        size_type bytes() const;
 
         // ////////////////////////////////////////////////////////////////////////
 
-        UInt64LSBParser            tsft()
-            { return parseField<UInt64LSBParser>             (0); }
-        RadiotapPacketParser_Flags flags()
-            { return parseField<RadiotapPacketParser_Flags>  (1); }
-        UInt8Parser                rate()
-            { return parseField<UInt8Parser>                 (2); }
-        RadiotapPacketParser_ChannelOptions channelOptions()
-            { return parseField<RadiotapPacketParser_ChannelOptions>(3); }
-        UInt16LSBParser            fhss()
-            { return parseField<UInt16LSBParser>             (4); }
-        Int8Parser                 dbmAntennaSignal()
-            { return parseField<Int8Parser>                  (5); }
-        Int8Parser                 dbmAntennaNoise()
-            { return parseField<Int8Parser>                  (6); }
-        UInt16LSBParser            lockQuality()
-            { return parseField<UInt16LSBParser>             (7); }
-        UInt16LSBParser            txAttenuation()
-            { return parseField<UInt16LSBParser>             (8); }
-        UInt16LSBParser            dbTxAttenuation()
-            { return parseField<UInt16LSBParser>             (9); }
-        Int8Parser                 dbmTxAttenuation()
-            { return parseField<Int8Parser>                 (10); }
-        UInt8Parser                antenna()
-            { return parseField<UInt8Parser>                (11); }
-        UInt8Parser                dbAntennaSignal()
-            { return parseField<UInt8Parser>                (12); }
-        UInt8Parser                dbAntennaNoise()
-            { return parseField<UInt8Parser>                (13); }
-        UInt32Parser               headerFcs()
-            { return parseField<UInt32Parser>               (14); }
-
-        unsigned frameType()
-            { return parse<RadiotapPacketParser_FrameType>(length()).frameType(); }
-
-        UInt32Parser fcs()
-            { return parse<senf::UInt32Parser>(data().end()-4); }
+#       define FIELD(name,type,index)                                   \
+            typedef type name ## _t;                                    \
+            type name() { return parseField<type>(index); }             \
+            bool has_ ## name() { return name ## Present(); }           \
+            type init_ ## name() { initField(index); return name(); }   \
+            void disable_ ## name() { disableField(index); }
+
+        FIELD( tsft,              UInt64LSBParser,                      TSFT_INDEX              );
+
+        // flags is special: disabling 'flags' must also disable the 'fcs' field
+        typedef RadiotapPacketParser_Flags flags_t;
+        flags_t flags() { return parseField<flags_t>(FLAGS_INDEX); }
+        bool has_flags() { return flagsPresent(); }
+        flags_t init_flags() { initField(FLAGS_INDEX); return flags(); }
+        void disable_flags() { disable_fcs(); disableField(FLAGS_INDEX); }
+
+        FIELD( rate,              UInt8Parser,                          RATE_INDEX              );
+        FIELD( channelOptions,    RadiotapPacketParser_ChannelOptions,  CHANNEL_INDEX           );
+        FIELD( fhss,              UInt16LSBParser,                      FHSS_INDEX              );
+        FIELD( dbmAntennaSignal,  Int8Parser,                           DBM_ANTSIGNAL_INDEX     );
+        FIELD( dbmAntennaNoise,   Int8Parser,                           DBM_ANTNOISE_INDEX      );
+        FIELD( lockQuality,       UInt16LSBParser,                      LOCK_QUALITY_INDEX      );
+        FIELD( txAttenuation,     UInt16LSBParser,                      TX_ATTENUATION_INDEX    );
+        FIELD( dbTxAttenuation,   UInt16LSBParser,                      DB_TX_ATTENUATION_INDEX );
+        FIELD( dbmTxAttenuation,  Int8Parser,                           DBM_TX_POWER_INDEX      );
+        FIELD( antenna,           UInt8Parser,                          ANTENNA_INDEX           );
+        FIELD( dbAntennaSignal,   UInt8Parser,                          DB_ANTSIGNAL_INDEX      );
+        FIELD( dbAntennaNoise,    UInt8Parser,                          DB_ANTNOISE_INDEX       );
+        FIELD( rxFlags,           RadiotapPacketParser_RxFlags,         RX_FLAGS_INDEX          );
+        FIELD( txFlags,           RadiotapPacketParser_TxFlags,         TX_FLAGS_INDEX          );
+        FIELD( rtsRetries,        UInt8Parser,                          RTS_RETRIES_INDEX       );
+        FIELD( dataRetries,       UInt8Parser,                          DATA_RETRIES_INDEX      );
+
+#       undef FIELD
+
+        typedef UInt32Parser fcs_t;
+        UInt32Parser fcs();
+        bool has_fcs();
+        UInt32Parser init_fcs();
+        void disable_fcs();
+
+        unsigned frameType();
 
     private:
-        static const size_type fixed_bytes = 0; // 'remove' this member ...
-        static const unsigned MAX_INDEX = 14;
+        static const size_type fixed_bytes = 0; // hide this member, just in case
 
         typedef boost::array<size_type,MAX_INDEX+2> OffsetTable;
 
-        OffsetTable const & offsetTable(boost::uint32_t presentFlags);
-        static void fillOffsetTable(boost::uint8_t * data, int maxLength, OffsetTable & table);
+        ///////////////////////////////////////////////////////////////////////////
+        // Offset table handling
+
+        static OffsetTable & offsetTable(boost::uint32_t presentFlags);
+        // Fills the offset table based on a packet
+        static void parseOffsetTable(boost::uint8_t * data, int maxLength, OffsetTable & table);
+        // Generate an offset table just from the present flags
+        static void buildOffsetTable(boost::uint32_t presentFlags, OffsetTable & table);
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        OffsetTable const & currentTable() const;
+        OffsetTable const & getTable(boost::uint32_t presentFlags) const;
 
         template <class Parser>
-        Parser parseField(unsigned index)
-            { return parse<Parser>(offsetTable(presentFlags())[index]); }
+        Parser parseField(unsigned index);
+        void initField(unsigned index);
+        void disableField(unsigned index);
+
+        size_type calculateSize() const;
 
-        size_type calculateSize()
-            { return offsetTable(presentFlags())[MAX_INDEX+1]; }
+        void updatePresentFlags(boost::uint32_t flags);
+        void insertRemoveBytes(unsigned from, unsigned to, int bytes);
 
         friend class RadiotapPacketType;
     };
@@ -251,9 +352,9 @@ namespace senf {
 }
 
 ///////////////////////////////hh.e////////////////////////////////////////
-//#include "RadiotapPacket.cci"
+#include "RadiotapPacket.cci"
 //#include "RadiotapPacket.ct"
-//#include "RadiotapPacket.cti"
+#include "RadiotapPacket.cti"
 #endif
 
 \f
index 46f8a63..d5631fd 100644 (file)
 #include <boost/test/test_tools.hpp>
 
 ///////////////////////////////cc.p////////////////////////////////////////
+
+SENF_AUTO_UNIT_TEST(RadiotapPacket_fieldSizes)
+{
+    // This test only asserts, that nobody forgot to update the FIELD_SIZE table
+    // when chaning MAX_INDEX
+    BOOST_CHECK( senf::RadiotapPacketParser_Header::FIELD_SIZE[
+                     senf::RadiotapPacketParser_Header::MAX_INDEX] != 0 );
+}
+
 SENF_AUTO_UNIT_TEST(RadiotapPacket_packet)
 {
     /* used madwifi 0.9.4 */
@@ -112,66 +121,100 @@ SENF_AUTO_UNIT_TEST(RadiotapPacket_packet)
                        "  antenna noise (dBm)     : -96\n"
                        "  antenna                 : 2\n"
                        "  antenna signal (dB)     : 35\n"
-                       "  FCS (at end)            : 0\n" );
+                       "  fcs                     : 0\n" );
 }
 
-#if 0
 SENF_AUTO_UNIT_TEST(RadiotapPacket_create)
 {
-    unsigned char data[] = {
-            0x00 ,0x00 ,0x1a ,0x00, 0x6f, 0x18, 0x00, 0x00,
-            0x02, 0xe6, 0x8a, 0xdf, 0x12, 0x00, 0x00, 0x00,
-            0x02, 0x0c, 0xc8, 0x14, 0x40, 0x01, 0xc3, 0xa0,
-            0x02, 0x23
-    };
-
     senf::RadiotapPacket p (senf::RadiotapPacket::create());
 
-    SENF_CHECK_NO_THROW( p->init_tsft());
-    SENF_CHECK_NO_THROW( p->tsft()=81059833346uLL);
+    BOOST_CHECK_EQUAL( p.size(), senf::RadiotapPacketParser_Header::fixed_bytes+0 );
 
-    SENF_CHECK_NO_THROW( p->init_rate());
-    SENF_CHECK_NO_THROW( p->rate() = 12u);
-    SENF_CHECK_NO_THROW( p->init_dbmAntennaSignal());
-    SENF_CHECK_NO_THROW( p->dbmAntennaSignal() = -61);
-    SENF_CHECK_NO_THROW( p->init_dbmAntennaNoise());
-    SENF_CHECK_NO_THROW( p->dbmAntennaNoise() = -96);
-    SENF_CHECK_NO_THROW( p->init_antenna());
-    SENF_CHECK_NO_THROW( p->antenna() = 2u);
-    SENF_CHECK_NO_THROW( p->init_dbAntennaSignal());
-    SENF_CHECK_NO_THROW( p->dbAntennaSignal() = 35);
+    SENF_CHECK_NO_THROW( p->init_tsft()             = 81059833346uLL );
+    SENF_CHECK_NO_THROW( p->init_rate()             =          12u   );
+    SENF_CHECK_NO_THROW( p->init_dbmAntennaSignal() =         -61    );
+    SENF_CHECK_NO_THROW( p->init_dbmAntennaNoise()  =         -96    );
+    SENF_CHECK_NO_THROW( p->init_antenna()          =           2u   );
+    SENF_CHECK_NO_THROW( p->init_dbAntennaSignal()  =          35    );
 
     SENF_CHECK_NO_THROW( p->init_flags());
-    SENF_CHECK_NO_THROW( p->flags().cfp() = false);
     SENF_CHECK_NO_THROW( p->flags().shortPreamble() = true);
-    SENF_CHECK_NO_THROW( p->flags().wep() = false);
-    SENF_CHECK_NO_THROW( p->flags().fragmentation() = false);
-    // SENF_CHECK_NO_THROW( p->flags().fcsAtEnd() = true);
-    SENF_CHECK_NO_THROW( p->flags().padding() = false);
-    SENF_CHECK_NO_THROW( p->flags().badFCS() = false);
-    SENF_CHECK_NO_THROW( p->flags().shortGI() = false);
 
     SENF_CHECK_NO_THROW( p->init_channelOptions());
     SENF_CHECK_NO_THROW( p->channelOptions().freq() = 5320u)
     SENF_CHECK_NO_THROW( p->channelOptions().ofdm() = true);
-    SENF_CHECK_NO_THROW( p->channelOptions().turbo() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().cck() = false);
     SENF_CHECK_NO_THROW( p->channelOptions().flag5ghz() = true);
-    SENF_CHECK_NO_THROW( p->channelOptions().passive() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().cckOfdm() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().gfsk() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().gsm() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().staticTurbo() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().halfRateChannel() = false);
-    SENF_CHECK_NO_THROW( p->channelOptions().quarterRateChannel() = false);
+
+    SENF_CHECK_NO_THROW( p->init_fcs() );
 
     p.finalizeAll();
 
     BOOST_CHECK_EQUAL( p->length(), 26u );
-    BOOST_CHECK_EQUAL_COLLECTIONS( p.data().begin(), p.data().end(),
-                                   data, data+sizeof(data)/sizeof(data[0]) );
+    BOOST_CHECK_EQUAL( p.size(), 30u );
+
+    std::stringstream ss;
+    p.dump(ss);
+    BOOST_CHECK_EQUAL( ss.str(),
+                       "Radiotap:\n"
+                       "  version                 : 0\n"
+                       "  length                  : 26\n"
+                       "  MAC timestamp           : 81059833346\n"
+                       "  flags                   : FCSatEnd ShortPreamble \n"
+                       "  rate                    : 12\n"
+                       "  channel frequency       : 5320\n"
+                       "  channel flags           : OFDM 5GHz \n"
+                       "  antenna signal (dBm)    : -61\n"
+                       "  antenna noise (dBm)     : -96\n"
+                       "  antenna                 : 2\n"
+                       "  antenna signal (dB)     : 35\n"
+                       "  fcs                     : 0\n" );
+
+    {
+        unsigned char data[] = {
+            /*  0 */ 0x00,                                           // version
+            /*    */ 0x00,
+            /*  2 */ 0x1a, 0x00,                                     // length
+            /*  4 */ 0x6f, 0x18, 0x00, 0x00,                         // presentFlags
+            /*  8 */ 0x02, 0xe6, 0x8a, 0xdf, 0x12, 0x00, 0x00, 0x00, // tsft
+            /* 16 */ 0x12,                                           // flags
+            /* 17 */ 0x0c,                                           // rate
+            /* 18 */ 0xc8, 0x14,                                     // channel frequency
+            /* 20 */ 0x40, 0x01,                                     // channel flags
+            /* 22 */ 0xc3,                                           // dbmAntennaSignal
+            /* 23 */ 0xa0,                                           // dbmAntennaNoise
+            /* 24 */ 0x02,                                           // antenna
+            /* 25 */ 0x23,                                           // dbAntennaSignal
+            /* 26 */ 0x0, 0x0, 0x0, 0x0                              // FCS
+        };
+
+        BOOST_CHECK_EQUAL_COLLECTIONS( p.data().begin(), p.data().end(),
+                                       data, data+sizeof(data)/sizeof(data[0]) );
+    }
+
+    SENF_CHECK_NO_THROW( p->disable_flags() );
+    SENF_CHECK_NO_THROW( p->disable_dbmAntennaSignal() );
+
+    p.finalizeAll();
+
+    {
+        unsigned char data[] = {
+            /*  0 */ 0x00,                                           // version
+            /*    */ 0x00,
+            /*  2 */ 0x19, 0x00,                                     // length
+            /*  4 */ 0x4d, 0x18, 0x00, 0x00,                         // presentFlags
+            /*  8 */ 0x02, 0xe6, 0x8a, 0xdf, 0x12, 0x00, 0x00, 0x00, // tsft
+            /* 16 */ 0x0c,                                           // rate
+            /*    */ 0x00,
+            /* 18 */ 0xc8, 0x14,                                     // channel frequency
+            /* 20 */ 0x40, 0x01,                                     // channel flags
+            /* 22 */ 0xa0,                                           // dbmAntennaNoise
+            /* 23 */ 0x02,                                           // antenna
+            /* 24 */ 0x23                                            // dbAntennaSignal
+        };
+        BOOST_CHECK_EQUAL_COLLECTIONS( p.data().begin(), p.data().end(),
+                                       data, data+sizeof(data)/sizeof(data[0]) );
+    }
 }
-#endif
 
 SENF_AUTO_UNIT_TEST(RadiotapPacket_packet_ath9k)
 {