/* packet-zbee-zdp-management.c * Dissector helper routines for the management services of the ZigBee Device Profile * By Owen Kirby * Copyright 2009 Exegin Technologies Limited * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* Include Files */ #include "config.h" #include #include #include "packet-zbee.h" #include "packet-zbee-zdp.h" #include "packet-zbee-tlv.h" /************************************** * HELPER FUNCTIONS ************************************** */ /** *Parses and displays a single network descriptor * *@param tvb pointer to buffer containing raw packet. *@param tree pointer to data tree Wireshark uses to display packet. */ static void zdp_parse_nwk_desc(proto_tree *tree, tvbuff_t *tvb, unsigned *offset, uint8_t version) { proto_tree *network_tree; proto_item *ti; uint8_t beacon; if (version >= ZBEE_VERSION_2007) { network_tree = proto_tree_add_subtree(tree, tvb, *offset, 12, ett_zbee_zdp_nwk_desc, NULL, "Network descriptor"); /* Extended PAN Identifiers are used in ZigBee 2006 & later. */ proto_tree_add_item(network_tree, hf_zbee_zdp_pan_eui64, tvb, *offset, 8, ENC_LITTLE_ENDIAN); *offset += 8; } else { network_tree = proto_tree_add_subtree(tree, tvb, *offset, 6, ett_zbee_zdp_nwk_desc, NULL, "Network descriptor"); /* Short PAN Identifiers are used in ZigBee 2003 and earlier. */ proto_tree_add_item(network_tree, hf_zbee_zdp_pan_uint, tvb, *offset, 2, ENC_LITTLE_ENDIAN); *offset += 2; } proto_tree_add_item(network_tree, hf_zbee_zdp_channel, tvb, *offset, 1, ENC_LITTLE_ENDIAN); *offset += 1; proto_tree_add_item(network_tree, hf_zbee_zdp_profile, tvb, *offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(network_tree, hf_zbee_zdp_profile_version, tvb, *offset, 1, ENC_LITTLE_ENDIAN); *offset += 1; ti = proto_tree_add_item(network_tree, hf_zbee_zdp_beacon, tvb, *offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(network_tree, hf_zbee_zdp_superframe, tvb, *offset, 1, ENC_LITTLE_ENDIAN); beacon = tvb_get_uint8(tvb, *offset) & 0x0f; if (beacon == 0xf) { proto_item_append_text(ti, " (Beacons Disabled)"); } *offset += 1; proto_tree_add_item(network_tree, hf_zbee_zdp_permit_joining, tvb, *offset, 1, ENC_LITTLE_ENDIAN); *offset += 1; } /* zdp_parse_nwk_desc */ /** *Parses and displays a neighbor table entry. * *@param tvb pointer to buffer containing raw packet. *@param tree pointer to data tree Wireshark uses to display packet. */ static void zdp_parse_neighbor_table_entry(proto_tree *tree, tvbuff_t *tvb, unsigned *offset, uint8_t version) { proto_tree *table_tree; proto_item *ti = NULL; unsigned len = 0; if (version >= ZBEE_VERSION_2007) { table_tree = proto_tree_add_subtree(tree, tvb, *offset, 8, ett_zbee_zdp_table_entry, &ti, "Table Entry"); /* ZigBee 2006 & later use an extended PAN Identifier. */ proto_tree_add_item(table_tree, hf_zbee_zdp_extended_pan, tvb, *offset, 8, ENC_LITTLE_ENDIAN); len += 8; } else { table_tree = proto_tree_add_subtree(tree, tvb, *offset, 2, ett_zbee_zdp_table_entry, &ti, "Table Entry"); /* ZigBee 2003 & earlier use a short PAN Identifier. */ proto_tree_add_item(table_tree, hf_zbee_zdp_pan_uint, tvb, *offset, 2, ENC_LITTLE_ENDIAN); len += 2; } proto_tree_add_item(table_tree, hf_zbee_zdp_ext_addr, tvb, *offset + len, 8, ENC_LITTLE_ENDIAN); len += 8; proto_tree_add_item(table_tree, hf_zbee_zdp_addr, tvb, *offset + len, 2, ENC_LITTLE_ENDIAN); len += 2; if (version >= ZBEE_VERSION_2007) { proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_type, tvb, *offset + len, 1, ENC_NA); proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_idle_rx_0c, tvb, *offset + len, 1, ENC_NA); proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_relationship_70, tvb, *offset + len, 1, ENC_NA); } else { proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_type, tvb, *offset + len, 1, ENC_NA); proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_idle_rx_04, tvb, *offset + len, 1, ENC_NA); proto_tree_add_item(table_tree, hf_zbee_zdp_table_entry_relationship_18, tvb, *offset + len, 1, ENC_NA); } len += 1; if (version <= ZBEE_VERSION_2004) { /* In ZigBee 2003 & earlier, the depth field is before the permit joining field. */ proto_tree_add_item(table_tree, hf_zbee_zdp_depth, tvb, *offset + len, 1, ENC_NA); len += 1; } proto_tree_add_item(table_tree, hf_zbee_zdp_permit_joining_03, tvb, *offset + len, 1, ENC_NA); len += 1; if (version >= ZBEE_VERSION_2007) { /* In ZigBee 2006 & later, the depth field is after the permit joining field. */ proto_tree_add_item(table_tree, hf_zbee_zdp_depth, tvb, *offset + len, 1, ENC_NA); len += 1; } proto_tree_add_item(table_tree, hf_zbee_zdp_lqi, tvb, *offset + len, 1, ENC_NA); len += 1; if (tree) proto_item_set_len(ti, len); *offset += len; } /* zdp_parse_neighbor_table_entry */ /** *Parses and displays a routing table entry. * *@param tvb pointer to buffer containing raw packet. *@param tree pointer to data tree Wireshark uses to display packet. */ static void zdp_parse_routing_table_entry(proto_tree *tree, tvbuff_t *tvb, unsigned *offset) { unsigned len = 0; proto_item *ti; proto_tree *field_tree; uint16_t dest; uint8_t status; uint16_t next; ti = proto_tree_add_item(tree, hf_zbee_zdp_rtg_entry, tvb, *offset + len, 2 + 1 + 2, ENC_NA); field_tree = proto_item_add_subtree(ti, ett_zbee_zdp_rtg); proto_tree_add_item(field_tree, hf_zbee_zdp_rtg_destination, tvb, *offset + len, 2, ENC_LITTLE_ENDIAN); dest = tvb_get_letohs(tvb, *offset + len); len += 2; proto_tree_add_item(field_tree, hf_zbee_zdp_rtg_status, tvb, *offset + len , 1, ENC_LITTLE_ENDIAN); status = tvb_get_uint8(tvb, *offset + len); len += 1; proto_tree_add_item(field_tree, hf_zbee_zdp_rtg_next_hop, tvb, *offset + len , 2, ENC_LITTLE_ENDIAN); next = tvb_get_letohs(tvb, *offset + len); len += 2; /* Display the next hop first, because it looks a lot cleaner that way. */ proto_item_append_text(ti, " {Destination: 0x%04x, Next Hop: 0x%04x, Status: %s}", dest, next, val_to_str_const(status, zbee_zdp_rtg_status_vals, "Unknown")); *offset += len; } /* zdp_parse_routing_table_entry */ /************************************** * MANAGEMENT REQUESTS ************************************** */ /** *ZigBee Device Profile dissector for the network discovery * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_nwk_disc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hf_channel) { proto_item *ti; unsigned i; unsigned offset = 0; uint32_t channels; /* Get the channel bitmap. */ channels = tvb_get_letohl(tvb, offset); if (tree) { bool first = 1; ti = proto_tree_add_uint_format(tree, hf_channel, tvb, offset, 4, channels, "Scan Channels: "); for (i=0; i<27; i++) { if (channels & (1<= ZBEE_VERSION_2007) { /* Flags present on ZigBee 2006 & later. */ proto_tree_add_bitmask_list(tree, tvb, offset, 1, flags, ENC_NA); offset += 1; } zbee_append_info(tree, pinfo, ", Device: %s", eui64_to_display(pinfo->pool, ext_addr)); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_mgmt_bind */ /** *ZigBee Device Profile dissector for the direct join request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_direct_join(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; uint64_t ext_addr; /*uint8_t cinfo;*/ ext_addr = zbee_parse_eui64(tree, hf_zbee_zdp_ext_addr, tvb, &offset, 8, NULL); /*cinfo =*/ zdp_parse_cinfo(tree, ett_zbee_zdp_cinfo, tvb, &offset); zbee_append_info(tree, pinfo, ", Device: %s", eui64_to_display(pinfo->pool, ext_addr)); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_mgmt_direct_join */ /** *ZigBee Device Profile dissector for the permit joining * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_permit_join(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; proto_tree_add_item(tree, hf_zbee_zdp_duration, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_zbee_zdp_significance, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; if (tvb_captured_length_remaining(tvb, offset)) { offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, NULL, ZBEE_TLV_SRC_TYPE_ZBEE_ZDP, ZBEE_ZDP_REQ_MGMT_PERMIT_JOIN); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } } /* dissect_zbee_zdp_req_mgmt_permit_join */ /** *ZigBee Device Profile dissector for the cache request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_cache(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; proto_tree_add_item(tree, hf_zbee_zdp_index, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_mgmt_cache */ /** *ZigBee Device Profile dissector for the nwk update request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_nwkupdate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; uint32_t duration; zdp_parse_chanmask(tree, tvb, &offset, hf_zbee_zdp_channel_page, hf_zbee_zdp_channel_mask); proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_duration, tvb, offset, 1, ENC_LITTLE_ENDIAN, &duration); offset += 1; if (duration == ZBEE_ZDP_NWKUPDATE_PARAMETERS) { proto_tree_add_item(tree, hf_zbee_zdp_update_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_zbee_zdp_manager, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; } else if (duration == ZBEE_ZDP_NWKUPDATE_CHANNEL_HOP) { proto_tree_add_item(tree, hf_zbee_zdp_update_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } else if (duration <= ZBEE_ZDP_NWKUPDATE_SCAN_MAX) { proto_tree_add_item(tree, hf_zbee_zdp_scan_count, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_mgmt_nwkupdate */ /** *ZigBee Device Profile dissector for the enhanced nwk update request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_mgmt_nwkupdate_enh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; uint32_t i, duration, count; proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_channel_page_count, tvb, offset, 1, ENC_LITTLE_ENDIAN, &count); offset += 1; for (i=0; i 0U) { count = tvb_get_uint8(tvb, offset); proto_tree_add_item(tree, hf_zbee_zdp_tlv_count, tvb, offset, 1, ENC_NA); offset += 1; for (i = 0; i < count; i++) { proto_tree_add_item(tree, hf_zbee_zdp_tlv_id, tvb, offset, 1, ENC_NA); offset += 1; } } /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_security_get_configuration */ /** *ZigBee Device Profile dissector for the Security Start Key Update Request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_security_start_key_update(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, NULL, ZBEE_TLV_SRC_TYPE_ZBEE_ZDP, ZBEE_ZDP_REQ_SECURITY_START_KEY_UPDATE); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_security_start_key_update */ /** *ZigBee Device Profile dissector for the Security Decommission Request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_security_decommission(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, NULL, ZBEE_TLV_SRC_TYPE_ZBEE_ZDP, ZBEE_ZDP_REQ_SECURITY_DECOMMISSION); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_security_decommission */ /** *ZigBee Device Profile dissector for the Security Challenge Request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_security_challenge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned offset = 0; offset = dissect_zbee_tlvs(tvb, pinfo, tree, offset, NULL, ZBEE_TLV_SRC_TYPE_ZBEE_ZDP, ZBEE_ZDP_REQ_SECURITY_CHALLENGE); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /************************************** * MANAGEMENT RESPONSES ************************************** */ /** *ZigBee Device Profile dissector for the network discovery * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_rsp_mgmt_nwk_disc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint8_t version) { proto_tree *field_tree = NULL; unsigned offset = 0; uint8_t status; uint32_t i, table_count; status = zdp_parse_status(tree, tvb, &offset); proto_tree_add_item(tree, hf_zbee_zdp_table_size, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_zbee_zdp_index, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_table_count, tvb, offset, 1, ENC_LITTLE_ENDIAN, &table_count); offset += 1; if (tree && table_count) { field_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_zbee_zdp_nwk, NULL, "Network List"); } for (i=0; i=channel_count) { /* Channel list has ended. */ break; } /* Get and display the channel energy. */ energy = tvb_get_uint8(tvb, offset); proto_tree_add_uint_format(tree, hf_zbee_zdp_channel_energy, tvb, offset, 1, energy, "Channel %d Energy: 0x%02x", i, energy); offset += 1; /* Increment the number of channels we found energy values for. */ j++; } /* for */ /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_not_mgmt_nwkupdate */ /** *ZigBee Device Profile dissector for the IEEE Joining List Response. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_rsp_mgmt_ieee_join_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { uint32_t i, status, list_total, list_count; unsigned offset = 0; status = zdp_parse_status(tree, tvb, &offset); if (status == 0x00) { proto_tree_add_item(tree, hf_zbee_zdp_ieee_join_update_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_zbee_zdp_ieee_join_policy, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_ieee_join_list_total, tvb, offset, 1, ENC_LITTLE_ENDIAN, &list_total); offset += 1; if (list_total > 0) { proto_tree_add_item(tree, hf_zbee_zdp_ieee_join_list_start, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_ieee_join_list_count, tvb, offset, 1, ENC_LITTLE_ENDIAN, &list_count); offset += 1; for(i=0; i