From 80cebf22a2789c782cddef2d413ab97fef55397c Mon Sep 17 00:00:00 2001 From: Ugur Dogru Date: Thu, 30 Jul 2026 11:17:22 +0300 Subject: [PATCH] Add 802.11 Microsoft WME element support AI-Assisted: yes (Codex) --- scapy/layers/dot11.py | 96 +++++++++++++++++++++++++++++++++++-- test/scapy/layers/dot11.uts | 41 ++++++++++++++++ 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index f8dc5a7ea9e..5622cf6ffdc 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1476,14 +1476,15 @@ class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: + if len(_pkt) < 6: + return Dot11EltVendorSpecific type_ = orb(_pkt[5]) if type_ == 0x01: # MS WPA IE return Dot11EltMicrosoftWPA elif type_ == 0x02: - # MS WME IE TODO - # return Dot11EltMicrosoftWME - pass + # MS WME IE + return Dot11EltMicrosoftWME elif type_ == 0x04: # MS WPS IE TODO # return Dot11EltWPS @@ -1492,6 +1493,95 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): return cls +_dot11_wme_subtypes = { + 0: "Information", + 1: "Parameter", +} + + +_dot11_wme_ac_aci = { + 0: "Best Effort", + 1: "Background", + 2: "Video", + 3: "Voice", +} + + +def _dot11_wme_remaining_len(pkt): + subtype = getattr(pkt, "subtype", None) + if subtype == 1 and pkt.len >= 24: + consumed = 24 + elif subtype == 1 and pkt.len >= 8: + consumed = 8 + elif pkt.len >= 5: + consumed = min(pkt.len, 7) + else: + consumed = 4 + return max(pkt.len - consumed, 0) + + +class Dot11WMEACParameter(Packet): + name = "802.11 WME AC Parameter" + fields_desc = [ + BitField("reserved", 0, 1, tot_size=-1), + BitEnumField("aci", 0, 2, _dot11_wme_ac_aci), + BitField("acm", 0, 1), + BitField("aifsn", 0, 4, end_tot_size=-1), + BitField("ecw_max", 0, 4, tot_size=-1), + BitField("ecw_min", 0, 4, end_tot_size=-1), + LEShortField("txop_limit", 0), + ] + + def extract_padding(self, s): + return b"", s + + +class Dot11EltMicrosoftWME(Dot11EltVendorSpecific): + name = "802.11 Microsoft WMM WME" + match_subclass = True + ID = 221 + oui = 0x0050f2 + fields_desc = Dot11EltVendorSpecific.fields_desc[:3] + [ + XByteField("type", 0x02), + ConditionalField( + ByteEnumField("subtype", 0, _dot11_wme_subtypes), + lambda pkt: pkt.len >= 5 + ), + ConditionalField( + ByteField("version", 1), + lambda pkt: pkt.len >= 6 + ), + ConditionalField( + ByteField("qos_info", 0), + lambda pkt: pkt.len >= 7 + ), + ConditionalField( + ByteField("reserved", 0), + lambda pkt: ( + getattr(pkt, "subtype", None) == 1 and + pkt.len >= 8 + ) + ), + ConditionalField( + PacketListField( + "ac_params", + [], + Dot11WMEACParameter, + count_from=lambda pkt: 4 + ), + lambda pkt: ( + getattr(pkt, "subtype", None) == 1 and + pkt.len >= 24 + ) + ), + StrLenField( + "info", + b"", + length_from=_dot11_wme_remaining_len + ) + ] + + # 802.11-2016 9.4.2.19 class Dot11EltCSA(Dot11Elt): diff --git a/test/scapy/layers/dot11.uts b/test/scapy/layers/dot11.uts index fbdc51ca299..ed445b0c916 100644 --- a/test/scapy/layers/dot11.uts +++ b/test/scapy/layers/dot11.uts @@ -282,6 +282,47 @@ assert ms_wpa_ie[Dot11EltMicrosoftWPA].nb_akm_suites == 0x01 assert ms_wpa_ie[Dot11EltMicrosoftWPA].akm_suites[0].suite == 0x01 assert Dot11Elt in ms_wpa_ie += Dot11EltMicrosoftWME +ms_wme_info_ie = Dot11Elt(b'\xdd\x07\x00P\xf2\x02\x00\x01\x80\x00\x04test') +assert Dot11EltMicrosoftWME in ms_wme_info_ie +assert ms_wme_info_ie[Dot11EltMicrosoftWME].type == 0x02 +assert ms_wme_info_ie[Dot11EltMicrosoftWME].subtype == 0x00 +assert ms_wme_info_ie[Dot11EltMicrosoftWME].version == 0x01 +assert ms_wme_info_ie[Dot11EltMicrosoftWME].qos_info == 0x80 +assert ms_wme_info_ie[Dot11EltMicrosoftWME].getfieldval("info") == b"" +assert Dot11Elt in ms_wme_info_ie +assert raw(ms_wme_info_ie) == b'\xdd\x07\x00P\xf2\x02\x00\x01\x80\x00\x04test' + +ms_wme_param_ie = Dot11Elt( + b'\xdd\x18\x00P\xf2\x02\x01\x01\x80\x00' + b'\x03\xa4\x00\x00\x27\xa4\x00\x00\x42\x43\x5e\x00\x62\x32\x2f\x00' + b'\x00\x04test' +) +assert Dot11EltMicrosoftWME in ms_wme_param_ie +assert ms_wme_param_ie[Dot11EltMicrosoftWME].subtype == 0x01 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].version == 0x01 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].qos_info == 0x80 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].reserved == 0 +assert len(ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params) == 4 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[0].aci == 0 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[0].aifsn == 3 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[0].ecw_min == 4 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[0].ecw_max == 10 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[1].aci == 1 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[2].aci == 2 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].ac_params[3].aci == 3 +assert ms_wme_param_ie[Dot11EltMicrosoftWME].getfieldval("info") == b"" +assert Dot11Elt in ms_wme_param_ie +assert raw(ms_wme_param_ie) == ( + b'\xdd\x18\x00P\xf2\x02\x01\x01\x80\x00' + b'\x03\xa4\x00\x00\x27\xa4\x00\x00\x42\x43\x5e\x00\x62\x32\x2f\x00' + b'\x00\x04test' +) + +short_ms_vendor_ie = Dot11Elt(b'\xdd\x03\x00P\xf2') +assert short_ms_vendor_ie.__class__ == Dot11EltVendorSpecific +assert raw(short_ms_vendor_ie) == b'\xdd\x03\x00P\xf2' + = Dot11EltVendorSpecific assert bytes(Dot11EltVendorSpecific()) == b'\xdd\x03\x00\x00\x00' vendor_specific_ie = Dot11EltVendorSpecific(b'\xdd\t\x00\x03\x7f\x01\x01\x00\x00\xff\x7f')