1"""IEEE 802.11""" 2import logging 3 4from pypacker import pypacker 5from pypacker import triggerlist 6from pypacker import utils 7from pypacker.structcbs import unpack_H, pack_Q, unpack_Q_le 8 9 10logger = logging.getLogger("pypacker") 11 12 13# Frame Types 14MGMT_TYPE = 0 15CTL_TYPE = 1 16DATA_TYPE = 2 17 18# Frame Sub-Types 19# MGMT_TYPE 20M_ASSOC_REQ = 0 21M_ASSOC_RESP = 1 22M_REASSOC_REQ = 2 23M_REASSOC_RESP = 3 24M_PROBE_REQ = 4 25M_PROBE_RESP = 5 26M_DISASSOC = 10 27M_AUTH = 11 28M_DEAUTH = 12 29M_ACTION = 13 30M_BEACON = 8 31M_ATIM = 9 32 33# CTL_TYPE 34C_BLOCK_ACK_REQ = 8 35C_BLOCK_ACK = 9 36C_PS_POLL = 10 37C_RTS = 11 38C_CTS = 12 39C_ACK = 13 40C_CF_END = 14 41C_CF_END_ACK = 15 42 43# DATA_TYPE 44D_NORMAL = 0 45D_DATA_CF_ACK = 1 46D_DATA_CF_POLL = 2 47D_DATA_CF_ACK_POLL = 3 48D_NULL = 4 49D_CF_ACK = 5 50D_CF_POLL = 6 51D_CF_ACK_POLL = 7 52D_QOS_DATA = 8 53D_QOS_CF_ACK = 9 54D_QOS_CF_POLL = 10 55D_QOS_CF_ACK_POLL = 11 56D_QOS_NULL = 12 57D_QOS_CF_POLL_EMPTY = 14 58 59TO_DS_FLAG = 1 60FROM_DS_FLAG = 2 61INTER_DS_FLAG = 3 62 63 64# name : (mask, offset) 65_FRAMECTRL_SUBHEADERDATA = { 66 "version": (0x0300, 8), 67 "type": (0x0C00, 10), 68 "subtype": (0xF000, 12), 69 "to_ds": (0x0001, 0), 70 "from_ds": (0x0002, 1), 71 "more_frag": (0x0004, 2), 72 "retry": (0x0008, 3), 73 "pwr_mgt": (0x0010, 4), 74 "more_data": (0x0020, 5), 75 "protected": (0x0040, 6), 76 "order": (0x0080, 7), 77 "from_to_ds": (0x0002 | 0x0001, 0), 78} 79 80# needed to distinguish subtypes via types 81TYPE_FACTORS = [16, 32, 64] 82TYPE_FACTOR_PROTECTED = 128 83 84_subheader_properties = [] 85 86IEEE_FIELDS_SRC_DST_BSSID = ["src", "dst", "bssid"] 87 88# Set properties to access flags 89for subfield_name, mask_off in _FRAMECTRL_SUBHEADERDATA.items(): 90 # logger.debug("setting prop: %r, %X, %X" % (subfield_name, mask_off[0], mask_off[1])) 91 subheader = [ 92 subfield_name, 93 # lambda**2: avoid lexical closure, do not refer to value via reference 94 (lambda mask, off: 95 (lambda _obj: (_obj.framectl & mask) >> off))(mask_off[0], mask_off[1]), 96 (lambda mask, off: 97 (lambda _obj, _val: _obj.__setattr__("framectl", 98 (_obj.framectl & ~mask) | (_val << off))))(mask_off[0], mask_off[1]), 99 ] 100 _subheader_properties.append(subheader) 101 102 103class IEEE80211(pypacker.Packet): 104 __hdr__ = ( 105 # AAAABBCC | 00000000 106 # AAAA = subtype BB = type CC = version 107 ("framectl", "H", 0), 108 ("duration", "H", 0x3A01) # 314 microseconds 109 ) 110 111 __hdr_sub__ = _subheader_properties 112 113 def _dissect(self, buf): 114 #logger.debug("Starting to dissect") 115 # self.type/self.subtype use self.framectl, no unpack will happen in dissect so this has 116 # to be done manually 117 self.framectl = unpack_H(buf[0:2])[0] 118 #logger.debug("ieee80211 bytes=%X, type/subtype is=%X/%X, handler=%r" % 119 # (self.framectl, self.type, self.subtype, 120 # pypacker.Packet._id_handlerclass_dct[self.__class__][TYPE_FACTORS[self.type] + self.subtype])) 121 self._init_handler(TYPE_FACTORS[self.type] + self.subtype, buf[4:]) 122 #logger.debug("Finished IEEE dissect") 123 return 4 124 125 def is_beacon(self): 126 """return -- True if packet is a beacon. Avoids parsing upper layer.""" 127 return self.type == MGMT_TYPE and self.subtype == M_BEACON 128 129 def extract_client_macs(self): 130 """ 131 Extracts client MACs from upper layer if this is a data packet. 132 133 return -- [mac_client1, ...] or [] if no client macs could be found 134 """ 135 macs_clients = [] 136 137 # data: client -> AP or client <- AP 138 if self.type == DATA_TYPE: 139 if self.from_ds == 1 and self.to_ds == 0: 140 macs_clients.append(self.higher_layer.dst) 141 elif self.from_ds == 0 and self.to_ds == 1: 142 macs_clients.append(self.higher_layer.src) 143 144 return [addr for addr in macs_clients if not utils.is_special_mac(addr)] 145 146 # 147 # mgmt frames 148 # 149 class Beacon(pypacker.Packet): 150 __hdr__ = ( 151 ("dst", "6s", b"\x00" * 6), 152 ("src", "6s", b"\x00" * 6), 153 ("bssid", "6s", b"\x00" * 6), 154 # 12 Bits: 0->4095 | 4 Bits 155 # SF SS (LE) 156 ("seq_frag", "H", 0), 157 # _ts (integer) is saved as LE 158 ("_ts", "Q", 0), 159 ("interval", "H", 0x6400), 160 ("capa", "H", 0x0100), 161 ("params", None, triggerlist.TriggerList) 162 ) 163 164 def _get_seq(self): 165 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 166 167 def _set_seq(self, val): 168 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 169 170 def _get_ts(self): 171 # LE->BE: dirty but simple 172 return unpack_Q_le(pack_Q(self._ts))[0] 173 174 def _set_ts(self, val): 175 self._ts = unpack_Q_le(pack_Q(val))[0] 176 177 def _get_essid(self): 178 return self.params.find_value(search_cb=lambda v: v.id == IEEE80211.IE_SSID).body_bytes 179 180 seq = property(_get_seq, _set_seq) 181 ts = property(_get_ts, _set_ts) 182 dst_s = pypacker.get_property_mac("dst") 183 bssid_s = pypacker.get_property_mac("bssid") 184 src_s = pypacker.get_property_mac("src") 185 essid = property(_get_essid) 186 187 def _dissect(self, buf): 188 self._init_triggerlist("params", buf[32:], IEEE80211._unpack_ies) 189 return len(buf) 190 191 def reverse_address(self): 192 self.dst, self.src = self.src, self.dst 193 194 class Action(pypacker.Packet): 195 __hdr__ = ( 196 ("dst", "6s", b"\x00" * 6), 197 ("src", "6s", b"\x00" * 6), 198 ("bssid", "6s", b"\x00" * 6), 199 ("seq_frag", "H", 0), 200 ("category", "B", 0), 201 ("code", "B", 0) 202 ) 203 204 def _get_seq(self): 205 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 206 207 def _set_seq(self, val): 208 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 209 210 seq = property(_get_seq, _set_seq) 211 212 class BlockAckRequest(pypacker.Packet): 213 __hdr__ = ( 214 ("dialog", "B", 0), 215 ("parameters", "H", 0), 216 ("timeout", "H", 0), 217 ("starting_seq", "H", 0), 218 ) 219 220 class BlockAckResponse(pypacker.Packet): 221 __hdr__ = ( 222 ("dialog", "B", 0), 223 ("status_code", "H", 0), 224 ("parameters", "H", 0), 225 ("timeout", "H", 0), 226 ) 227 228 CATEGORY_BLOCK_ACK = 3 229 CODE_BLOCK_ACK_REQUEST = 0 230 CODE_BLOCK_ACK_RESPONSE = 1 231 232 dst_s = pypacker.get_property_mac("dst") 233 src_s = pypacker.get_property_mac("src") 234 bssid_s = pypacker.get_property_mac("bssid") 235 236 def _dissect(self, buf): 237 # logger.debug(">>>>>>>> ACTION!!!") 238 # category: block ack, code: request or response 239 self._init_handler(buf[20] * 4 + buf[21], buf[22:]) 240 return 22 241 242 def reverse_address(self): 243 self.dst, self.src = self.src, self.dst 244 245 class ProbeReq(pypacker.Packet): 246 __hdr__ = ( 247 ("dst", "6s", b"\x00" * 6), 248 ("src", "6s", b"\x00" * 6), 249 ("bssid", "6s", b"\x00" * 6), 250 ("seq_frag", "H", 0), 251 ("params", None, triggerlist.TriggerList) 252 ) 253 254 dst_s = pypacker.get_property_mac("dst") 255 bssid_s = pypacker.get_property_mac("bssid") 256 src_s = pypacker.get_property_mac("src") 257 258 def _get_seq(self): 259 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 260 261 def _set_seq(self, val): 262 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 263 264 seq = property(_get_seq, _set_seq) 265 266 def _dissect(self, buf): 267 self._init_triggerlist("params", buf[20:], IEEE80211._unpack_ies) 268 return len(buf) 269 270 def reverse_address(self): 271 self.dst, self.src = self.src, self.dst 272 273 class ProbeResp(Beacon): 274 pass 275 276 class AssocReq(pypacker.Packet): 277 __hdr__ = ( 278 ("dst", "6s", b"\x00" * 6), 279 ("src", "6s", b"\x00" * 6), 280 ("bssid", "6s", b"\x00" * 6), 281 ("seq_frag", "H", 0), 282 ("capa", "H", 0), 283 ("interval", "H", 0), 284 ("params", None, triggerlist.TriggerList) 285 ) 286 287 dst_s = pypacker.get_property_mac("dst") 288 bssid_s = pypacker.get_property_mac("bssid") 289 src_s = pypacker.get_property_mac("src") 290 291 def _get_seq(self): 292 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 293 294 def _set_seq(self, val): 295 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 296 297 seq = property(_get_seq, _set_seq) 298 299 def _dissect(self, buf): 300 self._init_triggerlist("params", buf[24:], IEEE80211._unpack_ies) 301 return len(buf) 302 303 def reverse_address(self): 304 self.dst, self.src = self.src, self.dst 305 306 class AssocResp(pypacker.Packet): 307 __hdr__ = ( 308 ("dst", "6s", b"\x00" * 6), 309 ("src", "6s", b"\x00" * 6), 310 ("bssid", "6s", b"\x00" * 6), 311 ("seq_frag", "H", 0), 312 ("capa", "H", 0), 313 ("status", "H", 0), 314 ("aid", "H", 0), 315 ("params", None, triggerlist.TriggerList) 316 ) 317 318 dst_s = pypacker.get_property_mac("dst") 319 bssid_s = pypacker.get_property_mac("bssid") 320 src_s = pypacker.get_property_mac("src") 321 322 def _get_seq(self): 323 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 324 325 def _set_seq(self, val): 326 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 327 328 seq = property(_get_seq, _set_seq) 329 330 def _dissect(self, buf): 331 self._init_triggerlist("params", buf[26:], IEEE80211._unpack_ies) 332 return len(buf) 333 334 def reverse_address(self): 335 self.dst, self.src = self.src, self.dst 336 337 class Disassoc(pypacker.Packet): 338 __hdr__ = ( 339 ("dst", "6s", b"\x00" * 6), 340 ("src", "6s", b"\x00" * 6), 341 ("bssid", "6s", b"\x00" * 6), 342 ("seq_frag", "H", 0), 343 ("reason", "H", 0), 344 ) 345 346 dst_s = pypacker.get_property_mac("dst") 347 bssid_s = pypacker.get_property_mac("bssid") 348 src_s = pypacker.get_property_mac("src") 349 350 def _get_seq(self): 351 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 352 353 def _set_seq(self, val): 354 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 355 356 seq = property(_get_seq, _set_seq) 357 358 def reverse_address(self): 359 self.dst, self.src = self.src, self.dst 360 361 class ReassocReq(pypacker.Packet): 362 __hdr__ = ( 363 ("dst", "6s", b"\x00" * 6), 364 ("src", "6s", b"\x00" * 6), 365 ("bssid", "6s", b"\x00" * 6), 366 ("seq_frag", "H", 0), 367 ("capa", "H", 0), 368 ("interval", "H", 0), 369 ("current_ap", "6s", b"\x00" * 6) 370 ) 371 372 dst_s = pypacker.get_property_mac("dst") 373 bssid_s = pypacker.get_property_mac("bssid") 374 src_s = pypacker.get_property_mac("src") 375 376 def _get_seq(self): 377 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 378 379 def _set_seq(self, val): 380 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 381 382 seq = property(_get_seq, _set_seq) 383 384 def reverse_address(self): 385 self.dst, self.src = self.src, self.dst 386 387 class Auth(pypacker.Packet): 388 """Authentication request.""" 389 __hdr__ = ( 390 ("dst", "6s", b"\x00" * 6), 391 ("src", "6s", b"\x00" * 6), 392 ("bssid", "6s", b"\x00" * 6), 393 ("seq_frag", "H", 0), 394 ("algo", "H", 0), 395 ("authseq", "H", 0x0100), 396 ("status", "H", 0) 397 ) 398 399 dst_s = pypacker.get_property_mac("dst") 400 bssid_s = pypacker.get_property_mac("bssid") 401 src_s = pypacker.get_property_mac("src") 402 403 def _get_seq(self): 404 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 405 406 def _set_seq(self, val): 407 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 408 409 seq = property(_get_seq, _set_seq) 410 411 def reverse_address(self): 412 self.dst, self.src = self.src, self.dst 413 414 class Deauth(pypacker.Packet): 415 __hdr__ = ( 416 ("dst", "6s", b"\xff" * 6), 417 ("src", "6s", b"\x00" * 6), 418 ("bssid", "6s", b"\xff" * 6), 419 ("seq_frag", "H", 0), 420 ("reason", "H", 0x0700) # class 3 frame received from non associated client 421 ) 422 423 dst_s = pypacker.get_property_mac("dst") 424 bssid_s = pypacker.get_property_mac("bssid") 425 src_s = pypacker.get_property_mac("src") 426 427 def _get_seq(self): 428 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 429 430 def _set_seq(self, val): 431 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 432 433 seq = property(_get_seq, _set_seq) 434 435 def reverse_address(self): 436 self.dst, self.src = self.src, self.dst 437 438 m_decoder = { 439 M_BEACON : Beacon, 440 M_ACTION : Action, 441 M_ASSOC_REQ : AssocReq, 442 M_ASSOC_RESP : AssocResp, 443 M_DISASSOC : Disassoc, 444 M_REASSOC_REQ : ReassocReq, 445 M_REASSOC_RESP : AssocResp, 446 M_AUTH : Auth, 447 M_PROBE_REQ : ProbeReq, 448 M_PROBE_RESP : ProbeResp, 449 M_DEAUTH : Deauth 450 } 451 452 # 453 # Control frames: no need for extra layer: 802.11 Base data is enough 454 # 455 456 class RTS(pypacker.Packet): 457 __hdr__ = ( 458 ("dst", "6s", b"\x00" * 6), 459 ("src", "6s", b"\x00" * 6) 460 ) 461 462 dst_s = pypacker.get_property_mac("dst") 463 src_s = pypacker.get_property_mac("src") 464 465 def reverse_address(self): 466 self.dst, self.src = self.src, self.dst 467 468 class CTS(pypacker.Packet): 469 __hdr__ = ( 470 ("dst", "6s", b"\x00" * 6), 471 ) 472 473 dst_s = pypacker.get_property_mac("dst") 474 475 class ACK(pypacker.Packet): 476 __hdr__ = ( 477 ("dst", "6s", b"\x00" * 6), 478 ) 479 480 dst_s = pypacker.get_property_mac("dst") 481 482 class BlockAckReq(pypacker.Packet): 483 __hdr__ = ( 484 ("dst", "6s", b"\x00" * 6), 485 ("src", "6s", b"\x00" * 6), 486 ("reqctrl", "H", 0), 487 ("seq", "H", 0) 488 ) 489 490 dst_s = pypacker.get_property_mac("dst") 491 src_s = pypacker.get_property_mac("src") 492 493 def reverse_address(self): 494 self.dst, self.src = self.src, self.dst 495 496 class BlockAck(pypacker.Packet): 497 __hdr__ = ( 498 ("dst", "6s", b"\x00" * 6), 499 ("src", "6s", b"\x00" * 6), 500 ("reqctrl", "H", 0), 501 ("seq", "H", 0), 502 ("bitmap", "Q", 0) 503 ) 504 505 dst_s = pypacker.get_property_mac("dst") 506 src_s = pypacker.get_property_mac("src") 507 508 def reverse_address(self): 509 self.dst, self.src = self.src, self.dst 510 511 class CFEnd(pypacker.Packet): 512 __hdr__ = ( 513 ("dst", "6s", b"\x00" * 6), 514 ("src", "6s", b"\x00" * 6), 515 ) 516 517 dst_s = pypacker.get_property_mac("dst") 518 src_s = pypacker.get_property_mac("src") 519 520 def reverse_address(self): 521 self.dst, self.src = self.src, self.dst 522 523 c_decoder = { 524 C_RTS : RTS, 525 C_CTS : CTS, 526 C_ACK : ACK, 527 C_BLOCK_ACK_REQ : BlockAckReq, 528 C_BLOCK_ACK : BlockAck, 529 C_CF_END : CFEnd 530 } 531 532 # 533 # Data frames 534 # 535 class Dataframe(pypacker.Packet): 536 __hdr__ = ( 537 ("addr1", "6s", b"\x00" * 6), 538 ("addr2", "6s", b"\x00" * 6), 539 ("addr3", "6s", b"\x00" * 6), 540 ("seq_frag", "H", 0), 541 ("addr4", "6s", None), # to/from-DS = 1 542 ("qos_ctrl", "H", 0), # QoS 543 ("sec_param", "Q", 0) # protected 544 ) 545 546 def _get_seq(self): 547 return (self.seq_frag & 0xFF) << 4 | (self.seq_frag >> 12) 548 549 def _set_seq(self, val): 550 self.seq_frag = (val & 0xF) << 12 | (val & 0xFF0) >> 4 | (self.seq_frag & 0x0F00) 551 552 seq = property(_get_seq, _set_seq) 553 554 def reverse_address(self): 555 if self.from_to_ds == 0: 556 self.addr1, self.addr2 = self.addr2, self.addr1 557 elif self.from_to_ds == 1: 558 self.addr2, self.addr3 = self.addr3, self.addr2 559 elif self.from_to_ds == 2: 560 self.addr1, self.addr3 = self.addr3, self.addr1 561 562 def _get_from_to_ds(self): 563 try: 564 return self._lower_layer.from_to_ds 565 except: 566 return self._from_to_ds 567 568 _from_to_ds = 0 569 570 def _set_from_to_ds(self, value): 571 try: 572 self._lower_layer.from_to_ds = value 573 except: 574 self._from_to_ds = value 575 576 # Same property structure as in IEEE80211 class 577 from_to_ds = property(_get_from_to_ds, _set_from_to_ds) 578 579 def __get_src(self): 580 return self.addr2 if self.from_to_ds in [0, 1] else self.addr3 581 582 def __set_src(self, src): 583 if self.from_to_ds in [0, 1]: 584 self.addr2 = src 585 else: 586 self.addr3 = src 587 588 def __get_dst(self): 589 return self.addr1 if self.from_to_ds in [0, 2] else self.addr3 590 591 def __set_dst(self, dst): 592 if self.from_to_ds in [0, 2]: 593 self.addr1 = dst 594 else: 595 self.addr3 = dst 596 597 def __get_bssid(self): 598 dstype = self.from_to_ds 599 600 if dstype == 0: 601 return self.addr3 602 elif dstype == 1: 603 return self.addr1 604 elif dstype == 2: 605 return self.addr2 606 607 def __set_bssid(self, bssid): 608 dstype = self.from_to_ds 609 610 if dstype == 0: 611 self.addr3 = bssid 612 elif dstype == 1: 613 self.addr1 = bssid 614 elif dstype == 2: 615 self.addr2 = bssid 616 617 src = property(__get_src, __set_src) 618 src_s = pypacker.get_property_mac("src") 619 dst = property(__get_dst, __set_dst) 620 dst_s = pypacker.get_property_mac("dst") 621 bssid = property(__get_bssid, __set_bssid) 622 bssid_s = pypacker.get_property_mac("bssid") 623 624 __QOS_SUBTYPES = {8, 9, 10, 11, 12, 14, 15} 625 626 def _dissect(self, buf): 627 # logger.debug("starting dissecting, buflen: %r" % str(buf)) 628 header_len = 30 629 630 """ 631 DataFrames need special care: there are too many types of field combinations 632 to create classes for every one. Solution: initiate by taking from_to_ds of lower_layer 633 In order to use "src/dst/bssid" instead of addrX set from_to_ds 634 to one of the following values: 635 636 [Bit 0: from DS][Bit 1: to DS] = [order of fields] 637 638 00b = 0 = dst, src, bssid 639 01b = 1 = bssid, src, dst 640 10b = 2 = dst, bssid, src 641 11b = 3 = RA, TA, DA, SA 642 """ 643 if self._lower_layer.__class__ == IEEE80211: 644 is_qos = self._lower_layer.subtype in IEEE80211.Dataframe.__QOS_SUBTYPES 645 is_protected = self._lower_layer.protected == 1 646 is_bridge = self._lower_layer.from_ds == 1 and self._lower_layer.to_ds == 1 647 else: 648 # Default is fromds 649 is_qos = False 650 is_protected = False 651 is_bridge = False 652 653 # logger.debug("switching fields1") 654 if not is_qos: 655 self.qos_ctrl = None 656 header_len -= 2 657 # logger.debug("switching fields2") 658 if not is_protected: 659 self.sec_param = None 660 header_len -= 8 661 # logger.debug("switching fields3") 662 if is_bridge: 663 self.addr4 = b"\x00" * 6 664 header_len += 6 665 # logger.debug("format/length/len(bin): %s/%d/%d" % (self._hdr_fmtstr, self.hdr_len, len(self.bin()))) 666 # logger.debug("%r" % self) 667 return header_len 668 669 d_decoder = { 670 D_NORMAL : Dataframe, 671 D_DATA_CF_ACK : Dataframe, 672 D_DATA_CF_POLL : Dataframe, 673 D_DATA_CF_ACK_POLL : Dataframe, 674 D_NULL : Dataframe, 675 D_CF_ACK : Dataframe, 676 D_CF_POLL : Dataframe, 677 D_CF_ACK_POLL : Dataframe, 678 D_QOS_DATA : Dataframe, 679 D_QOS_CF_ACK : Dataframe, 680 D_QOS_CF_POLL : Dataframe, 681 D_QOS_CF_ACK_POLL : Dataframe, 682 D_QOS_NULL : Dataframe, 683 D_QOS_CF_POLL_EMPTY : Dataframe 684 } 685 686 # 687 # IEs for Mgmt-Frames 688 # 689 @staticmethod 690 def _unpack_ies(buf): 691 """Parse IEs and return them as Triggerlist.""" 692 # each IE starts with an ID and a length 693 ies = [] 694 off = 0 695 buflen = len(buf) 696 # logger.debug("lazy dissecting: %s" % buf) 697 698 while off + 2 < buflen: 699 ie_id = buf[off] 700 try: 701 parser = IEEE80211.ie_decoder[ie_id] 702 except KeyError: 703 # some unknown tag, use standard format 704 parser = IEEE80211.IE 705 706 dlen = buf[off + 1] 707 #logger.debug("IE parser is: %d = %s = %s" % (ie_id, parser, buf[off: off+2+dlen])) 708 try: 709 ie = parser(buf[off: off + 2 + dlen]) 710 ies.append(ie) 711 except: 712 # Not enough bytes for handler, add raw bytes 713 ies.append(buf[off: off + 2 + dlen]) 714 off += 2 + dlen 715 #logger.debug("Finished IE parsing") 716 717 return ies 718 719 class IE(pypacker.Packet): 720 __hdr__ = ( 721 ("id", "B", 0), 722 ("len", "B", 0) 723 ) 724 725 class FH(pypacker.Packet): 726 __hdr__ = ( 727 ("id", "B", 0), 728 ("len", "B", 0), 729 ("tu", "H", 0), 730 ("hopset", "B", 0), 731 ("hoppattern", "B", 0), 732 ("hopindex", "B", 0) 733 ) 734 735 class DS(pypacker.Packet): 736 __hdr__ = ( 737 ("id", "B", 0), 738 ("len", "B", 0), 739 ("ch", "B", 0) 740 ) 741 742 class CF(pypacker.Packet): 743 __hdr__ = ( 744 ("id", "B", 0), 745 ("len", "B", 0), 746 ("count", "B", 0), 747 ("period", "B", 0), 748 ("max", "H", 0), 749 ("dur", "H", 0) 750 ) 751 752 class TIM(pypacker.Packet): 753 __hdr__ = ( 754 ("id", "B", 0), 755 ("len", "B", 0), 756 ("count", "B", 0), 757 ("period", "B", 0), 758 ("ctrl", "H", 0) 759 ) 760 761 class IBSS(pypacker.Packet): 762 __hdr__ = ( 763 ("id", "B", 0), 764 ("len", "B", 0), 765 ("atim", "H", 0) 766 ) 767 768 # IEs 769 IE_SSID = 0 770 IE_RATES = 1 771 IE_FH = 2 772 IE_DS = 3 773 IE_CF = 4 774 IE_TIM = 5 775 IE_IBSS = 6 776 IE_HT_CAPA = 45 777 IE_ESR = 50 778 IE_HT_INFO = 61 779 780 ie_decoder = { 781 IE_SSID : IE, 782 IE_RATES : IE, 783 IE_FH : FH, 784 IE_DS : DS, 785 IE_CF : CF, 786 IE_TIM : TIM, 787 IE_IBSS : IBSS, 788 IE_HT_CAPA : IE, 789 IE_ESR : IE, 790 IE_HT_INFO : IE 791 } 792 793# Handler for IEEE80211 794# position in list = type-ID 795dicts = [IEEE80211.m_decoder, IEEE80211.c_decoder, IEEE80211.d_decoder] 796decoder_dict_complete = {} 797 798for pos, decoder_dict in enumerate(dicts): 799 for key_decoder, val_decoder in decoder_dict.items(): 800 # Same subtype-ID for different type-IDs, distinguish via "type_factor + subtype" 801 # Not doing so would lead to eg: type:0 + subtype:1 == type:1 + subtype:0 802 decoder_dict_complete[TYPE_FACTORS[pos] + key_decoder] = val_decoder 803 804pypacker.Packet.load_handler(IEEE80211, decoder_dict_complete) 805 806# handler for Action 807CATEGORY_BLOCK_ACK_FACTOR = IEEE80211.Action.CATEGORY_BLOCK_ACK * 4 808pypacker.Packet.load_handler(IEEE80211.Action, 809 { 810 CATEGORY_BLOCK_ACK_FACTOR + IEEE80211.Action.CODE_BLOCK_ACK_REQUEST: IEEE80211.Action.BlockAckRequest, 811 CATEGORY_BLOCK_ACK_FACTOR + IEEE80211.Action.CODE_BLOCK_ACK_RESPONSE: IEEE80211.Action.BlockAckResponse 812 } 813) 814