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_STATS_HXX_
00023 # define WIFI_STATS_STATS_HXX_
00024
00025 # include <wipal/wifi/stats/stats.hh>
00026 # include <wipal/wifi/dissector/dissector.hh>
00027
00028 namespace wpl
00029 {
00030
00031 namespace wifi
00032 {
00033
00034 namespace stats
00035 {
00036
00037
00038
00039
00040
00041 inline
00042 stats::hooks::hooks(): type (type::reserved),
00043 subtype (-1),
00044 retx (false),
00045 a1 (0),
00046 a2 (0)
00047 {
00048 }
00049
00050 inline
00051 stats::state::state(unsigned last_frame_id,
00052 const seqctl& last_sc,
00053 const tool::microseconds& last_rx_stamp):
00054 last_frame_id (last_frame_id),
00055 last_sc (last_sc),
00056 last_rx_stamp (last_rx_stamp)
00057 {
00058 }
00059
00060
00061
00062
00063
00064 inline
00065 std::ostream&
00066 stats::print(std::ostream& o) const
00067 {
00068 return o << modules_;
00069 }
00070
00071 inline
00072 void
00073 stats::restart()
00074 {
00075 states_.clear();
00076 aps_.clear();
00077 modules_.restart();
00078 }
00079
00080 template <class M>
00081 const M&
00082 stats::get() const
00083 {
00084 return modules_.get<M>();
00085 }
00086
00087
00088
00089
00090
00091 inline
00092 void
00093 stats::hooks::invalid_type_or_subtype_hook(const void* f, size_t,
00094 dissector_status::status)
00095 {
00096 type = type_of(f);
00097 subtype = subtype_of(f);
00098 retx = control_flag(3, f);
00099 }
00100
00101 inline
00102 void
00103 stats::hooks::addr_hook(const void* f, size_t, unsigned i, const addr& a)
00104 {
00105 bool account_addr = true;
00106
00107 switch (i)
00108 {
00109 case 1:
00110 type = type_of(f);
00111 subtype = subtype_of(f);
00112 retx = control_flag(3, f);
00113 a1 = &a;
00114
00115 switch (type)
00116 {
00117 case type::control:
00118 account_addr = subtype != ctl::subtype::ps_poll; break;
00119 case type::data:
00120 account_addr = not to_ds(f) or from_ds(f); break;
00121 default: break;
00122 }
00123 break;
00124
00125 case 2:
00126 a2 = &a;
00127
00128 if (type == type::management or type == type::data)
00129 id = seqnum_counter_id (a, addr::broadcast());
00130
00131 switch (type)
00132 {
00133 case type::control:
00134 account_addr =
00135 subtype != ctl::subtype::cf_end and
00136 subtype != ctl::subtype::cf_end_cf_ack; break;
00137 case type::data:
00138 account_addr = to_ds(f) or not from_ds(f); break;
00139 default: break;
00140 }
00141 break;
00142
00143 case 3:
00144
00145 switch (type)
00146 {
00147 case type::data: account_addr = to_ds(f) or from_ds(f); break;
00148 case type::management: account_addr = false; break;
00149 default: break;
00150 }
00151 break;
00152 }
00153
00154 if (account_addr)
00155 addrs.push_back(std::make_pair(i, &a));
00156 }
00157
00158 inline
00159 void
00160 stats::hooks::seq_ctl_hook(const void*, size_t, unsigned fn, unsigned sn)
00161 {
00162 sc = seqctl (sn, fn);
00163 }
00164
00165 inline
00166 void
00167 stats::hooks::qos_ctl_hook(const void*, size_t,
00168 unsigned tid, bool, unsigned, unsigned)
00169 {
00170 assert(a1);
00171 assert(id);
00172
00173 if (*a1 == addr::broadcast())
00174 return;
00175
00176 id->get<1>() = *a1;
00177 id->get<2>() = tid;
00178 }
00179
00180 inline
00181 void
00182 stats::hooks::beacon_hook(const mgt::header* header, size_t caplen)
00183 {
00184 beacon = beacon_data (header, caplen);
00185 }
00186
00187 inline
00188 stats::hooks::beacon_data::beacon_data(const mgt::header* header,
00189 size_t caplen):
00190 ap (0),
00191 bss (0),
00192 ibss (false)
00193 {
00194 if (caplen < sizeof (*header))
00195 return;
00196
00197 ap = header->addrs + mgt::header::sa;
00198 bss = header->addrs + mgt::header::bssid;
00199
00200 const struct beacon_body
00201 {
00202 uint64_t timestamp;
00203 uint16_t beacon_interval;
00204 uint16_t capability;
00205 ssid_elt ssid;
00206 }
00207 *const body = reinterpret_cast<const beacon_body*> (header + 1);
00208
00209 if (caplen < sizeof (*header) + sizeof (*body) or
00210 body->ssid.elt_id != ssid_elt::ssid_elt_id or
00211 caplen < sizeof (*header) + sizeof (*body) + body->ssid.length)
00212 return;
00213
00214 ibss = tool::extract_little_endian_short_u(body->capability) & 0x2;
00215 ssid = essid (body->ssid);
00216 }
00217
00218 template <class Phy, class Frame>
00219 void
00220 stats::account(const Frame& f)
00221 {
00222 const dissector<hooks> d = dissect<Phy, hooks>(f);
00223
00224 if (d.status() == dissector_status::invalid)
00225 return;
00226
00227
00228
00229
00230 bool from_ap = false;
00231
00232 if (d.beacon and not d.beacon->ibss)
00233 {
00234 from_ap = true;
00235 if (d.beacon->ap) aps_.insert(*d.beacon->ap);
00236 if (d.beacon->bss) aps_.insert(*d.beacon->bss);
00237 }
00238 else if (d.a2 and aps_.find(*d.a2) != aps_.end())
00239 from_ap = true;
00240
00241
00242
00243 size_t len;
00244 const pkt::metadata& meta = f.meta();
00245 {
00246 const Phy* const phy = static_cast<const Phy*> (f.bytes());
00247 const size_t phy_len = phy->len(meta.caplen, f.swapped());
00248 const size_t meta_len = meta.len;
00249
00250 if (phy_len > meta_len)
00251 {
00252 std::cerr << f << ": Too short to make sense.\n"
00253 << f << ": Length is " << meta_len << ".\n"
00254 << f << ": PHY header length should be " << phy_len
00255 << '.' << std::endl;
00256 len = 0;
00257 }
00258 else
00259 len = meta_len - phy_len;
00260 }
00261
00262
00263
00264
00265 modules_.account_frame(f, len, d.type, d.subtype,
00266 d.retx, d.a1, d.a2, from_ap);
00267 for (size_t i = 0; i < d.addrs.size(); ++i)
00268 modules_.account_addr(d.addrs[i].first, *d.addrs[i].second);
00269 if (d.beacon)
00270 modules_.account_beacon(f, d.beacon->ap, d.beacon->bss,
00271 d.beacon->ssid, d.beacon->ibss);
00272 if (d.id)
00273 update_states(f, d);
00274 }
00275
00276 template <class Frame>
00277 void
00278 stats::update_states(const Frame& f, const dissector<hooks>& d)
00279 {
00280 assert(d.id);
00281 assert(d.sc);
00282
00283 const unsigned frame_id = f.meta().id;
00284 const tool::microseconds& rx_stamp = f.microseconds();
00285 const state_map::iterator i = states_.find(*d.id);
00286
00287 state new_state (frame_id, *d.sc, rx_stamp);
00288
00289
00290 if (i == states_.end())
00291 {
00292 states_.insert(std::make_pair(*d.id, new_state));
00293 return;
00294 }
00295
00296 const state& s = i->second;
00297 const tool::microseconds delta_t = rx_stamp - s.last_rx_stamp;
00298
00299 if (state::lifetime < delta_t)
00300 modules_.account_expired();
00301 else if (*d.sc < s.last_sc)
00302 modules_.account_out_of_order();
00303 else if (*d.sc == s.last_sc)
00304 {
00305 if (not d.retx)
00306 modules_.account_duplicate();
00307 }
00308 else
00309 {
00310 assert(*d.sc > s.last_sc);
00311
00312 if (d.retx)
00313 modules_.account_miss();
00314
00315 const int delta_s = d.sc->seqnum_get() - s.last_sc.seqnum_get();
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 if (1 < delta_s)
00327 {
00328 if (delta_s < delta_t / state::min_frame_sending_time)
00329 modules_.account_gap(delta_s - 1);
00330 else
00331 modules_.account_seq_anomaly();
00332 }
00333 }
00334 i->second = new_state;
00335 }
00336
00337 }
00338
00339 }
00340
00341 }
00342
00343 #endif // ! WIFI_STATS_STATS_HXX_