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