diff --git a/scapy/layers/bluetooth.py b/scapy/layers/bluetooth.py index 55f580df5d4..b49c7fbe4c6 100644 --- a/scapy/layers/bluetooth.py +++ b/scapy/layers/bluetooth.py @@ -5,6 +5,8 @@ # Copyright (C) Mike Ryan # Copyright (C) Michael Farrell # Copyright (C) Haram Park +# Copyright (C) Guillaume Bouffard +# Copyright (C) Philippe Trébuchet """ Bluetooth layers, sockets and send/receive functions. @@ -33,6 +35,7 @@ BitField, LEFieldLenField, XBitField, + BitLenField, ByteEnumField, ByteField, FieldLenField, @@ -45,12 +48,15 @@ LenField, MultipleTypeField, NBytesField, + PacketField, PacketListField, PadField, ShortField, + ShortEnumField, SignedByteField, StrField, StrFixedLenField, + XStrFixedLenField, StrLenField, StrNullField, UUIDField, @@ -131,7 +137,7 @@ class HCI_PHDR_Hdr(Packet): 0x0F: "Connection Rejected due to Unacceptable BD_ADDR", 0x10: "Connection Accept Timeout Exceeded", 0x11: "Unsupported Feature or Parameter Value", - 0x12: "Invalid HCI Command Parameters", + 0x12: "Invalid HCI Command parameters", 0x13: "Remote User Terminated Connection", 0x14: "Remote Device Terminated Connection due to Low Resources", 0x15: "Remote Device Terminated Connection due to Power Off", @@ -143,7 +149,7 @@ class HCI_PHDR_Hdr(Packet): 0x1B: "SCO Offset Rejected", 0x1C: "SCO Interval Rejected", 0x1D: "SCO Air Mode Rejected", - 0x1E: "Invalid LMP Parameters / Invalid LL Parameters", + 0x1E: "Invalid LMP parameters / Invalid LL parameters", 0x1F: "Unspecified Error", 0x20: "Unsupported LMP Parameter Value / Unsupported LL Parameter Value", 0x21: "Role Change Not Allowed", @@ -172,7 +178,7 @@ class HCI_PHDR_Hdr(Packet): 0x38: "Host Busy - Pairing", 0x39: "Connection Rejected due to No Suitable Channel Found", 0x3A: "Controller Busy", - 0x3B: "Unacceptable Connection Parameters", + 0x3B: "Unacceptable Connection parameters", 0x3C: "Advertising Timeout", 0x3D: "Connection Terminated due to MIC Failure", 0x3E: "Connection Failed to be Established / Synchronization Timeout", @@ -436,6 +442,50 @@ def answers(self, other): return isinstance(other, L2CAP_ConfReq) +class L2CAP_ConfSet(Packet): + name = "L2CAP Conf Set" + fields_desc = [ + ByteEnumField("type", 0x0, {1: "mtu", + 2: "flushtimeout", + 3: "QoS"}), + PacketListField("option", [], next_cls_cb=lambda pkt, _, __, ___: { + 1: L2CAP_ConfSet_MTU, + 2: L2CAP_ConfSet_FlushTimeOut, + 3: L2CAP_ConfSet_QoS, + }[pkt.type]) + ] + + +class L2CAP_ConfSet_MTU(Packet): + name = "L2CAP Conf Set MTU" + fields_desc = [ + ByteField("length", 0x02), + LEShortField("mtu", 0x30), + ] + + +class L2CAP_ConfSet_FlushTimeOut(Packet): + name = "L2CAP Conf Set Flush Timeout" + fields_desc = [ + ByteField("length", 0x02), + LEShortField("flushtimeout", 0x30), + ] + + +class L2CAP_ConfSet_QoS(Packet): + name = "L2CAP Conf Set QoS" + fields_desc = [ + ByteField("length", 0x16), + ByteField("flags", 0x0), + ByteField("service_type", 0x1), + LEIntField("token_rate", 0x30), + LEIntField("token_bucket_size", 0x30), + LEIntField("peak_bandwidth", 0x30), + LEIntField("latency", 0xffff_ffff), + LEIntField("delay_variation", 0xffff_ffff), + ] + + class L2CAP_DisconnReq(Packet): name = "L2CAP Disconn Req" fields_desc = [LEShortField("dcid", 0), @@ -866,6 +916,251 @@ class ATT_Read_Multiple_Variable_Response(Packet): fields_desc = [PacketListField("values", [], ATT_Length_Value_Tuple)] +# Bluetooth Core Specification, Vol 3, Part B (SDP) + +SDP_FIXED_SIZES = {1: 2, 2: 4, 4: 16} + + +class SDP_Continuation(Packet): + name = "SDP Continuation State" + fields_desc = [ + ByteField("count", 0x00), + ConditionalField( + BitLenField("continuation_state_info", 0, + length_from=lambda pkt: pkt.count * 8), + lambda pkt: pkt.count != 0 + ), + ] + + +class SDP_DataElement(Packet): + name = "Data Element" + fields_desc = [ + BitEnumField("data_type", 0, 5, { + 0: "null", # size = 0 + 1: "unsigned_integer", # size_index = 0, 1, 2, 3, 4 + 2: "signed_integer", # size_index = 0, 1, 2, 3, 4 + 3: "UUID", # size_index = 1, 2, 4 + 4: "text_string", # size_index = 5, 6, 7 + 5: "boolean", # size_index = 0 | False == 0 + 6: "data_element_sequence", # size_index = 5, 6, 7 + 7: "data_element_alternative", # size_index = 5, 6, 7 + 8: "URL", # size_index = 5, 6, 7 + # Other Reserved for future use + }), + BitField("size_index", None, size=3), + ConditionalField( + MultipleTypeField( + [ + ( + FieldLenField("size", None, fmt="B", length_of="data"), + lambda pkt: pkt.size_index == 5 + ), + ( + FieldLenField("size", None, fmt="H", length_of="data"), + lambda pkt: pkt.size_index == 6 + ), + ( + FieldLenField("size", None, fmt="I", length_of="data"), + lambda pkt: pkt.size_index == 7 + ), + ], + FieldLenField("size", None, length_of="data"), + ), + lambda pkt: 5 <= pkt.size_index <= 7 + ), + ConditionalField( + MultipleTypeField( + [ + ( + # Unsigned Integer + BitLenField("data", 0, + length_from=lambda pkt: pkt.get_data_size() * 8), + lambda pkt: pkt.data_type == 1 and 0 <= pkt.size_index <= 4 + ), + ( + # Signed two's-complement integer + BitLenField("data", 0, + length_from=lambda pkt: pkt.get_data_size() * 8), + lambda pkt: pkt.data_type == 2 and 0 <= pkt.size_index <= 4 + ), + ( + # UUID, a universally unique identifier + XStrFixedLenField("data", "", + length_from=lambda pkt: pkt.get_data_size()), + lambda pkt: pkt.data_type == 3 and pkt.size_index in (1, 2, 4) + ), + ( + # Text string + StrLenField("data", "", + length_from=lambda pkt: pkt.get_data_size()), + lambda pkt: pkt.data_type == 4 and 5 <= pkt.size_index <= 7 + ), + ( + # Boolean + ByteField("data", 0), + lambda pkt: pkt.data_type == 5 and pkt.size_index == 0 + ), + ( + # Sequence or alternative + PacketListField( + "data", [], + length_from=lambda pkt: pkt.get_data_size(), + next_cls_cb=lambda pkt, _, __, ___: SDP_DataElement), + lambda pkt: (pkt.data_type in (6, 7) and + 5 <= pkt.size_index <= 7) + ), + ( + # URL + StrLenField("data", "", + length_from=lambda pkt: pkt.get_data_size()), + lambda pkt: pkt.data_type == 8 and 5 <= pkt.size_index <= 7 + ), + ], + StrLenField("data", "", + length_from=lambda pkt: pkt.get_data_size()), + ), + lambda pkt: 5 <= pkt.size_index <= 7 or pkt.get_data_size() > 0 + ), + ] + + def get_data_size(self): + if self.data_type == 0: + return 0 + if self.size_index == 0: + return 1 + if self.size_index in SDP_FIXED_SIZES: + return SDP_FIXED_SIZES[self.size_index] + return self.size + + def extract_padding(self, s): + return b"", s + + +class SDP_Error_Response(Packet): + name = "SDP PDU Error" + fields_desc = [ + ShortEnumField("error_code", 1, { + 1: "Invalid/unsupported SDP version", + 2: "Invalid Service Record Handle", + 3: "Invalid request syntax", + 4: "Invalid PDU Size", + 5: "Invalid Continuation State", + 6: "Insufficient Resources to satisfy Request", + # All other values are reserved for future use + }), + ] + + +class SDP_Service_Search_Request(Packet): + name = "SDP Service Search Req PDU" + fields_desc = [ + PacketField("service_search_pattern", None, SDP_DataElement), + # Range: 0x0001 to 0xFFFF + ShortField("max_service_record_count", 0x0001), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +class SDP_Service_Search_Response(Packet): + name = "SDP Service Search RSP PDU" + fields_desc = [ + ShortField("total_service_record_count", 0x0000), + FieldLenField("current_service_record_count", None, fmt="H", + count_of="service_record_handle_list"), + FieldListField( + "service_record_handle_list", [], IntField("", 0), + count_from=lambda pkt: pkt.current_service_record_count), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +class SDP_Service_Attr_Request(Packet): + name = "SDP Service ATTR REQ PDU" + fields_desc = [ + IntField("service_record_handle", 0x0000), + # Range: 0x0007 to 0xFFFF + ShortField("max_attribute_byte_count", 0x0000), + PacketField("attribute_id_list", None, SDP_DataElement), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +class SDP_Service_Attr_Response(Packet): + name = "SDP Service ATTR RSP PDU" + fields_desc = [ + FieldLenField("attribute_list_byte_count", None, fmt="H", + length_of="attribute_list"), + PacketListField( + "attribute_list", [], SDP_DataElement, + length_from=lambda pkt: pkt.attribute_list_byte_count), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +class SDP_Service_Search_Attr_Request(Packet): + name = "SDP Service Search ATTR REQ PDU" + fields_desc = [ + PacketField("service_search_pattern", None, SDP_DataElement), + # Range: 0x0007 to 0xFFFF + ShortField("max_attribute_byte_count", 0x0000), + PacketField("attribute_id_list", None, SDP_DataElement), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +class SDP_Service_Search_Attr_Response(Packet): + name = "SDP Service Search ATTR RSP PDU" + fields_desc = [ + FieldLenField("attribute_lists_byte_count", None, fmt="H", + length_of="attribute_lists"), + PacketListField( + "attribute_lists", [], SDP_DataElement, + length_from=lambda pkt: pkt.attribute_lists_byte_count), + PacketField("continuation_state", None, SDP_Continuation), + ] + + +SDP_PDU_CLASSES = { + 1: SDP_Error_Response, + 2: SDP_Service_Search_Request, + 3: SDP_Service_Search_Response, + 4: SDP_Service_Attr_Request, + 5: SDP_Service_Attr_Response, + 6: SDP_Service_Search_Attr_Request, + 7: SDP_Service_Search_Attr_Response, +} + + +class SDP_Hdr(Packet): + name = "SDP Protocol Data Unit Format" + fields_desc = [ + ByteEnumField("pdu_id", 1, { + 1: "SDP_ERROR_RSP", + 2: "SDP_SERVICE_SEARCH_REQ", + 3: "SDP_SERVICE_SEARCH_RSP", + 4: "SDP_SERVICE_ATTR_REQ", + 5: "SDP_SERVICE_ATTR_RSP", + 6: "SDP_SERVICE_SEARCH_ATTR_REQ", + 7: "SDP_SERVICE_SEARCH_ATTR_RSP", + # All other values are reserved for future use + }), + ShortField("transaction_id", 0), + FieldLenField("parameter_length", 0, fmt="H", length_of="parameters"), + PacketListField( + "parameters", [], + length_from=lambda pkt: pkt.parameter_length, + next_cls_cb=lambda pkt, _, __, ___: SDP_PDU_CLASSES[pkt.pdu_id]), + ] + + def post_build(self, p, pay): + size = len(p[5:]) + + p = p[:3] + struct.pack(">H", size) + p[5:] + + return p + pay + + class ATT_Handle_Length_Value_Tuple(Packet): fields_desc = [XLEShortField("handle", 0), LEFieldLenField("len", None, length_of="value"), @@ -2036,12 +2331,24 @@ class HCI_Cmd_Remote_OOB_Data_Request_Negative_Reply(Packet): # 7.2 Link Policy commands, the OGF is defined as 0x02 class HCI_Cmd_Hold_Mode(Packet): + """ + 7.2.1 Hold Mode command + """ 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_Switch_Role(Packet): + """ + 7.2.8 Switch Role command + """ + name = "HCI_Switch_Role" + fields_desc = [LEMACField("bd_addr", None), + ByteField("role", 0x00), ] + + # 7.3 CONTROLLER & BASEBAND COMMANDS, the OGF is defined as 0x03 class HCI_Cmd_Set_Event_Mask(Packet): @@ -2087,6 +2394,22 @@ class HCI_Cmd_Write_Connect_Accept_Timeout(Packet): fields_desc = [LEShortField("timeout", 32000)] # 32000 slots is 20000 msec +class HCI_Cmd_Read_Simple_Pairing_Mode(Packet): + """ + 7.3.58 Read Simple Pairing Mode command + """ + name = "HCI_Read_Simple_Pairing_Mode_command" + fields_desc = [] + + +class HCI_Cmd_Write_Simple_Pairing_Mode(Packet): + """ + 7.3.59 Write Simple Paring Mode + """ + name = "HCI_Write_Simple_Pairing_Mode" + fields_desc = [ByteField("status", 0x00)] + + class HCI_Cmd_Write_Extended_Inquiry_Response(Packet): name = "HCI_Write_Extended_Inquiry_Response" fields_desc = [ByteField("fec_required", 0), @@ -2599,6 +2922,17 @@ class HCI_Event_Disconnection_Complete(Packet): XByteField("reason", 0), ] +class HCI_Event_Authentication_Complete(Packet): + """ + 7.7.6 Authentication Complete event + """ + name = "HCI_Authientication_Complete" + fields_desc = [ + ByteField("status", 0x00), + ShortField("connection_handle", 0x0000), + ] + + class HCI_Event_Remote_Name_Request_Complete(Packet): """ 7.7.7 Remote Name Request Complete event @@ -2691,6 +3025,16 @@ def answers(self, other): return other[HCI_Command_Hdr].opcode == self.opcode +class HCI_Event_Role_Change(Packet): + """ + 7.7.18 Role Change event + """ + name = "HCI_Role_Change_event" + fields_desc = [ByteField("status", 0x00), + LEMACField("bd_addr", None), + ByteField("new_role", 0x00)] + + class HCI_Event_Number_Of_Completed_Packets(Packet): """ 7.7.19 Number Of Completed Packets event @@ -3171,6 +3515,7 @@ class HCI_LE_Meta_Extended_Advertising_Reports(Packet): # 7.2 Link Policy commands, the OGF is defined as 0x02 bind_layers(HCI_Command_Hdr, HCI_Cmd_Hold_Mode, ogf=0x02, ocf=0x0001) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Switch_Role, ogf=0x02, ocf=0x000B) # 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) @@ -3180,6 +3525,8 @@ class HCI_LE_Meta_Extended_Advertising_Reports(Packet): bind_layers(HCI_Command_Hdr, HCI_Cmd_Read_Local_Name, ogf=0x03, ocf=0x0014) 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_Read_Simple_Pairing_Mode, ogf=0x03, ocf=0x0055) +bind_layers(HCI_Command_Hdr, HCI_Cmd_Write_Simple_Pairing_Mode, ogf=0x03, ocf=0x0056) 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) @@ -3235,12 +3582,14 @@ class HCI_LE_Meta_Extended_Advertising_Reports(Packet): bind_layers(HCI_Event_Hdr, HCI_Event_Connection_Complete, code=0x03) bind_layers(HCI_Event_Hdr, HCI_Event_Connection_Request, code=0x04) bind_layers(HCI_Event_Hdr, HCI_Event_Disconnection_Complete, code=0x05) +bind_layers(HCI_Event_Hdr, HCI_Event_Authentication_Complete, code=0x06) bind_layers(HCI_Event_Hdr, HCI_Event_Remote_Name_Request_Complete, code=0x07) bind_layers(HCI_Event_Hdr, HCI_Event_Encryption_Change, code=0x08) bind_layers(HCI_Event_Hdr, HCI_Event_Read_Remote_Supported_Features_Complete, code=0x0b) bind_layers(HCI_Event_Hdr, HCI_Event_Read_Remote_Version_Information_Complete, code=0x0c) # noqa: E501 bind_layers(HCI_Event_Hdr, HCI_Event_Command_Complete, code=0x0e) bind_layers(HCI_Event_Hdr, HCI_Event_Command_Status, code=0x0f) +bind_layers(HCI_Event_Hdr, HCI_Event_Role_Change, code=0x12) bind_layers(HCI_Event_Hdr, HCI_Event_Number_Of_Completed_Packets, code=0x13) bind_layers(HCI_Event_Hdr, HCI_Event_Link_Key_Request, code=0x17) bind_layers(HCI_Event_Hdr, HCI_Event_Inquiry_Result_With_Rssi, code=0x22) @@ -3327,6 +3676,8 @@ class HCI_LE_Meta_Extended_Advertising_Reports(Packet): bind_layers(L2CAP_CmdHdr, L2CAP_Credit_Based_Connection_Response, code=24) bind_layers(L2CAP_CmdHdr, L2CAP_Credit_Based_Reconfigure_Request, code=25) bind_layers(L2CAP_CmdHdr, L2CAP_Credit_Based_Reconfigure_Response, code=26) +bind_layers(L2CAP_ConfReq, L2CAP_ConfSet) +bind_layers(L2CAP_ConfResp, L2CAP_ConfSet) bind_layers(L2CAP_Hdr, ATT_Hdr, cid=4) bind_layers(ATT_Hdr, ATT_Error_Response, opcode=0x1) bind_layers(ATT_Hdr, ATT_Exchange_MTU_Request, opcode=0x2) diff --git a/test/scapy/layers/bluetooth.uts b/test/scapy/layers/bluetooth.uts index e5e6de4d0ed..67fe637e273 100644 --- a/test/scapy/layers/bluetooth.uts +++ b/test/scapy/layers/bluetooth.uts @@ -81,6 +81,18 @@ assert hci_cmd_hold_mode.ogf == 0x02 assert hci_cmd_hold_mode.ocf == 0x01 assert hci_cmd_hold_mode.len == 6 +# HCI_Cmd_Switch_Role +hci_cmd_swith_role = HCI_Command_Hdr() / HCI_Cmd_Switch_Role() +assert hci_cmd_swith_role.ogf == 0x02 +assert hci_cmd_swith_role.ocf == 0x0B +assert hci_cmd_swith_role.len == None + +# parsing +hci_cmd_swith_role = HCI_Command_Hdr(raw(hci_cmd_swith_role)) +assert hci_cmd_swith_role.ogf == 0x02 +assert hci_cmd_swith_role.ocf == 0x0B +assert hci_cmd_swith_role.len == 7 + # 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 @@ -105,6 +117,30 @@ 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_Simple_Pairing_Mode +hci_cmd_read_simple_pairing_mode = HCI_Command_Hdr() / HCI_Cmd_Read_Simple_Pairing_Mode() +assert hci_cmd_read_simple_pairing_mode.ogf == 0x03 +assert hci_cmd_read_simple_pairing_mode.ocf == 0x55 +assert hci_cmd_read_simple_pairing_mode.len == None + +# parsing +hci_cmd_read_simple_pairing_mode = HCI_Command_Hdr(raw(hci_cmd_read_simple_pairing_mode)) +assert hci_cmd_read_simple_pairing_mode.ogf == 0x03 +assert hci_cmd_read_simple_pairing_mode.ocf == 0x55 +assert hci_cmd_read_simple_pairing_mode.len == 0 + +# HCI_Cmd_Write_Simple_Pairing_Mode +hci_cmd_write_simple_pairing_mode = HCI_Command_Hdr() / HCI_Cmd_Write_Simple_Pairing_Mode() +assert hci_cmd_write_simple_pairing_mode.ogf == 0x03 +assert hci_cmd_write_simple_pairing_mode.ocf == 0x56 +assert hci_cmd_write_simple_pairing_mode.len == None + +# parsing +hci_cmd_write_simple_pairing_mode = HCI_Command_Hdr(raw(hci_cmd_write_simple_pairing_mode)) +hci_cmd_write_simple_pairing_mode.show() +assert hci_cmd_write_simple_pairing_mode.ogf == 0x03 +assert hci_cmd_write_simple_pairing_mode.ocf == 0x56 +assert hci_cmd_write_simple_pairing_mode.len == 1 # HCI_Cmd_Read_Link_Quality hci_cmd_read_link_quality = HCI_Command_Hdr() / HCI_Cmd_Read_Link_Quality() @@ -144,6 +180,26 @@ 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 +# HCI_Event_Authentication_Complete +hci_event_authentication_complete = HCI_Event_Hdr() / HCI_Event_Authentication_Complete() +assert hci_event_authentication_complete.code == 0x06 +assert hci_event_authentication_complete.len == None + +# parsing +hci_event_authentication_complete = HCI_Event_Hdr(raw(hci_event_authentication_complete)) +assert hci_event_authentication_complete.code == 0x06 +assert hci_event_authentication_complete.len == 0x03 + +# HCI_Event_Role_Change +hci_event_role_change = HCI_Event_Hdr() / HCI_Event_Role_Change() +assert hci_event_role_change.code == 0x12 +assert hci_event_role_change.len == None + +# parsing +hci_event_role_change = HCI_Event_Hdr(raw(hci_event_role_change)) +assert hci_event_role_change.code == 0x12 +assert hci_event_role_change.len == 0x08 + + Bluetooth Transport Layers = Test HCI_PHDR_Hdr piling up @@ -239,7 +295,7 @@ assert response[HCI_Cmd_Complete_Read_Local_Extended_Features].max_page == 2 assert response[HCI_Cmd_Complete_Read_Local_Extended_Features].extended_features == 0 assert response.answers(cmd) -= LE Set Extended Scan Parameters += LE Set Extended Scan parameters cmd = HCI_Hdr(hex_bytes("0141200d00010500600060000020012001")) assert HCI_Command_Hdr in cmd @@ -941,7 +997,7 @@ else: = Parse EIR_ServiceSolicitation16BitUUID and EIR_ServiceSolicitation128BitUUID -d = hex_bytes("043e29020100013d1ef10747d81d0319000002010603140d181115d0002d121e4b0fa4994eceb531f40579aa") +d = hex_bytes("043e29020100013d1ef10747d81d0319000002010603140d181115d0002d121e4b0fa4994eceb531f40579aa") p = HCI_Hdr(d) assert p[EIR_ServiceSolicitation16BitUUID].svc_uuid == 0x180d assert p[EIR_ServiceSolicitation128BitUUID].svc_uuid == UUID('7905f431-b5ce-4e99-a40f-4b1e122d00d0') @@ -1026,6 +1082,18 @@ assert b[HCI_LE_Meta_Advertising_Report].addr == "a1:b2:c3:d4:e5:f6" assert a.summary() == "HCI Event / HCI_Event_Hdr / HCI_Event_LE_Meta / HCI_LE_Meta_Advertising_Reports" += L2CAP - ConfSet MTU +p = HCI_Hdr()/HCI_ACL_Hdr()/L2CAP_Hdr()/L2CAP_CmdHdr()/L2CAP_ConfSet(type="mtu")/L2CAP_ConfSet_MTU(mtu=512) +assert bytes(p) == b'\x02\x00\x00\x0c\x00\x08\x00\x05\x00\x08\x01\x04\x00\x01\x02\x00\x02' + += L2CAP - ConfSet Flush TimeOut +p = HCI_Hdr()/HCI_ACL_Hdr()/L2CAP_Hdr()/L2CAP_CmdHdr()/L2CAP_ConfSet(type="flushtimeout")/L2CAP_ConfSet_FlushTimeOut(flushtimeout=1337) +assert bytes(p) == b'\x02\x00\x00\x0c\x00\x08\x00\x05\x00\x08\x01\x04\x00\x02\x029\x05' + += L2CAP - ConfSet QoS +p = HCI_Hdr()/HCI_ACL_Hdr()/L2CAP_Hdr()/L2CAP_CmdHdr()/L2CAP_ConfSet(type="QoS")/L2CAP_ConfSet_QoS() +assert bytes(p) == b'\x02\x00\x00 \x00\x1c\x00\x05\x00\x08\x01\x18\x00\x03\x16\x00\x010\x00\x00\x000\x00\x00\x000\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff' + = EIR_Hdr - HCI_LE_Meta_Advertising_Report (duplicate reports) # When duplicate reports are allowed, there are "Connectable Unidirected # Advertising" reports, and "Scan Responses", for the same device/MAC, in the @@ -1265,6 +1333,577 @@ pkt = HCI_Hdr(hex_bytes('0200260600020006000e02')) assert SM_Keypress_Notification in pkt assert pkt[SM_Keypress_Notification].notification_type == 0x02 +### +# SDP tests +### + += SDP commands + +constate = SDP_Continuation(count=2, continuation_state_info=0xCAFE) +attributes = SDP_DataElement(data_type=6, size_index=5, + data=[SDP_DataElement(data_type=1,size_index=2,data=0x0000_ffff)]) +search_pattern = SDP_DataElement(data_type=6, size_index=5, + data=[SDP_DataElement(data_type=3,size_index=1,data=b'\x10\x00')]) +parameters = ( + SDP_Service_Search_Attr_Request(service_search_pattern=search_pattern, + max_attribute_byte_count=0x1234, + attribute_id_list=attributes, + continuation_state=constate + ) +) + +pkt = (HCI_Hdr() / HCI_ACL_Hdr() / L2CAP_Hdr() / SDP_Hdr(pdu_id=6, transaction_id=0xFADE, parameters=parameters) ) + +assert raw(pkt[SDP_Hdr]) == hex_bytes("06fade00113503191000123435050a0000ffff02cafe") + +pkt = SDP_Hdr(raw(pkt[SDP_Hdr])) +req = pkt.parameters[0] +assert pkt.pdu_id == 6 +assert pkt.transaction_id == 0xFADE +assert pkt.parameter_length == 0x11 +assert isinstance(req, SDP_Service_Search_Attr_Request) +assert req.service_search_pattern.data_type == 6 +assert req.service_search_pattern.size_index == 5 +assert req.service_search_pattern.size == 3 +assert req.service_search_pattern.data[0].data_type == 3 +assert req.service_search_pattern.data[0].size_index == 1 +assert req.service_search_pattern.data[0].data == b'\x10\x00' +assert req.max_attribute_byte_count == 0x1234 +assert req.attribute_id_list.data_type == 6 +assert req.attribute_id_list.size_index == 5 +assert req.attribute_id_list.size == 5 +assert req.attribute_id_list.data[0].data_type == 1 +assert req.attribute_id_list.data[0].size_index == 2 +assert req.attribute_id_list.data[0].data == 0x0000_ffff +assert req.continuation_state.count == 2 +assert req.continuation_state.continuation_state_info == 0xCAFE + += SDP response + +pkt = SDP_Hdr(hex_bytes('070000019901963700000191370000002b0900000a000000000900000a0000000009000135031900010900053503191002090200350609010309010437000000690900000a00010000090001350619110e19110f0900020a0000440e09000435103506190100090017350619001709010409000535031910020900093508350619110e090106090100250e416476616e63656420417564696f09010225064d745669657709031109000337000000570900000a00010001090001350319110c09000435103506190100090017350619001709010409000535031910020900093508350619110e09010609000d35123510350619010009001b350619001709010409031109000237000000400900000a00010002090001350319110b09000435103506190100090019350619001909010309000535031910020900093508350619110d090103090311090003370000004d0900000a00010003090001350619111e191203090004350c3503190100350519000308130900053503191002090006350909656e09006a0901000900093508350619111e09010709031109003f00')) + +assert pkt[SDP_Hdr].pdu_id == 7 +assert pkt[SDP_Hdr].transaction_id == 0 +assert pkt[SDP_Hdr].parameter_length == 409 +assert pkt[SDP_Hdr].parameters[0].attribute_lists_byte_count == 406 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].size == 401 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].size == 43 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[0].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[1].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[1].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[2].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[3].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[3].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[3].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[4].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[4].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[4].data == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[5].data[0].data == b"\x00\x01" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[6].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[6].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[6].data == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[7].data[0].data == b"\x10\x02" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[8].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[8].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[8].data == 512 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[0].data == 259 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[0].data[9].data[1].data == 260 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].size == 105 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[0].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[1].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[1].data == 65536 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[2].data == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[0].data == b"\x11\x0e" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[1].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[3].data[1].data == b"\x11\x0f" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[4].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[4].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[4].data == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[5].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[5].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[5].data == 17422 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[6].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[6].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[6].data == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].size == 16 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[0].data == b"\x01\x00" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[0].data[1].data == 23 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[0].data == b"\x00\x17" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[7].data[1].data[1].data == 260 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[8].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[8].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[8].data == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[9].data[0].data == b"\x10\x02" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[10].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[10].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[10].data == 9 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].size == 8 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[0].data == b"\x11\x0e" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[11].data[0].data[1].data == 262 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[12].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[12].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[12].data == 256 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[13].data_type == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[13].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[13].size == 14 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[13].data == b'Advanced Audio' +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[14].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[14].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[14].data == 258 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[15].data_type == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[15].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[15].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[15].data == b'MtView' +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[16].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[16].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[16].data == 785 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[17].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[17].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[1].data[17].data == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].size == 87 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[0].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[1].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[1].data == 65537 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[2].data == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[3].data[0].data == b"\x11\x0c" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[4].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[4].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[4].data == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].size == 16 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[0].data == b"\x01\x00" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[0].data[1].data == 23 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[0].data == b"\x00\x17" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[5].data[1].data[1].data == 260 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[6].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[6].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[6].data == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[7].data[0].data == b"\x10\x02" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[8].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[8].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[8].data == 9 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].size == 8 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0] +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[0].data == b"\x11\x0e" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[9].data[0].data[1].data == 262 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[10].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[10].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[10].data == 13 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].size == 18 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].size == 16 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[0].data == b"\x01\x00" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[0].data[1].data == 27 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[0].data == b"\x00\x17" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[11].data[0].data[1].data[1].data == 260 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[12].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[12].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[12].data == 785 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[13].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[13].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[2].data[13].data == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].size == 64 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[0].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[1].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[1].data == 65538 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[2].data == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[3].data[0].data == b"\x11\x0b" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[4].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[4].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[4].data == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].size == 16 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[0].data == b"\x01\x00" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[0].data[1].data == 25 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[0].data == b"\x00\x19" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[5].data[1].data[1].data == 259 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[6].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[6].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[6].data == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[7].data[0].data == b"\x10\x02" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[8].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[8].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[8].data == 9 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].size == 8 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[0].data == b"\x11\x0d" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[9].data[0].data[1].data == 259 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[10].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[10].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[10].data == 785 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[11].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[11].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[3].data[11].data == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].size_index == 7 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].size == 77 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[0].data == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[1].size_index == 2 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[1].data == 65539 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[2].data == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[0].data == b"\x11\x1e" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[1].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[3].data[1].data == b"\x12\x03" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[4].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[4].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[4].data == 4 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].size == 12 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[0].data[0].data == b"\x01\x00" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].size == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[0].data == b"\x00\x03" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[1].size_index == 0 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[5].data[1].data[1].data == 19 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[6].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[6].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[6].data == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].size == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[7].data[0].data == b"\x10\x02" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[8].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[8].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[8].data == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].size == 9 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[0].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[0].data == 25966 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[1].data == 106 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[2].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[2].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[9].data[2].data == 256 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[10].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[10].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[10].data == 9 + +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].size == 8 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data_type == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].size_index == 5 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].size == 6 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[0].data_type == 3 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[0].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[0].data == b"\x11\x1e" +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[1].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[1].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[11].data[0].data[1].data == 263 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[12].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[12].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[12].data == 785 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[13].data_type == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[13].size_index == 1 +assert pkt[SDP_Hdr].parameters[0].attribute_lists[0].data[4].data[13].data == 63 +assert pkt[SDP_Hdr].parameters[0].continuation_state.count == 0 + += SDP_DataElement - null, boolean, integers and UUIDs + +e = SDP_DataElement(data_type=0, size_index=0) +assert raw(e) == b"\x00" +e = SDP_DataElement(raw(e)) +assert e.data_type == 0 and e.get_data_size() == 0 + +e = SDP_DataElement(data_type=5, size_index=0, data=1) +assert raw(e) == hex_bytes("2801") +assert SDP_DataElement(raw(e)).data == 1 + +e = SDP_DataElement(data_type=2, size_index=1, data=0xfffe) +assert raw(e) == hex_bytes("11fffe") +e = SDP_DataElement(raw(e)) +assert e.data_type == 2 and e.data == 0xfffe + +e = SDP_DataElement(data_type=3, size_index=4, data=b"\x00" * 15 + b"\x01") +assert raw(e) == hex_bytes("1c" + "00" * 15 + "01") +assert SDP_DataElement(raw(e)).data == b"\x00" * 15 + b"\x01" + += SDP_DataElement - text string and URL with 1, 2 and 4 bytes size fields + +for data_type, header in ((4, 0x20), (8, 0x40)): + for size_index, size_bytes in ((5, "03"), (6, "0003"), (7, "00000003")): + e = SDP_DataElement(data_type=data_type, size_index=size_index, data=b"abc") + expected = "%02x%s616263" % (header | size_index, size_bytes) + assert raw(e) == hex_bytes(expected) + e = SDP_DataElement(raw(e)) + assert e.size == 3 + assert e.data == b"abc" + += SDP_DataElement - sequence with a 2 bytes size field + +e = SDP_DataElement(data_type=6, size_index=6, + data=[SDP_DataElement(data_type=1, size_index=1, data=1)]) +assert raw(e) == hex_bytes("3600030900" "01") +e = SDP_DataElement(raw(e)) +assert e.size == 3 +assert e.data[0].data == 1 + += SDP error response + +pkt = SDP_Hdr(pdu_id=1, transaction_id=1, parameters=[SDP_Error_Response(error_code=3)]) +assert raw(pkt) == hex_bytes("0100010002" "0003") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Error_Response) +assert pkt.parameters[0].error_code == 3 + += SDP_Service_Search_Request / SDP_Service_Search_Response + +pattern = SDP_DataElement(data_type=6, size_index=5, + data=[SDP_DataElement(data_type=3, size_index=1, data=b'\x01\x00')]) +pkt = SDP_Hdr(pdu_id=2, transaction_id=1, parameters=[ + SDP_Service_Search_Request(service_search_pattern=pattern, + max_service_record_count=3, + continuation_state=SDP_Continuation()) +]) +assert raw(pkt) == hex_bytes("02000100083503190100000300") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Service_Search_Request) +assert pkt.parameters[0].service_search_pattern.data[0].data == b'\x01\x00' +assert pkt.parameters[0].max_service_record_count == 3 + +pkt = SDP_Hdr(pdu_id=3, parameters=[ + SDP_Service_Search_Response(total_service_record_count=2, + service_record_handle_list=[0x10001, 0x10002], + continuation_state=SDP_Continuation()) +]) +assert raw(pkt) == hex_bytes("030000000d00020002000100010001000200") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Service_Search_Response) +assert pkt.parameters[0].current_service_record_count == 2 +assert pkt.parameters[0].service_record_handle_list == [0x10001, 0x10002] + += SDP_Service_Attr_Request / SDP_Service_Attr_Response + +attr_list = SDP_DataElement(data_type=6, size_index=5, + data=[SDP_DataElement(data_type=1, size_index=1, data=0x0001)]) +pkt = SDP_Hdr(pdu_id=4, parameters=[ + SDP_Service_Attr_Request(service_record_handle=0x10000, + max_attribute_byte_count=0x100, + attribute_id_list=attr_list, + continuation_state=SDP_Continuation()) +]) +assert raw(pkt) == hex_bytes("040000000c000100000100350309000100") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Service_Attr_Request) +assert pkt.parameters[0].service_record_handle == 0x10000 +assert pkt.parameters[0].attribute_id_list.data[0].data == 1 + +pkt = SDP_Hdr(pdu_id=5, parameters=[ + SDP_Service_Attr_Response(attribute_list=[attr_list], + continuation_state=SDP_Continuation()) +]) +assert raw(pkt) == hex_bytes("05000000080005350309000100") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Service_Attr_Response) +assert pkt.parameters[0].attribute_list_byte_count == 5 +assert pkt.parameters[0].attribute_list[0].data[0].data == 1 + += SDP_Service_Search_Attr_Response build + +pkt = SDP_Hdr(pdu_id=7, parameters=[ + SDP_Service_Search_Attr_Response(attribute_lists=[attr_list], + continuation_state=SDP_Continuation()) +]) +assert raw(pkt) == hex_bytes("07000000080005350309000100") +pkt = SDP_Hdr(raw(pkt)) +assert isinstance(pkt.parameters[0], SDP_Service_Search_Attr_Response) +assert pkt.parameters[0].attribute_lists_byte_count == 5 + +# pkt.show() + + HCIMon tests