00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef WIFI_DISSECTOR_DISSECTOR_HXX_
00023 # define WIFI_DISSECTOR_DISSECTOR_HXX_
00024
00025 # include <wipal/tool/endianness.hh>
00026 # include <wipal/wifi/frame.hh>
00027 # include <wipal/wifi/data.hh>
00028
00029 # include "dissector.hh"
00030
00031 namespace wpl
00032 {
00033
00034 namespace wifi
00035 {
00036
00037 template <class Hooks>
00038 dissector<Hooks>::dissector(const Hooks& hooks):
00039 Hooks (hooks),
00040 status_ (dissector_status::invalid)
00041 {
00042 }
00043
00044 template <class Hooks>
00045 dissector<Hooks>::dissector(const void* frame,
00046 size_t caplen,
00047 const Hooks& hooks):
00048 Hooks(hooks),
00049 status_ (dissector_status::invalid)
00050 {
00051 (*this)(frame, caplen);
00052 }
00053
00054 template <class Hooks>
00055 dissector_status::status
00056 dissector<Hooks>::status() const
00057 {
00058 return status_;
00059 }
00060
00061 template <class Hooks>
00062 void
00063 dissector<Hooks>::operator () (const void* frame, size_t caplen)
00064 {
00065 this->frame_hook(frame, caplen);
00066
00067 if (caplen < control)
00068 {
00069 status_ = dissector_status::invalid;
00070 this->truncated_unknown_frame_hook(frame, caplen);
00071 this->truncated_frame_hook(frame, caplen, status_);
00072 }
00073 else
00074 {
00075 status_ = dissector_status::valid_control;
00076 switch (type_of(frame))
00077 {
00078 case type::management: management_frame(frame, caplen); break;
00079 case type::control: control_frame(frame, caplen); break;
00080 case type::data: data_frame(frame, caplen); break;
00081
00082 default:
00083 this->invalid_type_hook(frame, caplen);
00084 this->invalid_type_or_subtype_hook(frame, caplen, status_);
00085 break;
00086 }
00087 }
00088 this->end_of_frame_hook(frame, caplen, status_);
00089 }
00090
00091 template <class Hooks>
00092 Hooks&
00093 dissector<Hooks>::hooks()
00094 {
00095 return *static_cast<Hooks*> (this);
00096 }
00097
00098 template <class Hooks>
00099 const Hooks&
00100 dissector<Hooks>::hooks() const
00101 {
00102 return *static_cast<const Hooks*> (this);
00103 }
00104
00105 # define WP_dissector_get_header(Type, VarName, Frame) \
00106 const Type::header* VarName = static_cast<const Type::header*> (Frame)
00107
00108 # define WP_dissector_check_addr(N, Type, Header, Caplen) \
00109 if (Caplen < addr ## N) \
00110 { \
00111 this->truncated_ ## Type ## _frame_hook(Header, Caplen, status_); \
00112 this->truncated_frame_hook(Header, Caplen, status_); \
00113 return; \
00114 } \
00115 status_ = dissector_status::valid_addr ## N; \
00116 this->Type ## _addr ## N ## _hook(Header, Caplen)
00117
00118 # define WP_dissector_check_addr2(N, Type, Header, Caplen) \
00119 WP_dissector_check_addr(N, Type, Header, Caplen); \
00120 this->addr_hook(Header, Caplen, N, Header->addrs[N - 1])
00121
00122 # define WP_dissector_check_seq_ctl(Type, Header, Caplen) \
00123 if (caplen < seqctl) \
00124 { \
00125 this->truncated_ ## Type ## _frame_hook(Header, Caplen, status_); \
00126 this->truncated_frame_hook(Header, Caplen, status_); \
00127 } \
00128 do \
00129 { \
00130 const unsigned seq_ctl = \
00131 tool::extract_little_endian_short_u(Header->seq_ctl); \
00132 const unsigned fragnum = seq_ctl & 0xF; \
00133 const unsigned seqnum = seq_ctl >> 4; \
00134 \
00135 status_ = dissector_status::valid_seq_ctl; \
00136 this->Type ## _seq_ctl_hook(Header, Caplen, fragnum, seqnum); \
00137 this->seq_ctl_hook(Header, Caplen, fragnum, seqnum); \
00138 } \
00139 while (false)
00140
00141 template <class Hooks>
00142 void
00143 dissector<Hooks>::management_frame(const void* frame, size_t caplen)
00144 {
00145 WP_dissector_get_header(mgt::header, h, frame);
00146
00147 this->management_hook(h, caplen);
00148
00149 WP_dissector_check_addr2(1, management, h, caplen);
00150 WP_dissector_check_addr2(2, management, h, caplen);
00151 WP_dissector_check_addr2(3, management, h, caplen);
00152 WP_dissector_check_seq_ctl(management, h, caplen);
00153
00154 management_frame_dispatch(h, caplen);
00155 this->end_of_frame_headers_hook(frame, caplen,
00156 static_cast<const char*> (frame) +
00157 seqctl);
00158 }
00159
00160 template <class Hooks>
00161 void
00162 dissector<Hooks>::management_frame_dispatch(const mgt::header* h,
00163 size_t caplen)
00164 {
00165
00166 const void* const body = reinterpret_cast<const uint8_t*> (h) + seqctl;
00167 (void) body;
00168
00169 switch (subtype_of(h))
00170 {
00171 case mgt::subtype::beacon:
00172 return this->beacon_hook(h, caplen);
00173
00174 case mgt::subtype::assoc_req:
00175 return this->assoc_req_hook(h, caplen);
00176
00177 case mgt::subtype::assoc_resp:
00178 return this->assoc_resp_hook(h, caplen);
00179
00180 case mgt::subtype::reassoc_req:
00181 return this->reassoc_req_hook(h, caplen);
00182
00183 case mgt::subtype::reassoc_resp:
00184 return this->reassoc_resp_hook(h, caplen);
00185
00186 case mgt::subtype::probe_req:
00187 return this->probe_req_hook(h, caplen);
00188
00189 case mgt::subtype::probe_resp:
00190 return this->probe_resp_hook(h, caplen);
00191
00192 case mgt::subtype::atim:
00193 return this->atim_hook(h, caplen);
00194
00195 case mgt::subtype::disassoc:
00196 return this->disassoc_hook(h, caplen);
00197
00198 case mgt::subtype::auth:
00199 return this->auth_hook(h, caplen);
00200
00201 case mgt::subtype::deauth:
00202 return this->deauth_hook(h, caplen);
00203
00204 default:
00205 this->invalid_management_subtype_hook(h, caplen);
00206 this->invalid_subtype_hook(h, caplen, status_);
00207 this->invalid_type_or_subtype_hook(h, caplen, status_);
00208 return;
00209 }
00210 }
00211
00212 template <class Hooks>
00213 void
00214 dissector<Hooks>::control_frame(const void* frame, size_t caplen)
00215 {
00216 this->control_hook(frame, caplen);
00217
00218 switch (subtype_of(frame))
00219 {
00220
00221 # define WP_dissector_control_dispatch_1addr(Name, Frame, Caplen) \
00222 case ctl::subtype::Name: \
00223 { \
00224 WP_dissector_get_header(ctl::Name::header, h, Frame); \
00225 if (Caplen < addr1) \
00226 { \
00227 this->truncated_ ## Name ## _frame_hook(h, Caplen); \
00228 this->truncated_frame_hook(h, Caplen, status_); \
00229 return; \
00230 } \
00231 status_ = dissector_status::valid_addr1; \
00232 this->Name ## _addr1 ## _hook(h, Caplen); \
00233 this->addr_hook(h, Caplen, 1, h->ra); \
00234 this->Name ## _hook(h, Caplen); \
00235 this->end_of_frame_headers_hook(h, Caplen, \
00236 reinterpret_cast<const char*> (h) + addr1); \
00237 } \
00238 return
00239
00240 # define WP_dissector_control_dispatch_2addr(Name, Frame, Caplen) \
00241 case ctl::subtype::Name: \
00242 { \
00243 WP_dissector_get_header(ctl::Name::header, h, Frame); \
00244 WP_dissector_check_addr2(1, Name, h, Caplen); \
00245 WP_dissector_check_addr2(2, Name, h, Caplen); \
00246 this->Name ## _hook(h, Caplen); \
00247 this->end_of_frame_headers_hook(h, Caplen, \
00248 reinterpret_cast<const char*> (h) + addr2); \
00249 } \
00250 return
00251
00252 WP_dissector_control_dispatch_2addr(ps_poll, frame, caplen);
00253 WP_dissector_control_dispatch_2addr(rts, frame, caplen);
00254 WP_dissector_control_dispatch_2addr(cf_end, frame, caplen);
00255 WP_dissector_control_dispatch_2addr(cf_end_cf_ack, frame, caplen);
00256
00257 WP_dissector_control_dispatch_1addr(cts, frame, caplen);
00258 WP_dissector_control_dispatch_1addr(ack, frame, caplen);
00259
00260 # undef WP_dissector_control_dispatch_2addr
00261 # undef WP_dissector_control_dispatch_1addr
00262
00263 default:
00264 this->invalid_control_subtype_hook(frame, caplen);
00265 this->invalid_subtype_hook(frame, caplen, status_);
00266 this->invalid_type_or_subtype_hook(frame, caplen, status_);
00267 return;
00268 }
00269 }
00270
00271 template <class Hooks>
00272 void
00273 dissector<Hooks>::data_frame(const void* frame, size_t caplen)
00274 {
00275 this->data_hook(frame, caplen);
00276
00277 const data::header_3addr* h3 =
00278 static_cast<const data::header_3addr*> (frame);
00279
00280 WP_dissector_check_addr2(1, data, h3, caplen);
00281 WP_dissector_check_addr2(2, data, h3, caplen);
00282 WP_dissector_check_addr2(3, data, h3, caplen);
00283 WP_dissector_check_seq_ctl(data, h3, caplen);
00284
00285 unsigned offset;
00286
00287 const int dir = (to_ds(frame) ? 2 : 0) | (from_ds(frame) ? 1 : 0);
00288 switch (dir)
00289 {
00290 case 3:
00291 {
00292 using data::ap_to_ap::header;
00293
00294 offset = addr4;
00295
00296 const header* const h = static_cast<const header*> (frame);
00297 WP_dissector_check_addr(4, data, h, caplen);
00298 this->addr_hook(h, caplen, 4, h->addrs_sa);
00299 this->ap_to_ap_hook(static_cast<const header*> (frame), caplen);
00300 break;
00301 }
00302
00303 case 2:
00304 {
00305 using data::to_ds::header;
00306
00307 offset = seqctl;
00308
00309 this->to_ds_hook(static_cast<const header*> (frame), caplen);
00310 break;
00311 }
00312
00313 case 1:
00314 {
00315 using data::from_ds::header;
00316
00317 offset = seqctl;
00318
00319 this->from_ds_hook(static_cast<const header*> (frame), caplen);
00320 break;
00321 }
00322
00323 case 0:
00324 {
00325 using data::within_ibss::header;
00326
00327 offset = seqctl;
00328
00329 this->within_ibss_hook(static_cast<const header*> (frame), caplen);
00330 break;
00331 }
00332
00333 default:
00334 throw std::logic_error ("Unreachable code reached!");
00335 }
00336 data_frame_dispatch(frame, caplen);
00337
00338 const uint8_t* before_qos = static_cast<const uint8_t*> (frame) + offset;
00339 const unsigned qos_shift = subtype_of(frame) & 0x8 ? 2 : 0;
00340
00341 if (qos_shift)
00342 {
00343
00344 const unsigned qosctl_lo = *before_qos;
00345 const unsigned tid = (qosctl_lo & 0x0F);
00346 const bool eosp = (qosctl_lo & 0x10) == 0x10;
00347 const unsigned ackpolicy = (qosctl_lo >> 5) & 0x3;
00348
00349 this->qos_ctl_hook(frame, caplen,
00350 tid, eosp, ackpolicy, before_qos[1]);
00351 }
00352
00353 this->end_of_frame_headers_hook(frame, caplen, before_qos + qos_shift);
00354 }
00355
00356 template <class Hooks>
00357 void
00358 dissector<Hooks>::data_frame_dispatch(const void* frame, size_t caplen)
00359 {
00360 switch (subtype_of(frame))
00361 {
00362 case data::subtype::data:
00363 return this->data_only_hook(frame, caplen, status_);
00364 case data::subtype::data_cf_ack:
00365 return this->data_cf_ack_hook(frame, caplen, status_);
00366 case data::subtype::data_cf_poll:
00367 return this->data_cf_poll_hook(frame, caplen, status_);
00368 case data::subtype::data_cf_ack_cf_poll:
00369 return this->data_cf_ack_cf_poll_hook(frame, caplen, status_);
00370 case data::subtype::null:
00371 return this->null_hook(frame, caplen, status_);
00372 case data::subtype::cf_ack:
00373 return this->cf_ack_hook(frame, caplen, status_);
00374 case data::subtype::cf_poll:
00375 return this->cf_poll_hook(frame, caplen, status_);
00376 case data::subtype::cf_ack_cf_poll:
00377 return this->cf_ack_cf_poll_hook(frame, caplen, status_);
00378 default:
00379 this->invalid_data_subtype_hook(frame, caplen, status_);
00380 this->invalid_subtype_hook(frame, caplen, status_);
00381 this->invalid_type_or_subtype_hook(frame, caplen, status_);
00382 return;
00383 }
00384 }
00385
00386 # undef WP_dissector_check_seq_ctl
00387 # undef WP_dissector_check_addr2
00388 # undef WP_dissector_check_addr
00389 # undef WP_dissector_get_header
00390
00391 template <class PhyH, class Hooks, class Src>
00392 dissector<Hooks>
00393 dissect(const pkt::packet<Src>& frm,
00394 const Hooks& hooks = Hooks ())
00395 {
00396 dissector<Hooks> ret (hooks);
00397
00398 const pkt::metadata& meta = frm.meta();
00399 const size_t caplen = meta.caplen;
00400 const bool swapped = frm.swapped();
00401 const PhyH* const phy = static_cast<const PhyH*> (frm.bytes());
00402 const size_t phy_len = phy->len(caplen, swapped);
00403
00404 if (phy_len < caplen)
00405 ret(phy->decapsulate(caplen, swapped), caplen - phy_len);
00406
00407 return ret;
00408 }
00409
00410 }
00411
00412 }
00413
00414 #endif // ! WIFI_DISSECTOR_DISSECTOR_HXX_