From 3f49f26888e2c746edc1a9011a30bf2ed85db4b7 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Sat, 5 Aug 2023 09:15:30 -0700 Subject: [PATCH 1/2] Improve Bluetooth HCI Command packet definition - Divide opcode into ogf and ocf following Core Spec - Redefine existing HCI commands with new format --- scapy/layers/bluetooth.py | 78 ++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/scapy/layers/bluetooth.py b/scapy/layers/bluetooth.py index 31438ce103e..39ddaf8944d 100644 --- a/scapy/layers/bluetooth.py +++ b/scapy/layers/bluetooth.py @@ -25,6 +25,7 @@ from scapy.packet import bind_layers, Packet from scapy.fields import ( BitField, + XBitField, ByteEnumField, ByteField, FieldLenField, @@ -898,12 +899,17 @@ def extract_padding(self, s): class HCI_Command_Hdr(Packet): name = "HCI Command header" - fields_desc = [XLEShortField("opcode", 0), + fields_desc = [XBitField("ogf", 0, 6, tot_size=-2), + XBitField("ocf", 0, 10, end_tot_size=-2), LenField("len", None, fmt="B"), ] def answers(self, other): return False + @property + def opcode(self): + return (self.ogf << 10) + self.ocf + def post_build(self, p, pay): p += pay if self.len is None: @@ -1290,39 +1296,43 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): conf.l2types.register(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, HCI_PHDR_Hdr) conf.l2types.register(DLT_BLUETOOTH_LINUX_MONITOR, BT_Mon_Pcap_Hdr) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Create_Connection, opcode=0x0405) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Disconnect, opcode=0x0406) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Link_Key_Request_Reply, opcode=0x040b) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Authentication_Requested, opcode=0x0411) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Connection_Encryption, opcode=0x0413) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Remote_Name_Request, opcode=0x0419) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Mask, opcode=0x0c01) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Reset, opcode=0x0c03) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Filter, opcode=0x0c05) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Local_Name, opcode=0x0c13) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Connect_Accept_Timeout, opcode=0x0c16) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Extended_Inquiry_Response, opcode=0x0c52) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Host_Supported, opcode=0x0c6d) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_BD_Addr, opcode=0x1009) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Buffer_Size, opcode=0x2002) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Random_Address, opcode=0x2005) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Parameters, opcode=0x2006) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Data, opcode=0x2008) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Response_Data, opcode=0x2009) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertise_Enable, opcode=0x200a) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Parameters, opcode=0x200b) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Enable, opcode=0x200c) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection, opcode=0x200d) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection_Cancel, opcode=0x200e) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_White_List_Size, opcode=0x200f) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Clear_White_List, opcode=0x2010) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Add_Device_To_White_List, opcode=0x2011) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Remove_Device_From_White_List, opcode=0x2012) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Connection_Update, opcode=0x2013) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Remote_Used_Features, opcode=0x2016) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Start_Encryption_Request, opcode=0x2019) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Reply, opcode=0x201a) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply, opcode=0x201b) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_Create_Connection, ogf=0x01, ocf=0x0005) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Disconnect, ogf=0x01, ocf=0x0006) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Link_Key_Request_Reply, ogf=0x01, ocf=0x000b) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Authentication_Requested, ogf=0x01, ocf=0x0011) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Connection_Encryption, ogf=0x01, ocf=0x0013) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Remote_Name_Request, ogf=0x01, ocf=0x0019) + + +bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Mask, ogf=0x03, ocf=0x0001) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Reset, ogf=0x03, ocf=0x0003) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Filter, ogf=0x03, ocf=0x0005) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Local_Name, ogf=0x03, ocf=0x0013) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Connect_Accept_Timeout, ogf=0x03, ocf=0x0016) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Extended_Inquiry_Response, ogf=0x03, ocf=0x0052) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Host_Supported, ogf=0x03, ocf=0x006d) + +bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_BD_Addr, ogf=0x04, ocf=0x0009) + +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Buffer_Size, ogf=0x08, ocf=0x0002) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Random_Address, ogf=0x08, ocf=0x0005) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Parameters, ogf=0x08, ocf=0x0006) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Data, ogf=0x08, ocf=0x0008) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Response_Data, ogf=0x08, ocf=0x0009) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertise_Enable, ogf=0x08, ocf=0x000a) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Parameters, ogf=0x08, ocf=0x000b) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Enable, ogf=0x08, ocf=0x000c) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection, ogf=0x08, ocf=0x000d) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection_Cancel, ogf=0x08, ocf=0x000e) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_White_List_Size, ogf=0x08, ocf=0x000f) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Clear_White_List, ogf=0x08, ocf=0x0010) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Add_Device_To_White_List, ogf=0x08, ocf=0x0011) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Remove_Device_From_White_List, ogf=0x08, ocf=0x0012) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Connection_Update, ogf=0x08, ocf=0x0013) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Remote_Used_Features, ogf=0x08, ocf=0x0016) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Start_Encryption_Request, ogf=0x08, ocf=0x0019) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Reply, ogf=0x08, ocf=0x001a) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply, ogf=0x08, ocf=0x001b) # noqa: E501 bind_layers(HCI_Event_Hdr, HCI_Event_Connect_Complete, code=0x03) bind_layers(HCI_Event_Hdr, HCI_Event_Disconnection_Complete, code=0x05) From a1a5e0356cdcd71cc7bc27a197dc81fd7b74586c Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Sun, 6 Aug 2023 00:13:33 -0700 Subject: [PATCH 2/2] Fix some issues in existing hci command packets 1. Fix some outdated command definitions 2. Fix the names of commands, use the formal name from core spec 3. Fix the some of the tests --- scapy/layers/bluetooth.py | 338 +++++++++++++++++++++----------- test/scapy/layers/bluetooth.uts | 184 ++++++++++++----- 2 files changed, 363 insertions(+), 159 deletions(-) diff --git a/scapy/layers/bluetooth.py b/scapy/layers/bluetooth.py index 39ddaf8944d..cca1d5a9086 100644 --- a/scapy/layers/bluetooth.py +++ b/scapy/layers/bluetooth.py @@ -46,6 +46,7 @@ StrLenField, UUIDField, XByteField, + XLE3BytesField, XLELongField, XStrLenField, XLEShortField, @@ -916,65 +917,37 @@ def post_build(self, p, pay): p = p[:2] + struct.pack("B", len(pay)) + p[3:] return p +# BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E +# 7 HCI COMMANDS AND EVENTS +# 7.1 LINK CONTROL COMMANDS, the OGF is defined as 0x01 -class HCI_Cmd_Reset(Packet): - name = "Reset" - - -class HCI_Cmd_Set_Event_Filter(Packet): - name = "Set Event Filter" - fields_desc = [ByteEnumField("type", 0, {0: "clear"}), ] - -class HCI_Cmd_Connect_Accept_Timeout(Packet): - name = "Connection Attempt Timeout" - fields_desc = [LEShortField("timeout", 32000)] # 32000 slots is 20000 msec - - -class HCI_Cmd_LE_Host_Supported(Packet): - name = "LE Host Supported" - fields_desc = [ByteField("supported", 1), - ByteField("simultaneous", 1), ] +class HCI_Cmd_Inquiry(Packet): + name = "HCI_Inquiry" + fields_desc = [XLE3BytesField("lap", 0x9E8B33), + ByteField("inquiry_length", 0), + ByteField("num_responses", 0)] -class HCI_Cmd_Set_Event_Mask(Packet): - name = "Set Event Mask" - fields_desc = [StrFixedLenField("mask", b"\xff\xff\xfb\xff\x07\xf8\xbf\x3d", 8)] # noqa: E501 +class HCI_Cmd_Inquiry_Cancel(Packet): + name = "HCI_Inquiry_Cancel" -class HCI_Cmd_Read_BD_Addr(Packet): - name = "Read BD Addr" +class HCI_Cmd_Periodic_Inquiry_Mode(Packet): + name = "HCI_Periodic_Inquiry_Mode" + fields_desc = [LEShortField("max_period_length", 0x0003), + LEShortField("min_period_length", 0x0002), + XLE3BytesField("lap", 0x9E8B33), + ByteField("inquiry_length", 0), + ByteField("num_responses", 0)] -class HCI_Cmd_Write_Local_Name(Packet): - name = "Write Local Name" - fields_desc = [StrField("name", "")] - - -class HCI_Cmd_Write_Extended_Inquiry_Response(Packet): - name = "Write Extended Inquiry Response" - fields_desc = [ByteField("fec_required", 0), - PacketListField("eir_data", [], EIR_Hdr, - length_from=lambda pkt:pkt.len)] - - -class HCI_Cmd_LE_Set_Scan_Parameters(Packet): - name = "LE Set Scan Parameters" - fields_desc = [ByteEnumField("type", 1, {1: "active"}), - XLEShortField("interval", 16), - XLEShortField("window", 16), - ByteEnumField("atype", 0, {0: "public"}), - ByteEnumField("policy", 0, {0: "all", 1: "whitelist"})] - - -class HCI_Cmd_LE_Set_Scan_Enable(Packet): - name = "LE Set Scan Enable" - fields_desc = [ByteField("enable", 1), - ByteField("filter_dups", 1), ] +class HCI_Cmd_Exit_Peiodic_Inquiry_Mode(Packet): + name = "HCI_Exit_Periodic_Inquiry_Mode" class HCI_Cmd_Create_Connection(Packet): - name = "Create Connection" + name = "HCI_Create_Connection" fields_desc = [LEMACField("bd_addr", None), LEShortField("packet_type", 0xcc18), ByteField("page_scan_repetition_mode", 0x02), @@ -984,100 +957,136 @@ class HCI_Cmd_Create_Connection(Packet): class HCI_Cmd_Disconnect(Packet): - name = "Disconnect" + name = "HCI_Disconnect" fields_desc = [XLEShortField("handle", 0), ByteField("reason", 0x13), ] class HCI_Cmd_Link_Key_Request_Reply(Packet): - name = "Link Key Request Reply" + name = "HCI_Link_Key_Request_Reply" fields_desc = [LEMACField("bd_addr", None), NBytesField("link_key", None, 16), ] class HCI_Cmd_Authentication_Requested(Packet): - name = "Authentication Requested" + name = "HCI_Authentication_Requested" fields_desc = [LEShortField("handle", 0)] class HCI_Cmd_Set_Connection_Encryption(Packet): - name = "Set Connection Encryption" + name = "HCI_Set_Connection_Encryption" fields_desc = [LEShortField("handle", 0), ByteField("encryption_enable", 0)] class HCI_Cmd_Remote_Name_Request(Packet): - name = "Remote Name Request" + name = "HCI_Remote_Name_Request" fields_desc = [LEMACField("bd_addr", None), ByteField("page_scan_repetition_mode", 0x02), ByteField("reserved", 0x0), LEShortField("clock_offset", 0x0), ] -class HCI_Cmd_LE_Create_Connection(Packet): - name = "LE Create Connection" - fields_desc = [LEShortField("interval", 96), - LEShortField("window", 48), - ByteEnumField("filter", 0, {0: "address"}), - ByteEnumField("patype", 0, {0: "public", 1: "random"}), - LEMACField("paddr", None), - ByteEnumField("atype", 0, {0: "public", 1: "random"}), - LEShortField("min_interval", 40), - LEShortField("max_interval", 56), - LEShortField("latency", 0), - LEShortField("timeout", 42), - LEShortField("min_ce", 0), - LEShortField("max_ce", 0), ] +# 7.2 Link Policy commands, the OGF is defined as 0x02 +class HCI_Cmd_Hold_Mode(Packet): + name = "HCI_Hold_Mode" + fields_desc = [LEShortField("connection_handle", 0), + LEShortField("hold_mode_max_interval", 0x0002), + LEShortField("hold_mode_min_interval", 0x0002), ] -class HCI_Cmd_LE_Create_Connection_Cancel(Packet): - name = "LE Create Connection Cancel" +# 7.3 CONTROLLER & BASEBAND COMMANDS, the OGF is defined as 0x03 +class HCI_Cmd_Set_Event_Mask(Packet): + name = "HCI_Set_Event_Mask" + fields_desc = [StrFixedLenField("mask", b"\xff\xff\xfb\xff\x07\xf8\xbf\x3d", 8)] # noqa: E501 -class HCI_Cmd_LE_Read_White_List_Size(Packet): - name = "LE Read White List Size" +class HCI_Cmd_Reset(Packet): + name = "HCI_Reset" -class HCI_Cmd_LE_Clear_White_List(Packet): - name = "LE Clear White List" +class HCI_Cmd_Set_Event_Filter(Packet): + name = "HCI_Set_Event_Filter" + fields_desc = [ByteEnumField("type", 0, {0: "clear"}), ] -class HCI_Cmd_LE_Add_Device_To_White_List(Packet): - name = "LE Add Device to White List" - fields_desc = [ByteEnumField("atype", 0, {0: "public", 1: "random"}), - LEMACField("address", None)] +class HCI_Cmd_Write_Local_Name(Packet): + name = "HCI_Write_Local_Name" + fields_desc = [StrField("name", "")] -class HCI_Cmd_LE_Remove_Device_From_White_List(HCI_Cmd_LE_Add_Device_To_White_List): # noqa: E501 - name = "LE Remove Device from White List" +class HCI_Cmd_Write_Connect_Accept_Timeout(Packet): + name = "HCI_Write_Connection_Accept_Timeout" + fields_desc = [LEShortField("timeout", 32000)] # 32000 slots is 20000 msec -class HCI_Cmd_LE_Connection_Update(Packet): - name = "LE Connection Update" - fields_desc = [XLEShortField("handle", 0), - XLEShortField("min_interval", 0), - XLEShortField("max_interval", 0), - XLEShortField("latency", 0), - XLEShortField("timeout", 0), - LEShortField("min_ce", 0), - LEShortField("max_ce", 0xffff), ] +class HCI_Cmd_Write_Extended_Inquiry_Response(Packet): + name = "HCI_Write_Extended_Inquiry_Response" + fields_desc = [ByteField("fec_required", 0), + PacketListField("eir_data", [], EIR_Hdr, + length_from=lambda pkt:pkt.len)] -class HCI_Cmd_LE_Read_Buffer_Size(Packet): - name = "LE Read Buffer Size" +class HCI_Cmd_Read_LE_Host_Support(Packet): + name = "HCI_Read_LE_Host_Support" + + +class HCI_Cmd_Write_LE_Host_Support(Packet): + name = "HCI_Write_LE_Host_Support" + fields_desc = [ByteField("supported", 1), + ByteField("unused", 1), ] + + +# 7.4 INFORMATIONAL PARAMETERS, the OGF is defined as 0x04 +class HCI_Cmd_Read_BD_Addr(Packet): + name = "HCI_Read_BD_ADDR" + +# 7.5 STATUS PARAMETERS, the OGF is defined as 0x05 -class HCI_Cmd_LE_Read_Remote_Used_Features(Packet): - name = "LE Read Remote Used Features" - fields_desc = [LEShortField("handle", 64)] + +class HCI_Cmd_Read_Link_Quality(Packet): + name = "HCI_Read_Link_Quality" + fields_desc = [LEShortField("handle", 0)] + + +class HCI_Cmd_Read_RSSI(Packet): + name = "HCI_Read_RSSI" + fields_desc = [LEShortField("handle", 0)] + + +# 7.6 TESTING COMMANDS, the OGF is defined as 0x06 +class HCI_Cmd_Read_Loopback_Mode(Packet): + name = "HCI_Read_Loopback_Mode" + + +class HCI_Cmd_Write_Loopback_Mode(Packet): + name = "HCI_Write_Loopback_Mode" + fields_desc = [ByteEnumField("loopback_mode", 0, + {0: "no loopback", + 1: "enable local loopback", + 2: "enable remote loopback"})] + + +# 7.8 LE CONTROLLER COMMANDS, the OGF code is defined as 0x08 +class HCI_Cmd_LE_Read_Buffer_Size_V1(Packet): + name = "HCI_LE_Read_Buffer_Size [v1]" + + +class HCI_Cmd_LE_Read_Buffer_Size_V2(Packet): + name = "HCI_LE_Read_Buffer_Size [v2]" + + +class HCI_Cmd_LE_Read_Local_Supported_Features(Packet): + name = "HCI_LE_Read_Local_Supported_Features" class HCI_Cmd_LE_Set_Random_Address(Packet): - name = "LE Set Random Address" + name = "HCI_LE_Set_Random_Address" fields_desc = [LEMACField("address", None)] class HCI_Cmd_LE_Set_Advertising_Parameters(Packet): - name = "LE Set Advertising Parameters" + name = "HCI_LE_Set_Advertising_Parameters" fields_desc = [LEShortField("interval_min", 0x0800), LEShortField("interval_max", 0x0800), ByteEnumField("adv_type", 0, {0: "ADV_IND", 1: "ADV_DIRECT_IND", 2: "ADV_SCAN_IND", 3: "ADV_NONCONN_IND", 4: "ADV_DIRECT_IND_LOW"}), # noqa: E501 @@ -1089,7 +1098,7 @@ class HCI_Cmd_LE_Set_Advertising_Parameters(Packet): class HCI_Cmd_LE_Set_Advertising_Data(Packet): - name = "LE Set Advertising Data" + name = "HCI_LE_Set_Advertising_Data" fields_desc = [FieldLenField("len", None, length_of="data", fmt="B"), PadField( PacketListField("data", [], EIR_Hdr, @@ -1098,35 +1107,109 @@ class HCI_Cmd_LE_Set_Advertising_Data(Packet): class HCI_Cmd_LE_Set_Scan_Response_Data(Packet): - name = "LE Set Scan Response Data" + name = "HCI_LE_Set_Scan_Response_Data" fields_desc = [FieldLenField("len", None, length_of="data", fmt="B"), StrLenField("data", "", length_from=lambda pkt:pkt.len), ] class HCI_Cmd_LE_Set_Advertise_Enable(Packet): - name = "LE Set Advertise Enable" + name = "HCI_LE_Set_Advertising_Enable" fields_desc = [ByteField("enable", 0)] -class HCI_Cmd_LE_Start_Encryption_Request(Packet): - name = "LE Start Encryption" +class HCI_Cmd_LE_Set_Scan_Parameters(Packet): + name = "HCI_LE_Set_Scan_Parameters" + fields_desc = [ByteEnumField("type", 0, {0: "passive", 1: "active"}), + XLEShortField("interval", 16), + XLEShortField("window", 16), + ByteEnumField("atype", 0, {0: "public", + 1: "random", + 2: "rpa (pub)", + 3: "rpa (random)"}), + ByteEnumField("policy", 0, {0: "all", 1: "whitelist"})] + + +class HCI_Cmd_LE_Set_Scan_Enable(Packet): + name = "HCI_LE_Set_Scan_Enable" + fields_desc = [ByteField("enable", 1), + ByteField("filter_dups", 1), ] + + +class HCI_Cmd_LE_Create_Connection(Packet): + name = "HCI_LE_Create_Connection" + fields_desc = [LEShortField("interval", 96), + LEShortField("window", 48), + ByteEnumField("filter", 0, {0: "address"}), + ByteEnumField("patype", 0, {0: "public", 1: "random"}), + LEMACField("paddr", None), + ByteEnumField("atype", 0, {0: "public", 1: "random"}), + LEShortField("min_interval", 40), + LEShortField("max_interval", 56), + LEShortField("latency", 0), + LEShortField("timeout", 42), + LEShortField("min_ce", 0), + LEShortField("max_ce", 0), ] + + +class HCI_Cmd_LE_Create_Connection_Cancel(Packet): + name = "HCI_LE_Create_Connection_Cancel" + + +class HCI_Cmd_LE_Read_Filter_Accept_List_Size(Packet): + name = "HCI_LE_Read_Filter_Accept_List_Size" + + +class HCI_Cmd_LE_Clear_Filter_Accept_List(Packet): + name = "HCI_LE_Clear_Filter_Accept_List" + + +class HCI_Cmd_LE_Add_Device_To_Filter_Accept_List(Packet): + name = "HCI_LE_Add_Device_To_Filter_Accept_List" + fields_desc = [ByteEnumField("address_type", 0, {0: "public", + 1: "random", + 0xff: "anonymous"}), + LEMACField("address", None)] + + +class HCI_Cmd_LE_Remove_Device_From_Filter_Accept_List(HCI_Cmd_LE_Add_Device_To_Filter_Accept_List): # noqa: E501 + name = "HCI_LE_Remove_Device_From_Filter_Accept_List" + + +class HCI_Cmd_LE_Connection_Update(Packet): + name = "HCI_LE_Connection_Update" + fields_desc = [XLEShortField("handle", 0), + XLEShortField("min_interval", 0), + XLEShortField("max_interval", 0), + XLEShortField("latency", 0), + XLEShortField("timeout", 0), + LEShortField("min_ce", 0), + LEShortField("max_ce", 0xffff), ] + + +class HCI_Cmd_LE_Read_Remote_Features(Packet): + name = "HCI_LE_Read_Remote_Features" + fields_desc = [LEShortField("handle", 64)] + + +class HCI_Cmd_LE_Enable_Encryption(Packet): + name = "HCI_LE_Enable_Encryption" fields_desc = [LEShortField("handle", 0), StrFixedLenField("rand", None, 8), XLEShortField("ediv", 0), StrFixedLenField("ltk", b'\x00' * 16, 16), ] -class HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply(Packet): - name = "LE Long Term Key Request Negative Reply" - fields_desc = [LEShortField("handle", 0), ] - - class HCI_Cmd_LE_Long_Term_Key_Request_Reply(Packet): - name = "LE Long Term Key Request Reply" + name = "HCI_LE_Long_Term_Key_Request_Reply" fields_desc = [LEShortField("handle", 0), StrFixedLenField("ltk", b'\x00' * 16, 16), ] +class HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply(Packet): + name = "HCI_LE_Long_Term_Key_Request _Negative_Reply" + fields_desc = [LEShortField("handle", 0), ] + + class HCI_Event_Hdr(Packet): name = "HCI Event header" fields_desc = [XByteField("code", 0), @@ -1296,6 +1379,12 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): conf.l2types.register(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, HCI_PHDR_Hdr) conf.l2types.register(DLT_BLUETOOTH_LINUX_MONITOR, BT_Mon_Pcap_Hdr) + +# 7.1 LINK CONTROL COMMANDS, the OGF is defined as 0x01 +bind_layers(HCI_Command_Hdr, HCI_Cmd_Inquiry, ogf=0x01, ocf=0x0001) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Inquiry_Cancel, ogf=0x01, ocf=0x0002) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Periodic_Inquiry_Mode, ogf=0x01, ocf=0x0003) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Exit_Peiodic_Inquiry_Mode, ogf=0x01, ocf=0x0004) bind_layers(HCI_Command_Hdr, HCI_Cmd_Create_Connection, ogf=0x01, ocf=0x0005) bind_layers(HCI_Command_Hdr, HCI_Cmd_Disconnect, ogf=0x01, ocf=0x0006) bind_layers(HCI_Command_Hdr, HCI_Cmd_Link_Key_Request_Reply, ogf=0x01, ocf=0x000b) @@ -1303,18 +1392,35 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Connection_Encryption, ogf=0x01, ocf=0x0013) bind_layers(HCI_Command_Hdr, HCI_Cmd_Remote_Name_Request, ogf=0x01, ocf=0x0019) +# 7.2 Link Policy commands, the OGF is defined as 0x02 +bind_layers(HCI_Command_Hdr, HCI_Cmd_Hold_Mode, ogf=0x02, ocf=0x0001) +# 7.3 CONTROLLER & BASEBAND COMMANDS, the OGF is defined as 0x03 bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Mask, ogf=0x03, ocf=0x0001) bind_layers(HCI_Command_Hdr, HCI_Cmd_Reset, ogf=0x03, ocf=0x0003) bind_layers(HCI_Command_Hdr, HCI_Cmd_Set_Event_Filter, ogf=0x03, ocf=0x0005) bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Local_Name, ogf=0x03, ocf=0x0013) -bind_layers(HCI_Command_Hdr, HCI_Cmd_Connect_Accept_Timeout, ogf=0x03, ocf=0x0016) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Connect_Accept_Timeout, ogf=0x03, ocf=0x0016) bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Extended_Inquiry_Response, ogf=0x03, ocf=0x0052) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Host_Supported, ogf=0x03, ocf=0x006d) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_LE_Host_Support, ogf=0x03, ocf=0x006c) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_LE_Host_Support, ogf=0x03, ocf=0x006d) +# 7.4 INFORMATIONAL PARAMETERS, the OGF is defined as 0x04 bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_BD_Addr, ogf=0x04, ocf=0x0009) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Buffer_Size, ogf=0x08, ocf=0x0002) +# 7.5 STATUS PARAMETERS, the OGF is defined as 0x05 +bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_Link_Quality, ogf=0x05, ocf=0x0003) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_RSSI, ogf=0x05, ocf=0x0005) + +# 7.6 TESTING COMMANDS, the OGF is defined as 0x06 +bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_Loopback_Mode, ogf=0x06, ocf=0x0001) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Loopback_Mode, ogf=0x06, ocf=0x0002) + +# 7.8 LE CONTROLLER COMMANDS, the OGF code is defined as 0x08 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Buffer_Size_V1, ogf=0x08, ocf=0x0002) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Buffer_Size_V2, ogf=0x08, ocf=0x0060) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Local_Supported_Features, + ogf=0x08, ocf=0x0003) bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Random_Address, ogf=0x08, ocf=0x0005) bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Parameters, ogf=0x08, ocf=0x0006) # noqa: E501 bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Advertising_Data, ogf=0x08, ocf=0x0008) @@ -1324,16 +1430,18 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Set_Scan_Enable, ogf=0x08, ocf=0x000c) bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection, ogf=0x08, ocf=0x000d) bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Create_Connection_Cancel, ogf=0x08, ocf=0x000e) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_White_List_Size, ogf=0x08, ocf=0x000f) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Clear_White_List, ogf=0x08, ocf=0x0010) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Add_Device_To_White_List, ogf=0x08, ocf=0x0011) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Remove_Device_From_White_List, ogf=0x08, ocf=0x0012) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Filter_Accept_List_Size, + ogf=0x08, ocf=0x000f) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Clear_Filter_Accept_List, ogf=0x08, ocf=0x0010) +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Add_Device_To_Filter_Accept_List, ogf=0x08, ocf=0x0011) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Remove_Device_From_Filter_Accept_List, ogf=0x08, ocf=0x0012) # noqa: E501 bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Connection_Update, ogf=0x08, ocf=0x0013) -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Remote_Used_Features, ogf=0x08, ocf=0x0016) # noqa: E501 -bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Start_Encryption_Request, ogf=0x08, ocf=0x0019) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Read_Remote_Features, ogf=0x08, ocf=0x0016) # noqa: E501 +bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Enable_Encryption, ogf=0x08, ocf=0x0019) # noqa: E501 bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Reply, ogf=0x08, ocf=0x001a) # noqa: E501 bind_layers(HCI_Command_Hdr, HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply, ogf=0x08, ocf=0x001b) # noqa: E501 +# 7.7 EVENTS bind_layers(HCI_Event_Hdr, HCI_Event_Connect_Complete, code=0x03) bind_layers(HCI_Event_Hdr, HCI_Event_Disconnection_Complete, code=0x05) bind_layers(HCI_Event_Hdr, HCI_Event_Remote_Name_Request_Complete, code=0x07) diff --git a/test/scapy/layers/bluetooth.uts b/test/scapy/layers/bluetooth.uts index c103fb0081b..1743e6de91c 100644 --- a/test/scapy/layers/bluetooth.uts +++ b/test/scapy/layers/bluetooth.uts @@ -3,50 +3,146 @@ + Bluetooth tests = HCI layers -# a huge packet with all classes in it! -pkt = HCI_ACL_Hdr()/HCI_Cmd_Create_Connection()/HCI_Cmd_Complete_Read_BD_Addr()/HCI_Cmd_Connect_Accept_Timeout()/HCI_Cmd_Disconnect()/HCI_Cmd_LE_Connection_Update()/HCI_Cmd_LE_Create_Connection()/HCI_Cmd_LE_Create_Connection_Cancel()/HCI_Cmd_LE_Host_Supported()/HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply()/HCI_Cmd_LE_Long_Term_Key_Request_Reply()/HCI_Cmd_LE_Read_Buffer_Size()/HCI_Cmd_LE_Set_Advertise_Enable()/HCI_Cmd_LE_Set_Advertising_Data()/HCI_Cmd_LE_Set_Advertising_Parameters()/HCI_Cmd_LE_Set_Random_Address()/HCI_Cmd_LE_Set_Scan_Enable()/HCI_Cmd_LE_Set_Scan_Parameters()/HCI_Cmd_LE_Start_Encryption_Request()/HCI_Cmd_Authentication_Requested()/HCI_Cmd_Link_Key_Request_Reply()/HCI_Cmd_Read_BD_Addr()/HCI_Cmd_Remote_Name_Request()/HCI_Cmd_Reset()/HCI_Cmd_Set_Connection_Encryption()/HCI_Cmd_Set_Event_Filter()/HCI_Cmd_Set_Event_Mask()/HCI_Command_Hdr()/HCI_Event_Command_Complete()/HCI_Event_Command_Status()/HCI_Event_Connect_Complete()/HCI_Event_Disconnection_Complete()/HCI_Event_Encryption_Change()/HCI_Event_Remote_Name_Request_Complete()/HCI_Event_Hdr()/HCI_Event_LE_Meta()/HCI_Event_Number_Of_Completed_Packets()/HCI_Hdr()/HCI_LE_Meta_Advertising_Reports()/HCI_LE_Meta_Connection_Complete()/HCI_LE_Meta_Connection_Update_Complete()/HCI_LE_Meta_Long_Term_Key_Request() -assert HCI_ACL_Hdr in pkt.layers() -assert HCI_Cmd_Create_Connection in pkt.layers() -assert HCI_Cmd_Complete_Read_BD_Addr in pkt.layers() -assert HCI_Cmd_Connect_Accept_Timeout in pkt.layers() -assert HCI_Cmd_Disconnect in pkt.layers() -assert HCI_Cmd_LE_Connection_Update in pkt.layers() -assert HCI_Cmd_LE_Create_Connection in pkt.layers() -assert HCI_Cmd_LE_Create_Connection_Cancel in pkt.layers() -assert HCI_Cmd_LE_Host_Supported in pkt.layers() -assert HCI_Cmd_LE_Long_Term_Key_Request_Negative_Reply in pkt.layers() -assert HCI_Cmd_LE_Long_Term_Key_Request_Reply in pkt.layers() -assert HCI_Cmd_LE_Read_Buffer_Size in pkt.layers() -assert HCI_Cmd_LE_Set_Advertise_Enable in pkt.layers() -assert HCI_Cmd_LE_Set_Advertising_Data in pkt.layers() -assert HCI_Cmd_LE_Set_Advertising_Parameters in pkt.layers() -assert HCI_Cmd_LE_Set_Random_Address in pkt.layers() -assert HCI_Cmd_LE_Set_Scan_Enable in pkt.layers() -assert HCI_Cmd_LE_Set_Scan_Parameters in pkt.layers() -assert HCI_Cmd_LE_Start_Encryption_Request in pkt.layers() -assert HCI_Cmd_Authentication_Requested in pkt.layers() -assert HCI_Cmd_Link_Key_Request_Reply in pkt.layers() -assert HCI_Cmd_Read_BD_Addr in pkt.layers() -assert HCI_Cmd_Remote_Name_Request in pkt.layers() -assert HCI_Cmd_Reset in pkt.layers() -assert HCI_Cmd_Set_Connection_Encryption in pkt.layers() -assert HCI_Cmd_Set_Event_Filter in pkt.layers() -assert HCI_Cmd_Set_Event_Mask in pkt.layers() -assert HCI_Command_Hdr in pkt.layers() -assert HCI_Event_Command_Complete in pkt.layers() -assert HCI_Event_Command_Status in pkt.layers() -assert HCI_Event_Connect_Complete in pkt.layers() -assert HCI_Event_Disconnection_Complete in pkt.layers() -assert HCI_Event_Encryption_Change in pkt.layers() -assert HCI_Event_Remote_Name_Request_Complete in pkt.layers() -assert HCI_Event_Hdr in pkt.layers() -assert HCI_Event_LE_Meta in pkt.layers() -assert HCI_Event_Number_Of_Completed_Packets in pkt.layers() -assert HCI_Hdr in pkt.layers() -assert HCI_LE_Meta_Advertising_Reports in pkt.layers() -assert HCI_LE_Meta_Connection_Complete in pkt.layers() -assert HCI_LE_Meta_Connection_Update_Complete in pkt.layers() -assert HCI_LE_Meta_Long_Term_Key_Request in pkt.layers() + +# HCI_Command_Hdr +# default construction +hci_cmd_hdr = HCI_Command_Hdr() +assert hci_cmd_hdr.ogf == 0 +assert hci_cmd_hdr.ocf == 0 +assert hci_cmd_hdr.len == None +assert raw(hci_cmd_hdr) == b'\x00\x00\x00' + +# parsing +hci_cmd_hdr = HCI_Command_Hdr(raw(hci_cmd_hdr)) +assert hci_cmd_hdr.ogf == 0 +assert hci_cmd_hdr.ocf == 0 +assert hci_cmd_hdr.len == 0 + +# HCI_Cmd_Inquiry default construction +hci_cmd_inquiry = HCI_Command_Hdr() / HCI_Cmd_Inquiry() +assert hci_cmd_inquiry.ogf == 0x01 +assert hci_cmd_inquiry.ocf == 0x01 +assert hci_cmd_inquiry.len == None +assert hci_cmd_inquiry.lap == 0x9e8b33 +assert hci_cmd_inquiry.inquiry_length == 0 +assert hci_cmd_inquiry.num_responses == 0 + +# parsing +hci_cmd_inquiry = HCI_Command_Hdr(raw(hci_cmd_inquiry)) +assert hci_cmd_inquiry.ogf == 0x01 +assert hci_cmd_inquiry.ocf == 0x01 +assert hci_cmd_inquiry.len == 5 +assert hci_cmd_inquiry.lap == 0x9e8b33 +assert hci_cmd_inquiry.inquiry_length == 0 +assert hci_cmd_inquiry.num_responses == 0 + +# HCI_Cmd_Inquiry constructing an invalid packet +hci_cmd_inquiry = HCI_Command_Hdr(len = 10) / HCI_Cmd_Inquiry() +assert hci_cmd_inquiry.ogf == 0x01 +assert hci_cmd_inquiry.ocf == 0x01 +assert hci_cmd_inquiry.len == 10 +assert hci_cmd_inquiry.lap == 0x9e8b33 +assert hci_cmd_inquiry.inquiry_length == 0 +assert hci_cmd_inquiry.num_responses == 0 + +assert raw(hci_cmd_inquiry)[2] == 10 + +# parse the invalid packet +hci_cmd_inquiry = HCI_Command_Hdr(raw(hci_cmd_inquiry)) +assert hci_cmd_inquiry.ogf == 0x01 +assert hci_cmd_inquiry.ocf == 0x01 +assert hci_cmd_inquiry.len == 10 +assert hci_cmd_inquiry.lap == 0x9e8b33 +assert hci_cmd_inquiry.inquiry_length == 0 +assert hci_cmd_inquiry.num_responses == 0 + +# HCI_Cmd_Inquiry_Cancel default construction +hci_cmd_inquiry_cancel = HCI_Command_Hdr() / HCI_Cmd_Inquiry_Cancel() +assert hci_cmd_inquiry_cancel.ogf == 0x01 +assert hci_cmd_inquiry_cancel.ocf == 0x02 +assert hci_cmd_inquiry_cancel.len == None + +# hci_cmd_inquiry_cancel parsing +hci_cmd_inquiry_cancel = HCI_Command_Hdr(raw(hci_cmd_inquiry_cancel)) +assert hci_cmd_inquiry_cancel.ogf == 0x01 +assert hci_cmd_inquiry_cancel.ocf == 0x02 +assert hci_cmd_inquiry_cancel.len == 0 + + +# Hci_Cmd_Hold_Mode +hci_cmd_hold_mode = HCI_Command_Hdr() / HCI_Cmd_Hold_Mode() +assert hci_cmd_hold_mode.ogf == 0x02 +assert hci_cmd_hold_mode.ocf == 0x01 +assert hci_cmd_hold_mode.len == None + +# parsing +hci_cmd_hold_mode = HCI_Command_Hdr(raw(hci_cmd_hold_mode)) +assert hci_cmd_hold_mode.ogf == 0x02 +assert hci_cmd_hold_mode.ocf == 0x01 +assert hci_cmd_hold_mode.len == 6 + +# HCI_Cmd_Set_Event_Mask +hci_cmd_set_event_mask = HCI_Command_Hdr() / HCI_Cmd_Set_Event_Mask() +assert hci_cmd_set_event_mask.ogf == 0x03 +assert hci_cmd_set_event_mask.ocf == 0x01 +assert hci_cmd_set_event_mask.len == None + +# parsing +hci_cmd_set_event_mask = HCI_Command_Hdr(raw(hci_cmd_set_event_mask)) +assert hci_cmd_set_event_mask.ogf == 0x03 +assert hci_cmd_set_event_mask.ocf == 0x01 +assert hci_cmd_set_event_mask.len == 8 + +# HCI_Cmd_Read_BD_Addr +hci_cmd_read_bd_addr = HCI_Command_Hdr() / HCI_Cmd_Read_BD_Addr() +assert hci_cmd_read_bd_addr.ogf == 0x04 +assert hci_cmd_read_bd_addr.ocf == 0x09 +assert hci_cmd_read_bd_addr.len == None + +# parsing +hci_cmd_read_bd_addr = HCI_Command_Hdr(raw(hci_cmd_read_bd_addr)) +assert hci_cmd_read_bd_addr.ogf == 0x04 +assert hci_cmd_read_bd_addr.ocf == 0x09 +assert hci_cmd_read_bd_addr.len == 0 + + +# HCI_Cmd_Read_Link_Quality +hci_cmd_read_link_quality = HCI_Command_Hdr() / HCI_Cmd_Read_Link_Quality() +assert hci_cmd_read_link_quality.ogf == 0x05 +assert hci_cmd_read_link_quality.ocf == 0x03 +assert hci_cmd_read_link_quality.len == None + +# parsing +hci_cmd_read_link_quality = HCI_Command_Hdr(raw(hci_cmd_read_link_quality)) +assert hci_cmd_read_link_quality.ogf == 0x05 +assert hci_cmd_read_link_quality.ocf == 0x03 +assert hci_cmd_read_link_quality.len == 2 + + +# HCI_Cmd_Read_Loopback_Mode +hci_cmd_read_loopback_mode = HCI_Command_Hdr() / HCI_Cmd_Read_Loopback_Mode() +assert hci_cmd_read_loopback_mode.ogf == 0x06 +assert hci_cmd_read_loopback_mode.ocf == 0x01 +assert hci_cmd_read_loopback_mode.len == None + +# parsing +hci_cmd_read_loopback_mode = HCI_Command_Hdr(raw(hci_cmd_read_loopback_mode)) +assert hci_cmd_read_loopback_mode.ogf == 0x06 +assert hci_cmd_read_loopback_mode.ocf == 0x01 +assert hci_cmd_read_loopback_mode.len == 0 + + +# HCI_Cmd_LE_Read_Buffer_Size_V1 +hci_cmd_le_read_buffer_size_v1 = HCI_Command_Hdr() / HCI_Cmd_LE_Read_Buffer_Size_V1() +assert hci_cmd_le_read_buffer_size_v1.ogf == 0x08 +assert hci_cmd_le_read_buffer_size_v1.ocf == 0x02 +assert hci_cmd_le_read_buffer_size_v1.len == None + +# parsing +hci_cmd_le_read_buffer_size_v1 = HCI_Command_Hdr(raw(hci_cmd_le_read_buffer_size_v1)) +assert hci_cmd_le_read_buffer_size_v1.ogf == 0x08 +assert hci_cmd_le_read_buffer_size_v1.ocf == 0x02 +assert hci_cmd_le_read_buffer_size_v1.len == 0 + Bluetooth Transport Layers = Test HCI_PHDR_Hdr