src/wit_import/wit_importer.hxx

00001 /*
00002  * trace-tools - A library and a set of tools to manipulate wireless traces.
00003  * Copyright (C) 2007  Universite Pierre et Marie Curie - Paris 6
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00018  * MA  02110-1301  USA
00019  *
00020  * Author: Thomas Claveirole <thomas.claveirole@lip6.fr>
00021  */
00022 #ifndef WIT_IMPORTER_HXX_
00023 # define WIT_IMPORTER_HXX_
00024 
00025 # include <cassert>
00026 # include <utility>
00027 # include <fstream>
00028 # include <sstream>
00029 # include <iomanip>
00030 
00031 # include <boost/lexical_cast.hpp>
00032 
00033 # include <trace-tools/prism_header.hh>
00034 # include <trace-tools/wifi/timestamp.hh>
00035 # include <trace-tools/wifi/frame/dissector/dissector.hh>
00036 
00037 # include "wit_importer.hh"
00038 
00039 namespace wit
00040 {
00041 
00042   /*----------------.
00043   | importer::hooks |
00044   `----------------*/
00045 
00046   inline
00047   importer::hooks::hooks(wifi::addr_mapping& m)
00048     : mapping_ (m),
00049       addrs_ (),
00050       beacon_timestamp_ (db_null),
00051       fragnum_ (db_null),
00052       seqnum_ (db_null),
00053       error_ (db_null)
00054   {
00055   }
00056 
00057   inline
00058   std::string
00059   importer::hooks::addrs() const
00060   {
00061     return addrs_;
00062   }
00063 
00064   inline
00065   std::string
00066   importer::hooks::beacon_timestamp() const
00067   {
00068     return beacon_timestamp_;
00069   }
00070 
00071   inline
00072   std::string
00073   importer::hooks::fragnum() const
00074   {
00075     return fragnum_;
00076   }
00077 
00078   inline
00079   std::string
00080   importer::hooks::seqnum() const
00081   {
00082     return seqnum_;
00083   }
00084 
00085   inline
00086   std::string
00087   importer::hooks::error() const
00088   {
00089     return error_;
00090   }
00091 
00092   inline
00093   void
00094   importer::hooks::invalid_type_or_subtype_hook(const void*, size_t, status)
00095   {
00096     error_ = boost::lexical_cast<std::string> (bad_type_subtype);
00097   }
00098 
00099   inline
00100   void
00101   importer::hooks::truncated_frame_hook(const void*, size_t, status)
00102   {
00103     error_ = boost::lexical_cast<std::string> (malformed_802);
00104   }
00105 
00106   inline
00107   void
00108   importer::hooks::addr_hook(const void*, size_t,
00109                                  unsigned n, const wifi::addr& a)
00110   {
00111     addrs_ += boost::lexical_cast<std::string> (mapping_[a]);
00112     if (n < 4)
00113       addrs_ += '\t';
00114   }
00115 
00116   inline
00117   void
00118   importer::hooks::seq_ctl_hook(const void*, size_t,
00119                                     unsigned fragnum, unsigned seqnum)
00120   {
00121     fragnum_ = boost::lexical_cast<std::string> (fragnum);
00122     seqnum_ = boost::lexical_cast<std::string> (seqnum);
00123   }
00124 
00125   inline
00126   void
00127   importer::hooks::beacon_hook(const wifi::frame::mgt::header* h,
00128                                    size_t caplen)
00129   {
00130     if (caplen < sizeof (*h) + sizeof (wifi::timestamp))
00131       {
00132         truncated_frame_hook(h, caplen,
00133                              wifi::frame::dissector_status::valid_addr3);
00134         return;
00135       }
00136 
00137     std::ostringstream  output;
00138     output << *reinterpret_cast<const wifi::timestamp*> (h->body);
00139     beacon_timestamp_ = output.str();
00140   }
00141 
00142   inline
00143   void
00144   importer::hooks::end_of_frame_hook(const void*, size_t, status s)
00145   {
00146     using namespace wifi::frame::dissector_status;
00147 
00148     std::ostringstream  nulls;
00149     switch (s)
00150       {
00151       case valid_addr4:
00152         break;
00153 
00154       case valid_seq_ctl:
00155       case valid_addr3:
00156         addrs_ += db_null;
00157         break;
00158 
00159       case valid_addr2:
00160         nulls << db_null << '\t' << db_null;
00161         break;
00162 
00163       case valid_addr1:
00164         nulls << db_null << '\t' << db_null << '\t' << db_null;
00165         break;
00166 
00167       case valid_control:
00168       case invalid:
00169         nulls << db_null << '\t' << db_null << '\t'
00170               << db_null << '\t' << db_null;
00171         break;
00172       }
00173     addrs_ += nulls.str();
00174   }
00175 
00176   /*---------.
00177   | importer |
00178   `---------*/
00179 
00180   inline
00181   std::string
00182   importer::frames_data_filename(const std::string& prefix, unsigned channel)
00183   {
00184     assert(0 < channel);
00185     assert(channel <= channels_max);
00186 
00187     return prefix + "_c" + boost::lexical_cast<std::string> (channel);
00188   }
00189 
00190   inline
00191   std::string
00192   importer::mapping_filename(const std::string& prefix, unsigned channel)
00193   {
00194     assert(0 < channel);
00195     assert(channel <= channels_max);
00196 
00197     return frames_data_filename(prefix, channel) + "_MACIndex";
00198   }
00199 
00200   inline
00201   std::string
00202   importer::handle_time_data(const pcapxx::pkthdr* h)
00203   {
00204     using namespace boost::gregorian;
00205     using namespace boost::posix_time;
00206 
00207     std::ostringstream  time_string;
00208     const ptime         toa (date(1970, Jan, 01),
00209                              seconds (h->ts.tv_sec) +
00210                              microseconds (h->ts.tv_usec));
00211 
00212     time_string << h->ts.tv_sec
00213                 << '.'
00214                 <<  std::setw (6) << std::setfill('0') << h->ts.tv_usec
00215                 << '\t';
00216 
00217     if (last_frame_.is_not_a_date_time())
00218       time_string << db_null;
00219     else
00220       time_string << (toa - last_frame_).total_microseconds();
00221 
00222     last_frame_ = toa;
00223 
00224     return time_string.str();
00225   }
00226 
00227   inline
00228   void
00229   importer::handle_malformed_prism()
00230   {
00231     tool::datafile&     f = frames_data_[last_channel_ - 1];
00232 
00233     for (unsigned i = 0; i < 25; ++i)
00234       f << db_null << '\t';
00235     f << boost::lexical_cast<std::string> (malformed_prism)     // zErr
00236       << '\t' << db_null << '\t' << db_null << '\n';            // zErrDriver
00237                                                                 // zErrPhy
00238   }
00239 
00240   inline
00241   const prism::header*
00242   importer::handle_prism_header(const std::string& time_string,
00243                                 const void* p,
00244                                 size_t caplen)
00245   {
00246     typedef prism::header       header;
00247 
00248     bool                truncated_frame = false;
00249     const header* const prism = static_cast<const header*> (p);
00250 
00251     if (caplen < sizeof (prism::header))
00252       {
00253         truncated_frame = true;
00254         std::cerr << "WARNING: Truncated Prism header. Unknown channel, ";
00255         if (not last_channel_)
00256           {
00257             last_channel_ = 1;
00258             std::cerr << "using default value of 1.";
00259           }
00260         else
00261           std::cerr << "using last value of " << last_channel_ << '.';
00262         std::cerr << std::endl;
00263       }
00264     else
00265       last_channel_ = prism->channel.data;
00266     assert(last_channel_ > 0);
00267     assert(last_channel_ <= channels_max);
00268 
00269     tool::datafile& f = frames_data_[last_channel_ - 1];
00270 
00271     f << ++last_id_[last_channel_ - 1] << '\t'  // id
00272       << time_string << '\t';                   // aFrameTime
00273                                                 // aTimeDelta
00274 
00275     if (truncated_frame)
00276       {
00277         handle_malformed_prism();
00278         return 0;
00279       }
00280 
00281     f << prism->channel.data << '\t'            // bChannel
00282       << prism->hosttime.data << '\t'           // bHostTime
00283       << prism->mactime.data << '\t'            // bMACTime
00284       << (prism->rate.data / 2.) << '\t'        // bRate
00285       << int16_t (prism->signal.data) << '\t'   // bRssi
00286       << prism->frmlen.data << '\t';            // bSize
00287 
00288     return prism;
00289   }
00290 
00291   inline
00292   void
00293   importer::got_frame(const pcapxx::pkthdr* h, const void* p)
00294   {
00295     const std::string                   tstr = handle_time_data(h);
00296     const prism::header* const  prism = handle_prism_header(tstr, p,
00297                                                             h->caplen);
00298 
00299     if (not prism)
00300       return;
00301 
00302     tool::datafile&                     f = frames_data_[last_channel_ - 1];
00303 
00304     /*--------------------.
00305     | PHY invalid frame.  |
00306     `--------------------*/
00307 
00308     if (const unsigned noise = prism->noise.data)
00309       {
00310         for (unsigned i = 0; i < 19; ++i)
00311           f << db_null << '\t';
00312         f << driver_reported << '\t'            // zErr
00313           << noise << '\t';                     // zErrDriver
00314 
00315         /*
00316           Some black magic frome Wit's createRawDataDatabase.pl.
00317           I have absolutely no clue about the rationale.
00318         */
00319         if (noise & 8)
00320           f << prism->rssi.data << '\n';        // zErrPhy
00321         else
00322           f << db_null << '\n';                 // zErrPhy
00323       }
00324 
00325     /*----------------------------------------------.
00326     | PHY valid frame, go check the 802.11 header.  |
00327     `----------------------------------------------*/
00328 
00329     else
00330       {
00331         using namespace wifi::frame;
00332 
00333         const void* const       frame = static_cast<const void*> (prism + 1);
00334         const size_t            caplen = h->caplen - sizeof (*prism);
00335         wifi::addr_mapping&     map = mappings_[last_channel_ - 1];
00336         const dissector<hooks>  dctor (frame, caplen, map);
00337         const unsigned          type = type_of(frame);
00338         const unsigned          subtype = subtype_of(frame);
00339 
00340         f << dctor.addrs() << '\t'              // cA1_Dest
00341                                                 // cA2_Src
00342                                                 // cA3
00343                                                 // cA4
00344           << from_ds(frame) << '\t'             // cDSFrom
00345           << to_ds(frame) << '\t'               // cDSTo
00346           << duration_of(frame) << '\t'         // cDur
00347           << dctor.fragnum() << '\t'            // cFragno
00348           << control_flag(5, frame) << '\t'     // cMoredata
00349           << control_flag(2, frame) << '\t'     // cMorefrag
00350           << control_flag(7, frame) << '\t'     // cOrdered
00351           << protocol_version_of(frame) << '\t' // cProtver
00352           << control_flag(4, frame) << '\t'     // cPwrMgt
00353           << control_flag(3, frame) << '\t'     // cRetry
00354           << dctor.seqnum() << '\t'             // cSeqno
00355           << ((type << 4) | subtype) << '\t'    // cSubtype
00356           << type << '\t'                       // cType
00357           << control_flag(6, frame) << '\t'     // cWEP
00358           << dctor.beacon_timestamp() << '\t'   // dBeaconTimestamp
00359           << dctor.error() << '\t'              // zErr
00360           << db_null << '\t'                    // zErrDriver
00361           << db_null << '\n';                   // zErrPhy
00362       }
00363   }
00364 
00365 } // End of namespace wit.
00366 
00367 #endif // ! WIT_IMPORTER_HXX_

Generated on Wed Sep 12 16:02:47 2007 for trace-tools by  doxygen 1.5.3