1# $Id: 80211.py 53 2008-12-18 01:22:57Z jon.oberheide $ 2# -*- coding: utf-8 -*- 3"""IEEE 802.11.""" 4from __future__ import print_function 5from __future__ import absolute_import 6 7import struct 8 9from . import dpkt 10from .compat import ntole 11 12# Frame Types 13MGMT_TYPE = 0 14CTL_TYPE = 1 15DATA_TYPE = 2 16 17# Frame Sub-Types 18M_ASSOC_REQ = 0 19M_ASSOC_RESP = 1 20M_REASSOC_REQ = 2 21M_REASSOC_RESP = 3 22M_PROBE_REQ = 4 23M_PROBE_RESP = 5 24M_BEACON = 8 25M_ATIM = 9 26M_DISASSOC = 10 27M_AUTH = 11 28M_DEAUTH = 12 29M_ACTION = 13 30C_BLOCK_ACK_REQ = 8 31C_BLOCK_ACK = 9 32C_PS_POLL = 10 33C_RTS = 11 34C_CTS = 12 35C_ACK = 13 36C_CF_END = 14 37C_CF_END_ACK = 15 38D_DATA = 0 39D_DATA_CF_ACK = 1 40D_DATA_CF_POLL = 2 41D_DATA_CF_ACK_POLL = 3 42D_NULL = 4 43D_CF_ACK = 5 44D_CF_POLL = 6 45D_CF_ACK_POLL = 7 46D_QOS_DATA = 8 47D_QOS_CF_ACK = 9 48D_QOS_CF_POLL = 10 49D_QOS_CF_ACK_POLL = 11 50D_QOS_NULL = 12 51D_QOS_CF_POLL_EMPTY = 14 52 53TO_DS_FLAG = 10 54FROM_DS_FLAG = 1 55INTER_DS_FLAG = 11 56 57# Bitshifts for Frame Control 58_VERSION_MASK = 0x0300 59_TYPE_MASK = 0x0c00 60_SUBTYPE_MASK = 0xf000 61_TO_DS_MASK = 0x0001 62_FROM_DS_MASK = 0x0002 63_MORE_FRAG_MASK = 0x0004 64_RETRY_MASK = 0x0008 65_PWR_MGT_MASK = 0x0010 66_MORE_DATA_MASK = 0x0020 67_WEP_MASK = 0x0040 68_ORDER_MASK = 0x0080 69_VERSION_SHIFT = 8 70_TYPE_SHIFT = 10 71_SUBTYPE_SHIFT = 12 72_TO_DS_SHIFT = 0 73_FROM_DS_SHIFT = 1 74_MORE_FRAG_SHIFT = 2 75_RETRY_SHIFT = 3 76_PWR_MGT_SHIFT = 4 77_MORE_DATA_SHIFT = 5 78_WEP_SHIFT = 6 79_ORDER_SHIFT = 7 80 81# IEs 82IE_SSID = 0 83IE_RATES = 1 84IE_FH = 2 85IE_DS = 3 86IE_CF = 4 87IE_TIM = 5 88IE_IBSS = 6 89IE_HT_CAPA = 45 90IE_ESR = 50 91IE_HT_INFO = 61 92 93FCS_LENGTH = 4 94 95FRAMES_WITH_CAPABILITY = [M_BEACON, M_ASSOC_RESP, M_ASSOC_REQ, M_REASSOC_REQ, ] 96 97# Block Ack control constants 98_ACK_POLICY_SHIFT = 0 99_MULTI_TID_SHIFT = 1 100_COMPRESSED_SHIFT = 2 101_TID_SHIFT = 12 102 103_ACK_POLICY_MASK = 0x0001 104_MULTI_TID_MASK = 0x0002 105_COMPRESSED_MASK = 0x0004 106_TID_MASK = 0xf000 107 108_COMPRESSED_BMP_LENGTH = 8 109_BMP_LENGTH = 128 110 111# Action frame categories 112BLOCK_ACK = 3 113 114# Block ack category action codes 115BLOCK_ACK_CODE_REQUEST = 0 116BLOCK_ACK_CODE_RESPONSE = 1 117BLOCK_ACK_CODE_DELBA = 2 118 119 120class IEEE80211(dpkt.Packet): 121 """IEEE 802.11. 122 123 TODO: Longer class information.... 124 125 Attributes: 126 __hdr__: Header fields of IEEE802.11. 127 TODO. 128 """ 129 130 __hdr__ = ( 131 ('framectl', 'H', 0), 132 ('duration', 'H', 0) 133 ) 134 135 # The standard really defines the entire MAC protocol as little-endian on the wire, 136 # however there is broken logic in the rest of the module preventing this from working right now 137 # __byte_order__ = '<' 138 139 @property 140 def version(self): 141 return (self.framectl & _VERSION_MASK) >> _VERSION_SHIFT 142 143 @version.setter 144 def version(self, val): 145 self.framectl = (val << _VERSION_SHIFT) | (self.framectl & ~_VERSION_MASK) 146 147 @property 148 def type(self): 149 return (self.framectl & _TYPE_MASK) >> _TYPE_SHIFT 150 151 @type.setter 152 def type(self, val): 153 self.framectl = (val << _TYPE_SHIFT) | (self.framectl & ~_TYPE_MASK) 154 155 @property 156 def subtype(self): 157 return (self.framectl & _SUBTYPE_MASK) >> _SUBTYPE_SHIFT 158 159 @subtype.setter 160 def subtype(self, val): 161 self.framectl = (val << _SUBTYPE_SHIFT) | (self.framectl & ~_SUBTYPE_MASK) 162 163 @property 164 def to_ds(self): 165 return (self.framectl & _TO_DS_MASK) >> _TO_DS_SHIFT 166 167 @to_ds.setter 168 def to_ds(self, val): 169 self.framectl = (val << _TO_DS_SHIFT) | (self.framectl & ~_TO_DS_MASK) 170 171 @property 172 def from_ds(self): 173 return (self.framectl & _FROM_DS_MASK) >> _FROM_DS_SHIFT 174 175 @from_ds.setter 176 def from_ds(self, val): 177 self.framectl = (val << _FROM_DS_SHIFT) | (self.framectl & ~_FROM_DS_MASK) 178 179 @property 180 def more_frag(self): 181 return (self.framectl & _MORE_FRAG_MASK) >> _MORE_FRAG_SHIFT 182 183 @more_frag.setter 184 def more_frag(self, val): 185 self.framectl = (val << _MORE_FRAG_SHIFT) | (self.framectl & ~_MORE_FRAG_MASK) 186 187 @property 188 def retry(self): 189 return (self.framectl & _RETRY_MASK) >> _RETRY_SHIFT 190 191 @retry.setter 192 def retry(self, val): 193 self.framectl = (val << _RETRY_SHIFT) | (self.framectl & ~_RETRY_MASK) 194 195 @property 196 def pwr_mgt(self): 197 return (self.framectl & _PWR_MGT_MASK) >> _PWR_MGT_SHIFT 198 199 @pwr_mgt.setter 200 def pwr_mgt(self, val): 201 self.framectl = (val << _PWR_MGT_SHIFT) | (self.framectl & ~_PWR_MGT_MASK) 202 203 @property 204 def more_data(self): 205 return (self.framectl & _MORE_DATA_MASK) >> _MORE_DATA_SHIFT 206 207 @more_data.setter 208 def more_data(self, val): 209 self.framectl = (val << _MORE_DATA_SHIFT) | (self.framectl & ~_MORE_DATA_MASK) 210 211 @property 212 def wep(self): 213 return (self.framectl & _WEP_MASK) >> _WEP_SHIFT 214 215 @wep.setter 216 def wep(self, val): 217 self.framectl = (val << _WEP_SHIFT) | (self.framectl & ~_WEP_MASK) 218 219 @property 220 def order(self): 221 return (self.framectl & _ORDER_MASK) >> _ORDER_SHIFT 222 223 @order.setter 224 def order(self, val): 225 self.framectl = (val << _ORDER_SHIFT) | (self.framectl & ~_ORDER_MASK) 226 227 def unpack_ies(self, buf): 228 self.ies = [] 229 230 ie_decoder = { 231 IE_SSID: ('ssid', self.IE), 232 IE_RATES: ('rate', self.IE), 233 IE_FH: ('fh', self.FH), 234 IE_DS: ('ds', self.DS), 235 IE_CF: ('cf', self.CF), 236 IE_TIM: ('tim', self.TIM), 237 IE_IBSS: ('ibss', self.IBSS), 238 IE_HT_CAPA: ('ht_capa', self.IE), 239 IE_ESR: ('esr', self.IE), 240 IE_HT_INFO: ('ht_info', self.IE) 241 } 242 243 # each IE starts with an ID and a length 244 while len(buf) > FCS_LENGTH: 245 ie_id = struct.unpack('B', buf[:1])[0] 246 try: 247 parser = ie_decoder[ie_id][1] 248 name = ie_decoder[ie_id][0] 249 except KeyError: 250 parser = self.IE 251 name = 'ie_' + str(ie_id) 252 ie = parser(buf) 253 254 ie.data = buf[2:2 + ie.len] 255 setattr(self, name, ie) 256 self.ies.append(ie) 257 buf = buf[2 + ie.len:] 258 259 class Capability(object): 260 def __init__(self, field): 261 self.ess = field & 1 262 self.ibss = (field >> 1) & 1 263 self.cf_poll = (field >> 2) & 1 264 self.cf_poll_req = (field >> 3) & 1 265 self.privacy = (field >> 4) & 1 266 self.short_preamble = (field >> 5) & 1 267 self.pbcc = (field >> 6) & 1 268 self.hopping = (field >> 7) & 1 269 self.spec_mgmt = (field >> 8) & 1 270 self.qos = (field >> 9) & 1 271 self.short_slot = (field >> 10) & 1 272 self.apsd = (field >> 11) & 1 273 self.dsss = (field >> 13) & 1 274 self.delayed_blk_ack = (field >> 14) & 1 275 self.imm_blk_ack = (field >> 15) & 1 276 277 def __init__(self, *args, **kwargs): 278 if kwargs and 'fcs' in kwargs: 279 self.fcs_present = kwargs.pop('fcs') 280 else: 281 self.fcs_present = False 282 283 super(IEEE80211, self).__init__(*args, **kwargs) 284 285 def unpack(self, buf): 286 dpkt.Packet.unpack(self, buf) 287 self.data = buf[self.__hdr_len__:] 288 289 m_decoder = { 290 M_BEACON: ('beacon', self.Beacon), 291 M_ASSOC_REQ: ('assoc_req', self.Assoc_Req), 292 M_ASSOC_RESP: ('assoc_resp', self.Assoc_Resp), 293 M_DISASSOC: ('diassoc', self.Disassoc), 294 M_REASSOC_REQ: ('reassoc_req', self.Reassoc_Req), 295 M_REASSOC_RESP: ('reassoc_resp', self.Assoc_Resp), 296 M_AUTH: ('auth', self.Auth), 297 M_PROBE_RESP: ('probe_resp', self.Beacon), 298 M_DEAUTH: ('deauth', self.Deauth), 299 M_ACTION: ('action', self.Action) 300 } 301 302 c_decoder = { 303 C_RTS: ('rts', self.RTS), 304 C_CTS: ('cts', self.CTS), 305 C_ACK: ('ack', self.ACK), 306 C_BLOCK_ACK_REQ: ('bar', self.BlockAckReq), 307 C_BLOCK_ACK: ('back', self.BlockAck), 308 C_CF_END: ('cf_end', self.CFEnd), 309 } 310 311 d_dsData = { 312 0: self.Data, 313 FROM_DS_FLAG: self.DataFromDS, 314 TO_DS_FLAG: self.DataToDS, 315 INTER_DS_FLAG: self.DataInterDS 316 } 317 318 # For now decode everything with DATA. Haven't checked about other QoS 319 # additions 320 d_decoder = { 321 # modified the decoder to consider the ToDS and FromDS flags 322 # Omitting the 11 case for now 323 D_DATA: ('data_frame', d_dsData), 324 D_NULL: ('data_frame', d_dsData), 325 D_QOS_DATA: ('data_frame', d_dsData), 326 D_QOS_NULL: ('data_frame', d_dsData) 327 } 328 329 decoder = { 330 MGMT_TYPE: m_decoder, 331 CTL_TYPE: c_decoder, 332 DATA_TYPE: d_decoder 333 } 334 335 # Strip off the FCS field 336 if self.fcs_present: 337 self.fcs = struct.unpack('<I', self.data[-1 * FCS_LENGTH:])[0] 338 self.data = self.data[0: -1 * FCS_LENGTH] 339 340 if self.type == MGMT_TYPE: 341 self.mgmt = self.MGMT_Frame(self.data) 342 self.data = self.mgmt.data 343 if self.subtype == M_PROBE_REQ: 344 self.unpack_ies(self.data) 345 return 346 if self.subtype == M_ATIM: 347 return 348 349 try: 350 parser = decoder[self.type][self.subtype][1] 351 name = decoder[self.type][self.subtype][0] 352 except KeyError: 353 raise dpkt.UnpackError("KeyError: type=%s subtype=%s" % (self.type, self.subtype)) 354 355 if self.type == DATA_TYPE: 356 # need to grab the ToDS/FromDS info 357 parser = parser[self.to_ds * 10 + self.from_ds] 358 359 if self.type == MGMT_TYPE: 360 field = parser(self.mgmt.data) 361 else: 362 field = parser(self.data) 363 self.data = field 364 365 setattr(self, name, field) 366 367 if self.type == MGMT_TYPE: 368 self.unpack_ies(field.data) 369 if self.subtype in FRAMES_WITH_CAPABILITY: 370 self.capability = self.Capability(ntole(field.capability)) 371 372 if self.type == DATA_TYPE and self.subtype == D_QOS_DATA: 373 self.qos_data = self.QoS_Data(field.data) 374 field.data = self.qos_data.data 375 376 self.data = field.data 377 378 class BlockAckReq(dpkt.Packet): 379 __hdr__ = ( 380 ('dst', '6s', '\x00' * 6), 381 ('src', '6s', '\x00' * 6), 382 ('ctl', 'H', 0), 383 ('seq', 'H', 0), 384 ) 385 386 class BlockAck(dpkt.Packet): 387 __hdr__ = ( 388 ('dst', '6s', '\x00' * 6), 389 ('src', '6s', '\x00' * 6), 390 ('ctl', 'H', 0), 391 ('seq', 'H', 0), 392 ) 393 394 @property 395 def compressed(self): 396 return (self.ctl & _COMPRESSED_MASK) >> _COMPRESSED_SHIFT 397 398 @compressed.setter 399 def compressed(self, val): 400 self.ctl = (val << _COMPRESSED_SHIFT) | (self.ctl & ~_COMPRESSED_MASK) 401 402 @property 403 def ack_policy(self): 404 return (self.ctl & _ACK_POLICY_MASK) >> _ACK_POLICY_SHIFT 405 406 @ack_policy.setter 407 def ack_policy(self, val): 408 self.ctl = (val << _ACK_POLICY_SHIFT) | (self.ctl & ~_ACK_POLICY_MASK) 409 410 @property 411 def multi_tid(self): 412 return (self.ctl & _MULTI_TID_MASK) >> _MULTI_TID_SHIFT 413 414 @multi_tid.setter 415 def multi_tid(self, val): 416 self.ctl = (val << _MULTI_TID_SHIFT) | (self.ctl & ~_MULTI_TID_MASK) 417 418 @property 419 def tid(self): 420 return (self.ctl & _TID_MASK) >> _TID_SHIFT 421 422 @tid.setter 423 def tid(self, val): 424 self.ctl = (val << _TID_SHIFT) | (self.ctl & ~_TID_MASK) 425 426 def unpack(self, buf): 427 dpkt.Packet.unpack(self, buf) 428 self.data = buf[self.__hdr_len__:] 429 self.ctl = ntole(self.ctl) 430 431 if self.compressed: 432 self.bmp = struct.unpack('8s', self.data[0:_COMPRESSED_BMP_LENGTH])[0] 433 else: 434 self.bmp = struct.unpack('128s', self.data[0:_BMP_LENGTH])[0] 435 self.data = self.data[len(self.__hdr__) + len(self.bmp):] 436 437 class RTS(dpkt.Packet): 438 __hdr__ = ( 439 ('dst', '6s', '\x00' * 6), 440 ('src', '6s', '\x00' * 6) 441 ) 442 443 class CTS(dpkt.Packet): 444 __hdr__ = ( 445 ('dst', '6s', '\x00' * 6), 446 ) 447 448 class ACK(dpkt.Packet): 449 __hdr__ = ( 450 ('dst', '6s', '\x00' * 6), 451 ) 452 453 class CFEnd(dpkt.Packet): 454 __hdr__ = ( 455 ('dst', '6s', '\x00' * 6), 456 ('src', '6s', '\x00' * 6), 457 ) 458 459 class MGMT_Frame(dpkt.Packet): 460 __hdr__ = ( 461 ('dst', '6s', '\x00' * 6), 462 ('src', '6s', '\x00' * 6), 463 ('bssid', '6s', '\x00' * 6), 464 ('frag_seq', 'H', 0) 465 ) 466 467 class Beacon(dpkt.Packet): 468 __hdr__ = ( 469 ('timestamp', 'Q', 0), 470 ('interval', 'H', 0), 471 ('capability', 'H', 0) 472 ) 473 474 class Disassoc(dpkt.Packet): 475 __hdr__ = ( 476 ('reason', 'H', 0), 477 ) 478 479 class Assoc_Req(dpkt.Packet): 480 __hdr__ = ( 481 ('capability', 'H', 0), 482 ('interval', 'H', 0) 483 ) 484 485 class Assoc_Resp(dpkt.Packet): 486 __hdr__ = ( 487 ('capability', 'H', 0), 488 ('status', 'H', 0), 489 ('aid', 'H', 0) 490 ) 491 492 class Reassoc_Req(dpkt.Packet): 493 __hdr__ = ( 494 ('capability', 'H', 0), 495 ('interval', 'H', 0), 496 ('current_ap', '6s', '\x00' * 6) 497 ) 498 499 # This obviously doesn't support any of AUTH frames that use encryption 500 class Auth(dpkt.Packet): 501 __hdr__ = ( 502 ('algorithm', 'H', 0), 503 ('auth_seq', 'H', 0), 504 ) 505 506 class Deauth(dpkt.Packet): 507 __hdr__ = ( 508 ('reason', 'H', 0), 509 ) 510 511 class Action(dpkt.Packet): 512 __hdr__ = ( 513 ('category', 'B', 0), 514 ('code', 'B', 0), 515 ) 516 517 def unpack(self, buf): 518 dpkt.Packet.unpack(self, buf) 519 520 action_parser = { 521 BLOCK_ACK: { 522 BLOCK_ACK_CODE_REQUEST: ('block_ack_request', IEEE80211.BlockAckActionRequest), 523 BLOCK_ACK_CODE_RESPONSE: ('block_ack_response', IEEE80211.BlockAckActionResponse), 524 BLOCK_ACK_CODE_DELBA: ('block_ack_delba', IEEE80211.BlockAckActionDelba), 525 }, 526 } 527 528 try: 529 decoder = action_parser[self.category][self.code][1] 530 field_name = action_parser[self.category][self.code][0] 531 except KeyError: 532 raise dpkt.UnpackError("KeyError: category=%s code=%s" % (self.category, self.code)) 533 534 field = decoder(self.data) 535 setattr(self, field_name, field) 536 self.data = field.data 537 538 class BlockAckActionRequest(dpkt.Packet): 539 __hdr__ = ( 540 ('dialog', 'B', 0), 541 ('parameters', 'H', 0), 542 ('timeout', 'H', 0), 543 ('starting_seq', 'H', 0), 544 ) 545 546 class BlockAckActionResponse(dpkt.Packet): 547 __hdr__ = ( 548 ('dialog', 'B', 0), 549 ('status_code', 'H', 0), 550 ('parameters', 'H', 0), 551 ('timeout', 'H', 0), 552 ) 553 554 class BlockAckActionDelba(dpkt.Packet): 555 __byte_order__ = '<' 556 __hdr__ = ( 557 ('delba_param_set', 'H', 0), 558 ('reason_code', 'H', 0), 559 # ('gcr_group_addr', '8s', '\x00' * 8), # Standard says it must be there, but it isn't? 560 ) 561 562 class Data(dpkt.Packet): 563 __hdr__ = ( 564 ('dst', '6s', '\x00' * 6), 565 ('src', '6s', '\x00' * 6), 566 ('bssid', '6s', '\x00' * 6), 567 ('frag_seq', 'H', 0) 568 ) 569 570 class DataFromDS(dpkt.Packet): 571 __hdr__ = ( 572 ('dst', '6s', '\x00' * 6), 573 ('bssid', '6s', '\x00' * 6), 574 ('src', '6s', '\x00' * 6), 575 ('frag_seq', 'H', 0) 576 ) 577 578 class DataToDS(dpkt.Packet): 579 __hdr__ = ( 580 ('bssid', '6s', '\x00' * 6), 581 ('src', '6s', '\x00' * 6), 582 ('dst', '6s', '\x00' * 6), 583 ('frag_seq', 'H', 0) 584 ) 585 586 class DataInterDS(dpkt.Packet): 587 __hdr__ = ( 588 ('dst', '6s', '\x00' * 6), 589 ('src', '6s', '\x00' * 6), 590 ('da', '6s', '\x00' * 6), 591 ('frag_seq', 'H', 0), 592 ('sa', '6s', '\x00' * 6) 593 ) 594 595 class QoS_Data(dpkt.Packet): 596 __hdr__ = ( 597 ('control', 'H', 0), 598 ) 599 600 class IE(dpkt.Packet): 601 __hdr__ = ( 602 ('id', 'B', 0), 603 ('len', 'B', 0) 604 ) 605 606 def unpack(self, buf): 607 dpkt.Packet.unpack(self, buf) 608 self.info = buf[2:self.len + 2] 609 610 class FH(dpkt.Packet): 611 __hdr__ = ( 612 ('id', 'B', 0), 613 ('len', 'B', 0), 614 ('tu', 'H', 0), 615 ('hopset', 'B', 0), 616 ('hoppattern', 'B', 0), 617 ('hopindex', 'B', 0) 618 ) 619 620 class DS(dpkt.Packet): 621 __hdr__ = ( 622 ('id', 'B', 0), 623 ('len', 'B', 0), 624 ('ch', 'B', 0) 625 ) 626 627 class CF(dpkt.Packet): 628 __hdr__ = ( 629 ('id', 'B', 0), 630 ('len', 'B', 0), 631 ('count', 'B', 0), 632 ('period', 'B', 0), 633 ('max', 'H', 0), 634 ('dur', 'H', 0) 635 ) 636 637 class TIM(dpkt.Packet): 638 __hdr__ = ( 639 ('id', 'B', 0), 640 ('len', 'B', 0), 641 ('count', 'B', 0), 642 ('period', 'B', 0), 643 ('ctrl', 'H', 0) 644 ) 645 646 def unpack(self, buf): 647 dpkt.Packet.unpack(self, buf) 648 self.bitmap = buf[5:self.len + 2] 649 650 class IBSS(dpkt.Packet): 651 __hdr__ = ( 652 ('id', 'B', 0), 653 ('len', 'B', 0), 654 ('atim', 'H', 0) 655 ) 656 657 658def test_802211_ack(): 659 s = b'\xd4\x00\x00\x00\x00\x12\xf0\xb6\x1c\xa4\xff\xff\xff\xff' 660 ieee = IEEE80211(s, fcs=True) 661 assert ieee.version == 0 662 assert ieee.type == CTL_TYPE 663 assert ieee.subtype == C_ACK 664 assert ieee.to_ds == 0 665 assert ieee.from_ds == 0 666 assert ieee.pwr_mgt == 0 667 assert ieee.more_data == 0 668 assert ieee.wep == 0 669 assert ieee.order == 0 670 assert ieee.ack.dst == b'\x00\x12\xf0\xb6\x1c\xa4' 671 fcs = struct.unpack('<I', s[-4:])[0] 672 assert ieee.fcs == fcs 673 674 675def test_80211_beacon(): 676 s = ( 677 b'\x80\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x26\xcb\x18\x6a\x30\x00\x26\xcb\x18\x6a\x30' 678 b'\xa0\xd0\x77\x09\x32\x03\x8f\x00\x00\x00\x66\x00\x31\x04\x00\x04\x43\x41\x45\x4e\x01\x08' 679 b'\x82\x84\x8b\x0c\x12\x96\x18\x24\x03\x01\x01\x05\x04\x00\x01\x00\x00\x07\x06\x55\x53\x20' 680 b'\x01\x0b\x1a\x0b\x05\x00\x00\x6e\x00\x00\x2a\x01\x02\x2d\x1a\x6e\x18\x1b\xff\xff\x00\x00' 681 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x14\x01' 682 b'\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x01\x28\x00\x32\x04\x30' 683 b'\x48\x60\x6c\x36\x03\x51\x63\x03\x3d\x16\x01\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00' 684 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\x1e\x05\x00\x8f\x00\x0f\x00\xff\x03\x59\x00' 685 b'\x63\x73\x65\x2d\x33\x39\x31\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x36\x96\x06' 686 b'\x00\x40\x96\x00\x14\x00\xdd\x18\x00\x50\xf2\x02\x01\x01\x80\x00\x03\xa4\x00\x00\x27\xa4' 687 b'\x00\x00\x42\x43\x5e\x00\x62\x32\x2f\x00\xdd\x06\x00\x40\x96\x01\x01\x04\xdd\x05\x00\x40' 688 b'\x96\x03\x05\xdd\x05\x00\x40\x96\x0b\x09\xdd\x08\x00\x40\x96\x13\x01\x00\x34\x01\xdd\x05' 689 b'\x00\x40\x96\x14\x05' 690 ) 691 ieee = IEEE80211(s, fcs=True) 692 assert ieee.version == 0 693 assert ieee.type == MGMT_TYPE 694 assert ieee.subtype == M_BEACON 695 assert ieee.to_ds == 0 696 assert ieee.from_ds == 0 697 assert ieee.pwr_mgt == 0 698 assert ieee.more_data == 0 699 assert ieee.wep == 0 700 assert ieee.order == 0 701 assert ieee.mgmt.dst == b'\xff\xff\xff\xff\xff\xff' 702 assert ieee.mgmt.src == b'\x00\x26\xcb\x18\x6a\x30' 703 assert ieee.beacon.capability == 0x3104 704 assert ieee.capability.privacy == 1 705 assert ieee.ssid.data == b'CAEN' 706 assert ieee.rate.data == b'\x82\x84\x8b\x0c\x12\x96\x18\x24' 707 assert ieee.ds.data == b'\x01' 708 assert ieee.tim.data == b'\x00\x01\x00\x00' 709 fcs = struct.unpack('<I', s[-4:])[0] 710 assert ieee.fcs == fcs 711 712 713def test_80211_data(): 714 s = ( 715 b'\x08\x09\x20\x00\x00\x26\xcb\x17\x3d\x91\x00\x16\x44\xb0\xae\xc6\x00\x02\xb3\xd6\x26\x3c' 716 b'\x80\x7e\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x07\x27\x40\x00\x80\x06\x1d\x39' 717 b'\x8d\xd4\x37\x3d\x3f\xf5\xd1\x69\xc0\x5f\x01\xbb\xb2\xd6\xef\x23\x38\x2b\x4f\x08\x50\x10' 718 b'\x42\x04\xac\x17\x00\x00' 719 ) 720 ieee = IEEE80211(s, fcs=True) 721 assert ieee.type == DATA_TYPE 722 assert ieee.subtype == D_DATA 723 assert ieee.data_frame.dst == b'\x00\x02\xb3\xd6\x26\x3c' 724 assert ieee.data_frame.src == b'\x00\x16\x44\xb0\xae\xc6' 725 assert ieee.data_frame.frag_seq == 0x807e 726 assert ieee.data == (b'\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x07\x27\x40\x00\x80\x06' 727 b'\x1d\x39\x8d\xd4\x37\x3d\x3f\xf5\xd1\x69\xc0\x5f\x01\xbb\xb2\xd6\xef\x23' 728 b'\x38\x2b\x4f\x08\x50\x10\x42\x04') 729 assert ieee.fcs == struct.unpack('<I', b'\xac\x17\x00\x00')[0] 730 731 from . import llc 732 llc_pkt = llc.LLC(ieee.data_frame.data) 733 ip_pkt = llc_pkt.data 734 assert ip_pkt.dst == b'\x3f\xf5\xd1\x69' 735 736 737def test_80211_data_qos(): 738 s = ( 739 b'\x88\x01\x3a\x01\x00\x26\xcb\x17\x44\xf0\x00\x23\xdf\xc9\xc0\x93\x00\x26\xcb\x17\x44\xf0' 740 b'\x20\x7b\x00\x00\xaa\xaa\x03\x00\x00\x00\x88\x8e\x01\x00\x00\x74\x02\x02\x00\x74\x19\x80' 741 b'\x00\x00\x00\x6a\x16\x03\x01\x00\x65\x01\x00\x00\x61\x03\x01\x4b\x4c\xa7\x7e\x27\x61\x6f' 742 b'\x02\x7b\x3c\x72\x39\xe3\x7b\xd7\x43\x59\x91\x7f\xaa\x22\x47\x51\xb6\x88\x9f\x85\x90\x87' 743 b'\x5a\xd1\x13\x20\xe0\x07\x00\x00\x68\xbd\xa4\x13\xb0\xd5\x82\x7e\xc7\xfb\xe7\xcc\xab\x6e' 744 b'\x5d\x5a\x51\x50\xd4\x45\xc5\xa1\x65\x53\xad\xb5\x88\x5b\x00\x1a\x00\x2f\x00\x05\x00\x04' 745 b'\x00\x35\x00\x0a\x00\x09\x00\x03\x00\x08\x00\x33\x00\x39\x00\x16\x00\x15\x00\x14\x01\x00' 746 b'\xff\xff\xff\xff' 747 ) 748 ieee = IEEE80211(s, fcs=True) 749 assert ieee.type == DATA_TYPE 750 assert ieee.subtype == D_QOS_DATA 751 assert ieee.data_frame.dst == b'\x00\x26\xcb\x17\x44\xf0' 752 assert ieee.data_frame.src == b'\x00\x23\xdf\xc9\xc0\x93' 753 assert ieee.data_frame.frag_seq == 0x207b 754 assert ieee.data == (b'\xaa\xaa\x03\x00\x00\x00\x88\x8e\x01\x00\x00\x74\x02\x02\x00\x74\x19\x80' 755 b'\x00\x00\x00\x6a\x16\x03\x01\x00\x65\x01\x00\x00\x61\x03\x01\x4b\x4c\xa7' 756 b'\x7e\x27\x61\x6f\x02\x7b\x3c\x72\x39\xe3\x7b\xd7\x43\x59\x91\x7f\xaa\x22' 757 b'\x47\x51\xb6\x88\x9f\x85\x90\x87\x5a\xd1\x13\x20\xe0\x07\x00\x00\x68\xbd' 758 b'\xa4\x13\xb0\xd5\x82\x7e\xc7\xfb\xe7\xcc\xab\x6e\x5d\x5a\x51\x50\xd4\x45' 759 b'\xc5\xa1\x65\x53\xad\xb5\x88\x5b\x00\x1a\x00\x2f\x00\x05\x00\x04\x00\x35' 760 b'\x00\x0a\x00\x09\x00\x03\x00\x08\x00\x33\x00\x39\x00\x16\x00\x15\x00\x14\x01\x00') 761 assert ieee.qos_data.control == 0x0 762 assert ieee.fcs == struct.unpack('<I', b'\xff\xff\xff\xff')[0] 763 764 765def test_bug(): 766 s = (b'\x88\x41\x2c\x00\x00\x26\xcb\x17\x44\xf0\x00\x1e\x52\x97\x14\x11\x00\x1f\x6d\xe8\x18\x00' 767 b'\xd0\x07\x00\x00\x6f\x00\x00\x20\x00\x00\x00\x00') 768 ieee = IEEE80211(s) 769 assert ieee.wep == 1 770 771 772def test_data_ds(): 773 # verifying the ToDS and FromDS fields and that we're getting the 774 # correct values 775 776 s = (b'\x08\x03\x00\x00\x01\x0b\x85\x00\x00\x00\x00\x26\xcb\x18\x73\x50\x01\x0b\x85\x00\x00\x00' 777 b'\x00\x89\x00\x26\xcb\x18\x73\x50') 778 ieee = IEEE80211(s) 779 assert ieee.type == DATA_TYPE 780 assert ieee.to_ds == 1 781 assert ieee.from_ds == 1 782 assert ieee.data_frame.sa == b'\x00\x26\xcb\x18\x73\x50' 783 assert ieee.data_frame.src == b'\x00\x26\xcb\x18\x73\x50' 784 assert ieee.data_frame.dst == b'\x01\x0b\x85\x00\x00\x00' 785 assert ieee.data_frame.da == b'\x01\x0b\x85\x00\x00\x00' 786 787 s = (b'\x88\x41\x50\x01\x00\x26\xcb\x17\x48\xc1\x00\x24\x2c\xe7\xfe\x8a\xff\xff\xff\xff\xff\xff' 788 b'\x80\xa0\x00\x00\x09\x1a\x00\x20\x00\x00\x00\x00') 789 ieee = IEEE80211(s) 790 assert ieee.type == DATA_TYPE 791 assert ieee.to_ds == 1 792 assert ieee.from_ds == 0 793 assert ieee.data_frame.bssid == b'\x00\x26\xcb\x17\x48\xc1' 794 assert ieee.data_frame.src == b'\x00\x24\x2c\xe7\xfe\x8a' 795 assert ieee.data_frame.dst == b'\xff\xff\xff\xff\xff\xff' 796 797 s = b'\x08\x02\x02\x01\x00\x02\x44\xac\x27\x70\x00\x1f\x33\x39\x75\x44\x00\x1f\x33\x39\x75\x44\x90\xa4' 798 ieee = IEEE80211(s) 799 assert ieee.type == DATA_TYPE 800 assert ieee.to_ds == 0 801 assert ieee.from_ds == 1 802 assert ieee.data_frame.bssid == b'\x00\x1f\x33\x39\x75\x44' 803 assert ieee.data_frame.src == b'\x00\x1f\x33\x39\x75\x44' 804 assert ieee.data_frame.dst == b'\x00\x02\x44\xac\x27\x70' 805 806 807def test_compressed_block_ack(): 808 s = (b'\x94\x00\x00\x00\x34\xc0\x59\xd6\x3f\x62\xb4\x75\x0e\x46\x83\xc1\x05\x50\x80\xee\x03\x00' 809 b'\x00\x00\x00\x00\x00\x00\xa2\xe4\x98\x45') 810 ieee = IEEE80211(s, fcs=True) 811 assert ieee.type == CTL_TYPE 812 assert ieee.subtype == C_BLOCK_ACK 813 assert ieee.back.dst == b'\x34\xc0\x59\xd6\x3f\x62' 814 assert ieee.back.src == b'\xb4\x75\x0e\x46\x83\xc1' 815 assert ieee.back.compressed == 1 816 assert len(ieee.back.bmp) == 8 817 assert ieee.back.ack_policy == 1 818 assert ieee.back.tid == 5 819 820 821def test_action_block_ack_request(): 822 s = (b'\xd0\x00\x3a\x01\x00\x23\x14\x36\x52\x30\xb4\x75\x0e\x46\x83\xc1\xb4\x75\x0e\x46\x83\xc1' 823 b'\x70\x14\x03\x00\x0d\x02\x10\x00\x00\x40\x29\x06\x50\x33\x9e') 824 ieee = IEEE80211(s, fcs=True) 825 assert ieee.type == MGMT_TYPE 826 assert ieee.subtype == M_ACTION 827 assert ieee.action.category == BLOCK_ACK 828 assert ieee.action.code == BLOCK_ACK_CODE_REQUEST 829 assert ieee.action.block_ack_request.timeout == 0 830 parameters = struct.unpack('<H', b'\x10\x02')[0] 831 assert ieee.action.block_ack_request.parameters == parameters 832 833 834def test_action_block_ack_response(): 835 s = (b'\xd0\x00\x3c\x00\xb4\x75\x0e\x46\x83\xc1\x00\x23\x14\x36\x52\x30\xb4\x75\x0e\x46\x83\xc1' 836 b'\xd0\x68\x03\x01\x0d\x00\x00\x02\x10\x88\x13\x9f\xc0\x0b\x75') 837 ieee = IEEE80211(s, fcs=True) 838 assert ieee.type == MGMT_TYPE 839 assert ieee.subtype == M_ACTION 840 assert ieee.action.category == BLOCK_ACK 841 assert ieee.action.code == BLOCK_ACK_CODE_RESPONSE 842 timeout = struct.unpack('<H', b'\x13\x88')[0] 843 assert ieee.action.block_ack_response.timeout == timeout 844 parameters = struct.unpack('<H', b'\x10\x02')[0] 845 assert ieee.action.block_ack_response.parameters == parameters 846 847 848def test_action_block_ack_delete(): 849 s = (b'\xd0\x00\x2c\x00\x00\xc1\x41\x06\x13\x0d\x6c\xb2\xae\xae\xde\x80\x6c\xb2\xae\xae\xde\x80' 850 b'\xa0\x52\x03\x02\x00\x08\x01\x00\x74\x5d\x0a\xc6') 851 ieee = IEEE80211(s, fcs=True) 852 assert ieee.type == MGMT_TYPE 853 assert ieee.subtype == M_ACTION 854 assert ieee.action.category == BLOCK_ACK 855 assert ieee.action.code == BLOCK_ACK_CODE_DELBA 856 assert ieee.action.block_ack_delba.delba_param_set == 0x0800 857 assert ieee.action.block_ack_delba.reason_code == 1 858 859 860def test_ieee80211_properties(): 861 ieee80211 = IEEE80211() 862 assert ieee80211.version == 0 863 ieee80211.version = 1 864 assert ieee80211.version == 1 865 866 assert ieee80211.type == 0 867 ieee80211.type = 1 868 assert ieee80211.type == 1 869 870 assert ieee80211.subtype == 0 871 ieee80211.subtype = 1 872 assert ieee80211.subtype == 1 873 874 assert ieee80211.to_ds == 0 875 ieee80211.to_ds = 1 876 assert ieee80211.to_ds == 1 877 878 assert ieee80211.from_ds == 0 879 ieee80211.from_ds = 1 880 assert ieee80211.from_ds == 1 881 882 assert ieee80211.more_frag == 0 883 ieee80211.more_frag = 1 884 assert ieee80211.more_frag == 1 885 886 assert ieee80211.retry == 0 887 ieee80211.retry = 0 888 assert ieee80211.retry == 0 889 890 assert ieee80211.pwr_mgt == 0 891 ieee80211.pwr_mgt = 0 892 assert ieee80211.pwr_mgt == 0 893 894 assert ieee80211.more_data == 0 895 ieee80211.more_data = 0 896 assert ieee80211.more_data == 0 897 898 assert ieee80211.wep == 0 899 ieee80211.wep = 1 900 assert ieee80211.wep == 1 901 902 assert ieee80211.order == 0 903 ieee80211.order = 1 904 assert ieee80211.order == 1 905 906 907def test_blockack_properties(): 908 blockack = IEEE80211.BlockAck() 909 assert blockack.compressed == 0 910 blockack.compressed = 1 911 assert blockack.compressed == 1 912 913 assert blockack.ack_policy == 0 914 blockack.ack_policy = 1 915 assert blockack.ack_policy == 1 916 917 assert blockack.multi_tid == 0 918 blockack.multi_tid = 1 919 assert blockack.multi_tid == 1 920 921 assert blockack.tid == 0 922 blockack.tid = 1 923 assert blockack.tid == 1 924 925 926def test_ieee80211_unpack(): 927 import pytest 928 from binascii import unhexlify 929 930 buf = unhexlify( 931 '4000' # subtype set to M_PROBE_REQ 932 '0000' 933 934 # MGMT_Frame 935 '000000000000' # dst 936 '000000000000' # src 937 '000000000000' # bssid 938 '0000' # frag_seq 939 ) 940 ieee80211 = IEEE80211(buf) 941 assert ieee80211.ies == [] 942 943 buf = unhexlify( 944 '9000' # subtype set to M_ATIM 945 '0000' 946 947 # MGMT_Frame 948 '000000000000' # dst 949 '000000000000' # src 950 '000000000000' # bssid 951 '0000' # frag_seq 952 ) 953 ieee80211 = IEEE80211(buf) 954 assert not hasattr(ieee80211, 'ies') 955 956 buf = unhexlify( 957 '0c00' # type set to invalid value 958 '0000' 959 ) 960 with pytest.raises(dpkt.UnpackError, match="KeyError: type=3 subtype=0"): 961 IEEE80211(buf) 962 963 964def test_blockack_unpack(): 965 from binascii import unhexlify 966 # unpack a non-compressed BlockAck 967 buf = unhexlify( 968 '000000000000' 969 '000000000000' 970 '0000' # compressed flag not set 971 '0000' 972 ) + b'\xff' * 128 973 974 blockack = IEEE80211.BlockAck(buf) 975 assert blockack.bmp == b'\xff' * 128 976 assert blockack.data == b'' 977 978 979def test_action_unpack(): 980 import pytest 981 from binascii import unhexlify 982 buf = unhexlify( 983 '01' # category 984 '00' # code (non-existent) 985 ) 986 with pytest.raises(dpkt.UnpackError, match="KeyError: category=1 code=0"): 987 IEEE80211.Action(buf) 988