77import struct
88
99from . import dpkt
10- from .compat import ntole
10+ from .compat import ntole , ntole64
1111
1212# Frame Types
1313MGMT_TYPE = 0
6666_MORE_DATA_MASK = 0x0020
6767_WEP_MASK = 0x0040
6868_ORDER_MASK = 0x0080
69+ _FRAGMENT_NUMBER_MASK = 0x000F
70+ _SEQUENCE_NUMBER_MASK = 0XFFF0
6971_VERSION_SHIFT = 8
7072_TYPE_SHIFT = 10
7173_SUBTYPE_SHIFT = 12
7779_MORE_DATA_SHIFT = 5
7880_WEP_SHIFT = 6
7981_ORDER_SHIFT = 7
82+ _SEQUENCE_NUMBER_SHIFT = 4
8083
8184# IEs
8285IE_SSID = 0
@@ -437,6 +440,15 @@ def unpack(self, buf):
437440 self .bmp = struct .unpack ('128s' , self .data [0 :_BMP_LENGTH ])[0 ]
438441 self .data = self .data [len (self .__hdr__ ) + len (self .bmp ):]
439442
443+ class _FragmentNumSeqNumMixin (object ):
444+ @property
445+ def fragment_number (self ):
446+ return ntole (self .frag_seq ) & _FRAGMENT_NUMBER_MASK
447+
448+ @property
449+ def sequence_number (self ):
450+ return (ntole (self .frag_seq ) & _SEQUENCE_NUMBER_MASK ) >> _SEQUENCE_NUMBER_SHIFT
451+
440452 class RTS (dpkt .Packet ):
441453 __hdr__ = (
442454 ('dst' , '6s' , '\x00 ' * 6 ),
@@ -459,7 +471,7 @@ class CFEnd(dpkt.Packet):
459471 ('src' , '6s' , '\x00 ' * 6 ),
460472 )
461473
462- class MGMT_Frame (dpkt .Packet ):
474+ class MGMT_Frame (dpkt .Packet , _FragmentNumSeqNumMixin ):
463475 __hdr__ = (
464476 ('dst' , '6s' , '\x00 ' * 6 ),
465477 ('src' , '6s' , '\x00 ' * 6 ),
@@ -474,6 +486,11 @@ class Beacon(dpkt.Packet):
474486 ('capability' , 'H' , 0 )
475487 )
476488
489+ def unpack (self , buf ):
490+ dpkt .Packet .unpack (self , buf )
491+ self .timestamp = ntole64 (self .timestamp )
492+ self .interval = ntole (self .interval )
493+
477494 class Disassoc (dpkt .Packet ):
478495 __hdr__ = (
479496 ('reason' , 'H' , 0 ),
@@ -562,31 +579,31 @@ class BlockAckActionDelba(dpkt.Packet):
562579 # ('gcr_group_addr', '8s', '\x00' * 8), # Standard says it must be there, but it isn't?
563580 )
564581
565- class Data (dpkt .Packet ):
582+ class Data (dpkt .Packet , _FragmentNumSeqNumMixin ):
566583 __hdr__ = (
567584 ('dst' , '6s' , '\x00 ' * 6 ),
568585 ('src' , '6s' , '\x00 ' * 6 ),
569586 ('bssid' , '6s' , '\x00 ' * 6 ),
570587 ('frag_seq' , 'H' , 0 )
571588 )
572589
573- class DataFromDS (dpkt .Packet ):
590+ class DataFromDS (dpkt .Packet , _FragmentNumSeqNumMixin ):
574591 __hdr__ = (
575592 ('dst' , '6s' , '\x00 ' * 6 ),
576593 ('bssid' , '6s' , '\x00 ' * 6 ),
577594 ('src' , '6s' , '\x00 ' * 6 ),
578595 ('frag_seq' , 'H' , 0 )
579596 )
580597
581- class DataToDS (dpkt .Packet ):
598+ class DataToDS (dpkt .Packet , _FragmentNumSeqNumMixin ):
582599 __hdr__ = (
583600 ('bssid' , '6s' , '\x00 ' * 6 ),
584601 ('src' , '6s' , '\x00 ' * 6 ),
585602 ('dst' , '6s' , '\x00 ' * 6 ),
586603 ('frag_seq' , 'H' , 0 )
587604 )
588605
589- class DataInterDS (dpkt .Packet ):
606+ class DataInterDS (dpkt .Packet , _FragmentNumSeqNumMixin ):
590607 __hdr__ = (
591608 ('dst' , '6s' , '\x00 ' * 6 ),
592609 ('src' , '6s' , '\x00 ' * 6 ),
@@ -726,6 +743,8 @@ def test_80211_data():
726743 assert ieee .data_frame .dst == b'\x00 \x02 \xb3 \xd6 \x26 \x3c '
727744 assert ieee .data_frame .src == b'\x00 \x16 \x44 \xb0 \xae \xc6 '
728745 assert ieee .data_frame .frag_seq == 0x807e
746+ assert ieee .data_frame .fragment_number == 0
747+ assert ieee .data_frame .sequence_number == 2024
729748 assert ieee .data == (b'\xaa \xaa \x03 \x00 \x00 \x00 \x08 \x00 \x45 \x00 \x00 \x28 \x07 \x27 \x40 \x00 \x80 \x06 '
730749 b'\x1d \x39 \x8d \xd4 \x37 \x3d \x3f \xf5 \xd1 \x69 \xc0 \x5f \x01 \xbb \xb2 \xd6 \xef \x23 '
731750 b'\x38 \x2b \x4f \x08 \x50 \x10 \x42 \x04 ' )
@@ -754,6 +773,8 @@ def test_80211_data_qos():
754773 assert ieee .data_frame .dst == b'\x00 \x26 \xcb \x17 \x44 \xf0 '
755774 assert ieee .data_frame .src == b'\x00 \x23 \xdf \xc9 \xc0 \x93 '
756775 assert ieee .data_frame .frag_seq == 0x207b
776+ assert ieee .data_frame .fragment_number == 0
777+ assert ieee .data_frame .sequence_number == 1970
757778 assert ieee .data == (b'\xaa \xaa \x03 \x00 \x00 \x00 \x88 \x8e \x01 \x00 \x00 \x74 \x02 \x02 \x00 \x74 \x19 \x80 '
758779 b'\x00 \x00 \x00 \x6a \x16 \x03 \x01 \x00 \x65 \x01 \x00 \x00 \x61 \x03 \x01 \x4b \x4c \xa7 '
759780 b'\x7e \x27 \x61 \x6f \x02 \x7b \x3c \x72 \x39 \xe3 \x7b \xd7 \x43 \x59 \x91 \x7f \xaa \x22 '
@@ -988,3 +1009,30 @@ def test_action_unpack():
9881009 )
9891010 with pytest .raises (dpkt .UnpackError , match = "KeyError: category=1 code=0" ):
9901011 IEEE80211 .Action (buf )
1012+
1013+
1014+ def test_beacon_unpack ():
1015+ beacon_payload = b"\xb9 \x71 \xfa \x45 \x52 \x02 \x00 \x00 \x64 \x00 \x11 \x04 "
1016+ beacon = IEEE80211 .Beacon (beacon_payload )
1017+ assert beacon .timestamp == 0x0000025245fa71b9
1018+ assert beacon .interval == 100
1019+ assert beacon .capability == 0x1104
1020+
1021+
1022+ def test_fragment_and_sequence_values ():
1023+ from binascii import unhexlify
1024+ for raw_frag_seq , (expected_frag_num , expected_seq_num ) in [
1025+ ("0000" , (0 , 0 )),
1026+ ("0F00" , (15 , 0 )),
1027+ ("0111" , (1 , 272 )),
1028+ ("B3FF" , (3 , 4091 ))
1029+ ]:
1030+ buf = unhexlify (
1031+ '000000000000' # dst
1032+ '000000000000' # src
1033+ '000000000000' # bssid
1034+ + raw_frag_seq
1035+ )
1036+ data = IEEE80211 .Data (buf )
1037+ assert data .fragment_number == expected_frag_num
1038+ assert data .sequence_number == expected_seq_num
0 commit comments