src/wit-import/wit_importer.hxx

00001 /*
00002  * WiPal - 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 <wipal/phy/prism_header.hh>
00034 # include <wipal/wifi/timestamp.hh>
00035 # include <wipal/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.get(false); // FIXME: Endianness bug!
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     // FIXME: Lots of endianness bugs here!
00282     f << prism->channel.get(false) << '\t'              // bChannel
00283       << prism->hosttime.get(false) << '\t'             // bHostTime
00284       << prism->mactime.get(false) << '\t'              // bMACTime
00285       << (prism->rate.get(false) / 2.) << '\t'          // bRate
00286       << int16_t (prism->signal.get(false)) << '\t'     // bRssi
00287       << prism->frmlen.get(false) << '\t';              // bSize
00288 
00289     return prism;
00290   }
00291 
00292   inline
00293   void
00294   importer::operator () (const pcapxx::frame_descriptor& d)
00295   {
00296     const pcapxx::pkthdr* const h = d.pcap_header().get();
00297     const void* const           p = d.bytes().get();
00298     const std::string           tstr = handle_time_data(h);
00299     const prism::header* const  prism = handle_prism_header(tstr, p,
00300                                                             h->caplen);
00301 
00302     if (not prism)
00303       return;
00304 
00305     tool::datafile&                     f = frames_data_[last_channel_ - 1];
00306 
00307     /*--------------------.
00308     | PHY invalid frame.  |
00309     `--------------------*/
00310 
00311     // FIXME: Two endianness bugs follow.
00312 
00313     if (const unsigned noise = prism->noise.get(false))
00314       {
00315         for (unsigned i = 0; i < 19; ++i)
00316           f << db_null << '\t';
00317         f << driver_reported << '\t'            // zErr
00318           << noise << '\t';                     // zErrDriver
00319 
00320         /*
00321           Some black magic frome Wit's createRawDataDatabase.pl.
00322           I have absolutely no clue about the rationale.
00323         */
00324         if (noise & 8)
00325           f << prism->rssi.get(false) << '\n';  // zErrPhy
00326         else
00327           f << db_null << '\n';                 // zErrPhy
00328       }
00329 
00330     /*----------------------------------------------.
00331     | PHY valid frame, go check the 802.11 header.  |
00332     `----------------------------------------------*/
00333 
00334     else
00335       {
00336         using namespace wifi::frame;
00337 
00338         const void* const       frame = static_cast<const void*> (prism + 1);
00339         const size_t            caplen = h->caplen - sizeof (*prism);
00340         wifi::addr_mapping&     map = mappings_[last_channel_ - 1];
00341         const dissector<hooks>  dctor (frame, caplen, map);
00342         const unsigned          type = type_of(frame);
00343         const unsigned          subtype = subtype_of(frame);
00344 
00345         f << dctor.addrs() << '\t'              // cA1_Dest
00346                                                 // cA2_Src
00347                                                 // cA3
00348                                                 // cA4
00349           << from_ds(frame) << '\t'             // cDSFrom
00350           << to_ds(frame) << '\t'               // cDSTo
00351           << duration_of(frame) << '\t'         // cDur
00352           << dctor.fragnum() << '\t'            // cFragno
00353           << control_flag(5, frame) << '\t'     // cMoredata
00354           << control_flag(2, frame) << '\t'     // cMorefrag
00355           << control_flag(7, frame) << '\t'     // cOrdered
00356           << protocol_version_of(frame) << '\t' // cProtver
00357           << control_flag(4, frame) << '\t'     // cPwrMgt
00358           << control_flag(3, frame) << '\t'     // cRetry
00359           << dctor.seqnum() << '\t'             // cSeqno
00360           << ((type << 4) | subtype) << '\t'    // cSubtype
00361           << type << '\t'                       // cType
00362           << control_flag(6, frame) << '\t'     // cWEP
00363           << dctor.beacon_timestamp() << '\t'   // dBeaconTimestamp
00364           << dctor.error() << '\t'              // zErr
00365           << db_null << '\t'                    // zErrDriver
00366           << db_null << '\n';                   // zErrPhy
00367       }
00368   }
00369 
00370 } // End of namespace wit.
00371 
00372 #endif // ! WIT_IMPORTER_HXX_

Generated on Wed Jan 16 16:15:14 2008 for wipal by  doxygen 1.5.4