00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef WIFI_STATS_HXX_
00023 # define WIFI_STATS_HXX_
00024
00025 # include <cmath>
00026 # include <iostream>
00027
00028 # include <wipal/wifi/frame.hh>
00029
00030 # include "wifi_stats.hh"
00031
00032 namespace stats
00033 {
00034
00035
00036
00037
00038
00039 inline
00040 distribution::distribution(float min, float max, float gran):
00041 min_ (min),
00042 max_ (max),
00043 gran_ (gran),
00044 dist_ (2 + size_t (std::ceil((max - min) / gran))),
00045 total_ (0)
00046 {
00047 }
00048
00049 inline
00050 void
00051 distribution::insert(float p)
00052 {
00053 size_t i;
00054
00055 if (p < min_)
00056 i = 0;
00057 else if (p > max_)
00058 i = dist_.size() - 1;
00059 else
00060 i = 1 + size_t ((p - min_) / gran_);
00061
00062 ++dist_[i];
00063 ++total_;
00064 }
00065
00066 inline
00067 std::ostream&
00068 operator << (std::ostream& os, const distribution& d)
00069 {
00070 return d.dump(os);
00071 }
00072
00073
00074
00075
00076
00077 inline
00078 boost::posix_time::time_duration
00079 timed_events::insert(const ptime& ev)
00080 {
00081 const size_t old_size = evs_.size();
00082
00083 evs_.push_back(ev);
00084 return
00085 old_size ? ev - evs_[old_size - 1]: boost::posix_time::not_a_date_time;
00086 }
00087
00088 inline
00089 const std::vector<boost::posix_time::ptime>&
00090 timed_events::evs() const
00091 {
00092 return evs_;
00093 }
00094
00095 template <class C>
00096 std::vector<boost::posix_time::time_duration>
00097 its(const C& evs)
00098 {
00099 using boost::posix_time::time_duration;
00100
00101 typedef typename C::const_iterator const_iterator;
00102
00103 std::vector<time_duration> r;
00104
00105 const_iterator curr = evs.begin();
00106 for (const_iterator prev = curr++; curr != evs.end(); prev = curr++)
00107 r.push_back(*curr - *prev);
00108
00109 return r;
00110 }
00111
00112 template <class C>
00113 boost::posix_time::time_duration
00114 mean(const C& its)
00115 {
00116 boost::posix_time::time_duration m (0, 0, 0, 0);
00117
00118 for (typename C::const_iterator i = its.begin(); i != its.end(); ++i)
00119 m += *i;
00120 return m / its.size();
00121 }
00122
00123 template <class C>
00124 boost::posix_time::time_duration
00125 stddev(const C& its, const boost::posix_time::time_duration* mean_)
00126 {
00127 using boost::posix_time::time_duration;
00128 using boost::posix_time::microseconds;
00129
00130 time_duration m = mean_ ? *mean_ : mean(its);
00131 double d = 0;
00132
00133 for (typename C::const_iterator i = its.begin(); i != its.end(); ++i)
00134 d += std::pow(double ((*i - m).total_microseconds()), 2);
00135 return microseconds (unsigned (std::sqrt(d / its.size())));
00136 }
00137
00138 template <class C>
00139 boost::posix_time::time_duration
00140 median(const C& its)
00141 {
00142 using boost::posix_time::time_duration;
00143
00144 const size_t s = its.size();
00145 const size_t m = s / 2;
00146 std::vector<time_duration> r (m + 1);
00147
00148 std::partial_sort_copy(its.begin(), its.end(), r.begin(), r.end());
00149 return s % 2 ? r[m] : (r[m - 1] + r[m]) / 2;
00150 }
00151
00152 template <class C>
00153 distribution
00154 make_distribution(float min, float max, float gran, const C& its)
00155 {
00156 distribution r (min, max, gran);
00157
00158 for (typename C::const_iterator it = its.begin(); it != its.end(); ++it)
00159 r.insert(it->total_microseconds());
00160
00161 return r;
00162 }
00163
00164
00165
00166
00167
00168 inline
00169 addr_state::addr_state():
00170 pr_answers (),
00171 last_presp (0),
00172 heard_as_tmiter (0),
00173 mentioned_as_ap (0)
00174 {
00175 for (unsigned i = 0; i < sizeof (pr_stats) / sizeof (*pr_stats); ++i)
00176 pr_stats[i] = timed_events ();
00177 }
00178
00179 inline
00180 addr_state::presp_attr::presp_attr():
00181 arrival (),
00182 ack_expected_arrival (),
00183 ack_arrival (),
00184 retries (0),
00185 acks (0)
00186 {
00187 }
00188
00189
00190
00191
00192
00193 inline
00194 probe_requests::probe_requests(addr_state_map& m):
00195 count (0),
00196 addrs (&m),
00197 it_dist (min, max, gran)
00198 {
00199 }
00200
00201 inline
00202 void
00203 probe_requests::update(const wpl::wifi::mgt::header *frame,
00204 const ptime& toa)
00205 {
00206 using boost::posix_time::time_duration;
00207 using wpl::wifi::mgt::header;
00208
00209 addr_state_map& m = *addrs;
00210
00211 count++;
00212 m[frame->addrs[header::da]].pr_stats[header::da].insert(toa);
00213 m[frame->addrs[header::bssid]].pr_stats[header::bssid].insert(toa);
00214
00215 addr_state& s = m[frame->addrs[header::sa]];
00216
00217 const time_duration d = s.pr_stats[header::sa].insert(toa);
00218 if (not d.is_not_a_date_time())
00219 it_dist.insert(d.total_microseconds());
00220
00221 s.pr_answers.push_back(addr_state::preq_answer_set ());
00222 }
00223
00224
00225
00226
00227
00228 inline
00229 frames::frames():
00230 frame_count (0),
00231 total_len (0),
00232 total_caplen (0),
00233 phy_error_count (0),
00234 pr (addrs),
00235 first (),
00236 last ()
00237 {
00238 }
00239
00240 inline
00241 void
00242 frames::update(const wpl::pkt::metadata& h, const void* f)
00243 {
00244 using boost::posix_time::microseconds;
00245
00246 const ptime toa = update_counters(h);
00247 const wpl::wifi::addr *ta = wpl::wifi::transmitter_address(f);
00248 const wpl::wifi::addr *ba = wpl::wifi::bssid_address(f);
00249
00250 if (ta)
00251 ++addrs[*ta].heard_as_tmiter;
00252 if (ba and *ba != wpl::wifi::addr::broadcast())
00253 ++addrs[*ba].mentioned_as_ap;
00254
00255 const wpl::wifi::type::frame_type ty = wpl::wifi::type_of(f);
00256 const unsigned subty = wpl::wifi::subtype_of(f);
00257
00258 switch (ty)
00259 {
00260 case wpl::wifi::type::management:
00261 {
00262 namespace mgt = wpl::wifi::mgt;
00263 namespace subtype = mgt::subtype;
00264
00265 const mgt::header* mh = reinterpret_cast<const mgt::header*> (f);
00266
00267 switch (subty)
00268 {
00269 case subtype::probe_req:
00270
00271
00272
00273 pr.update(mh, toa);
00274 break;
00275 case subtype::probe_resp:
00276 {
00277 typedef addr_state::pr_answers_t pr_answers_t;
00278
00279 const wpl::wifi::addr& sa = mh->addrs[mgt::header::sa];
00280 const wpl::wifi::addr& da = mh->addrs[mgt::header::da];
00281 pr_answers_t& pr_answers = addrs[da].pr_answers;
00282
00283
00284
00285 if (not pr_answers.empty())
00286 {
00287 typedef addr_state::presp_attr presp_attr;
00288 typedef addr_state::preq_answer_set::iterator iterator;
00289 typedef
00290 addr_state::preq_answer_set::value_type
00291 value_type;
00292
00293 const unsigned duration =
00294 wpl::tool::extract_little_endian_short_u(mh->duration);
00295 if (duration > 32767)
00296 std::cerr << "WARNING: Invalid duration." << std::endl;
00297
00298 std::pair<iterator, bool> insertion = pr_answers.back().
00299 insert(value_type (sa, presp_attr ()));
00300 presp_attr& attr = insertion.first->second;
00301
00302 if (not insertion.second)
00303 ++attr.retries;
00304 addrs[sa].last_presp = &attr;
00305 attr.arrival = toa;
00306 attr.ack_expected_arrival = toa + microseconds(duration);
00307 attr.ack_arrival = boost::posix_time::not_a_date_time;
00308 }
00309 break;
00310 }
00311 default:
00312 break;
00313 }
00314 break;
00315 }
00316
00317 case wpl::wifi::type::control:
00318 {
00319 namespace ack = wpl::wifi::ctl::ack;
00320 namespace subtype = wpl::wifi::ctl::subtype;
00321
00322 if (subty == subtype::ack)
00323 {
00324 const ack::header* ah =
00325 reinterpret_cast<const ack::header*> (f);
00326
00327
00328 addr_state::presp_attr* last_presp = addrs[ah->ra].last_presp;
00329
00330 if (last_presp and
00331 toa < last_presp->ack_expected_arrival + microseconds(1))
00332 {
00333 ++last_presp->acks;
00334 last_presp->ack_arrival = toa;
00335
00336
00337
00338
00339
00340 }
00341 }
00342 }
00343 break;
00344
00345 default:
00346 break;
00347 }
00348 }
00349
00350 inline
00351 void
00352 frames::update(const wpl::pkt::metadata& h, const wpl::prism::header* p)
00353 {
00354 if (p->noise.get(false))
00355 {
00356 update_counters(h);
00357 phy_error_count++;
00358 return;
00359 }
00360
00361 update(h, reinterpret_cast<const void*> (p + 1));
00362 }
00363
00364 inline
00365 boost::posix_time::ptime
00366 frames::update_counters(const wpl::pkt::metadata& h)
00367 {
00368 using boost::gregorian::date;
00369 using boost::gregorian::Jan;
00370 using boost::posix_time::seconds;
00371 using boost::posix_time::microseconds;
00372
00373 const ptime toa (date(1970, Jan, 01),
00374 seconds (h.ts.tv_sec) +
00375 microseconds (h.ts.tv_usec));
00376
00377 if (first.is_not_a_date_time())
00378 first = toa;
00379 last = toa;
00380 frame_count++;
00381 total_len += h.len;
00382 total_caplen += h.caplen;
00383
00384 return toa;
00385 }
00386
00387 }
00388
00389 #endif // ! WIFI_STATS_HXX_