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::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 == frame::type::management or type == frame::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(&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 pcapxx::pkthdr& pcap = *f.pcap_header();
00245 {
00246 const Phy* const phy = reinterpret_cast<const Phy*> (f.bytes().
00247 get());
00248 const size_t phy_len = phy->len(pcap.caplen, f.swapped());
00249 const size_t pcap_len = pcap.len;
00250
00251 if (phy_len > pcap_len)
00252 {
00253 std::cerr << f << ": Too short to make sense.\n"
00254 << f << ": Length is " << pcap_len << ".\n"
00255 << f << ": PHY header length should be " << phy_len
00256 << '.' << std::endl;
00257 len = 0;
00258 }
00259 else
00260 len = pcap_len - phy_len;
00261 }
00262
00263
00264
00265
00266 modules_.account_frame(f, len, d.type, d.subtype,
00267 d.retx, d.a1, d.a2, from_ap);
00268 BOOST_FOREACH(const addr& a, d.addrs)
00269 modules_.account_addr(a);
00270 if (d.beacon)
00271 modules_.account_beacon(f, d.beacon->ap, d.beacon->bss,
00272 d.beacon->ssid, d.beacon->ibss);
00273 if (d.id)
00274 update_states(f, d);
00275 }
00276
00277 template <class Frame>
00278 void
00279 stats::update_states(const Frame& f, const dissector<hooks>& d)
00280 {
00281 assert(d.id);
00282 assert(d.sc);
00283
00284 const unsigned frame_id = f.id();
00285 const tool::microseconds& rx_stamp = f.microseconds();
00286 const state_map::iterator i = states_.find(*d.id);
00287
00288 state new_state (frame_id, *d.sc, rx_stamp);
00289
00290
00291 if (i == states_.end())
00292 {
00293 states_.insert(std::make_pair(*d.id, new_state));
00294 return;
00295 }
00296
00297 const state& s = i->second;
00298 const tool::microseconds delta_t = rx_stamp - s.last_rx_stamp;
00299
00300 if (state::lifetime < delta_t)
00301 modules_.account_expired();
00302 else if (*d.sc < s.last_sc)
00303 modules_.account_out_of_order();
00304 else if (*d.sc == s.last_sc)
00305 {
00306 if (not d.retx)
00307 modules_.account_duplicate();
00308 }
00309 else
00310 {
00311 assert(*d.sc > s.last_sc);
00312
00313 if (d.retx)
00314 modules_.account_miss();
00315
00316 const int delta_s = d.sc->seqnum_get() - s.last_sc.seqnum_get();
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 if (1 < delta_s)
00328 {
00329 if (delta_s < delta_t / state::min_frame_sending_time)
00330 modules_.account_gap(delta_s - 1);
00331 else
00332 modules_.account_seq_anomaly();
00333 }
00334 }
00335 i->second = new_state;
00336 }
00337
00338 }
00339
00340 }
00341
00342 }
00343
00344 #endif // ! WIFI_FRAME_STATS_STATS_HXX_