Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Ethereal-dev: [Ethereal-dev] Patch to packet-bacapp.c

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Herbert Lischka <herbert@xxxxxxxxxxxxxxxxx>
Date: Wed, 16 Feb 2005 18:13:18 +0100
Hi list,

this patch implements some (not all) tags according to bacnet application handbook

please check in

thanks
Herbert
Index: epan/dissectors/packet-bacapp.c
===================================================================
--- epan/dissectors/packet-bacapp.c	(revision 13415)
+++ epan/dissectors/packet-bacapp.c	(working copy)
@@ -2,6 +2,8 @@
  * Routines for BACnet (APDU) dissection
  * Copyright 2001, Hartmut Mueller <hartmut@xxxxxxxxxxxx>, FH Dortmund
  *
+ * modified 2004, Herbert Lischka <lischka@xxxxxxxxxxxxxxxx>, Berlin
+ *
  * $Id$
  *
  * Ethereal - Network traffic analyzer
@@ -37,81 +39,3538 @@
 
 #include <epan/packet.h>
 
-static const char*
-bacapp_type_name (guint8 bacapp_type){
-  static const char *type_names[] = {
-	"Confirmed-Request-PDU",
-	"Unconfirmed-Request-PDU",
-	"SimpleACK-PDU",
-	"ComplexACK-PDU",
-	"SegmentACK-PDU",
-	"Error-PDU",
-	"Reject-PDU",
-	"Abort-PDU"
-	};
-        return (bacapp_type > 7)? "unknown PDU" : type_names[bacapp_type];
-}
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
 
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+static const value_string bacapp_type_name[] = {
+	{0, "Conf-Request "},
+	{1, "Unconf-Request "},
+	{2, "SimpleACK-PDU "},
+	{3, "ComplexACK-PDU "},
+	{4, "SegmentACK-PDU "},
+	{5, "#### Error-PDU #### "},
+	{6, "---- Reject-PDU ---- "},
+	{7, "==== Abort-PDU ==== "},
+	{0, NULL }
+};
+
+static const true_false_string segments_follow = {
+	"Segmented Request",
+	"Unsegemented Request"
+};
+
+static const true_false_string more_follow = {
+	"More Segments Follow",
+	"No More Segments Follow"
+};
+
+static const true_false_string segmented_accept = {
+	"Segmented Response accepted",
+	"Segmented Response not accepted"
+};
+
+static const true_false_string bacapp_tag_class = {
+	"Context Specific Tag",
+	"Application Tag"
+};
+
+static const value_string
+bacapp_max_segments_accepted [] = {
+	{0, "Unspecified"},
+	{1,	"2 segments"},
+	{2,	"4 segments"},
+	{3,	"8 segments"},
+	{4,	"16 segments"},
+	{5,	"32 segments"},
+	{6,	"64 segments"},
+	{7,	"Greater than 64 segments"},
+	{0, NULL }
+};
+
+static const value_string
+bacapp_max_APDU_length_accepted [] = {
+	{0,	"Up to MinimumMessageSize (50 octets)"},
+	{1,	"Up to 128 octets"},
+	{2,	"Up to 206 octets (fits in a LonTalk frame)"},
+	{3,	"Up to 480 octets (fits in an ARCNET frame)"},
+	{4,	"Up to 1024 octets"},
+	{5,	"Up to 1476 octets"},
+	{6,	"reserved by ASHRAE"},
+	{7,	"reserved by ASHRAE"},
+	{8,	"reserved by ASHRAE"},
+	{9,	"reserved by ASHRAE"},
+	{10, "reserved by ASHRAE"},
+	{11, "reserved by ASHRAE"},
+	{12, "reserved by ASHRAE"},
+	{13, "reserved by ASHRAE"},
+	{14, "reserved by ASHRAE"},
+	{15, "reserved by ASHRAE"},
+	{0,	NULL}
+};
+
+static const value_string
+bacapp_reject_reason [] = {
+	{0,	"other"},
+	{1,	"buffer-overflow"},
+	{2,	"inconsistent-parameters"},
+	{3,	"invalid-parameter-data-type"},
+	{4,	"invalid-tag"},
+	{5,	"missing-required-parameter"},
+	{6,	"parameter-out-of-range"},
+	{7,	"too-many-arguments"},
+	{8,	"undefined-enumeration"},
+	{9,	"unrecognized-service"},
+	{10, "reserved by ASHRAE"},
+	{11, "reserved by ASHRAE"},
+	{12, "reserved by ASHRAE"},
+	{13, "reserved by ASHRAE"},
+	{14, "reserved by ASHRAE"},
+	{15, "reserved by ASHRAE"},
+	{0,	NULL}
+};
+
+static const value_string
+bacapp_tag_number [] = {
+	{0,	"Null"},
+	{1,	"Boolean"},
+	{2,	"Unsigned Integer"},
+	{3,	"Signed Integer (2's complement notation)"},
+	{4,	"Real (ANSI/IEE-754 floating point)"},
+	{5,	"Double (ANSI/IEE-754 double precision floating point)"},
+	{6,	"Octet String"},
+	{7,	"Character String"},
+	{8,	"Bit String"},
+	{9,	"Enumerated"},
+	{10, "Date"},
+	{11, "Time"},
+	{12, "BACnetObjectIdentifier"},
+	{13, "reserved by ASHRAE"},
+	{14, "reserved by ASHRAE"},
+	{15, "reserved by ASHRAE"},
+	{0,	NULL}
+};
+
+static const value_string
+bacapp_abort_reason [] = {
+	{0,	"other"},
+	{1,	"buffer-overflow"},
+	{2,	"invalid-apdu-in-this-state"},
+	{3,	"preempted-by-higher-priority-task"},
+	{4,	"segmentation-not-supported"},
+	{5, "reserved by ASHRAE"},
+	{0,	NULL}
+};
+
+static const value_string
+bacapp_confirmed_service_choice [] = {
+	{0,	"acknowledgeAlarm"},
+	{1,	"confirmedCOVNotification"},
+	{2,	"confirmedEventNotification"},
+	{3,	"getAlarmSummary"},
+	{4,	"getEnrollmentSummary"},
+	{5,	"subscribeCOV"},
+	{6,	"atomicReadFile"},
+	{7,	"atomicWriteFile"},
+	{8,	"addListElement"},
+	{9,	"removeListElement"},
+	{10,"createObject"},
+	{11,"deleteObject"},
+	{12,"readProperty"},
+	{13,"readPropertyConditional"},
+	{14,"readPropertyMultiple"},
+	{15,"writeProperty"},		/* 15 */
+	{16,"writePropertyMultiple"},
+	{17,"deviceCommunicationControl"},
+	{18,"confirmedPrivateTransfer"},
+	{19,"confirmedTextMessage"},
+	{20,"reinitializeDevice"},
+	{21,"vtOpen"},
+	{22,"vtClose"},
+	{23,"vtData"},
+	{24,"authenticate"},
+	{25,"requestKey"},	/* 25 */
+	{26,"readRange"},
+	{27,"lifeSafetyOperation"},
+	{28,"subscribeCOVProperty"},
+	{29,"getEventInformation"},
+	{30,"reserved by ASHRAE"},
+	{0, NULL}
+};
+
+static const value_string
+BACnetUnconfirmedServiceChoice [] = {
+	{0,	"i-Am"},
+	{1,	"i-Have"},
+	{2,	"unconfirmedCOVNotification"},
+	{3,	"unconfirmedEventNotification"},
+	{4,	"unconfirmedPrivateTransfer"},
+	{5,	"unconfirmedTextMessage"},
+	{6,	"timeSynchronization"},
+	{7,	"who-Has"},
+	{8,	"who-Is"},
+	{9,	"utcTimeSynchonization"},
+	{0, NULL}
+};
+
+static const value_string
+BACnetUnconfirmedServiceRequest [] = {
+	{0,	"i-Am-Request"},
+	{1,	"i-Have-Request"},
+	{2,	"unconfirmedCOVNotification-Request"},
+	{3,	"unconfirmedEventNotification-Request"},
+	{4,	"unconfirmedPrivateTransfer-Request"},
+	{5,	"unconfirmedTextMessage-Request"},
+	{6,	"timeSynchronization-Request"},
+	{7,	"who-Has-Request"},
+	{8,	"who-Is-Request"},
+	{9,	"utcTimeSynchonization-Request"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_object_type [] = {
+	{0,	"analog-input object"},
+	{1,	"analog-output object"},
+	{2,	"analog-value object"},
+	{3,	"binary-input object"},
+	{4,	"binary-output object"},
+	{5,	"binary-value object"},
+	{6,	"calendar object"},
+	{7,	"command object"},
+	{8,	"device object"},
+	{9,	"event-enrollment object"},
+	{10,"file object"},
+	{11,"group object"},
+	{12,"loop object"},
+	{13,"multi-state-input object"},
+	{14,"multi-state-output object"},
+	{15,"notification-class object"},
+	{16,"program object"},
+	{17,"schedule object"},
+	{18,"averaging object"},
+	{19,"multi-state-value object"},
+	{20,"trend-log object"},
+	{21,"life-safety-point object"},
+	{22,"life-safety-zone object"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_error_code [] = {
+	{0,	"other"},
+	{1,	"authentication-failed"},
+	{2,	"character-set-not-supported"},
+	{3,	"configuration-in-progress"},
+	{4,	"device-busy"},
+	{5,	"file-access-denied"},
+	{6,	"incompatible-security-levels"},
+	{7,	"inconsistent-parameters"},
+	{8,	"inconsistent-selection-criterion"},
+	{9,	"invalid-data-type"},
+	{10,"invalid-file-access-method"},
+	{11,"invalid-file-start-position"},
+	{12,"invalid-operator-name"},
+	{13,"invalid-parameter-data-type"},
+	{14,"invalid-time-stamp"},
+	{15,"key-generation-error"},
+	{16,"missing-required-parameter"},
+	{17,"no-objects-of-specified-type"},
+	{18,"no-space-for-object"},
+	{19,"no-space-to-add-list-element"},
+	{20,"no-space-to-write-property"},
+	{21,"no-vt-sessions-available"},
+	{22,"property-is-not-a-list"},
+	{23,"object-deletion-not-permitted"},
+	{24,"object-identifier-already-exists"},
+	{25,"operational-problem"},
+	{26,"password-failure"},
+	{27,"read-access-denied"},
+	{28,"security-not-supported"},
+	{29,"service-request-denied"},
+	{30,"timeout"},
+	{31,"unknown-object"},
+	{32,"unknown-property"},
+	{33,"removed enumeration"},
+	{34,"unknown-vt-class"},
+	{35,"unknown-vt-session"},
+	{36,"unsupported-object-type"},
+	{37,"value-out-of-range"},
+	{38,"vt-session-already-closed"},
+	{39,"vt-session-termination-failure"},
+	{40,"write-access-denied"},
+	{41,"character-set-not-supported"},
+	{42,"invalid-array-index"},
+	{43,"cov-subscription-failed"},
+	{44,"not-cov-property"},
+	{45,"optional-functionaltity-not-supported"},
+	{46,"invalid-configuration-data"},
+	{47,"reserved by ASHRAE"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_property_identifier [] = {
+	{0,	"acked-transition"},
+	{1,	"ack-required"},
+	{2,	"action"},
+	{3,	"action-text"},
+	{4,	"active-text"},
+	{5,	"active-vt-session"},
+	{6,	"alarm-value"},
+	{7,	"alarm-values"},
+	{8,	"all"},
+	{9,	"all-write-successfull"},
+	{10,"apdu-segment-timeout"},
+	{11,"apdu-timeout"},
+	{12,"application-software-version"},
+	{13,"archive"},
+	{14,"bias"},
+	{15,"change-of-state-count"},
+	{16,"change-of-state-time"},
+	{17,"notification-class"},
+	{18,"the property in this place was deleted"},
+	{19,"controlled-variable-reference"},
+	{20,"controlled-variable-units"},
+	{21,"controlled-variable-value"},
+	{22,"cov-increment"},
+	{23,"datelist"},
+	{24,"daylights-savings-status"},
+	{25,"deadband"},
+	{26,"derivative-constant"},
+	{27,"derivative-constant-units"},
+	{28,"description"},
+	{29,"description-of-halt"},
+	{30,"device-address-binding"},
+	{31,"device-type"},
+	{32,"effective-period"},
+	{33,"elapsed-active-time"},
+	{34,"error-limit"},
+	{35,"event-enable"},
+	{36,"event-state"},
+	{37,"event-type"},
+	{38,"exception-schedule"},
+	{39,"fault-values"},
+	{40,"feedback-value"},
+	{41,"file-access-method"},
+	{42,"file-size"},
+	{43,"file-type"},
+	{44,"firmware-revision"},
+	{45,"high-limit"},
+	{46,"inactive-text"},
+	{47,"in-progress"},
+	{48,"instance-of"},
+	{49,"integral-constant"},
+	{50,"integral-constant-units"},
+	{51,"issue-confirmed-notifications"},
+	{52,"limit-enable"},
+	{53,"list-of-group-members"},
+	{54,"list-of-object-property-references"},
+	{55,"list-of-session-keys"},
+	{56,"local-date"},
+	{57,"local-time"},
+	{58,"location"},
+	{59,"low-limit"},
+	{60,"manipulated-variable-reference"},
+	{61,"maximum-output"},
+	{62,"max-apdu-length-accepted"},
+	{63,"max-info-frames"},
+	{64,"max-master"},
+	{65,"max-pres-value"},
+	{66,"minimum-off-time"},
+	{67,"minimum-on-time"},
+	{68,"minimum-output"},
+	{69,"min-pres-value"},
+	{70,"model-name"},
+	{71,"modification-date"},
+	{72,"notify-type"},
+	{73,"number-of-APDU-retries"},
+	{74,"number-of-states"},
+	{75,"object-identifier"},
+	{76,"object-list"},
+	{77,"object-name"},
+	{78,"object-property-reference"},
+	{79,"object-type"},
+	{80,"optional"},
+	{81,"out-of-service"},
+	{82,"output-units"},
+	{83,"event-parameters"},
+	{84,"polarity"},
+	{85,"present-value"},
+	{86,"priority"},
+	{87,"priority-array"},
+	{88,"priority-for-writing"},
+	{89,"process-identifier"},
+	{90,"program-change"},
+	{91,"program-location"},
+	{92,"program-state"},
+	{93,"proportional-constant"},
+	{94,"proportional-constant-units"},
+	{95,"protocol-conformance-class"},
+	{96,"protocol-object-types-supported"},
+	{97,"protocol-services-supported"},
+	{98,"protocol-version"},
+	{99,"read-only"},
+	{100,"reason-for-halt"},
+	{101,"recipient"},
+	{102,"recipient-list"},
+	{103,"reliability"},
+	{104,"relinquish-default"},
+	{105,"required"},
+	{106,"resolution"},
+	{107,"segmentation-supported"},
+	{108,"setpoint"},
+	{109,"setpoint-reference"},
+	{110,"state-text"},
+	{111,"status-flags"},
+	{112,"system-status"},
+	{113,"time-delay"},
+	{114,"time-of-active-time-reset"},
+	{115,"time-of-state-count-reset"},
+	{116,"time-synchronization-recipients"},
+	{117,"units"},
+	{118,"update-interval"},
+	{119,"utc-offset"},
+	{120,"vendor-identifier"},
+	{121,"vendor-name"},
+	{122,"vt-class-supported"},
+	{123,"weekly-svhedule"},
+	{124,"attempted-samples"},
+	{125,"average-value"},
+	{126,"buffer-size"},
+	{127,"client-cov-increment"},
+	{128,"cov-resubscription-interval"},
+	{129,"current-notify-time"},
+	{130,"event-time-stamp"},
+	{131,"log-buffer"},
+	{132,"log-device-object-property"},
+	{133,"log-enable"},
+	{134,"log-interval"},
+	{135,"maximum-value"},
+	{136,"minimum-value"},
+	{137,"notification-threshold"},
+	{138,"previous-notify-time"},
+	{139,"protocol-revision"},
+	{140,"records-since-notification"},
+	{141,"record-count"},
+	{142,"start-time"},
+	{143,"stop-time"},
+	{144,"stop-when-full"},
+	{145,"total-record-count"},
+	{146,"valid-samples"},
+	{147,"window-interval"},
+	{148,"window-samples"},
+	{149,"maximum-value-time-stamp"},
+	{150,"minimum-value-time-stamp"},
+	{151,"variance-value"},
+	{152,"active-cov-subscriptions"},
+	{153,"backup-failure-timeout"},
+	{154,"configuration-files"},
+	{155,"database-revision"},
+	{156,"direct-reading"},
+	{157,"last-restore-time"},
+	{158,"maintenance-required"},
+	{159,"member-of"},
+	{160,"mode"},
+	{161,"operation-expected"},
+	{162,"setting"},
+	{163,"silenced"},
+	{164,"tracking-value"},
+	{165,"zone-members"},
+	{166,"life-safety-alarm-values"},
+	{167,"max-segments-accepted"},
+	{168,"profile-name"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_character_set [] = {
+	{0, "   ANSI X3.4"},
+	{1, "   IBM/Microsoft DBCS"},
+	{2, "   JIS C 6226"},
+	{3, "   ISO 10646(UCS-4)"},
+	{4, "   ISO 10646(UCS-2)"},
+	{5, "   ISO 18859-1"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_status_flags [] = {
+	{0, "in-alarm"},
+	{1, "fault"},
+	{2, "overridden"},
+	{3, "out-of-service"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_messagePriority [] = {
+	{0, "normal"},
+	{1, "urgent"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_AcknowledgementFilter [] = {
+	{0, "and"},
+	{1, "or"},
+	{2, "all"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_resultFlags [] = {
+	{0, "firstitem"},
+	{1, "lastitem"},
+	{2, "moreitems"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_relationSpecifier [] = {
+	{0, "equal"},
+	{1, "not-equal"},
+	{2, "less-than"},
+	{3, "greater-than"},
+	{4, "less-than-or-equal"},
+	{5, "greater-than-or-equal"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_selectionLogic [] = {
+	{0, "normal"},
+	{1, "urgent"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_eventStateFilter [] = {
+	{0, "offnormal"},
+	{1, "fault"},
+	{2, "normal"},
+	{3, "all"},
+	{4, "active"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_EventTransitionBits [] = {
+	{0, "to-offnormal"},
+	{1, "to-fault"},
+	{2, "to-normal"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_segmentation [] = {
+	{0, "segmented-both"},
+	{1, "segmented-transmit"},
+	{2, "segmented-receive"},
+	{3, "no-segmentation"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_deviceStatus [] = {
+	{0, "operational"},
+	{1, "operational-read-only"},
+	{2, "download-required"},
+	{3, "download-in-progress"},
+	{4, "non-operational"},
+	{5, "backup-in-progress"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_statusFlags [] = {
+	{0, "in-alarm"},
+	{1, "fault"},
+	{2, "overridden"},
+	{3, "out-of-service"},
+	{0, NULL}
+};
+
+static const value_string
+months [] = {
+	{1, "January" },
+	{2, "February" },
+	{3, "March" },
+	{4, "April" },
+	{5, "May" },
+	{6, "June" },
+	{7, "July" },
+	{8, "August" },
+	{9, "September" },
+	{10, "October" },
+	{11, "November" },
+	{12, "December" },
+	{255, "unspecified" },
+	{0, NULL }
+};
+
+static const value_string
+days [] = {
+	{1, "Monday" },
+	{2, "Tuesday" },
+	{3, "Wednesday" },
+	{4, "Thursday" },
+	{5, "Friday" },
+	{6, "Saturday" },
+	{7, "Sonday" },
+	{255, "unspecified" },
+	{0, NULL },
+};
+
+static const value_string
+bacapp_errorClass [] = {
+	{0, "device" },
+	{1, "object" },
+	{2, "property" },
+	{3, "resources" },
+	{4, "security" },
+	{5, "services" },
+	{6, "vt" },
+	{0, NULL },
+};
+
+static const value_string
+bacapp_EventType [] = {
+	{0, "change-of-bitstring" },
+	{1, "change-of-state" },
+	{2, "change-of-value" },
+	{3, "command-failure" },
+	{4, "floating-limit" },
+	{5, "out-of-range" },
+	{6, "complex-event-type" },
+	{7, "buffer-ready" },
+	{8, "change-of-life-safety" },
+	{0, NULL },
+};
+
+static const value_string
+bacapp_EventState [] = {
+	{0, "normal" },
+	{1, "fault" },
+	{2, "offnormal" },
+	{3, "high-limit" },
+	{4, "low-limit" },
+	{5, "life-safety-alarm" },
+	{0, NULL },
+};
+
+static const value_string
+bacapp_NotifyType [] = {
+	{0, "alarm" },
+	{1, "event" },
+	{2, "ack-notification" },
+	{0, NULL },
+};
+
+static const value_string
+bacapp_servicesSupported [] = {
+	{0,	"acknowledgeAlarm"},
+	{1,	"confirmedCOVNotification"},
+	{2,	"confirmedEventNotification"},
+	{3,	"getAlarmSummary"},
+	{4,	"getEnrollmentSummary"},
+	{5,	"subscribeCOV"},
+	{6,	"atomicReadFile"},
+	{7,	"atomicWriteFile"},
+	{8,	"addListElement"},
+	{9,	"removeListElement"},
+	{10,"createObject"},
+	{11,"deleteObject"},
+	{12,"readProperty"},
+	{13,"readPropertyConditional"},
+	{14,"readPropertyMultiple"},
+	{15,"writeProperty"},		/* 15 */
+	{16,"writePropertyMultiple"},
+	{17,"deviceCommunicationControl"},
+	{18,"confirmedPrivateTransfer"},
+	{19,"confirmedTextMessage"},
+	{20,"reinitializeDevice"},
+	{21,"vtOpen"},
+	{22,"vtClose"},
+	{23,"vtData"},
+	{24,"authenticate"},
+	{25,"requestKey"},	/* 25 */
+	{26,"i-Am"},
+	{27,"i-Have"},
+	{28,"unconfirmedCOVNotification"},
+	{29,"unconfirmedEventNotification"},
+	{30,"unconfirmedPrivateTransfer"},
+	{31,"unconfirmedTextMessage"},
+	{32,"timeSynchronization"},
+	{33,"who-Has"},
+	{34,"who-Is"},
+	{35,"readRange"},
+	{36,"utcTimeSynchronization"},
+	{37,"lifeSafetyOperation"},
+	{38,"subscribeCOVProperty"},
+	{39,"getEventInformation"},
+	{40,"reserved by ASHRAE"},
+	{0, NULL}
+};
+
+static const value_string
+bacapp_PropertyStates [] = {
+	{0,	"boolean-value"},
+	{1,	"binary-value"},
+	{2,	"event-type"},
+	{3,	"polarity"},
+	{4,	"program-change"},
+	{5,	"program-state"},
+	{6,	"reason-for-halt"},
+	{7,	"reliability"},
+	{8,	"state"},
+	{9,	"system-status"},
+	{10,"units"},
+	{11,"unsigned-value"},
+	{12,"life-safety-mode"},
+	{13,"life-safety-state"},
+	{0, NULL}
+};
+
 static int proto_bacapp = -1;
 static int hf_bacapp_type = -1;
+static int hf_bacapp_SEG = -1;
+static int hf_bacapp_MOR = -1;
+static int hf_bacapp_SA = -1;
+static int hf_bacapp_response_segments = -1;
+static int hf_bacapp_max_adpu_size = -1;
+static int hf_bacapp_invoke_id = -1;
+static int hf_bacapp_sequence_number = -1;
+static int hf_bacapp_window_size = -1;
+static int hf_bacapp_service = -1;
+static int hf_bacapp_NAK = -1;
+static int hf_bacapp_SRV = -1;
+static int hf_bacapp_reject_reason = -1;
+static int hf_bacapp_abort_reason = -1;
+static int hf_bacapp_tag_number = -1;
+static int hf_bacapp_tag_class = -1;
+static int hf_bacapp_tag_lvt = -1;
+static int hf_bacapp_tag_ProcessId = -1;
+static int hf_bacapp_tag_initiatingObjectType = -1;
+/* static int hf_bacapp_tag_initiatingObjectId = -1; */
+static int hf_bacapp_vpart = -1;
 
+/*
+static int hf_bacapp_tag_null = -1;
+static int hf_bacapp_tag_boolean = -1;
+static int hf_bacapp_tag_uint8 = -1;
+static int hf_bacapp_tag_uint16 = -1;
+static int hf_bacapp_tag_uint32 = -1;
+static int hf_bacapp_tag_uint64 = -1;
+static int hf_bacapp_tag_sint8 = -1;
+static int hf_bacapp_tag_sint16 = -1;
+static int hf_bacapp_tag_sint32 = -1;
+static int hf_bacapp_tag_sint64 = -1;
+static int hf_bacapp_tag_real = -1;
+static int hf_bacapp_tag_double = -1;
+static int hf_bacapp_initiatingObject = -1;
+static int hf_bacapp_monitoredObject = -1;
+static int hf_bacapp_tag_timeRemaining = -1;
+static int hf_bacapp_tag_string = -1;
+static int hf_bacapp_tag_bytes = -1;
+static int hf_bacapp_tag_character_set = -1;
+*/
+static int hf_bacapp_uservice = -1;
+
+
 static gint ett_bacapp = -1;
+static gint ett_bacapp_control = -1;
+static gint ett_bacapp_tag = -1;
 
 static dissector_handle_t data_handle;
 
-static void
-dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static gint32 propertyIdentifier = -1;
+
+static guint8 bacapp_flags = 0;
+static guint8 bacapp_seq = 0;
+
+
+int
+fTagHeader (tvbuff_t *tvb, guint *offset, guint8 *tag_no, guint8* class_tag, guint64 *lvt)
 {
-	proto_item *ti;
+	int tmp, retVal = 0;
+
+	tmp = tvb_get_guint8(tvb, *offset);
+	*class_tag = tmp & 0x08;
+	*lvt = tmp & 0x07;
+	*tag_no = tmp >> 4;
+	if (*tag_no == 15) { /* B'1111' because of extended tagnumber */
+		*tag_no = tvb_get_guint8(tvb, (*offset)+1);
+		retVal++;
+	}
+	if (*lvt == 5) { /* length is more than 4 Bytes */
+		*lvt = tvb_get_guint8(tvb, (*offset)+retVal+1);
+		retVal++;
+		if (*lvt == 254) { /* length is more than 253 Bytes */
+			*lvt = tvb_get_guint8(tvb, (*offset)+retVal+1);
+			retVal++;
+			*lvt = (*lvt << 8) + tvb_get_guint8(tvb, (*offset)+retVal+1);
+			retVal++;
+		}
+	}
+
+	return retVal;
+}
+
+#define LABEL(lbl) (lbl==NULL ? (guint8 *) "   Value: " : lbl)
+
+
+void
+fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt)
+{
+	guint8 tmp, i;
+	long val = 0;
+
+	(*offset)++;
+	for (i = 0; i < min((guint8) lvt,8); i++) {
+		tmp = tvb_get_guint8(tvb, (*offset)+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,8), "%s%ld", LABEL(label), val);
+	(*offset)+=min((guint8) lvt,8);
+}
+
+void
+fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt)
+{
+	guint8 tmp, i;
+	long val = 0;
+
+	(*offset)++;
+	for (i = 0; i < min((guint8) lvt,8); i++) {
+		tmp = tvb_get_guint8(tvb, (*offset)+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,8), "%s%ld", LABEL(label), val);
+	(*offset)+=min((guint8) lvt,8);
+}
+
+void
+fDateTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt)
+{
+	guint32 year, month, day, weekday;
+
+	(*offset)++;
+	year = tvb_get_guint8(tvb, (*offset)) + 1900;
+	month = tvb_get_guint8(tvb, (*offset)+1);
+	day = tvb_get_guint8(tvb, (*offset)+2);
+	weekday = tvb_get_guint8(tvb, (*offset)+3);
+	if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+		proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%sany", LABEL(label));
+	else
+		proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%s%s %d, %d, (Day of Week = %s)", LABEL(label), match_strval(month, months), day, year, match_strval(weekday, days));
+	(*offset)+=(guint8) lvt;
+}
+
+void
+fTimeTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt)
+{
+	guint32 year, month, day, weekday;
+
+	(*offset)++;
+	year = tvb_get_guint8(tvb, (*offset));
+	month = tvb_get_guint8(tvb, (*offset)+1);
+	day = tvb_get_guint8(tvb, (*offset)+2);
+	weekday = tvb_get_guint8(tvb, (*offset)+3);
+	if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+		proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%sany", LABEL(label));
+	else
+		proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d", LABEL(label), year > 12 ? year -12 : year, month, day, weekday, year > 12 ? "P.M." : "A.M.", year, month, day, weekday);
+	(*offset)+=(guint8) lvt;
+}
+
+void
+fOctetString (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt)
+{
+	guint8 *str_val, len;
+
+	if ((lvt == 0) || (lvt > tvb->length))
+		lvt = tvb->length - *offset;
+
+	proto_tree_add_text(tree, tvb, *offset, (int)lvt, "[displayed OctetString with %ld Bytes:] %s", (long)lvt, LABEL(label));
+
+	do {
+		len = (guint8) min (lvt, 200);
+		str_val = tvb_get_string(tvb, *offset, len);
+		proto_tree_add_text(tree, tvb, *offset, len, "%s", str_val);
+		g_free(str_val);
+		lvt -= len;
+		(*offset) += len;
+	} while (lvt > 0);
+
+	if (tvb->length < tvb->reported_length)
+		proto_tree_add_text(tree, tvb, *offset-1, 1, "[Frame is %d Bytes shorter than expected]", tvb->reported_length - tvb->length);
+
+}
+
+void
+fBACnetAddress (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	fUnsignedTag (tvb, tree, offset, "network-number", lvt);
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	if (lvt == 0)
+		proto_tree_add_text(tree, tvb, *offset-1, 1, "mac-address: broadcast");
+	else
+		fOctetString (tvb, tree, offset, "mac-address: ", lvt);
+}
+
+void
+fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label)
+{
+	guint8 offs, tag_no, class_tag;
+	guint32 tmp, val = 0, type;
+	guint64 lvt;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	(*offset)+= offs + 1;
+
+	val = tvb_get_guint8(tvb, (*offset));
+	tmp = tvb_get_guint8(tvb, (*offset)+1);
+	type = (val << 2) + (tmp >> 6);
+	val = ((tmp & 0x03) << 16) + (tvb_get_guint8(tvb, (*offset)+2) << 8) + tvb_get_guint8(tvb, (*offset)+3);
+	proto_tree_add_text(tree, tvb, *offset, 4,
+		"%s%s, instance number %d", LABEL(label), val_to_str(type, bacapp_object_type, "(%d) reserved for ASHREA"), val);
+	(*offset)+=4;
+}
+
+void
+fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* device */
+		fObjectIdentifier (tvb, tree, offset, "device: ");
+		break;
+	case 1:	/* address */
+		fBACnetAddress (tvb, tree, offset);
+		break;
+	default:
+		return;
+		break;
+	}
+	fRecipient (tvb, pinfo, tree, offset);
+}
+
+
+void
+fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* recipient */
+		fRecipient (tvb, pinfo, tree, offset);
+		break;
+	case 1:	/* processId */
+		fUnsignedTag (tvb, tree, offset, "processId: ", lvt);
+		break;
+	default:
+		return;
+		break;
+	}
+	fRecipientProcess (tvb, pinfo, tree, offset);
+}
+
+void
+fBACnetAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	fObjectIdentifier (tvb, tree, offset, "deviceObjectId: ");
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	fBACnetAddress (tvb, tree, offset);
+}
+
+int
+fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label)
+{
+	guint8 offs, tag_no, class_tag, tmp, i;
+	guint64 lvt;
+	guint val = 0;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	(*offset) += offs + 1;
+
+	for (i = 0; i < min((guint8) lvt,4); i++) {
+		tmp = tvb_get_guint8(tvb, (*offset)+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,4),
+		"%s%s", LABEL(label),val_to_str(val, bacapp_property_identifier, "(%d) reserved for ASHREA"));
+	(*offset)+=min((guint8) lvt,4);
+	return val;
+}
+
+void
+fApplicationTags (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, const value_string
+ *src)
+{
+	guint8 offs, tag_no, class_tag, tmp, i, j, unused;
+	guint64 val = 0, lvt;
+	gfloat f_val = 0.0;
+	gdouble d_val = 0.0;
+	guint8 *str_val;
+	guint8 bf_arr[256];
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	(*offset) += offs;	/* set offset according to enhancements.... */
+
+	switch (tag_no) {
+		case 0:	/* NULL */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "%sNULL", LABEL(label));
+			break;
+		case 1:	/* BOOLEAN */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "%s%s", LABEL(label), lvt == 0 ? "FALSE" : "TRUE");
+			break;
+		case 2:	/* Unsigned Integer */
+			fUnsignedTag (tvb, tree, offset, label, lvt);
+			break;
+		case 3:	/* Signed Integer */
+			fSignedTag (tvb, tree, offset, label, lvt);
+			break;
+		case 4:	/* Real */
+			(*offset)++;
+			f_val = tvb_get_ntohieee_float(tvb, *offset);
+			proto_tree_add_text(tree, tvb, *offset, 4, "%s%f", LABEL(label), f_val);
+			(*offset)+=4;
+			break;
+		case 5:	/* Double */
+			(*offset)++;
+			d_val = tvb_get_ntohieee_double(tvb, *offset);
+			proto_tree_add_text(tree, tvb, *offset, 8, "%s%lf", LABEL(label), d_val);
+			(*offset)+=8;
+			break;
+		case 6: /* Octet String */
+			(*offset)++;
+			proto_tree_add_text(tree, tvb, *offset-offs-1, offs+1, "%s (%d Characters)", LABEL(label), (int)lvt);
+			fOctetString (tvb, tree, offset, label, lvt);
+			break;
+		case 7: /* Character String */
+			(*offset)++;
+			tmp = tvb_get_guint8(tvb, *offset);
+			if (tmp == 3) {
+				proto_tree_add_text (tree, tvb, *offset, 4, "   String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE"));
+				(*offset)+=4;
+				lvt-=4;
+			}
+			if (tmp == 4) {
+				proto_tree_add_text (tree, tvb, *offset, 2, "   String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE"));
+				(*offset)+=2;
+				lvt-=2;
+			}
+			if ((tmp != 3) && (tmp != 4)) {
+				proto_tree_add_text (tree, tvb, *offset, 1, "   String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE"));
+				(*offset)++;
+				lvt--;
+			}
+			do {
+				guint8 l = (guint8) min(lvt, 255);
+				str_val = tvb_get_string(tvb, *offset, l);
+				/* this decoding is not correct for multi-byte characters, Lka */
+				proto_tree_add_text(tree, tvb, *offset, l, "%s'%s'", LABEL(label), str_val);
+				g_free(str_val);
+				lvt -= l;
+				(*offset) += l;
+			} while (lvt > 0);
+			break;
+		case 8: /* Bit String */
+			(*offset)++;
+			unused = tvb_get_guint8(tvb, *offset); /* get the unused Bits */
+			for (i = 0; i < (lvt-2); i++) {
+				tmp = tvb_get_guint8(tvb, (*offset)+i+1);
+				for (j = 0; j < 8; j++) {
+					if (src != NULL) {
+						if (tmp & (1 << (7 - j)))
+							proto_tree_add_text(tree, tvb, (*offset)+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+						else
+							proto_tree_add_text(tree, tvb, (*offset)+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+
+					} else {
+						bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
+					}
+				}
+			}
+			tmp = tvb_get_guint8(tvb, (*offset)+(guint8)lvt-1);	/* jetzt das letzte Byte */
+			if (src == NULL) {
+				for (j = 0; j < (8 - unused); j++)
+					bf_arr[min(255,((lvt-2)*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
+				for (; j < 8; j++)
+					bf_arr[min(255,((lvt-2)*8)+j)] = 'x';
+				bf_arr[min(255,((lvt-2)*8)+j)] = '\0';
+				proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%sB'%s'", LABEL(label), bf_arr);
+			} else {
+				for (j = 0; j < (8 - unused); j++) {
+					if (tmp & (1 << (7 - j)))
+						proto_tree_add_text(tree, tvb, (*offset)+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+					else
+						proto_tree_add_text(tree, tvb, (*offset)+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+				}
+			}
+			(*offset)+=(guint8)lvt;
+			break;
+		case 9: /* Enumerated */
+			(*offset)++;
+			for (i = 0; i < min((guint8) lvt,8); i++) {
+				tmp = tvb_get_guint8(tvb, (*offset)+i);
+				val = (val << 8) + tmp;
+			}
+			if (src != NULL)
+				proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s%s", LABEL(label), val_to_str((guint) val, src, "Reserved by ASHRAE"));
+			else
+				proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s%ld", LABEL(label), (long)val);
+
+			(*offset)+=(guint8)lvt;
+			break;
+		case 10: /* Date */
+			fDateTag (tvb, tree, offset, label, lvt);
+			break;
+		case 11: /* Time */
+			fTimeTag (tvb, tree, offset, label, lvt);
+			break;
+		case 12: /* BACnetObjectIdentifier */
+			fObjectIdentifier (tvb, tree, offset, LABEL(label));
+			break;
+		case 13: /* reserved for ASHRAE */
+		case 14:
+		case 15:
+			(*offset)++;
+			proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s'reserved for ASHRAE'", LABEL(label));
+			(*offset)+=(guint8)lvt;
+			break;
+	}
+}
+
+void
+fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+	static int awaitingClosingTag = 0;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	if (((lvt == 7) && (offs == 0)) && !awaitingClosingTag) {  /* closing Tag */
+		return;	/* but not for me */
+	}
+
+	if (class_tag) {
+		switch (tag_no) {
+		case 0:	/* PropertyIdentifier */
+			propertyIdentifier = fPropertyIdentifier (tvb, tree, offset,  "   property Identifier: ");
+			break;
+		case 1:	/* propertyArrayIndex */
+			fPropertyIdentifier (tvb, tree, offset, "propertyArrayIndex: ");
+		break;
+		case 2:  /* Value */
+			(*offset) += offs + 1;	/* set offset according to enhancements.... */
+			if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+				awaitingClosingTag = 1;
+				if (propertyIdentifier == 111) {	/* status-flags */
+					fApplicationTags (tvb, tree, offset, "   propertyValue: ", bacapp_statusFlags);
+				} else {
+					fApplicationTags (tvb, tree, offset, NULL, NULL);
+				}
+			}
+			if (((lvt == 7) && (offs == 0)))  /* closing Tag */
+				awaitingClosingTag = 0; /* ignore corresponding closing Tag, just throw ist away */
+			break;
+		case 3:  /* Priority */
+			(*offset) += offs;	/* set offset according to enhancements.... */
+			fSignedTag (tvb, tree, offset, "   Priority: ", lvt);
+		break;
+		default:
+			break;
+		}
+	} else {
+		switch (propertyIdentifier)
+		{
+		case 97: /* Protocol-Services-Supported */
+			fApplicationTags (tvb, tree, offset, "   propertyValue: ", bacapp_servicesSupported);
+			break;
+		case 111: /* Status-Flags */
+			fApplicationTags (tvb, tree, offset, "   propertyValue: ", bacapp_statusFlags);
+			break;
+		case 76:  /* object-list */
+			fApplicationTags (tvb, tree, offset, "   propertyValue: ", NULL);
+			break;
+		default:
+			fApplicationTags (tvb, tree, offset, "   propertyValue: ", NULL);
+			break;
+		}
+	}
+	fPropertyValue (tvb, pinfo, tree, offset);
+}
+
+void
+fSubscribeCOV (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tmp, tag_no, class_tag, i;
+	guint64 lvt;
+	guint32 val = 0;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* ProcessId */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < (guint8) min(lvt, 2); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+
+		proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val);
+		(*offset)+=(guint8)lvt;
+		break;
+	case 1: /* monitored ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: ");
+	break;
+	case 2: /* issueConfirmedNotifications */
+		fApplicationTags (tvb, tree, offset, "issueConfirmedNotifications: ", NULL);
+		break;
+	case 3:	/* life time */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < (guint8) min(lvt, 4); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+		proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "life time (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : "");
+		(*offset)+=(guint8)lvt;
+		return;
+		break;
+	default:
+		return;
+		break;
+	}
+	fSubscribeCOV (tvb, pinfo, tree, offset);
+}
+
+void
+fWhoHas (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0: /* deviceInstanceLowLimit */
+		fUnsignedTag (tvb, tree, offset, "deviceInstanceLowLimit: ", lvt);
+		break;
+	case 1: /* deviceInstanceHighLimit */
+		fUnsignedTag (tvb, tree, offset, "deviceInstanceHighLimit: ", lvt);
+		break;
+	case 2: /* BACnetObjectId */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectId: ");
+	break;
+	case 3: /* messageText */
+		fApplicationTags (tvb, tree, offset, "ObjectName: ", NULL);
+		break;
+	default:
+		return;
+	}
+	fWhoHas (tvb, pinfo, tree, offset);
+}
+
+void
+fUTCTimeSynchronization (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	fDateTag (tvb, tree, offset, "Date: ", lvt);
+	fTimeTag (tvb, tree, offset, "UTC-Time: ", lvt);
+}
+
+void
+fTimeSynchronization (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	fDateTag (tvb, tree, offset, "Date: ", lvt);
+	fTimeTag (tvb, tree, offset, "Time: ", lvt);
+}
+
+void
+fTextMessage (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* textMessageSourceDevice */
+		fObjectIdentifier (tvb, tree, offset, "TextMessageSourceDevice: ");
+		break;
+	case 1: /* messageClass */
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		switch (tag_no) {
+		case 0: /* numeric */
+			fUnsignedTag (tvb, tree, offset, "   messageClass: ", lvt);
+			break;
+		case 1: /* character */
+			fApplicationTags (tvb, tree, offset, "messageClass: ", NULL);
+			break;
+		}
+		break;
+	case 2: /* messagePriority */
+		fApplicationTags (tvb, tree, offset, "ObjectName: ", bacapp_messagePriority);
+		break;
+	case 3: /* message */
+		fApplicationTags (tvb, tree, offset, "message: ", NULL);
+		break;
+	}
+	fTextMessage (tvb, pinfo, tree, offset);
+}
+
+void
+fPrivateTransfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0: /* vendorID */
+		fUnsignedTag (tvb, tree, offset, "   vendorID: ", lvt);
+		break;
+	case 1: /* serviceNumber */
+		fUnsignedTag (tvb, tree, offset, "   serviceNumber: ", lvt);
+		break;
+	case 2: /*serviceParameters */
+		if (!((lvt == 7) && (offs == 0))) {   /* not closing Tag */
+			(*offset) += offs + 1;	/* set offset according to enhancements.... */
+			proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		} else {
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+		break;
+	}
+}
+
+void
+fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0: /* change-of-bitstring */
+		fApplicationTags (tvb, tree, offset, "referenced-bitstring: ", NULL);
+		fApplicationTags (tvb, tree, offset, "status-flags: ", bacapp_statusFlags);
+		break;
+	case 1: /* change-of-state */
+		fApplicationTags (tvb, tree, offset, "new-state: ", bacapp_PropertyStates);
+		fApplicationTags (tvb, tree, offset, "status-flags: ", bacapp_statusFlags);
+		break;
+	default:
+		return;
+	}
+	fNotificationParameters (tvb, pinfo, tree, offset);
+}
+
+void
+fEventNotification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tmp, tag_no, class_tag, i;
+	guint64 lvt;
+	guint32 val = 0;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* ProcessId */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < min((guint8) lvt, 2); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+
+		proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val);
+		(*offset)+=(guint8)lvt;
+		break;
+	case 1: /* initiating ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "initiating DeviceId: ");
+	break;
+	case 2: /* event ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "event ObjectId: ");
+	break;
+	case 3:	/* time stamp */
+		fApplicationTags (tvb, tree, offset, "Time Stamp: ", NULL);
+		break;
+	case 4:	/* notificationClass */
+		fApplicationTags (tvb, tree, offset, "Notification Class: ", NULL);
+		break;
+	case 5:	/* Priority */
+		fApplicationTags (tvb, tree, offset, "Priority: ", NULL);
+		break;
+	case 6:	/* EventType */
+		fApplicationTags (tvb, tree, offset, "EventType: ", bacapp_EventType);
+		break;
+	case 7: /* messageText */
+		fApplicationTags (tvb, tree, offset, "messageText: ", NULL);
+		break;
+	case 8:	/* NotifyType */
+		fApplicationTags (tvb, tree, offset, "NotifyType: ", bacapp_NotifyType);
+		break;
+	case 9: /* ackRequired */
+		fApplicationTags (tvb, tree, offset, "ackRequired: ", NULL);
+		break;
+	case 10: /* fromState */
+		fApplicationTags (tvb, tree, offset, "fromState: ", bacapp_EventState);
+		break;
+	case 11: /* toState */
+		fApplicationTags (tvb, tree, offset, "toState: ", bacapp_EventState);
+		break;
+	case 12: /* NotificationParameters */
+		fNotificationParameters (tvb, pinfo, tree, offset);
+		break;
+	default:
+		return;
+		break;
+	}
+	fEventNotification (tvb, pinfo, tree, offset);
+}
+
+void
+fCOVNotification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tmp, tag_no, class_tag, i;
+	guint64 lvt;
+	guint32 val = 0;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* ProcessId */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < min((guint8) lvt, 2); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+
+		proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val);
+		(*offset)+=(guint8)lvt;
+		break;
+	case 1: /* initiating ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "initiating ObjectId: ");
+	break;
+	case 2: /* monitored ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: ");
+	break;
+	case 3:	/* time remaining */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < min((guint8) lvt, 4); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+		proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "time remaining (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : "");
+		(*offset)+=(guint8)lvt;
+		break;
+	case 4:	/* List of Values */
+		if (!((lvt == 7) && (offs == 0))) {   /* not closing Tag */
+			(*offset) += offs + 1;	/* set offset according to enhancements.... */
+			proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		} else {
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+		break;
+	default:
+		return;
+		break;
+	}
+	fCOVNotification (tvb, pinfo, tree, offset);
+}
+
+void
+fAckAlarm (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tmp, tag_no, class_tag, i;
+	guint64 lvt;
+	guint32 val = 0;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* acknowledgingProcessId */
+		fUnsignedTag (tvb, tree, offset, "initiating ObjectId: ", lvt);
+		break;
+	case 1: /* initiating ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "initiating ObjectId: ");
+	break;
+	case 2: /* monitored ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: ");
+	break;
+	case 3:	/* time remaining */
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+		for (i = 0; i < min((guint8) lvt, 4); i++) {
+			tmp = tvb_get_guint8(tvb, (*offset)+i);
+			val = (val << 8) + tmp;
+		}
+		proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "time remaining (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : "");
+		(*offset)+=(guint8)lvt;
+		break;
+	case 4:	/* List of Values */
+		if (!((lvt == 7) && (offs == 0))) {   /* not closing Tag */
+			(*offset) += offs + 1;	/* set offset according to enhancements.... */
+			proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		} else {
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	default:
+		return;
+		break;
+	}
+	fAckAlarm (tvb, pinfo, tree, offset);
+}
+
+void
+fAckAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* acknowledgingProcessId */
+		fUnsignedTag (tvb, tree, offset, "acknowledgingProcessId: ", lvt);
+		break;
+	case 1: /* eventObjectId */
+		fObjectIdentifier (tvb, tree, offset, "eventObjectId: ");
+	break;
+	case 2: /* eventStateAcknowledged */
+		fApplicationTags (tvb, tree, offset, "eventStateAcknowledged: ", bacapp_EventState);
+	break;
+	case 3:	/* timeStamp */
+		fTimeTag (tvb, tree, offset, "timeStamp: ", lvt);
+		break;
+	case 4:	/* acknowledgementSource */
+		fApplicationTags (tvb, tree, offset, "acknowledgementSource: ", NULL);
+		break;
+	case 5:	/* timeOfAcknowledgement */
+		fTimeTag (tvb, tree, offset, "timeOfAcknowledgement: ", lvt);
+		break;
+	default:
+		return;
+		break;
+	}
+	fAckAlarmRequest (tvb, pinfo, tree, offset);
+}
+
+void
+fGetAlarmSummary (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	fObjectIdentifier (tvb, tree, offset, "objectIdentifier: ");
+	fApplicationTags (tvb, tree, offset, "alarmState: ", bacapp_EventState);
+	fApplicationTags (tvb, tree, offset, "acknowledgedTransitions: ", bacapp_EventTransitionBits);
+
+	fGetAlarmSummary (tvb, pinfo, tree, offset);
+}
+
+void
+fgetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* acknowledgmentFilter */
+		fApplicationTags (tvb, tree, offset, "acknowledgmentFilter: ", bacapp_AcknowledgementFilter);
+		break;
+	case 1: /* eventObjectId */
+		fRecipientProcess (tvb, pinfo, tree, offset);
+	break;
+	case 2: /* eventStateFilter */
+		fApplicationTags (tvb, tree, offset, "eventStateFilter: ", bacapp_eventStateFilter);
+	break;
+	case 3:	/* eventTypeFilter */
+		fApplicationTags (tvb, tree, offset, "eventTypeFilter: ", bacapp_EventType);
+		break;
+	case 4:	/* priorityFilter */
+		(*offset)++;
+		fUnsignedTag (tvb, tree, offset, "minPriority: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fUnsignedTag (tvb, tree, offset, "maxPriority: ", lvt);
+		break;
+	case 5:	/* notificationClassFilter */
+		fUnsignedTag (tvb, tree, offset, "notificationClassFilter: ", lvt);
+		break;
+	default:
+		return;
+		break;
+	}
+	fgetEnrollmentSummaryRequest (tvb, pinfo, tree, offset);
+}
+
+void
+fgetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	fObjectIdentifier (tvb, tree, offset, "ObjectId: ");
+	fApplicationTags (tvb, tree, offset, "eventType: ", bacapp_EventType);
+	fApplicationTags (tvb, tree, offset, "eventState: ", bacapp_eventStateFilter);
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	fUnsignedTag (tvb, tree, offset, "Priority: ", lvt);
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	fUnsignedTag (tvb, tree, offset, "notificationClass: ", lvt);
+
+	fgetEnrollmentSummaryAck (tvb, pinfo, tree, offset);
+}
+
+void
+fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* lastReceivedObjectId */
+		fObjectIdentifier (tvb, tree, offset, "lastReceivedObjectId: ");
+		break;
+	default:
+		return;
+		break;
+	}
+	fGetEventInformationRequest (tvb, pinfo, tree, offset);
+}
+
+void
+flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "ObjectId: ");
+		break;
+	case 1: /* eventState */
+		fApplicationTags (tvb, tree, offset, "eventState: ", bacapp_eventStateFilter);
+		break;
+	case 2: /* acknowledgedTransitions */
+		fApplicationTags (tvb, tree, offset, "acknowledgedTransitions: ", bacapp_EventTransitionBits);
+		break;
+	case 3: /* eventTimeStamps */
+		fTimeTag (tvb, tree, offset, "timeStamp: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fTimeTag (tvb, tree, offset, "timeStamp: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fTimeTag (tvb, tree, offset, "timeStamp: ", lvt);
+		break;
+	case 4: /* notifyType */
+		fApplicationTags (tvb, tree, offset, "NotifyType: ", bacapp_NotifyType);
+		break;
+	case 5: /* eventEnable */
+		fApplicationTags (tvb, tree, offset, "eventEnable: ", bacapp_EventTransitionBits);
+		break;
+	case 6: /* eventPriorities */
+		fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt);
+		break;
+	default:
+		return;
+		break;
+	}
+	flistOfEventSummaries (tvb, pinfo, tree, offset);
+}
+
+void
+fGetEventInformation (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* listOfEventSummaries */
+		flistOfEventSummaries (tvb, pinfo, tree, offset);
+		break;
+	case 1: /* moreEvents */
+		fApplicationTags (tvb, tree, offset, "moreEvents: ", NULL);
+		break;
+	default:
+		return;
+		break;
+	}
+	fGetEventInformationRequest (tvb, pinfo, tree, offset);
+}
+
+void
+fAddListElement (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* ObjectId */
+		fObjectIdentifier (tvb, tree, offset, "ObjectId: ");
+		break;
+	case 1:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+	break;
+	case 2: /* propertyArrayIndex */
+		(*offset)+= offs;
+		fSignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt);
+	break;
+	case 3:	/* propertyValue */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Elements {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	default:
+		return;
+		break;
+	}
+	fAddListElement (tvb, pinfo, tree, offset);
+}
+
+void
+fDeleteObject (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+}
+
+void
+fWritePropertyMultiple (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fDeviceCommunicationControl (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fReinitializeDevice (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fVtOpen (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fVtClose (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fVtData (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fAuthenticate (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fRequestKey (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fLifeSafetyOperation (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fSubscribeCOVProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fRemoveListElement (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	if ((*offset) >= tvb->length)
+		return;
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+
+}
+
+void
+fReadWriteProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectIdentifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+	break;
+	case 1:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+	break;
+	case 2: /* propertyArrayIndex */
+		(*offset)+= offs;
+		fSignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt);
+	break;
+	case 3:	/* propertyValue */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		/*	return;  */
+		}
+	break;
+	case 4: /* Priority */
+		(*offset)+= offs;
+		fSignedTag (tvb, tree, offset, "Priority: ", lvt);
+	break;
+	default:
+		proto_tree_add_text(tree, tvb, (*offset)++, 1, "unknown");
+		return;
+	}
+	fReadWriteProperty (tvb, pinfo, tree, offset);
+}
+
+
+void
+fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	if (lvt == 7)	/* closing bracket */
+		return;
+
+	switch (tag_no) {
+	case 0:	/* PropertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+		break;
+	case 1:	/* propertyArrayIndex */
+		(*offset)+= offs;
+		fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt);
+	break;
+	default:
+		return;
+	}
+	fPropertyReference (tvb, pinfo, tree, offset);
+}
+
+void
+fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* selectionLogic */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+		break;
+	case 1:	/* propertyArrayIndex */
+		(*offset)+= offs;
+		fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt);
+		break;
+	case 2: /* relationSpecifier */
+		fApplicationTags (tvb, tree, offset, "relationSpecifier: ", bacapp_relationSpecifier);
+		break;
+	case 3: /* comparisonValue */
+		fApplicationTags (tvb, tree, offset, "comparisonValue: ", NULL);
+		break;
+	default:
+		return;
+	}
+	fSelectionCriteria (tvb, pinfo, tree, offset);
+}
+
+void
+fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* selectionLogic */
+		fApplicationTags (tvb, tree, offset, "selectionLogic: ", bacapp_selectionLogic);
+		break;
+	case 1:	/* listOfSelectionCriteria */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {");
+		}
+		fSelectionCriteria (tvb, pinfo, tree, offset);
+
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	fObjectSelectionCriteria (tvb, pinfo, tree, offset);
+}
+
+
+void
+fReadPropertyConditional (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSelectionCriteria */
+		fObjectSelectionCriteria (tvb, pinfo, tree, offset);
+		break;
+	case 1:	/* listOfPropertyReferences */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {");
+		}
+		fPropertyReference (tvb, pinfo, tree, offset);
+
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	fReadPropertyConditional (tvb, pinfo, tree, offset);
+}
+
+void
+fReadWriteMultipleProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	/* not yet implemented */
+	*pinfo = *pinfo; /* just to eliminate warnings */
+	*tree = *tree; /* just to eliminate warnings */
+}
+
+void
+fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectIdentifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* listOfPropertyReferences */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {");
+		}
+		fPropertyReference (tvb, pinfo, tree, offset);
+
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	fReadAccessSpecification (tvb, pinfo, tree, offset);
+}
+
+void
+fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectIdentifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* listOfPropertyValues */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyValues {");
+		}
+		fPropertyValue (tvb, pinfo, tree, offset);
+
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	default:
+		return;
+	}
+	fReadAccessSpecification (tvb, pinfo, tree, offset);
+}
+
+void
+fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectIdentifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* listOfResults */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Results {");
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+		break;
+	case 2:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+	break;
+	case 3: /* propertyArrayIndex */
+		(*offset)+= offs;
+		fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt);
+	break;
+	case 4:	/* propertyValue */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	case 5:	/* propertyAccessError */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Errors {");
+			/* Error Code follows */
+			fApplicationTags (tvb, tree, offset, "   errorClass: ", bacapp_errorClass);
+			fApplicationTags (tvb, tree, offset, "   errorCode: ", bacapp_error_code);
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	default:
+		return;
+	}
+	fReadAccessResult (tvb, pinfo, tree, offset);
+}
+
+
+void
+fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	/* listOfReadAccessResults */
+	fReadAccessResult (tvb, pinfo, tree, offset);
+	fReadPropertyConditionalAck (tvb, pinfo, tree, offset);
+}
+
+
+void
+fObjectSpecifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectType */
+		proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, (*offset), 1, TRUE);
+	break;
+	case 1:	/* objectIdentifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+	break;
+	}
+	fObjectSpecifier (tvb, pinfo, tree, offset);
+}
+
+
+
+void
+fCreateObject (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSpecifier */
+		fObjectSpecifier (tvb, pinfo, tree, offset);
+	break;
+	case 1:	/* propertyValue */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	default:
+		proto_tree_add_text(tree, tvb, (*offset)++, 1, "unknown");
+		return;
+	}
+	fCreateObject (tvb, pinfo, tree, offset);
+}
+
+void
+fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+}
+
+void
+fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSpecifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+		break;
+	case 2:	/* propertyArrayIndex Optional */
+		fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt);
+		break;
+	case 3:	/* range byPosition */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "range byPosition: referenceIndex, count {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	case 4:	/* range byTime */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "range byTime: referenceTime, count {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	case 5:	/* range timeRange */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "TimeRange: beginningTime, endingTime {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	default:
+		return;
+	}
+	fReadRangeRequest (tvb, pinfo, tree, offset);
+}
+
+void
+fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSpecifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+		break;
+	case 2:	/* propertyArrayIndex Optional */
+		fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt);
+		break;
+	case 3:	/* resultFlags */
+		fApplicationTags (tvb, tree, offset, "resultFlags: ", bacapp_resultFlags);
+	break;
+	case 4:	/* itemCount */
+		fUnsignedTag (tvb, tree, offset, "itemCount: ", lvt);
+	break;
+	case 5:	/* itemData */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "List Of Values {");
+			fApplicationTags (tvb, tree, offset, "   Data: ", NULL);
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			return;
+		}
+	break;
+	default:
+		return;
+	}
+	fReadRangeAck (tvb, pinfo, tree, offset);
+}
+
+void
+fAtomicReadFileRequest (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* streamAccess */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {");
+		}
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fSignedTag (tvb, tree, offset, "   FileStartPosition: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fUnsignedTag (tvb, tree, offset, "   requestetOctetCount: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+		break;
+	case 1:	/* recordAccess */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "recordAccess {");
+		}
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fSignedTag (tvb, tree, offset, "   FileStartRecord: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		fUnsignedTag (tvb, tree, offset, "   requestetRecordCount: ", lvt);
+		(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	default:
+		return;
+	}
+}
+
+void
+fAtomicWriteFileRequest (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) {	/* Segment of an Request */
+		if (bacapp_flags & 0x04) { /* More Flag is set */
+			fOctetString (tvb, tree, offset, "   fileData: ", 0);
+		} else {
+			fOctetString (tvb, tree, offset, "   fileData: ", tvb->length - *offset - 1);
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (lvt == 7) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+		}
+	} else {
+		fObjectIdentifier (tvb, tree, offset, "fileIdentifier: ");
+
+		offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+		switch (tag_no) {
+		case 0:	/* streamAccess */
+			(*offset) += offs; /* set offset according to enhancements.... */
+			if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {");
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			fSignedTag (tvb, tree, offset, "   FileStartPosition: ", lvt);
+			fApplicationTags (tvb, tree, offset, "   fileData: ", NULL);
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+			break;
+		case 1:	/* recordAccess */
+			(*offset) += offs; /* set offset according to enhancements.... */
+			if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {");
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			fSignedTag (tvb, tree, offset, "  fileStartRecord: ", lvt);
+			fUnsignedTag (tvb, tree, offset, "  RecordCount: ", lvt);
+			fApplicationTags (tvb, tree, offset, "  Data: ", NULL);
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+		break;
+		default:
+			return;
+		}
+	}
+}
+
+void
+fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* streamAccess */
+		fSignedTag (tvb, tree, offset, "   FileStartPosition: ", lvt);
+		break;
+	case 1:	/* recordAccess */
+		fSignedTag (tvb, tree, offset, "  fileStartRecord: ", lvt);
+	break;
+	default:
+		return;
+	}
+}
+
+void
+fAtomicReadFile (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) {	/* Segment of an Request */
+		if (bacapp_flags & 0x04) { /* More Flag is set */
+			fOctetString (tvb, tree, offset, "   fileData: ", 0);
+		} else {
+			fOctetString (tvb, tree, offset, "   fileData: ", tvb->length - *offset - 1);
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (lvt == 7) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+		}
+	} else {
+		fApplicationTags (tvb, tree, offset, "EndOfFile: ", NULL);
+
+		offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+		switch (tag_no) {
+		case 0:	/* streamAccess */
+			(*offset) += offs; /* set offset according to enhancements.... */
+			if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {");
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			fSignedTag (tvb, tree, offset, "   FileStartPosition: ", lvt);
+			fApplicationTags (tvb, tree, offset, "   fileData: ", NULL);
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+			break;
+		case 1:	/* recordAccess */
+			(*offset) += offs; /* set offset according to enhancements.... */
+			if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {");
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			fSignedTag (tvb, tree, offset, "  FileStartRecord: ", lvt);
+			fUnsignedTag (tvb, tree, offset, "  returnedRecordCount: ", lvt);
+			fApplicationTags (tvb, tree, offset, "  Data: ", NULL);
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+				proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+			}
+		break;
+		default:
+			return;
+		}
+	}
+}
+
+void
+fReadPropertyMultipleRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSpecifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* list of propertyReferences */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {");
+			fPropertyReference (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	default:
+		return;
+	}
+	fReadPropertyMultipleRequest (tvb, pinfo, tree, offset);
+}
+
+void
+fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (tag_no) {
+	case 0:	/* objectSpecifier */
+		fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: ");
+		break;
+	case 1:	/* list of Results */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Results {");
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	case 2:	/* propertyIdentifier */
+		propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: ");
+		break;
+	case 3:	/* propertyArrayIndex Optional */
+		fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt);
+		break;
+	case 4:	/* propertyValue */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {");
+			fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	case 5:	/* propertyAccessError */
+		(*offset) += offs; /* set offset according to enhancements.... */
+		if ((lvt == 6) && (offs == 0)) {   /* opening Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Errors {");
+			/* Error Code follows */
+			fApplicationTags (tvb, tree, offset, "   errorClass: ", bacapp_errorClass);
+			fApplicationTags (tvb, tree, offset, "   errorCode: ", bacapp_error_code);
+		}
+		if (((lvt == 7) && (offs == 0))) {   /* closing Tag */
+			proto_tree_add_text(tree, tvb, (*offset)++, 1, "}");
+		}
+	break;
+	default:
+		return;
+	}
+	fReadPropertyMultipleAck (tvb, pinfo, tree, offset);
+}
+
+void
+fTagRequests (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+//	if (class_tag)	{	/* Context Specific Tag detected */
+		switch (service_choice) {
+		case 0:	/* acknowledgeAlarm */
+			fAckAlarmRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 1: /* confirmedCOVNotification*/
+			fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 2: /* confirmedEventNotification*/
+			fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 3: /* confirmedEventNotification*/
+			fGetAlarmSummary (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 4: /* getEnrollmentSummaryRequest */
+			fgetEnrollmentSummaryRequest (tvb, pinfo, tree, offset);
+			break;
+		case 5: /* subscribeCOVRequest */
+			fSubscribeCOV (tvb, pinfo, tree, offset);
+		break;
+		case 6: /* atomicReadFile-Request */
+			fAtomicReadFileRequest (tvb, tree, offset);
+			break;
+		case 7: /* atomicReadFile-Request */
+			fAtomicWriteFileRequest (tvb, tree, offset);
+			break;
+		case 8: /* AddListElement-Request */
+			fAddListElement (tvb, pinfo, tree, offset);
+			break;
+		case 9: /* removeListElement-Request */
+			fRemoveListElement (tvb, pinfo, tree, offset);
+			break;
+		case 10: /* createObjectRequest */
+			fCreateObject (tvb, pinfo, tree, offset);
+		break;
+		case 11: /* deleteObject */
+			fDeleteObject (tvb, tree, offset);
+		break;
+		case 12:
+			fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 13:
+			fReadPropertyConditional (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 14:
+			fReadPropertyMultipleRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 15:
+			fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 16:
+			fReadWriteMultipleProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 17:
+			fDeviceCommunicationControl (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 18:
+			fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 19:
+			fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 20:
+			fReinitializeDevice (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 21:
+			fVtOpen (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 22:
+			fVtClose (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 23:
+			fVtData (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 24:
+			fAuthenticate (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 25:
+			fRequestKey (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 26:
+			fReadRangeRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 27:
+			fLifeSafetyOperation (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 28:
+			fSubscribeCOVProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 29:
+			fGetEventInformationRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		default:
+			return;
+		break;
+		}
+//	} else {	/* Application Specific Tags */
+//		fApplicationTags (tvb, tree, offset, NULL, NULL);
+//	}
+
+ /*	fTagRequests (tvb, pinfo, tree, offset, service_choice); ### */
+}
+
+void
+fTags (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+//	if (class_tag)	{	/* Context Specific Tag detected */
+		switch (service_choice) {
+		case 0:	/* acknowledgeAlarm */
+			fAckAlarm (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 1: /* confirmedCOVNotification*/
+			fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 2: /* confirmedEventNotification*/
+			fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 3: /* confirmedEventNotification*/
+			fGetAlarmSummary (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+		case 4: /* getEnrollmentSummaryAck */
+			fgetEnrollmentSummaryAck (tvb, pinfo, tree, offset);
+			break;
+		case 5: /* subscribeCOV */
+			fSubscribeCOV (tvb, pinfo, tree, offset);
+		break;
+		case 6: /* atomicReadFile */
+			fAtomicReadFile (tvb, tree, offset);
+			break;
+		case 7: /* atomicReadFileAck */
+			fAtomicWriteFileAck (tvb, tree, offset);
+			break;
+		case 8: /* AddListElement */
+			fAddListElement (tvb, pinfo, tree, offset);
+			break;
+		case 9: /* removeListElement */
+			fRemoveListElement (tvb, pinfo, tree, offset);
+			break;
+		case 10: /* createObject */
+			fCreateObjectAck (tvb, tree, offset);
+		break;
+		case 11: /* deleteObject */
+			fDeleteObject (tvb, tree, offset);
+		break;
+		case 12:
+			fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 13:
+			fReadPropertyConditionalAck (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 14:
+			fReadPropertyMultipleAck (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 15:
+			fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 16:
+			fReadWriteMultipleProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 17:
+			fDeviceCommunicationControl (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 18:
+			fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 19:
+			fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 20:
+			fReinitializeDevice (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 21:
+			fVtOpen (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 22:
+			fVtClose (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 23:
+			fVtData (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 24:
+			fAuthenticate (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 25:
+			fRequestKey (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 26:
+			fReadRangeAck (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 27:
+			fLifeSafetyOperation (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 28:
+			fSubscribeCOVProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		case 29:
+			fGetEventInformation (tvb, pinfo, tree, offset); /* offset changes his value on return */
+			break;
+		default:
+			return;
+		break;
+		}
+//	} else {	/* Application Specific Tags */
+//		fApplicationTags (tvb, pinfo, tree, offset, NULL, NULL);
+//	}
+}
+
+void
+fIAm (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	guint8 offs, tmp, tag_no, class_tag, i;
+	guint64 lvt;
+	guint32 val = 0;
+
+	/* BACnetObjectIdentifier */
+	fApplicationTags (tvb, tree, offset, "BACnetObjectIdentifier: ", NULL);
+
+	/* MaxAPDULengthAccepted */
+	fApplicationTags (tvb, tree, offset, "Maximum ADPU Length accepted: ", NULL);
+
+	/* segmentationSupported */
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		(*offset) += offs + 1;	/* set offset according to enhancements.... */
+	for (i = 0; i < min((guint8) lvt, 4); i++) {
+		tmp = tvb_get_guint8(tvb, (*offset)+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, *offset, 1, "segmentationSupported: %s", match_strval(val, bacapp_segmentation));
+	(*offset)+=(guint8)lvt;
+
+	/* vendor ID */
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	fUnsignedTag (tvb, tree, offset, "vendorID: ", lvt);
+
+}
+
+void
+fIHave (tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{
+	/* BACnetDeviceIdentifier */
+	fApplicationTags (tvb, tree, offset, "DeviceIdentifier: ", NULL);
+
+	/* BACnetObjectIdentifier */
+	fApplicationTags (tvb, tree, offset, "ObjectIdentifier: ", NULL);
+
+	/* ObjectName */
+	fApplicationTags (tvb, tree, offset, "ObjectName: ", NULL);
+
+}
+
+void
+fWhoIs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{
+	guint8 tag_no, class_tag;
+	guint64 lvt;
+
+	if ((*offset) >= tvb->length)
+		return;
+
+	(*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+
+	switch (tag_no) {
+	case 0:	/* DeviceInstanceRangeLowLimit Optional */
+		fUnsignedTag (tvb, tree, offset, "DeviceInstanceRangeLowLimit: ", lvt);
+		break;
+	case 1:	/* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
+		fUnsignedTag (tvb, tree, offset, "DeviceInstanceRangeHighLimit: ", lvt);
+		break;
+	default:
+		return;
+		break;
+	}
+ 	fWhoIs (tvb, pinfo, tree, offset);
+}
+
+void
+fUnconfirmedTags (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice)
+{
+	guint8 offs, tag_no, class_tag;
+	guint64 lvt;
+
+	if (*offset >= tvb->length)
+		return;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	switch (service_choice) {
+	case 0:	/* I-Am-Request */
+		fIAm (tvb, tree, offset); /* offset changes his value on return */
+		break;
+	case 1: /* i-Have Request */
+		fIHave (tvb, tree, offset); /* offset changes his value on return */
+	break;
+	case 2: /* unconfirmedCOVNotification */
+		fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 3: /* unconfirmedEventNotification */
+		fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 4: /* unconfirmedPrivateTransfer */
+		fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 5: /* unconfirmedTextMessage */
+		fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 6: /* timeSynchronization */
+		fTimeSynchronization (tvb, tree, offset); /* offset changes his value on return */
+		break;
+	case 7: /* who-Has */
+		fWhoHas (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 8: /* who-Is */
+		fWhoIs (tvb, pinfo, tree, offset); /* offset changes his value on return */
+		break;
+	case 9: /* utcTimeSynchronization */
+		fUTCTimeSynchronization (tvb, tree, offset); /* offset changes his value on return */
+		break;
+	default:
+		break;
+	}
+}
+
+void
+fConfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{	/* BACnet-Confirmed-Request */
+	/* ASHRAE 135-2001 20.1.2 */
+
+	proto_item *tc, *tt, *ti;
+	proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
+	gint tmp, bacapp_type, service_choice;
+
+	tmp = (gint) tvb_get_guint8(tvb, (*offset));
+	bacapp_type = (tmp >> 4) & 0x0f;
+	bacapp_flags = tmp & 0x0f;
+
+	service_choice = (gint) tvb_get_guint8(tvb, (*offset)+3);
+	if (bacapp_flags & 0x08)
+		service_choice = (gint) tvb_get_guint8(tvb, (*offset)+5);
+
+
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_append_str(pinfo->cinfo, COL_INFO, val_to_str(service_choice, bacapp_confirmed_service_choice, "Reserved by ASHRAE"));
+
+	if (tree) {
+
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+		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);
+		proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, (*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree_control, hf_bacapp_response_segments, tvb,
+			                (*offset), 1, TRUE);
+		proto_tree_add_item(bacapp_tree_control, hf_bacapp_max_adpu_size, tvb,
+							(*offset), 1, TRUE);
+		(*offset) ++;
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,	(*offset)++, 1, TRUE);
+		if (bacapp_flags & 0x08) {
+			bacapp_seq = tvb_get_guint8(tvb, (*offset));
+			proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
+				(*offset)++, 1, TRUE);
+			proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
+				(*offset)++, 1, TRUE);
+		}
+		tmp = tvb_get_guint8(tvb, (*offset));
+		proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+			(*offset)++, 1, TRUE);
+		tt = proto_tree_add_item(bacapp_tree, hf_bacapp_vpart, tvb,
+			(*offset), 0, TRUE);
+		/* Service Request follows... Variable Encoding 20.2ff */
+		bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+		fTagRequests (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */
+	}
+}
+
+void
+fUnconfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{	/* BACnet-Unconfirmed-Request-PDU */
+	/* ASHRAE 135-2001 20.1.3 */
+
+	proto_item *tt, *ti;
+	proto_tree *bacapp_tree_tag, *bacapp_tree;
+	gint tmp;
+
+	tmp = tvb_get_guint8(tvb, (*offset)+1);
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, BACnetUnconfirmedServiceRequest, "Reserved by ASHRAE"));
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE);
+
+		tmp = tvb_get_guint8(tvb, (*offset));
+		tt = proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
+				(*offset)++, 1, TRUE);
+		/* Service Request follows... Variable Encoding 20.2ff */
+		bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+		fUnconfirmedTags (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */
+	}
+}
+
+void
+fSimpleAcknowledge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{	/* BACnet-Simple-Ack-PDU */
+	/* ASHRAE 135-2001 20.1.4 */
+
+	proto_item *tc, *ti;
+	gint tmp;
 	proto_tree *bacapp_tree;
-	guint8 offset;
-	guint8 bacapp_type;
-	tvbuff_t *next_tvb;
 
-	if (check_col(pinfo->cinfo, COL_PROTOCOL))
-		col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
+	tmp = tvb_get_guint8(tvb, (*offset)+2);
 	if (check_col(pinfo->cinfo, COL_INFO))
-		col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
+		col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, bacapp_confirmed_service_choice, "Reserved by ASHRAE"));
 
-	offset  = 0;
-	bacapp_type = (tvb_get_guint8(tvb, offset) >> 4) & 0x0f;
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
 
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+			(*offset)++, 1, TRUE);
+	}
+}
+
+void
+fComplexAcknowledge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset)
+{	/* BACnet-Complex-Ack-PDU */
+	/* ASHRAE 135-2001 20.1.5 */
+
+	proto_item *tc, *tt, *ti;
+	proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
+	gint tmp, bacapp_type;
+
+	tmp = (gint) tvb_get_guint8(tvb, (*offset));
+	bacapp_type = (tmp >> 4) & 0x0f;
+	bacapp_flags = tmp & 0x0f;
+
+	tmp = tvb_get_guint8(tvb, (*offset)+2);
+	if (bacapp_flags & 0x08)
+		tmp = tvb_get_guint8(tvb, (*offset)+4);
+
 	if (check_col(pinfo->cinfo, COL_INFO))
-		col_append_fstr(pinfo->cinfo, COL_INFO, "(%s)",
-		bacapp_type_name(bacapp_type));
+		col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, bacapp_confirmed_service_choice, "Reserved by ASHRAE"));
+
 	if (tree) {
-		ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
 
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
 		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
 
-		proto_tree_add_uint_format(bacapp_tree, hf_bacapp_type, tvb,
-			offset, 1, bacapp_type, "APDU Type: %u (%s)", bacapp_type,
-				bacapp_type_name(bacapp_type));
-		offset ++;
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
 
+		proto_tree_add_item(bacapp_tree, hf_bacapp_SEG, tvb, (*offset), 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_MOR, tvb, (*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		if (bacapp_flags & 0x08) {
+			bacapp_seq = tvb_get_guint8(tvb, (*offset));
+			proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
+				(*offset)++, 1, TRUE);
+			proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
+				(*offset)++, 1, TRUE);
+		}
+		tmp = tvb_get_guint8(tvb, (*offset));
+		tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+			(*offset)++, 1, TRUE);
+		/* Service ACK follows... */
+		bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+		fTags (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */
 	}
-	next_tvb = tvb_new_subset(tvb,offset,-1,-1);
-	call_dissector(data_handle,next_tvb, pinfo, tree);
 }
 
 
 void
+fSegmentedAcknowledge(tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{	/* BACnet-SegmentAck-PDU */
+	/* ASHRAE 135-2001 20.1.6 */
+
+	proto_item *tc, *ti;
+	proto_tree *bacapp_tree_control, *bacapp_tree;
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_NAK, tvb, (*offset), 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, (*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
+				(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
+				(*offset)++, 1, TRUE);
+	}
+}
+
+void
+fError(tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{	/* BACnet-Error-PDU */
+	/* ASHRAE 135-2001 20.1.7 */
+
+	proto_item *tc, *ti;
+	proto_tree *bacapp_tree_control, *bacapp_tree;
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+			(*offset)++, 1, TRUE);
+		/* Error Code follows */
+		fApplicationTags (tvb, bacapp_tree, offset, "   errorClass: ", bacapp_errorClass);
+		fApplicationTags (tvb, bacapp_tree, offset, "   errorCode: ", bacapp_error_code);
+
+	}
+}
+
+void
+fReject(tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{	/* BACnet-Reject-PDU */
+	/* ASHRAE 135-2001 20.1.8 */
+
+	proto_item *tc, *ti;
+	proto_tree *bacapp_tree_control, *bacapp_tree;
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_reject_reason, tvb,
+			(*offset)++, 1, TRUE);
+	}
+}
+
+void
+dissect_bacapp_abort(tvbuff_t *tvb, proto_tree *tree, guint *offset)
+{	/* BACnet-Abort-PDU */
+	/* ASHRAE 135-2001 20.1.9 */
+
+	proto_item *tc, *ti;
+	proto_tree *bacapp_tree_control, *bacapp_tree;
+
+	if (tree) {
+		ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE);
+		bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+		tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE);
+		bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+		proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, (*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+			(*offset)++, 1, TRUE);
+		proto_tree_add_item(bacapp_tree, hf_bacapp_abort_reason, tvb,
+			(*offset)++, 1, TRUE);
+	}
+}
+
+void
+dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+	gint tmp, bacapp_type;
+	tvbuff_t *next_tvb;
+	guint offset = 0;
+
+	tmp = (gint) tvb_get_guint8(tvb, 0);
+	bacapp_type = (tmp >> 4) & 0x0f;
+
+	if (check_col(pinfo->cinfo, COL_INFO))
+		col_set_str(pinfo->cinfo, COL_INFO, val_to_str(bacapp_type, bacapp_type_name, "#### unknown APDU ##### "));
+
+	/* ASHRAE 135-2001 20.1.1 */
+	switch (bacapp_type) {
+	case 0:	/* BACnet-Confirmed-Service-Request */
+		fConfirmedServiceRequest(tvb, pinfo, tree, &offset);	/* offset will be modified */
+		break;
+	case 1:	/* BACnet-Unconfirmed-Request-PDU */
+		fUnconfirmedServiceRequest(tvb, pinfo, tree, &offset);	/* offset will be modified */
+		break;
+	case 2:	/* BACnet-Simple-Ack-PDU */
+		fSimpleAcknowledge(tvb, pinfo, tree, &offset);	/* offset will be modified */
+		break;
+	case 3:	/* BACnet-Complex-Ack-PDU */
+		fComplexAcknowledge(tvb, pinfo, tree, &offset);	/* offset will be modified */
+		break;
+	case 4:	/* BACnet-SegmentAck-PDU */
+		fSegmentedAcknowledge(tvb, tree, &offset);	/* offset will be modified */
+		break;
+	case 5:	/* BACnet-Error-PDU */
+		fError(tvb, tree, &offset);	/* offset will be modified */
+		break;
+	case 6:	/* BACnet-Reject-PDU */
+		fReject(tvb, tree, &offset);	/* offset will be modified */
+		break;
+	case 7:	/* BACnet-Abort-PDU */
+		dissect_bacapp_abort(tvb, tree, &offset);	/* offset will be modified */
+		break;
+	}
+
+	next_tvb = tvb_new_subset(tvb,offset,-1,tvb->reported_length - offset);
+	call_dissector(data_handle,next_tvb, pinfo, tree);
+}
+
+void
 proto_register_bacapp(void)
 {
 	static hf_register_info hf[] = {
 		{ &hf_bacapp_type,
 			{ "APDU Type",           "bacapp.bacapp_type",
-			FT_UINT8, BASE_DEC, NULL, 0xf0, "APDU Type", HFILL }
+			FT_UINT8, BASE_DEC, VALS(bacapp_type_name), 0xf0, "APDU Type", HFILL }
 		},
+		{ &hf_bacapp_SEG,
+			{ "SEG",           "bacapp.bacapp_type.SEG",
+			FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Requests", HFILL }
+		},
+		{ &hf_bacapp_MOR,
+			{ "MOR",           "bacapp.bacapp_type.MOR",
+			FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
+		},
+		{ &hf_bacapp_SA,
+			{ "SA",           "bacapp.bacapp_type.SA",
+			FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
+		},
+		{ &hf_bacapp_max_adpu_size,
+			{ "Size of Maximum ADPU accepted",           "bacapp.bacapp_max_adpu_size",
+			FT_UINT8, BASE_DEC, VALS(bacapp_max_APDU_length_accepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
+		},
+		{ &hf_bacapp_response_segments,
+			{ "Max Response Segments accepted",           "bacapp.bacapp_response_segments",
+			FT_UINT8, BASE_DEC, VALS(bacapp_max_segments_accepted), 0xe0, "Max Response Segments accepted", HFILL }
+		},
+		{ &hf_bacapp_invoke_id,
+			{ "Invoke ID",           "bacapp.bacapp_invoke_id",
+			FT_UINT8, BASE_HEX, NULL, 0, "Invoke ID", HFILL }
+		},
+		{ &hf_bacapp_sequence_number,
+			{ "Sequence Number",           "bacapp.bacapp_sequence_number",
+			FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
+		},
+		{ &hf_bacapp_window_size,
+			{ "Proposed Window Size",           "bacapp.bacapp_window_size",
+			FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
+		},
+		{ &hf_bacapp_service,
+			{ "Service Choice",           "bacapp.bacapp_service",
+			FT_UINT8, BASE_DEC, VALS(bacapp_confirmed_service_choice), 0x00, "Service Choice", HFILL }
+		},
+		{ &hf_bacapp_uservice,
+			{ "Unconfirmed Service Choice",           "bacapp.bacapp_unconfirmed_service",
+			FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
+		},
+		{ &hf_bacapp_NAK,
+			{ "NAK",           "bacapp.bacapp_type.NAK",
+			FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
+		},
+		{ &hf_bacapp_SRV,
+			{ "SRV",           "bacapp.bacapp_type.SRV",
+			FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
+		},
+		{ &hf_bacapp_reject_reason,
+			{ "Reject Reason",           "bacapp.bacapp_reject_reason",
+			FT_UINT8, BASE_DEC, VALS(bacapp_reject_reason), 0x00, "Reject Reason", HFILL }
+		},
+		{ &hf_bacapp_abort_reason,
+			{ "Abort Reason",           "bacapp.bacapp_abort_reason",
+			FT_UINT8, BASE_DEC, VALS(bacapp_abort_reason), 0x00, "Abort Reason", HFILL }
+		},
+		{ &hf_bacapp_vpart,
+			{ "BACnet APDU variable part:",           "bacapp.variable_part",
+			FT_NONE, 0, NULL, 00, "BACnet APDU varaiable part:", HFILL }
+		},
+		{ &hf_bacapp_tag_number,
+			{ "Tag Number",           "bacapp.bacapp_tag.number",
+			FT_UINT8, BASE_DEC, VALS(bacapp_tag_number), 0xF0, "Tag Number", HFILL }
+		},
+		{ &hf_bacapp_tag_class,
+			{ "Class",           "bacapp.bacapp_tag.class",
+			FT_BOOLEAN, 8, TFS(&bacapp_tag_class), 0x08, "Class", HFILL }
+		},
+		{ &hf_bacapp_tag_lvt,
+			{ "Length Value Type",           "bacapp.bacapp_tag.lvt",
+			FT_UINT8, BASE_DEC, NULL, 0x07, "Length Value Type", HFILL }
+		},
+/*		{ &hf_bacapp_initiatingObject,
+			{ "initiating Object Identifier:",           "bacapp.initiatingObject",
+			FT_NONE, 0, NULL, 0x00, "BACnet APDU InitiatingObject:", HFILL }
+		},
+		{ &hf_bacapp_monitoredObject,
+			{ "monitored Object Identifier:",           "bacapp.monitoredObject",
+			FT_NONE, 0, NULL, 0x00, "BACnet APDU MonitoredObject:", HFILL }
+		},
+*/		{ &hf_bacapp_tag_ProcessId,
+			{ "subscriberProcessIdentifier",           "bacapp.bacapp_tag.ProcessId",
+			FT_UINT32, BASE_DEC, NULL, 0, "subscriberProcessIdentifier", HFILL }
+		},
+		{ &hf_bacapp_tag_initiatingObjectType,
+			{ "ObjectType",           "bacapp.bacapp_tag.ObjectType",
+			FT_UINT16, BASE_DEC, VALS(bacapp_object_type), 0x00, "ObjectType", HFILL }
+		},
+/*		{ &hf_bacapp_tag_initiatingObjectId,
+			{ "instance Number",           "bacapp.bacapp_tag.ObjectId",
+			FT_UINT24, BASE_DEC, NULL, 0, "instance Number", HFILL }
+		},
+		{ &hf_bacapp_tag_null,
+			{ "   Value -  NULL",           "bacapp.bacapp_tag.null",
+			FT_UINT8, BASE_HEX, NULL, 0x07, "Application Tag NULL", HFILL }
+		},
+		{ &hf_bacapp_tag_boolean,
+			{ "   Value - Boolean",           "bacapp.bacapp_tag.boolean",
+			FT_BOOLEAN, 8, NULL, 0x07, "Application Tag Boolean", HFILL }
+		},
+		{ &hf_bacapp_tag_uint8,
+			{ "   Value - Unsigned Integer",           "bacapp.bacapp_tag.uint8",
+			FT_UINT8, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_uint16,
+			{ "   Value - Unsigned Integer",           "bacapp.bacapp_tag.uint16",
+			FT_UINT16, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_uint32,
+			{ "   Value - Unsigned Integer",           "bacapp.bacapp_tag.uint32",
+			FT_UINT32, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_uint64,
+			{ "   Value - Unsigned Integer",           "bacapp.bacapp_tag.uint64",
+			FT_UINT64, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_sint8,
+			{ "   Value - Signed Integer",           "bacapp.bacapp_tag.sint8",
+			FT_INT8, BASE_DEC, NULL, 0, "Signed Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_sint16,
+			{ "   Value - Signed Integer",           "bacapp.bacapp_tag.sint16",
+			FT_INT16, BASE_DEC, NULL, 0, "Signed Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_sint32,
+			{ "   Value - Signed Integer",           "bacapp.bacapp_tag.sint32",
+			FT_INT32, BASE_DEC, NULL, 0, "Signed Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_sint64,
+			{ "   Value - Signed Integer",           "bacapp.bacapp_tag.sint64",
+			FT_INT64, BASE_DEC, NULL, 0, "Signed Integer", HFILL }
+		},
+		{ &hf_bacapp_tag_real,
+			{ "   Value - REAL",           "bacapp.bacapp_tag.real",
+			FT_FLOAT, BASE_DEC, NULL, 0, "Real (Floating Point)", HFILL }
+		},
+		{ &hf_bacapp_tag_double,
+			{ "   Value - DOUBLE",           "bacapp.bacapp_tag.double",
+			FT_DOUBLE, BASE_DEC, NULL, 0, "Double (Double Precision Floating Point)", HFILL }
+		},
+		{ &hf_bacapp_tag_timeRemaining,
+			{ "time remaining (seconds)",           "bacapp.bacapp_tag.timeRemaining",
+			FT_UINT64, BASE_DEC, NULL, 0, "time remaining (seconds)", HFILL }
+		},
+		{ &hf_bacapp_tag_string,
+			{ "   Value - String",           "bacapp.bacapp_tag.string",
+			FT_STRING, BASE_DEC, NULL, 0, "String", HFILL }
+		},
+		{ &hf_bacapp_tag_bytes,
+			{ "   Value - Bytes",           "bacapp.bacapp_tag.bytes",
+			FT_BYTES, BASE_DEC, NULL, 0, "Bytes", HFILL }
+		},
+		{ &hf_bacapp_tag_character_set,
+			{ "   Value - String Character Set",           "bacapp.bacapp_tag.character_set",
+			FT_UINT8, BASE_DEC, bacapp_character_set, 0, "Bytes", HFILL }
+		},
+		{ &hf_bacapp_error_code,
+			{ "Error Code",           "bacapp.bacapp_code",
+			FT_UINT8, BASE_DEC, VALS(bacapp_error_code), 0x00, "Error Code", HFILL }
+		},
+*/
 	};
 	static gint *ett[] = {
 		&ett_bacapp,
+		&ett_bacapp_control,
+		&ett_bacapp_tag,
 	};
 	proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
 	    "BACapp", "bacapp");
+
 	proto_register_field_array(proto_bacapp, hf, array_length(hf));
 	proto_register_subtree_array(ett, array_length(ett));
 	register_dissector("bacapp", dissect_bacapp, proto_bacapp);
+
 }
 
 void