From d377b137fa67845896442fd01615abcd883bc590 Mon Sep 17 00:00:00 2001 From: rkinder2023 <138834119+rkinder2023@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:27:34 +1000 Subject: [PATCH 1/3] Add support for S1G beacon to the dot11 layer. (#2) - Includes unit test parsing and confirming an S1G beacon - Includes support for the new Frame Control format for type=3, subtype=1 (S1G beacon) - Includes changes to support addressing used in S1G beacon. All dot11 unit tests pass with this change. --- scapy/layers/dot11.py | 22 +++++++++++++++++++--- test/scapy/layers/dot11.uts | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index 8ed4d38cd0e..6f2db0e2b8d 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -702,6 +702,14 @@ class Dot11(Packet): FlagsField("FCfield", 0, 4, ["pw-mgt", "MD", "protected", "order"]), lambda pkt: (pkt.type, pkt.subtype) == (1, 6) + ), + ( + # FIXME: bw1/2/3 are a 3-bit field. + # Unsure how to do this properly. + FlagsField("FCfield", 0, 8, + ["next_tbtt", "comp_ssid", "ano", "bw1", + "bw2", "bw3", "security", "AP_PM"]), + lambda pkt: (pkt.type, pkt.subtype) == (3, 1) ) ], FlagsField("FCfield", 0, 8, @@ -712,7 +720,7 @@ class Dot11(Packet): _Dot11MacField("addr1", ETHER_ANY, 1), ConditionalField( _Dot11MacField("addr2", ETHER_ANY, 2), - lambda pkt: (pkt.type != 1 or + lambda pkt: (pkt.type not in [1, 3] or pkt.subtype in [0x4, 0x5, 0x6, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf]), ), ConditionalField( @@ -720,7 +728,7 @@ class Dot11(Packet): lambda pkt: (pkt.type in [0, 2] or ((pkt.type, pkt.subtype) == (1, 6) and pkt.cfe == 6)), ), - ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type != 1), + ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type not in [1, 3]), ConditionalField( _Dot11MacField("addr4", ETHER_ANY, 4), lambda pkt: (pkt.type == 2 and @@ -736,7 +744,7 @@ def guess_payload_class(self, payload): if self.type == 0x02 and ( 0x08 <= self.subtype <= 0xF and self.subtype != 0xD): return Dot11QoS - elif self.FCfield.protected: + elif hasattr(self.FCfield, "protected") and self.FCfield.protected: # When a frame is handled by encryption, the Protected Frame bit # (previously called WEP bit) is set to 1, and the Frame Body # begins with the appropriate cryptographic header. @@ -1829,6 +1837,12 @@ class Dot11CSA(Packet): ] +class Dot11S1GBeacon(_Dot11EltUtils): + name = "802.11 S1G Beacon" + fields_desc = [LEIntField("timestamp", 0), + ByteField("change_seq", 0)] + + ################### # 802.11 Security # ################### @@ -1978,6 +1992,7 @@ class Dot11CCMP(Dot11Encrypted): bind_layers(Dot11, Dot11ProbeReq, subtype=4, type=0) bind_layers(Dot11, Dot11ProbeResp, subtype=5, type=0) bind_layers(Dot11, Dot11Beacon, subtype=8, type=0) +bind_layers(Dot11, Dot11S1GBeacon, subtype=1, type=3) bind_layers(Dot11, Dot11ATIM, subtype=9, type=0) bind_layers(Dot11, Dot11Disas, subtype=10, type=0) bind_layers(Dot11, Dot11Auth, subtype=11, type=0) @@ -1985,6 +2000,7 @@ class Dot11CCMP(Dot11Encrypted): bind_layers(Dot11, Dot11Action, subtype=13, type=0) bind_layers(Dot11, Dot11Ack, subtype=13, type=1) bind_layers(Dot11Beacon, Dot11Elt,) +bind_layers(Dot11S1GBeacon, Dot11Elt,) bind_layers(Dot11AssoReq, Dot11Elt,) bind_layers(Dot11AssoResp, Dot11Elt,) bind_layers(Dot11ReassoReq, Dot11Elt,) diff --git a/test/scapy/layers/dot11.uts b/test/scapy/layers/dot11.uts index 944df86d370..a92feb9fc35 100644 --- a/test/scapy/layers/dot11.uts +++ b/test/scapy/layers/dot11.uts @@ -763,3 +763,22 @@ assert pkt[Dot11EltVHTOperation].VHT_Operation_Info assert pkt[Dot11EltVHTOperation].VHT_Operation_Info.channel_width == 1 assert pkt[Dot11EltVHTOperation].VHT_Operation_Info.channel_center0 == 42 assert pkt[Dot11EltVHTOperation].VHT_Operation_Info.channel_center1 == 50 + += Dot11S1GBeacon + +pkt=Dot11(b"\x1c\x18\x00\x00,/u\x1c\x103hq\xf8\x00\x00\xd5\x08\x01\x00d\x00\x00\x00\x00\x00\x05\x02\x00\x01\xd9\x0f\x9e\x00@\x18\x80\x0c\x00\x02@\x00\xfe\x00\xfc\x01\x00\xe8\x06\x06\x18&(\xc4\xcc\xd6\x02d\x00\x00\nWiFiDiving\xdd\x18\x00P\xf2\x02\x01\x01\x01\x00\x03\xa4\xd5\x01'\xa4\xd5\x01BC\xd5\x01b2\xd5\x01") +assert pkt[Dot11].type == 3 +assert pkt[Dot11].subtype == 1 +assert pkt[Dot11].addr1 == '2c:2f:75:1c:10:33' +assert pkt[Dot11S1GBeacon].timestamp == 16281960 +assert pkt[Dot11Elt::{"ID": 0}].info == b"WiFiDiving" +assert pkt[Dot11Elt::{"ID": 217}].len == 15 +assert pkt[Dot11Elt::{"ID": 232}].len == 6 +assert pkt[Dot11].FCfield.bw1 == 1 +assert pkt[Dot11].FCfield.bw2 == 1 +assert pkt[Dot11].FCfield.bw3 == 0 +assert pkt[Dot11].FCfield.next_tbtt == False +assert pkt[Dot11].FCfield.comp_ssid == False +assert pkt[Dot11].FCfield.ano == False +assert pkt[Dot11].FCfield.security == False +assert pkt[Dot11].FCfield.AP_PM == False From 2fc3244a937aa8d4c5de831a7a30fe092a96821a Mon Sep 17 00:00:00 2001 From: rkinder2023 <138834119+rkinder2023@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:49:41 +1000 Subject: [PATCH 2/3] More unit test changes to trigger workflows (#3) * Add support for S1G beacon to the dot11 layer. - Includes unit test parsing and confirming an S1G beacon - Includes support for the new Frame Control format for type=3, subtype=1 (S1G beacon) - Includes changes to support addressing used in S1G beacon. All dot11 unit tests pass with this change. --- test/scapy/layers/dot11.uts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/scapy/layers/dot11.uts b/test/scapy/layers/dot11.uts index a92feb9fc35..b4f29d81e31 100644 --- a/test/scapy/layers/dot11.uts +++ b/test/scapy/layers/dot11.uts @@ -772,6 +772,7 @@ assert pkt[Dot11].subtype == 1 assert pkt[Dot11].addr1 == '2c:2f:75:1c:10:33' assert pkt[Dot11S1GBeacon].timestamp == 16281960 assert pkt[Dot11Elt::{"ID": 0}].info == b"WiFiDiving" +assert pkt[Dot11Elt::{"ID": 214}].len == 2 assert pkt[Dot11Elt::{"ID": 217}].len == 15 assert pkt[Dot11Elt::{"ID": 232}].len == 6 assert pkt[Dot11].FCfield.bw1 == 1 From 59b73300fd13df0c704b30d0d780c4f95f24944d Mon Sep 17 00:00:00 2001 From: rkinder2023 <138834119+rkinder2023@users.noreply.github.com> Date: Sat, 20 Jul 2024 08:42:21 +1000 Subject: [PATCH 3/3] Update S1G beacon parsing based on code review. (#4) * Fix review comments from @p-l-: - Use set for 'type in' checks for extension frame type 3, subtype 1 (S1G beacon). * Update to FCfield to split into three parts for type 3, subtype 1 (S1G beacon frame control field). This allows use of BitField for the 'bw', and FlagsField for the remaining bits. --- scapy/layers/dot11.py | 22 ++++++++++++++-------- test/scapy/layers/dot11.uts | 10 ++++------ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index 6f2db0e2b8d..eae5badafa0 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -683,7 +683,7 @@ def i2repr(self, pkt, val): return s -# 802.11-2016 9.2.4.1.1 +# 802.11-2020 9.2.4.1.1 class Dot11(Packet): name = "802.11" fields_desc = [ @@ -704,11 +704,8 @@ class Dot11(Packet): lambda pkt: (pkt.type, pkt.subtype) == (1, 6) ), ( - # FIXME: bw1/2/3 are a 3-bit field. - # Unsure how to do this properly. - FlagsField("FCfield", 0, 8, - ["next_tbtt", "comp_ssid", "ano", "bw1", - "bw2", "bw3", "security", "AP_PM"]), + FlagsField("FCfield", 0, 2, + ["security", "AP_PM"]), lambda pkt: (pkt.type, pkt.subtype) == (3, 1) ) ], @@ -716,11 +713,20 @@ class Dot11(Packet): ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "protected", "order"]) ), + ConditionalField( + BitField("FCfield_bw", 0, 3), + lambda pkt: (pkt.type, pkt.subtype) == (3, 1) + ), + ConditionalField( + FlagsField("FCfield2", 0, 3, + ["next_tbtt", "comp_ssid", "ano"]), + lambda pkt: (pkt.type, pkt.subtype) == (3, 1) + ), ShortField("ID", 0), _Dot11MacField("addr1", ETHER_ANY, 1), ConditionalField( _Dot11MacField("addr2", ETHER_ANY, 2), - lambda pkt: (pkt.type not in [1, 3] or + lambda pkt: (pkt.type not in {1, 3} or pkt.subtype in [0x4, 0x5, 0x6, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf]), ), ConditionalField( @@ -728,7 +734,7 @@ class Dot11(Packet): lambda pkt: (pkt.type in [0, 2] or ((pkt.type, pkt.subtype) == (1, 6) and pkt.cfe == 6)), ), - ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type not in [1, 3]), + ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type not in {1, 3}), ConditionalField( _Dot11MacField("addr4", ETHER_ANY, 4), lambda pkt: (pkt.type == 2 and diff --git a/test/scapy/layers/dot11.uts b/test/scapy/layers/dot11.uts index b4f29d81e31..96cd474cc2f 100644 --- a/test/scapy/layers/dot11.uts +++ b/test/scapy/layers/dot11.uts @@ -775,11 +775,9 @@ assert pkt[Dot11Elt::{"ID": 0}].info == b"WiFiDiving" assert pkt[Dot11Elt::{"ID": 214}].len == 2 assert pkt[Dot11Elt::{"ID": 217}].len == 15 assert pkt[Dot11Elt::{"ID": 232}].len == 6 -assert pkt[Dot11].FCfield.bw1 == 1 -assert pkt[Dot11].FCfield.bw2 == 1 -assert pkt[Dot11].FCfield.bw3 == 0 -assert pkt[Dot11].FCfield.next_tbtt == False -assert pkt[Dot11].FCfield.comp_ssid == False -assert pkt[Dot11].FCfield.ano == False +assert pkt[Dot11].FCfield_bw == 3 +assert pkt[Dot11].FCfield2.next_tbtt == False +assert pkt[Dot11].FCfield2.comp_ssid == False +assert pkt[Dot11].FCfield2.ano == False assert pkt[Dot11].FCfield.security == False assert pkt[Dot11].FCfield.AP_PM == False