diff options
author | Anders Broman <anders.broman@ericsson.com> | 2010-10-24 10:04:29 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2010-10-24 10:04:29 +0000 |
commit | 43cb273d08e3d2e9f5526adcd9acf7cce2dd88f8 (patch) | |
tree | d6365afbff5e656a1e54da04c4945873eedd51fb /epan | |
parent | dbd143d68a42c17e69c0f356427c7256088eac75 (diff) |
From Fred Fierling:
Multi-key Support and Extended Address Mapping for ZigBee Dissectors
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5331
svn path=/trunk/; revision=34627
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-6lowpan.c | 8 | ||||
-rw-r--r-- | epan/dissectors/packet-ieee802154.c | 587 | ||||
-rw-r--r-- | epan/dissectors/packet-ieee802154.h | 63 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-aps.c | 137 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-aps.h | 58 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-nwk.c | 427 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-nwk.h | 32 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-security.c | 715 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee-security.h | 12 | ||||
-rw-r--r-- | epan/dissectors/packet-zbee.h | 10 |
10 files changed, 1368 insertions, 681 deletions
diff --git a/epan/dissectors/packet-6lowpan.c b/epan/dissectors/packet-6lowpan.c index f2525b0e3b..7cd4054bdb 100644 --- a/epan/dissectors/packet-6lowpan.c +++ b/epan/dissectors/packet-6lowpan.c @@ -516,14 +516,14 @@ lowpan_dlsrc_to_ifcid(packet_info *pinfo, guint8 *ifcid) /* Derive the IID from the IEEE 802.15.4 packet structure. */ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) { guint64 addr; - addr = pntoh64(&packet->src.addr64); + addr = pntoh64(&packet->src64); memcpy(ifcid, &addr, LOWPAN_IFC_ID_LEN); /* RFC2464: Invert the U/L bit when using an EUI64 address. */ ifcid[0] ^= 0x02; return TRUE; } if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) { - lowpan_addr16_to_ifcid(packet->src.addr16, ifcid); + lowpan_addr16_to_ifcid(packet->src16, ifcid); return TRUE; } @@ -561,14 +561,14 @@ lowpan_dldst_to_ifcid(packet_info *pinfo, guint8 *ifcid) /* Derive the IID from the IEEE 802.15.4 packet structure. */ if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) { guint64 addr; - addr = pntoh64(&packet->dst.addr64); + addr = pntoh64(&packet->dst64); memcpy(ifcid, &addr, LOWPAN_IFC_ID_LEN); /* RFC2464: Invert the U/L bit when using an EUI64 address. */ ifcid[0] ^= 0x02; return TRUE; } if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) { - lowpan_addr16_to_ifcid(packet->dst.addr16, ifcid); + lowpan_addr16_to_ifcid(packet->dst16, ifcid); return TRUE; } diff --git a/epan/dissectors/packet-ieee802154.c b/epan/dissectors/packet-ieee802154.c index 9d230807bd..24b5b63a0c 100644 --- a/epan/dissectors/packet-ieee802154.c +++ b/epan/dissectors/packet-ieee802154.c @@ -100,7 +100,7 @@ static unsigned int ieee802154_ethertype = 0x809A; /* boolean value set if the FCS field is using the TI CC24xx format */ static gboolean ieee802154_cc24xx = FALSE; -/* boolean value set if the FCS must be oke before data is dissected */ +/* boolean value set if the FCS must be ok before payload is dissected */ static gboolean ieee802154_fcs_ok = TRUE; /* User string with the decryption key. */ @@ -109,56 +109,10 @@ static gboolean ieee802154_key_valid; static guint8 ieee802154_key[IEEE802154_CIPHER_SIZE]; /*------------------------------------- - * Address Hash Table + * Address Hash Tables *------------------------------------- */ -static GHashTable * ieee802154_addr_table = NULL; - -/* Value used for the hash table. */ -typedef struct { - guint64 addr; - /*guint32 frame_counter; TODO for frame counter sequence checks. Any other security state to save across packets? */ -} ieee802154_long_addr; - -/* Keys used for the hash table. */ -typedef struct { - guint16 addr; - guint16 pan; -} ieee802154_short_addr; - -/* Key hash function. */ -static guint -ieee802154_addr_hash(gconstpointer key) -{ - return (((ieee802154_short_addr *)key)->addr) | (((ieee802154_short_addr *)key)->pan << 16); -} - -/* Key equals function. */ -static gboolean -ieee802154_addr_equals(gconstpointer a, gconstpointer b) -{ - return (((ieee802154_short_addr *)a)->addr == ((ieee802154_short_addr *)b)->addr) && - (((ieee802154_short_addr *)a)->pan == ((ieee802154_short_addr *)b)->pan); -} - -/* Function to update the address table. */ -/* TODO: Make this a public function, in case other layers expose short-to-extended address pairs. */ -static void ieee802154_addr_update(guint16 short_addr, guint16 pan, guint64 long_addr) -{ - ieee802154_short_addr addr16; - ieee802154_long_addr * addr64; - addr16.addr = short_addr; - addr16.pan = pan; - addr64 = g_hash_table_lookup(ieee802154_addr_table, &addr16); - if (addr64) { - addr64->addr = long_addr; - } - else { - addr64 = se_alloc(sizeof(ieee802154_long_addr)); - addr64->addr = long_addr; - g_hash_table_insert(ieee802154_addr_table, se_memdup(&addr16, sizeof(addr16)), addr64); - } -} /* ieee802154_addr_update */ +static ieee802154_addr_t ieee802154_addr = { 0, NULL, NULL }; /*------------------------------------- * Static Address Mapping UAT @@ -192,7 +146,7 @@ addr_uat_update_cb(void* r, const char** err) } /* Ensure a valid EUI-64 length */ if (map->eui64_len != sizeof(guint64)) { - *err = "Invalid EUI-64"; + *err = "Invalid EUI-64 length"; } } /* ieee802154_addr_uat_update_cb */ @@ -243,10 +197,11 @@ typedef enum { DECRYPT_PACKET_MIC_CHECK_FAILED, } ws_decrypt_status; -static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *, ws_decrypt_status *); -static void ccm_init_block (gchar * block, gboolean adata, gint M, guint64 addr, guint32 counter, ieee802154_security_level level, gint ctr_val); -static gboolean ccm_ctr_encrypt (const gchar *key, const gchar *iv, gchar *mic, gchar *data, gint length); -static gboolean ccm_cbc_mac (const gchar * key, const gchar *iv, const gchar *a, gint a_len, const gchar *m, gint m_len, gchar *mic); +static tvbuff_t * dissect_ieee802154_decrypt(tvbuff_t *, guint, packet_info *, ieee802154_packet *, + ws_decrypt_status *); +static void ccm_init_block (gchar *, gboolean, gint, guint64, guint32, ieee802154_security_level, gint); +static gboolean ccm_ctr_encrypt (const gchar *, const gchar *, gchar *, gchar *, gint); +static gboolean ccm_cbc_mac (const gchar *, const gchar *, const gchar *, gint, const gchar *, gint, gchar *); /* Initialize Protocol and Registered fields */ static int proto_ieee802154_nonask_phy = -1; @@ -268,8 +223,9 @@ static int hf_ieee802154_dst_pan = -1; static int hf_ieee802154_dst_addr16 = -1; static int hf_ieee802154_dst_addr64 = -1; static int hf_ieee802154_src_panID = -1; -static int hf_ieee802154_src_addr16 = -1; -static int hf_ieee802154_src_addr64 = -1; +static int hf_ieee802154_src16 = -1; +static int hf_ieee802154_src64 = -1; +static int hf_ieee802154_src64_origin = -1; static int hf_ieee802154_fcs = -1; static int hf_ieee802154_rssi = -1; static int hf_ieee802154_fcs_ok = -1; @@ -509,8 +465,9 @@ dissect_ieee802154_fcf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ieee packet->src_addr_mode = (fcf & IEEE802154_FCF_SADDR_MASK) >> 14; /* Display the frame type. */ - if (tree) proto_item_append_text(tree, " %s", val_to_str(packet->frame_type, ieee802154_frame_types, "Reserved")); - if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved")); + if (tree) + proto_item_append_text(tree, " %s", val_to_str(packet->frame_type, ieee802154_frame_types, "Reserved")); + col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->frame_type, ieee802154_frame_types, "Reserved")); /* Add the FCF to the protocol tree. */ if (tree) { @@ -568,11 +525,9 @@ dissect_ieee802154_nonask_phy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre /* Add the protocol name. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4 non-ASK PHY"); /* Add the packet length. */ - if(check_col(pinfo->cinfo, COL_PACKET_LENGTH)){ - col_clear(pinfo->cinfo, COL_PACKET_LENGTH); - col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); - } - + col_clear(pinfo->cinfo, COL_PACKET_LENGTH); + col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); + preamble=tvb_get_letohl(tvb,offset); sfd=tvb_get_guint8(tvb,offset+4); phr=tvb_get_guint8(tvb,offset+4+1); @@ -704,23 +659,36 @@ dissect_ieee802154_cc24xx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) static void dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint options) { - tvbuff_t *volatile payload_tvb; - proto_tree *volatile ieee802154_tree = NULL; - proto_item *volatile proto_root = NULL; - proto_item *ti; - void *pd_save; - - guint offset = 0; - volatile gboolean fcs_ok = TRUE; - const char *saved_proto; - ieee802154_packet *packet = ep_alloc(sizeof(ieee802154_packet)); - ws_decrypt_status status; + tvbuff_t *volatile payload_tvb; + proto_tree *volatile ieee802154_tree = NULL; + proto_item *volatile proto_root = NULL; + proto_item *ti; + void *pd_save; + + guint offset = 0; + volatile gboolean fcs_ok = TRUE; + const char *saved_proto; + ws_decrypt_status status; + + ieee802154_packet *packet = ep_alloc(sizeof(ieee802154_packet)); + ieee802154_short_addr addr16; + ieee802154_hints_t *ieee_hints; /* Link our packet info structure into the private data field for the * Network-Layer heuristic subdissectors. */ pd_save = pinfo->private_data; pinfo->private_data = packet; + packet->short_table = ieee802154_addr.short_table; + + /* Allocate frame data with hints for upper layers */ + if(!pinfo->fd->flags.visited){ + ieee_hints = se_alloc0(sizeof(ieee802154_hints_t)); + p_add_proto_data(pinfo->fd, proto_ieee802154, ieee_hints); + } else { + ieee_hints = p_get_proto_data(pinfo->fd, proto_ieee802154); + } + /* Create the protocol tree. */ if (tree) { proto_root = proto_tree_add_protocol_format(tree, proto_ieee802154, tvb, 0, tvb_length(tvb), "IEEE 802.15.4"); @@ -729,10 +697,8 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g /* Add the protocol name. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE 802.15.4"); /* Add the packet length. */ - if(check_col(pinfo->cinfo, COL_PACKET_LENGTH)){ - col_clear(pinfo->cinfo, COL_PACKET_LENGTH); - col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); - } + col_clear(pinfo->cinfo, COL_PACKET_LENGTH); + col_add_fstr(pinfo->cinfo, COL_PACKET_LENGTH, "%i", tvb_length(tvb)); /*===================================================== * FRAME CONTROL FIELD @@ -782,20 +748,25 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g gchar *dst_addr = ep_alloc(32); /* Get the address. */ - packet->dst.addr16 = tvb_get_letohs(tvb, offset); + packet->dst16 = tvb_get_letohs(tvb, offset); /* Display the destination address. */ - if(packet->dst.addr16==IEEE802154_BCAST_ADDR) g_snprintf(dst_addr, 32, "Broadcast"); - else g_snprintf(dst_addr, 32, "0x%04x", packet->dst.addr16); + if ( packet->dst16 == IEEE802154_BCAST_ADDR ) { + g_snprintf(dst_addr, 32, "Broadcast"); + } + else { + g_snprintf(dst_addr, 32, "0x%04x", packet->dst16); + } + SET_ADDRESS(&pinfo->dl_dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); + if (tree) { - proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset, 2, packet->dst.addr16); + proto_tree_add_uint(ieee802154_tree, hf_ieee802154_dst_addr16, tvb, offset, 2, packet->dst16); proto_item_append_text(proto_root, ", Dst: %s", dst_addr); } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr); - } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr); offset += 2; } else if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) { @@ -804,14 +775,14 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g gchar *dst, *dst_oui; /* Get the address */ - packet->dst.addr64 = tvb_get_letoh64(tvb, offset); + packet->dst64 = tvb_get_letoh64(tvb, offset); /* print the address strings. */ - dst = print_eui64(packet->dst.addr64); - dst_oui = print_eui64_oui(packet->dst.addr64); + dst = print_eui64(packet->dst64); + dst_oui = print_eui64_oui(packet->dst64); /* Copy and convert the address to network byte order. */ - *(guint64 *)(addr) = pntoh64(&(packet->dst.addr64)); + *(guint64 *)(addr) = pntoh64(&(packet->dst64)); /* Display the destination address. */ /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses @@ -821,12 +792,12 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g SET_ADDRESS(&pinfo->dl_dst, AT_EUI64, 8, addr); SET_ADDRESS(&pinfo->dst, AT_EUI64, 8, addr); if (tree) { - proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset, 8, packet->dst.addr64, "%s (%s)", dst_oui, dst); + proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_dst_addr64, tvb, offset, + 8, packet->dst64, "%s (%s)", dst_oui, dst); proto_item_append_text(proto_root, ", Dst: %s", dst_oui); } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_oui); - } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_oui); offset += 8; } else if (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE) { @@ -843,7 +814,8 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g if ( ((packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) || (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT)) && ((packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) || (!packet->intra_pan)) ) { /* Source PAN is present, extract it and add it to the tree. */ - packet->src_pan = tvb_get_letohs(tvb, offset); + ieee_hints->src_pan = packet->src_pan = tvb_get_letohs(tvb, offset); + if (tree) { proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_panID, tvb, offset, 2, packet->src_pan); } @@ -851,31 +823,64 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g } else { /* Set the panID field in case the intra-pan condition was met. */ - packet->src_pan = packet->dst_pan; + ieee_hints->src_pan = packet->src_pan = packet->dst_pan; } - /* Get source address if present. */ + /* Get short source address if present. */ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) { /* Dynamic (not stack) memory required for address column. */ gchar *src_addr = ep_alloc(32); /* Get the address. */ - packet->src.addr16 = tvb_get_letohs(tvb, offset); + packet->src16 = tvb_get_letohs(tvb, offset); /* Update the Address fields. */ - if(packet->src.addr16==IEEE802154_BCAST_ADDR) g_snprintf(src_addr, 32, "Broadcast"); - else g_snprintf(src_addr, 32, "0x%04x", packet->src.addr16); + if (packet->src16==IEEE802154_BCAST_ADDR) { + g_snprintf(src_addr, 32, "Broadcast"); + } + else { + g_snprintf(src_addr, 32, "0x%04x", packet->src16); + + if (!pinfo->fd->flags.visited) { + /* If we know our extended source address from previous packets, + * provide a pointer to it in a hint for upper layers */ + addr16.addr = packet->src16; + addr16.pan = packet->src_pan; + + if (ieee_hints) { + ieee_hints->src16 = packet->src16; + ieee_hints->map_rec = (ieee802154_map_rec *) + g_hash_table_lookup(ieee802154_addr.short_table, &addr16); + } + } + } + SET_ADDRESS(&pinfo->dl_src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); /* Add the addressing info to the tree. */ if (tree) { - proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src_addr16, tvb, offset, 2, packet->src.addr16); + proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src16, tvb, offset, 2, packet->src16); proto_item_append_text(proto_root, ", Src: %s", src_addr); + + if (ieee_hints && ieee_hints->map_rec) { + /* Display inferred source address info */ + ti = proto_tree_add_eui64(ieee802154_tree, hf_ieee802154_src64, tvb, offset, 0, + ieee_hints->map_rec->addr64); + PROTO_ITEM_SET_GENERATED(ti); + + if ( ieee_hints->map_rec->start_fnum ) { + ti = proto_tree_add_uint(ieee802154_tree, hf_ieee802154_src64_origin, tvb, 0, 0, + ieee_hints->map_rec->start_fnum); + } + else { + ti = proto_tree_add_text(ieee802154_tree, tvb, 0, 0, "Origin: Pre-configured"); + } + PROTO_ITEM_SET_GENERATED(ti); + } } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr); - } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_addr); offset += 2; } else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) { @@ -884,14 +889,14 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g gchar *src, *src_oui; /* Get the address. */ - packet->src.addr64 = tvb_get_letoh64(tvb, offset); + packet->src64 = tvb_get_letoh64(tvb, offset); /* Print the address strings. */ - src = print_eui64(packet->src.addr64); - src_oui = print_eui64_oui(packet->src.addr64); + src = print_eui64(packet->src64); + src_oui = print_eui64_oui(packet->src64); /* Copy and convert the address to network byte order. */ - *(guint64 *)(addr) = pntoh64(&(packet->src.addr64)); + *(guint64 *)(addr) = pntoh64(&(packet->src64)); /* Display the source address. */ /* NOTE: OUI resolution doesn't happen when displaying EUI64 addresses @@ -901,12 +906,12 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g SET_ADDRESS(&pinfo->dl_src, AT_EUI64, 8, addr); SET_ADDRESS(&pinfo->src, AT_EUI64, 8, addr); if (tree) { - proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_src_addr64, tvb, offset, 8, packet->src.addr64, "%s (%s)", src_oui, src); + proto_tree_add_uint64_format_value(ieee802154_tree, hf_ieee802154_src64, tvb, offset, + 8, packet->src64, "%s (%s)", src_oui, src); proto_item_append_text(proto_root, ", Src: %s", src_oui); } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_oui); - } + + col_append_fstr(pinfo->cinfo, COL_INFO, ", Src: %s", src_oui); offset += 8; } else if (packet->src_addr_mode != IEEE802154_FCF_ADDR_NONE) { @@ -945,14 +950,14 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g if (packet->security_enable && (packet->version == 1)) { proto_tree *header_tree, *field_tree; guint8 security_control; - guint aux_length = 5; /* Minimum length of the auxilliary header. */ + guint aux_length = 5; /* Minimum length of the auxiliary header. */ /* Parse the security control field. */ security_control = tvb_get_guint8(tvb, offset); packet->security_level = (security_control & IEEE802154_AUX_SEC_LEVEL_MASK); packet->key_id_mode = (security_control & IEEE802154_AUX_KEY_ID_MODE_MASK) >> IEEE802154_AUX_KEY_ID_MODE_SHIFT; - /* Compute the length of the auxilliar header and create a subtree. */ + /* Compute the length of the auxiliary header and create a subtree. */ if (packet->key_id_mode != KEY_ID_MODE_IMPLICIT) aux_length++; if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_4) aux_length += 4; if (packet->key_id_mode == KEY_ID_MODE_KEY_EXPLICIT_8) aux_length += 8; @@ -1019,9 +1024,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g offset++; /* Display the command identifier in the info column. */ - if(check_col(pinfo->cinfo, COL_INFO)) { - col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command")); - } + col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet->command_id, ieee802154_cmd_names, "Unknown Command")); } /* No other frame types have nonpayload fields. */ @@ -1161,7 +1164,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && - (packet->dst.addr16 == IEEE802154_BCAST_ADDR) && + (packet->dst16 == IEEE802154_BCAST_ADDR) && (packet->src_pan == IEEE802154_BCAST_PAN) && (packet->dst_pan == IEEE802154_BCAST_PAN)); /* No payload expected. */ @@ -1171,7 +1174,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) && (packet->src_addr_mode == IEEE802154_FCF_ADDR_NONE) && - (packet->dst.addr16 == IEEE802154_BCAST_ADDR) && + (packet->dst16 == IEEE802154_BCAST_ADDR) && (packet->dst_pan == IEEE802154_BCAST_PAN)); /* No payload expected. */ break; @@ -1183,7 +1186,7 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g (packet->dst_addr_mode != IEEE802154_FCF_ADDR_NONE)); if (packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT) { /* If directed to a 16-bit address, check that it is being broadcast. */ - IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->dst.addr16 == IEEE802154_BCAST_ADDR); + IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, packet->dst16 == IEEE802154_BCAST_ADDR); } dissect_ieee802154_realign(payload_tvb, pinfo, ieee802154_tree, packet); break; @@ -1193,8 +1196,8 @@ dissect_ieee802154_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g IEEE802154_CMD_ADDR_CHECK(pinfo, proto_root, packet->command_id, (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_NONE) && - (packet->src.addr16 != IEEE802154_BCAST_ADDR) && - (packet->src.addr16 != IEEE802154_NO_ADDR16)); + (packet->src16 != IEEE802154_BCAST_ADDR) && + (packet->src16 != IEEE802154_NO_ADDR16)); dissect_ieee802154_gtsreq(payload_tvb, pinfo, ieee802154_tree, packet); break; @@ -1537,7 +1540,8 @@ dissect_ieee802154_assoc_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* Create a subtree for this command frame. */ if (tree) { - ti = proto_tree_add_text(tree, tvb, offset, 3, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command")); + ti = proto_tree_add_text(tree, tvb, offset, 3, "%s", val_to_str(packet->command_id, + ieee802154_cmd_names, "Unknown Command")); subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd); } @@ -1560,25 +1564,24 @@ dissect_ieee802154_assoc_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree offset += 1; /* Update the info column. */ - if (check_col(pinfo->cinfo, COL_INFO)) { - if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) { - /* Association was successful. */ - if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) { - col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_pan); - } - if (short_addr != IEEE802154_NO_ADDR16) { - col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr); - } + if (status == IEEE802154_CMD_ASRSP_AS_SUCCESS) { + /* Association was successful. */ + if (packet->src_addr_mode != IEEE802154_FCF_ADDR_SHORT) { + col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", packet->dst_pan); } - else { - /* Association was unsuccessful. */ - col_append_fstr(pinfo->cinfo, COL_INFO, ", Unsuccessful"); + if (short_addr != IEEE802154_NO_ADDR16) { + col_append_fstr(pinfo->cinfo, COL_INFO, " Addr: 0x%04x", short_addr); } } + else { + /* Association was unsuccessful. */ + col_append_fstr(pinfo->cinfo, COL_INFO, ", Unsuccessful"); + } /* Update the address table. */ if ((status == IEEE802154_CMD_ASRSP_AS_SUCCESS) && (short_addr != IEEE802154_NO_ADDR16)) { - ieee802154_addr_update(short_addr, packet->dst_pan, packet->dst.addr64); + ieee802154_addr_update(&ieee802154_addr, short_addr, packet->dst_pan, packet->dst64, + proto_ieee802154, pinfo->fd->num); } /* Call the data dissector for any leftover bytes. */ @@ -1614,7 +1617,7 @@ dissect_ieee802154_disassoc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd); } - /* Get and display the dissasociation reason. */ + /* Get and display the disassociation reason. */ reason = tvb_get_guint8(tvb, 0); if (tree) { ti = proto_tree_add_uint(subtree, hf_ieee802154_disassoc_reason, tvb, 0, 1, reason); @@ -1633,6 +1636,15 @@ dissect_ieee802154_disassoc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, } /* switch */ } + if (!pinfo->fd->flags.visited) { + /* Update the address tables */ + if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT ) { + ieee802154_long_addr_invalidate(packet->dst64, pinfo->fd->num); + } else if ( packet->dst_addr_mode == IEEE802154_FCF_ADDR_SHORT ) { + ieee802154_short_addr_invalidate(packet->dst16, packet->dst_pan, pinfo->fd->num); + } + } + /* Call the data dissector for any leftover bytes. */ if (tvb_length(tvb) > 1) { call_dissector(data_handle, tvb_new_subset(tvb, 1, -1, -1), pinfo, tree); @@ -1673,40 +1685,45 @@ dissect_ieee802154_realign(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, /* Get and display the command PAN ID. */ pan_id = tvb_get_letohs(tvb, offset); - if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_pan, tvb, offset, 2, pan_id); - if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id); + if (tree) + proto_tree_add_uint(subtree, hf_ieee802154_realign_pan, tvb, offset, 2, pan_id); + col_append_fstr(pinfo->cinfo, COL_INFO, ", PAN: 0x%04x", pan_id); offset += 2; /* Get and display the coordinator address. */ coord_addr = tvb_get_letohs(tvb, offset); - if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_caddr, tvb, offset, 2, coord_addr); - if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr); + if (tree) + proto_tree_add_uint(subtree, hf_ieee802154_realign_caddr, tvb, offset, 2, coord_addr); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Coordinator: 0x%04x", coord_addr); offset += 2; /* Get and display the channel. */ channel = tvb_get_guint8(tvb, offset); - if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_channel, tvb, offset, 1, channel); - if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel); + if (tree) + proto_tree_add_uint(subtree, hf_ieee802154_realign_channel, tvb, offset, 1, channel); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Channel: %u", channel); offset += 1; /* Get and display the short address. */ short_addr = tvb_get_letohs(tvb, offset); - if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_addr, tvb, offset, 2, short_addr); - if ( (check_col(pinfo->cinfo, COL_INFO)) - && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) + if (tree) + proto_tree_add_uint(subtree, hf_ieee802154_realign_addr, tvb, offset, 2, short_addr); + if ( (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT) && (short_addr != IEEE802154_NO_ADDR16)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Addr: 0x%04x", short_addr); } offset += 2; /* Update the address table. */ if ((short_addr != IEEE802154_NO_ADDR16) && (packet->dst_addr_mode == IEEE802154_FCF_ADDR_EXT)) { - ieee802154_addr_update(short_addr, packet->dst_pan, packet->dst.addr64); + ieee802154_addr_update(&ieee802154_addr, short_addr, packet->dst_pan, packet->dst64, + proto_ieee802154, pinfo->fd->num); } /* Get and display the channel page, if it exists. Added in IEEE802.15.4-2006 */ if (tvb_bytes_exist(tvb, offset, 1)) { guint8 channel_page = tvb_get_guint8(tvb, offset); - if (tree) proto_tree_add_uint(subtree, hf_ieee802154_realign_channel_page, tvb, offset, 1, channel_page); + if (tree) + proto_tree_add_uint(subtree, hf_ieee802154_realign_channel_page, tvb, offset, 1, channel_page); offset += 1; } @@ -1752,7 +1769,8 @@ dissect_ieee802154_gtsreq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, i /* Create a subtree for this command frame. */ if (tree) { - ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, "Unknown Command")); + ti = proto_tree_add_text(tree, tvb, 0, 1, "%s", val_to_str(packet->command_id, ieee802154_cmd_names, + "Unknown Command")); subtree = proto_item_add_subtree(ti, ett_ieee802154_cmd); } @@ -1812,6 +1830,9 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie guint M = IEEE802154_MIC_LENGTH(packet->security_level); gint captured_len; gint reported_len; + ieee802154_hints_t *ieee_hints; + + ieee_hints = p_get_proto_data(pinfo->fd, proto_ieee802154); /* Get the captured and on-the-wire length of the payload. */ reported_len = tvb_reported_length_remaining(tvb, offset) - IEEE802154_FCS_LEN - M; @@ -1855,26 +1876,14 @@ dissect_ieee802154_decrypt(tvbuff_t * tvb, guint offset, packet_info * pinfo, ie */ if (packet->src_addr_mode == IEEE802154_FCF_ADDR_EXT) { /* The source EUI-64 is included in the headers. */ - srcAddr = packet->src.addr64; - } - else if (packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) { - ieee802154_short_addr addr16; - ieee802154_long_addr * addr64; - - /* Try to lookup the EUI-64 from the address table. */ - addr16.addr = packet->src.addr16; - addr16.pan = packet->src_pan; - addr64 = (ieee802154_long_addr *)g_hash_table_lookup(ieee802154_addr_table, &addr16); - if (!addr64) { - /* Lookup failed. */ - *status = DECRYPT_PACKET_NO_EXT_SRC_ADDR; - return NULL; - } - /* Lookup successful. */ - srcAddr = addr64->addr; + srcAddr = packet->src64; + } + else if (ieee_hints && ieee_hints->map_rec && ieee_hints->map_rec->addr64) { + /* Use the hint */ + srcAddr = ieee_hints->map_rec->addr64; } else { - /* No addressing is present in the headers. We're screwed. */ + /* Lookup failed. */ *status = DECRYPT_PACKET_NO_EXT_SRC_ADDR; return NULL; } @@ -2194,6 +2203,175 @@ ccm_cbc_mac(const gchar *key _U_, const gchar *iv _U_, const gchar *a _U_, gint #endif } /* ccm_cbc_mac */ +/* Key hash function. */ +guint ieee802154_short_addr_hash(gconstpointer key) +{ + return (((ieee802154_short_addr *)key)->addr) | (((ieee802154_short_addr *)key)->pan << 16); +} + +/* Key equal function. */ +gboolean ieee802154_short_addr_equal(gconstpointer a, gconstpointer b) +{ + return (((ieee802154_short_addr *)a)->pan == ((ieee802154_short_addr *)b)->pan) && + (((ieee802154_short_addr *)a)->addr == ((ieee802154_short_addr *)b)->addr); +} + +/*FUNCTION:------------------------------------------------------ + * NAME + * ieee802154_addr_update + * DESCRIPTION + * Creates a record that maps the given short address and pan + * to a long (extended) address. Typically called when a + * successful association reponse is received. + * PARAMETERS + * guint16 short_addr - 16-bit short address + * guint16 pan - 16-bit PAN id + * guint64 long_addr - 64-bit long (extended) address + * guint - Frame number this mapping became valid + * RETURNS + * TRUE - Record was updated + * FALSE - Couldn't find it + *--------------------------------------------------------------- + */ +ieee802154_map_rec *ieee802154_addr_update(ieee802154_addr_t *ieee802154_addr, + guint16 short_addr, guint16 pan, guint64 long_addr, int proto, guint fnum) +{ + ieee802154_short_addr addr16; + ieee802154_map_rec *p_map_rec; + gpointer old_key; + + /* Look up short address hash */ + addr16.pan = pan; + addr16.addr = short_addr; + p_map_rec = g_hash_table_lookup(ieee802154_addr->short_table, &addr16); + + /* Update mapping record */ + if (p_map_rec) { + /* record already exists */ + if ( p_map_rec->addr64 == long_addr ) { + /* no change */ + return p_map_rec; + } + else { + /* mark current mapping record invalid */ + p_map_rec->end_fnum = fnum; + } + } + + /* create a new mapping record */ + p_map_rec = se_alloc(sizeof(ieee802154_map_rec)); + p_map_rec->proto = proto; + p_map_rec->start_fnum = fnum; + p_map_rec->end_fnum = 0; + p_map_rec->addr64 = long_addr; + + /* link new mapping record to addr hash tables */ + if ( g_hash_table_lookup_extended(ieee802154_addr->short_table, &addr16, &old_key, NULL) ) { + /* update short addr hash table, reusing pointer to old key */ + g_hash_table_insert(ieee802154_addr->short_table, &old_key, p_map_rec); + } else { + /* create new hash entry */ + g_hash_table_insert(ieee802154_addr->short_table, se_memdup(&addr16, sizeof(addr16)), p_map_rec); + } + + if ( g_hash_table_lookup_extended(ieee802154_addr->long_table, &long_addr, &old_key, NULL) ) { + /* update long addr hash table, reusing pointer to old key */ + g_hash_table_insert(ieee802154_addr->long_table, &old_key, p_map_rec); + } else { + /* create new hash entry */ + g_hash_table_insert(ieee802154_addr->long_table, se_memdup(&long_addr, sizeof(long_addr)), p_map_rec); + } + + return p_map_rec; +} /* ieee802154_addr_update */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * ieee802154_short_addr_invalidate + * DESCRIPTION + * Marks a mapping record associated with device with short_addr + * as invalid at a certain frame number, typically when a + * dissassociation occurs. + * PARAMETERS + * guint16 short_addr - 16-bit short address + * guint16 pan - 16-bit PAN id + * guint - Frame number when mapping became invalid + * RETURNS + * TRUE - Record was updated + * FALSE - Couldn't find it + *--------------------------------------------------------------- + */ +gboolean ieee802154_short_addr_invalidate(guint16 short_addr, guint16 pan, guint fnum) +{ + ieee802154_short_addr addr16; + ieee802154_map_rec *map_rec; + + addr16.pan = pan; + addr16.addr = short_addr; + + map_rec = g_hash_table_lookup(ieee802154_addr.short_table, &addr16); + if ( map_rec ) { + /* indicates this mapping is invalid at frame fnum */ + map_rec->end_fnum = fnum; + return TRUE; + } + + return FALSE; +} /* ieee802154_short_addr_invalidate */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * ieee802154_long_addr_invalidate + * DESCRIPTION + * Marks a mapping record associated with device with long_addr + * as invalid at a certain frame number, typically when a + * dissassociation occurs. + * PARAMETERS + * guint64 long_addr - 16-bit short address + * guint - Frame number when mapping became invalid + * RETURNS + * TRUE - If record was updated + * FALSE - If record wasn't updated + *--------------------------------------------------------------- + */ +gboolean ieee802154_long_addr_invalidate(guint64 long_addr, guint fnum) +{ + ieee802154_map_rec *map_rec; + + map_rec = g_hash_table_lookup(ieee802154_addr.long_table, &long_addr); + if ( map_rec ) { + /* indicates this mapping is invalid at frame fnum */ + map_rec->end_fnum = fnum; + return TRUE; + } + + return FALSE; +} /* ieee802154_long_addr_invalidate */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_tree_add_eui64 + * DESCRIPTION + * Helper function to display an EUI-64 address to the tree. + * PARAMETERS + * proto_tree *tree + * int hfindex + * tvbuff_t *tvb + * gint start + * gint length + * guint64 value; + * RETURNS + * proto_item * + *--------------------------------------------------------------- + */ +proto_item * +proto_tree_add_eui64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, gint64 value) +{ + header_field_info *hf = proto_registrar_get_nth(hfindex); + return proto_tree_add_uint64_format(tree, hfindex, tvb, start, length, value, "%s: %s (%s)", + hf->name, print_eui64_oui(value), print_eui64(value)); +} + /*FUNCTION:------------------------------------------------------ * NAME * proto_register_ieee802154 @@ -2220,14 +2398,14 @@ void proto_register_ieee802154(void) NULL, HFILL }}, { &hf_ieee802154_nonask_phy_length, - { "Frame Length", "wpan-nonask-phy.frame_length", FT_UINT8, BASE_HEX, NULL, IEEE802154_PHY_LENGTH_MASK, - NULL, HFILL }}, + { "Frame Length", "wpan-nonask-phy.frame_length", FT_UINT8, BASE_HEX, NULL, + IEEE802154_PHY_LENGTH_MASK, NULL, HFILL }}, }; static hf_register_info hf[] = { { &hf_ieee802154_frame_type, - { "Frame Type", "wpan.frame_type", FT_UINT16, BASE_HEX, VALS(ieee802154_frame_types), IEEE802154_FCF_TYPE_MASK, - NULL, HFILL }}, + { "Frame Type", "wpan.frame_type", FT_UINT16, BASE_HEX, VALS(ieee802154_frame_types), + IEEE802154_FCF_TYPE_MASK, NULL, HFILL }}, { &hf_ieee802154_security, { "Security Enabled", "wpan.security", FT_BOOLEAN, 16, NULL, IEEE802154_FCF_SEC_EN, @@ -2250,12 +2428,12 @@ void proto_register_ieee802154(void) NULL, HFILL }}, { &hf_ieee802154_dst_addr_mode, - { "Destination Addressing Mode", "wpan.dst_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), IEEE802154_FCF_DADDR_MASK, - NULL, HFILL }}, + { "Destination Addressing Mode", "wpan.dst_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), + IEEE802154_FCF_DADDR_MASK, NULL, HFILL }}, { &hf_ieee802154_src_addr_mode, - { "Source Addressing Mode", "wpan.src_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), IEEE802154_FCF_SADDR_MASK, - NULL, HFILL }}, + { "Source Addressing Mode", "wpan.src_addr_mode", FT_UINT16, BASE_HEX, VALS(ieee802154_addr_modes), + IEEE802154_FCF_SADDR_MASK, NULL, HFILL }}, { &hf_ieee802154_version, { "Frame Version", "wpan.version", FT_UINT16, BASE_DEC, NULL, IEEE802154_FCF_VERSION, @@ -2277,12 +2455,16 @@ void proto_register_ieee802154(void) { "Source PAN", "wpan.src_pan", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, - { &hf_ieee802154_src_addr16, - { "Source", "wpan.src_addr16", FT_UINT16, BASE_HEX, NULL, 0x0, + { &hf_ieee802154_src16, + { "Source", "wpan.src16", FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_ieee802154_src64, + { "Extended Source", "wpan.src64", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }}, - { &hf_ieee802154_src_addr64, - { "Source", "wpan.src_addr64", FT_UINT64, BASE_HEX, NULL, 0x0, + { &hf_ieee802154_src64_origin, + { "Origin", "wpan.src64.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_ieee802154_fcs, @@ -2386,7 +2568,8 @@ void proto_register_ieee802154(void) "Specifies the transmission interval of the beacons.", HFILL }}, { &hf_ieee802154_superframe_order, - { "Superframe Interval", "wpan.superframe_order", FT_UINT16, BASE_DEC, NULL, IEEE802154_SUPERFRAME_ORDER_MASK, + { "Superframe Interval", "wpan.superframe_order", FT_UINT16, BASE_DEC, NULL, + IEEE802154_SUPERFRAME_ORDER_MASK, "Specifies the length of time the coordinator will interact with the PAN.", HFILL }}, { &hf_ieee802154_cap, @@ -2428,11 +2611,12 @@ void proto_register_ieee802154(void) /* Auxiliary Security Header Fields */ /*----------------------------------*/ { &hf_ieee802154_security_level, - { "Security Level", "wpan.aux_sec.sec_level", FT_UINT8, BASE_HEX, VALS(ieee802154_sec_level_names), IEEE802154_AUX_SEC_LEVEL_MASK, - "The Security Level of the frame", HFILL }}, + { "Security Level", "wpan.aux_sec.sec_level", FT_UINT8, BASE_HEX, VALS(ieee802154_sec_level_names), + IEEE802154_AUX_SEC_LEVEL_MASK, "The Security Level of the frame", HFILL }}, { &hf_ieee802154_key_id_mode, - { "Key Identifier Mode", "wpan.aux_sec.key_id_mode", FT_UINT8, BASE_HEX, VALS(ieee802154_key_id_mode_names), IEEE802154_AUX_KEY_ID_MODE_MASK, + { "Key Identifier Mode", "wpan.aux_sec.key_id_mode", FT_UINT8, BASE_HEX, VALS(ieee802154_key_id_mode_names), + IEEE802154_AUX_KEY_ID_MODE_MASK, "The scheme to use by the recipient to lookup the key in its key table", HFILL }}, { &hf_ieee802154_aux_sec_reserved, @@ -2487,8 +2671,10 @@ void proto_register_ieee802154(void) register_init_routine(proto_init_ieee802154); /* Register Protocol name and description. */ - proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN", "IEEE 802.15.4", "wpan"); - proto_ieee802154_nonask_phy = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN non-ASK PHY", "IEEE 802.15.4 non-ASK PHY", "wpan-nonask-phy"); + proto_ieee802154 = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN", "IEEE 802.15.4", + IEEE802154_PROTOABBREV_WPAN); + proto_ieee802154_nonask_phy = proto_register_protocol("IEEE 802.15.4 Low-Rate Wireless PAN non-ASK PHY", + "IEEE 802.15.4 non-ASK PHY", "wpan-nonask-phy"); /* Register header fields and subtrees. */ proto_register_field_array(proto_ieee802154, hf, array_length(hf)); @@ -2498,7 +2684,7 @@ void proto_register_ieee802154(void) /* add a user preference to set the 802.15.4 ethertype */ ieee802154_module = prefs_register_protocol(proto_ieee802154, - proto_reg_handoff_ieee802154); + proto_reg_handoff_ieee802154); prefs_register_uint_preference(ieee802154_module, "802154_ethertype", "802.15.4 Ethertype (in hex)", "(Hexadecimal) Ethertype used to indicate IEEE 802.15.4 frame.", @@ -2508,8 +2694,8 @@ void proto_register_ieee802154(void) "Set if the FCS field is in TI CC24xx format.", &ieee802154_cc24xx); prefs_register_bool_preference(ieee802154_module, "802154_fcs_ok", - "Dissect data only if FCS is ok", - "Dissect data only if FCS is ok.", + "Dissect only good FCS", + "Dissect payload only if FCS is valid.", &ieee802154_fcs_ok); /* Create a UAT for static address mappings. */ @@ -2537,10 +2723,10 @@ void proto_register_ieee802154(void) "128-bit decryption key in hexadecimal format", (const char **)&ieee802154_key_str); /* Register the subdissector list */ - register_heur_dissector_list("wpan", &ieee802154_heur_subdissector_list); + register_heur_dissector_list(IEEE802154_PROTOABBREV_WPAN, &ieee802154_heur_subdissector_list); /* Register dissectors with Wireshark. */ - register_dissector("wpan", dissect_ieee802154, proto_ieee802154); + register_dissector(IEEE802154_PROTOABBREV_WPAN, dissect_ieee802154, proto_ieee802154); register_dissector("wpan_nofcs", dissect_ieee802154_nofcs, proto_ieee802154); register_dissector("wpan_cc24xx", dissect_ieee802154_cc24xx, proto_ieee802154); register_dissector("wpan-nonask-phy", dissect_ieee802154_nonask_phy, proto_ieee802154_nonask_phy); @@ -2571,7 +2757,7 @@ void proto_reg_handoff_ieee802154(void) if (!prefs_initialized){ /* Get the dissector handles. */ - ieee802154_handle = find_dissector("wpan"); + ieee802154_handle = find_dissector(IEEE802154_PROTOABBREV_WPAN); ieee802154_nonask_phy_handle = find_dissector("wpan-nonask-phy"); ieee802154_nofcs_handle = find_dissector("wpan_nofcs"); data_handle = find_dissector("data"); @@ -2604,9 +2790,9 @@ void proto_reg_handoff_ieee802154(void) * NAME * proto_init_ieee802154 * DESCRIPTION - * Init routine for the IEEE 802.15.4 dissector. Creates a - * hash table for mapping 16-bit to 64-bit addresses and - * populates it with static address pairs from a UAT + * Init routine for the IEEE 802.15.4 dissector. Creates hash + * tables for mapping between 16-bit to 64-bit addresses and + * populates them with static address pairs from a UAT * preference table. * PARAMETERS * none @@ -2619,16 +2805,17 @@ proto_init_ieee802154(void) { guint i; - /* Destroy the hash table, if it exists. */ - if (ieee802154_addr_table) - g_hash_table_destroy(ieee802154_addr_table); + /* Destroy hash tables, if they exist. */ + if (ieee802154_addr.short_table) g_hash_table_destroy(ieee802154_addr.short_table); + if (ieee802154_addr.long_table) g_hash_table_destroy(ieee802154_addr.long_table); - /* (Re)create the hash table. */ - ieee802154_addr_table = g_hash_table_new(ieee802154_addr_hash, ieee802154_addr_equals); + /* Create the hash tables. */ + ieee802154_addr.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal); + ieee802154_addr.long_table = g_hash_table_new(g_int64_hash, g_int64_equal); /* Re-load the hash table from the static address UAT. */ for (i=0; (i<num_static_addrs) && (static_addrs); i++) { - ieee802154_addr_update((guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan, pntoh64(static_addrs[i].eui64)); + ieee802154_addr_update(&ieee802154_addr,(guint16)static_addrs[i].addr16, (guint16)static_addrs[i].pan, + pntoh64(static_addrs[i].eui64), proto_ieee802154, IEEE802154_USER_MAPPING); } /* for */ } /* proto_init_ieee802154 */ - diff --git a/epan/dissectors/packet-ieee802154.h b/epan/dissectors/packet-ieee802154.h index 428f573359..a4a8c0624e 100644 --- a/epan/dissectors/packet-ieee802154.h +++ b/epan/dissectors/packet-ieee802154.h @@ -27,6 +27,9 @@ #ifndef PACKET_IEEE802154_H #define PACKET_IEEE802154_H +/* Protocol Abbreviation */ +#define IEEE802154_PROTOABBREV_WPAN "wpan" + /* Packet Overhead from MAC header + footer (excluding addressing) */ #define IEEE802154_MAX_FRAME_LEN 127 #define IEEE802154_FCS_LEN 2 @@ -48,7 +51,7 @@ #define IEEE802154_CMD_ASRSP_PAN_FULL 0x01 #define IEEE802154_CMD_ASRSP_PAN_DENIED 0x02 -/* Bit Masks for Capability Information Feild +/* Bit Masks for Capability Information Field Included in Association Req. command */ #define IEEE802154_CMD_CINFO_ALT_PAN_COORD 0x01 #define IEEE802154_CMD_CINFO_DEVICE_TYPE 0x02 @@ -99,7 +102,7 @@ #define IEEE802154_FCF_SEC_EN 0x0008 #define IEEE802154_FCF_FRAME_PND 0x0010 #define IEEE802154_FCF_ACK_REQ 0x0020 -#define IEEE802154_FCF_INTRA_PAN 0x0040 +#define IEEE802154_FCF_INTRA_PAN 0x0040 /* known as PAN ID Compression in IEEE 802.15.4-2006 */ #define IEEE802154_FCF_DADDR_MASK 0x0C00 /* destination addressing mask */ #define IEEE802154_FCF_VERSION 0x3000 #define IEEE802154_FCF_SADDR_MASK 0xC000 /* source addressing mask */ @@ -164,7 +167,7 @@ typedef enum { /* Macro to check for payload encryption. */ #define IEEE802154_IS_ENCRYPTED(_level_) ((_level_) & 0x4) -/* Structure containing information regarding all necessary packet feilds. */ +/* Structure containing information regarding all necessary packet fields. */ typedef struct { /* Frame control field. */ gint32 version; @@ -180,15 +183,11 @@ typedef struct { /* Addressing Info. */ guint16 dst_pan; - union { - guint16 addr16; - guint64 addr64; - } dst; guint16 src_pan; - union { - guint16 addr16; - guint64 addr64; - } src; + guint16 dst16; + guint64 dst64; + guint16 src16; + guint64 src64; /* Security Info. */ ieee802154_security_level security_level; @@ -202,11 +201,49 @@ typedef struct { /* Command ID (only if frame_type == 0x3) */ guint8 command_id; + GHashTable *short_table; } ieee802154_packet; +typedef struct { + guint proto; + GHashTable *long_table; + GHashTable *short_table; +} ieee802154_addr_t; + +/* Key used by the short address hash table. */ +typedef struct { + guint16 pan; + guint16 addr; +} ieee802154_short_addr; + +/* A mapping record for a frame, pointed to by hash table */ +typedef struct { + int proto; /* protocol that created this record */ + guint start_fnum; + guint end_fnum; + guint64 addr64; + /*guint32 frame_counter; TODO for frame counter sequence checks. */ +} ieee802154_map_rec; + +#define IEEE802154_USER_MAPPING 0 + +typedef struct { + guint16 src_pan; + guint16 src16; + ieee802154_map_rec *map_rec; +} ieee802154_hints_t; /* Some Helper Function Definitions. */ -extern gchar *print_eui64(guint64); -extern gchar *print_eui64_oui(guint64); +extern gchar *print_eui64(guint64); +extern gchar *print_eui64_oui(guint64); +extern proto_item *proto_tree_add_eui64(proto_tree *, int, tvbuff_t *, gint, gint, gint64); + +/* Short to Extended Address Prototypes */ +extern ieee802154_map_rec *ieee802154_addr_update(ieee802154_addr_t *, guint16, guint16, guint64, int, guint); +extern guint ieee802154_short_addr_hash(gconstpointer); +extern gboolean ieee802154_short_addr_equal(gconstpointer, gconstpointer); + +static gboolean ieee802154_short_addr_invalidate(guint16, guint16, guint); +static gboolean ieee802154_long_addr_invalidate(guint64, guint); #endif /* PACKET_IEEE802154_H */ diff --git a/epan/dissectors/packet-zbee-aps.c b/epan/dissectors/packet-zbee-aps.c index 48cc7b84e6..27e78d549f 100644 --- a/epan/dissectors/packet-zbee-aps.c +++ b/epan/dissectors/packet-zbee-aps.c @@ -39,9 +39,9 @@ #include <epan/reassemble.h> #include "packet-zbee.h" +#include "packet-zbee-nwk.h" #include "packet-zbee-security.h" #include "packet-zbee-aps.h" -#include "packet-zbee-nwk.h" /************************* * Function Declarations * @@ -67,6 +67,8 @@ static guint dissect_zbee_aps_tunnel (tvbuff_t *tvb, packet_info *pinf /* Helper routine. */ static guint zbee_apf_transaction_len (tvbuff_t *tvb, guint offset, guint8 type); +static void proto_init_zbee_aps(void); + /******************** * Global Variables * ******************** @@ -76,7 +78,7 @@ static int proto_zbee_aps = -1; static int hf_zbee_aps_fcf_frame_type = -1; static int hf_zbee_aps_fcf_delivery = -1; static int hf_zbee_aps_fcf_indirect_mode = -1; /* ZigBee 2004 and earlier. */ -static int hf_zbee_aps_fcf_ack_mode = -1; /* ZigBee 2007 and later. */ +static int hf_zbee_aps_fcf_ack_format = -1; /* ZigBee 2007 and later. */ static int hf_zbee_aps_fcf_security = -1; static int hf_zbee_aps_fcf_ack_req = -1; static int hf_zbee_aps_fcf_ext_header = -1; @@ -165,6 +167,7 @@ static const fragment_items zbee_aps_frag_items = { /* Tag */ "APS Message fragments" }; + /********************/ /* Field Names */ /********************/ @@ -538,7 +541,7 @@ const value_string zbee_aps_cid_names[] = { * ZigBee Application Support Sublayer dissector for wireshark. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. - * packet_into *pinfo - pointer to packet information fields + * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * RETURNS * void @@ -577,7 +580,7 @@ dissect_zbee_aps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) packet.type = zbee_get_bit_field(fcf, ZBEE_APS_FCF_FRAME_TYPE); packet.delivery = zbee_get_bit_field(fcf, ZBEE_APS_FCF_DELIVERY_MODE); packet.indirect_mode = zbee_get_bit_field(fcf, ZBEE_APS_FCF_INDIRECT_MODE); - packet.ack_mode = zbee_get_bit_field(fcf, ZBEE_APS_FCF_ACK_MODE); + packet.ack_format = zbee_get_bit_field(fcf, ZBEE_APS_FCF_ACK_FORMAT); packet.security = zbee_get_bit_field(fcf, ZBEE_APS_FCF_SECURITY); packet.ack_req = zbee_get_bit_field(fcf, ZBEE_APS_FCF_ACK_REQ); packet.ext_header = zbee_get_bit_field(fcf, ZBEE_APS_FCF_EXT_HEADER); @@ -603,7 +606,7 @@ dissect_zbee_aps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) { /* ZigBee 2007 and later uses an ack mode flag. */ if (packet.type == ZBEE_APS_FCF_ACK) { - proto_tree_add_boolean(field_tree, hf_zbee_aps_fcf_ack_mode, tvb, offset, sizeof(guint8), fcf & ZBEE_APS_FCF_ACK_MODE); + proto_tree_add_boolean(field_tree, hf_zbee_aps_fcf_ack_format, tvb, offset, sizeof(guint8), fcf & ZBEE_APS_FCF_ACK_FORMAT); } } else { @@ -627,7 +630,7 @@ dissect_zbee_aps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) break; case ZBEE_APS_FCF_ACK: - if ((pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) && (packet.ack_mode)) { + if ((pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) && (packet.ack_format)) { /* Command Ack: endpoint addressing does not exist. */ goto dissect_zbee_aps_no_endpt; } @@ -719,17 +722,17 @@ dissect_zbee_aps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) offset += sizeof(guint8); } - /* Get and display the profile ID if it exists. */ + /* Get and display the profile ID. */ packet.profile = tvb_get_letohs(tvb, offset); profile_handle = dissector_get_port_handle(zbee_aps_dissector_table, packet.profile); if (tree) { ti = proto_tree_add_uint(aps_tree, hf_zbee_aps_profile, tvb, offset, sizeof(guint16), packet.profile); - offset += sizeof(guint16); /* Update the protocol root and info column later, after the source endpoint * so that the source and destination will be back-to-back in the text. */ - } + } + offset += sizeof(guint16); /* The source endpoint is present for all cases except indirect /w indirect_mode == FALSE */ if ((packet.delivery != ZBEE_APS_FCF_INDIRECT) || (!packet.indirect_mode)) { @@ -762,7 +765,6 @@ dissect_zbee_aps_no_endpt: offset += sizeof(guint8); } - /* Get and display the extended header, if present. */ if (packet.ext_header) { fcf = tvb_get_guint8(tvb, offset); @@ -1144,9 +1146,12 @@ dissect_zbee_aps_skke_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr static guint dissect_zbee_aps_transport_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset) { - guint8 key_type; - gchar *key = ep_alloc(ZBEE_APS_CMD_KEY_LENGTH); - guint i; + guint8 key_type; + guint8 key[ZBEE_APS_CMD_KEY_LENGTH]; + GSList **nwk_keyring; + key_record_t key_record; + zbee_nwk_hints_t *nwk_hints; + guint i; /* Get and display the key type. */ key_type = tvb_get_guint8(tvb, offset); @@ -1158,21 +1163,46 @@ dissect_zbee_aps_transport_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree /* Coincidentally, all the key descriptors start with the key. So * get and display it. */ - for (i=0;i<ZBEE_APS_CMD_KEY_LENGTH; i++) { - /* Copy the key in while swapping because the key is transmitted in little-endian - * order, but we want to display it in big-endian. - */ - key[(ZBEE_APS_CMD_KEY_LENGTH-1)-i] = tvb_get_guint8(tvb, offset+i); + for (i=0; i<ZBEE_APS_CMD_KEY_LENGTH ; i++) { + key[i] = tvb_get_guint8(tvb, offset+i); } /* for */ if (tree) { proto_tree_add_bytes(tree, hf_zbee_aps_cmd_key, tvb, offset, ZBEE_APS_CMD_KEY_LENGTH, key); } offset += ZBEE_APS_CMD_KEY_LENGTH; + + /* Update the key ring for this pan */ + if ( !pinfo->fd->flags.visited && + (nwk_hints = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK)))) { + + nwk_keyring = g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); + if ( !nwk_keyring ) { + /* Create an empty key ring for this pan. Use g_alloc() because we must free + * GSLists after a capture is closed and wireshark freed seasonal memory + * with se_free_all() + */ + nwk_keyring = g_malloc0(sizeof(GSList**)); + g_hash_table_insert(zbee_table_nwk_keyring, + g_memdup(&nwk_hints->src_pan, sizeof(nwk_hints->src_pan)), nwk_keyring); + } + + if ( nwk_keyring ) { + if ( !*nwk_keyring || + memcmp( ((key_record_t *)((GSList *)(*nwk_keyring))->data)->key, &key, + ZBEE_APS_CMD_KEY_LENGTH) ) { + /* Store a new or different key in the key ring */ + key_record.frame_num = pinfo->fd->num; + key_record.label = NULL; + memcpy(&key_record.key, &key, ZBEE_APS_CMD_KEY_LENGTH); + *nwk_keyring = g_slist_prepend(*nwk_keyring, se_memdup(&key_record, sizeof(key_record_t))); + } + } + } /* Parse the rest of the key descriptor. */ switch (key_type) { case ZBEE_APS_CMD_KEY_STANDARD_NWK: - case ZBEE_APS_CMD_KEY_HIGH_SEC_NWK:{ + case ZBEE_APS_CMD_KEY_HIGH_SEC_NWK: { /* Network Key */ guint8 seqno; guint64 src; @@ -1229,7 +1259,7 @@ dissect_zbee_aps_transport_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree guint64 partner; guint8 initiator; - /* get and display the parter address. */ + /* get and display the partner address. */ partner = tvb_get_letoh64(tvb, offset); if (tree) { proto_tree_add_eui64(tree, hf_zbee_aps_cmd_partner, tvb, offset, sizeof(guint64), partner); @@ -1457,7 +1487,8 @@ dissect_zbee_aps_auth_challenge(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tre /* Get and display the challenge. */ tvb_ensure_bytes_exist(tvb, offset, ZBEE_APS_CMD_EA_CHALLENGE_LENGTH); if (tree) { - proto_tree_add_bytes(tree, hf_zbee_aps_cmd_challenge, tvb, offset, ZBEE_APS_CMD_EA_CHALLENGE_LENGTH, ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_CHALLENGE_LENGTH)); + proto_tree_add_bytes(tree, hf_zbee_aps_cmd_challenge, tvb, offset, ZBEE_APS_CMD_EA_CHALLENGE_LENGTH, + ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_CHALLENGE_LENGTH)); } offset += ZBEE_APS_CMD_EA_CHALLENGE_LENGTH; @@ -1488,7 +1519,8 @@ dissect_zbee_aps_auth_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr /* Get and display the MAC. */ tvb_ensure_bytes_exist(tvb, offset, ZBEE_APS_CMD_EA_MAC_LENGTH); if (tree) { - proto_tree_add_bytes(tree, hf_zbee_aps_cmd_mac, tvb, offset, ZBEE_APS_CMD_EA_MAC_LENGTH, ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_MAC_LENGTH)); + proto_tree_add_bytes(tree, hf_zbee_aps_cmd_mac, tvb, offset, ZBEE_APS_CMD_EA_MAC_LENGTH, + ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_MAC_LENGTH)); } offset += ZBEE_APS_CMD_EA_MAC_LENGTH; @@ -1508,7 +1540,8 @@ dissect_zbee_aps_auth_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tr /* Get and display the data field. */ tvb_ensure_bytes_exist(tvb, offset, ZBEE_APS_CMD_EA_DATA_LENGTH); if (tree) { - proto_tree_add_bytes(tree, hf_zbee_aps_cmd_ea_data, tvb, offset, ZBEE_APS_CMD_EA_DATA_LENGTH, ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_DATA_LENGTH)); + proto_tree_add_bytes(tree, hf_zbee_aps_cmd_ea_data, tvb, offset, ZBEE_APS_CMD_EA_DATA_LENGTH, + ep_tvb_memdup(tvb, offset, ZBEE_APS_CMD_EA_DATA_LENGTH)); } offset += ZBEE_APS_CMD_EA_DATA_LENGTH; @@ -1545,7 +1578,8 @@ dissect_zbee_aps_tunnel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gui offset += sizeof(guint64); /* The remainder is a tunneled APS frame. */ - tunnel_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), tvb_reported_length_remaining(tvb, offset)); + tunnel_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), + tvb_reported_length_remaining(tvb, offset)); if (tree) root = proto_tree_get_root(tree); call_dissector(zbee_aps_handle, tunnel_tvb, pinfo, root); offset = tvb_length(tvb); @@ -1585,7 +1619,8 @@ static void dissect_zbee_apf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree /* Create the tree for the application framework. */ if (tree) { - proto_root = proto_tree_add_protocol_format(tree, proto_zbee_apf, tvb, 0, tvb_length(tvb), "ZigBee Application Framework"); + proto_root = proto_tree_add_protocol_format(tree, proto_zbee_apf, tvb, 0, + tvb_length(tvb), "ZigBee Application Framework"); apf_tree = proto_item_add_subtree(proto_root, ett_zbee_apf); } @@ -1719,24 +1754,6 @@ zbee_apf_transaction_len(tvbuff_t *tvb, guint offset, guint8 type) /*FUNCTION:------------------------------------------------------ * NAME - * proto_init_zbee_aps - * DESCRIPTION - * Initializes the APS dissectors prior to beginning protocol - * dissection. - * PARAMETERS - * none - * RETURNS - * void - *--------------------------------------------------------------- - */ -static void proto_init_zbee_aps(void) -{ - fragment_table_init(&zbee_aps_fragment_table); - reassembled_table_init(&zbee_aps_reassembled_table); -} /* proto_init_zbee_aps */ - -/*FUNCTION:------------------------------------------------------ - * NAME * proto_register_zbee_aps * DESCRIPTION * ZigBee APS protocol registration routine. @@ -1761,8 +1778,8 @@ void proto_register_zbee_aps(void) { "Indirect Address Mode", "zbee.aps.indirect_mode", FT_BOOLEAN, 8, NULL, ZBEE_APS_FCF_INDIRECT_MODE, NULL, HFILL }}, - { &hf_zbee_aps_fcf_ack_mode, - { "Acknowledgement Mode", "zbee.aps.ack_mode", FT_BOOLEAN, 8, NULL, ZBEE_APS_FCF_ACK_MODE, + { &hf_zbee_aps_fcf_ack_format, + { "Acknowledgement Format", "zbee.aps.ack_format", FT_BOOLEAN, 8, NULL, ZBEE_APS_FCF_ACK_FORMAT, NULL, HFILL }}, { &hf_zbee_aps_fcf_security, @@ -1941,24 +1958,24 @@ void proto_register_zbee_aps(void) }; /* Register ZigBee APS protocol with Wireshark. */ - proto_zbee_aps = proto_register_protocol("ZigBee Application Support Layer", "ZigBee APS", "zbee.aps"); + proto_zbee_aps = proto_register_protocol("ZigBee Application Support Layer", "ZigBee APS", ZBEE_PROTOABBREV_APS); proto_register_field_array(proto_zbee_aps, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* Register the APS dissector and subdissector list. */ zbee_aps_dissector_table = register_dissector_table("zbee.profile", "ZigBee Profile ID", FT_UINT16, BASE_HEX); - register_dissector("zbee.aps", dissect_zbee_aps, proto_zbee_aps); + register_dissector(ZBEE_PROTOABBREV_APS, dissect_zbee_aps, proto_zbee_aps); /* Register the init routine. */ register_init_routine(proto_init_zbee_aps); /* Register the ZigBee Application Framework protocol with Wireshark. */ - proto_zbee_apf = proto_register_protocol("ZigBee Application Framework", "ZigBee APF", "zbee.apf"); + proto_zbee_apf = proto_register_protocol("ZigBee Application Framework", "ZigBee APF", ZBEE_PROTOABBREV_APF); proto_register_field_array(proto_zbee_apf, hf_apf, array_length(hf_apf)); proto_register_subtree_array(ett_apf, array_length(ett_apf)); /* Register the App dissector. */ - register_dissector("zbee.apf", dissect_zbee_apf, proto_zbee_apf); + register_dissector(ZBEE_PROTOABBREV_APF, dissect_zbee_apf, proto_zbee_apf); } /* proto_register_zbee_aps */ /*FUNCTION:------------------------------------------------------ @@ -1976,7 +1993,25 @@ void proto_reg_handoff_zbee_aps(void) { /* Find the other dissectors we need. */ data_handle = find_dissector("data"); - zbee_aps_handle = find_dissector("zbee.aps"); - zbee_apf_handle = find_dissector("zbee.apf"); + zbee_aps_handle = find_dissector(ZBEE_PROTOABBREV_APS); + zbee_apf_handle = find_dissector(ZBEE_PROTOABBREV_APF); } /* proto_reg_handoff_zbee_aps */ +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_init_zbee_aps + * DESCRIPTION + * Initializes the APS dissectors prior to beginning protocol + * dissection. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void proto_init_zbee_aps(void) +{ + fragment_table_init(&zbee_aps_fragment_table); + reassembled_table_init(&zbee_aps_reassembled_table); +} /* proto_init_zbee_aps */ + diff --git a/epan/dissectors/packet-zbee-aps.h b/epan/dissectors/packet-zbee-aps.h index eb106d81e2..d8aa4b1e20 100644 --- a/epan/dissectors/packet-zbee-aps.h +++ b/epan/dissectors/packet-zbee-aps.h @@ -27,39 +27,11 @@ #ifndef PACKET_ZBEE_APS_H #define PACKET_ZBEE_APS_H -/* Structure to contain the APS frame information */ -typedef struct{ - gboolean indirect_mode; /* ZigBee 2004 and Earlier */ - gboolean ack_mode; /* ZigBee 2007 and Later */ - gboolean security; - gboolean ack_req; - gboolean ext_header; /* ZigBee 2007 and Later */ - guint8 type; - guint8 delivery; - - guint8 dst; - guint16 group; /* ZigBee 2006 and Later */ - guint16 cluster; - guint16 profile; - guint8 src; - guint8 counter; - - /* Fragmentation Fields. */ - guint8 fragmentation; /* ZigBee 2007 and Later */ - guint8 block_number; /* ZigBee 2007 and Later */ - guint8 ack_bitfield; /* ZigBee 2007 and Later */ - - /* Some helpers for the upper layers. */ - gboolean profile_present; - gboolean dst_present; - gboolean src_present; -} zbee_aps_packet; - /* ZigBee APS */ #define ZBEE_APS_FCF_FRAME_TYPE 0x03 #define ZBEE_APS_FCF_DELIVERY_MODE 0x0c #define ZBEE_APS_FCF_INDIRECT_MODE 0x10 /* ZigBee 2004 and earlier. */ -#define ZBEE_APS_FCF_ACK_MODE 0x10 /* ZigBee 2007 and later. */ +#define ZBEE_APS_FCF_ACK_FORMAT 0x10 /* ZigBee 2007 and later. */ #define ZBEE_APS_FCF_SECURITY 0x20 #define ZBEE_APS_FCF_ACK_REQ 0x40 #define ZBEE_APS_FCF_EXT_HEADER 0x80 @@ -234,4 +206,32 @@ typedef struct{ #define ZBEE_ZCL_CID_SMART_ENERGY_TUNNELING 0x0704 #define ZBEE_ZCL_CID_PRE_PAYMENT 0x0705 +/* Structure to contain the APS frame information */ +typedef struct{ + gboolean indirect_mode; /* ZigBee 2004 and Earlier */ + guint8 type; + guint8 delivery; + gboolean ack_format; /* ZigBee 2007 and Later */ + gboolean security; + gboolean ack_req; + gboolean ext_header; /* ZigBee 2007 and Later */ + + guint8 dst; + guint16 group; /* ZigBee 2006 and Later */ + guint16 cluster; + guint16 profile; + guint8 src; + guint8 counter; + + /* Fragmentation Fields. */ + guint8 fragmentation; /* ZigBee 2007 and Later */ + guint8 block_number; /* ZigBee 2007 and Later */ + guint8 ack_bitfield; /* ZigBee 2007 and Later */ + + /* Some helpers for the upper layers. */ + gboolean profile_present; + gboolean dst_present; + gboolean src_present; +} zbee_aps_packet; + #endif /* PACKET_ZBEE_APS_H*/ diff --git a/epan/dissectors/packet-zbee-nwk.c b/epan/dissectors/packet-zbee-nwk.c index 006220a53e..1023171ada 100644 --- a/epan/dissectors/packet-zbee-nwk.c +++ b/epan/dissectors/packet-zbee-nwk.c @@ -40,9 +40,10 @@ #include <epan/expert.h> #include <epan/value_string.h> +#include "packet-ieee802154.h" #include "packet-zbee.h" -#include "packet-zbee-security.h" #include "packet-zbee-nwk.h" +#include "packet-zbee-security.h" /*************************/ /* Function Declarations */ @@ -53,16 +54,21 @@ static void dissect_zbee_nwk_cmd (tvbuff_t *tvb, packet_info *pinfo, p static void dissect_zbee_beacon (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); /* Command Dissector Helpers */ -static guint dissect_zbee_nwk_route_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, guint offset); +static guint dissect_zbee_nwk_route_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + zbee_nwk_packet * packet, guint offset); static guint dissect_zbee_nwk_route_rep (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint dissect_zbee_nwk_status (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint dissect_zbee_nwk_leave (tvbuff_t *tvb, proto_tree *tree, guint offset); -static guint dissect_zbee_nwk_route_rec (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, guint offset); -static guint dissect_zbee_nwk_rejoin_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, guint offset); -static guint dissect_zbee_nwk_rejoin_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zbee_nwk_packet * packet, guint offset); +static guint dissect_zbee_nwk_route_rec (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + zbee_nwk_packet * packet, guint offset); +static guint dissect_zbee_nwk_rejoin_req (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + zbee_nwk_packet * packet, guint offset); +static guint dissect_zbee_nwk_rejoin_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + zbee_nwk_packet * packet, guint offset); static guint dissect_zbee_nwk_link_status(tvbuff_t *tvb, proto_tree *tree, guint offset); static guint dissect_zbee_nwk_report (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint dissect_zbee_nwk_update (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); +static void proto_init_zbee_nwk (void); /********************/ @@ -86,6 +92,7 @@ static int hf_zbee_nwk_mcast_radius = -1; static int hf_zbee_nwk_mcast_max_radius = -1; static int hf_zbee_nwk_dst64 = -1; static int hf_zbee_nwk_src64 = -1; +static int hf_zbee_nwk_src64_origin = -1; static int hf_zbee_nwk_relay_count = -1; static int hf_zbee_nwk_relay_index = -1; @@ -243,28 +250,14 @@ static const value_string zbee_nwk_stack_profiles[] = { { 0, NULL } }; -/*FUNCTION:------------------------------------------------------ - * NAME - * proto_tree_add_eui64 - * DESCRIPTION - * Helper function to display an EUI-64 address to the tree. - * PARAMETERS - * proto_tree *tree - * int hfindex - * tvbuff_t *tvb - * gint start - * gint length - * guint64 value; - * RETURNS - * proto_item * - *--------------------------------------------------------------- +/* TODO: much of the following copied from ieee80154 dissector */ +/*------------------------------------- + * Hash Tables and Lists + *------------------------------------- */ -proto_item * -proto_tree_add_eui64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, gint64 value) -{ - header_field_info *hf = proto_registrar_get_nth(hfindex); - return proto_tree_add_uint64_format(tree, hfindex, tvb, start, length, value, "%s: %s (%s)", hf->name, print_eui64_oui(value), print_eui64(value)); -} +static ieee802154_addr_t zbee_nwk_addr = { 0, NULL, NULL }; + GHashTable *zbee_table_nwk_keyring = NULL; +static GHashTable *zbee_table_link_keyring = NULL; /*FUNCTION:------------------------------------------------------ * NAME @@ -358,19 +351,41 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_tree *field_tree = NULL; zbee_nwk_packet packet; + ieee802154_packet *ieee_packet = pinfo->private_data; guint offset = 0; gchar *src_addr = ep_alloc(32); gchar *dst_addr = ep_alloc(32); guint16 fcf; + + ieee802154_short_addr addr16; + ieee802154_map_rec *map_rec; + ieee802154_hints_t *ieee_hints; + + zbee_nwk_hints_t *nwk_hints; + gboolean unicast_src; + memset(&packet, 0, sizeof(packet)); + /* Set up hint structures */ + if (!pinfo->fd->flags.visited) { + /* Allocate frame data with hints for upper layers */ + nwk_hints = se_alloc0(sizeof(zbee_nwk_hints_t)); + p_add_proto_data(pinfo->fd, proto_zbee_nwk, nwk_hints); + } else { + /* Retrieve existing structure */ + nwk_hints = p_get_proto_data(pinfo->fd, proto_zbee_nwk); + } + + ieee_hints = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN)); + /* Add ourself to the protocol column, clear the info column, and create the protocol tree. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZigBee"); col_clear(pinfo->cinfo, COL_INFO); if (tree) { - proto_root = proto_tree_add_protocol_format(tree, proto_zbee_nwk, tvb, offset, tvb_length(tvb), "ZigBee Network Layer"); + proto_root = proto_tree_add_protocol_format(tree, proto_zbee_nwk, tvb, offset, + tvb_length(tvb), "ZigBee Network Layer"); nwk_tree = proto_item_add_subtree(proto_root, ett_zbee_nwk); } @@ -392,19 +407,27 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) ti = proto_tree_add_text(nwk_tree, tvb, offset, sizeof(guint16), "Frame Control Field: %s (0x%04x)", val_to_str(packet.type, zbee_nwk_frame_types, "Unknown"), fcf); field_tree = proto_item_add_subtree(ti, ett_zbee_nwk_fcf); - proto_tree_add_uint(field_tree, hf_zbee_nwk_frame_type, tvb, offset, sizeof(guint8), fcf & ZBEE_NWK_FCF_FRAME_TYPE); + proto_tree_add_uint(field_tree, hf_zbee_nwk_frame_type, tvb, offset, sizeof(guint8), + fcf & ZBEE_NWK_FCF_FRAME_TYPE); /* Add the rest of the fcf fields to the subtree */ - proto_tree_add_uint(field_tree, hf_zbee_nwk_proto_version, tvb, offset, sizeof(guint8), fcf & ZBEE_NWK_FCF_VERSION); - proto_tree_add_uint(field_tree, hf_zbee_nwk_discover_route, tvb, offset, sizeof(guint8), fcf & ZBEE_NWK_FCF_DISCOVER_ROUTE); + proto_tree_add_uint(field_tree, hf_zbee_nwk_proto_version, tvb, offset, sizeof(guint8), + fcf & ZBEE_NWK_FCF_VERSION); + proto_tree_add_uint(field_tree, hf_zbee_nwk_discover_route, tvb, offset, sizeof(guint8), + fcf & ZBEE_NWK_FCF_DISCOVER_ROUTE); if (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) { - proto_tree_add_boolean(field_tree, hf_zbee_nwk_multicast, tvb, offset+sizeof(guint8), sizeof(guint8), fcf & ZBEE_NWK_FCF_MULTICAST); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_multicast, tvb, offset+sizeof(guint8), + sizeof(guint8), fcf & ZBEE_NWK_FCF_MULTICAST); } - proto_tree_add_boolean(field_tree, hf_zbee_nwk_security, tvb, offset+sizeof(guint8), sizeof(guint8), fcf & ZBEE_NWK_FCF_SECURITY); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_security, tvb, offset+sizeof(guint8), + sizeof(guint8), fcf & ZBEE_NWK_FCF_SECURITY); if (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) { - proto_tree_add_boolean(field_tree, hf_zbee_nwk_source_route, tvb, offset+sizeof(guint8), sizeof(guint8), fcf & ZBEE_NWK_FCF_SOURCE_ROUTE); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_ext_dst, tvb, offset+sizeof(guint8), sizeof(guint8), fcf & ZBEE_NWK_FCF_EXT_DEST); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_ext_src, tvb, offset+sizeof(guint8), sizeof(guint8), fcf & ZBEE_NWK_FCF_EXT_SOURCE); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_source_route, tvb, offset+sizeof(guint8), + sizeof(guint8), fcf & ZBEE_NWK_FCF_SOURCE_ROUTE); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_ext_dst, tvb, offset+sizeof(guint8), + sizeof(guint8), fcf & ZBEE_NWK_FCF_EXT_DEST); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_ext_src, tvb, offset+sizeof(guint8), + sizeof(guint8), fcf & ZBEE_NWK_FCF_EXT_SOURCE); } } offset += sizeof(guint16); @@ -430,9 +453,13 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) || (packet.dst == ZBEE_BCAST_ROUTERS)){ g_snprintf(dst_addr, 32, "Broadcast"); } - else g_snprintf(dst_addr, 32, "0x%04x", packet.dst); + else { + g_snprintf(dst_addr, 32, "0x%04x", packet.dst); + } + SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); SET_ADDRESS(&pinfo->net_dst, AT_STRINGZ, (int)strlen(dst_addr)+1, dst_addr); + if (tree) { proto_item_append_text(proto_root, ", Dst: %s", dst_addr); } @@ -440,9 +467,9 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_append_fstr(pinfo->cinfo, COL_INFO, ", Dst: %s", dst_addr); } - /* Get the source address. */ + /* Get the short nwk source address. */ packet.src = tvb_get_letohs(tvb, offset); - if(tree){ + if (tree) { proto_tree_add_uint(nwk_tree, hf_zbee_nwk_src, tvb, offset, sizeof(guint16), packet.src); } offset += sizeof(guint16); @@ -452,11 +479,17 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) || (packet.src == ZBEE_BCAST_ACTIVE) || (packet.src == ZBEE_BCAST_ROUTERS)){ /* Source Broadcast doesn't make much sense. */ - g_snprintf(src_addr, 32, "Broadcast"); + g_snprintf(src_addr, 32, "Unexpected Source Broadcast"); + unicast_src = FALSE; + } + else { + g_snprintf(src_addr, 32, "0x%04x", packet.src); + unicast_src = TRUE; } - else g_snprintf(src_addr, 32, "0x%04x", packet.src); + SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); SET_ADDRESS(&pinfo->net_src, AT_STRINGZ, (int)strlen(src_addr)+1, src_addr); + if (tree) { proto_item_append_text(proto_root, ", Src: %s", src_addr); } @@ -490,9 +523,12 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) ti = proto_tree_add_text(nwk_tree, tvb, offset, sizeof(guint8), "Multicast Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_nwk_mcast); /* Add the fields. */ - ti = proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_mode, tvb, offset, sizeof(guint8), mcast_control & ZBEE_NWK_MCAST_MODE); - proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_radius, tvb, offset, sizeof(guint8), mcast_control & ZBEE_NWK_MCAST_RADIUS); - proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_max_radius, tvb, offset, sizeof(guint8), mcast_control & ZBEE_NWK_MCAST_MAX_RADIUS); + ti = proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_mode, tvb, offset, sizeof(guint8), + mcast_control & ZBEE_NWK_MCAST_MODE); + proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_radius, tvb, offset, sizeof(guint8), + mcast_control & ZBEE_NWK_MCAST_RADIUS); + proto_tree_add_uint(field_tree, hf_zbee_nwk_mcast_max_radius, tvb, offset, sizeof(guint8), + mcast_control & ZBEE_NWK_MCAST_MAX_RADIUS); } offset += sizeof(guint8); } @@ -506,14 +542,79 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) offset += sizeof(guint64); } - /* Add the extended source address. (ZigBee 2006 and later). */ - if ((pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) && packet.ext_src) { - packet.src64 = tvb_get_letoh64(tvb, offset); - if (tree) { - proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_src64, tvb, offset, sizeof(guint64), packet.src64); + /* Display the extended source address. (ZigBee 2006 and later). */ + if (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) { + addr16.pan = ieee_packet->src_pan; + + if (packet.ext_src) { + packet.src64 = tvb_get_letoh64(tvb, offset); + if (tree) { + proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_src64, tvb, offset, sizeof(guint64), packet.src64); + } + offset += sizeof(guint64); + + if (!pinfo->fd->flags.visited) { + /* Provide hints to upper layers */ + nwk_hints->src_pan = ieee_packet->src_pan; + + /* Update nwk extended address hash table */ + if ( unicast_src ) { + nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_addr, + packet.src, addr16.pan, packet.src64, proto_zbee_nwk, pinfo->fd->num); + } + } } - offset += sizeof(guint64); - } + else { + /* See if extended source info was previously sniffed */ + if (!pinfo->fd->flags.visited) { + nwk_hints->src_pan = ieee_packet->src_pan; + addr16.addr = packet.src; + + map_rec = (ieee802154_map_rec *) g_hash_table_lookup(zbee_nwk_addr.short_table, &addr16); + if (map_rec) { + /* found a nwk mapping record */ + nwk_hints->map_rec = map_rec; + } + else { + /* does ieee layer know? */ + map_rec = (ieee802154_map_rec *) g_hash_table_lookup(ieee_packet->short_table, &addr16); + if (map_rec) nwk_hints->map_rec = map_rec; + } + } /* (!pinfo->fd->flags.visited) */ + else { + if (tree && nwk_hints && nwk_hints->map_rec ) { + /* Display inferred source address info */ + ti = proto_tree_add_eui64(nwk_tree, hf_zbee_nwk_src64, tvb, offset, 0, + nwk_hints->map_rec->addr64); + PROTO_ITEM_SET_GENERATED(ti); + + if ( nwk_hints->map_rec->start_fnum ) { + ti = proto_tree_add_uint(nwk_tree, hf_zbee_nwk_src64_origin, tvb, 0, 0, + nwk_hints->map_rec->start_fnum); + } + else { + ti = proto_tree_add_text(nwk_tree, tvb, 0, 0, "Origin: Pre-configured"); + } + PROTO_ITEM_SET_GENERATED(ti); + } + } + } + + /* If ieee layer didn't know its extended source address, and nwk layer does, fill it in */ + if (!pinfo->fd->flags.visited) { + if ( (ieee_packet->src_addr_mode == IEEE802154_FCF_ADDR_SHORT) && + ieee_hints && !ieee_hints->map_rec ) { + addr16.pan = ieee_packet->src_pan; + addr16.addr = ieee_packet->src16; + map_rec = (ieee802154_map_rec *) g_hash_table_lookup(zbee_nwk_addr.short_table, &addr16); + + if (map_rec) { + /* found a ieee mapping record */ + ieee_hints->map_rec = map_rec; + } + } + } /* (!pinfo->fd->flags.visited */ + } /* (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) */ /* Add the Source Route field. (ZigBee 2006 and later). */ if ((pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) && packet.route) { @@ -609,7 +710,7 @@ dissect_zbee_nwk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) * dissect_zbee_nwk_cmd * DESCRIPTION * ZigBee Network command packet dissection routine for Wireshark. - * note: this dissector differs from others in that is shouldn't be + * note: this dissector differs from others in that it shouldn't be * passed the main tree pointer, but the nwk tree instead. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. @@ -631,7 +732,8 @@ static void dissect_zbee_nwk_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree * /* Create a subtree for this command. */ if (tree) { - cmd_root = proto_tree_add_text(tree, tvb, offset, tvb_length(tvb), "Command Frame: %s", val_to_str(cmd_id, zbee_nwk_cmd_names, "Unknown")); + cmd_root = proto_tree_add_text(tree, tvb, offset, tvb_length(tvb), "Command Frame: %s", + val_to_str(cmd_id, zbee_nwk_cmd_names, "Unknown")); cmd_tree = proto_item_add_subtree(cmd_root, ett_zbee_nwk_cmd); /* Add the command ID. */ @@ -754,12 +856,16 @@ dissect_zbee_nwk_route_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, field_tree = proto_item_add_subtree(ti, ett_zbee_nwk_cmd_options); if (pinfo->zbee_stack_vers >= ZBEE_VERSION_2007) { - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_route_opt_multicast, tvb, offset, sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_MCAST); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_route_opt_dest_ext, tvb, offset, sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT); - proto_tree_add_uint(field_tree, hf_zbee_nwk_cmd_route_opt_many_to_one, tvb, offset, sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_route_opt_multicast, tvb, offset, + sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_MCAST); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_route_opt_dest_ext, tvb, offset, + sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT); + proto_tree_add_uint(field_tree, hf_zbee_nwk_cmd_route_opt_many_to_one, tvb, offset, + sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK); } else { - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_route_opt_repair, tvb, offset, sizeof(guint8), route_options & ZBEE_NWK_CMD_ROUTE_OPTION_REPAIR); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_route_opt_repair, tvb, offset, sizeof(guint8), + route_options & ZBEE_NWK_CMD_ROUTE_OPTION_REPAIR); } } offset += sizeof(guint8); @@ -968,9 +1074,12 @@ dissect_zbee_nwk_leave(tvbuff_t *tvb, proto_tree *tree, guint offset) /* Get and display the leave options. */ leave_options = tvb_get_guint8(tvb, offset); if (tree) { - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_rejoin, tvb, offset, sizeof(guint8), leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_REJOIN); - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_request, tvb, offset, sizeof(guint8), leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_REQUEST); - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_children, tvb, offset, sizeof(guint8), leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_CHILDREN); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_rejoin, tvb, offset, sizeof(guint8), + leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_REJOIN); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_request, tvb, offset, sizeof(guint8), + leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_REQUEST); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_leave_children, tvb, offset, sizeof(guint8), + leave_options & ZBEE_NWK_CMD_LEAVE_OPTION_CHILDREN); } offset += sizeof(guint8); @@ -1056,12 +1165,18 @@ dissect_zbee_nwk_rejoin_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, field_tree = proto_item_add_subtree(ti, ett_zbee_nwk_cmd_cinfo); /* Add the capability info flags. */ - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_alt_coord, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_ALT_COORD); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_type, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_FFD); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_power, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_POWER); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_idle_rx, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_IDLE_RX); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_security, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_SECURITY); - proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_alloc, tvb, offset, sizeof(guint8), capabilities & ZBEE_CINFO_ALLOC); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_alt_coord, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_ALT_COORD); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_type, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_FFD); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_power, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_POWER); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_idle_rx, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_IDLE_RX); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_security, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_SECURITY); + proto_tree_add_boolean(field_tree, hf_zbee_nwk_cmd_cinfo_alloc, tvb, offset, sizeof(guint8), + capabilities & ZBEE_CINFO_ALLOC); } offset += sizeof(guint8); @@ -1147,8 +1262,10 @@ dissect_zbee_nwk_link_status(tvbuff_t *tvb, proto_tree *tree, guint offset) options = tvb_get_guint8(tvb, offset); link_count = options & ZBEE_NWK_CMD_LINK_OPTION_COUNT_MASK; if (tree) { - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_link_last, tvb, offset, sizeof(guint8), options & ZBEE_NWK_CMD_LINK_OPTION_LAST_FRAME); - proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_link_first, tvb, offset, sizeof(guint8), options & ZBEE_NWK_CMD_LINK_OPTION_FIRST_FRAME); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_link_last, tvb, offset, sizeof(guint8), + options & ZBEE_NWK_CMD_LINK_OPTION_LAST_FRAME); + proto_tree_add_boolean(tree, hf_zbee_nwk_cmd_link_first, tvb, offset, sizeof(guint8), + options & ZBEE_NWK_CMD_LINK_OPTION_FIRST_FRAME); proto_tree_add_uint(tree, hf_zbee_nwk_cmd_link_count, tvb, offset, sizeof(guint8), link_count); } offset += sizeof(guint8); @@ -1159,7 +1276,10 @@ dissect_zbee_nwk_link_status(tvbuff_t *tvb, proto_tree *tree, guint offset) addr = tvb_get_letohs(tvb, offset); options = tvb_get_guint8(tvb, offset+sizeof(guint16)); if (tree) { - proto_tree_add_text(tree, tvb, offset, sizeof(guint16)+sizeof(guint8), "0x%04x, Incoming Cost: %d Outgoing Cost: %d", addr, options & ZBEE_NWK_CMD_LINK_INCOMMING_COST_MASK, (options & ZBEE_NWK_CMD_LINK_OUTGOING_COST_MASK)>>4); + proto_tree_add_text(tree, tvb, offset, sizeof(guint16)+sizeof(guint8), + "0x%04x, Incoming Cost: %d Outgoing Cost: %d", addr, + options & ZBEE_NWK_CMD_LINK_INCOMMING_COST_MASK, + (options & ZBEE_NWK_CMD_LINK_OUTGOING_COST_MASK)>>4); } offset += (sizeof(guint16)+sizeof(guint8)); } /* for */ @@ -1337,7 +1457,7 @@ static void dissect_zbee_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t /* Update the info column. */ if(check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); - col_append_fstr(pinfo->cinfo, COL_INFO, "Beacon, Src: 0x%04x", packet->src.addr16); + col_append_fstr(pinfo->cinfo, COL_INFO, "Beacon, Src: 0x%04x", packet->src16); } /* Get and display the protocol id, must be 0 on all ZigBee beacons. */ @@ -1351,7 +1471,8 @@ static void dissect_zbee_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t temp = tvb_get_guint8(tvb, offset); pinfo->zbee_stack_vers = version = zbee_get_bit_field(temp, ZBEE_NWK_BEACON_PROTOCOL_VERSION); if (tree) { - proto_tree_add_uint(beacon_tree, hf_zbee_beacon_stack_profile, tvb, offset, sizeof(guint8), zbee_get_bit_field(temp, ZBEE_NWK_BEACON_STACK_PROFILE)); + proto_tree_add_uint(beacon_tree, hf_zbee_beacon_stack_profile, tvb, offset, sizeof(guint8), + zbee_get_bit_field(temp, ZBEE_NWK_BEACON_STACK_PROFILE)); proto_tree_add_uint(beacon_tree, hf_zbee_beacon_version, tvb, offset, sizeof(guint8), version); } offset += sizeof(guint8); @@ -1359,9 +1480,12 @@ static void dissect_zbee_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t /* Get and display the security level and flags. */ temp = tvb_get_guint8(tvb, offset); if (tree) { - proto_tree_add_boolean(beacon_tree, hf_zbee_beacon_router_capacity, tvb, offset, sizeof(guint8), zbee_get_bit_field(temp, ZBEE_NWK_BEACON_ROUTER_CAPACITY)); - proto_tree_add_uint(beacon_tree, hf_zbee_beacon_depth, tvb, offset, sizeof(guint8), zbee_get_bit_field(temp, ZBEE_NWK_BEACON_NETWORK_DEPTH)); - proto_tree_add_boolean(beacon_tree, hf_zbee_beacon_end_device_capacity, tvb, offset, sizeof(guint8), zbee_get_bit_field(temp, ZBEE_NWK_BEACON_END_DEVICE_CAPACITY)); + proto_tree_add_boolean(beacon_tree, hf_zbee_beacon_router_capacity, tvb, offset, sizeof(guint8), + zbee_get_bit_field(temp, ZBEE_NWK_BEACON_ROUTER_CAPACITY)); + proto_tree_add_uint(beacon_tree, hf_zbee_beacon_depth, tvb, offset, sizeof(guint8), + zbee_get_bit_field(temp, ZBEE_NWK_BEACON_NETWORK_DEPTH)); + proto_tree_add_boolean(beacon_tree, hf_zbee_beacon_end_device_capacity, tvb, offset, sizeof(guint8), + zbee_get_bit_field(temp, ZBEE_NWK_BEACON_END_DEVICE_CAPACITY)); } offset += sizeof(guint8); @@ -1369,7 +1493,8 @@ static void dissect_zbee_beacon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t /* In ZigBee 2006 and later, the beacon contains an extended PAN ID. */ epid = tvb_get_letoh64(tvb, offset); if (tree) { - proto_tree_add_uint64_format_value(beacon_tree, hf_zbee_beacon_epid, tvb, offset, sizeof(guint64), epid, "%s", print_eui64(epid)); + proto_tree_add_uint64_format_value(beacon_tree, hf_zbee_beacon_epid, tvb, offset, sizeof(guint64), + epid, "%s", print_eui64(epid)); } offset += sizeof(guint64); @@ -1445,15 +1570,16 @@ void proto_register_zbee_nwk(void) static hf_register_info hf[] = { { &hf_zbee_nwk_frame_type, - { "Frame Type", "zbee.nwk.frame_type", FT_UINT16, BASE_HEX, VALS(zbee_nwk_frame_types), ZBEE_NWK_FCF_FRAME_TYPE, - NULL, HFILL }}, + { "Frame Type", "zbee.nwk.frame_type", FT_UINT16, BASE_HEX, VALS(zbee_nwk_frame_types), + ZBEE_NWK_FCF_FRAME_TYPE, NULL, HFILL }}, { &hf_zbee_nwk_proto_version, { "Protocol Version", "zbee.nwk.proto_version", FT_UINT16, BASE_DEC, NULL, ZBEE_NWK_FCF_VERSION, NULL, HFILL }}, { &hf_zbee_nwk_discover_route, - { "Discover Route", "zbee.nwk.discovery", FT_UINT16, BASE_HEX, VALS(zbee_nwk_discovery_modes), ZBEE_NWK_FCF_DISCOVER_ROUTE, + { "Discover Route", "zbee.nwk.discovery", FT_UINT16, BASE_HEX, VALS(zbee_nwk_discovery_modes), + ZBEE_NWK_FCF_DISCOVER_ROUTE, "Determines how route discovery may be handled, if at all.", HFILL }}, { &hf_zbee_nwk_multicast, @@ -1469,7 +1595,7 @@ void proto_register_zbee_nwk(void) NULL, HFILL }}, { &hf_zbee_nwk_ext_dst, - { "Extended Destination", "zbee.nwk.ext_dst", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_EXT_DEST, + { "Destination", "zbee.nwk.ext_dst", FT_BOOLEAN, 16, NULL, ZBEE_NWK_FCF_EXT_DEST, NULL, HFILL }}, { &hf_zbee_nwk_ext_src, @@ -1494,22 +1620,27 @@ void proto_register_zbee_nwk(void) { &hf_zbee_nwk_mcast_mode, { "Multicast Mode", "zbee.nwk.multicast.mode", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_MCAST_MODE, - "Controls whether this packet is permitted to be routed through non-members of the multicast group.", HFILL }}, + "Controls whether this packet is permitted to be routed through non-members of the multicast group.", + HFILL }}, { &hf_zbee_nwk_mcast_radius, { "Non-Member Radius", "zbee.nwk.multicast.radius", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_MCAST_RADIUS, "Limits the range of multicast packets when being routed through non-members.", HFILL }}, { &hf_zbee_nwk_mcast_max_radius, - { "Max Non-Member Radius", "zbee.nwk.multicast.max_radius", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_MCAST_MAX_RADIUS, - NULL, HFILL }}, + { "Max Non-Member Radius", "zbee.nwk.multicast.max_radius", FT_UINT8, BASE_DEC, NULL, + ZBEE_NWK_MCAST_MAX_RADIUS, NULL, HFILL }}, { &hf_zbee_nwk_dst64, - { "Extended Destination", "zbee.nwk.dst64", FT_UINT64, BASE_HEX, NULL, 0x0, + { "Destination", "zbee.nwk.dst64", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_zbee_nwk_src64, - { "Extended Source", "zbee.nwk.scr64", FT_UINT64, BASE_HEX, NULL, 0x0, + { "Extended Source", "zbee.nwk.src64", FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL }}, + + { &hf_zbee_nwk_src64_origin, + { "Origin", "zbee.nwk.src64.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }}, { &hf_zbee_nwk_relay_count, @@ -1561,27 +1692,30 @@ void proto_register_zbee_nwk(void) "A value specifying the efficiency of this route.", HFILL }}, { &hf_zbee_nwk_cmd_route_opt_repair, - { "Route Repair", "zbee.nwk.cmd.route.opts.repair", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_ROUTE_OPTION_REPAIR, + { "Route Repair", "zbee.nwk.cmd.route.opts.repair", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_ROUTE_OPTION_REPAIR, "Flag identifying whether the route request command was to repair a failed route.", HFILL }}, { &hf_zbee_nwk_cmd_route_opt_multicast, - { "Multicast", "zbee.nwk.cmd.route.opts.mcast", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_ROUTE_OPTION_MCAST, + { "Multicast", "zbee.nwk.cmd.route.opts.mcast", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_ROUTE_OPTION_MCAST, "Flag identifying this as a multicast route request.", HFILL }}, { &hf_zbee_nwk_cmd_route_opt_dest_ext, - { "Extended Destination", "zbee.nwk.cmd.route.opts.dest_ext", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT, - NULL, HFILL }}, + { "Extended Destination", "zbee.nwk.cmd.route.opts.dest_ext", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_ROUTE_OPTION_DEST_EXT, NULL, HFILL }}, { &hf_zbee_nwk_cmd_route_opt_resp_ext, - { "Extended Responder", "zbee.nwk.cmd.route.opts.resp_ext", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_ROUTE_OPTION_RESP_EXT, - NULL, HFILL }}, + { "Extended Responder", "zbee.nwk.cmd.route.opts.resp_ext", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_ROUTE_OPTION_RESP_EXT, NULL, HFILL }}, { &hf_zbee_nwk_cmd_route_opt_orig_ext, - { "Extended Originator", "zbee.nwk.cmd.route.opts.orig_ext", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_ROUTE_OPTION_ORIG_EXT, - NULL, HFILL }}, + { "Extended Originator", "zbee.nwk.cmd.route.opts.orig_ext", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_ROUTE_OPTION_ORIG_EXT, NULL, HFILL }}, { &hf_zbee_nwk_cmd_route_opt_many_to_one, - { "Many-to-One Discovery", "zbee.nwk.cmd.route.opts.many2one", FT_UINT8, BASE_HEX, VALS(zbee_nwk_cmd_route_many_modes), ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK, + { "Many-to-One Discovery", "zbee.nwk.cmd.route.opts.many2one", FT_UINT8, BASE_HEX, + VALS(zbee_nwk_cmd_route_many_modes), ZBEE_NWK_CMD_ROUTE_OPTION_MANY_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_nwk_status, @@ -1589,15 +1723,17 @@ void proto_register_zbee_nwk(void) NULL, HFILL }}, { &hf_zbee_nwk_cmd_leave_rejoin, - { "Rejoin", "zbee.nwk.cmd.leave.rejoin", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_LEAVE_OPTION_REJOIN, - "Flag instructing the device to rejoin the network.", HFILL }}, + { "Rejoin", "zbee.nwk.cmd.leave.rejoin", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_LEAVE_OPTION_REJOIN, "Flag instructing the device to rejoin the network.", HFILL }}, { &hf_zbee_nwk_cmd_leave_request, - { "Request", "zbee.nwk.cmd.leave.request", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_LEAVE_OPTION_REQUEST, + { "Request", "zbee.nwk.cmd.leave.request", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_LEAVE_OPTION_REQUEST, "Flag identifying the direction of this command. 1=Request, 0=Indication", HFILL }}, { &hf_zbee_nwk_cmd_leave_children, - { "Remove Children", "zbee.nwk.cmd.leave.children", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_LEAVE_OPTION_CHILDREN, + { "Remove Children", "zbee.nwk.cmd.leave.children", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_LEAVE_OPTION_CHILDREN, "Flag instructing the device to remove its children in addition to itself.", HFILL }}, { &hf_zbee_nwk_cmd_relay_count, @@ -1605,60 +1741,66 @@ void proto_register_zbee_nwk(void) "Number of relays required to route to the destination.", HFILL }}, { &hf_zbee_nwk_cmd_cinfo_alt_coord, - { "Alternate Coordinator", "zbee.nwk.cmd.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALT_PAN_COORD, + { "Alternate Coordinator", "zbee.nwk.cmd.cinfo.alt_coord", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_ALT_PAN_COORD, "Indicates that the device is able to operate as a PAN coordinator.", HFILL }}, { &hf_zbee_nwk_cmd_cinfo_type, - { "Full-Function Device", "zbee.nwk.cmd.cinfo.ffd", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_DEVICE_TYPE, - NULL, HFILL }}, + { "Full-Function Device", "zbee.nwk.cmd.cinfo.ffd", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_DEVICE_TYPE, NULL, HFILL }}, { &hf_zbee_nwk_cmd_cinfo_power, - { "AC Power", "zbee.nwk.cmd.cinfo.power", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_POWER_SRC, - "Indicates this device is using AC/Mains power.", HFILL }}, + { "AC Power", "zbee.nwk.cmd.cinfo.power", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_POWER_SRC, "Indicates this device is using AC/Mains power.", HFILL }}, { &hf_zbee_nwk_cmd_cinfo_idle_rx, - { "Rx On When Idle", "zbee.nwk.cmd.cinfo.power", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_IDLE_RX, + { "Rx On When Idle", "zbee.nwk.cmd.cinfo.power", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_IDLE_RX, "Indicates the receiver is active when the device is idle.", HFILL }}, { &hf_zbee_nwk_cmd_cinfo_security, - { "Security Capability", "zbee.nwk.cmd.cinfo.security", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_SEC_CAPABLE, + { "Security Capability", "zbee.nwk.cmd.cinfo.security", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_SEC_CAPABLE, "Indicates this device is capable of performing encryption/decryption.", HFILL }}, { &hf_zbee_nwk_cmd_cinfo_alloc, - { "Allocate Short Address", "zbee.nwk.cmd.cinfo.alloc", FT_BOOLEAN, 8, NULL, IEEE802154_CMD_CINFO_ALLOC_ADDR, + { "Allocate Short Address", "zbee.nwk.cmd.cinfo.alloc", FT_BOOLEAN, 8, NULL, + IEEE802154_CMD_CINFO_ALLOC_ADDR, "Flag requesting the parent to allocate a short address for this device.", HFILL }}, { &hf_zbee_nwk_cmd_rejoin_status, - { "Status", "zbee.nwk.cmd.rejoin_status", FT_UINT8, BASE_HEX, VALS(zbee_nwk_rejoin_codes), 0x0, - NULL, HFILL }}, + { "Status", "zbee.nwk.cmd.rejoin_status", FT_UINT8, BASE_HEX, + VALS(zbee_nwk_rejoin_codes), 0x0, NULL, HFILL }}, { &hf_zbee_nwk_cmd_link_last, - { "Last Frame", "zbee.nwk.cmd.link.last", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_LINK_OPTION_LAST_FRAME, + { "Last Frame", "zbee.nwk.cmd.link.last", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_LINK_OPTION_LAST_FRAME, "Flag indicating the last in a series of link status commands.", HFILL }}, { &hf_zbee_nwk_cmd_link_first, - { "First Frame", "zbee.nwk.cmd.link.first", FT_BOOLEAN, 8, NULL, ZBEE_NWK_CMD_LINK_OPTION_FIRST_FRAME, + { "First Frame", "zbee.nwk.cmd.link.first", FT_BOOLEAN, 8, NULL, + ZBEE_NWK_CMD_LINK_OPTION_FIRST_FRAME, "Flag indicating the first in a series of link status commands.", HFILL }}, { &hf_zbee_nwk_cmd_link_count, - { "Link Status Count", "zbee.nwk.cmd.link.count", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_CMD_LINK_OPTION_COUNT_MASK, - NULL, HFILL }}, + { "Link Status Count", "zbee.nwk.cmd.link.count", FT_UINT8, BASE_DEC, NULL, + ZBEE_NWK_CMD_LINK_OPTION_COUNT_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_report_type, - { "Report Type", "zbee.nwk.cmd.report.type", FT_UINT8, BASE_HEX, VALS(zbee_nwk_report_types), ZBEE_NWK_CMD_NWK_REPORT_ID_MASK, - NULL, HFILL }}, + { "Report Type", "zbee.nwk.cmd.report.type", FT_UINT8, BASE_HEX, + VALS(zbee_nwk_report_types), ZBEE_NWK_CMD_NWK_REPORT_ID_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_report_count, - { "Report Information Count", "zbee.nwk.cmd.report.count", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_CMD_NWK_REPORT_COUNT_MASK, - NULL, HFILL }}, + { "Report Information Count", "zbee.nwk.cmd.report.count", FT_UINT8, BASE_DEC, NULL, + ZBEE_NWK_CMD_NWK_REPORT_COUNT_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_update_type, - { "Update Type", "zbee.nwk.cmd.update.type", FT_UINT8, BASE_HEX, VALS(zbee_nwk_update_types), ZBEE_NWK_CMD_NWK_UPDATE_ID_MASK, - NULL, HFILL }}, + { "Update Type", "zbee.nwk.cmd.update.type", FT_UINT8, BASE_HEX, + VALS(zbee_nwk_update_types), ZBEE_NWK_CMD_NWK_UPDATE_ID_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_update_count, - { "Update Information Count", "zbee.nwk.cmd.update.count", FT_UINT8, BASE_DEC, NULL, ZBEE_NWK_CMD_NWK_UPDATE_COUNT_MASK, - NULL, HFILL }}, + { "Update Information Count", "zbee.nwk.cmd.update.count", FT_UINT8, BASE_DEC, NULL, + ZBEE_NWK_CMD_NWK_UPDATE_COUNT_MASK, NULL, HFILL }}, { &hf_zbee_nwk_cmd_update_id, { "Update ID", "zbee.nwk.cmd.update.id", FT_UINT8, BASE_DEC, NULL, 0x0, @@ -1673,8 +1815,8 @@ void proto_register_zbee_nwk(void) NULL, HFILL }}, { &hf_zbee_beacon_stack_profile, - { "Stack Profile", "zbee.beacon.profile", FT_UINT8, BASE_HEX, VALS(zbee_nwk_stack_profiles), 0x0, - NULL, HFILL }}, + { "Stack Profile", "zbee.beacon.profile", FT_UINT8, BASE_HEX, + VALS(zbee_nwk_stack_profiles), 0x0, NULL, HFILL }}, { &hf_zbee_beacon_version, { "Protocol Version", "zbee.beacon.version", FT_UINT8, BASE_DEC, NULL, 0x0, @@ -1717,18 +1859,20 @@ void proto_register_zbee_nwk(void) &ett_zbee_nwk_cmd_cinfo }; + register_init_routine(proto_init_zbee_nwk); + /* Register the protocol with Wireshark. */ - proto_zbee_nwk = proto_register_protocol("ZigBee Network Layer", "ZigBee NWK", "zbee.nwk"); + proto_zbee_nwk = proto_register_protocol("ZigBee Network Layer", "ZigBee NWK", ZBEE_PROTOABBREV_NWK); proto_register_field_array(proto_zbee_nwk, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* Register the dissectors with Wireshark. */ - register_dissector("zbee.nwk", dissect_zbee_nwk, proto_zbee_nwk); + register_dissector(ZBEE_PROTOABBREV_NWK, dissect_zbee_nwk, proto_zbee_nwk); register_dissector("zbee.beacon", dissect_zbee_beacon, proto_zbee_nwk); /* Register the Security dissector. */ zbee_security_register(NULL, proto_zbee_nwk); -} /* proto_register_zbee */ +} /* proto_register_zbee_nwk */ /*FUNCTION:------------------------------------------------------ * NAME @@ -1748,8 +1892,43 @@ void proto_reg_handoff_zbee_nwk(void) aps_handle = find_dissector("zbee.aps"); /* Register our dissector with IEEE 802.15.4 */ - heur_dissector_add("wpan", dissect_zbee_nwk_heur, proto_zbee_nwk); + heur_dissector_add(IEEE802154_PROTOABBREV_WPAN, dissect_zbee_nwk_heur, proto_zbee_nwk); /* Handoff the ZigBee security dissector code. */ zbee_security_handoff(); } /* proto_reg_handoff_zbee */ + +static void free_keyring_val(gpointer a) +{ + GSList **slist = a; + g_slist_free(*slist); + return; +} + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_init_zbee_nwk + * DESCRIPTION + * Init routine for the nwk dissector. Creates a + * hash table for mapping 16-bit to 64-bit addresses and + * populates it with static address pairs from a UAT + * preference table. + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void +proto_init_zbee_nwk(void) +{ + /* Destroy the hash tables, if they exist. */ + if (zbee_nwk_addr.short_table) g_hash_table_destroy(zbee_nwk_addr.short_table); + if (zbee_nwk_addr.long_table) g_hash_table_destroy(zbee_nwk_addr.long_table); + if (zbee_table_nwk_keyring) g_hash_table_destroy(zbee_table_nwk_keyring); + + /* (Re)create the hash tables. */ + zbee_nwk_addr.short_table = g_hash_table_new(ieee802154_short_addr_hash, ieee802154_short_addr_equal); + zbee_nwk_addr.long_table = g_hash_table_new(g_int64_hash, g_int64_equal); + zbee_table_nwk_keyring = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free_keyring_val); +} /* proto_init_zbee_nwk */ diff --git a/epan/dissectors/packet-zbee-nwk.h b/epan/dissectors/packet-zbee-nwk.h index b1e3da4fe4..9069e83961 100644 --- a/epan/dissectors/packet-zbee-nwk.h +++ b/epan/dissectors/packet-zbee-nwk.h @@ -21,7 +21,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef PACKET_ZBEE_NWK_H #define PACKET_ZBEE_NWK_H @@ -122,10 +122,11 @@ #define ZBEE_NWK_STATUS_BAD_FRAME_COUNTER 0x11 #define ZBEE_NWK_STATUS_BAD_KEY_SEQNO 0x12 +#define ZBEE_SEC_CONST_KEYSIZE 16 + typedef struct{ gboolean security; gboolean discovery; - gboolean is_bcast; gboolean multicast; /* ZigBee 2006 and Later */ gboolean route; /* ZigBee 2006 and Later */ gboolean ext_dst; /* ZigBee 2006 and Later */ @@ -148,6 +149,33 @@ typedef struct{ guint8 payload_len; } zbee_nwk_packet; +/* Key used for link key hash table. */ +typedef struct { + guint64 lt_addr64; /* lesser than address */ + guint64 gt_addr64; /* greater than address */ +} table_link_key_t; + +/* Values in the key rings. */ +typedef struct { + guint frame_num; + gchar *label; + guint8 key[ZBEE_SEC_CONST_KEYSIZE]; +} key_record_t; + +typedef struct { + gint src_pan; /* source pan */ + gint ieee_src; /* short source address from mac */ + ieee802154_map_rec *map_rec; /* extended src from nwk */ + key_record_t *nwk; /* Network key found for this packet */ + key_record_t *link; /* Link key found for this packet */ +} zbee_nwk_hints_t; + +extern GHashTable *zbee_table_nwk_keyring; +extern GHashTable *zbee_table_link_keyring; + +/* Key Types */ +#define ZBEE_USER_KEY 0x01 + /* Beacon Definitions. */ #define ZBEE_NWK_BEACON_PROCOL_ID 0x00 #define ZBEE_NWK_BEACON_STACK_PROFILE 0x0f diff --git a/epan/dissectors/packet-zbee-security.c b/epan/dissectors/packet-zbee-security.c index 2bde0c9b81..246dfcf445 100644 --- a/epan/dissectors/packet-zbee-security.c +++ b/epan/dissectors/packet-zbee-security.c @@ -1,6 +1,6 @@ /* packet-zbee-security.c * Dissector helper routines for encrypted ZigBee frames. - * By Owen Kirby <osk@exegin.com> + * By Owen Kirby <osk@exegin.com>; portions by Fred Fierling <fff@exegin.com> * Copyright 2009 Exegin Technologies Limited * * $Id$ @@ -38,6 +38,8 @@ #include <epan/prefs.h> #include <epan/expert.h> +#include <epan/uat.h> + /* We require libgcrpyt in order to decrypt ZigBee packets. Without it the best * we can do is parse the security header and give up. */ @@ -45,25 +47,36 @@ #include <gcrypt.h> #endif /* HAVE_LIBGCRYPT */ +#include "packet-ieee802154.h" #include "packet-zbee.h" +#include "packet-zbee-nwk.h" #include "packet-zbee-security.h" /* Helper Functions */ #ifdef HAVE_LIBGCRYPT -static gboolean zbee_sec_ccm_decrypt(const gchar *, const gchar *, const gchar *, const gchar *, gchar *, guint, guint, guint); -static guint8 * zbee_sec_key_hash(guint8 *, guint8, packet_info *); -static void zbee_sec_make_nonce (guint8 *, zbee_security_packet *); +static gboolean zbee_sec_ccm_decrypt(const gchar *, const gchar *, const gchar *, const gchar *, gchar *, + guint, guint, guint); +static guint8 * zbee_sec_key_hash(guint8 *, guint8, guint8 *); +static void zbee_sec_make_nonce (zbee_security_packet *, guint8 *); +static gboolean zbee_sec_decrypt_payload(zbee_security_packet *, const gchar *, const gchar, guint8 *, + guint, guint, guint8 *); #endif -static void zbee_security_parse_prefs(void); +static gboolean zbee_security_parse_key(const gchar *, guint8 *, gboolean); +static void proto_init_zbee_security(void); /* Field pointers. */ +#if 0 static int hf_zbee_sec_level = -1; -static int hf_zbee_sec_key = -1; +#endif +static int hf_zbee_sec_key_id = -1; static int hf_zbee_sec_nonce = -1; static int hf_zbee_sec_counter = -1; -static int hf_zbee_sec_src = -1; +static int hf_zbee_sec_src64 = -1; +static int hf_zbee_sec_isrc64 = -1; static int hf_zbee_sec_key_seqno = -1; static int hf_zbee_sec_mic = -1; +static int hf_zbee_sec_key_origin = -1; +static int hf_zbee_sec_src64_origin = -1; /* Subtree pointers. */ static gint ett_zbee_sec = -1; @@ -79,6 +92,7 @@ static const value_string zbee_sec_key_names[] = { { 0, NULL } }; +#if 0 /* These aren't really used anymore, as ZigBee no longer includes them in the * security control field. If we were to display them all we would ever see is * security level 0. @@ -94,6 +108,7 @@ static const value_string zbee_sec_level_names[] = { { ZBEE_SEC_ENC_MIC128, "Encryption, 128-bit MIC" }, { 0, NULL } }; +#endif /* The ZigBee security level, in enum_val_t for the security preferences. */ static enum_val_t zbee_sec_level_enums[] = { @@ -108,22 +123,78 @@ static enum_val_t zbee_sec_level_enums[] = { { NULL, NULL, 0 } }; -/* Network Key. */ -static gboolean zbee_sec_have_nwk_key = FALSE; -static guint8 zbee_sec_nwk_key[ZBEE_SEC_CONST_KEYSIZE]; +static gint gPREF_zbee_sec_level = ZBEE_SEC_ENC_MIC32; +static uat_t *zbee_sec_key_table_uat; + +static const value_string byte_order_vals[] = { + { 0, "Normal"}, + { 1, "Reverse"}, + { 0, NULL } +}; + +/* UAT Key Entry */ +typedef struct _uat_key_record_t { + gchar *string; + gint byte_order; + gchar *label; + guint8 key[ZBEE_SEC_CONST_KEYSIZE]; +} uat_key_record_t; + +/* */ +static uat_key_record_t *uat_key_records = NULL; +static guint num_uat_key_records = 0; + +static void* uat_key_record_copy_cb(void* n, const void* o, unsigned siz _U_) { + uat_key_record_t* new_key = n; + const uat_key_record_t* old_key = o; + + if (old_key->string) { + new_key->string = g_strdup(old_key->string); + } else { + new_key->string = NULL; + } + + if (old_key->label) { + new_key->label = g_strdup(old_key->label); + } else { + new_key->label = NULL; + } + + return new_key; +} + +static void uat_key_record_update_cb(void* r, const char** err) { + uat_key_record_t* rec = r; + + if (rec->string == NULL) { + *err = ep_strdup_printf("Key can't be blank"); + } else { + g_strstrip(rec->string); + + if (rec->string[0] != 0) { + *err = NULL; + if ( !zbee_security_parse_key(rec->string, rec->key, rec->byte_order) ) { + *err = ep_strdup_printf("Expecting %d hexadecimal bytes or\n" + "a %d character double-quoted string", ZBEE_SEC_CONST_KEYSIZE, ZBEE_SEC_CONST_KEYSIZE); + } + } else { + *err = ep_strdup_printf("Key can't be blank"); + } + } +} -/* Trust-Center Link Key. */ -static gboolean zbee_sec_have_tclink_key = FALSE; -static guint8 zbee_sec_tclink_key[ZBEE_SEC_CONST_KEYSIZE]; +static void uat_key_record_free_cb(void*r) { + uat_key_record_t* key = r; -/* Trust-Center Extended Address */ -static guint64 zbee_sec_tcaddr = 0; + if (key->string) g_free(key->string); + if (key->label) g_free(key->label); +} -/* ZigBee Security Preferences. */ -static gint gPREF_zbee_sec_level = ZBEE_SEC_ENC_MIC32; -static const gchar * gPREF_zbee_sec_nwk_key = NULL; -static const gchar * gPREF_zbee_sec_tcaddr = NULL; -static const gchar * gPREF_zbee_sec_tclink_key = NULL; +UAT_CSTRING_CB_DEF(uat_key_records, string, uat_key_record_t) +UAT_VS_DEF(uat_key_records, byte_order, uat_key_record_t, 0, "Normal") +UAT_CSTRING_CB_DEF(uat_key_records, label, uat_key_record_t) + +static GSList *zbee_pc_keyring = NULL; /* * Enable this macro to use libgcrypt's CBC_MAC mode for the authentication @@ -137,8 +208,8 @@ static const gchar * gPREF_zbee_sec_tclink_key = NULL; * NAME * zbee_security_register * DESCRIPTION - * Called to initialize the security dissectors. Roughly the - * equivalent of proto_register_* + * Called by proto_register_zbee_nwk() to initialize the security + * dissectors. * PARAMETERS * module_t zbee_prefs - Prefs module to load preferences under. * RETURNS @@ -148,12 +219,13 @@ static const gchar * gPREF_zbee_sec_tclink_key = NULL; void zbee_security_register(module_t *zbee_prefs, int proto) { static hf_register_info hf[] = { +#if 0 { &hf_zbee_sec_level, { "Level", "zbee.sec.level", FT_UINT8, BASE_HEX, VALS(zbee_sec_level_names), ZBEE_SEC_CONTROL_LEVEL, NULL, HFILL }}, - - { &hf_zbee_sec_key, - { "Key", "zbee.sec.key", FT_UINT8, BASE_HEX, VALS(zbee_sec_key_names), ZBEE_SEC_CONTROL_KEY, +#endif + { &hf_zbee_sec_key_id, + { "Key Id", "zbee.sec.key", FT_UINT8, BASE_HEX, VALS(zbee_sec_key_names), ZBEE_SEC_CONTROL_KEY, NULL, HFILL }}, { &hf_zbee_sec_nonce, @@ -164,8 +236,8 @@ void zbee_security_register(module_t *zbee_prefs, int proto) { "Frame Counter", "zbee.sec.counter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, - { &hf_zbee_sec_src, - { "Source", "zbee.sec.src", FT_UINT64, BASE_HEX, NULL, 0x0, + { &hf_zbee_sec_src64, + { "Source", "zbee.sec.src64", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }}, { &hf_zbee_sec_key_seqno, @@ -174,6 +246,11 @@ void zbee_security_register(module_t *zbee_prefs, int proto) { &hf_zbee_sec_mic, { "Message Integrity Code", "zbee.sec.mic", FT_BYTES, BASE_NONE, NULL, 0x0, + + NULL, HFILL }}, + + { &hf_zbee_sec_key_origin, + { "Key Origin", "zbee.sec.key.origin", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }} }; @@ -182,135 +259,136 @@ void zbee_security_register(module_t *zbee_prefs, int proto) &ett_zbee_sec_control }; + static uat_field_t key_uat_fields[] = { + UAT_FLD_CSTRING(uat_key_records, string, "Key", + "A 16-byte key in hexadecimal with optional dash-,\n" + "colon-, or space-separator characters, or a\n" + "a 16-character string in double-quotes."), + UAT_FLD_VS(uat_key_records, byte_order, "Byte Order", byte_order_vals, + "Byte order of key."), + UAT_FLD_LSTRING(uat_key_records, label, "Label", "User label for key."), + UAT_END_FIELDS + }; + /* If no prefs module was supplied, register our own. */ if (zbee_prefs == NULL) { - zbee_prefs = prefs_register_protocol(proto, zbee_security_parse_prefs); + zbee_prefs = prefs_register_protocol(proto, NULL); } /* Register preferences */ prefs_register_enum_preference(zbee_prefs, "seclevel", "Security Level", - "Specifies the security level to use in the decryption process. This value is ignored for ZigBee 2004 and unsecured networks.", + "Specifies the security level to use in the\n" + "decryption process. This value is ignored\n" + "for ZigBee 2004 and unsecured networks.", &gPREF_zbee_sec_level, zbee_sec_level_enums, FALSE); - prefs_register_string_preference(zbee_prefs, "nwkkey", "Network Key", - "Specifies the network key to use for decryption.", - &gPREF_zbee_sec_nwk_key); - prefs_register_string_preference(zbee_prefs, "tcaddr", "Trust Center Address", - "The Extended address of the trust center.", - &gPREF_zbee_sec_tcaddr); - prefs_register_string_preference(zbee_prefs, "tclinkkey", "Trust Center Link Key", - "Specifies the trust center link key to use for decryption.", - &gPREF_zbee_sec_tclink_key); + + zbee_sec_key_table_uat = uat_new("Pre-configured Keys", + sizeof(uat_key_record_t), + "zigbee_pc_keys", + TRUE, + (void*) &uat_key_records, + &num_uat_key_records, + UAT_CAT_FFMT, + NULL, /* TODO: ptr to help manual? */ + uat_key_record_copy_cb, + uat_key_record_update_cb, + uat_key_record_free_cb, + NULL, /* TODO: post_update */ + key_uat_fields ); + + prefs_register_uat_preference(zbee_prefs, + "key_table", + "Pre-configured Keys", + "Pre-configured link or network keys.", + zbee_sec_key_table_uat); proto_register_field_array(proto, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + + /* Register the init routine. */ + register_init_routine(proto_init_zbee_security); } /* zbee_security_register */ /*FUNCTION:------------------------------------------------------ * NAME * zbee_security_parse_key * DESCRIPTION - * Parses a key string into a buffer. + * Parses a key string from left to right into a buffer with + * increasing (normal byte order) or decreasing (reverse byte + * order) address. * PARAMETERS - * const gchar * key_str; - * guint8 key_buf; + * const gchar *key_str - pointer to the string + * guint8 *key_buf - destination buffer in memory + * gboolean big_end - fill key_buf with incrementing address * RETURNS * gboolean *--------------------------------------------------------------- */ static gboolean -zbee_security_parse_key(const gchar *key_str, guint8 *key_buf) +zbee_security_parse_key(const gchar *key_str, guint8 *key_buf, gboolean byte_order) { - int i; + int i, j; gchar temp; + gboolean string_mode = FALSE; /* Clear the key. */ memset(key_buf, 0, ZBEE_SEC_CONST_KEYSIZE); if (key_str == NULL) { return FALSE; } + /* - * Attempt to parse the key string. The key string must represent - * exactly 16 bytes in hexadecimal format with the following - * separators: ':', '-', " ", or no separator at all. Start by - * getting the first character. + * Attempt to parse the key string. The key string must + * be at least 16 pairs of hexidecimal digits with the + * following optional separators: ':', '-', " ", or 16 + * alphanumeric characters after a double-quote. */ - temp = *(key_str++); + if ( (temp = *key_str++) == '"') { + string_mode = TRUE; + temp = *key_str++; + } + + j = byte_order?ZBEE_SEC_CONST_KEYSIZE-1:0; for (i=ZBEE_SEC_CONST_KEYSIZE-1; i>=0; i--) { - /* If this character is a separator, skip it. */ - if ((temp == ':') || (temp == '-') || (temp == ' ')) temp = *(key_str++); - /* Process this nibble. */ - if (('0' <= temp) && (temp <= '9')) key_buf[i] |= ((temp-'0')<<4); - else if (('a' <= temp) && (temp <= 'f')) key_buf[i] |= ((temp-'a'+0x0a)<<4); - else if (('A' <= temp) && (temp <= 'F')) key_buf[i] |= ((temp-'A'+0x0A)<<4); - else return FALSE; - /* Get the next nibble. */ - temp = *(key_str++); - /* Process this nibble. */ - if (('0' <= temp) && (temp <= '9')) key_buf[i] |= (temp-'0'); - else if (('a' <= temp) && (temp <= 'f')) key_buf[i] |= (temp-'a'+0x0a); - else if (('A' <= temp) && (temp <= 'F')) key_buf[i] |= (temp-'A'+0x0A); - else return FALSE; - /* Get the next nibble. */ - temp = *(key_str++); - } /* for */ - /* If we get this far, then the key was good. */ - return TRUE; -} /* zbee_security_parse_key */ + if ( string_mode ) { + if ( g_ascii_isprint(temp) ) { + key_buf[j] = temp; + temp = *key_str++; + } else { + return FALSE; + } + } + else { + /* If this character is a separator, skip it. */ + if ( (temp == ':') || (temp == '-') || (temp == ' ') ) temp = *(key_str++); -/*FUNCTION:------------------------------------------------------ - * NAME - * zbee_security_parse_prefs - * DESCRIPTION - * Parses the security preferences into the parameters needed - * for decryption. - * PARAMETERS - * none - * RETURNS - * void - *--------------------------------------------------------------- - */ -static void -zbee_security_parse_prefs(void) -{ - int i; - const gchar * str_ptr; - gchar temp; + /* Process a nibble. */ + if ( g_ascii_isxdigit (temp) ) key_buf[j] = g_ascii_xdigit_value(temp)<<4; + else return FALSE; + + /* Get the next nibble. */ + temp = *(key_str++); + + /* Process another nibble. */ + if ( g_ascii_isxdigit (temp) ) key_buf[j] |= g_ascii_xdigit_value(temp); + else return FALSE; + + /* Get the next nibble. */ + temp = *(key_str++); + } + + /* Move key_buf pointer */ + if ( byte_order ) { + j--; + } else { + j++; + } - /* Get the network key. */ - zbee_sec_have_nwk_key = zbee_security_parse_key(gPREF_zbee_sec_nwk_key, zbee_sec_nwk_key); - /* Get the trust-center link key. */ - zbee_sec_have_tclink_key = zbee_security_parse_key(gPREF_zbee_sec_tclink_key, zbee_sec_tclink_key); - /* Get the trust-center address. */ - zbee_sec_tcaddr = 0; - str_ptr = gPREF_zbee_sec_tcaddr; - temp = *(str_ptr++); - for (i=0;i<(int)sizeof(guint64);i++) { - /* Except for the first octet, ensure the next character is a - * separator and skip over it. - */ - if ((temp == ':') || (temp == '-')) temp = *(str_ptr++); - else if (i!=0) goto bad_tcaddr; - /* Process this nibble. */ - if (('0' <= temp) && (temp <= '9')) zbee_sec_tcaddr |= ((guint64)(temp-'0'+0x00)<<(8*(sizeof(guint64)-i)-4)); - else if (('a' <= temp) && (temp <= 'f')) zbee_sec_tcaddr |= ((guint64)(temp-'a'+0x0a)<<(8*(sizeof(guint64)-i)-4)); - else if (('A' <= temp) && (temp <= 'F')) zbee_sec_tcaddr |= ((guint64)(temp-'A'+0x0A)<<(8*(sizeof(guint64)-i)-4)); - else goto bad_tcaddr; - /* Get the next nibble. */ - temp = *(str_ptr++); - /* Process this nibble. */ - if (('0' <= temp) && (temp <= '9')) zbee_sec_tcaddr |= ((guint64)(temp-'0'+0x00)<<(8*(sizeof(guint64)-i)-8)); - else if (('a' <= temp) && (temp <= 'f')) zbee_sec_tcaddr |= ((guint64)(temp-'a'+0x0a)<<(8*(sizeof(guint64)-i)-8)); - else if (('A' <= temp) && (temp <= 'F')) zbee_sec_tcaddr |= ((guint64)(temp-'A'+0x0A)<<(8*(sizeof(guint64)-i)-8)); - else goto bad_tcaddr; - /* Get the next nibble. */ - temp = *(str_ptr++); } /* for */ - /* Done */ - return; -bad_tcaddr: - zbee_sec_tcaddr = 0; -} /* zbee_security_parse_prefs */ + /* If we get this far, then the key was good. */ + return TRUE; +} /* zbee_security_parse_key */ /*FUNCTION:------------------------------------------------------ * NAME @@ -328,8 +406,6 @@ zbee_security_handoff(void) { /* Lookup the data dissector. */ data_handle = find_dissector("data"); - /* Parse the security prefs. */ - zbee_security_parse_prefs(); } /* zbee_security_handoff */ /*FUNCTION:------------------------------------------------------ @@ -343,35 +419,49 @@ zbee_security_handoff(void) * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. - * packet_into *pinfo - pointer to packet information fields + * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxilliary security header. - * guint64 src - extended source address, or 0 if unknown. + * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * -dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset, guint64 src) +dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset, guint64 src64) { - proto_tree * sec_tree = NULL; - proto_item * sec_root; - proto_tree * field_tree; - proto_item * ti; + proto_tree *sec_tree = NULL; + proto_item *sec_root; + proto_tree *field_tree; + proto_item *ti; zbee_security_packet packet; guint mic_len; guint payload_len; - tvbuff_t * payload_tvb; + tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT - const guint8 * enc_buffer; - guint8 * dec_buffer; - guint8 * key_buffer; - guint8 nonce[ZBEE_SEC_CONST_NONCE_LEN]; + const guint8 *enc_buffer; + guint8 *dec_buffer; + guint8 buffer[ZBEE_SEC_CONST_BLOCKSIZE+1]; + guint8 *key_buffer = buffer; + gboolean decrypted; + GSList **nwk_keyring; + GSList *GSList_i; + key_record_t *key_rec = NULL; #endif - - /* Create a substree for the security information. */ + zbee_nwk_hints_t *nwk_hints; + ieee802154_hints_t *ieee_hints; + ieee802154_map_rec *map_rec = NULL; + + /* Init */ + memset(&packet, 0, sizeof(zbee_security_packet)); + + /* Get pointers to any useful frame data from lower layers */ + nwk_hints = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK)); + ieee_hints = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN)); + + /* Create a subtree for the security information. */ if (tree) { sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header"); sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec); @@ -379,14 +469,17 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); + /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); + /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just - * so we can fix these 3 bits. + * so we can fix these 3 bits. Memory allocated by ep_tvb_memdup() is + * automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = ep_tvb_memdup(tvb, 0, tvb_length(tvb)); @@ -398,14 +491,16 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o ((guint8 *)(enc_buffer))[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); - packet.key = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); + packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); if (tree) { ti = proto_tree_add_text(sec_tree, tvb, offset, sizeof(guint8), "Security Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control); - proto_tree_add_uint(field_tree, hf_zbee_sec_key, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_KEY); - proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, sizeof(guint8), packet.control & ZBEE_SEC_CONTROL_NONCE); + proto_tree_add_uint(field_tree, hf_zbee_sec_key_id, tvb, offset, sizeof(guint8), + packet.control & ZBEE_SEC_CONTROL_KEY); + proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, sizeof(guint8), + packet.control & ZBEE_SEC_CONTROL_NONCE); } offset += sizeof(guint8); @@ -417,21 +512,32 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o offset += sizeof(guint32); if (packet.nonce) { - /* Get and display the source address. */ - packet.src = tvb_get_letoh64(tvb, offset); + /* Get and display the source address of the device that secured this payload. */ + packet.src64 = tvb_get_letoh64(tvb, offset); if (tree) { - proto_tree_add_eui64(sec_tree, hf_zbee_sec_src, tvb, offset, sizeof(guint64), packet.src); + proto_tree_add_eui64(sec_tree, hf_zbee_sec_src64, tvb, offset, sizeof(guint64), packet.src64); } offset += sizeof(guint64); + } else { - /* This field is required in the security decryption process, so - * fill it in in case the higher layer provided it. - */ - packet.src = src; + /* Look for a source address in hints */ + switch ( packet.key_id ) { + case ZBEE_SEC_KEY_NWK: + /* use the ieee extended source address for NWK decryption */ + if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; + else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "Source: Unknown"); + break; + + default: + /* use the nwk extended source address for APS decryption */ + if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; + else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "Source: Unknown"); + break; + } } - if (packet.key == ZBEE_SEC_KEY_NWK) { + if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); if (tree) { @@ -441,7 +547,7 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o } /* Determine the length of the MIC. */ - switch (packet.level){ + switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: @@ -471,7 +577,8 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o if (mic_len) { /* Display the MIC. */ if (tree) { - ti = proto_tree_add_bytes(sec_tree, hf_zbee_sec_mic, tvb, tvb_length(tvb)-mic_len, mic_len, ep_tvb_memdup(tvb, tvb_length(tvb)-mic_len, mic_len)); + ti = proto_tree_add_bytes(sec_tree, hf_zbee_sec_mic, tvb, tvb_length(tvb)-mic_len, + mic_len, ep_tvb_memdup(tvb, tvb_length(tvb)-mic_len, mic_len)); } } @@ -483,105 +590,118 @@ dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint o (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { + /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset(tvb, offset, payload_len, payload_len); } #ifdef HAVE_LIBGCRYPT - /* Ensure we have enough security material to decrypt this payload. */ - switch (packet.key) { - /* Network Keys use the shared network key. */ - case ZBEE_SEC_KEY_NWK: - if (!zbee_sec_have_nwk_key) { - /* Without a key we can't decrypt (if we could what good would security be?)*/ - goto decrypt_failed; - } - if (packet.src == 0) { - /* Without the extended source address, we can't create the nonce. */ - goto decrypt_failed; - } - /* The key, is the network key. */ - key_buffer = zbee_sec_nwk_key; - break; - - /* Link Key might use the trust center link key. */ - case ZBEE_SEC_KEY_LINK: - if (!zbee_sec_have_tclink_key) { - /* Without a key we can't decrypt. */ - goto decrypt_failed; - } - if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ - /* Without the extended source address, we can't create the nonce. */ - goto decrypt_failed; - } - else if (packet.src == 0) { - packet.src = zbee_sec_tcaddr; - } - key_buffer = zbee_sec_tclink_key; - break; + /* Allocate memory to decrypt the payload into. */ + dec_buffer = g_malloc(payload_len); - /* Key-Transport Key should use the trust center link key. */ - case ZBEE_SEC_KEY_TRANSPORT: - if (!zbee_sec_have_tclink_key) { - /* Without a key we can't decrypt. */ - goto decrypt_failed; - } - if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ - /* Without the extended source address, we can't create the nonce. */ - goto decrypt_failed; - } - else if (packet.src == 0) { - packet.src = zbee_sec_tcaddr; + decrypted = FALSE; + if ( packet.src64 ) { + if (pinfo->fd->flags.visited) { + if ( nwk_hints ) { + /* Use previously found key */ + switch ( packet.key_id ) { + case ZBEE_SEC_KEY_NWK: + if ( key_rec = nwk_hints->nwk ) { + decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, + payload_len, mic_len, nwk_hints->nwk->key); + } + break; + + default: + if ( key_rec = nwk_hints->link ) { + decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, + payload_len, mic_len, nwk_hints->link->key); + } + break; + } } - key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x00, pinfo); - break; - - /* Key-Load Key should use the trust center link key. */ - case ZBEE_SEC_KEY_LOAD: - if (!zbee_sec_have_tclink_key) { - /* Without a key we can't decrypt. */ - goto decrypt_failed; + } /* ( !pinfo->fd->flags.visited ) */ + else { + /* We only search for sniffed keys in the first pass, + * to save time, and because decrypting with keys + * transported in future packets is cheating */ + + /* Lookup NWK and link key in hash for this pan. */ + /* This overkill approach is a placeholder for a hash that looks up + * a key ring for a link key associated with a pair of devices. + */ + if ( nwk_hints ) { + nwk_keyring = g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); + + if ( nwk_keyring ) { + GSList_i = *nwk_keyring; + while ( GSList_i && !decrypted ) { + decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, + payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); + + if (decrypted) { + /* save pointer to the successful key record */ + switch (packet.key_id) { + case ZBEE_SEC_KEY_NWK: + key_rec = nwk_hints->nwk = GSList_i->data; + break; + + default: + key_rec = nwk_hints->link = GSList_i->data; + break; + } + } else { + GSList_i = g_slist_next(GSList_i); + } + } + } } - if ((packet.src == 0) && (zbee_sec_tcaddr == 0)){ - /* Without the extended source address, we can't create the nonce. */ - goto decrypt_failed; + + /* Loop through user's password table for preconfigured keys, our last resort */ + GSList_i = zbee_pc_keyring; + while ( GSList_i && !decrypted ) { + decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, + payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); + + if (decrypted) { + /* save pointer to the successful key record */ + switch (packet.key_id) { + case ZBEE_SEC_KEY_NWK: + key_rec = nwk_hints->nwk = GSList_i->data; + break; + + default: + key_rec = nwk_hints->link = GSList_i->data; + break; + } + } else { + GSList_i = g_slist_next(GSList_i); + } } - else if (packet.src == 0) { - packet.src = zbee_sec_tcaddr; + } /* ( ! pinfo->fd->flags.visited ) */ + } /* ( packet.src64 ) */ + + if ( decrypted ) { + if ( tree && key_rec ) { + if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { + ti = proto_tree_add_text(sec_tree, tvb, 0, 0, "Decryption Key: %s", key_rec->label); + } else { + ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, + key_rec->frame_num); } - key_buffer = zbee_sec_key_hash(zbee_sec_tclink_key, 0x02, pinfo); - break; + PROTO_ITEM_SET_GENERATED(ti); + } - default: - goto decrypt_failed; - } /* switch */ + /* Found a key that worked, setup the new tvbuff_t and return */ + payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); + tvb_set_free_cb(payload_tvb, g_free); /* set up callback to free dec_buffer */ + add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); - /* Create the nonce. */ - zbee_sec_make_nonce(nonce, &packet); - /* Allocate memory to decrypt the payload into. */ - dec_buffer = g_malloc(payload_len); - /* Perform Decryption. */ - if (!zbee_sec_ccm_decrypt(key_buffer, /* key */ - nonce, /* Nonce */ - enc_buffer, /* a, length l(a) */ - enc_buffer+offset, /* c, length l(c) = l(m) + M */ - dec_buffer, /* m, length l(m) */ - offset, /* l(a) */ - payload_len, /* l(m) */ - mic_len)) { /* M */ - /* Decryption Failed! */ - g_free(dec_buffer); - goto decrypt_failed; + /* Done! */ + return payload_tvb; } - /* Setup the new tvbuff_t and return */ - payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); - tvb_set_free_cb(payload_tvb, g_free); - add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); - /* Done! */ - return payload_tvb; - -decrypt_failed: + g_free(dec_buffer); #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ @@ -592,35 +712,97 @@ decrypt_failed: call_dissector(data_handle, payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; - } /* dissect_zbee_secure */ #ifdef HAVE_LIBGCRYPT /*FUNCTION:------------------------------------------------------ * NAME + * zbee_sec_decrypt_payload + * DESCRIPTION + * Creates a nonce and decrypts a secured payload. + * PARAMETERS + * gchar *nonce - Nonce Buffer. + * zbee_security_packet *packet - Security information. + * RETURNS + * void + *--------------------------------------------------------------- + */ +static gboolean +zbee_sec_decrypt_payload(zbee_security_packet *packet, const gchar *enc_buffer, const gchar offset, guint8 *dec_buffer, + guint payload_len, guint mic_len, guint8 *key) +{ + guint8 nonce[ZBEE_SEC_CONST_NONCE_LEN]; + guint8 buffer[ZBEE_SEC_CONST_BLOCKSIZE+1]; + guint8 *key_buffer = buffer; + + switch (packet->key_id) { + case ZBEE_SEC_KEY_NWK: + /* Decrypt with the PAN's current network key */ + case ZBEE_SEC_KEY_LINK: + /* Decrypt with the unhashed link key assigned by the trust center to this + * source/destination pair */ + key_buffer = key; + break; + + case ZBEE_SEC_KEY_TRANSPORT: + /* Decrypt with a Key-Transport key, a hashed link key that protects network + * keys sent from the trust center */ + zbee_sec_key_hash(key, 0x00, buffer); + key_buffer = buffer; + break; + + case ZBEE_SEC_KEY_LOAD: + /* Decrypt with a Key-Load key, a hashed link key that protects link keys + * sent from the trust center. */ + zbee_sec_key_hash(key, 0x02, buffer); + key_buffer = buffer; + break; + + default: + break; + } /* switch */ + + /* Perform Decryption. */ + zbee_sec_make_nonce(packet, nonce); + + if ( zbee_sec_ccm_decrypt(key_buffer, /* key */ + nonce, /* Nonce */ + enc_buffer, /* a, length l(a) */ + enc_buffer+offset, /* c, length l(c) = l(m) + M */ + dec_buffer, /* m, length l(m) */ + offset, /* l(a) */ + payload_len, /* l(m) */ + mic_len) ) { /* M */ + return TRUE; + } + else return FALSE; +} + +/*FUNCTION:------------------------------------------------------ + * NAME * zbee_sec_make_nonce * DESCRIPTION * Fills in the ZigBee security nonce from the provided security * packet structure. * PARAMETERS - * gchar *nonce - Nonce Buffer. * zbee_security_packet *packet - Security information. + * gchar *nonce - Nonce Buffer. * RETURNS * void *--------------------------------------------------------------- */ static void -zbee_sec_make_nonce(guint8 *nonce, zbee_security_packet *packet) +zbee_sec_make_nonce(zbee_security_packet *packet, guint8 *nonce) { /* First 8 bytes are the extended source address (little endian). */ - *(nonce++) = (guint8)((packet->src)>>0 & 0xff); - *(nonce++) = (guint8)((packet->src)>>8 & 0xff); - *(nonce++) = (guint8)((packet->src)>>16 & 0xff); - *(nonce++) = (guint8)((packet->src)>>24 & 0xff); - *(nonce++) = (guint8)((packet->src)>>32 & 0xff); - *(nonce++) = (guint8)((packet->src)>>40 & 0xff); - *(nonce++) = (guint8)((packet->src)>>48 & 0xff); - *(nonce++) = (guint8)((packet->src)>>56 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>0 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>8 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>16 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>24 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>32 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>40 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>48 & 0xff); + *(nonce++) = (guint8)((packet->src64)>>56 & 0xff); /* Next 4 bytes are the frame counter (little endian). */ *(nonce++) = (guint8)((packet->counter)>>0 & 0xff); *(nonce++) = (guint8)((packet->counter)>>8 & 0xff); @@ -806,7 +988,8 @@ zbee_sec_ccm_decrypt(const gchar *key, /* Input */ for (i=0;i<l_a;i++,j++) { if (j>=ZBEE_SEC_CONST_BLOCKSIZE) { /* Generate the next cipher block. */ - if (gcry_cipher_encrypt(cipher_hd, cipher_out, ZBEE_SEC_CONST_BLOCKSIZE, cipher_in, ZBEE_SEC_CONST_BLOCKSIZE)) { + if (gcry_cipher_encrypt(cipher_hd, cipher_out, ZBEE_SEC_CONST_BLOCKSIZE, cipher_in, + ZBEE_SEC_CONST_BLOCKSIZE)) { gcry_cipher_close(cipher_hd); return FALSE; } @@ -824,7 +1007,8 @@ zbee_sec_ccm_decrypt(const gchar *key, /* Input */ for (i=0; i<l_m; i++, j++) { if (j>=ZBEE_SEC_CONST_BLOCKSIZE) { /* Generate the next cipher block. */ - if (gcry_cipher_encrypt(cipher_hd, cipher_out, ZBEE_SEC_CONST_BLOCKSIZE, cipher_in, ZBEE_SEC_CONST_BLOCKSIZE)) { + if (gcry_cipher_encrypt(cipher_hd, cipher_out, ZBEE_SEC_CONST_BLOCKSIZE, cipher_in, + ZBEE_SEC_CONST_BLOCKSIZE)) { gcry_cipher_close(cipher_hd); return FALSE; } @@ -976,15 +1160,15 @@ zbee_sec_hash(guint8 *input, guint input_len, guint8 *output) * PARAMETERS * guint8 *key - ZigBee Security Key (must be ZBEE_SEC_CONST_KEYSIZE) in length. * guint8 input - ZigBee CCM* Nonce (must be ZBEE_SEC_CONST_NONCE_LEN) in length. + * packet_info *pinfo - pointer to packet information fields * RETURNS * guint8* *--------------------------------------------------------------- */ static guint8 * -zbee_sec_key_hash(guint8 *key, guint8 input, packet_info *pinfo _U_) +zbee_sec_key_hash(guint8 *key, guint8 input, guint8 *hash_out) { guint8 hash_in[2*ZBEE_SEC_CONST_BLOCKSIZE]; - guint8 * hash_out = ep_alloc(ZBEE_SEC_CONST_BLOCKSIZE+1); int i; static const guint8 ipad = 0x36; static const guint8 opad = 0x5c; @@ -1004,3 +1188,36 @@ zbee_sec_key_hash(guint8 *key, guint8 input, packet_info *pinfo _U_) return hash_out; } /* zbee_sec_key_hash */ #endif /* HAVE_LIBGCRYPT */ + +/*FUNCTION:------------------------------------------------------ + * NAME + * proto_init_zbee_security + * DESCRIPTION + * Init routine for the + * PARAMETERS + * none + * RETURNS + * void + *--------------------------------------------------------------- + */ +static void +proto_init_zbee_security(void) +{ + guint i; + key_record_t key_record; + + /* empty the key ring */ + if (zbee_pc_keyring) { + g_slist_free(zbee_pc_keyring); + zbee_pc_keyring = NULL; + } + + /* Load the pre-configured slist from the UAT. */ + for (i=0; (uat_key_records) && (i<num_uat_key_records) ; i++) { + key_record.frame_num = ZBEE_SEC_PC_KEY; /* means it's a user PC key */ + key_record.label = se_strdup(uat_key_records[i].label); + memcpy(&key_record.key, &uat_key_records[i].key, ZBEE_SEC_CONST_KEYSIZE); + + zbee_pc_keyring = g_slist_prepend(zbee_pc_keyring, se_memdup(&key_record, sizeof(key_record_t))); + } /* for */ +} /* proto_init_zbee_security */ diff --git a/epan/dissectors/packet-zbee-security.h b/epan/dissectors/packet-zbee-security.h index 257de8302c..56aee490e9 100644 --- a/epan/dissectors/packet-zbee-security.h +++ b/epan/dissectors/packet-zbee-security.h @@ -30,13 +30,13 @@ /* Structure containing the fields stored in the Aux Header */ typedef struct{ /* The fields of the Aux Header */ - guint8 control; - guint32 counter; - guint64 src; + guint8 control; /* needed to decrypt */ + guint32 counter; /* needed to decrypt */ + guint64 src64; /* needed to decrypt */ guint8 key_seqno; guint8 level; - guint8 key; + guint8 key_id; /* needed to decrypt */ gboolean nonce; } zbee_security_packet; @@ -64,7 +64,6 @@ typedef struct{ /* ZigBee Security Constants. */ #define ZBEE_SEC_CONST_L 2 #define ZBEE_SEC_CONST_NONCE_LEN (ZBEE_SEC_CONST_BLOCKSIZE-ZBEE_SEC_CONST_L-1) -#define ZBEE_SEC_CONST_KEYSIZE 16 #define ZBEE_SEC_CONST_BLOCKSIZE 16 /* CCM* Flags */ @@ -72,6 +71,9 @@ typedef struct{ #define ZBEE_SEC_CCM_FLAG_M(m) ((((m-2)/2) & 0x7)<<3) /* 3-bit encoding of (M-2)/2 shifted 3 bits. */ #define ZBEE_SEC_CCM_FLAG_ADATA(l_a) ((l_a>0)?0x40:0x00) /* Adata flag. */ +/* Program Constants */ +#define ZBEE_SEC_PC_KEY 0 + /* Init routine for the Security dissectors. */ extern void zbee_security_register (module_t *module, int proto); extern void zbee_security_handoff (void); diff --git a/epan/dissectors/packet-zbee.h b/epan/dissectors/packet-zbee.h index 2e0f11af79..e7aded465f 100644 --- a/epan/dissectors/packet-zbee.h +++ b/epan/dissectors/packet-zbee.h @@ -27,7 +27,7 @@ #define PACKET_ZBEE_H /* IEEE 802.15.4 definitions. */ -#include <epan/dissectors/packet-ieee802154.h> +#include "packet-ieee802154.h" /* The ZigBee Broadcast Address */ #define ZBEE_BCAST_ALL 0xffff @@ -576,10 +576,12 @@ #define ZBEE_MFG_KAGA "Kaga Electronics" #define ZBEE_MFG_4_NOKS "4-noks s.r.l." +/* Protocol Abbreviations */ +#define ZBEE_PROTOABBREV_NWK "zbee.nwk" +#define ZBEE_PROTOABBREV_APS "zbee.aps" +#define ZBEE_PROTOABBREV_APF "zbee.apf" + /* Helper Functions */ -extern proto_item *proto_tree_add_eui64(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, - gint length, gint64 value); extern guint zbee_get_bit_field(guint input, guint mask); #endif /* PACKET_ZBEE_H */ - |