diff --git a/epan/packet.c b/epan/packet.c index 33174b72b7..6a83263009 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -729,6 +729,67 @@ struct dissector_handle { protocol_t *protocol; }; +static void +add_layer(packet_info *pinfo, int proto_id) +{ + int *proto_layer_num_ptr; + + pinfo->curr_layer_num++; + wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_id)); + + /* Increment layer number for this proto id. */ + if (pinfo->proto_layers == NULL) { + pinfo->proto_layers = wmem_map_new(pinfo->pool, g_direct_hash, g_direct_equal); + } + + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + if (proto_layer_num_ptr == NULL) { + /* Insert new layer */ + proto_layer_num_ptr = wmem_new(pinfo->pool, int); + *proto_layer_num_ptr = 1; + wmem_map_insert(pinfo->proto_layers, GINT_TO_POINTER(proto_id), proto_layer_num_ptr); + } + else { + /* Increment layer number */ + (*proto_layer_num_ptr)++; + } + pinfo->curr_proto_layer_num = *proto_layer_num_ptr; +} + +static void +remove_last_layer(packet_info *pinfo, gboolean reduce_count) +{ + int *proto_layer_num_ptr; + wmem_list_frame_t *frame; + int proto_id; + + if (reduce_count) { + pinfo->curr_layer_num--; + } + + frame = wmem_list_tail(pinfo->layers); + proto_id = GPOINTER_TO_INT(wmem_list_frame_data(frame)); + wmem_list_remove_frame(pinfo->layers, frame); + + if (reduce_count) { + /* Reduce count for removed protocol layer. */ + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + if (proto_layer_num_ptr && *proto_layer_num_ptr > 0) { + (*proto_layer_num_ptr)--; + } + } + + /* Restore count for new last (protocol) layer. */ + frame = wmem_list_tail(pinfo->layers); + if (frame) { + proto_id = GPOINTER_TO_INT(wmem_list_frame_data(frame)); + proto_layer_num_ptr = wmem_map_lookup(pinfo->proto_layers, GINT_TO_POINTER(proto_id)); + ws_assert(proto_layer_num_ptr); + pinfo->curr_proto_layer_num = *proto_layer_num_ptr; + } +} + + /* This function will return * old style dissector : * length of the payload or 1 of the payload is empty @@ -788,10 +849,9 @@ call_dissector_work_error(dissector_handle_t handle, tvbuff_t *tvb, #define PINFO_LAYER_MAX_RECURSION_DEPTH 500 static int -call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo_arg, +call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean add_proto_name, void *data) { - packet_info *pinfo = pinfo_arg; const char *saved_proto; guint16 saved_can_desegment; int len; @@ -836,8 +896,7 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo */ /* XXX Should we check for a duplicate layer here? */ if (add_proto_name) { - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_get_id(handle->protocol))); + add_layer(pinfo, proto_get_id(handle->protocol)); } } @@ -857,16 +916,13 @@ call_dissector_work(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo * tree. Remove it. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - if (len == 0) { - /* - * Only reduce the layer number if the dissector - * rejected the data. Since tree can be NULL on - * the first pass, we cannot check it or it will - * break dissectors that rely on a stable value. - */ - pinfo->curr_layer_num--; - } - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + /* + * Only reduce the layer number if the dissector + * rejected the data. Since tree can be NULL on + * the first pass, we cannot check it or it will + * break dissectors that rely on a stable value. + */ + remove_last_layer(pinfo, len == 0); } } pinfo->current_proto = saved_proto; @@ -2875,8 +2931,7 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors, tvbuff_t *tvb, * Add the protocol name to the layers; we'll remove it * if the dissector fails. */ - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_id)); + add_layer(pinfo, proto_id); } pinfo->heur_list_name = hdtbl_entry->list_name; @@ -2890,16 +2945,13 @@ dissector_try_heuristic(heur_dissector_list_t sub_dissectors, tvbuff_t *tvb, * items to the tree so remove it from the list. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - if (len == 0) { - /* - * Only reduce the layer number if the dissector - * rejected the data. Since tree can be NULL on - * the first pass, we cannot check it or it will - * break dissectors that rely on a stable value. - */ - pinfo->curr_layer_num--; - } - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + /* + * Only reduce the layer number if the dissector + * rejected the data. Since tree can be NULL on + * the first pass, we cannot check it or it will + * break dissectors that rely on a stable value. + */ + remove_last_layer(pinfo, len == 0); } } if (len) { @@ -3368,8 +3420,7 @@ void call_heur_dissector_direct(heur_dtbl_entry_t *heur_dtbl_entry, tvbuff_t *tv /* do NOT change this behavior - wslua uses the protocol short name set here in order to determine which Lua-based heuristic dissector to call */ pinfo->current_proto = proto_get_protocol_short_name(heur_dtbl_entry->protocol); - pinfo->curr_layer_num++; - wmem_list_append(pinfo->layers, GINT_TO_POINTER(proto_get_id(heur_dtbl_entry->protocol))); + add_layer(pinfo, proto_get_id(heur_dtbl_entry->protocol)); } pinfo->heur_list_name = heur_dtbl_entry->list_name; @@ -3384,8 +3435,7 @@ void call_heur_dissector_direct(heur_dtbl_entry_t *heur_dtbl_entry, tvbuff_t *tv * items to the tree so remove it from the list. */ while (wmem_list_count(pinfo->layers) > saved_layers_len) { - pinfo->curr_layer_num--; - wmem_list_remove_frame(pinfo->layers, wmem_list_tail(pinfo->layers)); + remove_last_layer(pinfo, TRUE); } } diff --git a/epan/packet_info.h b/epan/packet_info.h index 439c5880c1..6c723d46ff 100644 --- a/epan/packet_info.h +++ b/epan/packet_info.h @@ -132,8 +132,10 @@ typedef struct _packet_info { GHashTable *private_table; /**< a hash table passed from one dissector to another */ - wmem_list_t *layers; /**< layers of each protocol */ - guint8 curr_layer_num; /**< The current "depth" or layer number in the current frame */ + wmem_list_t *layers; /**< layers of each protocol */ + wmem_map_t *proto_layers; /** map of proto_id to curr_layer_num. */ + guint8 curr_layer_num; /**< The current "depth" or layer number in the current frame */ + guint8 curr_proto_layer_num; /**< The current "depth" or layer number for this dissector in the current frame */ guint16 link_number; guint16 clnp_srcref; /**< clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ diff --git a/epan/proto.c b/epan/proto.c index b9522a9ec8..5f6dfab82d 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -6309,6 +6309,9 @@ new_field_info(proto_tree *tree, header_field_info *hfinfo, tvbuff_t *tvb, fi->appendix_start = 0; fi->appendix_length = 0; + fi->total_layer_num = tree->tree_data->pinfo->curr_layer_num; + fi->proto_layer_num = tree->tree_data->pinfo->curr_proto_layer_num; + return fi; } diff --git a/epan/proto.h b/epan/proto.h index fe28d8e463..6854ed8247 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -798,6 +798,8 @@ typedef struct field_info { item_label_t *rep; /**< string for GUI tree */ tvbuff_t *ds_tvb; /**< data source tvbuff */ fvalue_t value; + int total_layer_num; /**< Hierarchical layer number, for all protocols in the tree. */ + int proto_layer_num; /**< Protocol layer number, so 1st, 2nd, 3rd, ... for protocol X. */ } field_info;