diff --git a/scapy/layers/bluetooth.py b/scapy/layers/bluetooth.py index 4962babee10..84f93ceffe5 100644 --- a/scapy/layers/bluetooth.py +++ b/scapy/layers/bluetooth.py @@ -2518,6 +2518,69 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): XLEShortField("ediv", 0), ] +class HCI_LE_Meta_Extended_Advertising_Report(Packet): + name = "Extended Advertising Report" + fields_desc = [ + BitField("reserved0", 0, 1), + BitEnumField("data_status", 0, 2, { + 0b00: "complete", + 0b01: "incomplete", + 0b10: "incomplete_truncated", + 0b11: "reserved" + }), + BitField("legacy", 0, 1), + BitField("scan_response", 0, 1), + BitField("directed", 0, 1), + BitField("scannable", 0, 1), + BitField("connectable", 0, 1), + ByteField("reserved", 0), + ByteEnumField("address_type", 0, { + 0x00: "public_device_address", + 0x01: "random_device_address", + 0x02: "public_identity_address", + 0x03: "random_identity_address", + 0xff: "anonymous" + }), + LEMACField('address', None), + ByteEnumField("primary_phy", 0, { + 0x01: "le_1m", + 0x03: "le_coded_s8", + 0x04: "le_coded_s2" + }), + ByteEnumField("secondary_phy", 0, { + 0x01: "le_1m", + 0x02: "le_2m", + 0x03: "le_coded_s8", + 0x04: "le_coded_s2" + }), + ByteField("advertising_sid", 0xff), + ByteField("tx_power", 0x7f), + SignedByteField("rssi", 0x00), + LEShortField("periodic_advertising_interval", 0x0000), + ByteEnumField("direct_address_type", 0, { + 0x00: "public_device_address", + 0x01: "non_resolvable_private_address", + 0x02: "resolvable_private_address_resolved_0", + 0x03: "resolvable_private_address_resolved_1", + 0xfe: "resolvable_private_address_unable_resolve"}), + LEMACField("direct_address", None), + FieldLenField("data_length", None, length_of="data", fmt="B"), + PacketListField("data", [], EIR_Hdr, + length_from=lambda pkt: pkt.data_length), + ] + + def extract_padding(self, s): + return '', s + + +class HCI_LE_Meta_Extended_Advertising_Reports(Packet): + name = "Extended Advertising Reports" + fields_desc = [FieldLenField("num_reports", None, count_of="reports", fmt="B"), + PacketListField("reports", None, + HCI_LE_Meta_Extended_Advertising_Report, + count_from=lambda pkt: pkt.num_reports)] + + bind_layers(HCI_PHDR_Hdr, HCI_Hdr) bind_layers(HCI_Hdr, HCI_Command_Hdr, type=1) @@ -2648,6 +2711,7 @@ class HCI_LE_Meta_Long_Term_Key_Request(Packet): bind_layers(HCI_Event_LE_Meta, HCI_LE_Meta_Advertising_Reports, event=0x02) bind_layers(HCI_Event_LE_Meta, HCI_LE_Meta_Connection_Update_Complete, event=0x03) bind_layers(HCI_Event_LE_Meta, HCI_LE_Meta_Long_Term_Key_Request, event=0x05) +bind_layers(HCI_Event_LE_Meta, HCI_LE_Meta_Extended_Advertising_Reports, event=0x0d) bind_layers(EIR_Hdr, EIR_Flags, type=0x01) bind_layers(EIR_Hdr, EIR_IncompleteList16BitServiceUUIDs, type=0x02) diff --git a/test/scapy/layers/bluetooth.uts b/test/scapy/layers/bluetooth.uts index 9072aa1d31a..7497671326d 100644 --- a/test/scapy/layers/bluetooth.uts +++ b/test/scapy/layers/bluetooth.uts @@ -705,6 +705,59 @@ assert b[EIR_CompleteList128BitServiceUUIDs].svc_uuids[0] == UUID("01234567-89ab assert a.summary() == "HCI Event / HCI_Event_Hdr / HCI_Event_LE_Meta / HCI_LE_Meta_Advertising_Reports" += EIR_Hdr - HCI_LE_Meta_Extended_Advertising_Report +a = HCI_Hdr()/HCI_Event_Hdr()/HCI_Event_LE_Meta()/HCI_LE_Meta_Extended_Advertising_Reports(reports=[ + HCI_LE_Meta_Extended_Advertising_Report( + #event_type = 0x0012, + scannable = 1, + legacy = 1, + address_type = 0x01, + address="a1:b2:c3:d4:e5:f6", + primary_phy = 1, + rssi = -85, + data=[ + EIR_Hdr()/EIR_CompleteList16BitServiceUUIDs( + svc_uuids = [0xffff], + ), + EIR_Hdr()/EIR_ServiceData16BitUUID( + svc_uuid = 0xffff + )/Raw(b"scapy\x00\x00\x00") + ] + ), + HCI_LE_Meta_Extended_Advertising_Report( + #event_type = 0x001a, + scannable = 1, + scan_response = 1, + legacy = 1, + address_type = 0x01, + address="a1:b2:c3:d4:e5:f6", + primary_phy = 1, + rssi = -85, + data=[ + EIR_Hdr()/EIR_Manufacturer_Specific_Data( + company_id = 0xffff, + ) / Raw(b"scapy\x00\x01\x02\x03\x04") + ] + ), +]) + +assert raw(a) == b"\x04\x3e\x50\x0d\x02\x12\x00\x01\xf6\xe5\xd4\xc3\xb2\xa1\x01\x00\xff\x7f\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x03\x03\xff\xff\x0b\x16\xff\xffscapy\x00\x00\x00\x1a\x00\x01\xf6\xe5\xd4\xc3\xb2\xa1\x01\x00\xff\x7f\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x0d\xff\xff\xffscapy\x00\x01\x02\x03\x04" + +b = HCI_Hdr(raw(a)) +b.show() +assert b[HCI_Event_Hdr].len > 0 +assert b[HCI_LE_Meta_Extended_Advertising_Reports].num_reports == 2 +assert b[HCI_LE_Meta_Extended_Advertising_Report][0].address == "a1:b2:c3:d4:e5:f6" +assert b[HCI_LE_Meta_Extended_Advertising_Report][0].tx_power == 0x7f +assert b[HCI_LE_Meta_Extended_Advertising_Report][0].rssi == -85 +assert b[HCI_LE_Meta_Extended_Advertising_Report][0].data_length > 0 +assert b[EIR_CompleteList16BitServiceUUIDs].svc_uuids == [0xffff] +assert b[EIR_ServiceData16BitUUID].svc_uuid == 0xffff +assert raw(b[EIR_ServiceData16BitUUID].payload) == b"scapy\x00\x00\x00" +assert b[EIR_Manufacturer_Specific_Data].company_id == 0xffff +assert raw(b[EIR_Manufacturer_Specific_Data].payload) == b"scapy\x00\x01\x02\x03\x04" + + = ATT_Hdr - misc a = HCI_Hdr()/HCI_ACL_Hdr()/L2CAP_Hdr()/ATT_Hdr()/ATT_Read_By_Type_Request_128bit(uuid1=0xa14, uuid2=0xa24) a = HCI_Hdr(raw(a))