From: g0dil Date: Fri, 20 Aug 2010 06:40:22 +0000 (+0000) Subject: Packets/80211Bundle: RadiotapPacketParser create and field update X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=01e8fa6cf173c60c3deb47c29c6d56718ef9548e;p=senf.git Packets/80211Bundle: RadiotapPacketParser create and field update git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1693 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/senf/Packets/80211Bundle/RadiotapPacket.cc b/senf/Packets/80211Bundle/RadiotapPacket.cc index 7c6d84a..4bf458d 100644 --- a/senf/Packets/80211Bundle/RadiotapPacket.cc +++ b/senf/Packets/80211Bundle/RadiotapPacket.cc @@ -28,6 +28,7 @@ // Custom includes #include "WLANPacket.hh" #include +#include 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 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< 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 index 0000000..2164b40 --- /dev/null +++ b/senf/Packets/80211Bundle/RadiotapPacket.cci @@ -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 +// +// 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(data().end()-4); +} + +prefix_ bool senf::RadiotapPacketParser::has_fcs() +{ + return flagsPresent() && flags().fcsAtEnd(); +} + +prefix_ unsigned senf::RadiotapPacketParser::frameType() +{ + return parse(length()).frameType(); +} +//////////////////////////////////////// +// private members + +prefix_ void senf::RadiotapPacketParser::initField(unsigned index) +{ + updatePresentFlags( presentFlags() | (1< +// +// 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 +prefix_ Parser senf::RadiotapPacketParser::parseField(unsigned index) +{ + return parse(currentTable()[index]); +} + +///////////////////////////////cti.e/////////////////////////////////////// +#undef prefix_ + + +// 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.hh b/senf/Packets/80211Bundle/RadiotapPacket.hh index 966f2b7..f6bd76e 100644 --- a/senf/Packets/80211Bundle/RadiotapPacket.hh +++ b/senf/Packets/80211Bundle/RadiotapPacket.hh @@ -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< (0); } - RadiotapPacketParser_Flags flags() - { return parseField (1); } - UInt8Parser rate() - { return parseField (2); } - RadiotapPacketParser_ChannelOptions channelOptions() - { return parseField(3); } - UInt16LSBParser fhss() - { return parseField (4); } - Int8Parser dbmAntennaSignal() - { return parseField (5); } - Int8Parser dbmAntennaNoise() - { return parseField (6); } - UInt16LSBParser lockQuality() - { return parseField (7); } - UInt16LSBParser txAttenuation() - { return parseField (8); } - UInt16LSBParser dbTxAttenuation() - { return parseField (9); } - Int8Parser dbmTxAttenuation() - { return parseField (10); } - UInt8Parser antenna() - { return parseField (11); } - UInt8Parser dbAntennaSignal() - { return parseField (12); } - UInt8Parser dbAntennaNoise() - { return parseField (13); } - UInt32Parser headerFcs() - { return parseField (14); } - - unsigned frameType() - { return parse(length()).frameType(); } - - UInt32Parser fcs() - { return parse(data().end()-4); } +# define FIELD(name,type,index) \ + typedef type name ## _t; \ + type name() { return parseField(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_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 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 - Parser parseField(unsigned index) - { return parse(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 diff --git a/senf/Packets/80211Bundle/RadiotapPacket.test.cc b/senf/Packets/80211Bundle/RadiotapPacket.test.cc index 46f8a63..d5631fd 100644 --- a/senf/Packets/80211Bundle/RadiotapPacket.test.cc +++ b/senf/Packets/80211Bundle/RadiotapPacket.test.cc @@ -31,6 +31,15 @@ #include ///////////////////////////////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) {