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