From a148a936b180524ac44a4b4f195d8ea6774bf216 Mon Sep 17 00:00:00 2001 From: Jeff Morriss Date: Tue, 5 Apr 2011 02:18:28 +0000 Subject: [PATCH] From Felix Kraemer: fix https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5694 : This patch adds the capability to create BACnet statistics trees. Find the respective menu items under 'Statistics->BACnet'. Packets can be sorted by different criteria: - Src/Dst IP adresses - Instance ID - Object Type - Service From me: - Don't use C++/C99-style comments. - Name variables for tick_stat_node() don't need to be static. - Change updateBacnetInfoValue() to require 'data' to be ep_ allocated. Change the couple of calls that did not send in ep_ allocated data to do so. - Change one or two functions to be static. - Do not use (memory-unsafe) g_sprintf(). - Use ep_strconcat() instead of leaking memory with g_strconcat(). - Put back one if(tree) that doesn't appear to do any harm. - Remove variable declarations and #includes from the header file. svn path=/trunk/; revision=36468 --- AUTHORS | 4 + epan/dissectors/Makefile.common | 1 + epan/dissectors/packet-bacapp.c | 493 ++++++++++++++++++++++++-------- epan/dissectors/packet-bacapp.h | 42 +++ epan/wslua/taps | 2 + 5 files changed, 420 insertions(+), 122 deletions(-) create mode 100644 epan/dissectors/packet-bacapp.h diff --git a/AUTHORS b/AUTHORS index 42c71a5443..78c5409218 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3140,6 +3140,10 @@ Herbert Lischka { BACNET dissector fixes and enhancements } +Felix Krämer { + Stats Tree for BACapp dissector +} + Tom Hughes { FCGI dissector } diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index cbf6951803..8e79a7491f 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -1033,6 +1033,7 @@ DISSECTOR_INCLUDES = \ packet-assa_r3_public.h \ packet-atalk.h \ packet-atm.h \ + packet-bacapp.h \ packet-ber.h \ packet-bgp.h \ packet-bootparams.h \ diff --git a/epan/dissectors/packet-bacapp.c b/epan/dissectors/packet-bacapp.c index 94b6e4200c..b41b9c55f4 100644 --- a/epan/dissectors/packet-bacapp.c +++ b/epan/dissectors/packet-bacapp.c @@ -3,6 +3,8 @@ * Copyright 2001, Hartmut Mueller , FH Dortmund * Enhanced by Steve Karg, 2005, , Atlanta * Enhanced by Herbert Lischka, 2005, , Berlin + * Enhanced by Felix Kraemer, 2010, , + * Sauter-Cumulus GmbH, Freiburg * * $Id$ * @@ -36,6 +38,10 @@ #include #include #include +#include +#include "packet-bacapp.h" + +static int bacapp_tap = -1; /* formerly bacapp.h contains definitions and forward declarations */ @@ -3986,6 +3992,217 @@ static guint8 bacapp_seq = 0; /* Defined to allow vendor identifier registration of private transfer dissectors */ static dissector_table_t bacapp_dissector_table; + +/* Stat: BACnet Packets sorted by IP */ +bacapp_info_value_t bacinfo; + +static const gchar* st_str_packets_by_ip = "BACnet Packets by IP"; +static const gchar* st_str_packets_by_ip_dst = "By Destination"; +static const gchar* st_str_packets_by_ip_src = "By Source"; +static int st_node_packets_by_ip = -1; +static int st_node_packets_by_ip_dst = -1; +static int st_node_packets_by_ip_src = -1; + +static void +bacapp_packet_stats_tree_init(stats_tree* st) +{ + st_node_packets_by_ip = stats_tree_create_pivot(st, st_str_packets_by_ip, 0); + st_node_packets_by_ip_src = stats_tree_create_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, TRUE); + st_node_packets_by_ip_dst = stats_tree_create_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, TRUE); +} + +static int +bacapp_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) +{ + int packets_for_this_dst; + int packets_for_this_src; + int service_for_this_dst; + int service_for_this_src; + int src_for_this_dst; + int dst_for_this_src; + int objectid_for_this_dst; + int objectid_for_this_src; + int instanceid_for_this_dst; + int instanceid_for_this_src; + gchar *dststr; + gchar *srcstr; + const bacapp_info_value_t *binfo = p; + + srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL); + dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL); + + tick_stat_node(st, st_str_packets_by_ip, 0, TRUE); + packets_for_this_dst = tick_stat_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, TRUE); + packets_for_this_src = tick_stat_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, TRUE); + src_for_this_dst = tick_stat_node(st, dststr, packets_for_this_dst, TRUE); + dst_for_this_src = tick_stat_node(st, srcstr, packets_for_this_src, TRUE); + service_for_this_src = tick_stat_node(st, dststr, dst_for_this_src, TRUE); + service_for_this_dst = tick_stat_node(st, srcstr, src_for_this_dst, TRUE); + if (binfo->service_type) { + objectid_for_this_dst = tick_stat_node(st, binfo->service_type, service_for_this_dst, TRUE); + objectid_for_this_src = tick_stat_node(st, binfo->service_type, service_for_this_src, TRUE); + if (binfo->object_ident) { + instanceid_for_this_dst=tick_stat_node(st, binfo->object_ident, objectid_for_this_dst, TRUE); + tick_stat_node(st, binfo->instance_ident, instanceid_for_this_dst, FALSE); + instanceid_for_this_src=tick_stat_node(st, binfo->object_ident, objectid_for_this_src, TRUE); + tick_stat_node(st, binfo->instance_ident, instanceid_for_this_src, FALSE); + } + } + + return 1; +} + +/* Stat: BACnet Packets sorted by Service */ +static const gchar* st_str_packets_by_service = "BACnet Packets by Service"; +static int st_node_packets_by_service = -1; + +static void +bacapp_service_stats_tree_init(stats_tree* st) +{ + st_node_packets_by_service = stats_tree_create_pivot(st, st_str_packets_by_service, 0); +} + +static int +bacapp_stats_tree_service(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) +{ + int servicetype; + int src,dst; + int objectid; + + gchar *dststr; + gchar *srcstr; + const bacapp_info_value_t *binfo = p; + + srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL); + dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL); + + tick_stat_node(st, st_str_packets_by_service, 0, TRUE); + if (binfo->service_type) { + servicetype = tick_stat_node(st, binfo->service_type, st_node_packets_by_service, TRUE); + src = tick_stat_node(st, srcstr, servicetype, TRUE); + dst = tick_stat_node(st, dststr, src, TRUE); + if (binfo->object_ident) { + objectid = tick_stat_node(st, binfo->object_ident, dst, TRUE); + tick_stat_node(st, binfo->instance_ident, objectid, FALSE); + } + } + + return 1; +} + +/* Stat: BACnet Packets sorted by Object Type */ +static const gchar* st_str_packets_by_objectid = "BACnet Packets by Object Type"; +static int st_node_packets_by_objectid = -1; + +static void +bacapp_objectid_stats_tree_init(stats_tree* st) +{ + st_node_packets_by_objectid = stats_tree_create_pivot(st, st_str_packets_by_objectid, 0); +} + +static int +bacapp_stats_tree_objectid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) +{ + int servicetype; + int src,dst; + int objectid; + + gchar *dststr; + gchar *srcstr; + const bacapp_info_value_t *binfo = p; + + srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL); + dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL); + + tick_stat_node(st, st_str_packets_by_objectid, 0, TRUE); + if (binfo->object_ident) { + objectid = tick_stat_node(st, binfo->object_ident, st_node_packets_by_objectid, TRUE); + src = tick_stat_node(st, srcstr, objectid, TRUE); + dst = tick_stat_node(st, dststr, src, TRUE); + if (binfo->service_type) { + servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE); + tick_stat_node(st, binfo->instance_ident, servicetype, FALSE); + } + } + + return 1; +} + +/* Stat: BACnet Packets sorted by Instance No */ +static const gchar* st_str_packets_by_instanceid = "BACnet Packets by Instance ID"; +static int st_node_packets_by_instanceid = -1; + +static void +bacapp_instanceid_stats_tree_init(stats_tree* st) +{ + st_node_packets_by_instanceid = stats_tree_create_pivot(st, st_str_packets_by_instanceid, 0); +} + +static int +bacapp_stats_tree_instanceid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p) +{ + int servicetype; + int src,dst; + int instanceid; + + gchar *dststr; + gchar *srcstr; + const bacapp_info_value_t *binfo = p; + + srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL); + dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL); + + tick_stat_node(st, st_str_packets_by_instanceid, 0, TRUE); + if (binfo->object_ident) { + instanceid = tick_stat_node(st, binfo->instance_ident, st_node_packets_by_instanceid, TRUE); + src = tick_stat_node(st, srcstr, instanceid, TRUE); + dst = tick_stat_node(st, dststr, src, TRUE); + if (binfo->service_type) { + servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE); + tick_stat_node(st, binfo->object_ident, servicetype, FALSE); + } + } + return 1; +} + + +/* register all BACnet Ststistic trees */ +static void +register_bacapp_stat_trees(void) +{ + stats_tree_register("bacapp","bacapp_ip","BACnet/Packets sorted by IP", 0, + bacapp_stats_tree_packet, bacapp_packet_stats_tree_init, NULL); + stats_tree_register("bacapp","bacapp_service","BACnet/Packets sorted by Service", 0, + bacapp_stats_tree_service, bacapp_service_stats_tree_init, NULL); + stats_tree_register("bacapp","bacapp_objectid","BACnet/Packets sorted by Object Type", 0, + bacapp_stats_tree_objectid, bacapp_objectid_stats_tree_init, NULL); + stats_tree_register("bacapp","bacapp_instanceid","BACnet/Packets sorted by Instance ID", 0, + bacapp_stats_tree_instanceid, bacapp_instanceid_stats_tree_init, NULL); +} + +/* 'data' must be ep_ allocated */ +static gint +updateBacnetInfoValue(gint whichval, gchar *data) +{ + if (whichval == BACINFO_SERVICE) { + bacinfo.service_type = data; + return 0; + } + if (whichval == BACINFO_INVOKEID) { + bacinfo.invoke_id = data; + return 0; + } + if (whichval == BACINFO_OBJECTID) { + bacinfo.object_ident = data; + return 0; + } + if (whichval == BACINFO_INSTANCEID) { + bacinfo.instance_ident = data; + return 0; + } + return -1; +} + static const fragment_items msg_frag_items = { /* Fragment subtrees */ &ett_msg_fragment, @@ -4203,8 +4420,8 @@ fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset, } else *lvt = value; } - if (tree) - { + + if (tree) { if (tag_is_opening(tag)) ti = proto_tree_add_text(tree, tvb, offset, tag_len, "{[%u]", *tag_no ); else if (tag_is_closing(tag)) @@ -4293,8 +4510,7 @@ fBooleanTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) guint bool_len = 1; tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_info && lvt == 1) - { + if (tag_info && lvt == 1) { lvt = tvb_get_guint8(tvb, offset+1); ++bool_len; } @@ -4537,13 +4753,11 @@ fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) month = tvb_get_guint8(tvb, offset+tag_len+1); day = tvb_get_guint8(tvb, offset+tag_len+2); weekday = tvb_get_guint8(tvb, offset+tag_len+3); - if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) - { + if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) { ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%sany", label); } - else if (year != 255) - { + else if (year != 255) { year += 1900; ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s%s %d, %d, (Day of Week = %s)", @@ -4553,9 +4767,7 @@ fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) day, year, val_to_str(weekday, day_of_week, "(%d) not found")); - } - else - { + } else { ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s%s %d, any year, (Day of Week = %s)", label, val_to_str(month, months, "month (%d) not found"), @@ -4658,8 +4870,8 @@ fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset) return offset; } -static guint fTimeStamp (tvbuff_t *tvb, proto_tree *tree, - guint offset, const gchar *label) +static guint +fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; @@ -4738,8 +4950,7 @@ fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (lvt > 0) - { + if (lvt > 0) { tmp = tvb_bytes_to_str(tvb, offset, lvt); ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp); offset += lvt; @@ -4766,8 +4977,7 @@ fMacAddress (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, ti = proto_tree_add_text(tree, tvb, offset, 6, "%s", label); /* just add the label, with the tagHeader information in its subtree */ - if (lvt > 0) - { + if (lvt > 0) { if (lvt == 6) { /* we have 6 Byte IP Address with 4 Octets IPv4 and 2 Octets Port Information */ guint32 ip = tvb_get_ipv4(tvb, offset); @@ -4856,6 +5066,14 @@ fObjectIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint of Vendor_Proprietary_Fmt), object_id_instance(object_id)); + /* update BACnet Statistics */ + updateBacnetInfoValue(BACINFO_OBJECTID, + ep_strdup(val_to_split_str(object_type, 128, + BACnetObjectType, ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt))); + updateBacnetInfoValue(BACINFO_INSTANCEID, ep_strdup_printf("Instance ID: %u", + object_id_instance(object_id))); + /* here are the details of how we arrived at the above text */ subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -5167,8 +5385,7 @@ fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *la character_set = tvb_get_guint8(tvb, offset+offs); /* Account for code page if DBCS */ - if (character_set == 1) - { + if (character_set == 1) { extra = 3; } offset += (offs+extra); @@ -5234,8 +5451,7 @@ fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *la fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt); proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, FALSE); - if (character_set == 1) - { + if (character_set == 1) { proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1)); } } @@ -5295,8 +5511,7 @@ fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *lab } } - if (src == NULL) - { + if (src == NULL) { bf_arr[MIN(255,numberOfBytes*8-unused)] = 0; proto_tree_add_text(subtree, tvb, offset, lvt, "B'%s'", bf_arr); } @@ -5325,8 +5540,7 @@ fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, packet_info *pinfo, proto_tree if (tvb_reported_length_remaining(tvb, offset) > 0) { tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (!tag_is_context_specific(tag_info)) - { + if (!tag_is_context_specific(tag_info)) { switch (tag_no) { case 0: /** NULL 20.2.2 */ offset = fNullTag(tvb, tree, offset, label); @@ -5436,8 +5650,7 @@ fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar * tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt); /* cap the the suggested length in case of bad data */ tvb_len = tvb_reported_length_remaining(tvb, offset+tag_len); - if ((tvb_len >= 0) && ((guint32)tvb_len < lvt)) - { + if ((tvb_len >= 0) && ((guint32)tvb_len < lvt)) { lvt = tvb_len; } ti = proto_tree_add_text(tree, tvb, offset+tag_len, lvt, @@ -5457,16 +5670,13 @@ fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint guint lastoffset = 0, depth = 0; char ar[256]; - if (propertyIdentifier >= 0) - { + if (propertyIdentifier >= 0) { g_snprintf (ar, sizeof(ar), "%s: ", val_to_split_str(propertyIdentifier, 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt)); - } - else - { + } else { g_snprintf (ar, sizeof(ar), "Abstract Type: "); } while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ @@ -5537,8 +5747,7 @@ fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint } break; case 38: /* exception-schedule */ - if (object_type < 128) - { + if (object_type < 128) { if (propertyArrayIndex == 0) { /* BACnetARRAY index 0 refers to the length of the array, not the elements of the array */ @@ -5555,8 +5764,7 @@ fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset = fDeviceObjectPropertyReference (tvb, pinfo, tree, offset); break; case 123: /* weekly-schedule -- accessed as a BACnetARRAY */ - if (object_type < 128) - { + if (object_type < 128) { if (propertyArrayIndex == 0) { /* BACnetARRAY index 0 refers to the length of the array, not the elements of the array */ @@ -5588,25 +5796,17 @@ fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset = fCOVSubscription (tvb, pinfo, tree, offset); break; default: - if (tag_info) - { - if (tag_is_opening(tag_info)) - { + if (tag_info) { + if (tag_is_opening(tag_info)) { ++depth; offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); - } - else if (tag_is_closing(tag_info)) - { + } else if (tag_is_closing(tag_info)) { --depth; offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); - } - else - { + } else { offset = fContextTaggedValue(tvb, tree, offset, ar); } - } - else - { + } else { offset = fApplicationTypes (tvb, pinfo, tree, offset, ar); } break; @@ -5649,8 +5849,7 @@ fPropertyIdentifierValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, g guint32 lvt; offset = fPropertyReference(tvb, pinfo, tree, offset, tagoffset, 0); - if (offset > lastoffset) - { + if (offset > lastoffset) { fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_no == tagoffset+2) { /* Value - might not be present in ReadAccessResult */ offset = fPropertyValue (tvb, pinfo, tree, offset, tag_info); @@ -5669,8 +5868,7 @@ fBACnetPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fPropertyIdentifierValue(tvb, pinfo, tree, offset, 0); - if (offset > lastoffset) - { + if (offset > lastoffset) { /* detect optional priority by looking to see if the next tag is context tag number 3 */ fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); @@ -5780,8 +5978,7 @@ fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint of guint32 lvt; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_opening(tag_info) && tag_no == 0) - { + if (tag_is_opening(tag_info) && tag_no == 0) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; @@ -5795,9 +5992,7 @@ fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint of offset = fTimeValue (tvb, pinfo, subtree, offset); if (offset == lastoffset) break; /* nothing happened, exit loop */ } - } - else if (tag_no == 0 && lvt == 0) - { + } else if (tag_no == 0 && lvt == 0) { /* not sure null (empty array element) is legal */ offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } @@ -6002,8 +6197,7 @@ fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree * next_tvb = tvb_new_subset_remaining(tvb,offset); if (dissector_try_uint(bacapp_dissector_table, - vendor_identifier, next_tvb, pinfo, tree)) - { + vendor_identifier, next_tvb, pinfo, tree)) { /* we parsed it so skip over length and we are done */ offset += tvb_length(next_tvb); return offset; @@ -6016,14 +6210,11 @@ fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree * lastoffset = offset; len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { - if (tag_no == 2) /* Make sure it's the expected tag */ - { + if (tag_no == 2) { /* Make sure it's the expected tag */ offset += len; subtree = tree; continue; - } - else - { + } else { break; /* End loop if incorrect closing tag */ } } @@ -7729,8 +7920,7 @@ fSpecialEvent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint off switch (tag_no) { case 0: /* calendaryEntry */ - if (tag_is_opening(tag_info)) - { + if (tag_is_opening(tag_info)) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); offset = fCalendaryEntry (tvb, subtree, offset); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -7981,8 +8171,7 @@ fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, gui lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_no < 2) - { + if (tag_no < 2) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* objectSpecifier */ @@ -8109,25 +8298,22 @@ fAccessMethod(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_opening(tag_info)) - { + if (tag_is_opening(tag_info)) { tt = proto_tree_add_text(tree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "invalid access method")); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "invalid option")); offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileWriteInfo, "unknown option")); - if (tag_no == 1) - { - while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) - { /* exit loop if nothing happens inside */ + if (tag_no == 1) { + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { + /* exit loop if nothing happens inside */ lastoffset = offset; offset = fApplicationTypes (tvb, pinfo, subtree, offset, "Record Data: "); } } - if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0) - { + if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0) { /* More Flag is not set, so we can look for closing tag in this segment */ fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { @@ -8150,8 +8336,7 @@ fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guin fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_opening(tag_info)) - { + if (tag_is_opening(tag_info)) { tt = proto_tree_add_text(subtree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "unknown access method")); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -8476,7 +8661,7 @@ fUnconfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree static guint fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset, guint8 ack, - gint *svc, proto_item **tt) + gint *svc, proto_item **tt) { proto_item *tc; proto_tree *bacapp_tree_control; @@ -8501,8 +8686,7 @@ fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, TRUE); proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE); - if (ack == 0) /* The following are for ConfirmedRequest, not Complex ack */ - { + if (ack == 0) { /* The following are for ConfirmedRequest, not Complex ack */ proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE); proto_tree_add_item(bacapp_tree, hf_bacapp_response_segments, tvb, offset, 1, TRUE); @@ -8719,12 +8903,10 @@ fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; - if (fTagNo(tvb, offset) == 0) - { + if (fTagNo(tvb, offset) == 0) { /* errorType */ offset = fContextTaggedError(tvb, pinfo, tree,offset); - if (fTagNo(tvb, offset) == 1) - { + if (fTagNo(tvb, offset) == 1) { /* listOfVTSessionIdentifiers [OPTIONAL] */ offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); offset = fVtCloseRequest (tvb, pinfo, tree, offset); @@ -8864,7 +9046,7 @@ do_the_dissection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) flag = (gint) tvb_get_guint8(tvb, 0); bacapp_type = (flag >> 4) & 0x0f; - if (tvb == NULL || tree == NULL) { + if (tvb == NULL) { return 0; } @@ -8915,6 +9097,15 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_item *tt = 0; gint8 ack = 0; + /* Strings for BACnet Statistics */ + const gchar errstr[]="ERROR: "; + const gchar rejstr[]="REJECTED: "; + const gchar abortstr[]="ABORTED: "; + const gchar sackstr[]=" (SimpleAck)"; + const gchar cackstr[]=" (ComplexAck)"; + const gchar uconfsreqstr[]=" (Unconfirmed Service Request)"; + const gchar confsreqstr[]=" (Confirmed Service Request)"; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU"); col_clear (pinfo->cinfo, COL_INFO); @@ -8925,12 +9116,16 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) col_add_fstr(pinfo->cinfo, COL_INFO, "%-16s", val_to_str(bacapp_type, BACnetTypeName, "# unknown APDU #")); + bacinfo.service_type = NULL; + bacinfo.invoke_id = NULL; + bacinfo.instance_ident = NULL; + bacinfo.object_ident = NULL; + switch (bacapp_type) { case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* segmented messages have 2 additional bytes */ - if (flag & BACAPP_SEGMENTED_REQUEST) - { + if (flag & BACAPP_SEGMENTED_REQUEST) { fragment = TRUE; ack = 0; bacapp_apdu_size = fGetMaxAPDUSize(tvb_get_guint8(tvb, offset + 1)); /* has 16 values, reserved are 50 Bytes */ @@ -8939,9 +9134,7 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 4); bacapp_service = tvb_get_guint8(tvb, offset + 5); data_offset = 6; - } - else - { + } else { bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2); bacapp_service = tvb_get_guint8(tvb, offset + 3); } @@ -8949,6 +9142,15 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) val_to_str(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str),bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), + confsreqstr, NULL)); break; case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: bacapp_service = tvb_get_guint8(tvb, offset + 1); @@ -8956,6 +9158,12 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) val_to_str(bacapp_service, BACnetUnconfirmedServiceChoice, bacapp_unknown_service_str)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(val_to_str(bacapp_service, + BACnetUnconfirmedServiceChoice, + bacapp_unknown_service_str), + uconfsreqstr, NULL)); break; case BACAPP_TYPE_SIMPLE_ACK: bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); @@ -8964,11 +9172,19 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) val_to_str(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), + sackstr, NULL)); break; case BACAPP_TYPE_COMPLEX_ACK: /* segmented messages have 2 additional bytes */ - if (flag & BACAPP_SEGMENTED_REQUEST) - { + if (flag & BACAPP_SEGMENTED_REQUEST) { fragment = TRUE; ack = 1; bacapp_apdu_size = fGetMaxAPDUSize(0); /* has minimum of 50 Bytes */ @@ -8977,9 +9193,7 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 3); bacapp_service = tvb_get_guint8(tvb, offset + 4); data_offset = 5; - } - else - { + } else { bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); bacapp_service = tvb_get_guint8(tvb, offset + 2); } @@ -8987,6 +9201,15 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) val_to_str(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), + cackstr, NULL)); break; case BACAPP_TYPE_SEGMENT_ACK: /* nothing more to add */ @@ -8998,6 +9221,16 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) val_to_str(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(errstr, + val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), + NULL)); break; case BACAPP_TYPE_REJECT: bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); @@ -9008,6 +9241,17 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) BACnetRejectReason, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(rejstr, + val_to_split_str(bacapp_reason, 64, + BACnetRejectReason, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt), + NULL)); break; case BACAPP_TYPE_ABORT: bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); @@ -9018,6 +9262,18 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) BACnetAbortReason, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), bacapp_invoke_id); + + updateBacnetInfoValue(BACINFO_INVOKEID, + ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id)); + + updateBacnetInfoValue(BACINFO_SERVICE, + ep_strconcat(abortstr, + val_to_split_str(bacapp_reason, + 64, + BACnetAbortReason, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt), + NULL)); break; /* UNKNOWN */ default: @@ -9027,17 +9283,14 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) save_fragmented = pinfo->fragmented; - if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); - ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE); - bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); - - if (!fragment) - offset = do_the_dissection(tvb,pinfo,bacapp_tree); - else - fStartConfirmed(tvb, pinfo, bacapp_tree, offset, ack, &svc, &tt); + if (!fragment) + offset = do_the_dissection(tvb,pinfo,bacapp_tree); + else + fStartConfirmed(tvb, pinfo, bacapp_tree, offset, ack, &svc, &tt); /* not resetting the offset so the remaining can be done */ - } if (fragment) { /* fragmented */ fragment_data *frag_msg = NULL; @@ -9082,6 +9335,8 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) pinfo->fragmented = save_fragmented; + /* tapping */ + tap_queue_packet(bacapp_tap,pinfo,&bacinfo); } static void @@ -9123,34 +9378,25 @@ uni_to_string(char * data, gsize str_length, char *dest_buf) length_remaining = str_length; dest_buf[0] = '\0'; - if(str_length == 0) - { + if(str_length == 0) { return; } - for ( i = 0; i < (gint) str_length; i++ ) - { + for ( i = 0; i < (gint) str_length; i++ ) { c_char = data[i]; - if (c_char<0x20 || c_char>0x7e) - { - if (c_char != 0x00) - { + if (c_char<0x20 || c_char>0x7e) { + if (c_char != 0x00) { c_char = '.'; dest_buf[i] = c_char & 0xff; - } - else - { + } else { i--; str_length--; } - } - else - { + } else { dest_buf[i] = c_char & 0xff; } length_remaining--; - if(length_remaining==0) - { + if(length_remaining==0) { dest_buf[i+1] = '\0'; return; } @@ -9402,6 +9648,9 @@ proto_register_bacapp(void) "BACapp Vendor Identifier", FT_UINT8, BASE_HEX); + /* Register BACnet Statistic trees */ + register_bacapp_stat_trees(); + bacapp_tap = register_tap("bacapp"); /* BACnet statistics tap */ } void diff --git a/epan/dissectors/packet-bacapp.h b/epan/dissectors/packet-bacapp.h new file mode 100644 index 0000000000..cd2e1d560e --- /dev/null +++ b/epan/dissectors/packet-bacapp.h @@ -0,0 +1,42 @@ +/* packet-bacapp.h + * by fkraemer, SAUTER + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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. + */ + +#ifndef __PACKET_BACNET_H__ +#define __PACKET_BACNET_H__ + +#define BACINFO_SERVICE 0 +#define BACINFO_INVOKEID 1 +#define BACINFO_INSTANCEID 2 +#define BACINFO_OBJECTID 4 + + +/* Used for BACnet statistics */ +typedef struct _bacapp_info_value_t { + gchar *service_type; + gchar *invoke_id; + gchar *instance_ident; + gchar *object_ident; +} bacapp_info_value_t; + +#endif /* __PACKET_BACNET_H__ */ diff --git a/epan/wslua/taps b/epan/wslua/taps index 13c2fabc1a..c5e06e7f78 100644 --- a/epan/wslua/taps +++ b/epan/wslua/taps @@ -35,6 +35,8 @@ ip ../dissectors/packet-ip.h ws_ip udp ../dissectors/packet-udp.h e_udphdr http ../dissectors/packet-http.h http_info_value_t +# BACnet statistics +bacapp ../dissectors/packet-bacapp.h bacapp_info_value_t h225 ../dissectors/packet-h225.h h225_packet_info h225_msg_type h225_cs_type actrace ../dissectors/packet-actrace.h actrace_info_t #afp ../dissectors/packet-afp.h