7070from scapy .layers .inet import IP , TCP
7171from scapy .error import warning , log_loading
7272from scapy .sendrecv import sniff , sendp
73+ from scapy .utils import str2mac
7374
7475
7576if conf .crypto_valid :
@@ -525,6 +526,7 @@ def post_build(self, p, pay):
525526
526527# 802.11-2016 9.2
527528
529+ # 802.11-2016 9.2.4.1.3
528530_dot11_subtypes = {
529531 0 : { # Management
530532 0 : "Association Request" ,
@@ -573,7 +575,7 @@ def post_build(self, p, pay):
573575 14 : "QoS CF-Poll (no data)" ,
574576 15 : "QoS CF-Ack+CF-Poll (no data)"
575577 },
576- 4 : { # Extension
578+ 3 : { # Extension
577579 0 : "DMG Beacon"
578580 }
579581}
@@ -591,13 +593,52 @@ def post_build(self, p, pay):
591593}
592594
593595
596+ _dot11_addr_meaning = [
597+ [ # Management: 802.11-2016 9.3.3.2
598+ "RA=DA" , "TA=SA" , "BSSID/STA" , None ,
599+ ],
600+ [ # Control
601+ "RA" , "TA" , None , None
602+ ],
603+ [ # Data: 802.11-2016 9.3.2.1: Table 9-26
604+ [["RA=DA" , "RA=DA" ], ["RA=BSSID" , "RA" ]],
605+ [["TA=SA" , "TA=BSSID" ], ["TA=SA" , "TA" ]],
606+ [["BSSID" , "SA" ], ["DA" , "DA" ]],
607+ [[None , None ], ["SA" , "BSSID" ]],
608+ ],
609+ [ # Extension
610+ "BSSID" , None , None , None
611+ ],
612+ ]
613+
614+
615+ class _Dot11MacField (MACField ):
616+ """
617+ A MACField that displays the address type depending on the
618+ 802.11 flags
619+ """
620+ __slots__ = ["index" ]
621+
622+ def __init__ (self , name , default , index ):
623+ self .index = index
624+ super (_Dot11MacField , self ).__init__ (name , default )
625+
626+ def i2repr (self , pkt , val ):
627+ s = super (_Dot11MacField , self ).i2repr (pkt , val )
628+ meaning = pkt .address_meaning (self .index )
629+ if meaning :
630+ return "%s (%s)" % (s , meaning )
631+ return s
632+
633+
634+ # 802.11-2016 9.2.4.1.1
594635class Dot11 (Packet ):
595636 name = "802.11"
596637 fields_desc = [
597638 BitMultiEnumField ("subtype" , 0 , 4 , _dot11_subtypes ,
598639 lambda pkt : pkt .type ),
599640 BitEnumField ("type" , 0 , 2 , ["Management" , "Control" , "Data" ,
600- "Reserved " ]),
641+ "Extension " ]),
601642 BitField ("proto" , 0 , 2 ),
602643 ConditionalField (
603644 BitEnumField ("cfe" , 0 , 4 , _dot11_cfe ),
@@ -616,19 +657,19 @@ class Dot11(Packet):
616657 "pw-mgt" , "MD" , "protected" , "order" ])
617658 ),
618659 ShortField ("ID" , 0 ),
619- MACField ("addr1" , ETHER_ANY ),
660+ _Dot11MacField ("addr1" , ETHER_ANY , 1 ),
620661 ConditionalField (
621- MACField ("addr2" , ETHER_ANY ),
662+ _Dot11MacField ("addr2" , ETHER_ANY , 2 ),
622663 lambda pkt : (pkt .type != 1 or
623664 pkt .subtype in [0x8 , 0x9 , 0xa , 0xb , 0xe , 0xf ]),
624665 ),
625666 ConditionalField (
626- MACField ("addr3" , ETHER_ANY ),
667+ _Dot11MacField ("addr3" , ETHER_ANY , 3 ),
627668 lambda pkt : pkt .type in [0 , 2 ],
628669 ),
629670 ConditionalField (LEShortField ("SC" , 0 ), lambda pkt : pkt .type != 1 ),
630671 ConditionalField (
631- MACField ("addr4" , ETHER_ANY ),
672+ _Dot11MacField ("addr4" , ETHER_ANY , 4 ),
632673 lambda pkt : (pkt .type == 2 and
633674 pkt .FCfield & 3 == 3 ), # from-DS+to-DS
634675 )
@@ -639,7 +680,8 @@ def mysummary(self):
639680 return self .sprintf ("802.11 %%%s.type%% %%%s.subtype%% %%%s.addr2%% > %%%s.addr1%%" % ((self .__class__ .__name__ ,) * 4 )) # noqa: E501
640681
641682 def guess_payload_class (self , payload ):
642- if self .type == 0x02 and (0x08 <= self .subtype <= 0xF and self .subtype != 0xD ): # noqa: E501
683+ if self .type == 0x02 and (
684+ 0x08 <= self .subtype <= 0xF and self .subtype != 0xD ):
643685 return Dot11QoS
644686 elif self .FCfield .protected :
645687 # When a frame is handled by encryption, the Protected Frame bit
@@ -666,6 +708,31 @@ def answers(self, other):
666708 return 0
667709 return 0
668710
711+ def address_meaning (self , index ):
712+ """
713+ Return the meaning of the address[index] considering the context
714+ """
715+ if index not in [1 , 2 , 3 , 4 ]:
716+ raise ValueError ("Wrong index: should be [1, 2, 3, 4]" )
717+ index = index - 1
718+ if self .type == 0 : # Management
719+ return _dot11_addr_meaning [0 ][index ]
720+ elif self .type == 1 : # Control
721+ return _dot11_addr_meaning [1 ][index ]
722+ elif self .type == 2 : # Data
723+ meaning = _dot11_addr_meaning [2 ][index ][
724+ self .FCfield .to_DS
725+ ][self .FCfield .from_DS ]
726+ if meaning and index in [2 , 3 ]: # Address 3-4
727+ if isinstance (self .payload , Dot11QoS ):
728+ # MSDU and Short A-MSDU
729+ if self .payload .A_MSDU_Present :
730+ meaning = "BSSID"
731+ return meaning
732+ elif self .type == 3 : # Extension
733+ return _dot11_addr_meaning [3 ][index ]
734+ return None
735+
669736 def unwep (self , key = None , warn = 1 ):
670737 if self .FCfield & 0x40 == 0 :
671738 if warn :
@@ -699,11 +766,11 @@ def post_build(self, p, pay):
699766
700767class Dot11QoS (Packet ):
701768 name = "802.11 QoS"
702- fields_desc = [BitField ("Reserved " , None , 1 ),
703- BitField ("Ack_Policy" , None , 2 ),
704- BitField ("EOSP" , None , 1 ),
705- BitField ("TID" , None , 4 ),
706- ByteField ("TXOP" , None )]
769+ fields_desc = [BitField ("A_MSDU_Present " , 0 , 1 ),
770+ BitField ("Ack_Policy" , 0 , 2 ),
771+ BitField ("EOSP" , 0 , 1 ),
772+ BitField ("TID" , 0 , 4 ),
773+ ByteField ("TXOP" , 0 )]
707774
708775 def guess_payload_class (self , payload ):
709776 if isinstance (self .underlayer , Dot11 ):
@@ -889,6 +956,15 @@ class Dot11Elt(Packet):
889956 max_length = 255 )]
890957 show_indent = 0
891958
959+ def __setattr__ (self , attr , val ):
960+ if attr == "info" :
961+ # Will be caught by __slots__: we need an extra call
962+ try :
963+ self .setfieldval (attr , val )
964+ except AttributeError :
965+ pass
966+ super (Dot11Elt , self ).__setattr__ (attr , val )
967+
892968 def mysummary (self ):
893969 if self .ID == 0 :
894970 ssid = repr (self .info )
@@ -933,10 +1009,44 @@ def post_build(self, p, pay):
9331009 return p + pay
9341010
9351011
1012+ class _OUIField (X3BytesField ):
1013+ def i2repr (self , pkt , val ):
1014+ by_val = struct .pack ("!I" , val or 0 )[1 :]
1015+ oui = str2mac (by_val + b"\0 " * 3 )[:8 ]
1016+ if conf .manufdb :
1017+ fancy = conf .manufdb ._get_manuf (oui )
1018+ if fancy != oui :
1019+ return "%s (%s)" % (fancy , oui )
1020+ return oui
1021+
1022+
1023+ class Dot11EltDSSSet (Dot11Elt ):
1024+ name = "802.11 DSSS Parameter Set"
1025+ match_subclass = True
1026+ fields_desc = [
1027+ ByteEnumField ("ID" , 3 , _dot11_id_enum ),
1028+ ByteField ("len" , 1 ),
1029+ ByteField ("channel" , 0 ),
1030+ ]
1031+
1032+
1033+ class Dot11EltERP (Dot11Elt ):
1034+ name = "802.11 ERP"
1035+ match_subclass = True
1036+ fields_desc = [
1037+ ByteEnumField ("ID" , 42 , _dot11_id_enum ),
1038+ ByteField ("len" , 1 ),
1039+ BitField ("NonERP_Present" , 0 , 1 ),
1040+ BitField ("Use_Protection" , 0 , 1 ),
1041+ BitField ("Barker_Preamble_Mode" , 0 , 1 ),
1042+ BitField ("res" , 0 , 5 ),
1043+ ]
1044+
1045+
9361046class RSNCipherSuite (Packet ):
9371047 name = "Cipher suite"
9381048 fields_desc = [
939- X3BytesField ("oui" , 0x000fac ),
1049+ _OUIField ("oui" , 0x000fac ),
9401050 ByteEnumField ("cipher" , 0x04 , {
9411051 0x00 : "Use group cipher suite" ,
9421052 0x01 : "WEP-40" ,
@@ -962,7 +1072,7 @@ def extract_padding(self, s):
9621072class AKMSuite (Packet ):
9631073 name = "AKM suite"
9641074 fields_desc = [
965- X3BytesField ("oui" , 0x000fac ),
1075+ _OUIField ("oui" , 0x000fac ),
9661076 ByteEnumField ("suite" , 0x01 , {
9671077 0x00 : "Reserved" ,
9681078 0x01 : "802.1X" ,
@@ -1049,8 +1159,8 @@ class Dot11EltRSN(Dot11Elt):
10491159 0 if pkt .len is None else
10501160 pkt .len - (
10511161 12 +
1052- pkt .nb_pairwise_cipher_suites * 4 +
1053- pkt .nb_akm_suites * 4
1162+ ( pkt .nb_pairwise_cipher_suites or 0 ) * 4 +
1163+ ( pkt .nb_akm_suites or 0 ) * 4
10541164 ) >= 2
10551165 )
10561166 ),
@@ -1125,7 +1235,7 @@ class Dot11EltRates(Dot11Elt):
11251235
11261236
11271237class Dot11EltHTCapabilities (Dot11Elt ):
1128- name = "HT Capabilities"
1238+ name = "802.11 HT Capabilities"
11291239 match_subclass = True
11301240 fields_desc = [
11311241 ByteEnumField ("ID" , 45 , _dot11_id_enum ),
@@ -1211,7 +1321,7 @@ class Dot11EltVendorSpecific(Dot11Elt):
12111321 fields_desc = [
12121322 ByteEnumField ("ID" , 221 , _dot11_id_enum ),
12131323 ByteField ("len" , None ),
1214- X3BytesField ("oui" , 0x000000 ),
1324+ _OUIField ("oui" , 0x000000 ),
12151325 StrLenField ("info" , "" , length_from = lambda x : x .len - 3 )
12161326 ]
12171327
@@ -1240,10 +1350,10 @@ class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific):
12401350 name = "802.11 Microsoft WPA"
12411351 match_subclass = True
12421352 ID = 221
1353+ oui = 0x0050f2
12431354 # It appears many WPA implementations ignore the fact
12441355 # that this IE should only have a single cipher and auth suite
1245- fields_desc = Dot11EltRSN .fields_desc [:2 ] + [
1246- X3BytesField ("oui" , 0x0050f2 ),
1356+ fields_desc = Dot11EltVendorSpecific .fields_desc [:3 ] + [
12471357 XByteField ("type" , 0x01 )
12481358 ] + Dot11EltRSN .fields_desc [2 :8 ]
12491359
@@ -1437,7 +1547,7 @@ class Dot11TKIP(Dot11Encrypted):
14371547
14381548
14391549class Dot11CCMP (Dot11Encrypted ):
1440- name = "802.11 TKIP packet"
1550+ name = "802.11 CCMP packet"
14411551 fields_desc = [
14421552 # iv - 8 bytes
14431553 ByteField ("PN0" , 0 ),
@@ -1461,6 +1571,7 @@ class Dot11CCMP(Dot11Encrypted):
14611571
14621572
14631573bind_top_down (RadioTap , Dot11FCS , present = 2 , Flags = 16 )
1574+ bind_top_down (Dot11 , Dot11QoS , type = 2 , subtype = 0xc )
14641575
14651576bind_layers (PrismHeader , Dot11 ,)
14661577bind_layers (Dot11 , LLC , type = 2 )
0 commit comments