class ZCLReadAttributeStatusRecord(Packet): name = "ZCL Read Attribute Status Record" fields_desc = [ # Attribute Identifier XLEShortField("attribute_identifier", 0), # Status ByteEnumField("status", 0, _zcl_enumerated_status_values), # Attribute data type (0/1 octet), and data (0/variable size) # are only included if status == 0x00 (SUCCESS) ConditionalField( ByteEnumField("attribute_data_type", 0, _zcl_attribute_data_types), lambda pkt: pkt.status == 0x00), ConditionalField(_DiscreteString("attribute_value", ""), lambda pkt: pkt.status == 0x00), ] def extract_padding(self, s): return "", s
class Dot15d4Beacon(Packet): name = "802.15.4 Beacon" fields_desc = [ # Superframe spec field: BitField("sf_sforder", 15, 4), # not used by ZigBee BitField("sf_beaconorder", 15, 4), # not used by ZigBee BitEnumField("sf_assocpermit", 0, 1, [False, True]), BitEnumField("sf_pancoord", 0, 1, [False, True]), BitField("sf_reserved", 0, 1), # not used by ZigBee BitEnumField("sf_battlifeextend", 0, 1, [False, True]), # not used by ZigBee # noqa: E501 BitField("sf_finalcapslot", 15, 4), # not used by ZigBee # GTS Fields # GTS Specification (1 byte) BitEnumField("gts_spec_permit", 1, 1, [False, True]), # GTS spec bit 7, true=1 iff PAN cord is accepting GTS requests # noqa: E501 BitField("gts_spec_reserved", 0, 4), # GTS spec bits 3-6 BitField("gts_spec_desccount", 0, 3), # GTS spec bits 0-2 # GTS Directions (0 or 1 byte) ConditionalField(BitField("gts_dir_reserved", 0, 1), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 ConditionalField(BitField("gts_dir_mask", 0, 7), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 # GTS List (variable size) # TODO add a Packet/FieldListField tied to 3bytes per count in gts_spec_desccount # noqa: E501 # Pending Address Fields: # Pending Address Specification (1 byte) BitField("pa_reserved_1", 0, 1), BitField("pa_num_long", 0, 3), # number of long addresses pending BitField("pa_reserved_2", 0, 1), BitField("pa_num_short", 0, 3), # number of short addresses pending # Address List (var length) FieldListField("pa_short_addresses", [], XLEShortField("", 0x0000), count_from=lambda pkt: pkt.pa_num_short), FieldListField("pa_long_addresses", [], LEEUI64Field("", 0), count_from=lambda pkt: pkt.pa_num_long), # TODO beacon payload ] def mysummary(self): return self.sprintf( "802.15.4 Beacon " "( %Dot15d4Beacon.src_panid%:%Dot15d4Beacon.src_addr% " "assocPermit %Dot15d4Beacon.sf_assocpermit% " "panCoord %Dot15d4Beacon.sf_pancoord%)")
class ZCLReadAttributeStatusRecord(Packet): name = "ZCL Read Attribute Status Record" fields_desc = [ # Attribute Identifier XLEShortField("attribute_identifier", 0), # Status ByteEnumField("status", 0, _zcl_enumerated_status_values), # Attribute data type (0/1 octet), only included if status == 0x00 (SUCCESS) # noqa: E501 ConditionalField( ByteEnumField("attribute_data_type", 0, _zcl_attribute_data_types), lambda pkt: pkt.status == 0x00), # Attribute data (0/variable in size), only included if status == 0x00 (SUCCESS) # noqa: E501 ConditionalField( StrLenField("attribute_value", "", length_from=lambda pkt: util_zcl_attribute_value_len( pkt)), # noqa: E501 lambda pkt: pkt.status == 0x00), ]
class Dot15d4Beacon(Packet): name = "802.15.4 Beacon" fields_desc = [ XLEShortField("src_panid", 0x0), dot15d4AddressField("src_addr", None, length_of="fcf_srcaddrmode"), # Security field present if fcf_security == True ConditionalField(PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), # noqa: E501 lambda pkt:pkt.underlayer.getfieldval("fcf_security") is True), # noqa: E501 # Superframe spec field: BitField("sf_sforder", 15, 4), # not used by ZigBee BitField("sf_beaconorder", 15, 4), # not used by ZigBee BitEnumField("sf_assocpermit", 0, 1, [False, True]), BitEnumField("sf_pancoord", 0, 1, [False, True]), BitField("sf_reserved", 0, 1), # not used by ZigBee BitEnumField("sf_battlifeextend", 0, 1, [False, True]), # not used by ZigBee # noqa: E501 BitField("sf_finalcapslot", 15, 4), # not used by ZigBee # GTS Fields # GTS Specification (1 byte) BitEnumField("gts_spec_permit", 1, 1, [False, True]), # GTS spec bit 7, true=1 iff PAN cord is accepting GTS requests # noqa: E501 BitField("gts_spec_reserved", 0, 4), # GTS spec bits 3-6 BitField("gts_spec_desccount", 0, 3), # GTS spec bits 0-2 # GTS Directions (0 or 1 byte) ConditionalField(BitField("gts_dir_reserved", 0, 1), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 ConditionalField(BitField("gts_dir_mask", 0, 7), lambda pkt:pkt.getfieldval("gts_spec_desccount") != 0), # noqa: E501 # GTS List (variable size) # TODO add a Packet/FieldListField tied to 3bytes per count in gts_spec_desccount # noqa: E501 # Pending Address Fields: # Pending Address Specification (1 byte) BitField("pa_num_short", 0, 3), # number of short addresses pending BitField("pa_reserved_1", 0, 1), BitField("pa_num_long", 0, 3), # number of long addresses pending BitField("pa_reserved_2", 0, 1), # Address List (var length) # TODO add a FieldListField of the pending short addresses, followed by the pending long addresses, with max 7 addresses # noqa: E501 # TODO beacon payload ] def mysummary(self): return self.sprintf("802.15.4 Beacon ( %Dot15d4Beacon.src_panid%:%Dot15d4Beacon.src_addr% ) assocPermit(%Dot15d4Beacon.sf_assocpermit%) panCoord(%Dot15d4Beacon.sf_pancoord%)") # noqa: E501
class Dot15d4FCS(Dot15d4): ''' This class is a drop-in replacement for the Dot15d4 class above, except it expects a FCS/checksum in the input, and produces one in the output. This provides the user flexibility, as many 802.15.4 interfaces will have an AUTO_CRC setting # noqa: E501 that will validate the FCS/CRC in firmware, and add it automatically when transmitting. # noqa: E501 ''' name = "802.15.4 - FCS" match_subclass = True fields_desc = Dot15d4.fields_desc + [ XLEShortField("fcs", None) ] # Automatically moved to the end of the packet # noqa: E501 def compute_fcs(self, data): # Do a CRC-CCITT Kermit 16bit on the data given # Returns a CRC that is the FCS for the frame # Implemented using pseudocode from: June 1986, Kermit Protocol Manual # See also: # http://regregex.bbcmicro.net/crc-catalogue.htm#crc.cat.kermit crc = 0 for i in range(0, len(data)): c = orb(data[i]) q = (crc ^ c) & 15 # Do low-order 4 bits crc = (crc // 16) ^ (q * 4225) q = (crc ^ (c // 16)) & 15 # And high 4 bits crc = (crc // 16) ^ (q * 4225) return struct.pack('<H', crc) # return as bytes in little endian order def pre_dissect(self, s): # Get the frame check sequence return s[:3] + s[-2:] + s[3:-2] def post_dissect(self, s): self.raw_packet_cache = None # Reset packet to allow post_build return s def post_build(self, p, pay): # construct the packet with the FCS at the end return Dot15d4.post_build(self, p[:-2], pay) + ( p[-2:] if self.fcs is not None else self.compute_fcs(p[:-2] + pay) ) # noqa: E501
class ZigbeeAppDataPayloadStub(Packet): name = "Zigbee Application Layer Data Payload for Inter-PAN Transmission" fields_desc = [ FlagsField("frame_control", 0, 4, ['reserved1', 'security', 'ack_req', 'extended_hdr']), # noqa: E501 BitEnumField("delivery_mode", 0, 2, {0: 'unicast', 2: 'broadcast', 3: 'group'}), # noqa: E501 BitField("frametype", 3, 2), # value 0b11 (3) is a reserved frame type # Group Address present only when delivery mode field has a value of 0b11 (group delivery mode) # noqa: E501 ConditionalField( XLEShortField("group_addr", 0x0), # 16-bit identifier of the group lambda pkt: pkt.getfieldval("delivery_mode") == 0b11 ), # Cluster identifier EnumField("cluster", 0, _zcl_cluster_identifier, fmt="<H"), # unsigned short (little-endian) # noqa: E501 # Profile identifier EnumField("profile", 0, _zcl_profile_identifier, fmt="<H"), # ZigBee Payload ConditionalField( StrField("data", ""), lambda pkt: pkt.frametype == 3 ), ]
class Dot15d4CmdAssocResp(Packet): ASSOCIATION_STATUS = { 0x00: 'successful', 0x01: 'PAN_at_capacity', 0x02: 'PAN_access_denied' # 0x03 - 0x7f == Reserved # 0x80 - 0xff == Reserved for MAC primitive enumeration values } name = "802.15.4 Association Response Command" fields_desc = [ # Address assigned to device from coordinator (0xFFFF == none) XLEShortField("short_address", 0xFFFF), ByteEnumField("association_status", 0x00, ASSOCIATION_STATUS), ] def mysummary(self): return self.sprintf( "802.15.4 Association Response Command" "( Association Status: %Dot15d4CmdAssocResp.association_status% " "Assigned Address: %Dot15d4CmdAssocResp.short_address% )")
class SMB2_Negociate_Protocol_Request_Header(Packet): name = "SMB2 Negociate Protocol Request Header" fields_desc = [ XLEShortField("StructureSize", 0), FieldLenField( "DialectCount", 0, fmt="<H", count_of="Dialects" ), # SecurityMode FlagsField("SecurityMode", 0, 16, { 0x7: "Signing Required", 0x8: "Signing Enabled", }), LEShortField("Reserved", 0), # Capabilities FlagsField("Capabilities", 0, 32, SMB2_CAPABILITIES), UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE), XLEIntField("NegociateContextOffset", 0x0), FieldLenField( "NegociateCount", 0x0, fmt="<H", count_of="NegociateContexts" ), ShortField("Reserved2", 0), # Padding the dialects - the whole packet (from the # beginning) should be aligned on 8 bytes ; so the list of # dialects should be aligned on 6 bytes (because it starts # at PKT + 8 * N + 2 PadField(FieldListField( "Dialects", [0x0202], LEShortEnumField("", 0x0, SMB_DIALECTS), count_from=lambda pkt: pkt.DialectCount ), 6), PacketListField( "NegociateContexts", [], SMB2_Negociate_Context, count_from=lambda pkt: pkt.NegociateCount ), ]
class ZigbeeClusterLibrary(Packet): name = "Zigbee Cluster Library (ZCL) Frame" fields_desc = [ # Frame control (8 bits) BitField("reserved", 0, 3), BitField("disable_default_response", 0, 1), # 0 default response command will be returned # noqa: E501 BitField("direction", 0, 1), # 0 command sent from client to server; 1 command sent from server to client # noqa: E501 BitField("manufacturer_specific", 0, 1), # 0 manufacturer code shall not be included in the ZCL frame # noqa: E501 # Frame Type # 0b00 command acts across the entire profile # 0b01 command is specific to a cluster # 0b10 - 0b11 reserved BitEnumField("zcl_frametype", 0, 2, {0: 'profile-wide', 1: 'cluster-specific', 2: 'reserved2', 3: 'reserved3'}), # noqa: E501 # Manufacturer code (0/16 bits) only present then manufacturer_specific field is set to 1 # noqa: E501 ConditionalField(XLEShortField("manufacturer_code", 0x0), lambda pkt: pkt.getfieldval("manufacturer_specific") == 1 # noqa: E501 ), # Transaction sequence number (8 bits) ByteField("transaction_sequence", 0), # Command identifier (8 bits): the cluster command ByteEnumField("command_identifier", 0, _zcl_command_frames), ] def guess_payload_class(self, payload): # Profile-wide commands if self.zcl_frametype == 0x00 and self.command_identifier == 0x00: return ZCLGeneralReadAttributes elif self.zcl_frametype == 0x00 and self.command_identifier == 0x01: return ZCLGeneralReadAttributesResponse # Cluster-specific commands elif self.zcl_frametype == 0x01 and self.command_identifier == 0x00 and self.direction == 0 and self.underlayer.cluster == 0x0700: # "price" # noqa: E501 return ZCLPriceGetCurrentPrice elif self.zcl_frametype == 0x01 and self.command_identifier == 0x01 and self.direction == 0 and self.underlayer.cluster == 0x0700: # "price" # noqa: E501 return ZCLPriceGetScheduledPrices elif self.zcl_frametype == 0x01 and self.command_identifier == 0x00 and self.direction == 1 and self.underlayer.cluster == 0x0700: # "price" # noqa: E501 return ZCLPricePublishPrice else: return Packet.guess_payload_class(self, payload)
class Dot15d4CmdAssocResp(Packet): name = "802.15.4 Association Response Payload" fields_desc = [ XLEShortField( "short_address", 0xFFFF ), # Address assigned to device from coordinator (0xFFFF == none) # noqa: E501 # Association Status # 0x00 == successful # 0x01 == PAN at capacity # 0x02 == PAN access denied # 0x03 - 0x7f == Reserved # 0x80 - 0xff == Reserved for MAC primitive enumeration values ByteEnumField("association_status", 0x00, { 0: 'successful', 1: 'PAN_at_capacity', 2: 'PAN_access_denied' }), # noqa: E501 ] def mysummary(self): return self.sprintf( "802.15.4 Association Response Payload ( Association Status: %Dot15d4CmdAssocResp.association_status% Assigned Address: %Dot15d4CmdAssocResp.short_address% )" ) # noqa: E501
class SMB2_Negociate_Protocol_Request_Header(Packet): name = "SMB2 Negociate Protocol Request Header" fields_desc = [ XLEShortField("StructureSize", 0), FieldLenField( "DialectCount", None, fmt="<H", count_of="Dialects" ), # SecurityMode FlagsField("SecurityMode", 0, 16, { 0x7: "Signing Required", 0x8: "Signing Enabled", }), LEShortField("Reserved", 0), # Capabilities FlagsField("Capabilities", 0, 32, SMB2_CAPABILITIES), UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE), XLEIntField("NegociateContextOffset", 0x0), FieldLenField( "NegociateCount", 0x0, fmt="<H", count_of="NegociateContexts" ), ShortField("Reserved2", 0), FieldListField( "Dialects", [0x0202], LEShortEnumField("", 0x0, SMB_DIALECTS), count_from=lambda pkt: pkt.DialectCount ), # The first negotiate context must be 8-byte aligned ReversePadField(PacketListField( "NegociateContexts", [], SMB2_Negociate_Context, count_from=lambda pkt: pkt.NegociateCount ), 8), ]
class SMB2_Negotiate_Protocol_Request(Packet): name = "SMB2 Negotiate Protocol Request" fields_desc = [ XLEShortField("StructureSize", 0), FieldLenField("DialectCount", None, fmt="<H", count_of="Dialects"), # SecurityMode FlagsField( "SecurityMode", 0, -16, { 0x01: "SMB2_NEGOTIATE_SIGNING_ENABLED", 0x02: "SMB2_NEGOTIATE_SIGNING_REQUIRED", }), LEShortField("Reserved", 0), # Capabilities FlagsField("Capabilities", 0, -32, SMB2_CAPABILITIES), UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE), # XXX TODO If we ever want to properly dissect the offsets, we have # a _NTLMPayloadField in scapy/layers/ntlm.py that does precisely that XLEIntField("NegotiateContextOffset", 0x0), FieldLenField("NegotiateCount", None, fmt="<H", count_of="NegotiateContexts"), ShortField("Reserved2", 0), FieldListField("Dialects", [0x0202], LEShortEnumField("", 0x0, SMB_DIALECTS), count_from=lambda pkt: pkt.DialectCount), # Field only exists if Dialects contains 0x0311 # Each negotiate context must be 8-byte aligned ConditionalField( FieldListField("NegotiateContexts", [], ReversePadField( PacketField("Context", None, SMB2_Negotiate_Context), 8), count_from=lambda pkt: pkt.NegotiateCount), lambda x: 0x0311 in x.Dialects), ]
class ZigbeeNWKCommandPayload(Packet): name = "Zigbee Network Layer Command Payload" fields_desc = [ ByteEnumField( "cmd_identifier", 1, { 1: "route request", 2: "route reply", 3: "network status", 4: "leave", 5: "route record", 6: "rejoin request", 7: "rejoin response", 8: "link status", 9: "network report", 10: "network update" # 0x0b - 0xff reserved }), # - Route Request Command - # # Command options (1 octet) ConditionalField(BitField("reserved", 0, 1), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 ConditionalField(BitField("multicast", 0, 1), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 ConditionalField(BitField("dest_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 ConditionalField( BitEnumField( "many_to_one", 0, 2, { 0: "not_m2one", 1: "m2one_support_rrt", 2: "m2one_no_support_rrt", 3: "reserved" } # noqa: E501 ), lambda pkt: pkt.cmd_identifier == 1), ConditionalField(BitField("reserved", 0, 3), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 # Route request identifier (1 octet) ConditionalField(ByteField("route_request_identifier", 0), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 # Destination address (2 octets) ConditionalField(XLEShortField("destination_address", 0x0000), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 # Path cost (1 octet) ConditionalField(ByteField("path_cost", 0), lambda pkt: pkt.cmd_identifier == 1), # noqa: E501 # Destination IEEE Address (0/8 octets), only present when dest_addr_bit has a value of 1 # noqa: E501 ConditionalField( dot15d4AddressField("ext_dst", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 1 and pkt.dest_addr_bit == 1) ), # noqa: E501 # - Route Reply Command - # # Command options (1 octet) ConditionalField(BitField("reserved", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("multicast", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("responder_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("originator_addr_bit", 0, 1), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 ConditionalField(BitField("reserved", 0, 4), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Route request identifier (1 octet) ConditionalField(ByteField("route_request_identifier", 0), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Originator address (2 octets) ConditionalField(XLEShortField("originator_address", 0x0000), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Responder address (2 octets) ConditionalField(XLEShortField("responder_address", 0x0000), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Path cost (1 octet) ConditionalField(ByteField("path_cost", 0), lambda pkt: pkt.cmd_identifier == 2), # noqa: E501 # Originator IEEE address (0/8 octets) ConditionalField( dot15d4AddressField("originator_addr", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 2 and pkt.originator_addr_bit == 1) ), # noqa: E501 # Responder IEEE address (0/8 octets) ConditionalField( dot15d4AddressField("responder_addr", 0, adjust=lambda pkt, x: 8), # noqa: E501 lambda pkt: (pkt.cmd_identifier == 2 and pkt.responder_addr_bit == 1) ), # noqa: E501 # - Network Status Command - # # Status code (1 octet) ConditionalField( ByteEnumField( "status_code", 0, { 0x00: "No route available", 0x01: "Tree link failure", 0x02: "Non-tree link failure", 0x03: "Low battery level", 0x04: "No routing capacity", 0x05: "No indirect capacity", 0x06: "Indirect transaction expiry", 0x07: "Target device unavailable", 0x08: "Target address unallocated", 0x09: "Parent link failure", 0x0a: "Validate route", 0x0b: "Source route failure", 0x0c: "Many-to-one route failure", 0x0d: "Address conflict", 0x0e: "Verify addresses", 0x0f: "PAN identifier update", 0x10: "Network address update", 0x11: "Bad frame counter", 0x12: "Bad key sequence number", # 0x13 - 0xff Reserved }), lambda pkt: pkt.cmd_identifier == 3), # Destination address (2 octets) ConditionalField(XLEShortField("destination_address", 0x0000), lambda pkt: pkt.cmd_identifier == 3), # noqa: E501 # - Leave Command - # # Command options (1 octet) # Bit 7: Remove children ConditionalField(BitField("remove_children", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 6: Request ConditionalField(BitField("request", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 5: Rejoin ConditionalField(BitField("rejoin", 0, 1), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # Bit 0 - 4: Reserved ConditionalField(BitField("reserved", 0, 5), lambda pkt: pkt.cmd_identifier == 4), # noqa: E501 # - Route Record Command - # # Relay count (1 octet) ConditionalField(ByteField("rr_relay_count", 0), lambda pkt: pkt.cmd_identifier == 5), # noqa: E501 # Relay list (variable in length) ConditionalField( FieldListField( "rr_relay_list", [], XLEShortField("", 0x0000), count_from=lambda pkt: pkt.rr_relay_count), # noqa: E501 lambda pkt: pkt.cmd_identifier == 5), # - Rejoin Request Command - # # Capability Information (1 octet) ConditionalField(BitField("allocate_address", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # Allocate Address # noqa: E501 ConditionalField(BitField("security_capability", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # Security Capability # noqa: E501 ConditionalField(BitField("reserved2", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # bit 5 is reserved # noqa: E501 ConditionalField(BitField("reserved1", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # bit 4 is reserved # noqa: E501 ConditionalField(BitField("receiver_on_when_idle", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # Receiver On When Idle # noqa: E501 ConditionalField( BitField("power_source", 0, 1), lambda pkt: pkt.cmd_identifier == 6), # Power Source # noqa: E501 ConditionalField( BitField("device_type", 0, 1), lambda pkt: pkt.cmd_identifier == 6), # Device Type # noqa: E501 ConditionalField(BitField("alternate_pan_coordinator", 0, 1), lambda pkt: pkt.cmd_identifier == 6 ), # Alternate PAN Coordinator # noqa: E501 # - Rejoin Response Command - # # Network address (2 octets) ConditionalField(XLEShortField("network_address", 0xFFFF), lambda pkt: pkt.cmd_identifier == 7), # noqa: E501 # Rejoin status (1 octet) ConditionalField(ByteField("rejoin_status", 0), lambda pkt: pkt.cmd_identifier == 7), # noqa: E501 # - Link Status Command - # # Command options (1 octet) ConditionalField( BitField("reserved", 0, 1), lambda pkt: pkt.cmd_identifier == 8), # Reserved # noqa: E501 ConditionalField( BitField("last_frame", 0, 1), lambda pkt: pkt.cmd_identifier == 8), # Last frame # noqa: E501 ConditionalField( BitField("first_frame", 0, 1), lambda pkt: pkt.cmd_identifier == 8), # First frame # noqa: E501 ConditionalField( BitField("entry_count", 0, 5), lambda pkt: pkt.cmd_identifier == 8), # Entry count # noqa: E501 # Link status list (variable size) ConditionalField( PacketListField( "link_status_list", [], LinkStatusEntry, count_from=lambda pkt: pkt.entry_count), # noqa: E501 lambda pkt: pkt.cmd_identifier == 8), # - Network Report Command - # # Command options (1 octet) ConditionalField( BitEnumField("report_command_identifier", 0, 3, {0: "PAN identifier conflict" }), # 0x01 - 0x07 Reserved # noqa: E501 lambda pkt: pkt.cmd_identifier == 9), ConditionalField(BitField("report_information_count", 0, 5), lambda pkt: pkt.cmd_identifier == 9), # noqa: E501 # EPID: Extended PAN ID (8 octets) ConditionalField( dot15d4AddressField("epid", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 9), # noqa: E501 # Report information (variable length) # Only present if we have a PAN Identifier Conflict Report ConditionalField( FieldListField( "PAN_ID_conflict_report", [], XLEShortField("", 0x0000), # noqa: E501 count_from=lambda pkt: pkt.report_information_count), lambda pkt: (pkt.cmd_identifier == 9 and pkt. report_command_identifier == 0) # noqa: E501 ), # - Network Update Command - # # Command options (1 octet) ConditionalField( BitEnumField("update_command_identifier", 0, 3, {0: "PAN Identifier Update" }), # 0x01 - 0x07 Reserved # noqa: E501 lambda pkt: pkt.cmd_identifier == 10), ConditionalField(BitField("update_information_count", 0, 5), lambda pkt: pkt.cmd_identifier == 10), # noqa: E501 # EPID: Extended PAN ID (8 octets) ConditionalField( dot15d4AddressField("epid", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 10), # noqa: E501 # Update Id (1 octet) ConditionalField(ByteField("update_id", 0), lambda pkt: pkt.cmd_identifier == 10), # noqa: E501 # Update Information (Variable) # Only present if we have a PAN Identifier Update # New PAN ID (2 octets) ConditionalField( XLEShortField("new_PAN_ID", 0x0000), lambda pkt: (pkt.cmd_identifier == 10 and pkt.update_command_identifier == 0) ), # noqa: E501 # StrField("data", ""), ]
class ZigbeeAppDataPayload(Packet): name = "Zigbee Application Layer Data Payload (General APS Frame Format)" fields_desc = [ # Frame control (1 octet) FlagsField("frame_control", 2, 4, ['ack_format', 'security', 'ack_req', 'extended_hdr']), BitEnumField("delivery_mode", 0, 2, {0: 'unicast', 1: 'indirect', 2: 'broadcast', 3: 'group_addressing'}), BitEnumField("aps_frametype", 0, 2, {0: 'data', 1: 'command', 2: 'ack'}), # Destination endpoint (0/1 octet) ConditionalField( ByteField("dst_endpoint", 10), lambda pkt: ((pkt.aps_frametype == 0 and pkt.delivery_mode in [0, 2]) or (pkt.aps_frametype == 2 and not pkt.frame_control.ack_format)) ), # Group address (0/2 octets) ConditionalField( XLEShortField("group_addr", 0x0000), lambda pkt: (pkt.aps_frametype == 0 and pkt.delivery_mode == 3) ), # Cluster identifier (0/2 octets) ConditionalField( # unsigned short (little-endian) EnumField("cluster", 0, _zcl_cluster_identifier, fmt="<H"), lambda pkt: ((pkt.aps_frametype == 0) or (pkt.aps_frametype == 2 and not pkt.frame_control.ack_format)) ), # Profile identifier (0/2 octets) ConditionalField( EnumField("profile", 0, _zcl_profile_identifier, fmt="<H"), lambda pkt: ((pkt.aps_frametype == 0) or (pkt.aps_frametype == 2 and not pkt.frame_control.ack_format)) ), # Source endpoint (0/1 octets) ConditionalField( ByteField("src_endpoint", 10), lambda pkt: ((pkt.aps_frametype == 0) or (pkt.aps_frametype == 2 and not pkt.frame_control.ack_format)) ), # APS counter (1 octet) ByteField("counter", 0), # Extended header (0/1/2 octets) # cribbed from https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-zbee-aps.c # noqa: E501 ConditionalField( ByteEnumField( "fragmentation", 0, {0: "none", 1: "first_block", 2: "middle_block"}), lambda pkt: (pkt.aps_frametype in [0, 2] and pkt.frame_control.extended_hdr) ), ConditionalField( ByteField("block_number", 0), lambda pkt: (pkt.aps_frametype in [0, 2] and pkt.fragmentation in [1, 2]) ), ConditionalField( ByteField("ack_bitfield", 0), lambda pkt: (pkt.aps_frametype == 2 and pkt.fragmentation in [1, 2]) ), # variable length frame payload: # 3 frame types: data, APS command, and acknowledgement # ConditionalField(StrField("data", ""), lambda pkt:pkt.aps_frametype == 0), # noqa: E501 ] def guess_payload_class(self, payload): if self.frame_control & 0x02: # we have a security header return ZigbeeSecurityHeader elif self.aps_frametype == 0: # data if self.profile == 0x0000: return ZigbeeDeviceProfile else: return ZigbeeClusterLibrary elif self.aps_frametype == 1: # command return ZigbeeAppCommandPayload else: return Packet.guess_payload_class(self, payload)
class Dot15d4(Packet): FRAME_TYPE = { 0b000: "Beacon", 0b001: "Data", 0b010: "Ack", 0b011: "Command", 0b101: "Multipurpose", 0b110: "Fragment", 0b111: "Extended" } FRAME_VERSION = { 0b00: "2003", 0b01: "2006", 0b10: "2015" } name = "802.15.4" fields_desc = [ # Frame control BitField("fcf_reserved_1", 0, 1), BitEnumField("fcf_panidcompress", 0, 1, [False, True]), BitEnumField("fcf_ackreq", 0, 1, [False, True]), BitEnumField("fcf_pending", 0, 1, [False, True]), BitEnumField("fcf_security", 0, 1, [False, True]), Emph(BitEnumField("fcf_frametype", 0, 3, FRAME_TYPE)), AddressingModeField("fcf_srcaddrmode", 0, "src_addr"), BitEnumField("fcf_framever", 0, 2, FRAME_VERSION), AddressingModeField("fcf_destaddrmode", 2, "dest_addr"), BitField("fcf_reserved_2", 0, 2), # Sequence number Emph(ByteField("seqnum", 1)), # Addressing fields ConditionalField( XLEShortField("dest_panid", 0xFFFF), lambda pkt: panids_present(pkt)[0]), MultipleTypeField( [(ShortAddressField("dest_addr", 0xFFFF), lambda pkt: pkt.fcf_destaddrmode == 0b10), (LEEUI64Field("dest_addr", 0xFFFFFFFFFFFFFFFF), lambda pkt: pkt.fcf_destaddrmode == 0b11)], NoneField("dest_addr", 0xFFFF)), ConditionalField( XLEShortField("src_panid", 0x0000), lambda pkt: panids_present(pkt)[1]), MultipleTypeField( [(ShortAddressField("src_addr", None), lambda pkt: pkt.fcf_srcaddrmode == 0b10), (LEEUI64Field("src_addr", None), lambda pkt: pkt.fcf_srcaddrmode == 0b11)], NoneField("src_addr", None)), # Security field ConditionalField( PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), lambda pkt: pkt.fcf_security), ] def mysummary(self): return self.sprintf( "802.15.4 %Dot15d4.fcf_frametype% " "(ackreq=%Dot15d4.fcf_ackreq% " "%Dot15d4.fcf_destaddrmode% -> %Dot15d4.fcf_srcaddrmode% " "Seq#%Dot15d4.seqnum%)") def answers(self, other): if isinstance(other, Dot15d4): if self.fcf_frametype == 2: # ack # check for seqnum matching if self.seqnum != other.seqnum: return 0 # check that an ack was indeed requested elif other.fcf_ackreq == 1: return 1 return 0 def post_build(self, p, pay): # This just forces destaddrmode to None for Ack frames. if self.fcf_frametype == 2 and self.fcf_destaddrmode != 0: self.fcf_destaddrmode = 0 return p[:1] + \ chb((self.fcf_srcaddrmode << 6) + (self.fcf_framever << 4)) \ + p[2:] + pay else: return p + pay
class LL_CHANNEL_MAP_REQ(Packet): name = 'LL_CHANNEL_MAP_REQ' fields_desc = [ BTLEChanMapField("chM", 0), XLEShortField("instant", 0x0), ]
class ZigbeeAppCommandPayload(Packet): name = "Zigbee Application Layer Command Payload" fields_desc = [ ByteEnumField("cmd_identifier", 1, { 1: "APS_CMD_SKKE_1", 2: "APS_CMD_SKKE_2", 3: "APS_CMD_SKKE_3", 4: "APS_CMD_SKKE_4", 5: "APS_CMD_TRANSPORT_KEY", 6: "APS_CMD_UPDATE_DEVICE", 7: "APS_CMD_REMOVE_DEVICE", 8: "APS_CMD_REQUEST_KEY", 9: "APS_CMD_SWITCH_KEY", # TODO: implement 10 to 13 10: "APS_CMD_EA_INIT_CHLNG", 11: "APS_CMD_EA_RSP_CHLNG", 12: "APS_CMD_EA_INIT_MAC_DATA", 13: "APS_CMD_EA_RSP_MAC_DATA", 14: "APS_CMD_TUNNEL", 15: "APS_CMD_VERIFY_KEY", 16: "APS_CMD_CONFIRM_KEY" }), # SKKE Commands ConditionalField(dot15d4AddressField("initiator", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), ConditionalField(dot15d4AddressField("responder", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), ConditionalField(StrFixedLenField("data", 0, length=16), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), # Confirm-key command ConditionalField( ByteEnumField("status", 0, _ApsStatusValues), lambda pkt: pkt.cmd_identifier == 16), # Common fields ConditionalField( ByteEnumField("key_type", 0, _TransportKeyKeyTypes), lambda pkt: pkt.cmd_identifier in [5, 8, 15, 16]), ConditionalField(dot15d4AddressField("address", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [6, 7, 15, 16]), # Transport-key Command ConditionalField( StrFixedLenField("key", None, 16), lambda pkt: pkt.cmd_identifier == 5), ConditionalField( ByteField("key_seqnum", 0), lambda pkt: (pkt.cmd_identifier == 5 and pkt.key_type in [0x01, 0x05])), ConditionalField( dot15d4AddressField("dest_addr", 0, adjust=lambda pkt, x: 8), lambda pkt: ((pkt.cmd_identifier == 5 and pkt.key_type not in [0x02, 0x03]) or pkt.cmd_identifier == 14)), ConditionalField( dot15d4AddressField("src_addr", 0, adjust=lambda pkt, x: 8), lambda pkt: (pkt.cmd_identifier == 5 and pkt.key_type not in [0x02, 0x03])), ConditionalField( dot15d4AddressField("partner_addr", 0, adjust=lambda pkt, x: 8), lambda pkt: ((pkt.cmd_identifier == 5 and pkt.key_type in [0x02, 0x03]) or (pkt.cmd_identifier == 8 and pkt.key_type == 0x02))), ConditionalField( ByteField("initiator_flag", 0), lambda pkt: (pkt.cmd_identifier == 5 and pkt.key_type in [0x02, 0x03])), # Update-Device Command ConditionalField(XLEShortField("short_address", 0), lambda pkt: pkt.cmd_identifier == 6), ConditionalField(ByteField("update_status", 0), lambda pkt: pkt.cmd_identifier == 6), # Switch-Key Command ConditionalField(StrFixedLenField("seqnum", None, 8), lambda pkt: pkt.cmd_identifier == 9), # Un-implemented: 10-13 (+?) ConditionalField(StrField("unimplemented", ""), lambda pkt: (pkt.cmd_identifier >= 10 and pkt.cmd_identifier <= 13)), # Tunnel Command ConditionalField( FlagsField("frame_control", 2, 4, [ "ack_format", "security", "ack_req", "extended_hdr" ]), lambda pkt: pkt.cmd_identifier == 14), ConditionalField( BitEnumField("delivery_mode", 0, 2, { 0: "unicast", 1: "indirect", 2: "broadcast", 3: "group_addressing" }), lambda pkt: pkt.cmd_identifier == 14), ConditionalField( BitEnumField("aps_frametype", 1, 2, { 0: "data", 1: "command", 2: "ack" }), lambda pkt: pkt.cmd_identifier == 14), ConditionalField( ByteField("counter", 0), lambda pkt: pkt.cmd_identifier == 14), # Verify-Key Command ConditionalField( StrFixedLenField("key_hash", None, 16), lambda pkt: pkt.cmd_identifier == 15), ] def guess_payload_class(self, payload): if self.cmd_identifier == 14: # Tunneled APS Auxiliary Header return ZigbeeSecurityHeader else: return Packet.guess_payload_class(self, payload)
LEShortField('pfh_length', None), # pfh_len ByteField('geotag_ver', CURR_GEOTAG_VER), # base_geotag_header.ver # noqa: E501 ByteField('geotag_pad', 0), # base_geotag_header.pad LEShortField('geotag_len', None) ] + _HCSIBuildFields(SENS_Fields) # noqa: E501 # HCSIAntenna Fields ANT_Fields = [ FlagsField("AntennaFlags", None, -32, _hcsi_antenna_flags), ByteField("Gain", None), Fixed3_6Field("HorizBw", None), Fixed3_6Field("VertBw", None), Fixed3_6Field("PrecisionGain", None), XLEShortField("BeamID", None), # noqa: E501 HCSINullField("Reserved06", None), HCSINullField("Reserved07", None), # noqa: E501 HCSINullField("Reserved08", None), HCSINullField("Reserved09", None), # noqa: E501 HCSINullField("Reserved10", None), HCSINullField("Reserved11", None), # noqa: E501 HCSINullField("Reserved12", None), HCSINullField("Reserved13", None), # noqa: E501 HCSINullField("Reserved14", None), HCSINullField("Reserved15", None), # noqa: E501 HCSINullField("Reserved16", None), HCSINullField("Reserved17", None), # noqa: E501 HCSINullField("Reserved18", None), HCSINullField("Reserved19", None), # noqa: E501 HCSINullField("Reserved20", None),
class ZCLGeneralReadAttributes(Packet): name = "General Domain: Command Frame Payload: read_attributes" fields_desc = [ FieldListField("attribute_identifiers", [], XLEShortField("", 0x0000)), ]
class ZigbeeAppCommandPayload(Packet): name = "Zigbee Application Layer Command Payload" fields_desc = [ ByteEnumField( "cmd_identifier", 1, { 1: "APS_CMD_SKKE_1", 2: "APS_CMD_SKKE_2", 3: "APS_CMD_SKKE_3", 4: "APS_CMD_SKKE_4", 5: "APS_CMD_TRANSPORT_KEY", 6: "APS_CMD_UPDATE_DEVICE", 7: "APS_CMD_REMOVE_DEVICE", 8: "APS_CMD_REQUEST_KEY", 9: "APS_CMD_SWITCH_KEY", # TODO: implement 10 to 14 10: "APS_CMD_EA_INIT_CHLNG", 11: "APS_CMD_EA_RSP_CHLNG", 12: "APS_CMD_EA_INIT_MAC_DATA", 13: "APS_CMD_EA_RSP_MAC_DATA", 14: "APS_CMD_TUNNEL" }), # SKKE Commands ConditionalField( dot15d4AddressField("initiator", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), ConditionalField( dot15d4AddressField("responder", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), ConditionalField(StrFixedLenField("data", 0, length=16), lambda pkt: pkt.cmd_identifier in [1, 2, 3, 4]), # Transport-key Command ConditionalField(ByteEnumField("key_type", 0, _TransportKeyKeyTypes), lambda pkt: pkt.cmd_identifier == 5), ConditionalField(StrFixedLenField("key", None, 16), lambda pkt: pkt.cmd_identifier == 5), ConditionalField( ByteField("key_seqnum", 0), lambda pkt: (pkt.cmd_identifier == 5 and pkt.key_type in [0x01, 0x05])), ConditionalField( dot15d4AddressField("dest_addr", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 5), ConditionalField( dot15d4AddressField("src_addr", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 5), # Update-Device Command ConditionalField( dot15d4AddressField("address", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 6), ConditionalField(XLEShortField("short_address", 0), lambda pkt: pkt.cmd_identifier == 6), ConditionalField(ByteField("status", 0), lambda pkt: pkt.cmd_identifier == 6), # Remove-Device Command ConditionalField( dot15d4AddressField("address", 0, adjust=lambda pkt, x: 8), lambda pkt: pkt.cmd_identifier == 7), # Request-Key Command ConditionalField(ByteEnumField("key_type", 0, _TransportKeyKeyTypes), lambda pkt: pkt.cmd_identifier == 8), ConditionalField(StrFixedLenField("key", None, 16), lambda pkt: pkt.cmd_identifier == 8), # Switch-Key Command ConditionalField(StrFixedLenField("seqnum", None, 8), lambda pkt: pkt.cmd_identifier == 9), # Un-implemented: 10-14 (+?) ConditionalField( StrField("data", ""), lambda pkt: (pkt.cmd_identifier < 0 or pkt.cmd_identifier > 9)) ]