00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef WIFI_FRAME_STATS_STATS_HXX_
00023 # define WIFI_FRAME_STATS_STATS_HXX_
00024
00025 # include <wipal/wifi/frame/stats/stats.hh>
00026 # include <wipal/wifi/frame/dissector/dissector.hh>
00027
00028 namespace wifi
00029 {
00030
00031 namespace frame
00032 {
00033
00034 namespace stats
00035 {
00036
00037
00038
00039
00040
00041 inline
00042 stats::stats(): me_ (sc_)
00043 {
00044 }
00045
00046 inline
00047 stats::hooks::hooks(stats& parent): type (-1),
00048 subtype (-1),
00049 retx (false),
00050 txer_type (unknown),
00051 receiver (0),
00052 parent (&parent)
00053 {
00054 }
00055
00056 inline
00057 stats::state::state(unsigned last_frame_id,
00058 const seqctl& last_sc,
00059 const tool::microseconds& last_rx_stamp):
00060 last_frame_id (last_frame_id),
00061 last_sc (last_sc),
00062 last_rx_stamp (last_rx_stamp)
00063 {
00064 }
00065
00066
00067
00068
00069
00070 inline
00071 void
00072 stats::restart()
00073 {
00074 states_.clear();
00075 df_.restart();
00076 tp_.restart();
00077 ay_.restart();
00078 ag_.restart();
00079 bg_.restart();
00080 ig_.restart();
00081 sg_.restart();
00082 pg_.restart();
00083 }
00084
00085 inline
00086 std::ostream&
00087 stats::print(std::ostream& o) const
00088 {
00089 return
00090 o << df_ << me_ << sc_ << '\n'
00091 << "begin gap length frequencies\n" << gl_
00092 << "end gap length frequencies\n\n"
00093 << "begin T-Fi plot\n" << tp_ << "end T-Fi plot\n\n"
00094 << "begin BSS figures\n" << bs_ << "end BSS figures\n\n"
00095 << "begin SSID figures\n" << ss_ << "end SSID figures\n\n"
00096 << "begin activity\n" << ay_ << "end activity\n\n"
00097 << "begin MAC addr. growth\n" << ag_ << "end MAC addr. growth\n\n"
00098 << "begin BSSID growth\n" << bg_ << "end BSSID growth\n\n"
00099 << "begin IBSSID growth\n" << ig_ << "end IBSSID growth\n\n"
00100 << "begin SSID growth\n" << sg_ << "end SSID growth\n\n"
00101 << "begin AP growth\n" << pg_ << "end AP growth\n"
00102 << std::flush;
00103 }
00104
00105
00106
00107
00108
00109 inline
00110 const delimiter_frames&
00111 stats::delimiter_frames_get() const
00112 {
00113 return df_;
00114 }
00115
00116 inline
00117 const simple_counters&
00118 stats::simple_counters_get() const
00119 {
00120 return sc_;
00121 }
00122
00123 inline
00124 const gap_lengths&
00125 stats::gap_lengths_get() const
00126 {
00127 return gl_;
00128 }
00129
00130 inline
00131 const missed_estimations&
00132 stats::missed_estimations_get() const
00133 {
00134 return me_;
00135 }
00136
00137 inline
00138 const tfi_plot&
00139 stats::tfi_plot_get() const
00140 {
00141 return tp_;
00142 }
00143
00144 inline
00145 const bss_stats&
00146 stats::bss_stats_get() const
00147 {
00148 return bs_;
00149 }
00150
00151 inline
00152 const ssid_stats&
00153 stats::ssid_stats_get() const
00154 {
00155 return ss_;
00156 }
00157
00158 inline
00159 const activity&
00160 stats::activity_get() const
00161 {
00162 return ay_;
00163 }
00164
00165 inline
00166 const stats::addr_growth&
00167 stats::addr_growth_get() const
00168 {
00169 return ag_;
00170 }
00171
00172 inline
00173 const stats::bssid_growth&
00174 stats::bssid_growth_get() const
00175 {
00176 return bg_;
00177 }
00178
00179 inline
00180 const stats::ssid_growth&
00181 stats::ssid_growth_get() const
00182 {
00183 return sg_;
00184 }
00185
00186 inline
00187 const stats::ap_growth&
00188 stats::ap_growth_get() const
00189 {
00190 return pg_;
00191 }
00192
00193
00194
00195
00196
00197 inline
00198 void
00199 stats::hooks::invalid_type_or_subtype_hook(const void* f, size_t,
00200 dissector_status::status)
00201 {
00202 type = type_of(f);
00203 subtype = subtype_of(f);
00204 retx = control_flag(3, f);
00205 }
00206
00207 inline
00208 void
00209 stats::hooks::addr_hook(const void* f, size_t,
00210 unsigned i, const addr& a)
00211 {
00212 bool account_addr = true;
00213
00214 switch (i)
00215 {
00216 case 1:
00217 type = type_of(f);
00218 subtype = subtype_of(f);
00219 retx = control_flag(3, f);
00220 receiver = &a;
00221
00222 switch (type)
00223 {
00224 case type::control:
00225 account_addr = subtype != ctl::subtype::ps_poll; break;
00226 case type::data:
00227 account_addr = not to_ds(f) or from_ds(f); break;
00228 default: break;
00229 }
00230 break;
00231
00232 case 2:
00233 txer_type =
00234 parent->aps_.find(a) == parent->aps_.end() ? client : ap;
00235
00236 if (type == frame::type::management or type == frame::type::data)
00237 id = state_id (a, addr::broadcast());
00238
00239 switch (type)
00240 {
00241 case type::control:
00242 account_addr =
00243 subtype != ctl::subtype::cf_end and
00244 subtype != ctl::subtype::cf_end_cf_ack; break;
00245 case type::data:
00246 account_addr = to_ds(f) or not from_ds(f); break;
00247 default: break;
00248 }
00249 break;
00250
00251 case 3:
00252
00253 switch (type)
00254 {
00255 case type::data: account_addr = to_ds(f) or from_ds(f); break;
00256 case type::management: account_addr = false; break;
00257 default: break;
00258 }
00259 break;
00260 }
00261
00262 if (account_addr)
00263 parent->account_addr(a);
00264 }
00265
00266 inline
00267 void
00268 stats::hooks::seq_ctl_hook(const void*, size_t, unsigned fn, unsigned sn)
00269 {
00270 sc = seqctl (sn, fn);
00271 }
00272
00273 inline
00274 void
00275 stats::hooks::qos_ctl_hook(const void*, size_t,
00276 unsigned tid,
00277 bool, unsigned, unsigned)
00278 {
00279 assert(id);
00280
00281 if (*receiver == addr::broadcast())
00282 return;
00283
00284 id->get<1>() = *receiver;
00285 id->get<2>() = tid;
00286 }
00287
00288 inline
00289 void
00290 stats::hooks::beacon_hook(const mgt::header* header, size_t caplen)
00291 {
00292 beacon = beacon_header (header, caplen);
00293
00294 const beacon_body* bb =
00295 reinterpret_cast<const beacon_body*> (header + 1);
00296
00297 if (caplen < sizeof (*header) + sizeof (*bb))
00298 return;
00299
00300 if ((tool::extract_little_endian_short_u(bb->capability) & 0x3) == 1)
00301 {
00302 txer_type = ap;
00303 parent->aps_.insert(header->addrs[mgt::header::sa]);
00304 parent->aps_.insert(header->addrs[mgt::header::bssid]);
00305 }
00306 }
00307
00308 template <class Phy, class Frame>
00309 void
00310 stats::account(const Frame& f)
00311 {
00312 const stats_dissector d = dissect<Phy, hooks>(f, hooks (*this));
00313
00314 if (d.status() == dissector_status::invalid)
00315 return;
00316
00317 account_frame<Phy>(f, d);
00318 if (d.beacon)
00319 account_beacon(f.microseconds(), d.beacon->first, d.beacon->second,
00320 d.txer_type == client);
00321
00322 if (d.id)
00323 update_states(f, d);
00324 }
00325
00326 template <class Frame>
00327 void
00328 stats::update_states(const Frame& f, const stats_dissector& d)
00329 {
00330 assert(d.id);
00331 assert(d.sc);
00332
00333 const unsigned frame_id = f.id();
00334 const tool::microseconds& rx_stamp = f.microseconds();
00335 const state_map::iterator i = states_.find(*d.id);
00336
00337 state new_state (frame_id, *d.sc, rx_stamp);
00338
00339
00340 if (i == states_.end())
00341 {
00342 states_.insert(std::make_pair(*d.id, new_state));
00343 return;
00344 }
00345
00346 const state& s = i->second;
00347 const tool::microseconds delta_t = rx_stamp - s.last_rx_stamp;
00348
00349 if (state_lifetime < delta_t)
00350 account_expired();
00351 else if (*d.sc < s.last_sc)
00352 account_out_of_order();
00353 else if (*d.sc == s.last_sc)
00354 {
00355 if (not d.retx)
00356 account_duplicate();
00357 }
00358 else
00359 {
00360 assert(*d.sc > s.last_sc);
00361
00362 if (d.retx)
00363 account_miss();
00364
00365 const int delta_s = d.sc->seqnum_get() - s.last_sc.seqnum_get();
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376 if (1 < delta_s)
00377 {
00378 if (delta_s < delta_t / min_frame_sending_time)
00379 account_gap(delta_s - 1);
00380 else
00381 account_seq_anomaly();
00382 }
00383 }
00384 i->second = new_state;
00385 }
00386
00387 template <class PhyHeader, class Frame>
00388 void
00389 stats::account_frame(const Frame& f, const stats_dissector& d)
00390 {
00391 const tool::microseconds tstamp = f.microseconds();
00392 const bool from_ap = d.txer_type == ap;
00393 const pcapxx::pkthdr& pcap = *f.pcap_header();
00394 const PhyHeader* phy = reinterpret_cast<const PhyHeader*>
00395 (f.bytes().get());
00396 const size_t phy_len = phy->len(pcap.caplen, f.swapped());
00397
00398 size_t len;
00399
00400 if (phy_len > pcap.len)
00401 {
00402 std::cerr << "WARNING: Packet " << f
00403 << " too short to make sense.\n"
00404 << "WARNING: Packet length is " << pcap.len << ".\n"
00405 << "WARNING: PHY header length should be " << phy_len
00406 << '.' << std::endl;
00407 len = 0;
00408 }
00409 else
00410 len = pcap.len - phy_len;
00411
00412 df_.account_frame(tstamp, pcap.ts);
00413 sc_.account_frame(len, d.type, d.subtype, d.retx, from_ap);
00414 ay_.account_frame(tstamp, len, d.type, d.subtype, from_ap);
00415 tp_.account_frame(f.id(), tstamp);
00416
00417
00418 ag_.update(tstamp);
00419 bg_.update(tstamp);
00420 ig_.update(tstamp);
00421 sg_.update(tstamp);
00422 pg_.update(tstamp);
00423 }
00424
00425 inline
00426 void
00427 stats::account_beacon(const tool::microseconds& tstamp,
00428 const mgt::header* header,
00429 size_t caplen,
00430 bool ibss)
00431 {
00432 if (caplen < sizeof (*header))
00433 return;
00434
00435 const wifi::addr& ap = header->addrs[mgt::header::sa];
00436 const wifi::addr& bss = header->addrs[mgt::header::bssid];
00437
00438 me_.account_beacon(tstamp, ap);
00439 bs_.account_beacon(bss, ap);
00440 if (ibss)
00441 ig_.update(bss);
00442 else
00443 bg_.update(bss);
00444 pg_.update(ap);
00445
00446 const beacon_body* bb =
00447 reinterpret_cast<const beacon_body*> (header + 1);
00448
00449 if (caplen < sizeof (*header) + sizeof (*bb) or
00450 caplen < sizeof (*header) + sizeof (*bb) + bb->ssid_len)
00451 return;
00452
00453 const std::string ssid (bb->ssid, bb->ssid + bb->ssid_len);
00454
00455 ss_.account_beacon(ssid);
00456 sg_.update(ssid);
00457 }
00458
00459 inline
00460 void
00461 stats::account_miss()
00462 {
00463 me_.account_miss();
00464 tp_.account_miss();
00465 }
00466
00467 inline
00468 void
00469 stats::account_gap(unsigned gaplen)
00470 {
00471 sc_.account_gap();
00472 gl_.account_gap(gaplen);
00473 me_.account_gap(gaplen);
00474 tp_.account_gap(gaplen);
00475 }
00476
00477 inline
00478 void
00479 stats::account_expired()
00480 {
00481 sc_.account_expired();
00482 }
00483
00484 inline
00485 void
00486 stats::account_out_of_order()
00487 {
00488 sc_.account_out_of_order();
00489 }
00490
00491 inline
00492 void
00493 stats::account_duplicate()
00494 {
00495 sc_.account_duplicate();
00496 }
00497
00498 inline
00499 void
00500 stats::account_seq_anomaly()
00501 {
00502 sc_.account_seq_anomaly();
00503 }
00504
00505 inline
00506 void
00507 stats::account_addr(const addr& a)
00508 {
00509 ag_.update(a);
00510 }
00511
00512 }
00513
00514 }
00515
00516 }
00517
00518 #endif // ! WIFI_FRAME_STATS_STATS_HXX_